libgig 4.3.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#ifndef __has_extension
44# define __has_extension(x) 0
45#endif
46
47#ifndef HAS_BUILTIN_TYPE_TRAITS
48# if __cplusplus >= 201103L
49# define HAS_BUILTIN_TYPE_TRAITS 1
50# elif ( __has_extension(is_class) && __has_extension(is_enum) )
51# define HAS_BUILTIN_TYPE_TRAITS 1
52# elif ( __GNUC__ > 4 || ( __GNUC__ == 4 && __GNUC_MINOR__ >= 3 ) )
53# define HAS_BUILTIN_TYPE_TRAITS 1
54# elif _MSC_VER >= 1400 /* MS Visual C++ 8.0 (Visual Studio 2005) */
55# define HAS_BUILTIN_TYPE_TRAITS 1
56# elif __INTEL_COMPILER >= 1100
57# define HAS_BUILTIN_TYPE_TRAITS 1
58# else
59# define HAS_BUILTIN_TYPE_TRAITS 0
60# endif
61#endif
62
63#if !HAS_BUILTIN_TYPE_TRAITS
64# include <tr1/type_traits>
65# define LIBGIG_IS_CLASS(type) std::tr1::__is_union_or_class<type>::value //NOTE: without compiler support we cannot distinguish union from class
66#else
67# define LIBGIG_IS_CLASS(type) __is_class(type)
68#endif
69
113namespace Serialization {
114
115 // just symbol prototyping
116 class DataType;
117 class Object;
118 class Member;
119 class Archive;
120 class ObjectPool;
121 class Exception;
122
130 typedef std::string String;
131
144 template<class T>
145 using Array = std::vector<T>;
146
156 template<class T>
157 using Set = std::set<T>;
158
177 template<class T_key, class T_value>
178 using Map = std::map<T_key,T_value>;
179
188 typedef std::vector<uint8_t> RawData;
189
200 typedef void* ID;
201
209 typedef uint32_t Version;
210
218 UTC_TIME
219 };
220
228 template<typename T>
229 bool IsEnum(const T& data) {
230 #if !HAS_BUILTIN_TYPE_TRAITS
231 return std::tr1::is_enum<T>::value;
232 #else
233 return __is_enum(T);
234 #endif
235 }
236
247 template<typename T>
248 bool IsUnion(const T& data) {
249 #if !HAS_BUILTIN_TYPE_TRAITS
250 return false; // without compiler support we cannot distinguish union from class
251 #else
252 return __is_union(T);
253 #endif
254 }
255
265 template<typename T>
266 bool IsClass(const T& data) {
267 #if !HAS_BUILTIN_TYPE_TRAITS
268 return std::tr1::__is_union_or_class<T>::value; // without compiler support we cannot distinguish union from class
269 #else
270 return __is_class(T);
271 #endif
272 }
273
274 /*template<typename T>
275 bool IsTrivial(T data) {
276 return __is_trivial(T);
277 }*/
278
279 /*template<typename T>
280 bool IsPOD(T data) {
281 return __is_pod(T);
282 }*/
283
284 /*template<typename T>
285 bool IsArray(const T& data) {
286 return false;
287 }*/
288
289 /*template<typename T>
290 bool IsArray(const Array<T>& data) {
291 return true;
292 }*/
293
294 template<typename T> inline
295 String toString(const T& value) {
296 return std::to_string(value);
297 }
298
299 template<> inline
300 String toString(const String& value) {
301 return value;
302 }
303
319 class UID {
320 public:
322 size_t size;
323
324 bool isValid() const;
325 operator bool() const { return isValid(); }
326 //bool operator()() const { return isValid(); }
327 bool operator==(const UID& other) const { return id == other.id && size == other.size; }
328 bool operator!=(const UID& other) const { return id != other.id || size != other.size; }
329 bool operator<(const UID& other) const { return id < other.id || (id == other.id && size < other.size); }
330 bool operator>(const UID& other) const { return id > other.id || (id == other.id && size > other.size); }
331
339 template<typename T>
340 static UID from(const T& obj) {
341 return Resolver<T>::resolve(obj);
342 }
343
344 protected:
345 // UID resolver for non-pointer types
346 template<typename T>
347 struct Resolver {
348 static UID resolve(const T& obj) {
349 const UID uid = { (ID) &obj, sizeof(obj) };
350 return uid;
351 }
352 };
353
354 // UID resolver for pointer types (of 1st degree)
355 template<typename T>
356 struct Resolver<T*> {
357 static UID resolve(const T* const & obj) {
358 const UID uid = { (ID) obj, sizeof(*obj) };
359 return uid;
360 }
361 };
362 };
363
369 extern const UID NO_UID;
370
402 typedef std::vector<UID> UIDChain;
403
404#if LIBGIG_SERIALIZATION_INTERNAL
405 // prototyping of private internal friend functions
406 static String _encodePrimitiveValue(const Object& obj);
407 static DataType _popDataTypeBlob(const char*& p, const char* end);
408 static Member _popMemberBlob(const char*& p, const char* end);
409 static Object _popObjectBlob(const char*& p, const char* end);
410 static void _popPrimitiveValue(const char*& p, const char* end, Object& obj);
411 static String _primitiveObjectValueToString(const Object& obj);
412 // |
413 template<typename T>
414 static T _primitiveObjectValueToNumber(const Object& obj);
415#endif // LIBGIG_SERIALIZATION_INTERNAL
416
433 class DataType {
434 public:
435 DataType();
436 size_t size() const { return m_size; }
437 bool isValid() const;
438 bool isPointer() const;
439 bool isClass() const;
440 bool isPrimitive() const;
441 bool isString() const;
442 bool isInteger() const;
443 bool isReal() const;
444 bool isBool() const;
445 bool isEnum() const;
446 bool isArray() const;
447 bool isSet() const;
448 bool isMap() const;
449 bool isSigned() const;
450 operator bool() const { return isValid(); }
451 //bool operator()() const { return isValid(); }
452 bool operator==(const DataType& other) const;
453 bool operator!=(const DataType& other) const;
454 bool operator<(const DataType& other) const;
455 bool operator>(const DataType& other) const;
456 String asLongDescr() const;
457 String baseTypeName() const;
458 String customTypeName(bool demangle = false) const;
459 String customTypeName2(bool demangle = false) const;
460
471 template<typename T>
472 static DataType dataTypeOf(const T& data) {
473 return Resolver<T>::resolve(data);
474 }
475
476 protected:
477 DataType(bool isPointer, int size, String baseType,
478 String customType1 = "", String customType2 = "");
479
480 template<typename T, bool T_isPointer>
481 struct ResolverBase {
482 static DataType resolve(const T& data) {
483 const std::type_info& type = typeid(data);
484 const int sz = sizeof(data);
485
486 // for primitive types we are using our own type names instead of
487 // using std:::type_info::name(), because the precise output of the
488 // latter may vary between compilers
489 if (type == typeid(int8_t)) return DataType(T_isPointer, sz, "int8");
490 if (type == typeid(uint8_t)) return DataType(T_isPointer, sz, "uint8");
491 if (type == typeid(int16_t)) return DataType(T_isPointer, sz, "int16");
492 if (type == typeid(uint16_t)) return DataType(T_isPointer, sz, "uint16");
493 if (type == typeid(int32_t)) return DataType(T_isPointer, sz, "int32");
494 if (type == typeid(uint32_t)) return DataType(T_isPointer, sz, "uint32");
495 if (type == typeid(int64_t)) return DataType(T_isPointer, sz, "int64");
496 if (type == typeid(uint64_t)) return DataType(T_isPointer, sz, "uint64");
497 if (type == typeid(size_t)) {
498 if (sz == 1) return DataType(T_isPointer, sz, "uint8");
499 if (sz == 2) return DataType(T_isPointer, sz, "uint16");
500 if (sz == 4) return DataType(T_isPointer, sz, "uint32");
501 if (sz == 8) return DataType(T_isPointer, sz, "uint64");
502 else assert(false /* unknown size_t size */);
503 }
504 if (type == typeid(ssize_t)) {
505 if (sz == 1) return DataType(T_isPointer, sz, "int8");
506 if (sz == 2) return DataType(T_isPointer, sz, "int16");
507 if (sz == 4) return DataType(T_isPointer, sz, "int32");
508 if (sz == 8) return DataType(T_isPointer, sz, "int64");
509 else assert(false /* unknown ssize_t size */);
510 }
511 if (type == typeid(bool)) return DataType(T_isPointer, sz, "bool");
512 if (type == typeid(float)) return DataType(T_isPointer, sz, "real32");
513 if (type == typeid(double)) return DataType(T_isPointer, sz, "real64");
514 if (type == typeid(String)) return DataType(T_isPointer, sz, "String");
515
516 if (IsEnum(data)) return DataType(T_isPointer, sz, "enum", rawCppTypeNameOf(data));
517 if (IsUnion(data)) return DataType(T_isPointer, sz, "union", rawCppTypeNameOf(data));
518 if (IsClass(data)) return DataType(T_isPointer, sz, "class", rawCppTypeNameOf(data));
519
520 return DataType();
521 }
522 };
523
524 // DataType resolver for non-pointer types
525 template<typename T>
526 struct Resolver : ResolverBase<T,false> {
527 static DataType resolve(const T& data) {
528 return ResolverBase<T,false>::resolve(data);
529 }
530 };
531
532 // DataType resolver for pointer types (of 1st degree)
533 template<typename T>
534 struct Resolver<T*> : ResolverBase<T,true> {
535 static DataType resolve(const T*& data) {
536 return ResolverBase<T,true>::resolve(*data);
537 }
538 };
539
540 // DataType resolver for non-pointer Array<> container object types.
541 template<typename T>
542 struct Resolver<Array<T>> {
543 static DataType resolve(const Array<T>& data) {
544 const int sz = sizeof(data);
545 T unused;
546 return DataType(false, sz, "Array", rawCppTypeNameOf(unused));
547 }
548 };
549
550 // DataType resolver for Array<> pointer types (of 1st degree).
551 template<typename T>
552 struct Resolver<Array<T>*> {
553 static DataType resolve(const Array<T>*& data) {
554 const int sz = sizeof(*data);
555 T unused;
556 return DataType(true, sz, "Array", rawCppTypeNameOf(unused));
557 }
558 };
559
560 // DataType resolver for non-pointer Set<> container object types.
561 template<typename T>
562 struct Resolver<Set<T>> {
563 static DataType resolve(const Set<T>& data) {
564 const int sz = sizeof(data);
565 T unused;
566 return DataType(false, sz, "Set", rawCppTypeNameOf(unused));
567 }
568 };
569
570 // DataType resolver for Set<> pointer types (of 1st degree).
571 template<typename T>
572 struct Resolver<Set<T>*> {
573 static DataType resolve(const Set<T>*& data) {
574 const int sz = sizeof(*data);
575 T unused;
576 return DataType(true, sz, "Set", rawCppTypeNameOf(unused));
577 }
578 };
579
580 // DataType resolver for non-pointer Map<> container object types.
581 template<typename T_key, typename T_value>
582 struct Resolver<Map<T_key,T_value>> {
583 static DataType resolve(const Map<T_key,T_value>& data) {
584 const int sz = sizeof(data);
585 T_key unused1;
586 T_value unused2;
587 return DataType(false, sz, "Map", rawCppTypeNameOf(unused1),
588 rawCppTypeNameOf(unused2));
589 }
590 };
591
592 // DataType resolver for Map<> pointer types (of 1st degree).
593 template<typename T_key, typename T_value>
594 struct Resolver<Map<T_key,T_value>*> {
595 static DataType resolve(const Map<T_key,T_value>*& data) {
596 const int sz = sizeof(*data);
597 T_key unused1;
598 T_value unused2;
599 return DataType(true, sz, "Map", rawCppTypeNameOf(unused1),
600 rawCppTypeNameOf(unused2));
601 }
602 };
603
604 template<typename T>
605 static String rawCppTypeNameOf(const T& data) {
606 #if defined _MSC_VER // Microsoft compiler ...
607 String name = typeid(data).raw_name();
608 #else // i.e. especially GCC and clang ...
609 String name = typeid(data).name();
610 #endif
611 //while (!name.empty() && name[0] >= 0 && name[0] <= 9)
612 // name = name.substr(1);
613 return name;
614 }
615
616 private:
617 String m_baseTypeName;
618 String m_customTypeName;
619 String m_customTypeName2;
620 int m_size;
621 bool m_isPointer;
622
623#if LIBGIG_SERIALIZATION_INTERNAL
624 friend DataType _popDataTypeBlob(const char*& p, const char* end);
625#endif
626 friend class Archive;
627 };
628
650 class Member {
651 public:
652 Member();
653 UID uid() const;
654 String name() const;
655 ssize_t offset() const;
656 const DataType& type() const;
657 bool isValid() const;
658 operator bool() const { return isValid(); }
659 //bool operator()() const { return isValid(); }
660 bool operator==(const Member& other) const;
661 bool operator!=(const Member& other) const;
662 bool operator<(const Member& other) const;
663 bool operator>(const Member& other) const;
664
665 protected:
667 friend class Archive;
668
669 private:
670 UID m_uid;
671 ssize_t m_offset;
672 String m_name;
673 DataType m_type;
674
675#if LIBGIG_SERIALIZATION_INTERNAL
676 friend Member _popMemberBlob(const char*& p, const char* end);
677#endif
678 };
679
704 class Object {
705 public:
706 Object();
708
709 UID uid(int index = 0) const;
710 const UIDChain& uidChain() const;
711 const DataType& type() const;
712 const RawData& rawData() const;
713 Version version() const;
714 Version minVersion() const;
715 bool isVersionCompatibleTo(const Object& other) const;
716 std::vector<Member>& members();
717 const std::vector<Member>& members() const;
718 Member memberNamed(String name) const;
719 Member memberByUID(const UID& uid) const;
720 std::vector<Member> membersOfType(const DataType& type) const;
721 int sequenceIndexOf(const Member& member) const;
722 bool isValid() const;
723 operator bool() const { return isValid(); }
724 //bool operator()() const { return isValid(); }
725 bool operator==(const Object& other) const;
726 bool operator!=(const Object& other) const;
727 bool operator<(const Object& other) const;
728 bool operator>(const Object& other) const;
729 void setNativeValueFromString(const String& s);
730
731 protected:
732 void remove(const Member& member);
733 void setVersion(Version v);
734 void setMinVersion(Version v);
735
736 private:
737 DataType m_type;
738 UIDChain m_uid;
739 Version m_version;
740 Version m_minVersion;
741 RawData m_data;
742 std::vector<Member> m_members;
743 std::function<void(Object& dstObj, const Object& srcObj, void* syncer)> m_sync;
744
745#if LIBGIG_SERIALIZATION_INTERNAL
746 friend String _encodePrimitiveValue(const Object& obj);
747 friend Object _popObjectBlob(const char*& p, const char* end);
748 friend void _popPrimitiveValue(const char*& p, const char* end, Object& obj);
749 friend String _primitiveObjectValueToString(const Object& obj);
750 // |
751 template<typename T>
752 friend T _primitiveObjectValueToNumber(const Object& obj);
753#endif // LIBGIG_SERIALIZATION_INTERNAL
754
755 friend class Archive;
756 };
757
895 class Archive {
896 public:
903 };
904
905 Archive();
906 Archive(const RawData& data);
907 Archive(const uint8_t* data, size_t size);
908 virtual ~Archive();
909
935 template<typename T>
936 void serialize(const T* obj) {
937 m_operation = OPERATION_SERIALIZE;
938 m_allObjects.clear();
939 m_rawData.clear();
940 m_root = UID::from(obj);
941 const_cast<T*>(obj)->serialize(this);
942 encode();
943 m_operation = OPERATION_NONE;
944 }
945
970 template<typename T>
971 void deserialize(T* obj) {
972 Archive a;
973 a.m_operation = m_operation = OPERATION_DESERIALIZE;
974 obj->serialize(&a);
975 a.m_root = UID::from(obj);
976 Syncer s(a, *this);
977 a.m_operation = m_operation = OPERATION_NONE;
978 }
979
994 template<typename T>
995 void operator<<(const T& obj) {
996 serialize(&obj);
997 }
998
1017 template<typename T>
1018 void operator>>(T& obj) {
1019 deserialize(&obj);
1020 }
1021
1022 const RawData& rawData();
1023 virtual String rawDataFormat() const;
1024
1081 template<typename T_classType, typename T_memberType>
1082 void serializeMember(const T_classType& nativeObject, const T_memberType& nativeMember, const char* memberName) {
1083 const ssize_t offset =
1084 ((const uint8_t*)(const void*)&nativeMember) -
1085 ((const uint8_t*)(const void*)&nativeObject);
1086 const UIDChain uids = UIDChainResolver<T_memberType>(nativeMember);
1087 const DataType type = DataType::dataTypeOf(nativeMember);
1088 const Member member(memberName, uids[0], offset, type);
1089 const UID parentUID = UID::from(nativeObject);
1090 Object& parent = m_allObjects[parentUID];
1091 if (!parent) {
1092 const UIDChain uids = UIDChainResolver<T_classType>(nativeObject);
1093 const DataType type = DataType::dataTypeOf(nativeObject);
1094 parent = Object(uids, type);
1095 }
1096 parent.members().push_back(member);
1097 const Object obj(uids, type);
1098 const bool bExistsAlready = m_allObjects.count(uids[0]);
1099 const bool isValidObject = obj;
1100 const bool bExistingObjectIsInvalid = !m_allObjects[uids[0]];
1101 if (!bExistsAlready || (bExistingObjectIsInvalid && isValidObject)) {
1102 m_allObjects[uids[0]] = obj;
1103 // recurse serialization for all members of this member
1104 // (only for struct/class types, noop for primitive types)
1105 SerializationRecursion<T_memberType>::serializeObject(this, nativeMember);
1106 }
1107 }
1108
1139 template<typename T_classType, typename T_memberType>
1140 void serializeHeapMember(const T_classType& nativeObject, const T_memberType& heapMember, const char* memberName) {
1141 const ssize_t offset = -1; // used for all members on heap
1142 const UIDChain uids = UIDChainResolver<T_memberType>(heapMember);
1143 const DataType type = DataType::dataTypeOf(heapMember);
1144 const Member member(memberName, uids[0], offset, type);
1145 const UID parentUID = UID::from(nativeObject);
1146 Object& parent = m_allObjects[parentUID];
1147 if (!parent) {
1148 const UIDChain uids = UIDChainResolver<T_classType>(nativeObject);
1149 const DataType type = DataType::dataTypeOf(nativeObject);
1150 parent = Object(uids, type);
1151 }
1152 parent.members().push_back(member);
1153 const Object obj(uids, type);
1154 const bool bExistsAlready = m_allObjects.count(uids[0]);
1155 const bool isValidObject = obj;
1156 const bool bExistingObjectIsInvalid = !m_allObjects[uids[0]];
1157 if (!bExistsAlready || (bExistingObjectIsInvalid && isValidObject)) {
1158 m_allObjects[uids[0]] = obj;
1159 // recurse serialization for all members of this member
1160 // (only for struct/class types, noop for primitive types)
1161 SerializationRecursion<T_memberType>::serializeObject(this, heapMember);
1162 }
1163 }
1164
1244 template<typename T_classType>
1245 void setVersion(const T_classType& nativeObject, Version v) {
1246 const UID uid = UID::from(nativeObject);
1247 Object& obj = m_allObjects[uid];
1248 if (!obj) {
1249 const UIDChain uids = UIDChainResolver<T_classType>(nativeObject);
1250 const DataType type = DataType::dataTypeOf(nativeObject);
1251 obj = Object(uids, type);
1252 }
1253 setVersion(obj, v);
1254 }
1255
1285 template<typename T_classType>
1286 void setMinVersion(const T_classType& nativeObject, Version v) {
1287 const UID uid = UID::from(nativeObject);
1288 Object& obj = m_allObjects[uid];
1289 if (!obj) {
1290 const UIDChain uids = UIDChainResolver<T_classType>(nativeObject);
1291 const DataType type = DataType::dataTypeOf(nativeObject);
1292 obj = Object(uids, type);
1293 }
1294 setMinVersion(obj, v);
1295 }
1296
1297 virtual void decode(const RawData& data);
1298 virtual void decode(const uint8_t* data, size_t size);
1299 void clear();
1300 bool isModified() const;
1301 void removeMember(Object& parent, const Member& member);
1302 void remove(const Object& obj);
1303 Object& rootObject();
1304 Object& objectByUID(const UID& uid);
1305 void setAutoValue(Object& object, String value);
1306 void setIntValue(Object& object, int64_t value);
1307 void setRealValue(Object& object, double value);
1308 void setBoolValue(Object& object, bool value);
1309 void setEnumValue(Object& object, uint64_t value);
1310 void setStringValue(Object& object, String value);
1311 String valueAsString(const Object& object);
1312 int64_t valueAsInt(const Object& object);
1313 double valueAsReal(const Object& object);
1314 bool valueAsBool(const Object& object);
1315 void setVersion(Object& object, Version v);
1316 void setMinVersion(Object& object, Version v);
1317 String name() const;
1318 void setName(String name);
1319 String comment() const;
1321 time_t timeStampCreated() const;
1322 time_t timeStampModified() const;
1323 tm dateTimeCreated(time_base_t base = LOCAL_TIME) const;
1324 tm dateTimeModified(time_base_t base = LOCAL_TIME) const;
1325 operation_t operation() const;
1326
1327 protected:
1328 // UID resolver for non-pointer types
1329 template<typename T>
1330 class UIDChainResolver {
1331 public:
1332 UIDChainResolver(const T& data) {
1333 m_uid.push_back(UID::from(data));
1334 }
1335
1336 operator UIDChain() const { return m_uid; }
1337 UIDChain operator()() const { return m_uid; }
1338 private:
1339 UIDChain m_uid;
1340 };
1341
1342 // UID resolver for pointer types (of 1st degree)
1343 template<typename T>
1344 class UIDChainResolver<T*> {
1345 public:
1346 UIDChainResolver(const T*& data) {
1347 const UID uids[2] = {
1348 { &data, sizeof(data) },
1349 { data, sizeof(*data) }
1350 };
1351 m_uid.push_back(uids[0]);
1352 m_uid.push_back(uids[1]);
1353 }
1354
1355 operator UIDChain() const { return m_uid; }
1356 UIDChain operator()() const { return m_uid; }
1357 private:
1358 UIDChain m_uid;
1359 };
1360
1361 // SerializationRecursion for non-pointer class/struct types.
1362 template<typename T, bool T_isRecursive>
1363 struct SerializationRecursionImpl {
1364 static void serializeObject(Archive* archive, const T& obj) {
1365 const_cast<T&>(obj).serialize(archive);
1366 }
1367 };
1368
1369 // SerializationRecursion for pointers (of 1st degree) to class/structs.
1370 template<typename T, bool T_isRecursive>
1371 struct SerializationRecursionImpl<T*,T_isRecursive> {
1372 static void serializeObject(Archive* archive, const T*& obj) {
1373 if (!obj) return;
1374 const_cast<T*&>(obj)->serialize(archive);
1375 }
1376 };
1377
1378 // NOOP SerializationRecursion for primitive types.
1379 template<typename T>
1380 struct SerializationRecursionImpl<T,false> {
1381 static void serializeObject(Archive* archive, const T& obj) {}
1382 };
1383
1384 // NOOP SerializationRecursion for pointers (of 1st degree) to primitive types.
1385 template<typename T>
1386 struct SerializationRecursionImpl<T*,false> {
1387 static void serializeObject(Archive* archive, const T*& obj) {}
1388 };
1389
1390 // NOOP SerializationRecursion for String objects.
1391 template<bool T_isRecursive>
1392 struct SerializationRecursionImpl<String,T_isRecursive> {
1393 static void serializeObject(Archive* archive, const String& obj) {}
1394 };
1395
1396 // NOOP SerializationRecursion for String pointers (of 1st degree).
1397 template<bool T_isRecursive>
1398 struct SerializationRecursionImpl<String*,T_isRecursive> {
1399 static void serializeObject(Archive* archive, const String*& obj) {}
1400 };
1401
1402 // SerializationRecursion for Array<> objects.
1403 template<typename T, bool T_isRecursive>
1404 struct SerializationRecursionImpl<Array<T>,T_isRecursive> {
1405 static void serializeObject(Archive* archive, const Array<T>& obj) {
1406 const UIDChain uids = UIDChainResolver<Array<T>>(obj);
1407 const Object& object = archive->objectByUID(uids[0]);
1408 if (archive->operation() == OPERATION_SERIALIZE) {
1409 for (size_t i = 0; i < obj.size(); ++i) {
1410 archive->serializeHeapMember(
1411 obj, obj[i], ("[" + toString(i) + "]").c_str()
1412 );
1413 }
1414 } else {
1415 const_cast<Object&>(object).m_sync =
1416 [&obj,archive](Object& dstObj, const Object& srcObj,
1417 void* syncer)
1418 {
1419 const size_t n = srcObj.members().size();
1420 const_cast<Array<T>&>(obj).resize(n);
1421 for (size_t i = 0; i < obj.size(); ++i) {
1422 archive->serializeHeapMember(
1423 obj, obj[i], ("[" + toString(i) + "]").c_str()
1424 );
1425 }
1426 // updating dstObj required as serializeHeapMember()
1427 // replaced the original object by a new one
1428 dstObj = archive->objectByUID(dstObj.uid());
1429 for (size_t i = 0; i < obj.size(); ++i) {
1430 String name = "[" + toString(i) + "]";
1431 Member srcMember = srcObj.memberNamed(name);
1432 Member dstMember = dstObj.memberNamed(name);
1433 ((Syncer*)syncer)->syncMember(dstMember, srcMember);
1434 }
1435 };
1436 }
1437 }
1438 };
1439
1440 // SerializationRecursion for Array<> pointers (of 1st degree).
1441 template<typename T, bool T_isRecursive>
1442 struct SerializationRecursionImpl<Array<T>*,T_isRecursive> {
1443 static void serializeObject(Archive* archive, const Array<T>*& obj) {
1444 if (!obj) return;
1445 SerializationRecursionImpl<Array<T>,T_isRecursive>::serializeObject(
1446 archive, *obj
1447 );
1448 }
1449 };
1450
1451 // SerializationRecursion for Set<> objects.
1452 template<typename T, bool T_isRecursive>
1453 struct SerializationRecursionImpl<Set<T>,T_isRecursive> {
1454 static void serializeObject(Archive* archive, const Set<T>& obj) {
1455 const UIDChain uids = UIDChainResolver<Set<T>>(obj);
1456 const Object& object = archive->objectByUID(uids[0]);
1457 if (archive->operation() == OPERATION_SERIALIZE) {
1458 for (const T& key : obj) {
1459 archive->serializeHeapMember(
1460 obj, key, ("[" + toString(key) + "]").c_str()
1461 );
1462 }
1463 } else {
1464 const_cast<Object&>(object).m_sync =
1465 [&obj,archive](Object& dstObj, const Object& srcObj,
1466 void* syncer)
1467 {
1468 const size_t n = srcObj.members().size();
1469 const_cast<Set<T>&>(obj).clear();
1470 for (size_t i = 0; i < n; ++i) {
1471 const Member& member = srcObj.members()[i];
1472 String name = member.name();
1473 if (name.length() < 2 || name[0] != '[' ||
1474 *name.rbegin() != ']') continue;
1475 name = name.substr(1, name.length() - 2);
1476 T key;
1477 const UIDChain uids = UIDChainResolver<T>(key);
1478 const DataType type = DataType::dataTypeOf(key);
1479 Object tmpObj(uids, type);
1480 tmpObj.setNativeValueFromString(name);
1481 const_cast<Set<T>&>(obj).insert(key);
1482 }
1483 for (const T& key : obj) {
1484 archive->serializeHeapMember(
1485 obj, key, ("[" + toString(key) + "]").c_str()
1486 );
1487 }
1488 // updating dstObj required as serializeHeapMember()
1489 // replaced the original object by a new one
1490 dstObj = archive->objectByUID(dstObj.uid());
1491 };
1492 }
1493 }
1494 };
1495
1496 // SerializationRecursion for Set<> pointers (of 1st degree).
1497 template<typename T, bool T_isRecursive>
1498 struct SerializationRecursionImpl<Set<T>*,T_isRecursive> {
1499 static void serializeObject(Archive* archive, const Set<T>*& obj) {
1500 if (!obj) return;
1501 SerializationRecursionImpl<Set<T>,T_isRecursive>::serializeObject(
1502 archive, *obj
1503 );
1504 }
1505 };
1506
1507 // SerializationRecursion for Map<> objects.
1508 template<typename T_key, typename T_value, bool T_isRecursive>
1509 struct SerializationRecursionImpl<Map<T_key,T_value>,T_isRecursive> {
1510 static void serializeObject(Archive* archive, const Map<T_key,T_value>& obj) {
1511 const UIDChain uids = UIDChainResolver<Map<T_key,T_value>>(obj);
1512 const Object& object = archive->objectByUID(uids[0]);
1513 if (archive->operation() == OPERATION_SERIALIZE) {
1514 for (const auto& it : obj) {
1515 archive->serializeHeapMember(
1516 obj, it.second, ("[" + toString(it.first) + "]").c_str()
1517 );
1518 }
1519 } else {
1520 const_cast<Object&>(object).m_sync =
1521 [&obj,archive](Object& dstObj, const Object& srcObj,
1522 void* syncer)
1523 {
1524 const size_t n = srcObj.members().size();
1525 const_cast<Map<T_key,T_value>&>(obj).clear();
1526 for (size_t i = 0; i < n; ++i) {
1527 const Member& member = srcObj.members()[i];
1528 String name = member.name();
1529 if (name.length() < 2 || name[0] != '[' ||
1530 *name.rbegin() != ']') continue;
1531 name = name.substr(1, name.length() - 2);
1532 T_key key;
1533 const UIDChain uids = UIDChainResolver<T_key>(key);
1534 const DataType type = DataType::dataTypeOf(key);
1535 Object tmpObj(uids, type);
1536 tmpObj.setNativeValueFromString(name);
1537 const_cast<Map<T_key,T_value>&>(obj)[key] = T_value();
1538 }
1539 for (const auto& it : obj) {
1540 archive->serializeHeapMember(
1541 obj, it.second, ("[" + toString(it.first) + "]").c_str()
1542 );
1543 }
1544 // updating dstObj required as serializeHeapMember()
1545 // replaced the original object by a new one
1546 dstObj = archive->objectByUID(dstObj.uid());
1547 for (size_t i = 0; i < n; ++i) {
1548 Member srcMember = srcObj.members()[i];
1549 Member dstMember = dstObj.memberNamed(srcMember.name());
1550 ((Syncer*)syncer)->syncMember(dstMember, srcMember);
1551 }
1552 };
1553 }
1554 }
1555 };
1556
1557 // SerializationRecursion for Map<> pointers (of 1st degree).
1558 template<typename T_key, typename T_value, bool T_isRecursive>
1559 struct SerializationRecursionImpl<Map<T_key,T_value>*,T_isRecursive> {
1560 static void serializeObject(Archive* archive, const Map<T_key,T_value>*& obj) {
1561 if (!obj) return;
1562 SerializationRecursionImpl<Map<T_key,T_value>,T_isRecursive>::serializeObject(
1563 archive, *obj
1564 );
1565 }
1566 };
1567
1568 // Automatically handles recursion for class/struct types, while ignoring all primitive types.
1569 template<typename T>
1570 struct SerializationRecursion : SerializationRecursionImpl<T, LIBGIG_IS_CLASS(T)> {
1571 };
1572
1573 class ObjectPool : public std::map<UID,Object> {
1574 public:
1575 // prevent passing obvious invalid UID values from creating a new pair entry
1576 Object& operator[](const UID& k) {
1577 static Object invalid;
1578 if (!k.isValid()) {
1579 invalid = Object();
1580 return invalid;
1581 }
1582 return std::map<UID,Object>::operator[](k);
1583 }
1584 };
1585
1586 friend String _encode(const ObjectPool& objects);
1587
1588 private:
1589 String _encodeRootBlob();
1590 void _popRootBlob(const char*& p, const char* end);
1591 void _popObjectsBlob(const char*& p, const char* end);
1592
1593 protected:
1633 class Syncer {
1634 public:
1635 Syncer(Archive& dst, Archive& src);
1636 void syncObject(const Object& dst, const Object& src);
1637 void syncPrimitive(const Object& dst, const Object& src);
1638 void syncString(const Object& dst, const Object& src);
1639 void syncArray(const Object& dst, const Object& src);
1640 void syncSet(const Object& dst, const Object& src);
1641 void syncMap(const Object& dst, const Object& src);
1642 void syncPointer(const Object& dst, const Object& src);
1643 void syncMember(const Member& dstMember, const Member& srcMember);
1644 protected:
1645 static Member dstMemberMatching(const Object& dstObj, const Object& srcObj, const Member& srcMember);
1646 private:
1647 Archive& m_dst;
1648 Archive& m_src;
1649 };
1650
1651 virtual void encode();
1652
1653 ObjectPool m_allObjects;
1654 operation_t m_operation;
1655 UID m_root;
1656 RawData m_rawData;
1657 bool m_isModified;
1658 String m_name;
1659 String m_comment;
1660 time_t m_timeCreated;
1661 time_t m_timeModified;
1662 };
1663
1669 public:
1670 String Message;
1671
1672 Exception(String format, ...);
1673 Exception(String format, va_list arg);
1674 void PrintMessage();
1675 virtual ~Exception() {}
1676
1677 protected:
1678 Exception();
1679 static String assemble(String format, va_list arg);
1680 };
1681
1682} // namespace Serialization
1683
1684#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.
const UID NO_UID
Reflects an invalid UID and behaves similar to NULL as invalid value for pointer types.
std::set< T > Set
Set<> template.
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::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< T > Array
Array<> template.
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...