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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 3156 - (hide annotations) (download) (as text)
Mon May 8 17:18:07 2017 UTC (6 years, 11 months ago) by schoenebeck
File MIME type: text/x-c++hdr
File size: 28470 byte(s)
* class Archive: Added methods name() and setName().
* class Archive: Added methods comment() and setComment().
* class Archive: Added methods timeStampCreated(),
  timeStampModified(), dateTimeCreated() and
  dateTimeModified().
* Bumped version (4.0.0.svn18).

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

  ViewVC Help
Powered by ViewVC