Main Page | Namespace List | Class Hierarchy | Alphabetical List | Class List | Directories | File List | Namespace Members | Class Members | File Members | Related Pages

variant.hpp

Go to the documentation of this file.
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-&lt;str() &lt; rhs.str()).
00283                 */
00284                 inline bool operator<( const variant & rhs ) const
00285                 {
00286                         return this->str() < rhs.str();
00287                 }
00288 
00289                 /**
00290                  Returns (this-&lt;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 

Generated on Sun Dec 25 20:26:12 2005 for libs11n-1.2.3 by  doxygen 1.4.4