ana/api/binary_streams.hpp

Go to the documentation of this file.
00001 /* $Id: binary_streams.hpp 47318 2010-10-30 21:42:12Z silene $ */
00002 
00003 /**
00004  * @file
00005  * @brief Minimal serialization library.
00006  *
00007  * This file is part of the MiLi Minimalistic Library :
00008  *      mili.googlecode.com
00009  *
00010  * binary_streams: A minimal library supporting encoding of different data
00011  *                 types in a single binary stream.
00012  *
00013  * Copyright (C) 2009, 2010  Guillermo Biset
00014  *
00015  * Subsystem: ana: Asynchronous Network API.
00016  * Language:       C++
00017  *
00018  * Author:         Guillermo Biset
00019  * E-Mail:         billybiset AT gmail DOT com
00020  *
00021  * ana is free software: you can redistribute it and/or modify
00022  * it under the terms of the GNU General Public License as published by
00023  * the Free Software Foundation, either version 2 of the License, or
00024  * (at your option) any later version.
00025  *
00026  * ana is distributed in the hope that it will be useful,
00027  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00028  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00029  * GNU General Public License for more details.
00030  *
00031  * You should have received a copy of the GNU General Public License
00032  * along with ana.  If not, see <http://www.gnu.org/licenses/>.
00033  *
00034  */
00035 
00036 #ifndef BINARY_STREAMS_HPP
00037 #define BINARY_STREAMS_HPP
00038 
00039 #include <list>
00040 #include <map>
00041 #include <set>
00042 #include <vector>
00043 
00044 #include "common.hpp"
00045 
00046 namespace ana
00047 {
00048     /**
00049      * Module for object serialization and Marshalling.
00050      */
00051     namespace serializer
00052     {
00053         /// @cond false
00054         template <class T>
00055         struct template_is_container { enum {  value = 0   }; };
00056 
00057         // This could/should be done with Template Meta Programming
00058         template <class T>
00059         struct template_is_container< std::vector<T> > { enum {  value = 1 }; };
00060 
00061         template <class K, class D>
00062         struct template_is_container< std::vector<K,D> > { enum {  value = 1 }; };
00063 
00064         template <class T>
00065         struct template_is_container< std::list<T> > { enum {  value = 1 }; };
00066 
00067         template <class K, class D>
00068         struct template_is_container< std::list<K,D> > { enum {  value = 1 }; };
00069 
00070         template <class K, class D, class C>
00071         struct template_is_container< std::set<K,D,C> > { enum {  value = 1 }; };
00072 
00073         template <class K, class D>
00074         struct template_is_container< std::map<K,D> > { enum {  value = 1 }; };
00075 
00076         template <class K, class D>
00077         struct template_is_container< std::multimap<K,D> > { enum {  value = 1 }; };
00078         /// @endcond
00079 
00080         /**
00081          * Output stream serialization. This class provides stream functionality to serialize
00082          * objects in a way similar to that of std::cout or std::ostringstream.
00083          *
00084          * Extracted from MiLi (mili.googlecode.com).
00085          *
00086          * An extensive example of its usage can be seen in:
00087          *    http://code.google.com/p/mili/source/browse/trunk/example_binary-streams.cpp
00088          */
00089         class bostream
00090         {
00091             private:
00092                 template<class T, bool IsContainer> struct _inserter_helper;
00093 
00094                 template<class T, bool IsContainer> friend struct _inserter_helper;
00095 
00096             public:
00097                 /**
00098                  * Standard constructor.
00099                  */
00100                 bostream() :
00101                     _s()
00102                 {
00103                 }
00104 
00105                 /**
00106                  * Insert any object to the stream.
00107                  *
00108                  * @param x : A copy of the object being inserted.
00109                  */
00110                 template <class T>
00111                 bostream& operator<< (T x)
00112                 {
00113                     _inserter_helper<T, template_is_container<T>::value >::call(this, x);
00114                     return *this;
00115                 }
00116 
00117                 /**
00118                  * Insert a string to the stream.
00119                  */
00120                 bostream& operator<< (const std::string& s)
00121                 {
00122                     (*this) << ana::ana_uint32( s.size() );
00123                     _s += s;
00124                     return *this;
00125                 }
00126 
00127                 /**
00128                  * Insert a vector of elements.
00129                  */
00130                 template <class Other>
00131                 bostream& operator<< (const std::vector<Other>& vec)
00132                 {
00133                     const ana::ana_uint32 size(vec.size());
00134                     (*this) << size;
00135                     for (size_t i(0); i < size; ++i)
00136                         (*this) << vec[i];
00137 
00138                     return *this;
00139                 }
00140 
00141                 /** Insert a literal string. */
00142                 bostream& operator<< (const char* cs)
00143                 {
00144                     const std::string s(cs);
00145                     return operator<< (s);
00146                 }
00147 
00148                 /** Obtain the string representing the stream. */
00149                 const std::string& str() const
00150                 {
00151                     return _s;
00152                 }
00153 
00154                 /** Clear the stream. Enables the user to use it several times. */
00155                 void clear()
00156                 {
00157                     _s.clear();
00158                 }
00159 
00160             private:
00161 
00162                 /** The representation of the stream in memory. */
00163                 std::string _s;
00164         };
00165 
00166         /**
00167          * Input stream serialization. This class provides stream functionality to serialize
00168          * objects in a way similar to that of std::cin or std::istringstream.
00169          *
00170          * Extracted from MiLi (mili.googlecode.com).
00171          *
00172          * An extensive example of its usage can be seen in:
00173          *    http://code.google.com/p/mili/source/browse/trunk/example_binary-streams.cpp
00174          */
00175         class bistream
00176         {
00177             private:
00178                 template<class T> friend class container_reader;
00179 
00180             public:
00181                 /**
00182                  * Construct a new input stream object using a string representing a binary stream
00183                  * as input.
00184                  */
00185                 bistream(const std::string& str) :
00186                     _s(str),
00187                     _pos(0)
00188                 {
00189                 }
00190 
00191                 /**
00192                  * Creates a new input stream object, but with no data.
00193                  */
00194                 bistream() :
00195                     _s(),
00196                     _pos(0)
00197                 {
00198                 }
00199 
00200                 /**
00201                  * Set the representation binary string.
00202                  *
00203                  * @param str : The new binary stream representation string.
00204                  */
00205                 void str(const std::string& str)
00206                 {
00207                     _pos = 0;
00208                     _s = str;
00209                 }
00210 
00211                 /**
00212                  * Read an element.
00213                  *
00214                  * @param x : A reference to the element you are reading into.
00215                  *
00216                  * @pre : The remaining input stream holds enough data to read the element.
00217                  */
00218                 template <class T>
00219                 bistream& operator >> (T& x)
00220                 {
00221                     assert(_s.size() >= _pos + sizeof(x));
00222                     _pos += _s.copy(reinterpret_cast<char*>(&x), sizeof(x),_pos);
00223                     return *this;
00224                 }
00225 
00226                 /**
00227                  * Read a string.
00228                  *
00229                  * @param str : A reference to the string you are reading into.
00230                  *
00231                  * @pre : The stream is situated in a position holding a 32 bit unsigned integer
00232                  *        and then at least this very number of bytes remain.
00233                  */
00234                 bistream& operator >> (std::string& str)
00235                 {
00236                     ana::ana_uint32 size;
00237                     (*this) >> size;
00238                     assert(_s.size() >= size+_pos);
00239                     str  = _s.substr(_pos,size);
00240                     _pos += size;
00241                     return *this;
00242                 }
00243 
00244                 /**
00245                  * Read a vector.
00246                  *
00247                  * @param vec : A reference to the vector you are reading into.
00248                  *
00249                  * @pre : The stream is situated in a position holding a 32 bit unsigned integer
00250                  *        and then at least this very number of elements remain.
00251                  */
00252                 template <class Other>
00253                 bistream& operator>> (std::vector<Other>& vec)
00254                 {
00255                     ana::ana_uint32 size;
00256                     (*this) >> size;
00257                     assert(_s.size() >= (size * sizeof(Other)) + _pos);
00258                     vec.resize(size);
00259                     for (size_t i(0); i < size; i++)
00260                         (*this) >> vec[i];
00261 
00262                     return *this;
00263                 }
00264 
00265                 /** Clear the input stream. */
00266                 void clear()
00267                 {
00268                     _s.clear();
00269                     _pos = 0;
00270                 }
00271 
00272             private:
00273 
00274                 /** The string representing the input stream. */
00275                 std::string _s;
00276 
00277                 /** The position the stream is reading from.  */
00278                 std::size_t _pos;
00279         };
00280 
00281         /**
00282          * A helper class to insert containers from single elements. Use this when you know that
00283          * the data will later be read into a vector or some other container but you don't have
00284          * such a container for insertion, you want to create it on the go.
00285          *
00286          * @param T : The type of the elements in the container.
00287          */
00288         template<class T>
00289         class container_writer
00290         {
00291             public:
00292 
00293                 /**
00294                  * Default constructor.
00295                  *
00296                  * @param size : The amount of elements you will write.
00297                  * @param bos : A reference to the output stream where you will create the
00298                  *              container.
00299                  */
00300                 container_writer( size_t size, bostream& bos) :
00301                     _elements_left( size ),
00302                     _bos( bos )
00303                 {
00304                     _bos << ana::ana_uint32( size );
00305                 }
00306 
00307                 /**
00308                  * Push an element.
00309                  */
00310                 container_writer& operator<<(T element)
00311                 {
00312                     assert( _elements_left > 0 );
00313                     --_elements_left;
00314 
00315                     _bos << element;
00316 
00317                     return *this;
00318                 }
00319 
00320                 /**
00321                  * Default destructor.
00322                  *
00323                  * @pre : The elements inserted equals the amount of elements that were promised
00324                  *        to be inserted at the time of creation (size parameter.)
00325                  */
00326                 ~container_writer()
00327                 {
00328                     if ( _elements_left != 0 )
00329                         throw/* std::runtime_error*/("More elements were expected to be written.");
00330                 }
00331             private:
00332 
00333                 /** The amount of elements you have yet to insert. */
00334                 size_t    _elements_left;
00335 
00336                 /** A reference to the output stream. */
00337                 bostream& _bos;
00338         };
00339 
00340         /**
00341          * A helper class to read from containers one by one. Use this when you want to read
00342          * something inserted as a container one by one, you can also use it to know how many
00343          * elements were inserted.
00344          *
00345          * @param T : The type of the elements in the container.
00346          */
00347         template<class T>
00348         class container_reader
00349         {
00350             public:
00351                 /**
00352                  * Standard constructor.
00353                  *
00354                  * @param bis : The input stream holding the data.
00355                  */
00356                 container_reader( bistream& bis) :
00357                     _elements_left( 0 ),
00358                     _bis( bis )
00359                 {
00360                     _bis >> _elements_left;
00361                 }
00362 
00363                 /**
00364                  * Read an element.
00365                  */
00366                 container_reader& operator>>(T& element)
00367                 {
00368                     assert( _elements_left > 0 );
00369                     --_elements_left;
00370 
00371                     _bis >> element;
00372 
00373                     return *this;
00374                 }
00375 
00376                 /**
00377                  * Skip a given amount of elements, default: 1.
00378                  *
00379                  * Examples:
00380                  *    - skip();
00381                  *    - skip(10);
00382                  *
00383                  * @param elements : The amount of elements you want to skip. Default: 1.
00384                  *
00385                  * @pre : At least the amount of elements you want to skip remain.
00386                  */
00387                 void skip(size_t elements = 1)
00388                 {
00389                     if ( elements > _elements_left )
00390                         throw("Trying to skip too much.");
00391 
00392                     _elements_left -= elements;
00393 
00394                     _bis._pos += sizeof(T) * elements;
00395 
00396                     if ( _bis._pos > _bis._s.size() )
00397                         throw("Too much mas skipped.");
00398                 }
00399 
00400                 /**
00401                  * Signal that you have finished reading. It is the same as skipping the amount
00402                  * of elements left.
00403                  */
00404                 void finished()
00405                 {
00406                     skip( _elements_left );
00407                     _elements_left = 0;
00408                 }
00409 
00410                 /**
00411                  * Returns the amount of elements that still haven't been read from the container.
00412                  */
00413                 size_t elements_left() const
00414                 {
00415                     return _elements_left;
00416                 }
00417 
00418                 /**
00419                  * Standard destructor. Finishes the reading process if necessary.
00420                  */
00421                 ~container_reader()
00422                 {
00423                     if ( _elements_left != 0 )
00424                         finished();
00425                 }
00426 
00427             private:
00428 
00429                 /** The amount of elements that still haven't been read from the container. */
00430                 size_t    _elements_left;
00431 
00432                 /** A reference to the input stream. */
00433                 bistream& _bis;
00434         };
00435 
00436         /// @cond false
00437         template<class T>
00438         struct bostream::_inserter_helper<T, false>
00439         {
00440             static void call(bostream* bos, const T& x)
00441             {
00442                 bos->_s.append(reinterpret_cast<const char*>(&x), sizeof(T));
00443             }
00444         };
00445 
00446         template<class T>
00447         struct bostream::_inserter_helper<T, true>
00448         {
00449             static void call(bostream* bos, const T& cont)
00450             {
00451                 const ana::ana_uint32 size(cont.size());
00452                 (*bos) << size;
00453 
00454                 typename T::const_iterator it( cont.begin() );
00455 
00456                 for (; it != cont.end(); ++it)
00457                     (*bos) << *it;
00458             }
00459         };
00460         /// @endcond
00461 
00462     } //serializer namespace
00463 } //ana namespace
00464 
00465 #endif
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines

Generated by doxygen 1.7.1 on Wed May 23 2012 01:02:33 for The Battle for Wesnoth
Gna! | Forum | Wiki | CIA | devdocs