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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 3173 - (hide annotations) (download) (as text)
Wed May 10 23:07:28 2017 UTC (6 years, 11 months ago) by schoenebeck
File MIME type: text/x-c++hdr
File size: 29682 byte(s)
* Print compiler warning if no RTTI available.
* Serialization::DataType class: Implemented demangling C++ type
  names (for methods asLongDescr() and
  customTypeName(bool demangle=false)).
* gig.h: When there is no RTTI, only hide API functions which
  really require RTTI.
* Bumped version (4.0.0.svn21).

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 schoenebeck 3167 # 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 schoenebeck 3163 #endif
44 schoenebeck 3138
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 schoenebeck 3146 // just symbol prototyping
91     class DataType;
92     class Object;
93     class Member;
94 schoenebeck 3138 class Archive;
95 schoenebeck 3146 class ObjectPool;
96 schoenebeck 3138 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 schoenebeck 3156 enum time_base_t {
113     LOCAL_TIME,
114     UTC_TIME
115     };
116    
117 schoenebeck 3138 template<typename T>
118     bool IsEnum(const T& data) {
119 schoenebeck 3164 #if __cplusplus < 201103L
120 schoenebeck 3165 return std::tr1::is_enum<T>::value;
121 schoenebeck 3164 #else
122 schoenebeck 3138 return __is_enum(T);
123 schoenebeck 3164 #endif
124 schoenebeck 3138 }
125    
126     template<typename T>
127     bool IsUnion(const T& data) {
128 schoenebeck 3164 #if __cplusplus < 201103L
129 schoenebeck 3166 return false; // without compiler support we cannot distinguish union from class
130 schoenebeck 3164 #else
131 schoenebeck 3138 return __is_union(T);
132 schoenebeck 3164 #endif
133 schoenebeck 3138 }
134    
135     template<typename T>
136     bool IsClass(const T& data) {
137 schoenebeck 3164 #if __cplusplus < 201103L
138 schoenebeck 3166 return std::tr1::__is_union_or_class<T>::value; // without compiler support we cannot distinguish union from class
139 schoenebeck 3164 #else
140 schoenebeck 3138 return __is_class(T);
141 schoenebeck 3164 #endif
142 schoenebeck 3138 }
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 schoenebeck 3168 const UID uid = { (ID) &obj, sizeof(obj) };
184     return uid;
185 schoenebeck 3138 }
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 schoenebeck 3168 const UID uid = { (ID) obj, sizeof(*obj) };
193     return uid;
194 schoenebeck 3138 }
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 schoenebeck 3146 // prototyping of private internal friend functions
207 schoenebeck 3150 static String _encodePrimitiveValue(const Object& obj);
208 schoenebeck 3146 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 schoenebeck 3150 static String _primitiveObjectValueToString(const Object& obj);
213 schoenebeck 3169 // |
214     template<typename T>
215     static T _primitiveObjectValueToNumber(const Object& obj);
216 schoenebeck 3146
217 schoenebeck 3138 /** @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 schoenebeck 3173 String customTypeName(bool demangle = false) const;
246 schoenebeck 3138
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 schoenebeck 3150 friend class Archive;
321 schoenebeck 3138 };
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 schoenebeck 3153 Member memberByUID(const UID& uid) const;
395 schoenebeck 3138 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 schoenebeck 3153 protected:
406     void remove(const Member& member);
407    
408 schoenebeck 3138 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 schoenebeck 3150 friend String _encodePrimitiveValue(const Object& obj);
417 schoenebeck 3138 friend Object _popObjectBlob(const char*& p, const char* end);
418     friend void _popPrimitiveValue(const char*& p, const char* end, Object& obj);
419 schoenebeck 3150 friend String _primitiveObjectValueToString(const Object& obj);
420 schoenebeck 3169
421     template<typename T>
422     friend T _primitiveObjectValueToNumber(const Object& obj);
423    
424 schoenebeck 3150 friend class Archive;
425 schoenebeck 3138 };
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 schoenebeck 3142 * @endcode
439 schoenebeck 3138 * Or if you prefer the look of operator based code:
440     * @code
441     * Archive a;
442     * a << myRootObject;
443 schoenebeck 3142 * @endcode
444 schoenebeck 3138 * 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 schoenebeck 3142 * @endcode
459 schoenebeck 3138 * Or with operator instead:
460     * @code
461     * Archive a(rawDataStream);
462     * a >> myRootObject;
463 schoenebeck 3142 * @endcode
464 schoenebeck 3138 * 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 schoenebeck 3150 const RawData& rawData();
579 schoenebeck 3138 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 schoenebeck 3150 bool isModified() const;
613 schoenebeck 3153 void removeMember(Object& parent, const Member& member);
614 schoenebeck 3138 void remove(const Object& obj);
615     Object& rootObject();
616     Object& objectByUID(const UID& uid);
617 schoenebeck 3150 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 schoenebeck 3169 int64_t valueAsInt(const Object& object);
624     double valueAsReal(const Object& object);
625     bool valueAsBool(const Object& object);
626 schoenebeck 3156 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 schoenebeck 3138
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 schoenebeck 3168 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 schoenebeck 3138 }
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 schoenebeck 3167 struct SerializationRecursion : SerializationRecursionImpl<T, LIBGIG_IS_CLASS(T)> {
701 schoenebeck 3138 };
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 schoenebeck 3150 bool m_isModified;
745 schoenebeck 3156 String m_name;
746     String m_comment;
747     time_t m_timeCreated;
748     time_t m_timeModified;
749 schoenebeck 3138 };
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