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