libgig 4.4.0
Serialization.h
1/***************************************************************************
2 * *
3 * Copyright (C) 2017-2020 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 <set>
38#include <time.h>
39#include <stdarg.h>
40#include <assert.h>
41#include <functional>
42
43#ifdef _MSC_VER
44#include <BaseTsd.h>
45using ssize_t = SSIZE_T;
46#endif
47
48#ifndef __has_extension
49# define __has_extension(x) 0
50#endif
51
52#ifndef HAS_BUILTIN_TYPE_TRAITS
53# if __cplusplus >= 201103L
54# define HAS_BUILTIN_TYPE_TRAITS 1
55# elif ( __has_extension(is_class) && __has_extension(is_enum) )
56# define HAS_BUILTIN_TYPE_TRAITS 1
57# elif ( __GNUC__ > 4 || ( __GNUC__ == 4 && __GNUC_MINOR__ >= 3 ) )
58# define HAS_BUILTIN_TYPE_TRAITS 1
59# elif _MSC_VER >= 1400 /* MS Visual C++ 8.0 (Visual Studio 2005) */
60# define HAS_BUILTIN_TYPE_TRAITS 1
61# elif __INTEL_COMPILER >= 1100
62# define HAS_BUILTIN_TYPE_TRAITS 1
63# else
64# define HAS_BUILTIN_TYPE_TRAITS 0
65# endif
66#endif
67
68#if !HAS_BUILTIN_TYPE_TRAITS
69# include <tr1/type_traits>
70# define LIBGIG_IS_CLASS(type) std::tr1::__is_union_or_class<type>::value //NOTE: without compiler support we cannot distinguish union from class
71#else
72# define LIBGIG_IS_CLASS(type) __is_class(type)
73#endif
74
118namespace Serialization {
119
120 // just symbol prototyping
121 class DataType;
122 class Object;
123 class Member;
124 class Archive;
125 class ObjectPool;
126 class Exception;
127
135 typedef std::string String;
136
149 template<class T>
150 using Array = std::vector<T>;
151
161 template<class T>
162 using Set = std::set<T>;
163
182 template<class T_key, class T_value>
183 using Map = std::map<T_key,T_value>;
184
193 typedef std::vector<uint8_t> RawData;
194
205 typedef void* ID;
206
214 typedef uint32_t Version;
215
225
233 template<typename T>
234 bool IsEnum(const T& data) {
235 #if !HAS_BUILTIN_TYPE_TRAITS
236 return std::tr1::is_enum<T>::value;
237 #else
238 return __is_enum(T);
239 #endif
240 }
241
252 template<typename T>
253 bool IsUnion(const T& data) {
254 #if !HAS_BUILTIN_TYPE_TRAITS
255 return false; // without compiler support we cannot distinguish union from class
256 #else
257 return __is_union(T);
258 #endif
259 }
260
270 template<typename T>
271 bool IsClass(const T& data) {
272 #if !HAS_BUILTIN_TYPE_TRAITS
273 return std::tr1::__is_union_or_class<T>::value; // without compiler support we cannot distinguish union from class
274 #else
275 return __is_class(T);
276 #endif
277 }
278
279 /*template<typename T>
280 bool IsTrivial(T data) {
281 return __is_trivial(T);
282 }*/
283
284 /*template<typename T>
285 bool IsPOD(T data) {
286 return __is_pod(T);
287 }*/
288
289 /*template<typename T>
290 bool IsArray(const T& data) {
291 return false;
292 }*/
293
294 /*template<typename T>
295 bool IsArray(const Array<T>& data) {
296 return true;
297 }*/
298
299 template<typename T> inline
300 String toString(const T& value) {
301 return std::to_string(value);
302 }
303
304 template<> inline
305 String toString(const String& value) {
306 return value;
307 }
308
324 class UID {
325 public:
327 size_t size;
328
329 bool isValid() const;
330 operator bool() const { return isValid(); }
331 //bool operator()() const { return isValid(); }
332 bool operator==(const UID& other) const { return id == other.id && size == other.size; }
333 bool operator!=(const UID& other) const { return id != other.id || size != other.size; }
334 bool operator<(const UID& other) const { return id < other.id || (id == other.id && size < other.size); }
335 bool operator>(const UID& other) const { return id > other.id || (id == other.id && size > other.size); }
336
344 template<typename T>
345 static UID from(const T& obj) {
346 return Resolver<T>::resolve(obj);
347 }
348
349 protected:
350 // UID resolver for non-pointer types
351 template<typename T>
352 struct Resolver {
353 static UID resolve(const T& obj) {
354 const UID uid = { (ID) &obj, sizeof(obj) };
355 return uid;
356 }
357 };
358
359 // UID resolver for pointer types (of 1st degree)
360 template<typename T>
361 struct Resolver<T*> {
362 static UID resolve(const T* const & obj) {
363 const UID uid = { (ID) obj, sizeof(*obj) };
364 return uid;
365 }
366 };
367 };
368
374 extern const UID NO_UID;
375
407 typedef std::vector<UID> UIDChain;
408
409#if LIBGIG_SERIALIZATION_INTERNAL
410 // prototyping of private internal friend functions
411 static String _encodePrimitiveValue(const Object& obj);
412 static DataType _popDataTypeBlob(const char*& p, const char* end);
413 static Member _popMemberBlob(const char*& p, const char* end);
414 static Object _popObjectBlob(const char*& p, const char* end);
415 static void _popPrimitiveValue(const char*& p, const char* end, Object& obj);
416 static String _primitiveObjectValueToString(const Object& obj);
417 // |
418 template<typename T>
419 static T _primitiveObjectValueToNumber(const Object& obj);
420#endif // LIBGIG_SERIALIZATION_INTERNAL
421
438 class DataType {
439 public:
440 DataType();
441 size_t size() const { return m_size; }
442 bool isValid() const;
443 bool isPointer() const;
444 bool isClass() const;
445 bool isPrimitive() const;
446 bool isString() const;
447 bool isInteger() const;
448 bool isReal() const;
449 bool isBool() const;
450 bool isEnum() const;
451 bool isArray() const;
452 bool isSet() const;
453 bool isMap() const;
454 bool isSigned() const;
455 operator bool() const { return isValid(); }
456 //bool operator()() const { return isValid(); }
457 bool operator==(const DataType& other) const;
458 bool operator!=(const DataType& other) const;
459 bool operator<(const DataType& other) const;
460 bool operator>(const DataType& other) const;
461 String asLongDescr() const;
462 String baseTypeName() const;
463 String customTypeName(bool demangle = false) const;
464 String customTypeName2(bool demangle = false) const;
465
476 template<typename T>
477 static DataType dataTypeOf(const T& data) {
478 return Resolver<T>::resolve(data);
479 }
480
481 protected:
482 DataType(bool isPointer, int size, String baseType,
483 String customType1 = "", String customType2 = "");
484
485 template<typename T, bool T_isPointer>
486 struct ResolverBase {
487 static DataType resolve(const T& data) {
488 const std::type_info& type = typeid(data);
489 const int sz = sizeof(data);
490
491 // for primitive types we are using our own type names instead of
492 // using std:::type_info::name(), because the precise output of the
493 // latter may vary between compilers
494 if (type == typeid(int8_t)) return DataType(T_isPointer, sz, "int8");
495 if (type == typeid(uint8_t)) return DataType(T_isPointer, sz, "uint8");
496 if (type == typeid(int16_t)) return DataType(T_isPointer, sz, "int16");
497 if (type == typeid(uint16_t)) return DataType(T_isPointer, sz, "uint16");
498 if (type == typeid(int32_t)) return DataType(T_isPointer, sz, "int32");
499 if (type == typeid(uint32_t)) return DataType(T_isPointer, sz, "uint32");
500 if (type == typeid(int64_t)) return DataType(T_isPointer, sz, "int64");
501 if (type == typeid(uint64_t)) return DataType(T_isPointer, sz, "uint64");
502 if (type == typeid(size_t)) {
503 if (sz == 1) return DataType(T_isPointer, sz, "uint8");
504 if (sz == 2) return DataType(T_isPointer, sz, "uint16");
505 if (sz == 4) return DataType(T_isPointer, sz, "uint32");
506 if (sz == 8) return DataType(T_isPointer, sz, "uint64");
507 else assert(false /* unknown size_t size */);
508 }
509 if (type == typeid(ssize_t)) {
510 if (sz == 1) return DataType(T_isPointer, sz, "int8");
511 if (sz == 2) return DataType(T_isPointer, sz, "int16");
512 if (sz == 4) return DataType(T_isPointer, sz, "int32");
513 if (sz == 8) return DataType(T_isPointer, sz, "int64");
514 else assert(false /* unknown ssize_t size */);
515 }
516 if (type == typeid(bool)) return DataType(T_isPointer, sz, "bool");
517 if (type == typeid(float)) return DataType(T_isPointer, sz, "real32");
518 if (type == typeid(double)) return DataType(T_isPointer, sz, "real64");
519 if (type == typeid(String)) return DataType(T_isPointer, sz, "String");
520
521 if (IsEnum(data)) return DataType(T_isPointer, sz, "enum", rawCppTypeNameOf(data));
522 if (IsUnion(data)) return DataType(T_isPointer, sz, "union", rawCppTypeNameOf(data));
523 if (IsClass(data)) return DataType(T_isPointer, sz, "class", rawCppTypeNameOf(data));
524
525 return DataType();
526 }
527 };
528
529 // DataType resolver for non-pointer types
530 template<typename T>
531 struct Resolver : ResolverBase<T,false> {
532 static DataType resolve(const T& data) {
533 return ResolverBase<T,false>::resolve(data);
534 }
535 };
536
537 // DataType resolver for pointer types (of 1st degree)
538 template<typename T>
539 struct Resolver<T*> : ResolverBase<T,true> {
540 static DataType resolve(const T*& data) {
541 return ResolverBase<T,true>::resolve(*data);
542 }
543 };
544
545 // DataType resolver for non-pointer Array<> container object types.
546 template<typename T>
547 struct Resolver<Array<T>> {
548 static DataType resolve(const Array<T>& data) {
549 const int sz = sizeof(data);
550 T unused;
551 return DataType(false, sz, "Array", rawCppTypeNameOf(unused));
552 }
553 };
554
555 // DataType resolver for Array<> pointer types (of 1st degree).
556 template<typename T>
557 struct Resolver<Array<T>*> {
558 static DataType resolve(const Array<T>*& data) {
559 const int sz = sizeof(*data);
560 T unused;
561 return DataType(true, sz, "Array", rawCppTypeNameOf(unused));
562 }
563 };
564
565 // DataType resolver for non-pointer Set<> container object types.
566 template<typename T>
567 struct Resolver<Set<T>> {
568 static DataType resolve(const Set<T>& data) {
569 const int sz = sizeof(data);
570 T unused;
571 return DataType(false, sz, "Set", rawCppTypeNameOf(unused));
572 }
573 };
574
575 // DataType resolver for Set<> pointer types (of 1st degree).
576 template<typename T>
577 struct Resolver<Set<T>*> {
578 static DataType resolve(const Set<T>*& data) {
579 const int sz = sizeof(*data);
580 T unused;
581 return DataType(true, sz, "Set", rawCppTypeNameOf(unused));
582 }
583 };
584
585 // DataType resolver for non-pointer Map<> container object types.
586 template<typename T_key, typename T_value>
587 struct Resolver<Map<T_key,T_value>> {
588 static DataType resolve(const Map<T_key,T_value>& data) {
589 const int sz = sizeof(data);
590 T_key unused1;
591 T_value unused2;
592 return DataType(false, sz, "Map", rawCppTypeNameOf(unused1),
593 rawCppTypeNameOf(unused2));
594 }
595 };
596
597 // DataType resolver for Map<> pointer types (of 1st degree).
598 template<typename T_key, typename T_value>
599 struct Resolver<Map<T_key,T_value>*> {
600 static DataType resolve(const Map<T_key,T_value>*& data) {
601 const int sz = sizeof(*data);
602 T_key unused1;
603 T_value unused2;
604 return DataType(true, sz, "Map", rawCppTypeNameOf(unused1),
605 rawCppTypeNameOf(unused2));
606 }
607 };
608
609 template<typename T>
610 static String rawCppTypeNameOf(const T& data) {
611 #if defined _MSC_VER // Microsoft compiler ...
612 String name = typeid(data).raw_name();
613 #else // i.e. especially GCC and clang ...
614 String name = typeid(data).name();
615 #endif
616 //while (!name.empty() && name[0] >= 0 && name[0] <= 9)
617 // name = name.substr(1);
618 return name;
619 }
620
621 private:
622 String m_baseTypeName;
623 String m_customTypeName;
624 String m_customTypeName2;
625 int m_size;
626 bool m_isPointer;
627
628#if LIBGIG_SERIALIZATION_INTERNAL
629 friend DataType _popDataTypeBlob(const char*& p, const char* end);
630#endif
631 friend class Archive;
632 };
633
655 class Member {
656 public:
657 Member();
658 UID uid() const;
659 String name() const;
660 ssize_t offset() const;
661 const DataType& type() const;
662 bool isValid() const;
663 operator bool() const { return isValid(); }
664 //bool operator()() const { return isValid(); }
665 bool operator==(const Member& other) const;
666 bool operator!=(const Member& other) const;
667 bool operator<(const Member& other) const;
668 bool operator>(const Member& other) const;
669
670 protected:
672 friend class Archive;
673
674 private:
675 UID m_uid;
676 ssize_t m_offset;
677 String m_name;
678 DataType m_type;
679
680#if LIBGIG_SERIALIZATION_INTERNAL
681 friend Member _popMemberBlob(const char*& p, const char* end);
682#endif
683 };
684
709 class Object {
710 public:
711 Object();
713
714 UID uid(int index = 0) const;
715 const UIDChain& uidChain() const;
716 const DataType& type() const;
717 const RawData& rawData() const;
718 Version version() const;
719 Version minVersion() const;
720 bool isVersionCompatibleTo(const Object& other) const;
721 std::vector<Member>& members();
722 const std::vector<Member>& members() const;
723 Member memberNamed(String name) const;
724 Member memberByUID(const UID& uid) const;
725 std::vector<Member> membersOfType(const DataType& type) const;
726 int sequenceIndexOf(const Member& member) const;
727 bool isValid() const;
728 operator bool() const { return isValid(); }
729 //bool operator()() const { return isValid(); }
730 bool operator==(const Object& other) const;
731 bool operator!=(const Object& other) const;
732 bool operator<(const Object& other) const;
733 bool operator>(const Object& other) const;
734 void setNativeValueFromString(const String& s);
735
736 protected:
737 void remove(const Member& member);
738 void setVersion(Version v);
739 void setMinVersion(Version v);
740
741 private:
742 DataType m_type;
743 UIDChain m_uid;
744 Version m_version;
745 Version m_minVersion;
746 RawData m_data;
747 std::vector<Member> m_members;
748 std::function<void(Object& dstObj, const Object& srcObj, void* syncer)> m_sync;
749
750#if LIBGIG_SERIALIZATION_INTERNAL
751 friend String _encodePrimitiveValue(const Object& obj);
752 friend Object _popObjectBlob(const char*& p, const char* end);
753 friend void _popPrimitiveValue(const char*& p, const char* end, Object& obj);
754 friend String _primitiveObjectValueToString(const Object& obj);
755 // |
756 template<typename T>
757 friend T _primitiveObjectValueToNumber(const Object& obj);
758#endif // LIBGIG_SERIALIZATION_INTERNAL
759
760 friend class Archive;
761 };
762
900 class Archive {
901 public:
909
910 Archive();
911 Archive(const RawData& data);
912 Archive(const uint8_t* data, size_t size);
913 virtual ~Archive();
914
940 template<typename T>
941 void serialize(const T* obj) {
942 m_operation = OPERATION_SERIALIZE;
943 m_allObjects.clear();
944 m_rawData.clear();
945 m_root = UID::from(obj);
946 const_cast<T*>(obj)->serialize(this);
947 encode();
948 m_operation = OPERATION_NONE;
949 }
950
975 template<typename T>
976 void deserialize(T* obj) {
977 Archive a;
978 a.m_operation = m_operation = OPERATION_DESERIALIZE;
979 obj->serialize(&a);
980 a.m_root = UID::from(obj);
981 Syncer s(a, *this);
982 a.m_operation = m_operation = OPERATION_NONE;
983 }
984
999 template<typename T>
1000 void operator<<(const T& obj) {
1001 serialize(&obj);
1002 }
1003
1022 template<typename T>
1023 void operator>>(T& obj) {
1024 deserialize(&obj);
1025 }
1026
1027 const RawData& rawData();
1028 virtual String rawDataFormat() const;
1029
1086 template<typename T_classType, typename T_memberType>
1087 void serializeMember(const T_classType& nativeObject, const T_memberType& nativeMember, const char* memberName) {
1088 const ssize_t offset =
1089 ((const uint8_t*)(const void*)&nativeMember) -
1090 ((const uint8_t*)(const void*)&nativeObject);
1091 const UIDChain uids = UIDChainResolver<T_memberType>(nativeMember);
1092 const DataType type = DataType::dataTypeOf(nativeMember);
1093 const Member member(memberName, uids[0], offset, type);
1094 const UID parentUID = UID::from(nativeObject);
1095 Object& parent = m_allObjects[parentUID];
1096 if (!parent) {
1097 const UIDChain uids = UIDChainResolver<T_classType>(nativeObject);
1098 const DataType type = DataType::dataTypeOf(nativeObject);
1099 parent = Object(uids, type);
1100 }
1101 parent.members().push_back(member);
1102 const Object obj(uids, type);
1103 const bool bExistsAlready = m_allObjects.count(uids[0]);
1104 const bool isValidObject = obj;
1105 const bool bExistingObjectIsInvalid = !m_allObjects[uids[0]];
1106 if (!bExistsAlready || (bExistingObjectIsInvalid && isValidObject)) {
1107 m_allObjects[uids[0]] = obj;
1108 // recurse serialization for all members of this member
1109 // (only for struct/class types, noop for primitive types)
1110 SerializationRecursion<T_memberType>::serializeObject(this, nativeMember);
1111 }
1112 }
1113
1144 template<typename T_classType, typename T_memberType>
1145 void serializeHeapMember(const T_classType& nativeObject, const T_memberType& heapMember, const char* memberName) {
1146 const ssize_t offset = -1; // used for all members on heap
1147 const UIDChain uids = UIDChainResolver<T_memberType>(heapMember);
1148 const DataType type = DataType::dataTypeOf(heapMember);
1149 const Member member(memberName, uids[0], offset, type);
1150 const UID parentUID = UID::from(nativeObject);
1151 Object& parent = m_allObjects[parentUID];
1152 if (!parent) {
1153 const UIDChain uids = UIDChainResolver<T_classType>(nativeObject);
1154 const DataType type = DataType::dataTypeOf(nativeObject);
1155 parent = Object(uids, type);
1156 }
1157 parent.members().push_back(member);
1158 const Object obj(uids, type);
1159 const bool bExistsAlready = m_allObjects.count(uids[0]);
1160 const bool isValidObject = obj;
1161 const bool bExistingObjectIsInvalid = !m_allObjects[uids[0]];
1162 if (!bExistsAlready || (bExistingObjectIsInvalid && isValidObject)) {
1163 m_allObjects[uids[0]] = obj;
1164 // recurse serialization for all members of this member
1165 // (only for struct/class types, noop for primitive types)
1166 SerializationRecursion<T_memberType>::serializeObject(this, heapMember);
1167 }
1168 }
1169
1249 template<typename T_classType>
1250 void setVersion(const T_classType& nativeObject, Version v) {
1251 const UID uid = UID::from(nativeObject);
1252 Object& obj = m_allObjects[uid];
1253 if (!obj) {
1254 const UIDChain uids = UIDChainResolver<T_classType>(nativeObject);
1255 const DataType type = DataType::dataTypeOf(nativeObject);
1256 obj = Object(uids, type);
1257 }
1258 setVersion(obj, v);
1259 }
1260
1290 template<typename T_classType>
1291 void setMinVersion(const T_classType& nativeObject, Version v) {
1292 const UID uid = UID::from(nativeObject);
1293 Object& obj = m_allObjects[uid];
1294 if (!obj) {
1295 const UIDChain uids = UIDChainResolver<T_classType>(nativeObject);
1296 const DataType type = DataType::dataTypeOf(nativeObject);
1297 obj = Object(uids, type);
1298 }
1299 setMinVersion(obj, v);
1300 }
1301
1302 virtual void decode(const RawData& data);
1303 virtual void decode(const uint8_t* data, size_t size);
1304 void clear();
1305 bool isModified() const;
1306 void removeMember(Object& parent, const Member& member);
1307 void remove(const Object& obj);
1308 Object& rootObject();
1309 Object& objectByUID(const UID& uid);
1310 void setAutoValue(Object& object, String value);
1311 void setIntValue(Object& object, int64_t value);
1312 void setRealValue(Object& object, double value);
1313 void setBoolValue(Object& object, bool value);
1314 void setEnumValue(Object& object, uint64_t value);
1315 void setStringValue(Object& object, String value);
1316 String valueAsString(const Object& object);
1317 int64_t valueAsInt(const Object& object);
1318 double valueAsReal(const Object& object);
1319 bool valueAsBool(const Object& object);
1320 void setVersion(Object& object, Version v);
1321 void setMinVersion(Object& object, Version v);
1322 String name() const;
1323 void setName(String name);
1324 String comment() const;
1326 time_t timeStampCreated() const;
1327 time_t timeStampModified() const;
1328 tm dateTimeCreated(time_base_t base = LOCAL_TIME) const;
1329 tm dateTimeModified(time_base_t base = LOCAL_TIME) const;
1330 operation_t operation() const;
1331
1332 protected:
1333 // UID resolver for non-pointer types
1334 template<typename T>
1335 class UIDChainResolver {
1336 public:
1337 UIDChainResolver(const T& data) {
1338 m_uid.push_back(UID::from(data));
1339 }
1340
1341 operator UIDChain() const { return m_uid; }
1342 UIDChain operator()() const { return m_uid; }
1343 private:
1344 UIDChain m_uid;
1345 };
1346
1347 // UID resolver for pointer types (of 1st degree)
1348 template<typename T>
1349 class UIDChainResolver<T*> {
1350 public:
1351 UIDChainResolver(const T*& data) {
1352 const UID uids[2] = {
1353 { &data, sizeof(data) },
1354 { data, sizeof(*data) }
1355 };
1356 m_uid.push_back(uids[0]);
1357 m_uid.push_back(uids[1]);
1358 }
1359
1360 operator UIDChain() const { return m_uid; }
1361 UIDChain operator()() const { return m_uid; }
1362 private:
1363 UIDChain m_uid;
1364 };
1365
1366 // SerializationRecursion for non-pointer class/struct types.
1367 template<typename T, bool T_isRecursive>
1368 struct SerializationRecursionImpl {
1369 static void serializeObject(Archive* archive, const T& obj) {
1370 const_cast<T&>(obj).serialize(archive);
1371 }
1372 };
1373
1374 // SerializationRecursion for pointers (of 1st degree) to class/structs.
1375 template<typename T, bool T_isRecursive>
1376 struct SerializationRecursionImpl<T*,T_isRecursive> {
1377 static void serializeObject(Archive* archive, const T*& obj) {
1378 if (!obj) return;
1379 const_cast<T*&>(obj)->serialize(archive);
1380 }
1381 };
1382
1383 // NOOP SerializationRecursion for primitive types.
1384 template<typename T>
1385 struct SerializationRecursionImpl<T,false> {
1386 static void serializeObject(Archive* archive, const T& obj) {}
1387 };
1388
1389 // NOOP SerializationRecursion for pointers (of 1st degree) to primitive types.
1390 template<typename T>
1391 struct SerializationRecursionImpl<T*,false> {
1392 static void serializeObject(Archive* archive, const T*& obj) {}
1393 };
1394
1395 // NOOP SerializationRecursion for String objects.
1396 template<bool T_isRecursive>
1397 struct SerializationRecursionImpl<String,T_isRecursive> {
1398 static void serializeObject(Archive* archive, const String& obj) {}
1399 };
1400
1401 // NOOP SerializationRecursion for String pointers (of 1st degree).
1402 template<bool T_isRecursive>
1403 struct SerializationRecursionImpl<String*,T_isRecursive> {
1404 static void serializeObject(Archive* archive, const String*& obj) {}
1405 };
1406
1407 // SerializationRecursion for Array<> objects.
1408 template<typename T, bool T_isRecursive>
1409 struct SerializationRecursionImpl<Array<T>,T_isRecursive> {
1410 static void serializeObject(Archive* archive, const Array<T>& obj) {
1411 const UIDChain uids = UIDChainResolver<Array<T>>(obj);
1412 const Object& object = archive->objectByUID(uids[0]);
1413 if (archive->operation() == OPERATION_SERIALIZE) {
1414 for (size_t i = 0; i < obj.size(); ++i) {
1415 archive->serializeHeapMember(
1416 obj, obj[i], ("[" + toString(i) + "]").c_str()
1417 );
1418 }
1419 } else {
1420 const_cast<Object&>(object).m_sync =
1421 [&obj,archive](Object& dstObj, const Object& srcObj,
1422 void* syncer)
1423 {
1424 const size_t n = srcObj.members().size();
1425 const_cast<Array<T>&>(obj).resize(n);
1426 for (size_t i = 0; i < obj.size(); ++i) {
1427 archive->serializeHeapMember(
1428 obj, obj[i], ("[" + toString(i) + "]").c_str()
1429 );
1430 }
1431 // updating dstObj required as serializeHeapMember()
1432 // replaced the original object by a new one
1433 dstObj = archive->objectByUID(dstObj.uid());
1434 for (size_t i = 0; i < obj.size(); ++i) {
1435 String name = "[" + toString(i) + "]";
1436 Member srcMember = srcObj.memberNamed(name);
1437 Member dstMember = dstObj.memberNamed(name);
1438 ((Syncer*)syncer)->syncMember(dstMember, srcMember);
1439 }
1440 };
1441 }
1442 }
1443 };
1444
1445 // SerializationRecursion for Array<> pointers (of 1st degree).
1446 template<typename T, bool T_isRecursive>
1447 struct SerializationRecursionImpl<Array<T>*,T_isRecursive> {
1448 static void serializeObject(Archive* archive, const Array<T>*& obj) {
1449 if (!obj) return;
1450 SerializationRecursionImpl<Array<T>,T_isRecursive>::serializeObject(
1451 archive, *obj
1452 );
1453 }
1454 };
1455
1456 // SerializationRecursion for Set<> objects.
1457 template<typename T, bool T_isRecursive>
1458 struct SerializationRecursionImpl<Set<T>,T_isRecursive> {
1459 static void serializeObject(Archive* archive, const Set<T>& obj) {
1460 const UIDChain uids = UIDChainResolver<Set<T>>(obj);
1461 const Object& object = archive->objectByUID(uids[0]);
1462 if (archive->operation() == OPERATION_SERIALIZE) {
1463 for (const T& key : obj) {
1464 archive->serializeHeapMember(
1465 obj, key, ("[" + toString(key) + "]").c_str()
1466 );
1467 }
1468 } else {
1469 const_cast<Object&>(object).m_sync =
1470 [&obj,archive](Object& dstObj, const Object& srcObj,
1471 void* syncer)
1472 {
1473 const size_t n = srcObj.members().size();
1474 const_cast<Set<T>&>(obj).clear();
1475 for (size_t i = 0; i < n; ++i) {
1476 const Member& member = srcObj.members()[i];
1477 String name = member.name();
1478 if (name.length() < 2 || name[0] != '[' ||
1479 *name.rbegin() != ']') continue;
1480 name = name.substr(1, name.length() - 2);
1481 T key;
1482 const UIDChain uids = UIDChainResolver<T>(key);
1483 const DataType type = DataType::dataTypeOf(key);
1484 Object tmpObj(uids, type);
1485 tmpObj.setNativeValueFromString(name);
1486 const_cast<Set<T>&>(obj).insert(key);
1487 }
1488 for (const T& key : obj) {
1489 archive->serializeHeapMember(
1490 obj, key, ("[" + toString(key) + "]").c_str()
1491 );
1492 }
1493 // updating dstObj required as serializeHeapMember()
1494 // replaced the original object by a new one
1495 dstObj = archive->objectByUID(dstObj.uid());
1496 };
1497 }
1498 }
1499 };
1500
1501 // SerializationRecursion for Set<> pointers (of 1st degree).
1502 template<typename T, bool T_isRecursive>
1503 struct SerializationRecursionImpl<Set<T>*,T_isRecursive> {
1504 static void serializeObject(Archive* archive, const Set<T>*& obj) {
1505 if (!obj) return;
1506 SerializationRecursionImpl<Set<T>,T_isRecursive>::serializeObject(
1507 archive, *obj
1508 );
1509 }
1510 };
1511
1512 // SerializationRecursion for Map<> objects.
1513 template<typename T_key, typename T_value, bool T_isRecursive>
1514 struct SerializationRecursionImpl<Map<T_key,T_value>,T_isRecursive> {
1515 static void serializeObject(Archive* archive, const Map<T_key,T_value>& obj) {
1516 const UIDChain uids = UIDChainResolver<Map<T_key,T_value>>(obj);
1517 const Object& object = archive->objectByUID(uids[0]);
1518 if (archive->operation() == OPERATION_SERIALIZE) {
1519 for (const auto& it : obj) {
1520 archive->serializeHeapMember(
1521 obj, it.second, ("[" + toString(it.first) + "]").c_str()
1522 );
1523 }
1524 } else {
1525 const_cast<Object&>(object).m_sync =
1526 [&obj,archive](Object& dstObj, const Object& srcObj,
1527 void* syncer)
1528 {
1529 const size_t n = srcObj.members().size();
1530 const_cast<Map<T_key,T_value>&>(obj).clear();
1531 for (size_t i = 0; i < n; ++i) {
1532 const Member& member = srcObj.members()[i];
1533 String name = member.name();
1534 if (name.length() < 2 || name[0] != '[' ||
1535 *name.rbegin() != ']') continue;
1536 name = name.substr(1, name.length() - 2);
1537 T_key key;
1538 const UIDChain uids = UIDChainResolver<T_key>(key);
1539 const DataType type = DataType::dataTypeOf(key);
1540 Object tmpObj(uids, type);
1541 tmpObj.setNativeValueFromString(name);
1542 const_cast<Map<T_key,T_value>&>(obj)[key] = T_value();
1543 }
1544 for (const auto& it : obj) {
1545 archive->serializeHeapMember(
1546 obj, it.second, ("[" + toString(it.first) + "]").c_str()
1547 );
1548 }
1549 // updating dstObj required as serializeHeapMember()
1550 // replaced the original object by a new one
1551 dstObj = archive->objectByUID(dstObj.uid());
1552 for (size_t i = 0; i < n; ++i) {
1553 Member srcMember = srcObj.members()[i];
1554 Member dstMember = dstObj.memberNamed(srcMember.name());
1555 ((Syncer*)syncer)->syncMember(dstMember, srcMember);
1556 }
1557 };
1558 }
1559 }
1560 };
1561
1562 // SerializationRecursion for Map<> pointers (of 1st degree).
1563 template<typename T_key, typename T_value, bool T_isRecursive>
1564 struct SerializationRecursionImpl<Map<T_key,T_value>*,T_isRecursive> {
1565 static void serializeObject(Archive* archive, const Map<T_key,T_value>*& obj) {
1566 if (!obj) return;
1567 SerializationRecursionImpl<Map<T_key,T_value>,T_isRecursive>::serializeObject(
1568 archive, *obj
1569 );
1570 }
1571 };
1572
1573 // Automatically handles recursion for class/struct types, while ignoring all primitive types.
1574 template<typename T>
1575 struct SerializationRecursion : SerializationRecursionImpl<T, LIBGIG_IS_CLASS(T)> {
1576 };
1577
1578 class ObjectPool : public std::map<UID,Object> {
1579 public:
1580 // prevent passing obvious invalid UID values from creating a new pair entry
1581 Object& operator[](const UID& k) {
1582 static Object invalid;
1583 if (!k.isValid()) {
1584 invalid = Object();
1585 return invalid;
1586 }
1587 return std::map<UID,Object>::operator[](k);
1588 }
1589 };
1590
1591 friend String _encode(const ObjectPool& objects);
1592
1593 private:
1594 String _encodeRootBlob();
1595 void _popRootBlob(const char*& p, const char* end);
1596 void _popObjectsBlob(const char*& p, const char* end);
1597
1598 protected:
1638 class Syncer {
1639 public:
1640 Syncer(Archive& dst, Archive& src);
1641 void syncObject(const Object& dst, const Object& src);
1642 void syncPrimitive(const Object& dst, const Object& src);
1643 void syncString(const Object& dst, const Object& src);
1644 void syncArray(const Object& dst, const Object& src);
1645 void syncSet(const Object& dst, const Object& src);
1646 void syncMap(const Object& dst, const Object& src);
1647 void syncPointer(const Object& dst, const Object& src);
1648 void syncMember(const Member& dstMember, const Member& srcMember);
1649 protected:
1650 static Member dstMemberMatching(const Object& dstObj, const Object& srcObj, const Member& srcMember);
1651 private:
1652 Archive& m_dst;
1653 Archive& m_src;
1654 };
1655
1656 virtual void encode();
1657
1658 ObjectPool m_allObjects;
1659 operation_t m_operation;
1660 UID m_root;
1661 RawData m_rawData;
1662 bool m_isModified;
1663 String m_name;
1664 String m_comment;
1665 time_t m_timeCreated;
1666 time_t m_timeModified;
1667 };
1668
1674 public:
1675 String Message;
1676
1677 Exception(String format, ...);
1678 Exception(String format, va_list arg);
1679 void PrintMessage();
1680 virtual ~Exception() {}
1681
1682 protected:
1683 Exception();
1684 static String assemble(String format, va_list arg);
1685 };
1686
1687} // namespace Serialization
1688
1689#endif // LIBGIG_SERIALIZATION_H
Synchronizes 2 archives with each other.
Destination container for serialization, and source container for deserialization.
void setStringValue(Object &object, String value)
Set new textual string for given String object.
void setRealValue(Object &object, double value)
Set new floating point value for given floating point object.
void serializeMember(const T_classType &nativeObject, const T_memberType &nativeMember, const char *memberName)
Serialize a native C/C++ member variable.
void setMinVersion(const T_classType &nativeObject, Version v)
Set a minimum version number for your C++ class.
void setName(String name)
Assign a name to this archive.
void serialize(const T *obj)
Initiate serialization.
time_t timeStampCreated() const
Date and time when this archive was initially created.
void setBoolValue(Object &object, bool value)
Set new boolean value for given boolean object.
void clear()
Clear content of this archive.
double valueAsReal(const Object &object)
Get floating point value of object.
time_t timeStampModified() const
Date and time when this archive was modified for the last time.
virtual String rawDataFormat() const
Name of the encoding format used by this Archive class.
void setIntValue(Object &object, int64_t value)
Set new integer value for given integer object.
operation_t
Current activity of Archive object.
@ OPERATION_DESERIALIZE
Archive is currently deserializing.
@ OPERATION_NONE
Archive is currently neither serializing, nor deserializing.
@ OPERATION_SERIALIZE
Archive is currently serializing.
const RawData & rawData()
Raw data stream of this archive content.
bool isModified() const
Whether this archive was modified.
void deserialize(T *obj)
Initiate deserialization.
virtual void decode(const RawData &data)
Fill this archive with the given serialized raw data.
tm dateTimeCreated(time_base_t base=LOCAL_TIME) const
Date and time when this archive was initially created.
Object & rootObject()
Root C++ object of this archive.
Object & objectByUID(const UID &uid)
Access object by its unique identifier.
String valueAsString(const Object &object)
Get value of object as string.
int64_t valueAsInt(const Object &object)
Get integer value of object.
void setVersion(const T_classType &nativeObject, Version v)
Set current version number for your C++ class.
void removeMember(Object &parent, const Member &member)
Remove a member variable from the given object.
void remove(const Object &obj)
Remove an object from this archive.
bool valueAsBool(const Object &object)
Get boolean value of object.
void setEnumValue(Object &object, uint64_t value)
Set new value for given enum object.
void serializeHeapMember(const T_classType &nativeObject, const T_memberType &heapMember, const char *memberName)
Serialize a C/C++ member variable allocated on the heap.
void operator<<(const T &obj)
Initiate serialization of your C++ objects.
void setComment(String comment)
Assign a comment to this archive.
Archive()
Create an "empty" archive.
String name() const
Optional name of this archive.
void setAutoValue(Object &object, String value)
Automatically cast and assign appropriate value to object.
String comment() const
Optional comments for this archive.
void operator>>(T &obj)
Initiate deserialization of your C++ objects.
tm dateTimeModified(time_base_t base=LOCAL_TIME) const
Date and time when this archive was modified for the last time.
Abstract reflection of a native C++ data type.
bool isPrimitive() const
Whether this is reflecting a fundamental C/C++ data type.
bool isSet() const
Whether this is a C++ Set<> object type.
bool isPointer() const
Whether this is reflecting a C/C++ pointer type.
bool isSigned() const
Whether this is a signed integer C/C++ data type.
String baseTypeName() const
The base type name of this data type.
bool operator!=(const DataType &other) const
Comparison for inequalness.
bool isReal() const
Whether this is a floating point based C/C++ data type.
DataType()
Default constructor (as "invalid" DataType).
String asLongDescr() const
Human readable long description for this data type.
bool isBool() const
Whether this is a boolean C/C++ data type.
bool isMap() const
Whether this is a C++ Map<> object type.
bool isValid() const
Check if this is a valid DataType object.
bool isArray() const
Whether this is a C++ Array<> object type.
bool operator>(const DataType &other) const
Greater than comparison.
bool isEnum() const
Whether this is a C/C++ enum data type.
bool operator<(const DataType &other) const
Smaller than comparison.
String customTypeName2(bool demangle=false) const
The 2nd user defined C/C++ data type name of this data type.
bool isClass() const
Whether this is reflecting a C/C++ struct or class type.
bool isInteger() const
Whether this is an integer C/C++ data type.
bool operator==(const DataType &other) const
Comparison for equalness.
static DataType dataTypeOf(const T &data)
Construct a DataType object for the given native C++ data.
bool isString() const
Whether this is a C++ String data type.
String customTypeName(bool demangle=false) const
The 1st user defined C/C++ data type name of this data type.
size_t size() const
Returns native memory size of the respective C++ object or variable.
Will be thrown whenever an error occurs during an serialization or deserialization process.
void PrintMessage()
Print exception message to stdout.
Abstract reflection of a native C++ class/struct's member variable.
Member()
Default constructor.
bool operator!=(const Member &other) const
Comparison for inequalness.
bool operator<(const Member &other) const
Smaller than comparison.
bool operator>(const Member &other) const
Greater than comparison.
ssize_t offset() const
Offset of member in its containing parent data structure.
String name() const
Name of the member.
bool operator==(const Member &other) const
Comparison for equalness.
const DataType & type() const
C/C++ Data type of this member.
bool isValid() const
Check if this is a valid Member object.
UID uid() const
Unique identifier of this member instance.
Abstract reflection of some native serialized C/C++ data.
bool isValid() const
Check if this is a valid Object instance.
Member memberNamed(String name) const
Get the member of this Object with given name.
Version version() const
Version of original user defined C/C++ struct or class.
UID uid(int index=0) const
Unique identifier of this Object.
const UIDChain & uidChain() const
Unique identifier chain of this Object.
const RawData & rawData() const
Raw data of the original native C/C++ data.
bool operator<(const Object &other) const
Smaller than comparison.
Object()
Default constructor (for an "invalid" Object).
Member memberByUID(const UID &uid) const
Get the member of this Object with given unique identifier.
std::vector< Member > membersOfType(const DataType &type) const
Get all members of this Object with given data type.
int sequenceIndexOf(const Member &member) const
Serialization/deserialization sequence number of the requested member.
void setNativeValueFromString(const String &s)
Cast from string to object's data type and assign value natively.
bool operator!=(const Object &other) const
Comparison for inequalness.
bool operator>(const Object &other) const
Greater than comparison.
std::vector< Member > & members()
All members of the original native C/C++ struct or class instance.
const DataType & type() const
C/C++ data type this Object is reflecting.
bool isVersionCompatibleTo(const Object &other) const
Check version compatibility between Object instances.
Version minVersion() const
Minimum version of original user defined C/C++ struct or class.
bool operator==(const Object &other) const
Comparison for equalness.
Unique identifier referring to one specific native C++ object, member, fundamental variable,...
static UID from(const T &obj)
Create an unique indentifier for a native C++ object/member/variable.
bool isValid() const
Check whether this is a valid unique identifier.
size_t size
Memory size of the object or member in question.
ID id
Abstract non-unique ID of the object or member in question.
Serialization / deserialization framework.
Definition gig.h:98
bool IsUnion(const T &data)
Check whether data is a C++ union type.
void * ID
Abstract identifier for serialized C++ objects.
std::vector< T > Array
Array<> template.
const UID NO_UID
Reflects an invalid UID and behaves similar to NULL as invalid value for pointer types.
bool IsEnum(const T &data)
Check whether data is a C/C++ enum type.
bool IsClass(const T &data)
Check whether data is a C/C++ struct or C++ class type.
std::set< T > Set
Set<> template.
std::string String
Textual string.
std::map< T_key, T_value > Map
Map<> template.
uint32_t Version
Version number data type.
std::vector< UID > UIDChain
Chain of UIDs.
std::vector< uint8_t > RawData
Raw data stream of serialized C++ objects.
time_base_t
To which time zone a certain timing information relates to.
@ UTC_TIME
The time stamp relates to "Greenwhich Mean Time" zone, also known as "Coordinated Universal Time"....
@ LOCAL_TIME
The time stamp relates to the machine's local time zone. Request a time stamp in local time if you wa...