00001 #ifndef s11n_net_s11n_VARIANT_HPP_INCLUDED 00002 #define s11n_net_s11n_VARIANT_HPP_INCLUDED 1 00003 //////////////////////////////////////////////////////////////////////// 00004 // variant.hpp: the s11n::variant class 00005 //////////////////////////////////////////////////////////////////////// 00006 00007 00008 #include <string> 00009 #include <sstream> 00010 #include <map> 00011 00012 /** 00013 This file houses a little class for lexically casting strings and 00014 other types to and from each other. 00015 00016 00017 This software is released into the Public Domain by it's author, 00018 stephan beal (stephan@s11n.net). 00019 00020 00021 Change history: 00022 00023 27 June 2005: 00024 - Moved operator==() back into class, because they often cause 00025 odd overload ambiguities in unrelated code when comparing 00026 iterators of arbitrary types. 00027 00028 Early 2005: 00029 - Switch to Marc Duerner's hack for the istream>> operator, 00030 which is the sanest one i can think of. 00031 00032 31 Dec 2004: 00033 - Changed the impl of istream>>() again. Now uses a horrible 00034 hack but works across many more use cases. 00035 00036 28 Dec 2004: 00037 - Changed the impl of istream>>() to use getc() instead of getline(), 00038 so newlines are preserved. 00039 00040 00041 25 Nov 2004: 00042 - Minor doc updates. 00043 - Changed multiple-include guard to allow inclusion of this file twice 00044 for purposes of registering variant with s11n. Before, this header 00045 must have been included AFTER including s11n to pick up the 00046 registration. Now including this header after including s11n is safe 00047 if it has previously been included (and thus didn't pick up s11n 00048 registration). 00049 00050 00051 2 Oct 2004: 00052 00053 - Accomodated recent changes in libs11n. 00054 00055 00056 22 Aug 2004: 00057 00058 - Added ambiguity-buster overloads for operator==() for (const char *) 00059 and std::string. 00060 00061 00062 20 Aug 2004: 00063 00064 - Added variant::empty() 00065 - Moved variant::operator==() to a free function. 00066 - Added variant::operator=(const char *) (see API notes for why). 00067 00068 00069 17 Aug 2004: 00070 00071 - Initial release. 00072 - After-relase: 00073 - Added more docs. 00074 - Added std::string and (const char *) overloads, to avoid some ambiguities. 00075 00076 00077 00078 16 Aug 2004: 00079 - Zen Coding Session. 00080 00081 */ 00082 namespace {} /* for doxygen */ 00083 00084 00085 namespace s11n { namespace Detail { 00086 00087 namespace Private // not for use by clients of variant 00088 { 00089 00090 00091 /** 00092 Lexically casts str to a value_type, returning 00093 errorVal if the conversion fails. 00094 00095 TODO: implement the following suggestion from 00096 Kai Unger <kai.unger@hacon.de> (21 Sept 2004): 00097 00098 When the cast is done, you should check if there 00099 are unread characters left. For example, casting 00100 "1.2this_definitly_is_not_a_number" to double will 00101 not result in returning the error value, because 00102 conversion of "1.2" to 1.2d succeeds and the rest 00103 of the string is ignored. 00104 */ 00105 template <typename value_type> 00106 value_type from_string( const std::string & str, const value_type & errorVal ) throw() 00107 { 00108 std::istringstream is( str ); 00109 if ( !is ) 00110 return errorVal; 00111 value_type foo = value_type(); 00112 if ( is >> foo ) 00113 return foo; 00114 return errorVal; 00115 } 00116 00117 /** 00118 Returns a string representation of the given 00119 object, which must be ostreamble. 00120 */ 00121 template <typename value_type> 00122 std::string to_string( const value_type & obj ) throw() 00123 { 00124 std::ostringstream os; 00125 os.precision( 16 ); // unfortunate, but for the general case very useful 00126 os << obj; 00127 return os.str(); 00128 } 00129 00130 // Why the hell doesn't overload selection take this one? 00131 // inline std::string to_string( double d ) throw() 00132 // { 00133 // std::ostringstream os; 00134 // os.precision( 20 ); 00135 // os << d; 00136 // return os.str(); 00137 // } 00138 00139 00140 /** 00141 Convenience/efficiency overload. 00142 */ 00143 inline std::string from_string( const std::string & str, const std::string & /*errorVal*/ ) throw() 00144 { 00145 return str; 00146 } 00147 00148 /** 00149 Convenience/efficiency overload. 00150 */ 00151 inline std::string from_string( const char *str, const char * /*errorVal*/ ) throw() 00152 { 00153 return str; 00154 } 00155 00156 /** 00157 Convenience/efficiency overload. 00158 */ 00159 inline std::string to_string( const char *obj ) throw() 00160 { 00161 return obj ? obj : ""; 00162 } 00163 00164 /** 00165 Convenience/efficiency overload. 00166 */ 00167 inline std::string to_string( const std::string & obj ) throw() 00168 { 00169 return obj; 00170 } 00171 00172 00173 } // end Private namespace 00174 00175 00176 00177 /** 00178 variant provides a really convenient way to lexically cast 00179 strings and other streamable types to/from each other. 00180 00181 All parameterized types used by this type must be: 00182 00183 - i/o streamable. The operators must complement each other. 00184 00185 - Assignable. 00186 00187 - Default Constructable. 00188 00189 This type is fairly light-weight, with only one std::string 00190 data member, so it should copy quickly and implicitely use 00191 std::string's CoW and reference counting features. Adding 00192 reference counting to this class would be of no benefit, 00193 and would probably hurt performance, considering that 00194 std::string's are optimized in these ways, and this type 00195 is simply a proxy for a std::string. 00196 00197 For some uses the variant type can replace the requirement 00198 for returning a proxy type from a type's operator[](), as 00199 discussed in Scott Meyers' <em>More Effective C++</em>, Item 00200 30. This class originally was such a proxy, and then 00201 evolved into a generic solution for POD-based types, which 00202 inherently also covers most i/ostreamable types. It is less 00203 efficient than specialized proxies for, e.g. (char &), but 00204 it is also extremely easy to use, as shown here: 00205 00206 00207 <pre> 00208 s11n::variant lex = 17; 00209 int bogo = lex; 00210 ulong bogol = bogo * static_cast<long>(lex); 00211 lex = "bogus string"; 00212 00213 typedef std::map<variant,variant> LMap; 00214 LMap map; 00215 00216 map[4] = "one"; 00217 map["one"] = 4; 00218 map[123] = "eat this"; 00219 map['x'] = "marks the spot"; 00220 map["fred"] = 94.3 * static_cast<double>( map["one"] ); 00221 map["fred"] = 10 * static_cast<double>( map["fred"] ); 00222 map["123"] = "this was re-set"; 00223 int myint = map["one"]; 00224 00225 </pre> 00226 00227 Finally, Perl-ish type flexibility in C++. :) 00228 00229 It gets better: if we're using s11n, we can now save and load 00230 these objects at will: 00231 00232 <pre> 00233 s11nlite::save( map, "somefile.s11n" ); 00234 ... 00235 00236 LMap * map = s11nlite::load_serializable<LMap>( "somefile.s11n" ); 00237 </pre> 00238 00239 */ 00240 struct variant 00241 { 00242 /** 00243 Constructs an empty object. Calling <code>cast_to<T>()</code> 00244 on an un-populated variant object will return T(). 00245 */ 00246 variant() throw(){} 00247 00248 ~variant() throw() {} 00249 00250 /** 00251 Lexically casts f to a string. 00252 */ 00253 template <typename FromT> 00254 variant( const FromT & f ) throw() 00255 { 00256 this->m_data = Private::to_string( f ); 00257 } 00258 00259 /** 00260 Efficiency overload. 00261 */ 00262 variant( const std::string & f ) throw() : m_data(f) 00263 { 00264 } 00265 /** 00266 See operator=(const char *) for a note about why 00267 this exists. 00268 */ 00269 variant( const char * str ) throw() : m_data(str?str:"") 00270 { 00271 } 00272 00273 00274 /** 00275 Copies rhs's data to this object. 00276 */ 00277 variant( const variant & rhs ) throw() : m_data(rhs.m_data) 00278 { 00279 } 00280 00281 /** 00282 Returns (this-<str() < rhs.str()). 00283 */ 00284 inline bool operator<( const variant & rhs ) const 00285 { 00286 return this->str() < rhs.str(); 00287 } 00288 00289 /** 00290 Returns (this-<str() > rhs.str()). 00291 */ 00292 inline bool operator>( const variant & rhs ) const 00293 { 00294 return this->str() > rhs.str(); 00295 } 00296 00297 00298 /** 00299 Copies rhs's data and returns this object. 00300 */ 00301 inline variant & operator=( const variant & rhs ) throw() 00302 { 00303 if( &rhs != this ) this->m_data = rhs.m_data; 00304 return *this; 00305 } 00306 00307 /** 00308 This overload exists to keep the compiler/linker 00309 from generating a new instantiation of this function 00310 for each differently-lengthed (const char *) 00311 which is assigned to a variant. 00312 */ 00313 inline variant & operator=( const char * rhs ) throw() 00314 { 00315 this->m_data = rhs ? rhs : ""; 00316 return *this; 00317 } 00318 00319 00320 /** 00321 lexically casts str() to a ToType, returning 00322 dflt if the cast fails. 00323 00324 When calling this function you may need to use the 00325 following syntax to avoid compile errors: 00326 00327 Foo foo = lex.template cast_to<Foo>(); 00328 00329 (It's weird, i know, and the first time i saw it, 00330 finding the solution to took me days. (Thank you, 00331 Nicolai Josuttis!)) 00332 00333 However, in normal usage you won't need to use this 00334 function, as the generic type conversion operator 00335 does the exact same thing: 00336 00337 <pre> 00338 variant lex = 17; 00339 int foo = lex; 00340 </pre> 00341 */ 00342 template <typename ToType> 00343 ToType cast_to( const ToType & dflt = ToType() ) const throw() 00344 { 00345 return Private::from_string( this->m_data, dflt ); 00346 } 00347 00348 00349 /** 00350 i used to LOVE C++... After writing this function i 00351 WORSHIP C++. The grace with which C++ handles this 00352 is pure magic, my friends. 00353 00354 16.8.2004 ----- stephan 00355 */ 00356 template <typename ToType> 00357 inline operator ToType() const throw() 00358 { 00359 return this->template cast_to<ToType>(); 00360 } 00361 00362 /** 00363 Overload to avoid ambiguity in some cases. 00364 */ 00365 inline operator std::string () const throw() 00366 { 00367 return this->str(); 00368 } 00369 /** 00370 Returns the same as str(). 00371 */ 00372 operator std::string & () throw() { return this->m_data; } 00373 00374 /** 00375 Returns the same as str(). 00376 */ 00377 operator const std::string & () const throw() { return this->m_data; } 00378 00379 00380 /** 00381 Overload to avoid ambiguity in some cases. 00382 Useful for mixing C and C++ APIs: 00383 00384 <pre> 00385 variant arg = "USER"; 00386 variant user = ::getenv(arg); 00387 </pre> 00388 */ 00389 inline operator const char * () const throw() 00390 { 00391 return this->str().c_str(); 00392 } 00393 00394 00395 00396 /** 00397 Sets this object's value and returns this object. 00398 */ 00399 template <typename ToType> 00400 inline variant & operator=( const ToType & f ) throw() 00401 { 00402 this->m_data = Private::to_string( f ); 00403 return *this; 00404 } 00405 00406 /** 00407 Returns a reference to this object's raw string 00408 data. 00409 */ 00410 inline std::string & str() throw() { return this->m_data; } 00411 00412 00413 /** 00414 Returns a const reference to this object's raw 00415 string data. 00416 */ 00417 inline const std::string & str() const throw() { return this->m_data; } 00418 00419 /** 00420 Returns true if this object contains no data, else false. 00421 */ 00422 inline bool empty() const { return this->m_data.empty(); } 00423 00424 /** 00425 Casts lhs to a T object and returns true only if that 00426 object compares as equal to rhs. 00427 */ 00428 template <typename T> 00429 inline bool operator==( const T & rhs ) const 00430 { 00431 return this->template cast_to<T>() == rhs; 00432 } 00433 00434 /** Returns lhs.str() == rhs.str(). */ 00435 inline bool operator==( const variant & rhs ) const 00436 { 00437 return this->str() == rhs.str(); 00438 } 00439 00440 /** 00441 Avoid an ambiguity... 00442 00443 If rhs == 0 then this function returns true if 00444 lhs.empty(). 00445 */ 00446 inline bool operator==( const char * rhs ) const 00447 { 00448 if( ! rhs ) return this->empty(); 00449 return this->str() == std::string(rhs); 00450 } 00451 00452 /** 00453 Avoid an ambiguity... 00454 */ 00455 inline bool operator==( const std::string & rhs ) const 00456 { 00457 return this->str() == rhs; 00458 } 00459 00460 00461 /** 00462 Copies this->str() to os. 00463 */ 00464 inline std::ostream & operator<<( std::ostream & os ) const 00465 { 00466 return os << this->str(); 00467 } 00468 00469 /** 00470 Reads from the input stream, appending to this->str() until the stream 00471 gives up. If the implementation of this function seems "wrong" 00472 to you, please read the justification in this paper: 00473 00474 http://s11n.net/papers/lexical_casting.html 00475 00476 i believe there to be no satisfying, truly generic 00477 implementation for this function :(. 00478 */ 00479 inline std::istream & operator>>( std::istream & is ) 00480 { 00481 /**** 00482 WTF doesn't this do anything?!?!?!?!? 00483 00484 int c; 00485 while( is.get(c).good() ) { 00486 a.str() += c; 00487 } 00488 ****/ 00489 /***** 00490 while( std::getline( is, a.str() ).good() ); 00491 // ^^^ eeek! strips newlines! 00492 *****/ 00493 /***** 00494 is >> a.str(); // depends on skipws. 00495 *****/ 00496 /***** 00497 std::getline( is, a.str(), '\v' ); // UGLY, EVIL hack! 00498 The \v char ("virtical tab") is an ugly hack: it is simply a char from 00499 the ascii chart which never shows up in text. At least, i hope it 00500 doesn't. AFIK, \v was historically used on old line printers and some 00501 ancient terminals, but i've never seen it actually used. Unicode maps 00502 0-255 to the same as ascii, so this shouldn't be a problem for 00503 unicode. 00504 *****/ 00505 // Many thanks to Marc Duerner: 00506 std::getline( is, this->str(), static_cast<std::istream::char_type>(std::istream::traits_type::eof()) ); 00507 return is; 00508 } 00509 00510 00511 private: 00512 std::string m_data; 00513 }; 00514 00515 00516 00517 00518 00519 } } // namespace s11n::Detail 00520 00521 00522 #endif // s11n_net_s11n_VARIANT_HPP_INCLUDED 00523