Coverage for /Syzygy/core/serialization.h

CoverageLines executed / instrumented / missingexe / inst / missLanguageGroup
98.6%69700.C++source

Line-by-line coverage:

   1    :  // Copyright 2012 Google Inc. All Rights Reserved.
   2    :  //
   3    :  // Licensed under the Apache License, Version 2.0 (the "License");
   4    :  // you may not use this file except in compliance with the License.
   5    :  // You may obtain a copy of the License at
   6    :  //
   7    :  //     http://www.apache.org/licenses/LICENSE-2.0
   8    :  //
   9    :  // Unless required by applicable law or agreed to in writing, software
  10    :  // distributed under the License is distributed on an "AS IS" BASIS,
  11    :  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12    :  // See the License for the specific language governing permissions and
  13    :  // limitations under the License.
  14    :  //
  15    :  // Defines a set of simple serialization primitives.
  16    :  //
  17    :  // *** BASIC USAGE
  18    :  //
  19    :  // Serialization of a simple object works as follows:
  20    :  //
  21    :  //   Object object;
  22    :  //   FILE* file = OpenFile("foo.dat", "wb");
  23    :  //   FileOutStream out_stream(file);
  24    :  //   NativeBinaryOutArchive out_archive(out_stream);
  25    :  //   out_archive.Save(object);
  26    :  //   out_archive.Flush();
  27    :  //
  28    :  // Note that an output stream must be flushed as the archive or the stream may
  29    :  // introduce some buffering. If not explicitly called, it will be called for an
  30    :  // OutStream or OutArchive when it is destroyed.
  31    :  //
  32    :  // To deserialize an object:
  33    :  //
  34    :  //   Object object;
  35    :  //   FILE* file = OpenFile("foo.dat", "rb");
  36    :  //   FileInStream in_stream(file);
  37    :  //   NativeBinaryInArchive in_archive(in_stream);
  38    :  //   in_archive.Load(&object);
  39    :  //
  40    :  // Serialization of primitive types (bool, char, wchar_t, float, double,
  41    :  // int8/16/32/64, uint8/16/32/64), C-arrays of serializable types, and STL
  42    :  // containers (map, set, vector, basic_string, pair) of serializable types is
  43    :  // supported by default. Support can be added for further types by extending
  44    :  // the serialization system directly.
  45    :  //
  46    :  // There are currently two stream types defined: File*Stream, which uses a
  47    :  // FILE* under the hood; and Byte*Stream, which uses iterators to containers
  48    :  // of Bytes. Adding further stream types is trivial. Refer to to the comments/
  49    :  // declarations of File*Stream and Byte*Stream for details.
  50    :  //
  51    :  // There is currently a single archive type defined, NativeBinary, which is a
  52    :  // non-portable binary format. Additional archive formats may be easily added
  53    :  // as well. Refer to the comments/declaration of NativeBinaryInArchive and
  54    :  // NativeBinaryOutArchive for details.
  55    :  //
  56    :  // *** ADDING SERIALIZATION SUPPORT DIRECTLY TO A CLASS:
  57    :  //
  58    :  // The object itself supports serialization through a public member function:
  59    :  //
  60    :  //   class Object {
  61    :  //     ...
  62    :  //     template<class OutArchive> bool Save(OutArchive* out_archive) const {
  63    :  //       ... calls to out_archive.Save ...
  64    :  //     }
  65    :  //   };
  66    :  //
  67    :  // To support deserialization, a similar 'Load' function is created with the
  68    :  // signature:
  69    :  //
  70    :  //   template<class InArchive> bool Load(InArchive* in_archive);
  71    :  //
  72    :  // *** ADDING SERIALIZATION SUPPORT TO A CLASS IN AN EXTERNAL LIBRARY
  73    :  //
  74    :  // If you need to add serialization support to a class in an external library
  75    :  // (where you can't directly add member functions), you can do so using the
  76    :  // templated core::Save and core::Load functions. Simply provide an override
  77    :  // for the appropriate type, with signatures of the form:
  78    :  //
  79    :  //   template<class OutArchive> bool Save(const ClassName& data,
  80    :  //                                        OutArchive* out_archive);
  81    :  //   template<class InArchive> bool Load(ClassName* data,
  82    :  //                                       InArchive* in_archive);
  83    :  //
  84    :  // *** UNDER THE HOOD
  85    :  //
  86    :  // We trace the calltree for the serialization of a Foo object foo:
  87    :  //
  88    :  // - An object foo of type Foo is saved to an OutArchive by calling
  89    :  //   out_archive.Save(foo).
  90    :  //
  91    :  // - If OutArchive specializes Save(Foo), then the object is serialized
  92    :  //   directly (this is the case for primitive types). Otherwise, it is forwarded
  93    :  //   to core::Save(foo, out_archive).
  94    :  //
  95    :  // - If there is a specialized version of core::Save(foo, out_archive), it
  96    :  //   will be called. This is how STL types and C-arrays are serialized.
  97    :  //   Otherwise, the generic version of the function will delegate to
  98    :  //   foo.Save(out_archive).
  99    :  //
 100    :  // - If Foo::Save is not defined, compilation will fail.
 101    :  
 102    :  #ifndef SYZYGY_CORE_SERIALIZATION_H_
 103    :  #define SYZYGY_CORE_SERIALIZATION_H_
 104    :  
 105    :  #include <iterator>
 106    :  #include <map>
 107    :  #include <set>
 108    :  #include <string>
 109    :  #include <utility>
 110    :  #include <vector>
 111    :  
 112    :  #include "base/basictypes.h"
 113    :  #include "base/logging.h"
 114    :  #include "base/memory/scoped_ptr.h"
 115    :  
 116    :  namespace core {
 117    :  
 118    :  typedef uint8 Byte;
 119    :  typedef std::vector<Byte> ByteVector;
 120    :  
 121    :  namespace internal {
 122    :  
 123    :  // Forward declares of some utilities we need. These are defined in
 124    :  // serialization_impl.h.
 125    :  template<typename T> struct IsByteLike;
 126    :  template<typename IteratorTag> struct IteratorsAreEqualFunctor;
 127    :  
 128    :  }  // namespace internal
 129    :  
 130    :  // Serialization passes through these static functions before being routed
 131    :  // to 'Save' and 'Load' member functions. Overriding this function provides a
 132    :  // method to implement serialization for classes whose internals we can not
 133    :  // modify. This is how serialization is implemented for STL containers in
 134    :  // serialization_impl.h.
 135    :  template<class Data, class OutArchive> bool Save(
 136    :      const Data& data, OutArchive* out_archive);
 137    :  template<class Data, class InArchive> bool Load(
 138    :      Data* data, InArchive* in_archive);
 139    :  
 140    :  // We define extremely lightweight stream-like objects for use as the I/O
 141    :  // layer in serialization. This is so that our Serialization system can easily
 142    :  // stick to the use of FILE objects.
 143    :  class OutStream {
 144    :   public:
 145  E :    virtual ~OutStream() { }
 146    :  
 147    :    // An OutStream is expected to write all data provided to it. If it fails this
 148    :    // is considered a fatal error, and the stream is no longer usable.
 149    :    virtual bool Write(size_t length, const Byte* bytes) = 0;
 150    :  
 151    :    // Flushes any buffered data currently contained in this stream. Flush should
 152    :    // only be called at most once for a given stream and should be interpreted
 153    :    // as an end of stream event.
 154  E :    virtual bool Flush() { return true; }
 155    :  };
 156    :  class InStream {
 157    :   public:
 158  E :    virtual ~InStream() { }
 159    :  
 160    :    // An input stream is expected to read all data asked of it, unless the data
 161    :    // source has been exhausted and only a partial read is possible. In this
 162    :    // case it must still return true. A return value of false is fatal and
 163    :    // indicates that the stream is no longer usable.
 164    :    // @param length the number of bytes to read.
 165    :    // @param bytes a pointer to a buffer of length at least @p length to receive
 166    :    //     the bytes that are read.
 167    :    // @param bytes_read to receive the number of bytes actually read. It is
 168    :    //     possible for this to be any value from 0 to length, inclusive.
 169    :    // @returns true if the stream is reusable, false if it is errored.
 170  E :    bool Read(size_t length, Byte* bytes, size_t* bytes_read) {
 171  E :      return ReadImpl(length, bytes, bytes_read);
 172  E :    }
 173    :  
 174    :    // Calling this version of read is only safe if you have implicit knowledge
 175    :    // of the length of the input stream. This is inline so that common_lib, which
 176    :    // uses serialization, doesn't need a (circular) dependency on core_lib.
 177    :    // @param length the number of bytes to read.
 178    :    // @param bytes a pointer to a buffer of length at least @p length to receive
 179    :    //     the bytes that are read.
 180    :    // @returns true if the entire length of bytes was able to be read, false
 181    :    //     otherwise.
 182  E :    bool Read(size_t length, Byte* bytes) {
 183  E :      size_t bytes_read = 0;
 184  E :      if (!ReadImpl(length, bytes, &bytes_read))
 185  i :        return false;
 186  E :      if (bytes_read != length)
 187  E :        return false;
 188  E :      return true;
 189  E :    }
 190    :  
 191    :   protected:
 192    :    // Needs to be implemented by derived classes. See description of Read above.
 193    :    // @param length the number of bytes to read.
 194    :    // @param bytes a pointer to a buffer of length at least @p length to receive
 195    :    //     the bytes that are read.
 196    :    // @param bytes_read to receive the number of bytes actually read. It is
 197    :    //     possible for this to be any value from 0 to length, inclusive.
 198    :    // @returns true if the stream is reusable, false if it is errored.
 199    :    virtual bool ReadImpl(size_t length, Byte* bytes, size_t* bytes_read) = 0;
 200    :  };
 201    :  typedef scoped_ptr<OutStream> ScopedOutStreamPtr;
 202    :  typedef scoped_ptr<InStream> ScopedInStreamPtr;
 203    :  
 204    :  // A simple OutStream wrapper for FILE pointers.
 205    :  class FileOutStream : public OutStream {
 206    :   public:
 207    :    explicit FileOutStream(FILE* file);
 208  E :    virtual ~FileOutStream() { }
 209    :    virtual bool Write(size_t length, const Byte* bytes);
 210    :    virtual bool Flush();
 211    :  
 212    :   private:
 213    :    FILE* file_;
 214    :  };
 215    :  
 216    :  // A simple InStream wrapper for FILE pointers.
 217    :  class FileInStream : public InStream {
 218    :   public:
 219    :    explicit FileInStream(FILE* file);
 220  E :    virtual ~FileInStream() { }
 221    :  
 222    :   protected:
 223    :    virtual bool ReadImpl(size_t length, Byte* bytes, size_t* bytes_read);
 224    :  
 225    :   private:
 226    :    FILE* file_;
 227    :  };
 228    :  
 229    :  // A simple OutStream wrapper for containers of bytes. Uses an output iterator
 230    :  // to push data to some container, or a pair of non-const iterators to write
 231    :  // data to a preallocated container. The underlying container should store
 232    :  // 'byte-like' elements (integer of size 1).
 233    :  template<typename OutputIterator> class ByteOutStream : public OutStream {
 234    :   public:
 235    :    // We can't use a compile time assert to validate the value_type of an
 236    :    // output iterator, as it is undefined.
 237    :  
 238    :    // This constructor is for adding new elements to an existing container.
 239    :    // The iterator should be a bonafide OutputIterator.
 240    :    explicit ByteOutStream(OutputIterator iter)
 241  E :        : iter_(iter), end_(iter), have_end_(false) {
 242  E :    }
 243    :  
 244  E :    virtual ~ByteOutStream() { }
 245    :  
 246    :    // This constructor is for overwriting elements in an existing container.
 247    :    // The iterators should be normal non-const iterators.
 248    :    ByteOutStream(OutputIterator iter, OutputIterator end)
 249    :        : iter_(iter), end_(end), have_end_(true) {
 250    :    }
 251    :  
 252    :    virtual bool Write(size_t length, const Byte* bytes);
 253    :  
 254    :   private:
 255    :    typedef typename std::iterator_traits<OutputIterator>::iterator_category
 256    :        IteratorTag;
 257    :    typedef internal::IteratorsAreEqualFunctor<IteratorTag> IteratorsAreEqual;
 258    :  
 259    :    OutputIterator iter_;
 260    :    OutputIterator end_;
 261    :    bool have_end_;
 262    :  };
 263    :  
 264    :  // This is for implicit creation of ByteOutStreams without needing to specify
 265    :  // template parameters. Use with ScopedOutStreamPtr.
 266    :  template<typename OutputIterator>
 267  E :  OutStream* CreateByteOutStream(OutputIterator iter) {
 268  E :    return new ByteOutStream<OutputIterator>(iter);
 269  E :  }
 270    :  template<typename OutputIterator>
 271    :  OutStream* CreateByteOutStream(OutputIterator iter, OutputIterator end) {
 272    :    return new ByteOutStream<OutputIterator>(iter, end);
 273    :  }
 274    :  
 275    :  // A simple InStream wrapper for containers of bytes. Uses a range of input
 276    :  // iterators to traverse a container. The value type of the iterator must be
 277    :  // 'byte-like' (integer type of size 1). Use with ScopedInStreamPtr.
 278    :  template<typename InputIterator> class ByteInStream : public InStream {
 279    :   public:
 280    :    typedef typename std::iterator_traits<InputIterator>::value_type ValueType;
 281    :    COMPILE_ASSERT(internal::IsByteLike<ValueType>::Value,
 282    :                   value_type_must_be_byte_like);
 283    :  
 284    :    ByteInStream(InputIterator begin, InputIterator end)
 285  E :        : iter_(begin), end_(end) {
 286  E :    }
 287    :  
 288  E :    virtual ~ByteInStream() { }
 289    :  
 290    :   protected:
 291    :    virtual bool ReadImpl(size_t length, Byte* bytes, size_t* bytes_read);
 292    :  
 293    :   private:
 294    :    InputIterator iter_;
 295    :    InputIterator end_;
 296    :  };
 297    :  
 298    :  // This is for implicit creation of ByteInStreams without needing to specify
 299    :  // template parameters.
 300    :  template<typename InputIterator>
 301    :  ByteInStream<InputIterator>* CreateByteInStream(InputIterator iter,
 302  E :                                                  InputIterator end) {
 303  E :    return new ByteInStream<InputIterator>(iter, end);
 304  E :  }
 305    :  
 306    :  // This class defines a non-portable native binary serialization format.
 307    :  class NativeBinaryOutArchive {
 308    :   public:
 309    :    // All classes implementing the OutArchive concept must implement the
 310    :    // following 2 functions.
 311    :  
 312  E :    explicit NativeBinaryOutArchive(OutStream* out_stream)
 313    :        : out_stream_(out_stream) {
 314  E :      DCHECK(out_stream != NULL);
 315  E :    }
 316    :  
 317  E :    ~NativeBinaryOutArchive() { }
 318    :  
 319  E :    template<class Data> bool Save(const Data& data) {
 320  E :      return core::Save(data, this);
 321  E :    }
 322    :  
 323    :    // The following are specializations for primitive data types. Every
 324    :    // OutArchive should implement these types directly.
 325    :  #define NATIVE_BINARY_OUT_ARCHIVE_SAVE(Type) \
 326    :    bool Save(const Type& x) { \
 327    :      DCHECK(out_stream_ != NULL); \
 328    :      return out_stream_->Write(sizeof(Type), \
 329    :                                reinterpret_cast<const Byte*>(&x)); \
 330    :    }
 331  E :    NATIVE_BINARY_OUT_ARCHIVE_SAVE(bool);
 332  E :    NATIVE_BINARY_OUT_ARCHIVE_SAVE(char);
 333  E :    NATIVE_BINARY_OUT_ARCHIVE_SAVE(wchar_t);
 334  E :    NATIVE_BINARY_OUT_ARCHIVE_SAVE(float);
 335  E :    NATIVE_BINARY_OUT_ARCHIVE_SAVE(double);
 336  E :    NATIVE_BINARY_OUT_ARCHIVE_SAVE(int8);
 337  E :    NATIVE_BINARY_OUT_ARCHIVE_SAVE(int16);
 338  E :    NATIVE_BINARY_OUT_ARCHIVE_SAVE(int32);
 339  E :    NATIVE_BINARY_OUT_ARCHIVE_SAVE(int64);
 340  E :    NATIVE_BINARY_OUT_ARCHIVE_SAVE(uint8);
 341  E :    NATIVE_BINARY_OUT_ARCHIVE_SAVE(uint16);
 342  E :    NATIVE_BINARY_OUT_ARCHIVE_SAVE(uint32);
 343  E :    NATIVE_BINARY_OUT_ARCHIVE_SAVE(uint64);
 344    :    NATIVE_BINARY_OUT_ARCHIVE_SAVE(unsigned long);
 345    :  #undef NATIVE_BINARY_OUT_ARCHIVE_SAVE
 346    :  
 347  E :    bool Flush() { return out_stream_->Flush(); }
 348    :  
 349  E :    OutStream* out_stream() { return out_stream_; }
 350    :  
 351    :   private:
 352    :    OutStream* out_stream_;
 353    :  };
 354    :  
 355    :  // For now this is the only archive type, but if there are more OutArchive
 356    :  // would be the common pure-virtual base class.
 357    :  typedef NativeBinaryOutArchive OutArchive;
 358    :  
 359    :  class NativeBinaryInArchive {
 360    :   public:
 361    :    // All classes implementing the InArchive concept must implement the
 362    :    // following 3 functions.
 363    :  
 364  E :    explicit NativeBinaryInArchive(InStream* in_stream)
 365    :        : in_stream_(in_stream) {
 366  E :      DCHECK(in_stream != NULL);
 367  E :    }
 368    :  
 369  E :    template<class Data> bool Load(Data* data) {
 370  E :      return core::Load(data, this);
 371  E :    }
 372    :  
 373    :    // The following are specializations for primitive data types. Every
 374    :    // InArchive should implement these types directly.
 375    :  #define NATIVE_BINARY_IN_ARCHIVE_LOAD(Type) \
 376    :    bool Load(Type* x) { \
 377    :      DCHECK(in_stream_ != NULL); \
 378    :      return in_stream_->Read(sizeof(Type), reinterpret_cast<Byte*>(x)); \
 379    :    }
 380  E :    NATIVE_BINARY_IN_ARCHIVE_LOAD(bool);
 381  E :    NATIVE_BINARY_IN_ARCHIVE_LOAD(char);
 382  E :    NATIVE_BINARY_IN_ARCHIVE_LOAD(wchar_t);
 383  E :    NATIVE_BINARY_IN_ARCHIVE_LOAD(float);
 384  E :    NATIVE_BINARY_IN_ARCHIVE_LOAD(double);
 385  E :    NATIVE_BINARY_IN_ARCHIVE_LOAD(int8);
 386  E :    NATIVE_BINARY_IN_ARCHIVE_LOAD(int16);
 387  E :    NATIVE_BINARY_IN_ARCHIVE_LOAD(int32);
 388  E :    NATIVE_BINARY_IN_ARCHIVE_LOAD(int64);
 389  E :    NATIVE_BINARY_IN_ARCHIVE_LOAD(uint8);
 390  E :    NATIVE_BINARY_IN_ARCHIVE_LOAD(uint16);
 391  E :    NATIVE_BINARY_IN_ARCHIVE_LOAD(uint32);
 392  E :    NATIVE_BINARY_IN_ARCHIVE_LOAD(uint64);
 393    :    NATIVE_BINARY_IN_ARCHIVE_LOAD(unsigned long);
 394    :  #undef NATIVE_BINARY_IN_ARCHIVE_LOAD
 395    :  
 396  E :    InStream* in_stream() { return in_stream_; }
 397    :  
 398    :   private:
 399    :    InStream* in_stream_;
 400    :  };
 401    :  
 402    :  // For now this is the only archive type, but if there are more OutArchive
 403    :  // would be the common pure-virtual base class.
 404    :  typedef NativeBinaryInArchive InArchive;
 405    :  
 406    :  }  // namespace core
 407    :  
 408    :  // Bring in the implementation of the various templated functions.
 409    :  #include "syzygy/core/serialization_impl.h"
 410    :  
 411    :  #endif  // SYZYGY_CORE_SERIALIZATION_H_

Coverage information generated Thu Mar 26 16:15:41 2015.