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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 3166 - (hide annotations) (download) (as text)
Tue May 9 16:10:36 2017 UTC (6 years, 11 months ago) by schoenebeck
File MIME type: text/x-c++hdr
File size: 28976 byte(s)
- And yet another attempt to fix type traits issue.

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

  ViewVC Help
Powered by ViewVC