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

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

Parent Directory Parent Directory | Revision Log Revision Log


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

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

  ViewVC Help
Powered by ViewVC