/[svn]/libgig/trunk/src/Serialization.h
ViewVC logotype

Contents of /libgig/trunk/src/Serialization.h

Parent Directory Parent Directory | Revision Log Revision Log


Revision 3178 - (show annotations) (download) (as text)
Thu May 11 23:06:40 2017 UTC (6 years, 11 months ago) by schoenebeck
File MIME type: text/x-c++hdr
File size: 30290 byte(s)
* Fixed compile errors with some compilers.

1 /***************************************************************************
2 * *
3 * Copyright (C) 2017 Christian Schoenebeck *
4 * <cuse@users.sourceforge.net> *
5 * *
6 * This library is part of libgig. *
7 * *
8 * This library is free software; you can redistribute it and/or modify *
9 * it under the terms of the GNU General Public License as published by *
10 * the Free Software Foundation; either version 2 of the License, or *
11 * (at your option) any later version. *
12 * *
13 * This library is distributed in the hope that it will be useful, *
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
16 * GNU General Public License for more details. *
17 * *
18 * You should have received a copy of the GNU General Public License *
19 * along with this library; if not, write to the Free Software *
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, *
21 * MA 02111-1307 USA *
22 ***************************************************************************/
23
24 #ifndef LIBGIG_SERIALIZATION_H
25 #define LIBGIG_SERIALIZATION_H
26
27 #ifdef HAVE_CONFIG_H
28 # include <config.h>
29 #endif
30
31 #include <stdint.h>
32 #include <stdio.h>
33 #include <typeinfo>
34 #include <string>
35 #include <vector>
36 #include <map>
37 #include <time.h>
38
39 #ifndef __has_extension
40 # define __has_extension(x) 0
41 #endif
42
43 #ifndef HAS_BUILTIN_TYPE_TRAITS
44 # if __cplusplus >= 201103L
45 # define HAS_BUILTIN_TYPE_TRAITS 1
46 # elif ( __has_extension(is_class) && __has_extension(is_enum) )
47 # define HAS_BUILTIN_TYPE_TRAITS 1
48 # elif ( __GNUC__ > 4 || ( __GNUC__ == 4 && __GNUC_MINOR__ >= 3 ) )
49 # define HAS_BUILTIN_TYPE_TRAITS 1
50 # elif _MSC_VER >= 1400 /* MS Visual C++ 8.0 (Visual Studio 2005) */
51 # define HAS_BUILTIN_TYPE_TRAITS 1
52 # elif __INTEL_COMPILER >= 1100
53 # define HAS_BUILTIN_TYPE_TRAITS 1
54 # else
55 # define HAS_BUILTIN_TYPE_TRAITS 0
56 # endif
57 #endif
58
59 #if !HAS_BUILTIN_TYPE_TRAITS
60 # include <tr1/type_traits>
61 # define LIBGIG_IS_CLASS(type) std::tr1::__is_union_or_class<type>::value //NOTE: without compiler support we cannot distinguish union from class
62 #else
63 # define LIBGIG_IS_CLASS(type) __is_class(type)
64 #endif
65
66 /** @brief Serialization / deserialization framework.
67 *
68 * See class Archive as starting point for how to implement serialization and
69 * deserialization with your application.
70 *
71 * The classes in this namespace allow to serialize and deserialize native
72 * C++ objects in a portable, easy and flexible way. Serialization is a
73 * technique that allows to transform the current state and data of native
74 * (in this case C++) objects into a data stream (including all other objects
75 * the "serialized" objects relate to); the data stream may then be sent over
76 * "wire" (for example via network connection to another computer, which might
77 * also have a different OS, CPU architecture, native memory word size and
78 * endian type); and finally the data stream would be "deserialized" on that
79 * receiver side, that is transformed again to modify all objects and data
80 * structures on receiver side to resemble the objects' state and data as it
81 * was originally on sender side.
82 *
83 * In contrast to many other already existing serialization frameworks, this
84 * implementation has a strong focus on robustness regarding long-term changes
85 * to the serialized C++ classes of the serialized objects. So even if sender
86 * and receiver are using different versions of their serialized/deserialized
87 * C++ classes, structures and data types (thus having different data structure
88 * layout to a certain extent), this framework aims trying to automatically
89 * adapt its serialization and deserialization process in that case so that
90 * the deserialized objects on receiver side would still reflect the overall
91 * expected states and overall data as intended by the sender. For being able to
92 * do so, this framework stores all kind of additional information about each
93 * serialized object and each data structure member (for example name of each
94 * data structure member, but also the offset of each member within its
95 * containing data structure, precise data types, and more).
96 *
97 * Like most other serialization frameworks, this frameworks does not require a
98 * tree-structured layout of the serialized data structures. So it automatically
99 * handles also cyclic dependencies between serialized data structures
100 * correctly, without i.e. causing endless recursion or redundancy.
101 *
102 * Additionally this framework also allows partial deserialization. Which means
103 * the receiver side may for example decide that it wants to restrict
104 * deserialization so that it would only modify certain objects or certain
105 * members by the deserialization process, leaving all other ones untouched.
106 * So this partial deserialization technique for example allows to implement
107 * flexible preset features for applications in a powerful and easy way.
108 */
109 namespace Serialization {
110
111 // just symbol prototyping
112 class DataType;
113 class Object;
114 class Member;
115 class Archive;
116 class ObjectPool;
117 class Exception;
118
119 typedef std::string String;
120
121 typedef std::vector<uint8_t> RawData;
122
123 typedef void* ID;
124
125 typedef uint32_t Version;
126
127 enum operation_t {
128 OPERATION_NONE,
129 OPERATION_SERIALIZE,
130 OPERATION_DESERIALIZE
131 };
132
133 enum time_base_t {
134 LOCAL_TIME,
135 UTC_TIME
136 };
137
138 template<typename T>
139 bool IsEnum(const T& data) {
140 #if !HAS_BUILTIN_TYPE_TRAITS
141 return std::tr1::is_enum<T>::value;
142 #else
143 return __is_enum(T);
144 #endif
145 }
146
147 template<typename T>
148 bool IsUnion(const T& data) {
149 #if !HAS_BUILTIN_TYPE_TRAITS
150 return false; // without compiler support we cannot distinguish union from class
151 #else
152 return __is_union(T);
153 #endif
154 }
155
156 template<typename T>
157 bool IsClass(const T& data) {
158 #if !HAS_BUILTIN_TYPE_TRAITS
159 return std::tr1::__is_union_or_class<T>::value; // without compiler support we cannot distinguish union from class
160 #else
161 return __is_class(T);
162 #endif
163 }
164
165 /*template<typename T>
166 bool IsTrivial(T data) {
167 return __is_trivial(T);
168 }*/
169
170 /*template<typename T>
171 bool IsPOD(T data) {
172 return __is_pod(T);
173 }*/
174
175 /** @brief Unique identifier for one specific C++ object, member or fundamental variable.
176 *
177 * Reflects a unique identifier for one specific serialized C++ class
178 * instance, struct instance, member, primitive pointer, or fundamental
179 * variables.
180 */
181 class UID {
182 public:
183 ID id;
184 size_t size;
185
186 bool isValid() const;
187 operator bool() const { return isValid(); }
188 //bool operator()() const { return isValid(); }
189 bool operator==(const UID& other) const { return id == other.id && size == other.size; }
190 bool operator!=(const UID& other) const { return id != other.id || size != other.size; }
191 bool operator<(const UID& other) const { return id < other.id || (id == other.id && size < other.size); }
192 bool operator>(const UID& other) const { return id > other.id || (id == other.id && size > other.size); }
193
194 template<typename T>
195 static UID from(const T& obj) {
196 return Resolver<T>::resolve(obj);
197 }
198
199 protected:
200 // UID resolver for non-pointer types
201 template<typename T>
202 struct Resolver {
203 static UID resolve(const T& obj) {
204 const UID uid = { (ID) &obj, sizeof(obj) };
205 return uid;
206 }
207 };
208
209 // UID resolver for pointer types (of 1st degree)
210 template<typename T>
211 struct Resolver<T*> {
212 static UID resolve(const T* const & obj) {
213 const UID uid = { (ID) obj, sizeof(*obj) };
214 return uid;
215 }
216 };
217 };
218
219 /**
220 * Reflects an invalid UID and behaves similar to NULL as invalid value for
221 * pointer types.
222 */
223 extern const UID NO_UID;
224
225 typedef std::vector<UID> UIDChain;
226
227 // prototyping of private internal friend functions
228 static String _encodePrimitiveValue(const Object& obj);
229 static DataType _popDataTypeBlob(const char*& p, const char* end);
230 static Member _popMemberBlob(const char*& p, const char* end);
231 static Object _popObjectBlob(const char*& p, const char* end);
232 static void _popPrimitiveValue(const char*& p, const char* end, Object& obj);
233 static String _primitiveObjectValueToString(const Object& obj);
234 // |
235 template<typename T>
236 static T _primitiveObjectValueToNumber(const Object& obj);
237
238 /** @brief Abstract reflection of a native C++ data type.
239 *
240 * Provides detailed information about a C++ data type, whether it is a
241 * fundamental C/C++ data type (like int, float, char, etc.) or custom
242 * defined data type like a C++ class, struct, enum, as well as other
243 * features of the data type like its native memory size and more.
244 */
245 class DataType {
246 public:
247 DataType();
248 size_t size() const { return m_size; }
249 bool isValid() const;
250 bool isPointer() const;
251 bool isClass() const;
252 bool isPrimitive() const;
253 bool isInteger() const;
254 bool isReal() const;
255 bool isBool() const;
256 bool isEnum() const;
257 bool isSigned() const;
258 operator bool() const { return isValid(); }
259 //bool operator()() const { return isValid(); }
260 bool operator==(const DataType& other) const;
261 bool operator!=(const DataType& other) const;
262 bool operator<(const DataType& other) const;
263 bool operator>(const DataType& other) const;
264 String asLongDescr() const;
265 String baseTypeName() const { return m_baseTypeName; }
266 String customTypeName(bool demangle = false) const;
267
268 template<typename T>
269 static DataType dataTypeOf(const T& data) {
270 return Resolver<T>::resolve(data);
271 }
272
273 protected:
274 DataType(bool isPointer, int size, String baseType, String customType = "");
275
276 template<typename T, bool T_isPointer>
277 struct ResolverBase {
278 static DataType resolve(const T& data) {
279 const std::type_info& type = typeid(data);
280 const int sz = sizeof(data);
281
282 // for primitive types we are using our own type names instead of
283 // using std:::type_info::name(), because the precise output of the
284 // latter may vary between compilers
285 if (type == typeid(int8_t)) return DataType(T_isPointer, sz, "int8");
286 if (type == typeid(uint8_t)) return DataType(T_isPointer, sz, "uint8");
287 if (type == typeid(int16_t)) return DataType(T_isPointer, sz, "int16");
288 if (type == typeid(uint16_t)) return DataType(T_isPointer, sz, "uint16");
289 if (type == typeid(int32_t)) return DataType(T_isPointer, sz, "int32");
290 if (type == typeid(uint32_t)) return DataType(T_isPointer, sz, "uint32");
291 if (type == typeid(int64_t)) return DataType(T_isPointer, sz, "int64");
292 if (type == typeid(uint64_t)) return DataType(T_isPointer, sz, "uint64");
293 if (type == typeid(bool)) return DataType(T_isPointer, sz, "bool");
294 if (type == typeid(float)) return DataType(T_isPointer, sz, "real32");
295 if (type == typeid(double)) return DataType(T_isPointer, sz, "real64");
296
297 if (IsEnum(data)) return DataType(T_isPointer, sz, "enum", rawCppTypeNameOf(data));
298 if (IsUnion(data)) return DataType(T_isPointer, sz, "union", rawCppTypeNameOf(data));
299 if (IsClass(data)) return DataType(T_isPointer, sz, "class", rawCppTypeNameOf(data));
300
301 return DataType();
302 }
303 };
304
305 // DataType resolver for non-pointer types
306 template<typename T>
307 struct Resolver : ResolverBase<T,false> {
308 static DataType resolve(const T& data) {
309 return ResolverBase<T,false>::resolve(data);
310 }
311 };
312
313 // DataType resolver for pointer types (of 1st degree)
314 template<typename T>
315 struct Resolver<T*> : ResolverBase<T,true> {
316 static DataType resolve(const T*& data) {
317 return ResolverBase<T,true>::resolve(*data);
318 }
319 };
320
321 template<typename T>
322 static String rawCppTypeNameOf(const T& data) {
323 #if defined _MSC_VER // Microsoft compiler ...
324 # warning type_info::raw_name() demangling has not been tested yet with Microsoft compiler! Feedback appreciated!
325 String name = typeid(data).raw_name(); //NOTE: I haven't checked yet what MSC actually outputs here exactly
326 #else // i.e. especially GCC and clang ...
327 String name = typeid(data).name();
328 #endif
329 //while (!name.empty() && name[0] >= 0 && name[0] <= 9)
330 // name = name.substr(1);
331 return name;
332 }
333
334 private:
335 String m_baseTypeName;
336 String m_customTypeName;
337 int m_size;
338 bool m_isPointer;
339
340 friend DataType _popDataTypeBlob(const char*& p, const char* end);
341 friend class Archive;
342 };
343
344 /** @brief Abstract reflection of a native C++ class/struct's member variable.
345 *
346 * Provides detailed information about a specific C++ member variable of
347 * serialized C++ object, like its C++ data type, offset of this member
348 * within its containing data structure/class, its C++ member variable name
349 * and more.
350 */
351 class Member {
352 public:
353 Member();
354 UID uid() const { return m_uid; }
355 String name() const { return m_name; }
356 size_t offset() const { return m_offset; }
357 const DataType& type() const { return m_type; }
358 bool isValid() const;
359 operator bool() const { return isValid(); }
360 //bool operator()() const { return isValid(); }
361 bool operator==(const Member& other) const;
362 bool operator!=(const Member& other) const;
363 bool operator<(const Member& other) const;
364 bool operator>(const Member& other) const;
365
366 protected:
367 Member(String name, UID uid, size_t offset, DataType type);
368 friend class Archive;
369
370 private:
371 UID m_uid;
372 size_t m_offset;
373 String m_name;
374 DataType m_type;
375
376 friend Member _popMemberBlob(const char*& p, const char* end);
377 };
378
379 /** @brief Abstract reflection of a native C++ class/struct instance.
380 *
381 * Provides detailed information about a specific serialized C++ object,
382 * like its C++ member variables, its C++ class/struct name, its native
383 * memory size and more.
384 */
385 class Object {
386 public:
387 Object();
388 Object(UIDChain uidChain, DataType type);
389
390 UID uid(int index = 0) const {
391 return (index < m_uid.size()) ? m_uid[index] : NO_UID;
392 }
393
394 const UIDChain& uidChain() const { return m_uid; }
395 const DataType& type() const { return m_type; }
396 const RawData& rawData() const { return m_data; }
397
398 Version version() const { return m_version; }
399
400 void setVersion(Version v) {
401 m_version = v;
402 }
403
404 Version minVersion() const { return m_minVersion; }
405
406 void setMinVersion(Version v) {
407 m_minVersion = v;
408 }
409
410 bool isVersionCompatibleTo(const Object& other) const;
411
412 std::vector<Member>& members() { return m_members; }
413 const std::vector<Member>& members() const { return m_members; }
414 Member memberNamed(String name) const;
415 Member memberByUID(const UID& uid) const;
416 std::vector<Member> membersOfType(const DataType& type) const;
417 int sequenceIndexOf(const Member& member) const;
418 bool isValid() const;
419 operator bool() const { return isValid(); }
420 //bool operator()() const { return isValid(); }
421 bool operator==(const Object& other) const;
422 bool operator!=(const Object& other) const;
423 bool operator<(const Object& other) const;
424 bool operator>(const Object& other) const;
425
426 protected:
427 void remove(const Member& member);
428
429 private:
430 DataType m_type;
431 UIDChain m_uid;
432 Version m_version;
433 Version m_minVersion;
434 RawData m_data;
435 std::vector<Member> m_members;
436
437 friend String _encodePrimitiveValue(const Object& obj);
438 friend Object _popObjectBlob(const char*& p, const char* end);
439 friend void _popPrimitiveValue(const char*& p, const char* end, Object& obj);
440 friend String _primitiveObjectValueToString(const Object& obj);
441
442 template<typename T>
443 friend T _primitiveObjectValueToNumber(const Object& obj);
444
445 friend class Archive;
446 };
447
448 /** @brief Destination container for serialization, and source container for deserialization.
449 *
450 * This is the main class for implementing serialization and deserialization
451 * with your C++ application. This framework does not require a a tree
452 * structured layout of your C++ objects being serialized/deserialized, it
453 * uses a concept of a "root" object though. So to start serialization
454 * construct an empty Archive object and then instruct it to serialize your
455 * C++ objects by pointing it to your "root" object:
456 * @code
457 * Archive a;
458 * a.serialize(&myRootObject);
459 * @endcode
460 * Or if you prefer the look of operator based code:
461 * @code
462 * Archive a;
463 * a << myRootObject;
464 * @endcode
465 * The Archive object will then serialize all members of the passed C++
466 * object, and will recursively serialize all other C++ objects which it
467 * contains or points to. So the root object is the starting point for the
468 * overall serialization. After the serialize() method returned, you can
469 * then access the serialized data stream by calling rawData() and send that
470 * data stream over "wire", or store it on disk or whatever you may intend
471 * to do with it.
472 *
473 * Then on receiver side likewise, you create a new Archive object, pass the
474 * received data stream i.e. via constructor to the Archive object and call
475 * deserialize() by pointing it to the root object on receiver side:
476 * @code
477 * Archive a(rawDataStream);
478 * a.deserialize(&myRootObject);
479 * @endcode
480 * Or with operator instead:
481 * @code
482 * Archive a(rawDataStream);
483 * a >> myRootObject;
484 * @endcode
485 * Now this framework automatically handles serialization and
486 * deserialization of fundamental data types automatically for you (like
487 * i.e. char, int, long int, float, double, etc.). However for your own
488 * custom C++ classes and structs you must implement one method which
489 * defines which members of your class should actually be serialized and
490 * deserialized. That method to be added must have the following signature:
491 * @code
492 * void serialize(Serialization::Archive* archive);
493 * @endcode
494 * So let's say you have the following simple data structures:
495 * @code
496 * struct Foo {
497 * int a;
498 * bool b;
499 * double c;
500 * };
501 *
502 * struct Bar {
503 * char one;
504 * float two;
505 * Foo foo1;
506 * Foo* pFoo2;
507 * Foo* pFoo3DontTouchMe; // shall not be serialized/deserialized
508 * };
509 * @endcode
510 * So in order to be able to serialize and deserialize objects of those two
511 * structures you would first add the mentioned method to each struct
512 * definition (i.e. in your header file):
513 * @code
514 * struct Foo {
515 * int a;
516 * bool b;
517 * double c;
518 *
519 * void serialize(Serialization::Archive* archive);
520 * };
521 *
522 * struct Bar {
523 * char one;
524 * float two;
525 * Foo foo1;
526 * Foo* pFoo2;
527 * Foo* pFoo3DontTouchMe; // shall not be serialized/deserialized
528 *
529 * void serialize(Serialization::Archive* archive);
530 * };
531 * @endcode
532 * And then you would implement those two new methods like this (i.e. in
533 * your .cpp file):
534 * @code
535 * #define SRLZ(member) \
536 * archive->serializeMember(*this, member, #member);
537 *
538 * void Foo::serialize(Serialization::Archive* archive) {
539 * SRLZ(a);
540 * SRLZ(b);
541 * SRLZ(c);
542 * }
543 *
544 * void Bar::serialize(Serialization::Archive* archive) {
545 * SRLZ(one);
546 * SRLZ(two);
547 * SRLZ(foo1);
548 * SRLZ(pFoo2);
549 * // leaving out pFoo3DontTouchMe here
550 * }
551 * @endcode
552 * Now when you serialize such a Bar object, this framework will also
553 * automatically serialize the respective Foo object(s) accordingly, also
554 * for the pFoo2 pointer for instance (as long as it is not a NULL pointer
555 * that is).
556 *
557 * Note that there is only one method that you need to implement. So the
558 * respective serialize() method implementation of your classes/structs are
559 * both called for serialization, as well as for deserialization!
560 */
561 class Archive {
562 public:
563 Archive();
564 Archive(const RawData& data);
565 Archive(const uint8_t* data, size_t size);
566 virtual ~Archive();
567
568 template<typename T>
569 void serialize(const T* obj) {
570 m_operation = OPERATION_SERIALIZE;
571 m_allObjects.clear();
572 m_rawData.clear();
573 m_root = UID::from(obj);
574 const_cast<T*>(obj)->serialize(this);
575 encode();
576 m_operation = OPERATION_NONE;
577 }
578
579 template<typename T>
580 void deserialize(T* obj) {
581 Archive a;
582 m_operation = OPERATION_DESERIALIZE;
583 obj->serialize(&a);
584 a.m_root = UID::from(obj);
585 Syncer s(a, *this);
586 m_operation = OPERATION_NONE;
587 }
588
589 template<typename T>
590 void operator<<(const T& obj) {
591 serialize(&obj);
592 }
593
594 template<typename T>
595 void operator>>(T& obj) {
596 deserialize(&obj);
597 }
598
599 const RawData& rawData();
600 virtual String rawDataFormat() const;
601
602 template<typename T_classType, typename T_memberType>
603 void serializeMember(const T_classType& nativeObject, const T_memberType& nativeMember, const char* memberName) {
604 const size_t offset =
605 ((const uint8_t*)(const void*)&nativeMember) -
606 ((const uint8_t*)(const void*)&nativeObject);
607 const UIDChain uids = UIDChainResolver<T_memberType>(nativeMember);
608 const DataType type = DataType::dataTypeOf(nativeMember);
609 const Member member(memberName, uids[0], offset, type);
610 const UID parentUID = UID::from(nativeObject);
611 Object& parent = m_allObjects[parentUID];
612 if (!parent) {
613 const UIDChain uids = UIDChainResolver<T_classType>(nativeObject);
614 const DataType type = DataType::dataTypeOf(nativeObject);
615 parent = Object(uids, type);
616 }
617 parent.members().push_back(member);
618 const Object obj(uids, type);
619 const bool bExistsAlready = m_allObjects.count(uids[0]);
620 const bool isValidObject = obj;
621 const bool bExistingObjectIsInvalid = !m_allObjects[uids[0]];
622 if (!bExistsAlready || (bExistingObjectIsInvalid && isValidObject)) {
623 m_allObjects[uids[0]] = obj;
624 // recurse serialization for all members of this member
625 // (only for struct/class types, noop for primitive types)
626 SerializationRecursion<T_memberType>::serializeObject(this, nativeMember);
627 }
628 }
629
630 virtual void decode(const RawData& data);
631 virtual void decode(const uint8_t* data, size_t size);
632 void clear();
633 bool isModified() const;
634 void removeMember(Object& parent, const Member& member);
635 void remove(const Object& obj);
636 Object& rootObject();
637 Object& objectByUID(const UID& uid);
638 void setAutoValue(Object& object, String value);
639 void setIntValue(Object& object, int64_t value);
640 void setRealValue(Object& object, double value);
641 void setBoolValue(Object& object, bool value);
642 void setEnumValue(Object& object, uint64_t value);
643 String valueAsString(const Object& object);
644 int64_t valueAsInt(const Object& object);
645 double valueAsReal(const Object& object);
646 bool valueAsBool(const Object& object);
647 String name() const;
648 void setName(String name);
649 String comment() const;
650 void setComment(String comment);
651 time_t timeStampCreated() const;
652 time_t timeStampModified() const;
653 tm dateTimeCreated(time_base_t base = LOCAL_TIME) const;
654 tm dateTimeModified(time_base_t base = LOCAL_TIME) const;
655
656 protected:
657 // UID resolver for non-pointer types
658 template<typename T>
659 class UIDChainResolver {
660 public:
661 UIDChainResolver(const T& data) {
662 m_uid.push_back(UID::from(data));
663 }
664
665 operator UIDChain() const { return m_uid; }
666 UIDChain operator()() const { return m_uid; }
667 private:
668 UIDChain m_uid;
669 };
670
671 // UID resolver for pointer types (of 1st degree)
672 template<typename T>
673 class UIDChainResolver<T*> {
674 public:
675 UIDChainResolver(const T*& data) {
676 const UID uids[2] = {
677 { &data, sizeof(data) },
678 { data, sizeof(*data) }
679 };
680 m_uid.push_back(uids[0]);
681 m_uid.push_back(uids[1]);
682 }
683
684 operator UIDChain() const { return m_uid; }
685 UIDChain operator()() const { return m_uid; }
686 private:
687 UIDChain m_uid;
688 };
689
690 // SerializationRecursion for non-pointer class/struct types.
691 template<typename T, bool T_isRecursive>
692 struct SerializationRecursionImpl {
693 static void serializeObject(Archive* archive, const T& obj) {
694 const_cast<T&>(obj).serialize(archive);
695 }
696 };
697
698 // SerializationRecursion for pointers (of 1st degree) to class/structs.
699 template<typename T, bool T_isRecursive>
700 struct SerializationRecursionImpl<T*,T_isRecursive> {
701 static void serializeObject(Archive* archive, const T*& obj) {
702 if (!obj) return;
703 const_cast<T*&>(obj)->serialize(archive);
704 }
705 };
706
707 // NOOP SerializationRecursion for primitive types.
708 template<typename T>
709 struct SerializationRecursionImpl<T,false> {
710 static void serializeObject(Archive* archive, const T& obj) {}
711 };
712
713 // NOOP SerializationRecursion for pointers (of 1st degree) to primitive types.
714 template<typename T>
715 struct SerializationRecursionImpl<T*,false> {
716 static void serializeObject(Archive* archive, const T*& obj) {}
717 };
718
719 // Automatically handles recursion for class/struct types, while ignoring all primitive types.
720 template<typename T>
721 struct SerializationRecursion : SerializationRecursionImpl<T, LIBGIG_IS_CLASS(T)> {
722 };
723
724 class ObjectPool : public std::map<UID,Object> {
725 public:
726 // prevent passing obvious invalid UID values from creating a new pair entry
727 Object& operator[](const UID& k) {
728 static Object invalid;
729 if (!k.isValid()) {
730 invalid = Object();
731 return invalid;
732 }
733 return std::map<UID,Object>::operator[](k);
734 }
735 };
736
737 friend String _encode(const ObjectPool& objects);
738
739 private:
740 String _encodeRootBlob();
741 void _popRootBlob(const char*& p, const char* end);
742 void _popObjectsBlob(const char*& p, const char* end);
743
744 protected:
745 class Syncer {
746 public:
747 Syncer(Archive& dst, Archive& src);
748 protected:
749 void syncObject(const Object& dst, const Object& src);
750 void syncPrimitive(const Object& dst, const Object& src);
751 void syncPointer(const Object& dst, const Object& src);
752 void syncMember(const Member& dstMember, const Member& srcMember);
753 static Member dstMemberMatching(const Object& dstObj, const Object& srcObj, const Member& srcMember);
754 private:
755 Archive& m_dst;
756 Archive& m_src;
757 };
758
759 virtual void encode();
760
761 ObjectPool m_allObjects;
762 operation_t m_operation;
763 UID m_root;
764 RawData m_rawData;
765 bool m_isModified;
766 String m_name;
767 String m_comment;
768 time_t m_timeCreated;
769 time_t m_timeModified;
770 };
771
772 /**
773 * Will be thrown whenever an error occurs during an serialization or
774 * deserialization process.
775 */
776 class Exception {
777 public:
778 String Message;
779
780 Exception(String Message) { Exception::Message = Message; }
781 void PrintMessage();
782 virtual ~Exception() {}
783 };
784
785 } // namespace Serialization
786
787 #endif // LIBGIG_SERIALIZATION_H

  ViewVC Help
Powered by ViewVC