Wisp 1.2.1 C++ Unit Test Coverage
Current view: top level - ssrc/wisp - serialization.h (source / functions) Hit Total Coverage
Test: Wisp 1.2.1 C++ Unit Tests Lines: 67 68 98.5 %
Date: 2011-05-11 Functions: 40 41 97.6 %
Branches: 80 160 50.0 %

           Branch data     Line data    Source code
       1                 :            : /*
       2                 :            :  * Copyright 2006-2008 Savarese Software Research Corporation
       3                 :            :  *
       4                 :            :  * Licensed under the Apache License, Version 2.0 (the "License");
       5                 :            :  * you may not use this file except in compliance with the License.
       6                 :            :  * You may obtain a copy of the License at
       7                 :            :  *
       8                 :            :  *     http://www.savarese.com/software/ApacheLicense-2.0
       9                 :            :  *
      10                 :            :  * Unless required by applicable law or agreed to in writing, software
      11                 :            :  * distributed under the License is distributed on an "AS IS" BASIS,
      12                 :            :  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
      13                 :            :  * See the License for the specific language governing permissions and
      14                 :            :  * limitations under the License.
      15                 :            :  */
      16                 :            : 
      17                 :            : /**
      18                 :            :  * @file
      19                 :            :  * This header defines serialization support classes and functions.
      20                 :            :  */
      21                 :            : 
      22                 :            : #ifndef __SSRC_WISP_SERIALIZATION_H
      23                 :            : #define __SSRC_WISP_SERIALIZATION_H
      24                 :            : 
      25                 :            : #include <ssrc/wisp-packages.h>
      26                 :            : #include <ssrc/spread/detail/ByteBuffer.h>
      27                 :            : 
      28                 :            : #include <utility>
      29                 :            : 
      30                 :            : #include <boost/iostreams/stream.hpp>
      31                 :            : #include <boost/iostreams/device/array.hpp>
      32                 :            : 
      33                 :            : #include <boost/archive/binary_iarchive.hpp>
      34                 :            : #include <boost/archive/binary_oarchive.hpp>
      35                 :            : 
      36                 :            : #include <boost/serialization/split_free.hpp>
      37                 :            : #include <boost/serialization/binary_object.hpp>
      38                 :            : 
      39                 :            : /**
      40                 :            :  * Opens the boost::serialization namespace so you can add custom serialize
      41                 :            :  * functions.  Close the serialize function definition block with
      42                 :            :  * __END_BOOST_SERIALIZATION.
      43                 :            :  */
      44                 :            : #define __BEGIN_BOOST_SERIALIZATION \
      45                 :            : namespace boost { \
      46                 :            :   namespace serialization { 
      47                 :            : 
      48                 :            : /**
      49                 :            :  * Closes the boost::serialization namespace started with
      50                 :            :  * __BEGIN_BOOST_SERIALIZATION.
      51                 :            :  */
      52                 :            : #define __END_BOOST_SERIALIZATION \
      53                 :            :   } \
      54                 :            : }
      55                 :            : 
      56                 :            : __BEGIN_NS_SSRC_WISP
      57                 :            : 
      58                 :            : using NS_SSRC_SPREAD::detail::ByteBuffer;
      59                 :            : 
      60                 :            : namespace detail {
      61                 :            :   /**
      62                 :            :    * This is a Boost iostreams direct device whose begin and end
      63                 :            :    * pointers can be modified.  Unfortunately, Boost iostreams stream
      64                 :            :    * buffers make their own copies of the pointers.  Therefore, even
      65                 :            :    * after resetting the device pointers, you have to reopen the
      66                 :            :    * stream buffer.
      67                 :            :    */
      68                 :            :   template<typename Ch, typename mode_type = boost::iostreams::seekable>
      69                 :        165 :   class array_device_adapter {
      70                 :            :   public:
      71                 :            :     typedef Ch char_type;
      72                 :            :     typedef std::pair<char_type*, char_type*>  pair_type;
      73                 :            : 
      74                 :        330 :     struct category :
      75                 :            :       public mode_type,
      76                 :            :       public boost::iostreams::device_tag,
      77                 :            :       public boost::iostreams::direct_tag
      78                 :            :     { };
      79                 :            : 
      80                 :            :   private:
      81                 :            :     char_type *_begin, *_end;
      82                 :            : 
      83                 :            :   public:
      84                 :            : 
      85                 :         26 :     array_device_adapter() : _begin(0), _end(0) { }
      86                 :            : 
      87                 :            :     array_device_adapter(char_type* begin, char_type* end) :
      88                 :            :       _begin(begin), _end(end)
      89                 :            :     { }
      90                 :            : 
      91                 :            :     array_device_adapter(char_type* begin, std::size_t size) :
      92                 :            :       _begin(begin), _end(begin + size)
      93                 :            :     { }
      94                 :            : 
      95                 :            :     void init(char_type* begin, char_type* end) {
      96                 :            :       _begin = begin;
      97                 :            :       _end   = end;
      98                 :            :     }
      99                 :            : 
     100                 :        165 :     void init(char_type* begin, std::size_t size) {
     101                 :        165 :       _begin = begin;
     102                 :        165 :       _end   = begin + size;
     103                 :        165 :     }
     104                 :            : 
     105                 :            :     void set_size(std::size_t size) {
     106                 :            :       _end = _begin + size;
     107                 :            :     }
     108                 :            : 
     109                 :        165 :     pair_type input_sequence() {
     110                 :        165 :       return pair_type(_begin, _end);
     111                 :            :     }
     112                 :            : 
     113                 :        165 :     pair_type output_sequence() {
     114                 :        165 :       return pair_type(_begin, _end);
     115                 :            :     }
     116                 :            :   };
     117                 :            : 
     118                 :            :   typedef array_device_adapter<char> char_array_source;
     119                 :            :   typedef array_device_adapter<char> char_array_sink;
     120                 :            : 
     121                 :            :   // This class is an unfortunately required workaround for a change
     122                 :            :   // and possible bug in Boost 1.42.0 which causes stream_buffer::open to
     123                 :            :   // throw an "already open" exception even if the buffer has been closed.
     124                 :            :   template<typename DeviceAdapter>
     125 [ -  + ][ -  + ]:         52 :   struct char_array_streambuf :
     126                 :            :     public boost::iostreams::stream_buffer<DeviceAdapter>
     127                 :            :   {
     128                 :            :     typedef boost::iostreams::stream_buffer<DeviceAdapter> super;
     129                 :            :     typedef
     130                 :            :     boost::iostreams::detail::direct_streambuf<DeviceAdapter,
     131                 :            :                                                typename super::traits_type>
     132                 :            :     direct_streambuf;
     133                 :            : 
     134                 :        165 :     void open(const DeviceAdapter & device_adapter) {
     135                 :        165 :       direct_streambuf::open(device_adapter, 0, 0);
     136                 :        165 :     }
     137                 :            :   };
     138                 :            : 
     139                 :            :   typedef char_array_streambuf<char_array_source> char_array_source_buffer;
     140                 :            :   typedef char_array_streambuf<char_array_sink> char_array_sink_buffer;
     141                 :            : }
     142                 :            : 
     143                 :            : /**
     144                 :            :  * Packer serializes objects into ssrc::spread::detail::ByteBuffer instances
     145                 :            :  * (usually a ssrc::spread::Message instance).  Each object type must have
     146                 :            :  * a Boost serialize function or method defined (or load and save).
     147                 :            :  *
     148                 :            :  * @param Archive The archive type to use for serialization.
     149                 :            :  */
     150                 :            : template<typename Archive>
     151                 :         26 : class Packer {
     152                 :            : public:
     153                 :            :   typedef detail::char_array_sink sink_type; 
     154                 :            :   typedef detail::char_array_sink_buffer sink_buffer;
     155                 :            :   typedef Archive output_archive;
     156                 :            : 
     157                 :            : protected:
     158                 :            :   sink_type _sink;
     159                 :            :   sink_buffer _out_buf;
     160                 :            : 
     161                 :            : public:
     162                 :            : 
     163                 :            :   /**
     164                 :            :    * Serializes an object into a buffer.  The type of the object is
     165                 :            :    * automatically inferred by the compiler.  The object write starts
     166                 :            :    * at the current buffer offset.  After the object is serialized,
     167                 :            :    * the buffer size is adjusted and its write offset advanced to the
     168                 :            :    * end of the buffer.  The buffer must have enough room to hold the
     169                 :            :    * data written or an exception will be thrown (std::ios_base::failure).
     170                 :            :    *
     171                 :            :    * @param obj The object to serialize.
     172                 :            :    * @param buffer The buffer that will store the object.
     173                 :            :    * @param archive_flags Boost archive constructor flags.
     174                 :            :    * @return The number of bytes written.
     175                 :            :    * @throw boost::archive::archive_exception If there is an archive
     176                 :            :    *        writing error.
     177                 :            :    * @throw std::ios_base::failure If the stream buffer fails, most
     178                 :            :    *        likely because the buffer doesn't have enough room to hold the
     179                 :            :    *        data.
     180                 :            :    */
     181                 :            :   template<typename T>
     182                 :         79 :   unsigned int pack(const T & obj, ByteBuffer & buffer,
     183                 :            :                     const unsigned int archive_flags =
     184                 :            :                     boost::archive::no_header | boost::archive::no_codecvt |
     185                 :            :                     boost::archive::no_tracking)
     186                 :            :     SSRC_DECL_THROW(boost::archive::archive_exception, std::ios_base::failure)
     187                 :            :   {
     188                 :            :     unsigned int offset, bytes_written;
     189                 :            : 
     190                 :         79 :     _sink.init(&buffer[0], buffer.capacity());
     191                 :         79 :     _out_buf.open(_sink);
     192                 :         79 :     _out_buf.pubseekoff(buffer.offset(), std::basic_ios<sink_buffer>::beg);
     193                 :            : 
     194                 :        158 :     output_archive out_ar(_out_buf, archive_flags);
     195   [ +  -  +  -  :         79 :     out_ar << obj;
          +  -  +  -  +  
             -  +  -  +  
                      - ]
     196                 :            : 
     197 [ +  - ][ +  - ]:         79 :     offset = _out_buf.pubseekoff(0, std::basic_ios<sink_buffer>::cur);
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
                 [ +  - ]
     198                 :         79 :     bytes_written = offset - buffer.offset();
     199   [ +  -  +  -  :         79 :     buffer.resize(offset);
          +  -  +  -  +  
             -  +  -  +  
                      - ]
     200 [ +  - ][ +  - ]:         79 :     buffer.seek(offset);
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
                 [ +  - ]
     201                 :            : 
     202                 :         79 :     return bytes_written;
     203                 :            :   }
     204                 :            : };
     205                 :            : 
     206                 :            : /**
     207                 :            :  * Unpacker deserializes objects from ssrc::spread::detail::ByteBuffer
     208                 :            :  * instances (usually a ssrc::spread::Message instance).  Each object
     209                 :            :  * type must have a Boost serialize function or method defined (or load
     210                 :            :  * and save).
     211                 :            :  *
     212                 :            :  * @param Archive The archive type to use for serialization.
     213                 :            :  */
     214                 :            : template<typename Archive>
     215                 :         26 : class Unpacker {
     216                 :            : public:
     217                 :            :   typedef detail::char_array_source source_type; 
     218                 :            :   typedef detail::char_array_sink_buffer source_buffer;
     219                 :            :   typedef Archive input_archive;
     220                 :            : 
     221                 :            : protected:
     222                 :            :   source_type _source;
     223                 :            :   source_buffer _in_buf;
     224                 :            : 
     225                 :            : public:
     226                 :            : 
     227                 :            :   /**
     228                 :            :    * Deserializes an object from a buffer.  The type of the object is
     229                 :            :    * automatically inferred by the compiler.  The object read starts
     230                 :            :    * at the current buffer offset.  After the object is deserialized,
     231                 :            :    * the buffer offset is adjusted and its read offset advanced to the
     232                 :            :    * end of the data read.
     233                 :            :    *
     234                 :            :    * @param obj The deserialization target.
     235                 :            :    * @param buffer The buffer storing the serialized object.
     236                 :            :    * @param archive_flags Boost archive constructor flags.
     237                 :            :    * @return The number of bytes read.
     238                 :            :    * @throw boost::archive::archive_exception If there is an archive
     239                 :            :    *        read error.
     240                 :            :    * @throw std::ios_base::failure If the stream buffer fails.
     241                 :            :    */
     242                 :            :   template<typename T>
     243                 :         84 :   unsigned int unpack(T & obj, ByteBuffer & buffer,
     244                 :            :                       const unsigned int archive_flags =
     245                 :            :                       boost::archive::no_header | boost::archive::no_codecvt |
     246                 :            :                       boost::archive::no_tracking)
     247                 :            :     SSRC_DECL_THROW(boost::archive::archive_exception, std::ios_base::failure)
     248                 :            :   {
     249                 :         84 :     unsigned int bytes_read(0);
     250                 :            : 
     251 [ +  - ][ +  - ]:         84 :     if(buffer.size() > 0) {
         [ +  - ][ +  - ]
     252                 :            :       unsigned int offset;
     253                 :            : 
     254                 :         84 :       _source.init(&buffer[0], buffer.size());
     255                 :         84 :       _in_buf.open(_source);
     256                 :         84 :       _in_buf.pubseekoff(buffer.offset(), std::basic_ios<source_buffer>::beg);
     257                 :            : 
     258                 :        168 :       input_archive in_ar(_in_buf, archive_flags);
     259   [ +  -  +  -  :         84 :       in_ar >> obj;
             +  -  +  - ]
     260                 :            : 
     261 [ +  - ][ +  - ]:         84 :       offset = _in_buf.pubseekoff(0, std::basic_ios<source_buffer>::cur);
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
     262                 :         84 :       bytes_read = offset - buffer.offset();
     263   [ +  -  +  -  :         84 :       buffer.seek(offset);
             +  -  +  - ]
     264                 :            :     }
     265                 :            : 
     266                 :         84 :     return bytes_read;
     267                 :            :   }
     268                 :            : 
     269                 :            : 
     270                 :            :   /**
     271                 :            :    * Deserializes an object from a void * buffer.  The type of the object is
     272                 :            :    * automatically inferred by the compiler.  We use this method primarily
     273                 :            :    * to unpack serialized objects from blobs without copying the buffer first.
     274                 :            :    *
     275                 :            :    * @param obj The deserialization target.
     276                 :            :    * @param buffer The buffer storing the serialized object.
     277                 :            :    * @param size The number of bytes in the buffer.
     278                 :            :    * @param archive_flags Boost archive constructor flags.
     279                 :            :    * @return The number of bytes read.
     280                 :            :    * @throw boost::archive::archive_exception If there is an archive
     281                 :            :    *        read error.
     282                 :            :    * @throw std::ios_base::failure If the stream buffer fails.
     283                 :            :    */
     284                 :            :   template<typename T>
     285                 :          2 :   unsigned int unpack(T & obj, const void *buffer, unsigned int size,
     286                 :            :                       const unsigned int archive_flags =
     287                 :            :                       boost::archive::no_header | boost::archive::no_codecvt |
     288                 :            :                       boost::archive::no_tracking)
     289                 :            :     SSRC_DECL_THROW(boost::archive::archive_exception, std::ios_base::failure)
     290                 :            :   {
     291                 :          2 :     unsigned int bytes_read(0);
     292                 :            : 
     293 [ +  - ][ +  - ]:          2 :     if(size > 0) {
     294                 :          2 :       _source.init(static_cast<typename detail::char_array_source::char_type *>(const_cast<void *>(buffer)), size);
     295                 :          2 :       _in_buf.open(_source);
     296                 :          2 :       _in_buf.pubseekoff(0, std::basic_ios<source_buffer>::beg);
     297                 :            : 
     298                 :          4 :       input_archive in_ar(_in_buf, archive_flags);
     299   [ +  -  +  - ]:          2 :       in_ar >> obj;
     300                 :            : 
     301 [ +  - ][ +  - ]:          2 :       bytes_read = _in_buf.pubseekoff(0, std::basic_ios<source_buffer>::cur);
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
     302                 :            :     }
     303                 :            : 
     304                 :          2 :     return bytes_read;
     305                 :            :   }
     306                 :            : };
     307                 :            : 
     308                 :            : template<typename P, typename U>
     309                 :            : struct PackingTraits {
     310                 :            :   typedef P packer_type;
     311                 :            :   typedef U unpacker_type;
     312                 :            : };
     313                 :            : 
     314                 :            : typedef Packer<boost::archive::binary_oarchive> BinaryPacker;
     315                 :            : typedef Unpacker<boost::archive::binary_iarchive> BinaryUnpacker;
     316                 :            : typedef PackingTraits<BinaryPacker, BinaryUnpacker> BinaryPackingTraits;
     317                 :            : 
     318                 :            : __END_NS_SSRC_WISP
     319                 :            : 
     320                 :            : __BEGIN_BOOST_SERIALIZATION
     321                 :            : 
     322                 :            : template<class Archive>
     323                 :            : inline
     324                 :            : void save_construct_data(Archive & ar,
     325                 :            :                          const NS_SSRC_SPREAD::detail::ByteBuffer *buffer,
     326                 :            :                          const unsigned int)
     327                 :            : {
     328                 :            :   // Could use capacity, but lets keep it as small as we can.
     329                 :            :   ar << buffer->size();
     330                 :            : }
     331                 :            : 
     332                 :            : template<class Archive>
     333                 :            : inline
     334                 :            : void load_construct_data(Archive & ar,
     335                 :            :                          NS_SSRC_SPREAD::detail::ByteBuffer *buffer,
     336                 :            :                          const unsigned int)
     337                 :            : {
     338                 :            :   unsigned int capacity;
     339                 :            : 
     340                 :            :   ar >> capacity;
     341                 :            :   ::new(buffer)NS_SSRC_SPREAD::detail::ByteBuffer(capacity);
     342                 :            : }
     343                 :            : 
     344                 :            : template<class Archive>
     345                 :          3 : inline void save(Archive & ar,
     346                 :            :                  const NS_SSRC_SPREAD::detail::ByteBuffer & buffer,
     347                 :            :                  const unsigned int)
     348                 :            : {
     349                 :          3 :   unsigned int size = buffer.size();
     350                 :            : 
     351                 :          3 :   ar & size;
     352                 :            : 
     353         [ +  - ]:          3 :   if(size > 0) {
     354                 :          3 :     const binary_object obj(&buffer[0], size);
     355                 :          3 :     unsigned int offset = buffer.offset();
     356                 :          3 :     ar & offset & obj;
     357                 :            :   }
     358                 :          3 : }
     359                 :            : 
     360                 :            : template<class Archive>
     361                 :          2 : inline void load(Archive & ar,
     362                 :            :                  NS_SSRC_SPREAD::detail::ByteBuffer & buffer,
     363                 :            :                  const unsigned int)
     364                 :            : {
     365                 :            :   unsigned int size;
     366                 :            : 
     367                 :          2 :   ar & size;
     368                 :            : 
     369                 :          2 :   buffer.resize(size);
     370                 :            : 
     371         [ +  - ]:          2 :   if(size > 0) {
     372                 :          2 :     binary_object obj(&buffer[0], size);
     373                 :            :     unsigned int offset;
     374                 :          2 :     ar & offset & obj;
     375                 :          2 :     buffer.seek(offset);
     376                 :            :   } else
     377                 :          0 :     buffer.rewind();
     378                 :          2 : }
     379                 :            : 
     380                 :            : __END_BOOST_SERIALIZATION
     381                 :            : 
     382                 :          5 : BOOST_SERIALIZATION_SPLIT_FREE(NS_SSRC_SPREAD::detail::ByteBuffer)
     383                 :            : 
     384                 :            : #endif