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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 3169 - (show annotations) (download) (as text)
Wed May 10 21:17:10 2017 UTC (6 years, 10 months ago) by schoenebeck
File MIME type: text/x-c++hdr
File size: 29689 byte(s)
* src/gig.h: Added enum reflection API functions for
  retrieving enum declaration type information at
  runtime (countEnum(), enumKey(), enumKeys(),
  enumValue()).
* Archive: Added methods valueAsInt(), valueAsReal()
  and valueAsBool().
* Bumped version (4.0.0.svn20).

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

  ViewVC Help
Powered by ViewVC