libgig 4.5.2
Serialization.h
1/***************************************************************************
2 * *
3 * Copyright (C) 2017-2025 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#include <sstream>
43#include <locale>
44#include <limits>
45
46#include "sysdef.h"
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 // generalized C-locale guaranteed T to string conversion
300 template<typename T> inline
301 String toString(const T& value) {
302 //TODO: replace by locale-independent, maybe faster std::to_chars() [C++17]
303 std::stringstream ss;
304 ss.imbue(std::locale::classic()); // a.k.a. "C" locale
305 ss << value;
306 return ss.str();
307 }
308
309 // C-locale guaranteed double to string conversion
310 template<> inline
311 String toString(const double& value) {
312 //TODO: replace by locale-independent, maybe faster std::to_chars() [C++17]
313 std::stringstream ss;
314 ss.imbue(std::locale::classic()); // a.k.a. "C" locale
315 // stringstream has lower precision by default compared to std::to_string()
316 ss.precision(std::numeric_limits<double>::max_digits10);
317 ss << value;
318 return ss.str();
319 }
320
321 template<typename T> inline
322 String toString(T* ptr) {
323 std::stringstream ss;
324 ss.imbue(std::locale::classic()); // a.k.a. "C" locale
325 ss << "0x" << std::hex << size_t(ptr);
326 return ss.str();
327 }
328
329 template<> inline
330 String toString(const String& value) {
331 return value;
332 }
333
349 class UID {
350 public:
352 size_t size;
353
354 bool isValid() const;
355 operator bool() const { return isValid(); }
356 //bool operator()() const { return isValid(); }
357 bool operator==(const UID& other) const { return id == other.id && size == other.size; }
358 bool operator!=(const UID& other) const { return id != other.id || size != other.size; }
359 bool operator<(const UID& other) const { return id < other.id || (id == other.id && size < other.size); }
360 bool operator>(const UID& other) const { return id > other.id || (id == other.id && size > other.size); }
361
369 template<typename T>
370 static UID from(const T& obj) {
371 return Resolver<T>::resolve(obj);
372 }
373
374 protected:
375 // UID resolver for non-pointer types
376 template<typename T>
377 struct Resolver {
378 static UID resolve(const T& obj);
379 };
380
381 // UID resolver for pointer types (of 1st degree)
382 template<typename T>
383 struct Resolver<T*> {
384 static UID resolve(const T* const & obj);
385 };
386 };
387
393 extern const UID NO_UID;
394
426 typedef std::vector<UID> UIDChain;
427
428#if LIBGIG_SERIALIZATION_INTERNAL
429 // prototyping of private internal friend functions
430 static String _encodePrimitiveValue(const Object& obj);
431 static DataType _popDataTypeBlob(const char*& p, const char* end);
432 static Member _popMemberBlob(const char*& p, const char* end);
433 static Object _popObjectBlob(const char*& p, const char* end);
434 static void _popPrimitiveValue(const char*& p, const char* end, Object& obj);
435 static String _primitiveObjectValueToString(const Object& obj);
436 // |
437 template<typename T>
438 static T _primitiveObjectValueToNumber(const Object& obj);
439#endif // LIBGIG_SERIALIZATION_INTERNAL
440
457 class DataType {
458 public:
459 DataType();
460 size_t size() const { return m_size; }
461 bool isValid() const;
462 bool isPointer() const;
463 bool isClass() const;
464 bool isPrimitive() const;
465 bool isString() const;
466 bool isInteger() const;
467 bool isReal() const;
468 bool isBool() const;
469 bool isEnum() const;
470 bool isArray() const;
471 bool isSet() const;
472 bool isMap() const;
473 bool isSigned() const;
474 operator bool() const { return isValid(); }
475 //bool operator()() const { return isValid(); }
476 bool operator==(const DataType& other) const;
477 bool operator!=(const DataType& other) const;
478 bool operator<(const DataType& other) const;
479 bool operator>(const DataType& other) const;
480 String asLongDescr() const;
481 String baseTypeName() const;
482 String customTypeName(bool demangle = false) const;
483 String customTypeName2(bool demangle = false) const;
484
500 template<typename T>
501 static DataType dataTypeOf(const T& data, bool registerType = true) {
502 const DataType type = Resolver<T>::resolve(data);
503 if (registerType)
504 registerNativeDataType(type, data);
505 return type;
506 }
507
521 template<typename T>
522 static DataType dataType(bool registerType = true) {
523 T unused = T();
524 const DataType type = Resolver<T>::resolve(unused);
525 if (registerType)
526 registerNativeDataType(type, unused);
527 return type;
528 }
529
539 template<typename T>
540 static size_t sizeOf(const T& data) {
541 DataType type = dataTypeOf(data);
542 const auto itNativeType = m_nativeTypes.find(type.internalID());
543 return (itNativeType != m_nativeTypes.end()) ?
544 itNativeType->second.size : sizeof(data);
545 }
546
582 template<typename T>
583 static void registerNativeDataType();
584
614 template<typename T>
615 class NativeDataTypeRegistry {
616 public:
617 NativeDataTypeRegistry() {
619 }
620 };
621
622 protected:
623 DataType(bool isPointer, int size, String baseType,
624 String customType1 = "", String customType2 = "");
625
626 String internalID() const;
627 Object newInstance(Archive* archive) const;
628
629 template<typename T, typename std::enable_if<std::is_default_constructible<T>::value, bool>::type = true>
630 static void registerNativeDataType(const DataType& type, const T& nativeData);
631
632 template<typename T, typename std::enable_if<!std::is_default_constructible<T>::value, bool>::type = true>
633 static void registerNativeDataType(const DataType& type, const T& nativeData);
634
635 template<typename T, bool T_isPointer>
636 struct ResolverBase {
637 static DataType resolve(const T& data) {
638 // for pointers we must stick to the compile-time declared type
639 // of pointer to prevent potential type mismatches caused by
640 // RTTI in a polymorphic scenario
641 const std::type_info& type = (T_isPointer) ? typeid(T) : typeid(data);
642 const int sz = sizeof(data);
643
644 // for primitive types we are using our own type names instead of
645 // using std:::type_info::name(), because the precise output of the
646 // latter may vary between compilers
647 if (type == typeid(int8_t)) return DataType(T_isPointer, sz, "int8");
648 if (type == typeid(uint8_t)) return DataType(T_isPointer, sz, "uint8");
649 if (type == typeid(int16_t)) return DataType(T_isPointer, sz, "int16");
650 if (type == typeid(uint16_t)) return DataType(T_isPointer, sz, "uint16");
651 if (type == typeid(int32_t)) return DataType(T_isPointer, sz, "int32");
652 if (type == typeid(uint32_t)) return DataType(T_isPointer, sz, "uint32");
653 if (type == typeid(int64_t)) return DataType(T_isPointer, sz, "int64");
654 if (type == typeid(uint64_t)) return DataType(T_isPointer, sz, "uint64");
655 if (type == typeid(size_t)) {
656 if (sz == 1) return DataType(T_isPointer, sz, "uint8");
657 if (sz == 2) return DataType(T_isPointer, sz, "uint16");
658 if (sz == 4) return DataType(T_isPointer, sz, "uint32");
659 if (sz == 8) return DataType(T_isPointer, sz, "uint64");
660 else assert(false /* unknown size_t size */);
661 }
662 if (type == typeid(ssize_t)) {
663 if (sz == 1) return DataType(T_isPointer, sz, "int8");
664 if (sz == 2) return DataType(T_isPointer, sz, "int16");
665 if (sz == 4) return DataType(T_isPointer, sz, "int32");
666 if (sz == 8) return DataType(T_isPointer, sz, "int64");
667 else assert(false /* unknown ssize_t size */);
668 }
669 if (type == typeid(bool)) return DataType(T_isPointer, sz, "bool");
670 if (type == typeid(float)) return DataType(T_isPointer, sz, "real32");
671 if (type == typeid(double)) return DataType(T_isPointer, sz, "real64");
672 if (type == typeid(String)) return DataType(T_isPointer, sz, "String");
673
674 // for pointers we must stick to pointer's compile-time declared
675 // type and not use RTTI for the pointed object, because the
676 // latter would easily create a type mismatch conflict for
677 // pointers and objects in a polymorphic scenario, because the
678 // pointer might have been declared with a base class type,
679 // while actually assigned objects to these pointers might be of
680 // any other derived class and RTTI would resolve the latter
681 const String rawCppName =
682 (T_isPointer) ? rawCppTypeName<T>()
683 : rawCppTypeNameOf(data);
684
685 if (IsEnum(data)) return DataType(T_isPointer, sz, "enum", rawCppName);
686 if (IsUnion(data)) return DataType(T_isPointer, sz, "union", rawCppName);
687 if (IsClass(data)) return DataType(T_isPointer, sz, "class", rawCppName);
688
689 return DataType();
690 }
691 };
692
693 // DataType resolver for non-pointer types
694 template<typename T>
695 struct Resolver : ResolverBase<T,false> {
696 static DataType resolve(const T& data) {
697 return ResolverBase<T,false>::resolve(data);
698 }
699 };
700
701 // DataType resolver for pointer types (of 1st degree)
702 template<typename T>
703 struct Resolver<T*> : ResolverBase<T,true> {
704 static DataType resolve(const T* const & data) {
705 return ResolverBase<T,true>::resolve(*data);
706 }
707 };
708
709 // DataType resolver for non-pointer Array<> container object types.
710 template<typename T>
711 struct Resolver<Array<T>> {
712 static DataType resolve(const Array<T>& data) {
713 const int sz = sizeof(data);
714 T unused = T();
715 return DataType(false, sz, "Array", rawCppTypeNameOf(unused));
716 }
717 };
718
719 // DataType resolver for Array<> pointer types (of 1st degree).
720 template<typename T>
721 struct Resolver<Array<T>*> {
722 static DataType resolve(const Array<T>*& data) {
723 const int sz = sizeof(*data);
724 T unused = T();
725 return DataType(true, sz, "Array", rawCppTypeNameOf(unused));
726 }
727 };
728
729 // DataType resolver for non-pointer Set<> container object types.
730 template<typename T>
731 struct Resolver<Set<T>> {
732 static DataType resolve(const Set<T>& data) {
733 const int sz = sizeof(data);
734 T unused = T();
735 return DataType(false, sz, "Set", rawCppTypeNameOf(unused));
736 }
737 };
738
739 // DataType resolver for Set<> pointer types (of 1st degree).
740 template<typename T>
741 struct Resolver<Set<T>*> {
742 static DataType resolve(const Set<T>*& data) {
743 const int sz = sizeof(*data);
744 T unused = T();
745 return DataType(true, sz, "Set", rawCppTypeNameOf(unused));
746 }
747 };
748
749 // DataType resolver for non-pointer Map<> container object types.
750 template<typename T_key, typename T_value>
751 struct Resolver<Map<T_key,T_value>> {
752 static DataType resolve(const Map<T_key,T_value>& data) {
753 const int sz = sizeof(data);
754 T_key unused1 = T_key();
755 T_value unused2 = T_value();
756 return DataType(false, sz, "Map", rawCppTypeNameOf(unused1),
757 rawCppTypeNameOf(unused2));
758 }
759 };
760
761 // DataType resolver for Map<> pointer types (of 1st degree).
762 template<typename T_key, typename T_value>
763 struct Resolver<Map<T_key,T_value>*> {
764 static DataType resolve(const Map<T_key,T_value>*& data) {
765 const int sz = sizeof(*data);
766 T_key unused1 = T_key();
767 T_value unused2 = T_value();
768 return DataType(true, sz, "Map", rawCppTypeNameOf(unused1),
769 rawCppTypeNameOf(unused2));
770 }
771 };
772
773 // for compile-time known types
774 template<typename T>
775 static String rawCppTypeName() {
776 const std::type_info& type = typeid(T);
777 #if defined _MSC_VER // Microsoft compiler ...
778 String name = type.raw_name();
779 #else // i.e. especially GCC and clang ...
780 String name = type.name();
781 #endif
782 //while (!name.empty() && name[0] >= 0 && name[0] <= 9)
783 // name = name.substr(1);
784 return name;
785 }
786
787 // for RTTI resolved pointer types
788 template<typename T>
789 static String rawCppTypeNameOf(const T* const & data) {
790 return rawCppTypeName<T*>();
791 }
792
793 // for RTTI resolved non-pointer types
794 template<typename T>
795 static String rawCppTypeNameOf(const T& data) {
796 const std::type_info& type = typeid(data);
797 #if defined _MSC_VER // Microsoft compiler ...
798 String name = type.raw_name();
799 #else // i.e. especially GCC and clang ...
800 String name = type.name();
801 #endif
802 //while (!name.empty() && name[0] >= 0 && name[0] <= 9)
803 // name = name.substr(1);
804 return name;
805 }
806
807 private:
808 struct NativeType {
809 size_t size;
810 std::function<Object(Archive*)> allocFn;
811 };
812
813 String m_baseTypeName;
814 String m_customTypeName;
815 String m_customTypeName2;
816 int m_size;
817 bool m_isPointer;
818 static std::map<String,NativeType> m_nativeTypes;
819
820#if LIBGIG_SERIALIZATION_INTERNAL
821 friend DataType _popDataTypeBlob(const char*& p, const char* end);
822#endif
823 friend class Archive;
824 };
825
847 class Member {
848 public:
849 Member();
850 UID uid() const;
851 UID parentUID() const;
852 String name() const;
853 ssize_t offset() const;
854 const DataType& type() const;
855 bool isValid() const;
856 operator bool() const { return isValid(); }
857 //bool operator()() const { return isValid(); }
858 bool operator==(const Member& other) const;
859 bool operator!=(const Member& other) const;
860 bool operator<(const Member& other) const;
861 bool operator>(const Member& other) const;
862
863 protected:
864 Member(String name, UID uid, ssize_t offset, DataType type, const Object& parent);
865 friend class Archive;
866
867 private:
868 UID m_uid;
869 ssize_t m_offset;
870 String m_name;
871 DataType m_type;
872 UID m_parentUID;
873
874#if LIBGIG_SERIALIZATION_INTERNAL
875 friend Member _popMemberBlob(const char*& p, const char* end);
876#endif
877 };
878
903 class Object {
904 public:
905 Object();
906 Object(UIDChain uidChain, DataType type, const Object& parent);
907
908 UID uid(int index = 0) const;
909 const UIDChain& uidChain() const;
910 UID parentUID() const;
911 const DataType& type() const;
912 const RawData& rawData() const;
913 Version version() const;
914 Version minVersion() const;
915 bool isVersionCompatibleTo(const Object& other) const;
916 std::vector<Member>& members();
917 const std::vector<Member>& members() const;
918 Member memberNamed(String name) const;
919 Member memberByUID(const UID& uid) const;
920 std::vector<Member> membersOfType(const DataType& type) const;
921 int sequenceIndexOf(const Member& member) const;
922 bool isValid() const;
923 operator bool() const { return isValid(); }
924 //bool operator()() const { return isValid(); }
925 bool operator==(const Object& other) const;
926 bool operator!=(const Object& other) const;
927 bool operator<(const Object& other) const;
928 bool operator>(const Object& other) const;
929 void setNativeValueFromString(const String& s);
930
931 protected:
932 void remove(const Member& member);
933 void setVersion(Version v);
934 void setMinVersion(Version v);
935
936 private:
937 DataType m_type;
938 UIDChain m_uid;
939 UID m_parentUID;
940 Version m_version;
941 Version m_minVersion;
942 RawData m_data;
943 std::vector<Member> m_members;
944 std::function<void(Object& dstObj, const Object& srcObj, void* syncer)> m_sync;
945
946#if LIBGIG_SERIALIZATION_INTERNAL
947 friend String _encodePrimitiveValue(const Object& obj);
948 friend Object _popObjectBlob(const char*& p, const char* end);
949 friend void _popPrimitiveValue(const char*& p, const char* end, Object& obj);
950 friend String _primitiveObjectValueToString(const Object& obj);
951 // |
952 template<typename T>
953 friend T _primitiveObjectValueToNumber(const Object& obj);
954#endif // LIBGIG_SERIALIZATION_INTERNAL
955
956 friend class Archive;
957 };
958
1096 class Archive {
1097 public:
1105
1106 Archive();
1107 Archive(const RawData& data);
1108 Archive(const uint8_t* data, size_t size);
1109 virtual ~Archive();
1110
1136 template<typename T>
1137 void serialize(const T* obj) {
1138 m_operation = OPERATION_SERIALIZE;
1139 m_allObjects.clear();
1140 m_rawData.clear();
1141 m_root = UID::from(obj);
1142 const_cast<T*>(obj)->serialize(this);
1143 encode();
1144 m_operation = OPERATION_NONE;
1145 }
1146
1171 template<typename T>
1172 void deserialize(T* obj) {
1173 Archive a;
1174 a.m_operation = m_operation = OPERATION_DESERIALIZE;
1175 obj->serialize(&a);
1176 a.m_root = UID::from(obj);
1177 Syncer s(a, *this);
1178 a.m_operation = m_operation = OPERATION_NONE;
1179 }
1180
1195 template<typename T>
1196 void operator<<(const T& obj) {
1197 serialize(&obj);
1198 }
1199
1218 template<typename T>
1219 void operator>>(T& obj) {
1220 deserialize(&obj);
1221 }
1222
1223 const RawData& rawData();
1224 virtual String rawDataFormat() const;
1225
1282 template<typename T_classType, typename T_memberType>
1283 void serializeMember(const T_classType& nativeObject, const T_memberType& nativeMember, const char* memberName) {
1284 const ssize_t offset =
1285 ((const uint8_t*)(const void*)&nativeMember) -
1286 ((const uint8_t*)(const void*)&nativeObject);
1287 const UIDChain uids = UIDChainResolver<T_memberType>(nativeMember);
1288 const DataType type = DataType::dataTypeOf(nativeMember);
1289 const UID parentUID = UID::from(nativeObject);
1290 Object& parent = m_allObjects[parentUID];
1291 if (!parent) {
1292 const UIDChain uids = UIDChainResolver<T_classType>(nativeObject);
1293 const DataType type = DataType::dataTypeOf(nativeObject);
1294 parent = Object(uids, type, Object());
1295 }
1296 const Member member(memberName, uids[0], offset, type, parent);
1297 std::vector<Member>& members = parent.members();
1298 for (const Member& m : members)
1299 assert(m.name() != memberName);
1300 parent.members().push_back(member);
1301 const Object obj(uids, type, parent);
1302 const bool bExistsAlready = m_allObjects.count(uids[0]);
1303 const bool isValidObject = obj;
1304 const Object& existingObj = m_allObjects[uids[0]];
1305 const bool bExistingObjectIsInvalid = !existingObj;
1306 if (isValidObject && (
1307 !bExistsAlready || bExistingObjectIsInvalid || (
1308 obj.parentUID() && !existingObj.parentUID()
1309 )
1310 ))
1311 {
1312 m_allObjects[uids[0]] = obj;
1313 // recurse serialization for all members of this member
1314 // (only for struct/class types, noop for primitive types)
1315 SerializationRecursion<T_memberType>::serializeObject(this, nativeMember);
1316 }
1317 }
1318
1349 template<typename T_classType, typename T_memberType>
1350 void serializeHeapMember(const T_classType& nativeObject, const T_memberType& heapMember, const char* memberName) {
1351 const ssize_t offset = -1; // used for all members on heap
1352 const UIDChain uids = UIDChainResolver<T_memberType>(heapMember);
1353 const DataType type = DataType::dataTypeOf(heapMember);
1354 const UID parentUID = UID::from(nativeObject);
1355 Object& parent = m_allObjects[parentUID];
1356 if (!parent) {
1357 const UIDChain uids = UIDChainResolver<T_classType>(nativeObject);
1358 const DataType type = DataType::dataTypeOf(nativeObject);
1359 parent = Object(uids, type, Object());
1360 }
1361 const Member member(memberName, uids[0], offset, type, parent);
1362 parent.members().push_back(member);
1363 const Object obj(uids, type, parent);
1364 const bool bExistsAlready = m_allObjects.count(uids[0]);
1365 const bool isValidObject = obj;
1366 const Object& existingObj = m_allObjects[uids[0]];
1367 const bool bExistingObjectIsInvalid = !existingObj;
1368 if (isValidObject && (
1369 !bExistsAlready || bExistingObjectIsInvalid || (
1370 obj.parentUID() && !existingObj.parentUID()
1371 )
1372 ))
1373 {
1374 m_allObjects[uids[0]] = obj;
1375 // recurse serialization for all members of this member
1376 // (only for struct/class types, noop for primitive types)
1377 SerializationRecursion<T_memberType>::serializeObject(this, heapMember);
1378 }
1379 }
1380
1401 template<typename T_objectType>
1402 void serializeAnonymousObject(const T_objectType& heapObject) {
1403 const UIDChain uids = UIDChainResolver<T_objectType>(heapObject);
1404 const DataType type = DataType::dataTypeOf(heapObject);
1405 const Object obj(uids, type, Object());
1406 const bool bExistsAlready = m_allObjects.count(uids[0]);
1407 const bool isValidObject = obj;
1408 const Object& existingObj = m_allObjects[uids[0]];
1409 const bool bExistingObjectIsInvalid = !existingObj;
1410 if (isValidObject && (
1411 !bExistsAlready || bExistingObjectIsInvalid || (
1412 obj.parentUID() && !existingObj.parentUID()
1413 )
1414 ))
1415 {
1416 m_allObjects[uids[0]] = obj;
1417 // recurse serialization for all members of this object
1418 // (only for struct/class types, noop for primitive types)
1419 SerializationRecursion<T_objectType>::serializeObject(this, heapObject);
1420 }
1421 }
1422
1502 template<typename T_classType>
1503 void setVersion(const T_classType& nativeObject, Version v) {
1504 const UID uid = UID::from(nativeObject);
1505 Object& obj = m_allObjects[uid];
1506 if (!obj) {
1507 const UIDChain uids = UIDChainResolver<T_classType>(nativeObject);
1508 const DataType type = DataType::dataTypeOf(nativeObject);
1509 obj = Object(uids, type, Object());
1510 }
1511 setVersion(obj, v);
1512 }
1513
1543 template<typename T_classType>
1544 void setMinVersion(const T_classType& nativeObject, Version v) {
1545 const UID uid = UID::from(nativeObject);
1546 Object& obj = m_allObjects[uid];
1547 if (!obj) {
1548 const UIDChain uids = UIDChainResolver<T_classType>(nativeObject);
1549 const DataType type = DataType::dataTypeOf(nativeObject);
1550 obj = Object(uids, type, Object());
1551 }
1552 setMinVersion(obj, v);
1553 }
1554
1555 virtual void decode(const RawData& data);
1556 virtual void decode(const uint8_t* data, size_t size);
1557 void clear();
1558 bool isModified() const;
1559 void removeMember(Object& parent, const Member& member);
1560 void remove(const Object& obj);
1561 Object& rootObject();
1562 Object& objectByUID(const UID& uid);
1563 Object& parentObjectOf(const Object& obj);
1564 Object& parentObjectOf(const Member& member);
1565 void setAutoValue(Object& object, String value);
1566 void setIntValue(Object& object, int64_t value);
1567 void setRealValue(Object& object, double value);
1568 void setBoolValue(Object& object, bool value);
1569 void setEnumValue(Object& object, uint64_t value);
1570 void setStringValue(Object& object, String value);
1571 String valueAsString(const Object& object);
1572 int64_t valueAsInt(const Object& object);
1573 double valueAsReal(const Object& object);
1574 bool valueAsBool(const Object& object);
1575 void setVersion(Object& object, Version v);
1576 void setMinVersion(Object& object, Version v);
1577 String name() const;
1578 void setName(String name);
1579 String comment() const;
1581 time_t timeStampCreated() const;
1582 time_t timeStampModified() const;
1583 tm dateTimeCreated(time_base_t base = LOCAL_TIME) const;
1584 tm dateTimeModified(time_base_t base = LOCAL_TIME) const;
1585 operation_t operation() const;
1586
1587 protected:
1588 Object& objectByBaseUID(const UID& uid);
1589
1590 // UID resolver for non-pointer types
1591 template<typename T>
1592 class UIDChainResolver {
1593 public:
1594 UIDChainResolver(const T& data) {
1595 m_uid.push_back(UID::from(data));
1596 }
1597
1598 operator UIDChain() const { return m_uid; }
1599 UIDChain operator()() const { return m_uid; }
1600 private:
1601 UIDChain m_uid;
1602 };
1603
1604 // UID resolver for pointer types (of 1st degree)
1605 template<typename T>
1606 class UIDChainResolver<T*> {
1607 public:
1608 UIDChainResolver(const T* const & data) {
1609 m_uid.push_back({ (ID) &data, sizeof(data) });
1610 if (data)
1611 m_uid.push_back(UID::from(*data));
1612 else
1613 m_uid.push_back({ (ID) data, sizeof(*data) });
1614 }
1615
1616 operator UIDChain() const { return m_uid; }
1617 UIDChain operator()() const { return m_uid; }
1618 private:
1619 UIDChain m_uid;
1620 };
1621
1622 // SerializationRecursion for non-pointer class/struct types.
1623 template<typename T, bool T_isRecursive>
1624 struct SerializationRecursionImpl {
1625 static void serializeObject(Archive* archive, const T& obj) {
1626 const_cast<T&>(obj).serialize(archive);
1627 }
1628 };
1629
1630 // SerializationRecursion for pointers (of 1st degree) to class/structs.
1631 template<typename T, bool T_isRecursive>
1632 struct SerializationRecursionImpl<T*,T_isRecursive> {
1633 static void serializeObject(Archive* archive, const T*& obj) {
1634 if (!obj) return;
1635 const_cast<T*&>(obj)->serialize(archive);
1636 }
1637 };
1638
1639 // NOOP SerializationRecursion for primitive types.
1640 template<typename T>
1641 struct SerializationRecursionImpl<T,false> {
1642 static void serializeObject(Archive* /*archive*/, const T& /*obj*/) {}
1643 };
1644
1645 // SerializationRecursion for pointers (of 1st degree) to primitive types.
1646 template<typename T>
1647 struct SerializationRecursionImpl<T*,false> {
1648 static void serializeObject(Archive* archive, const T* const & obj) {
1649 if (!obj) return;
1650 archive->serializeAnonymousObject(*obj);
1651 }
1652 };
1653
1654 // NOOP SerializationRecursion for String objects.
1655 template<bool T_isRecursive>
1656 struct SerializationRecursionImpl<String,T_isRecursive> {
1657 static void serializeObject(Archive* archive, const String& obj) {}
1658 };
1659
1660 // SerializationRecursion for String pointers (of 1st degree).
1661 template<bool T_isRecursive>
1662 struct SerializationRecursionImpl<String*,T_isRecursive> {
1663 static void serializeObject(Archive* archive, const String*& obj) {
1664 if (!obj) return;
1665 archive->serializeAnonymousObject(*obj);
1666 }
1667 };
1668
1669 // SerializationRecursion for Array<> objects.
1670 template<typename T, bool T_isRecursive>
1671 struct SerializationRecursionImpl<Array<T>,T_isRecursive> {
1672 static void serializeObject(Archive* archive, const Array<T>& obj) {
1673 const UIDChain uids = UIDChainResolver<Array<T>>(obj);
1674 const Object& object = archive->objectByUID(uids[0]);
1675 if (archive->operation() == OPERATION_SERIALIZE) {
1676 for (size_t i = 0; i < obj.size(); ++i) {
1677 archive->serializeHeapMember(
1678 obj, obj[i], ("[" + toString(i) + "]").c_str()
1679 );
1680 }
1681 } else {
1682 const_cast<Object&>(object).m_sync =
1683 [&obj,archive](Object& dstObj, const Object& srcObj,
1684 void* syncer)
1685 {
1686 const size_t n = srcObj.members().size();
1687 const_cast<Array<T>&>(obj).resize(n);
1688 for (size_t i = 0; i < n; ++i) {
1689 archive->serializeHeapMember(
1690 obj, obj[i], ("[" + toString(i) + "]").c_str()
1691 );
1692 }
1693 // updating dstObj required as serializeHeapMember()
1694 // replaced the original object by a new one
1695 dstObj = archive->objectByUID(dstObj.uid());
1696 for (size_t i = 0; i < n; ++i) {
1697 String name = "[" + toString(i) + "]";
1698 Member srcMember = srcObj.memberNamed(name);
1699 Member dstMember = dstObj.memberNamed(name);
1700 ((Syncer*)syncer)->syncMember(dstMember, srcMember);
1701 }
1702 };
1703 }
1704 }
1705 };
1706
1707 // SerializationRecursion for Array<> pointers (of 1st degree).
1708 template<typename T, bool T_isRecursive>
1709 struct SerializationRecursionImpl<Array<T>*,T_isRecursive> {
1710 static void serializeObject(Archive* archive, const Array<T>*& obj) {
1711 if (!obj) return;
1712 SerializationRecursionImpl<Array<T>,T_isRecursive>::serializeObject(
1713 archive, *obj
1714 );
1715 }
1716 };
1717
1718 // SerializationRecursion for Set<> objects.
1719 template<typename T, bool T_isRecursive>
1720 struct SerializationRecursionImpl<Set<T>,T_isRecursive> {
1721 static void serializeObject(Archive* archive, const Set<T>& obj) {
1722 const UIDChain uids = UIDChainResolver<Set<T>>(obj);
1723 const Object& object = archive->objectByUID(uids[0]);
1724 if (archive->operation() == OPERATION_SERIALIZE) {
1725 for (const T& key : obj) {
1726 archive->serializeHeapMember(
1727 obj, key, ("[" + toString(key) + "]").c_str()
1728 );
1729 }
1730 } else {
1731 const_cast<Object&>(object).m_sync =
1732 [&obj,archive](Object& dstObj, const Object& srcObj,
1733 void* syncer)
1734 {
1735 const size_t n = srcObj.members().size();
1736 const_cast<Set<T>&>(obj).clear();
1737 for (size_t i = 0; i < n; ++i) {
1738 const Member& member = srcObj.members()[i];
1739 String name = member.name();
1740 // strip brackets from name
1741 if (name.length() < 2 || name[0] != '[' ||
1742 *name.rbegin() != ']') continue;
1743 name = name.substr(1, name.length() - 2);
1744 T key = T();
1745 const UIDChain uids = UIDChainResolver<T>(key);
1746 const DataType type = DataType::dataTypeOf(key);
1747 Object tmpObj(uids, type, Object());
1748 // set the value of "key" variable by abstraction API
1749 tmpObj.setNativeValueFromString(name);
1750 // only for keys of pointer type: translation of
1751 // memory address from source archive to destination
1752 // archive required, NOOP for all other data types
1753 ((Syncer*)syncer)->translateKey(key);
1754 // insert (translated) key into set
1755 const_cast<Set<T>&>(obj).insert(key);
1756 }
1757 // continue serialization recursion
1758 for (const T& key : obj) {
1759 archive->serializeHeapMember(
1760 obj, key, ("[" + toString(key) + "]").c_str()
1761 );
1762 }
1763 // updating dstObj required as serializeHeapMember()
1764 // replaced the original object by a new one
1765 dstObj = archive->objectByUID(dstObj.uid());
1766 };
1767 }
1768 }
1769 };
1770
1771 // SerializationRecursion for Set<> pointers (of 1st degree).
1772 template<typename T, bool T_isRecursive>
1773 struct SerializationRecursionImpl<Set<T>*,T_isRecursive> {
1774 static void serializeObject(Archive* archive, const Set<T>*& obj) {
1775 if (!obj) return;
1776 SerializationRecursionImpl<Set<T>,T_isRecursive>::serializeObject(
1777 archive, *obj
1778 );
1779 }
1780 };
1781
1782 // SerializationRecursion for Map<> objects.
1783 template<typename T_key, typename T_value, bool T_isRecursive>
1784 struct SerializationRecursionImpl<Map<T_key,T_value>,T_isRecursive> {
1785 static void serializeObject(Archive* archive, const Map<T_key,T_value>& obj) {
1786 const UIDChain uids = UIDChainResolver<Map<T_key,T_value>>(obj);
1787 const Object& object = archive->objectByUID(uids[0]);
1788 if (archive->operation() == OPERATION_SERIALIZE) {
1789 for (const auto& it : obj) {
1790 // recurse serialization for map's key ...
1791 SerializationRecursion<T_key>::serializeObject(archive, it.first);
1792 // ... and map's value
1793 archive->serializeHeapMember(
1794 obj, it.second, ("[" + toString(it.first) + "]").c_str()
1795 );
1796 }
1797 } else {
1798 const_cast<Object&>(object).m_sync =
1799 [&obj,archive](Object& dstObj, const Object& srcObj,
1800 void* syncer)
1801 {
1802 const size_t n = srcObj.members().size();
1803 const_cast<Map<T_key,T_value>&>(obj).clear();
1804 // translation is neutral except for keys of pointer type (see comments below)
1805 std::map<String,String> memberNameTranslation;
1806 for (size_t i = 0; i < n; ++i) {
1807 const Member& member = srcObj.members()[i];
1808 String name = member.name();
1809 // strip brackets from name
1810 if (name.length() < 2 || name[0] != '[' ||
1811 *name.rbegin() != ']') continue;
1812 name = name.substr(1, name.length() - 2);
1813 T_key srcKey = T_key();
1814 const UIDChain uids = UIDChainResolver<T_key>(srcKey);
1815 const DataType type = DataType::dataTypeOf(srcKey);
1816 Object tmpObj(uids, type, Object());
1817 // set the value of "srcKey" variable by abstraction API
1818 tmpObj.setNativeValueFromString(name);
1819 T_key dstKey = srcKey;
1820 // only for keys of pointer type: translation of
1821 // memory address from source archive to destination
1822 // archive required, NOOP for all other data types
1823 ((Syncer*)syncer)->translateKey(dstKey);
1824 memberNameTranslation[member.name()] = "[" + toString(dstKey) + "]";
1825 // insert (translated) key into the destination map
1826 const_cast<Map<T_key,T_value>&>(obj)[dstKey] = T_value();
1827 }
1828 // continue serialization recursion ...
1829 for (const auto& it : obj) {
1830 // ... for map's key ...
1831 SerializationRecursion<T_key>::serializeObject(archive, it.first);
1832 // ... and map's value
1833 archive->serializeHeapMember(
1834 obj, it.second, ("[" + toString(it.first) + "]").c_str()
1835 );
1836 }
1837 // updating dstObj required as serializeHeapMember()
1838 // replaced the original object by a new one
1839 dstObj = archive->objectByUID(dstObj.uid());
1840 // sync map's values
1841 for (size_t i = 0; i < n; ++i) {
1842 Member srcMember = srcObj.members()[i];
1843 Member dstMember = dstObj.memberNamed(
1844 memberNameTranslation[srcMember.name()]
1845 );
1846 ((Syncer*)syncer)->syncMember(dstMember, srcMember);
1847 }
1848 };
1849 }
1850 }
1851 };
1852
1853 // SerializationRecursion for Map<> pointers (of 1st degree).
1854 template<typename T_key, typename T_value, bool T_isRecursive>
1855 struct SerializationRecursionImpl<Map<T_key,T_value>*,T_isRecursive> {
1856 static void serializeObject(Archive* archive, const Map<T_key,T_value>*& obj) {
1857 if (!obj) return;
1858 SerializationRecursionImpl<Map<T_key,T_value>,T_isRecursive>::serializeObject(
1859 archive, *obj
1860 );
1861 }
1862 };
1863
1864 // Automatically handles recursion for class/struct types, while ignoring all primitive types.
1865 template<typename T>
1866 struct SerializationRecursion : SerializationRecursionImpl<T, LIBGIG_IS_CLASS(T)> {
1867 };
1868
1869 class ObjectPool : public std::map<UID,Object> {
1870 public:
1871 // prevent passing obvious invalid UID values from creating a new pair entry
1872 Object& operator[](const UID& k) {
1873 if (!k.isValid())
1874 return invalidObject();
1875 return std::map<UID,Object>::operator[](k);
1876 }
1877
1878 static Object& invalidObject() {
1879 static Object invalid;
1880 invalid = Object();
1881 return invalid;
1882 }
1883 };
1884
1885 friend String _encode(const ObjectPool& objects);
1886
1887 private:
1888 String _encodeRootBlob();
1889 void _popRootBlob(const char*& p, const char* end);
1890 void _popObjectsBlob(const char*& p, const char* end);
1891
1892 protected:
1932 class Syncer {
1933 public:
1934 Syncer(Archive& dst, Archive& src);
1935 void syncObject(const Object& dst, const Object& src);
1936 void syncPrimitive(const Object& dst, const Object& src);
1937 void syncString(const Object& dst, const Object& src);
1938 void syncArray(const Object& dst, const Object& src);
1939 void syncSet(const Object& dst, const Object& src);
1940 void syncMap(const Object& dst, const Object& src);
1941 void syncPointer(const Object& dst, const Object& src);
1942 void syncMember(const Member& dstMember, const Member& srcMember);
1943
1944 // Address translation for keys of pointer type.
1945 //
1946 // Translates memory address from source archive, to memory address
1947 // of destination archive. For "strong" pointers memory is allocated
1948 // and the pointed data is synced with data from source archive.
1949 template<typename T>
1950 void translateKey(T*& key) {
1951 if (!key) return; // NULL pointer on source side
1952
1953 // UIDChainResolver can't be used here, since the passed memory
1954 // address is an abstract one that originates from the source
1955 // archive (e.g. potentially even from another machine) and
1956 // UIDChainResolver would then crash on its typeid() operator.
1957 UID uid = { (ID) key, sizeof(*key) };
1958
1959 const Object& pointedSrcObject = m_src.objectByBaseUID(uid);
1960 assert(pointedSrcObject);
1961 std::map<UID,UID>::iterator uidRelation = m_counterparts.find(uid);
1962 if (pointedSrcObject.parentUID() || uidRelation != m_counterparts.end()) { // "weak" pointer to object ...
1963 assert(uidRelation != m_counterparts.end());
1964 key = (T*) uidRelation->second.id;
1965 } else { // "strong" pointer to object, allocation required ...
1966 assert(pointedSrcObject.type());
1967 Object pointedDstObject = pointedSrcObject.type().newInstance(&m_dst);
1968 assert(pointedDstObject);
1969 m_dst.m_allObjects[pointedDstObject.uid()] = pointedDstObject;
1970 key = (T*) pointedDstObject.uid().id;
1971
1972 syncObject(pointedDstObject, pointedSrcObject);
1973 }
1974 }
1975
1976 // NOOP, no key translation required for any other type
1977 template<typename T>
1978 void translateKey(T& key) {}
1979 protected:
1980 static Member dstMemberMatching(const Object& dstObj, const Object& srcObj, const Member& srcMember);
1981 private:
1982 Archive& m_dst;
1983 Archive& m_src;
1984 std::map<UID,UID> m_counterparts;
1985 };
1986
1987 virtual void encode();
1988
1989 ObjectPool m_allObjects;
1990 operation_t m_operation;
1991 UID m_root;
1992 RawData m_rawData;
1993 bool m_isModified;
1994 String m_name;
1995 String m_comment;
1996 time_t m_timeCreated;
1997 time_t m_timeModified;
1998
1999 friend class DataType;
2000 };
2001
2002 // UID resolver implementation for non-pointer types
2003 template<typename T>
2004 UID UID::Resolver<T>::resolve(const T& obj) {
2005 const size_t size = DataType::sizeOf(obj);
2006 const UID uid = { (ID) &obj, size };
2007 return uid;
2008 }
2009
2010 // UID resolver implementation for pointer types (of 1st degree)
2011 template<typename T>
2012 UID UID::Resolver<T*>::resolve(const T* const & obj) {
2013 const size_t size = DataType::sizeOf(*obj);
2014 const UID uid = { (ID) obj, size };
2015 return uid;
2016 }
2017
2018 // Manual registration of native data types by application.
2019 template<typename T>
2021 static_assert(
2022 std::is_default_constructible<T>::value,
2023 "missing default constructor for type: registration of data "
2024 "types is only needed for creating instances of that type at "
2025 "runtime by this framework's reflection API; which in turn "
2026 "requires the type to provide a default constructor."
2027 );
2028 const DataType staticType = DataType::dataType<T>(false);
2029 assert(staticType);
2030 const auto itType = m_nativeTypes.find(staticType.internalID());
2031 if (itType != m_nativeTypes.end()) {
2032 assert(itType->second.size >= sizeof(T));
2033 return;
2034 }
2035
2036 // register lambda function for allocating a new instance of this type
2037 m_nativeTypes[staticType.internalID()] = {
2038 /*.size =*/ sizeof(T),
2039 /*.allocFn =*/ [](Archive* archive) -> Object {
2040 T* instance = new T;
2041 Archive::SerializationRecursion<T>::serializeObject(archive, *instance);
2042 const UIDChain uids = Archive::UIDChainResolver<T>(*instance);
2043 Object& obj = archive->objectByUID(uids[0]);
2044 if (obj) return obj;
2045 const DataType type = DataType::dataTypeOf(*instance);
2046 return Object(uids, type, Object());
2047 }
2048 };
2049 }
2050
2051 // Automatic self-registration of native data types by this framework.
2052 // (SFINAE variant for types WITH default constructor)
2053 template<typename T, typename std::enable_if<std::is_default_constructible<T>::value, bool>::type>
2054 void DataType::registerNativeDataType(const DataType& rttiType, const T& nativeData) {
2055 if (!rttiType) return;
2056 if (m_nativeTypes.find(rttiType.internalID()) != m_nativeTypes.end())
2057 return;
2058
2059 // Ensure compile-time native data type 'T' matches passed runtime
2060 // native data type 'nativeData', because we can only offer to create
2061 // new instances of native data types by our reflection API if this
2062 // framework is aware about the data type already. Usually this happens
2063 // automatically without applications having to do anything. But
2064 // this only works for types this framework gets in touch with at
2065 // compile-time.
2066 //
2067 // Root problem of all of this: ATM there is no way in C++ to create new
2068 // instances of a type by using RTTI (typeid(), std::type_info, etc.).
2069 // If there is a way in a future C++ version then we can get rid of
2070 // manual type registration altogether. Bur for now we must use new T,
2071 // which is a compile-time only construct.
2072 //
2073 // See the discussion in DataType::registerNativeDataType() for an
2074 // example where manual type registration would be required.
2075 const DataType staticType = DataType::dataType<T>(false);
2076 if (staticType != rttiType) {
2077 fprintf(stderr, "Serialization Failure: run-time data type '%s' does not match compile-time data type '%s'!\n",
2078 rttiType.asLongDescr().c_str(),
2079 staticType.asLongDescr().c_str());
2080 assert(false && "You may need to explicitly register this run-time "
2081 "data type by either calling "
2082 "DataType::registerNativeType<T>() or using class "
2083 "NativeDataTypeRegistry");
2084 }
2085
2086 // register lambda function for allocating a new instance of this type
2087 m_nativeTypes[rttiType.internalID()] = {
2088 /*.size =*/ sizeof(T),
2089 /*.allocFn =*/ [](Archive* archive) -> Object {
2090 T* instance = new T;
2091 Archive::SerializationRecursion<T>::serializeObject(archive, *instance);
2092 const UIDChain uids = Archive::UIDChainResolver<T>(*instance);
2093 Object& obj = archive->objectByUID(uids[0]);
2094 if (obj) return obj;
2095 const DataType type = DataType::dataTypeOf(*instance);
2096 return Object(uids, type, Object());
2097 }
2098 };
2099 }
2100
2101 // Automatic self-registration of native data types by this framework.
2102 // (SFINAE variant for types WITHOUT default constructor)
2103 template<typename T, typename std::enable_if<!std::is_default_constructible<T>::value, bool>::type>
2104 void DataType::registerNativeDataType(const DataType& type, const T& nativeData) {
2105 if (!type) return;
2106 if (m_nativeTypes.find(type.internalID()) != m_nativeTypes.end())
2107 return;
2108 m_nativeTypes[type.internalID()] = {
2109 /*.size =*/ sizeof(T),
2110 /*.allocFn =*/ [](Archive*) -> Object {
2111 assert(false && "instance not possible: native data type does not have default constructor");
2112 return Object();
2113 }
2114 };
2115 }
2116
2121 class Exception {
2122 public:
2123 String Message;
2124
2125 Exception(String format, ...);
2126 Exception(String format, va_list arg);
2127 void PrintMessage() const;
2128 virtual ~Exception() {}
2129
2130 protected:
2131 Exception();
2132 static String assemble(String format, va_list arg);
2133 };
2134
2135} // namespace Serialization
2136
2137#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.
void serializeAnonymousObject(const T_objectType &heapObject)
Serialize anonymous C/C++ 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.
Object & objectByBaseUID(const UID &uid)
Find true object for a base pointer.
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.
Object & parentObjectOf(const Object &obj)
Access parent of supplied object.
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.
static DataType dataTypeOf(const T &data, bool registerType=true)
Construct a DataType object for the given native C++ data.
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).
static void registerNativeDataType()
Manual registration of native C++ data types.
String asLongDescr() const
Human readable long description for this data type.
bool isBool() const
Whether this is a boolean C/C++ data type.
static size_t sizeOf(const T &data)
True size of passed native data in bytes.
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.
String internalID() const
Unique key for native data type, for internal purposes only.
static DataType dataType(bool registerType=true)
Construct a DataType object for the given native C++ type.
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.
Object newInstance(Archive *archive) const
Allocate and initialize a native instance of data type.
Will be thrown whenever an error occurs during an serialization or deserialization process.
void PrintMessage() const
Print exception message to stdout.
Abstract reflection of a native C++ class/struct's member variable.
UID parentUID() const
Unique identifier of parent object.
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.
UID parentUID() const
Unique identifier of parent object.
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 &)
Check whether data is a C++ union type.
void * ID
Abstract identifier for serialized C++ objects.
bool IsClass(const T &)
Check whether data is a C/C++ struct or C++ class type.
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.
std::set< T > Set
Set<> template.
std::string String
Textual string.
std::map< T_key, T_value > Map
Map<> template.
bool IsEnum(const T &)
Check whether data is a C/C++ enum type.
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...