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_
|