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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 3165 - (show annotations) (download) (as text)
Tue May 9 15:24:45 2017 UTC (6 years, 10 months ago) by schoenebeck
File MIME type: text/x-c++hdr
File size: 28854 byte(s)
- Yet another attempt to fix type traits issue.

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

  ViewVC Help
Powered by ViewVC