LCOV - code coverage report
Current view: directory - src/shared/serialization - serialization.h (source / functions) Found Hit Coverage
Test: coverage.lcov Lines: 138 115 83.3 %
Date: 2014-12-17 Functions: 0 0 -

       1                 : /* -*- c++ -*- */
       2                 : /*
       3                 :  * Copyright (c) 2013 The Native Client Authors. All rights reserved.
       4                 :  * Use of this source code is governed by a BSD-style license that can be
       5                 :  * found in the LICENSE file.
       6                 :  */
       7                 : 
       8                 : #ifndef NATIVE_CLIENT_SRC_SHARED_SERIALIZATION_SERIALIZATION_H_
       9                 : #define NATIVE_CLIENT_SRC_SHARED_SERIALIZATION_SERIALIZATION_H_
      10                 : 
      11                 : #include <vector>
      12                 : #include <string>
      13                 : 
      14                 : #include "native_client/src/include/portability.h"
      15                 : #include "native_client/src/include/nacl_compiler_annotations.h"
      16                 : #include "native_client/src/shared/platform/nacl_check.h"
      17                 : 
      18                 : // SerializationBuffer enables serializing basic types and vectors
      19                 : 
      20                 : namespace nacl {
      21                 : 
      22                 : class SerializationBuffer;
      23                 : 
      24                 : template<typename T> class SerializationTraits;
      25                 : 
      26                 : enum {
      27                 :   kIllegalTag = -1,
      28                 : 
      29                 :   kUint8 = 0,
      30                 :   kInt8 = 1,
      31                 :   kUint16 = 2,
      32                 :   kInt16 = 3,
      33                 :   kUint32 = 4,
      34                 :   kInt32 = 5,
      35                 :   kUint64 = 6,
      36                 :   kInt64 = 7,
      37                 : 
      38                 :   kCString = 11,
      39                 :   kString = 12,
      40                 : 
      41                 :   kRecursiveVector = 31,
      42                 :   kVectorOffset = 32
      43                 : };
      44                 : 
      45                 : class SerializationBuffer {
      46                 :  public:
      47                 :   SerializationBuffer();
      48                 : 
      49                 :   // This initializes the Serialization buffer from |data_buffer|
      50                 :   // containing |nbytes| of data.  A copy of the data is made rather
      51                 :   // than transferring ownership, which is suboptimal.
      52                 :   SerializationBuffer(uint8_t const *data_buffer, size_t nbytes);
      53                 : 
      54                 :   template<typename T> bool Serialize(T basic) NACL_WUR;
      55                 : 
      56                 :   template<typename T> bool Serialize(std::vector<T> const& v) NACL_WUR;
      57                 : 
      58                 :   bool Serialize(char const *cstr) NACL_WUR;
      59                 :   bool Serialize(char const *cstr, size_t char_count) NACL_WUR;
      60                 : 
      61                 :   bool Serialize(std::string str) NACL_WUR;
      62                 : 
      63               1 :   int ReadTag() {
      64               1 :     if (bytes_unread() < kTagBytes) {
      65               0 :       return kIllegalTag;
      66                 :     }
      67               1 :     return buffer_[read_ix_++];
      68               1 :   }
      69                 : 
      70                 :   template<typename T> bool Deserialize(T *basic) NACL_WUR;
      71                 : 
      72                 :   template<typename T> bool Deserialize(std::vector<T> *v) NACL_WUR;
      73                 : 
      74                 :   // This function deserializes into the provided buffer at |cstr|.
      75                 :   // The parameter *buffer_size is an in-out parameter, initially
      76                 :   // containing the available space at |cstr|.  If there are decoding
      77                 :   // errors, this function returns false.  If it returns true, the
      78                 :   // caller should check *buffer_size -- if there were insufficient
      79                 :   // space, the read position is unchanged and *buffer_size is updated
      80                 :   // to reflect the amount of space that is required; otherwise
      81                 :   // *buffer_size is updated to reflect the actual number of bytes
      82                 :   // written to |cstr|.
      83                 :   bool Deserialize(char *cstr, size_t *buffer_size) NACL_WUR;
      84                 :   // caller provides buffer
      85                 : 
      86                 :   // This method deserializes a NUL-terminated C-style string.  The
      87                 :   // caller receives ownnership of the memory allocated via new[] and
      88                 :   // is responsible for delete[]ing it to release the storage.
      89                 :   bool Deserialize(char **cstr_out) NACL_WUR;
      90                 : 
      91                 :   bool Deserialize(std::string *str) NACL_WUR;
      92                 : 
      93               1 :   size_t num_bytes() const {
      94               1 :     return in_use_;
      95               1 :   }
      96                 : 
      97               1 :   uint8_t const *data() const {
      98                 :     // return buffer_.data();  // C++11 only, not available on windows
      99               1 :     return &buffer_[0];
     100               1 :   }
     101                 : 
     102               1 :   void rewind() {
     103               1 :     read_ix_ = 0;
     104               1 :   }
     105                 : 
     106               1 :   void reset() {
     107               1 :     in_use_ = 0;
     108               1 :     buffer_.clear();
     109               1 :     nbytes_ = 0;
     110               1 :     read_ix_ = 0;
     111               1 :   }
     112                 : 
     113                 :   static const size_t kTagBytes = 1;
     114                 : 
     115                 :  protected:
     116                 :   template<typename T> void AddTag();
     117                 : 
     118                 :   template<typename T> bool CheckTag();
     119                 : 
     120                 :   void AddUint8(uint8_t value);
     121                 :   void AddUint16(uint16_t value);
     122                 :   void AddUint32(uint32_t value);
     123                 :   void AddUint64(uint64_t value);
     124                 : 
     125                 :   bool GetUint8(uint8_t *val);
     126                 :   bool GetUint16(uint16_t *val);
     127                 :   bool GetUint32(uint32_t *val);
     128                 :   bool GetUint64(uint64_t *val);
     129                 : 
     130               8 :   template<typename T> void AddVal(T value) {
     131                 :     int T_must_be_integral_type[static_cast<T>(1)];
     132                 :     UNREFERENCED_PARAMETER(T_must_be_integral_type);
     133               8 :     if (sizeof(T) == 1) {
     134               2 :       AddUint8(static_cast<uint8_t>(value));
     135               6 :     } else if (sizeof(T) == 2) {
     136               2 :       AddUint16(static_cast<uint16_t>(value));
     137               4 :     } else if (sizeof(T) == 4) {
     138               2 :       AddUint32(static_cast<uint32_t>(value));
     139               2 :     } else if (sizeof(T) == 8) {
     140               2 :       AddUint64(static_cast<uint64_t>(value));
     141                 :     }
     142               8 :   }
     143                 : 
     144               8 :   template<typename T> bool GetVal(T *basic) {
     145                 :     int T_must_be_integral_type[static_cast<T>(1)];
     146                 :     UNREFERENCED_PARAMETER(T_must_be_integral_type);
     147               8 :     if (sizeof(T) == 1) {
     148                 :       uint8_t val;
     149               2 :       return GetUint8(&val) ? ((*basic = static_cast<T>(val)), true) : false;
     150               6 :     } else if (sizeof(T) == 2) {
     151                 :       uint16_t val;
     152               2 :       return GetUint16(&val) ? ((*basic = static_cast<T>(val)), true) : false;
     153               4 :     } else if (sizeof(T) == 4) {
     154                 :       uint32_t val;
     155               2 :       return GetUint32(&val) ? ((*basic = static_cast<T>(val)), true) : false;
     156               2 :     } else if (sizeof(T) == 8) {
     157                 :       uint64_t val;
     158               2 :       return GetUint64(&val) ? ((*basic = static_cast<T>(val)), true) : false;
     159                 :     }
     160               0 :     return false;
     161               8 :   }
     162                 : 
     163                 :   template<typename T, bool nested_tagging>
     164                 :   bool Serialize(std::vector<T> const& v);
     165                 : 
     166                 :   // Template metaprogramming to determine at compile time, based on
     167                 :   // whether the type T is a container type or not, whether to tag the
     168                 :   // elements with their own type tag, or to just write the elements
     169                 :   // sans type tag.  For vector containers of simple types such as
     170                 :   // int8_t, tagging every byte is excessive overhead.  NB: see the
     171                 :   // definition below of kTag for vectors.
     172                 :   template<typename T, bool nested_tagging> class SerializeHelper {
     173                 :    public:
     174                 :     static bool DoSerialize(SerializationBuffer *buf,
     175               2 :                             std::vector<T> const& v) {
     176               2 :       size_t orig = buf->cur_write_pos();
     177               2 :       size_t num_elt = v.size();
     178               2 :       if (num_elt > ~(uint32_t) 0) {
     179               0 :         return false;
     180                 :       }
     181               2 :       buf->AddTag<std::vector<T> >();
     182               2 :       buf->AddVal(static_cast<uint32_t>(num_elt));
     183                 : 
     184               2 :       for (size_t ix = 0; ix < v.size(); ++ix) {
     185               2 :         if (!buf->Serialize(v[ix])) {
     186               0 :           buf->reset_write_pos(orig);
     187               0 :           return false;
     188                 :         }
     189               2 :       }
     190               2 :       return true;
     191               2 :     }
     192                 :   };
     193                 : 
     194                 :   template<typename T> class SerializeHelper<T, false> {
     195                 :    public:
     196                 :     static bool DoSerialize(SerializationBuffer *buf,
     197               1 :                             std::vector<T> const& v) {
     198               1 :       size_t num_elt = v.size();
     199               1 :       if (num_elt > ~(uint32_t) 0) {
     200               0 :         return false;
     201                 :       }
     202               1 :       buf->AddTag<std::vector<T> >();
     203               1 :       buf->AddVal(static_cast<uint32_t>(num_elt));
     204                 : 
     205               1 :       for (size_t ix = 0; ix < v.size(); ++ix) {
     206               1 :         buf->AddVal(v[ix]);
     207               1 :       }
     208               1 :       return true;
     209               1 :     }
     210                 :   };
     211                 : 
     212                 :   template<typename T, bool b> friend class SerializeHelper;
     213                 : 
     214                 :   template<typename T, bool nested_tagging> class DeserializeHelper {
     215                 :    public:
     216                 :     static bool DoDeserialize(SerializationBuffer *buf,
     217               1 :                               std::vector<T> *v) {
     218               1 :       size_t orig = buf->cur_read_pos();
     219               1 :       if (buf->ReadTag() != SerializationTraits<std::vector<T> >::kTag) {
     220               0 :         buf->reset_read_pos(orig);
     221               0 :         return false;
     222                 :       }
     223                 :       uint32_t num_elt;
     224               1 :       if (!buf->GetVal(&num_elt)) {
     225               0 :         buf->reset_read_pos(orig);
     226               0 :         return false;
     227                 :       }
     228               1 :       for (size_t ix = 0; ix < num_elt; ++ix) {
     229               1 :         T val;
     230               1 :         if (!buf->Deserialize(&val)) {
     231               0 :           buf->reset_read_pos(orig);
     232               0 :           return false;
     233                 :         }
     234               1 :         v->push_back(val);
     235               1 :       }
     236               1 :       return true;
     237               1 :     }
     238                 :   };
     239                 : 
     240                 :   template<typename T> class DeserializeHelper<T, false> {
     241                 :    public:
     242                 :     static bool DoDeserialize(SerializationBuffer *buf,
     243               1 :                               std::vector<T> *v) {
     244               1 :       size_t orig = buf->cur_read_pos();
     245               1 :       if (buf->ReadTag() != SerializationTraits<std::vector<T> >::kTag) {
     246               0 :         buf->reset_read_pos(orig);
     247               0 :         return false;
     248                 :       }
     249                 :       uint32_t num_elt;
     250               1 :       if (!buf->GetVal(&num_elt)) {
     251               0 :         buf->reset_read_pos(orig);
     252               0 :         return false;
     253                 :       }
     254               1 :       for (size_t ix = 0; ix < num_elt; ++ix) {
     255                 :         T val;
     256               1 :         if (!buf->GetVal(&val)) {
     257               0 :           buf->reset_read_pos(orig);
     258               0 :           return false;
     259                 :         }
     260               1 :         v->push_back(val);
     261               1 :       }
     262               1 :       return true;
     263               1 :     }
     264                 :   };
     265                 : 
     266                 :   template<typename T, bool b> friend class DeserializeHelper;
     267                 : 
     268                 :   // TODO(bsy): consider doing something along the lines of
     269                 :   //
     270                 :   // template<typename T> Serialize(T stl_container) {
     271                 :   //   AddTag<T>();  // how?
     272                 :   //   for (T::const_iterator it = stl_container.begin();
     273                 :   //        it != stl_container.end();
     274                 :   //        ++it) {
     275                 :   //     Serialize(*it);
     276                 :   //     // Or AddVal, when SerializationTraits<T::value_type>::kNestedTag
     277                 :   //     // is false.
     278                 :   //   }
     279                 :   // }
     280                 :   //
     281                 :   // This means that the container type would probably be omitted or a
     282                 :   // generic stl_container type tag would be used -- or we'd have to
     283                 :   // enumerate all container types.
     284                 : 
     285                 :  private:
     286                 :   std::vector<uint8_t> buffer_;
     287                 :   size_t nbytes_;
     288                 :   size_t in_use_;
     289                 :   size_t read_ix_;
     290                 : 
     291                 :   void EnsureTotalSize(size_t req_size);
     292                 :   void EnsureAvailableSpace(size_t req_space);
     293                 : 
     294               1 :   size_t bytes_unread() const {
     295               1 :     return in_use_ - read_ix_;
     296               1 :   }
     297                 : 
     298               1 :   size_t cur_read_pos() const {
     299               1 :     return read_ix_;
     300               1 :   }
     301                 : 
     302               1 :   void reset_read_pos(size_t pos) {
     303               1 :     read_ix_ = pos;
     304               1 :   }
     305                 : 
     306               1 :   size_t cur_write_pos() const {
     307               1 :     return in_use_;
     308               1 :   }
     309                 : 
     310               0 :   void reset_write_pos(size_t pos) {
     311               0 :     in_use_ = pos;
     312               0 :   }
     313                 : };
     314                 : 
     315              13 : template<typename T> void SerializationBuffer::AddTag() {
     316              13 :   AddUint8(SerializationTraits<T>::kTag);
     317              13 : }
     318                 : 
     319               8 : template<typename T> bool SerializationBuffer::Serialize(T basic) {
     320               8 :   AddTag<T>();
     321               8 :   AddVal(basic);
     322               8 :   return true;
     323               8 : }
     324                 : 
     325                 : template<typename T> bool SerializationBuffer::Serialize(
     326               3 :     std::vector<T> const& v) {
     327                 :   return SerializeHelper<T, SerializationTraits<T>::kNestedTag>::
     328               3 :       DoSerialize(this, v);
     329               3 : }
     330                 : 
     331               8 : template<typename T> bool SerializationBuffer::Deserialize(T *basic) {
     332               8 :   size_t orig = cur_read_pos();
     333               8 :   if (bytes_unread() < kTagBytes + SerializationTraits<T>::kBytes) {
     334               1 :     return false;
     335                 :   }
     336                 :   uint8_t tag;
     337               8 :   if ((tag = ReadTag()) != SerializationTraits<T>::kTag) {
     338               0 :     reset_read_pos(orig);
     339               0 :     return false;
     340                 :   }
     341                 :   // if BytesAvail >= tag + serialization_size
     342               8 :   (void) GetVal(basic);
     343               8 :   return true;
     344               8 : }
     345                 : 
     346                 : template<typename T> bool SerializationBuffer::Deserialize(
     347               2 :     std::vector<T> *v) {
     348                 :   return DeserializeHelper<T, SerializationTraits<T>::kNestedTag>::
     349               2 :       DoDeserialize(this, v);
     350               2 : }
     351                 : 
     352                 : template<> class SerializationTraits<uint8_t> {
     353                 :  public:
     354                 :   static const int kTag = kUint8;
     355                 :   static const int kBytes = 1;
     356                 :   static const bool kNestedTag = false;
     357                 : };
     358                 : 
     359                 : template<> class SerializationTraits<int8_t> {
     360                 :  public:
     361                 :   static const int kTag = kInt8;
     362                 :   static const int kBytes = 1;
     363                 :   static const bool kNestedTag = false;
     364                 : };
     365                 : 
     366                 : template<> class SerializationTraits<uint16_t> {
     367                 :  public:
     368                 :   static const int kTag = kUint16;
     369                 :   static const int kBytes = 2;
     370                 :   static const bool kNestedTag = false;
     371                 : };
     372                 : 
     373                 : template<> class SerializationTraits<int16_t> {
     374                 :  public:
     375                 :   static const int kTag = kInt16;
     376                 :   static const int kBytes = 2;
     377                 :   static const bool kNestedTag = false;
     378                 : };
     379                 : 
     380                 : template<> class SerializationTraits<uint32_t> {
     381                 :  public:
     382                 :   static const int kTag = kUint32;
     383                 :   static const int kBytes = 4;
     384                 :   static const bool kNestedTag = false;
     385                 : };
     386                 : 
     387                 : template<> class SerializationTraits<int32_t> {
     388                 :  public:
     389                 :   static const int kTag = kInt32;
     390                 :   static const int kBytes = 4;
     391                 :   static const bool kNestedTag = false;
     392                 : };
     393                 : 
     394                 : template<> class SerializationTraits<uint64_t> {
     395                 :  public:
     396                 :   static const int kTag = kUint64;
     397                 :   static const int kBytes = 8;
     398                 :   static const bool kNestedTag = false;
     399                 : };
     400                 : 
     401                 : template<> class SerializationTraits<int64_t> {
     402                 :  public:
     403                 :   static const int kTag = kInt64;
     404                 :   static const int kBytes = 8;
     405                 :   static const bool kNestedTag = false;
     406                 : };
     407                 : 
     408                 : template<> class SerializationTraits<char *> {
     409                 :  public:
     410                 :   static const int kTag = kCString;
     411                 :   static const bool kNestedTag = true;
     412                 : };
     413                 : 
     414                 : template<> class SerializationTraits<std::string> {
     415                 :  public:
     416                 :   static const int kTag = kString;
     417                 :   static const bool kNestedTag = true;
     418                 : };
     419                 : 
     420                 : // We want the type tag for vector<T>, when the type T is a basic
     421                 : // type, to incorporate the type tag for T.  This way, we do not tag
     422                 : // each vector element (see SerializeHelper etc above), and yet the
     423                 : // type information is present.  When T is not a basic type (e.g., it
     424                 : // is a string, a vector<U>, or some other container to be added), we
     425                 : // don't want to just add the kVectorOffset to the type tag for T,
     426                 : // since deep nesting of containers could cause the tag to overflow.
     427                 : // Assuming that the type T nested containers are not empty, paying
     428                 : // the cost of tagging each element of the vector is not a huge
     429                 : // overhead.
     430                 : template<typename T> class SerializationTraits<std::vector<T> > {
     431                 :  private:
     432                 :   template<typename S, bool b> class RecursiveOrNotTag {
     433                 :    public:
     434                 :     static const int kVectorTag = kRecursiveVector;
     435                 :   };
     436                 :   template<typename S> class RecursiveOrNotTag<S, false> {
     437                 :    public:
     438                 :     static const int kVectorTag = kVectorOffset + SerializationTraits<S>::kTag;
     439                 :   };
     440                 :  public:
     441                 :   static const int kTag =
     442                 :       RecursiveOrNotTag<T, SerializationTraits<T>::kNestedTag>::kVectorTag;
     443                 :   static const bool kNestedTag = true;
     444                 : };
     445                 : 
     446                 : }  // namespace nacl
     447                 : 
     448                 : #endif

Generated by: LCOV version 1.7