libgig  4.5.0.svn7
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 
44 #include "sysdef.h"
45 
46 #ifndef __has_extension
47 # define __has_extension(x) 0
48 #endif
49 
50 #ifndef HAS_BUILTIN_TYPE_TRAITS
51 # if __cplusplus >= 201103L
52 # define HAS_BUILTIN_TYPE_TRAITS 1
53 # elif ( __has_extension(is_class) && __has_extension(is_enum) )
54 # define HAS_BUILTIN_TYPE_TRAITS 1
55 # elif ( __GNUC__ > 4 || ( __GNUC__ == 4 && __GNUC_MINOR__ >= 3 ) )
56 # define HAS_BUILTIN_TYPE_TRAITS 1
57 # elif _MSC_VER >= 1400 /* MS Visual C++ 8.0 (Visual Studio 2005) */
58 # define HAS_BUILTIN_TYPE_TRAITS 1
59 # elif __INTEL_COMPILER >= 1100
60 # define HAS_BUILTIN_TYPE_TRAITS 1
61 # else
62 # define HAS_BUILTIN_TYPE_TRAITS 0
63 # endif
64 #endif
65 
66 #if !HAS_BUILTIN_TYPE_TRAITS
67 # include <tr1/type_traits>
68 # define LIBGIG_IS_CLASS(type) std::tr1::__is_union_or_class<type>::value //NOTE: without compiler support we cannot distinguish union from class
69 #else
70 # define LIBGIG_IS_CLASS(type) __is_class(type)
71 #endif
72 
116 namespace Serialization {
117 
118  // just symbol prototyping
119  class DataType;
120  class Object;
121  class Member;
122  class Archive;
123  class ObjectPool;
124  class Exception;
125 
133  typedef std::string String;
134 
147  template<class T>
148  using Array = std::vector<T>;
149 
159  template<class T>
160  using Set = std::set<T>;
161 
180  template<class T_key, class T_value>
181  using Map = std::map<T_key,T_value>;
182 
191  typedef std::vector<uint8_t> RawData;
192 
203  typedef void* ID;
204 
212  typedef uint32_t Version;
213 
219  enum time_base_t {
221  UTC_TIME
222  };
223 
231  template<typename T>
232  bool IsEnum(const T& /*data*/) {
233  #if !HAS_BUILTIN_TYPE_TRAITS
234  return std::tr1::is_enum<T>::value;
235  #else
236  return __is_enum(T);
237  #endif
238  }
239 
250  template<typename T>
251  bool IsUnion(const T& /*data*/) {
252  #if !HAS_BUILTIN_TYPE_TRAITS
253  return false; // without compiler support we cannot distinguish union from class
254  #else
255  return __is_union(T);
256  #endif
257  }
258 
268  template<typename T>
269  bool IsClass(const T& /*data*/) {
270  #if !HAS_BUILTIN_TYPE_TRAITS
271  return std::tr1::__is_union_or_class<T>::value; // without compiler support we cannot distinguish union from class
272  #else
273  return __is_class(T);
274  #endif
275  }
276 
277  /*template<typename T>
278  bool IsTrivial(T data) {
279  return __is_trivial(T);
280  }*/
281 
282  /*template<typename T>
283  bool IsPOD(T data) {
284  return __is_pod(T);
285  }*/
286 
287  /*template<typename T>
288  bool IsArray(const T& data) {
289  return false;
290  }*/
291 
292  /*template<typename T>
293  bool IsArray(const Array<T>& data) {
294  return true;
295  }*/
296 
297  template<typename T> inline
298  String toString(const T& value) {
299  return std::to_string(value);
300  }
301 
302  template<typename T> inline
303  String toString(T* ptr) {
304  std::stringstream ss;
305  ss << "0x" << std::hex << size_t(ptr);
306  return ss.str();
307  }
308 
309  template<> inline
310  String toString(const String& value) {
311  return value;
312  }
313 
329  class UID {
330  public:
331  ID id;
332  size_t size;
333 
334  bool isValid() const;
335  operator bool() const { return isValid(); }
336  //bool operator()() const { return isValid(); }
337  bool operator==(const UID& other) const { return id == other.id && size == other.size; }
338  bool operator!=(const UID& other) const { return id != other.id || size != other.size; }
339  bool operator<(const UID& other) const { return id < other.id || (id == other.id && size < other.size); }
340  bool operator>(const UID& other) const { return id > other.id || (id == other.id && size > other.size); }
341 
349  template<typename T>
350  static UID from(const T& obj) {
351  return Resolver<T>::resolve(obj);
352  }
353 
354  protected:
355  // UID resolver for non-pointer types
356  template<typename T>
357  struct Resolver {
358  static UID resolve(const T& obj) {
359  const UID uid = { (ID) &obj, sizeof(obj) };
360  return uid;
361  }
362  };
363 
364  // UID resolver for pointer types (of 1st degree)
365  template<typename T>
366  struct Resolver<T*> {
367  static UID resolve(const T* const & obj) {
368  const UID uid = { (ID) obj, sizeof(*obj) };
369  return uid;
370  }
371  };
372  };
373 
379  extern const UID NO_UID;
380 
412  typedef std::vector<UID> UIDChain;
413 
414 #if LIBGIG_SERIALIZATION_INTERNAL
415  // prototyping of private internal friend functions
416  static String _encodePrimitiveValue(const Object& obj);
417  static DataType _popDataTypeBlob(const char*& p, const char* end);
418  static Member _popMemberBlob(const char*& p, const char* end);
419  static Object _popObjectBlob(const char*& p, const char* end);
420  static void _popPrimitiveValue(const char*& p, const char* end, Object& obj);
421  static String _primitiveObjectValueToString(const Object& obj);
422  // |
423  template<typename T>
424  static T _primitiveObjectValueToNumber(const Object& obj);
425 #endif // LIBGIG_SERIALIZATION_INTERNAL
426 
443  class DataType {
444  public:
445  DataType();
446  size_t size() const { return m_size; }
447  bool isValid() const;
448  bool isPointer() const;
449  bool isClass() const;
450  bool isPrimitive() const;
451  bool isString() const;
452  bool isInteger() const;
453  bool isReal() const;
454  bool isBool() const;
455  bool isEnum() const;
456  bool isArray() const;
457  bool isSet() const;
458  bool isMap() const;
459  bool isSigned() const;
460  operator bool() const { return isValid(); }
461  //bool operator()() const { return isValid(); }
462  bool operator==(const DataType& other) const;
463  bool operator!=(const DataType& other) const;
464  bool operator<(const DataType& other) const;
465  bool operator>(const DataType& other) const;
466  String asLongDescr() const;
467  String baseTypeName() const;
468  String customTypeName(bool demangle = false) const;
469  String customTypeName2(bool demangle = false) const;
470 
483  template<typename T>
484  static DataType dataTypeOf(const T& data) {
485  const DataType type = Resolver<T>::resolve(data);
486  registerNativeDataType(type, data);
487  return type;
488  }
489 
500  template<typename T>
501  static DataType dataType() {
502  T unused = T();
503  const DataType type = Resolver<T>::resolve(unused);
504  //FIXME: would create an endless recursion
505  //registerNativeDataType(type, unused);
506  return type;
507  }
508 
544  template<typename T>
545  static void registerNativeDataType();
546 
576  template<typename T>
578  public:
580  DataType::registerNativeDataType<T>();
581  }
582  };
583 
584  protected:
585  DataType(bool isPointer, int size, String baseType,
586  String customType1 = "", String customType2 = "");
587 
588  String internalID() const;
589  Object newInstance(Archive* archive) const;
590 
591  template<typename T, typename std::enable_if<std::is_default_constructible<T>::value, bool>::type = true>
592  static void registerNativeDataType(const DataType& type, const T& nativeData);
593 
594  template<typename T, typename std::enable_if<!std::is_default_constructible<T>::value, bool>::type = true>
595  static void registerNativeDataType(const DataType& type, const T& nativeData);
596 
597  template<typename T, bool T_isPointer>
598  struct ResolverBase {
599  static DataType resolve(const T& data) {
600  // for pointers we must stick to the compile-time declared type
601  // of pointer to prevent potential type mismatches caused by
602  // RTTI in a polymorphic scenario
603  const std::type_info& type = (T_isPointer) ? typeid(T) : typeid(data);
604  const int sz = sizeof(data);
605 
606  // for primitive types we are using our own type names instead of
607  // using std:::type_info::name(), because the precise output of the
608  // latter may vary between compilers
609  if (type == typeid(int8_t)) return DataType(T_isPointer, sz, "int8");
610  if (type == typeid(uint8_t)) return DataType(T_isPointer, sz, "uint8");
611  if (type == typeid(int16_t)) return DataType(T_isPointer, sz, "int16");
612  if (type == typeid(uint16_t)) return DataType(T_isPointer, sz, "uint16");
613  if (type == typeid(int32_t)) return DataType(T_isPointer, sz, "int32");
614  if (type == typeid(uint32_t)) return DataType(T_isPointer, sz, "uint32");
615  if (type == typeid(int64_t)) return DataType(T_isPointer, sz, "int64");
616  if (type == typeid(uint64_t)) return DataType(T_isPointer, sz, "uint64");
617  if (type == typeid(size_t)) {
618  if (sz == 1) return DataType(T_isPointer, sz, "uint8");
619  if (sz == 2) return DataType(T_isPointer, sz, "uint16");
620  if (sz == 4) return DataType(T_isPointer, sz, "uint32");
621  if (sz == 8) return DataType(T_isPointer, sz, "uint64");
622  else assert(false /* unknown size_t size */);
623  }
624  if (type == typeid(ssize_t)) {
625  if (sz == 1) return DataType(T_isPointer, sz, "int8");
626  if (sz == 2) return DataType(T_isPointer, sz, "int16");
627  if (sz == 4) return DataType(T_isPointer, sz, "int32");
628  if (sz == 8) return DataType(T_isPointer, sz, "int64");
629  else assert(false /* unknown ssize_t size */);
630  }
631  if (type == typeid(bool)) return DataType(T_isPointer, sz, "bool");
632  if (type == typeid(float)) return DataType(T_isPointer, sz, "real32");
633  if (type == typeid(double)) return DataType(T_isPointer, sz, "real64");
634  if (type == typeid(String)) return DataType(T_isPointer, sz, "String");
635 
636  // for pointers we must stick to pointer's compile-time declared
637  // type and not use RTTI for the pointed object, because the
638  // latter would easily create a type mismatch conflict for
639  // pointers and objects in a polymorphic scenario, because the
640  // pointer might have been declared with a base class type,
641  // while actually assigned objects to these pointers might be of
642  // any other derived class and RTTI would resolve the latter
643  const String rawCppName =
644  (T_isPointer) ? rawCppTypeName<T>()
645  : rawCppTypeNameOf(data);
646 
647  if (IsEnum(data)) return DataType(T_isPointer, sz, "enum", rawCppName);
648  if (IsUnion(data)) return DataType(T_isPointer, sz, "union", rawCppName);
649  if (IsClass(data)) return DataType(T_isPointer, sz, "class", rawCppName);
650 
651  return DataType();
652  }
653  };
654 
655  // DataType resolver for non-pointer types
656  template<typename T>
657  struct Resolver : ResolverBase<T,false> {
658  static DataType resolve(const T& data) {
659  return ResolverBase<T,false>::resolve(data);
660  }
661  };
662 
663  // DataType resolver for pointer types (of 1st degree)
664  template<typename T>
665  struct Resolver<T*> : ResolverBase<T,true> {
666  static DataType resolve(const T* const & data) {
667  return ResolverBase<T,true>::resolve(*data);
668  }
669  };
670 
671  // DataType resolver for non-pointer Array<> container object types.
672  template<typename T>
673  struct Resolver<Array<T>> {
674  static DataType resolve(const Array<T>& data) {
675  const int sz = sizeof(data);
676  T unused = T();
677  return DataType(false, sz, "Array", rawCppTypeNameOf(unused));
678  }
679  };
680 
681  // DataType resolver for Array<> pointer types (of 1st degree).
682  template<typename T>
683  struct Resolver<Array<T>*> {
684  static DataType resolve(const Array<T>*& data) {
685  const int sz = sizeof(*data);
686  T unused = T();
687  return DataType(true, sz, "Array", rawCppTypeNameOf(unused));
688  }
689  };
690 
691  // DataType resolver for non-pointer Set<> container object types.
692  template<typename T>
693  struct Resolver<Set<T>> {
694  static DataType resolve(const Set<T>& data) {
695  const int sz = sizeof(data);
696  T unused = T();
697  return DataType(false, sz, "Set", rawCppTypeNameOf(unused));
698  }
699  };
700 
701  // DataType resolver for Set<> pointer types (of 1st degree).
702  template<typename T>
703  struct Resolver<Set<T>*> {
704  static DataType resolve(const Set<T>*& data) {
705  const int sz = sizeof(*data);
706  T unused = T();
707  return DataType(true, sz, "Set", rawCppTypeNameOf(unused));
708  }
709  };
710 
711  // DataType resolver for non-pointer Map<> container object types.
712  template<typename T_key, typename T_value>
713  struct Resolver<Map<T_key,T_value>> {
714  static DataType resolve(const Map<T_key,T_value>& data) {
715  const int sz = sizeof(data);
716  T_key unused1 = T_key();
717  T_value unused2 = T_value();
718  return DataType(false, sz, "Map", rawCppTypeNameOf(unused1),
719  rawCppTypeNameOf(unused2));
720  }
721  };
722 
723  // DataType resolver for Map<> pointer types (of 1st degree).
724  template<typename T_key, typename T_value>
725  struct Resolver<Map<T_key,T_value>*> {
726  static DataType resolve(const Map<T_key,T_value>*& data) {
727  const int sz = sizeof(*data);
728  T_key unused1 = T_key();
729  T_value unused2 = T_value();
730  return DataType(true, sz, "Map", rawCppTypeNameOf(unused1),
731  rawCppTypeNameOf(unused2));
732  }
733  };
734 
735  // for compile-time known types
736  template<typename T>
737  static String rawCppTypeName() {
738  const std::type_info& type = typeid(T);
739  #if defined _MSC_VER // Microsoft compiler ...
740  String name = type.raw_name();
741  #else // i.e. especially GCC and clang ...
742  String name = type.name();
743  #endif
744  //while (!name.empty() && name[0] >= 0 && name[0] <= 9)
745  // name = name.substr(1);
746  return name;
747  }
748 
749  // for RTTI resolved pointer types
750  template<typename T>
751  static String rawCppTypeNameOf(const T* const & data) {
752  return rawCppTypeName<T*>();
753  }
754 
755  // for RTTI resolved non-pointer types
756  template<typename T>
757  static String rawCppTypeNameOf(const T& data) {
758  const std::type_info& type = typeid(data);
759  #if defined _MSC_VER // Microsoft compiler ...
760  String name = type.raw_name();
761  #else // i.e. especially GCC and clang ...
762  String name = type.name();
763  #endif
764  //while (!name.empty() && name[0] >= 0 && name[0] <= 9)
765  // name = name.substr(1);
766  return name;
767  }
768 
769  private:
770  String m_baseTypeName;
771  String m_customTypeName;
772  String m_customTypeName2;
773  int m_size;
774  bool m_isPointer;
775  static std::map<String,std::function<Object(Archive*)>> m_allocFns;
776 
777 #if LIBGIG_SERIALIZATION_INTERNAL
778  friend DataType _popDataTypeBlob(const char*& p, const char* end);
779 #endif
780  friend class Archive;
781  };
782 
804  class Member {
805  public:
806  Member();
807  UID uid() const;
808  UID parentUID() const;
809  String name() const;
810  ssize_t offset() const;
811  const DataType& type() const;
812  bool isValid() const;
813  operator bool() const { return isValid(); }
814  //bool operator()() const { return isValid(); }
815  bool operator==(const Member& other) const;
816  bool operator!=(const Member& other) const;
817  bool operator<(const Member& other) const;
818  bool operator>(const Member& other) const;
819 
820  protected:
821  Member(String name, UID uid, ssize_t offset, DataType type, const Object& parent);
822  friend class Archive;
823 
824  private:
825  UID m_uid;
826  ssize_t m_offset;
827  String m_name;
828  DataType m_type;
829  UID m_parentUID;
830 
831 #if LIBGIG_SERIALIZATION_INTERNAL
832  friend Member _popMemberBlob(const char*& p, const char* end);
833 #endif
834  };
835 
860  class Object {
861  public:
862  Object();
863  Object(UIDChain uidChain, DataType type, const Object& parent);
864 
865  UID uid(int index = 0) const;
866  const UIDChain& uidChain() const;
867  UID parentUID() const;
868  const DataType& type() const;
869  const RawData& rawData() const;
870  Version version() const;
871  Version minVersion() const;
872  bool isVersionCompatibleTo(const Object& other) const;
873  std::vector<Member>& members();
874  const std::vector<Member>& members() const;
875  Member memberNamed(String name) const;
876  Member memberByUID(const UID& uid) const;
877  std::vector<Member> membersOfType(const DataType& type) const;
878  int sequenceIndexOf(const Member& member) const;
879  bool isValid() const;
880  operator bool() const { return isValid(); }
881  //bool operator()() const { return isValid(); }
882  bool operator==(const Object& other) const;
883  bool operator!=(const Object& other) const;
884  bool operator<(const Object& other) const;
885  bool operator>(const Object& other) const;
886  void setNativeValueFromString(const String& s);
887 
888  protected:
889  void remove(const Member& member);
890  void setVersion(Version v);
891  void setMinVersion(Version v);
892 
893  private:
894  DataType m_type;
895  UIDChain m_uid;
896  UID m_parentUID;
897  Version m_version;
898  Version m_minVersion;
899  RawData m_data;
900  std::vector<Member> m_members;
901  std::function<void(Object& dstObj, const Object& srcObj, void* syncer)> m_sync;
902 
903 #if LIBGIG_SERIALIZATION_INTERNAL
904  friend String _encodePrimitiveValue(const Object& obj);
905  friend Object _popObjectBlob(const char*& p, const char* end);
906  friend void _popPrimitiveValue(const char*& p, const char* end, Object& obj);
907  friend String _primitiveObjectValueToString(const Object& obj);
908  // |
909  template<typename T>
910  friend T _primitiveObjectValueToNumber(const Object& obj);
911 #endif // LIBGIG_SERIALIZATION_INTERNAL
912 
913  friend class Archive;
914  };
915 
1053  class Archive {
1054  public:
1061  };
1062 
1063  Archive();
1064  Archive(const RawData& data);
1065  Archive(const uint8_t* data, size_t size);
1066  virtual ~Archive();
1067 
1093  template<typename T>
1094  void serialize(const T* obj) {
1095  m_operation = OPERATION_SERIALIZE;
1096  m_allObjects.clear();
1097  m_rawData.clear();
1098  m_root = UID::from(obj);
1099  const_cast<T*>(obj)->serialize(this);
1100  encode();
1101  m_operation = OPERATION_NONE;
1102  }
1103 
1128  template<typename T>
1129  void deserialize(T* obj) {
1130  Archive a;
1131  a.m_operation = m_operation = OPERATION_DESERIALIZE;
1132  obj->serialize(&a);
1133  a.m_root = UID::from(obj);
1134  Syncer s(a, *this);
1135  a.m_operation = m_operation = OPERATION_NONE;
1136  }
1137 
1152  template<typename T>
1153  void operator<<(const T& obj) {
1154  serialize(&obj);
1155  }
1156 
1175  template<typename T>
1176  void operator>>(T& obj) {
1177  deserialize(&obj);
1178  }
1179 
1180  const RawData& rawData();
1181  virtual String rawDataFormat() const;
1182 
1239  template<typename T_classType, typename T_memberType>
1240  void serializeMember(const T_classType& nativeObject, const T_memberType& nativeMember, const char* memberName) {
1241  const ssize_t offset =
1242  ((const uint8_t*)(const void*)&nativeMember) -
1243  ((const uint8_t*)(const void*)&nativeObject);
1244  const UIDChain uids = UIDChainResolver<T_memberType>(nativeMember);
1245  const DataType type = DataType::dataTypeOf(nativeMember);
1246  const UID parentUID = UID::from(nativeObject);
1247  Object& parent = m_allObjects[parentUID];
1248  if (!parent) {
1249  const UIDChain uids = UIDChainResolver<T_classType>(nativeObject);
1250  const DataType type = DataType::dataTypeOf(nativeObject);
1251  parent = Object(uids, type, Object());
1252  }
1253  const Member member(memberName, uids[0], offset, type, parent);
1254  parent.members().push_back(member);
1255  const Object obj(uids, type, parent);
1256  const bool bExistsAlready = m_allObjects.count(uids[0]);
1257  const bool isValidObject = obj;
1258  const Object& existingObj = m_allObjects[uids[0]];
1259  const bool bExistingObjectIsInvalid = !existingObj;
1260  if (isValidObject && (
1261  !bExistsAlready || bExistingObjectIsInvalid || (
1262  obj.parentUID() && !existingObj.parentUID()
1263  )
1264  ))
1265  {
1266  m_allObjects[uids[0]] = obj;
1267  // recurse serialization for all members of this member
1268  // (only for struct/class types, noop for primitive types)
1269  SerializationRecursion<T_memberType>::serializeObject(this, nativeMember);
1270  }
1271  }
1272 
1303  template<typename T_classType, typename T_memberType>
1304  void serializeHeapMember(const T_classType& nativeObject, const T_memberType& heapMember, const char* memberName) {
1305  const ssize_t offset = -1; // used for all members on heap
1306  const UIDChain uids = UIDChainResolver<T_memberType>(heapMember);
1307  const DataType type = DataType::dataTypeOf(heapMember);
1308  const UID parentUID = UID::from(nativeObject);
1309  Object& parent = m_allObjects[parentUID];
1310  if (!parent) {
1311  const UIDChain uids = UIDChainResolver<T_classType>(nativeObject);
1312  const DataType type = DataType::dataTypeOf(nativeObject);
1313  parent = Object(uids, type, Object());
1314  }
1315  const Member member(memberName, uids[0], offset, type, parent);
1316  parent.members().push_back(member);
1317  const Object obj(uids, type, parent);
1318  const bool bExistsAlready = m_allObjects.count(uids[0]);
1319  const bool isValidObject = obj;
1320  const Object& existingObj = m_allObjects[uids[0]];
1321  const bool bExistingObjectIsInvalid = !existingObj;
1322  if (isValidObject && (
1323  !bExistsAlready || bExistingObjectIsInvalid || (
1324  obj.parentUID() && !existingObj.parentUID()
1325  )
1326  ))
1327  {
1328  m_allObjects[uids[0]] = obj;
1329  // recurse serialization for all members of this member
1330  // (only for struct/class types, noop for primitive types)
1331  SerializationRecursion<T_memberType>::serializeObject(this, heapMember);
1332  }
1333  }
1334 
1355  template<typename T_objectType>
1356  void serializeAnonymousObject(const T_objectType& heapObject) {
1357  const UIDChain uids = UIDChainResolver<T_objectType>(heapObject);
1358  const DataType type = DataType::dataTypeOf(heapObject);
1359  const Object obj(uids, type, Object());
1360  const bool bExistsAlready = m_allObjects.count(uids[0]);
1361  const bool isValidObject = obj;
1362  const Object& existingObj = m_allObjects[uids[0]];
1363  const bool bExistingObjectIsInvalid = !existingObj;
1364  if (isValidObject && (
1365  !bExistsAlready || bExistingObjectIsInvalid || (
1366  obj.parentUID() && !existingObj.parentUID()
1367  )
1368  ))
1369  {
1370  m_allObjects[uids[0]] = obj;
1371  // recurse serialization for all members of this object
1372  // (only for struct/class types, noop for primitive types)
1373  SerializationRecursion<T_objectType>::serializeObject(this, heapObject);
1374  }
1375  }
1376 
1456  template<typename T_classType>
1457  void setVersion(const T_classType& nativeObject, Version v) {
1458  const UID uid = UID::from(nativeObject);
1459  Object& obj = m_allObjects[uid];
1460  if (!obj) {
1461  const UIDChain uids = UIDChainResolver<T_classType>(nativeObject);
1462  const DataType type = DataType::dataTypeOf(nativeObject);
1463  obj = Object(uids, type, Object());
1464  }
1465  setVersion(obj, v);
1466  }
1467 
1497  template<typename T_classType>
1498  void setMinVersion(const T_classType& nativeObject, Version v) {
1499  const UID uid = UID::from(nativeObject);
1500  Object& obj = m_allObjects[uid];
1501  if (!obj) {
1502  const UIDChain uids = UIDChainResolver<T_classType>(nativeObject);
1503  const DataType type = DataType::dataTypeOf(nativeObject);
1504  obj = Object(uids, type, Object());
1505  }
1506  setMinVersion(obj, v);
1507  }
1508 
1509  virtual void decode(const RawData& data);
1510  virtual void decode(const uint8_t* data, size_t size);
1511  void clear();
1512  bool isModified() const;
1513  void removeMember(Object& parent, const Member& member);
1514  void remove(const Object& obj);
1515  Object& rootObject();
1516  Object& objectByUID(const UID& uid);
1517  Object& parentObjectOf(const Object& obj);
1518  Object& parentObjectOf(const Member& member);
1519  void setAutoValue(Object& object, String value);
1520  void setIntValue(Object& object, int64_t value);
1521  void setRealValue(Object& object, double value);
1522  void setBoolValue(Object& object, bool value);
1523  void setEnumValue(Object& object, uint64_t value);
1524  void setStringValue(Object& object, String value);
1525  String valueAsString(const Object& object);
1526  int64_t valueAsInt(const Object& object);
1527  double valueAsReal(const Object& object);
1528  bool valueAsBool(const Object& object);
1529  void setVersion(Object& object, Version v);
1530  void setMinVersion(Object& object, Version v);
1531  String name() const;
1532  void setName(String name);
1533  String comment() const;
1534  void setComment(String comment);
1535  time_t timeStampCreated() const;
1536  time_t timeStampModified() const;
1537  tm dateTimeCreated(time_base_t base = LOCAL_TIME) const;
1538  tm dateTimeModified(time_base_t base = LOCAL_TIME) const;
1539  operation_t operation() const;
1540 
1541  protected:
1542  // UID resolver for non-pointer types
1543  template<typename T>
1544  class UIDChainResolver {
1545  public:
1546  UIDChainResolver(const T& data) {
1547  m_uid.push_back(UID::from(data));
1548  }
1549 
1550  operator UIDChain() const { return m_uid; }
1551  UIDChain operator()() const { return m_uid; }
1552  private:
1553  UIDChain m_uid;
1554  };
1555 
1556  // UID resolver for pointer types (of 1st degree)
1557  template<typename T>
1558  class UIDChainResolver<T*> {
1559  public:
1560  UIDChainResolver(const T* const & data) {
1561  const UID uids[2] = {
1562  { (ID) &data, sizeof(data) },
1563  { (ID) data, sizeof(*data) }
1564  };
1565  m_uid.push_back(uids[0]);
1566  m_uid.push_back(uids[1]);
1567  }
1568 
1569  operator UIDChain() const { return m_uid; }
1570  UIDChain operator()() const { return m_uid; }
1571  private:
1572  UIDChain m_uid;
1573  };
1574 
1575  // SerializationRecursion for non-pointer class/struct types.
1576  template<typename T, bool T_isRecursive>
1577  struct SerializationRecursionImpl {
1578  static void serializeObject(Archive* archive, const T& obj) {
1579  const_cast<T&>(obj).serialize(archive);
1580  }
1581  };
1582 
1583  // SerializationRecursion for pointers (of 1st degree) to class/structs.
1584  template<typename T, bool T_isRecursive>
1585  struct SerializationRecursionImpl<T*,T_isRecursive> {
1586  static void serializeObject(Archive* archive, const T*& obj) {
1587  if (!obj) return;
1588  const_cast<T*&>(obj)->serialize(archive);
1589  }
1590  };
1591 
1592  // NOOP SerializationRecursion for primitive types.
1593  template<typename T>
1594  struct SerializationRecursionImpl<T,false> {
1595  static void serializeObject(Archive* /*archive*/, const T& /*obj*/) {}
1596  };
1597 
1598  // SerializationRecursion for pointers (of 1st degree) to primitive types.
1599  template<typename T>
1600  struct SerializationRecursionImpl<T*,false> {
1601  static void serializeObject(Archive* archive, const T* const & obj) {
1602  if (!obj) return;
1603  archive->serializeAnonymousObject(*obj);
1604  }
1605  };
1606 
1607  // NOOP SerializationRecursion for String objects.
1608  template<bool T_isRecursive>
1609  struct SerializationRecursionImpl<String,T_isRecursive> {
1610  static void serializeObject(Archive* archive, const String& obj) {}
1611  };
1612 
1613  // SerializationRecursion for String pointers (of 1st degree).
1614  template<bool T_isRecursive>
1615  struct SerializationRecursionImpl<String*,T_isRecursive> {
1616  static void serializeObject(Archive* archive, const String*& obj) {
1617  if (!obj) return;
1618  archive->serializeAnonymousObject(*obj);
1619  }
1620  };
1621 
1622  // SerializationRecursion for Array<> objects.
1623  template<typename T, bool T_isRecursive>
1624  struct SerializationRecursionImpl<Array<T>,T_isRecursive> {
1625  static void serializeObject(Archive* archive, const Array<T>& obj) {
1626  const UIDChain uids = UIDChainResolver<Array<T>>(obj);
1627  const Object& object = archive->objectByUID(uids[0]);
1628  if (archive->operation() == OPERATION_SERIALIZE) {
1629  for (size_t i = 0; i < obj.size(); ++i) {
1630  archive->serializeHeapMember(
1631  obj, obj[i], ("[" + toString(i) + "]").c_str()
1632  );
1633  }
1634  } else {
1635  const_cast<Object&>(object).m_sync =
1636  [&obj,archive](Object& dstObj, const Object& srcObj,
1637  void* syncer)
1638  {
1639  const size_t n = srcObj.members().size();
1640  const_cast<Array<T>&>(obj).resize(n);
1641  for (size_t i = 0; i < n; ++i) {
1642  archive->serializeHeapMember(
1643  obj, obj[i], ("[" + toString(i) + "]").c_str()
1644  );
1645  }
1646  // updating dstObj required as serializeHeapMember()
1647  // replaced the original object by a new one
1648  dstObj = archive->objectByUID(dstObj.uid());
1649  for (size_t i = 0; i < n; ++i) {
1650  String name = "[" + toString(i) + "]";
1651  Member srcMember = srcObj.memberNamed(name);
1652  Member dstMember = dstObj.memberNamed(name);
1653  ((Syncer*)syncer)->syncMember(dstMember, srcMember);
1654  }
1655  };
1656  }
1657  }
1658  };
1659 
1660  // SerializationRecursion for Array<> pointers (of 1st degree).
1661  template<typename T, bool T_isRecursive>
1662  struct SerializationRecursionImpl<Array<T>*,T_isRecursive> {
1663  static void serializeObject(Archive* archive, const Array<T>*& obj) {
1664  if (!obj) return;
1665  SerializationRecursionImpl<Array<T>,T_isRecursive>::serializeObject(
1666  archive, *obj
1667  );
1668  }
1669  };
1670 
1671  // SerializationRecursion for Set<> objects.
1672  template<typename T, bool T_isRecursive>
1673  struct SerializationRecursionImpl<Set<T>,T_isRecursive> {
1674  static void serializeObject(Archive* archive, const Set<T>& obj) {
1675  const UIDChain uids = UIDChainResolver<Set<T>>(obj);
1676  const Object& object = archive->objectByUID(uids[0]);
1677  if (archive->operation() == OPERATION_SERIALIZE) {
1678  for (const T& key : obj) {
1679  archive->serializeHeapMember(
1680  obj, key, ("[" + toString(key) + "]").c_str()
1681  );
1682  }
1683  } else {
1684  const_cast<Object&>(object).m_sync =
1685  [&obj,archive](Object& dstObj, const Object& srcObj,
1686  void* syncer)
1687  {
1688  const size_t n = srcObj.members().size();
1689  const_cast<Set<T>&>(obj).clear();
1690  for (size_t i = 0; i < n; ++i) {
1691  const Member& member = srcObj.members()[i];
1692  String name = member.name();
1693  // strip brackets from name
1694  if (name.length() < 2 || name[0] != '[' ||
1695  *name.rbegin() != ']') continue;
1696  name = name.substr(1, name.length() - 2);
1697  T key;
1698  const UIDChain uids = UIDChainResolver<T>(key);
1699  const DataType type = DataType::dataTypeOf(key);
1700  Object tmpObj(uids, type, Object());
1701  // set the value of "key" variable by abstraction API
1702  tmpObj.setNativeValueFromString(name);
1703  // only for keys of pointer type: translation of
1704  // memory address from source archive to destination
1705  // archive required, NOOP for all other data types
1706  ((Syncer*)syncer)->translateKey(key);
1707  // insert (translated) key into set
1708  const_cast<Set<T>&>(obj).insert(key);
1709  }
1710  // continue serialization recursion
1711  for (const T& key : obj) {
1712  archive->serializeHeapMember(
1713  obj, key, ("[" + toString(key) + "]").c_str()
1714  );
1715  }
1716  // updating dstObj required as serializeHeapMember()
1717  // replaced the original object by a new one
1718  dstObj = archive->objectByUID(dstObj.uid());
1719  };
1720  }
1721  }
1722  };
1723 
1724  // SerializationRecursion for Set<> pointers (of 1st degree).
1725  template<typename T, bool T_isRecursive>
1726  struct SerializationRecursionImpl<Set<T>*,T_isRecursive> {
1727  static void serializeObject(Archive* archive, const Set<T>*& obj) {
1728  if (!obj) return;
1729  SerializationRecursionImpl<Set<T>,T_isRecursive>::serializeObject(
1730  archive, *obj
1731  );
1732  }
1733  };
1734 
1735  // SerializationRecursion for Map<> objects.
1736  template<typename T_key, typename T_value, bool T_isRecursive>
1737  struct SerializationRecursionImpl<Map<T_key,T_value>,T_isRecursive> {
1738  static void serializeObject(Archive* archive, const Map<T_key,T_value>& obj) {
1739  const UIDChain uids = UIDChainResolver<Map<T_key,T_value>>(obj);
1740  const Object& object = archive->objectByUID(uids[0]);
1741  if (archive->operation() == OPERATION_SERIALIZE) {
1742  for (const auto& it : obj) {
1743  // recurse serialization for map's key ...
1744  SerializationRecursion<T_key>::serializeObject(archive, it.first);
1745  // ... and map's value
1746  archive->serializeHeapMember(
1747  obj, it.second, ("[" + toString(it.first) + "]").c_str()
1748  );
1749  }
1750  } else {
1751  const_cast<Object&>(object).m_sync =
1752  [&obj,archive](Object& dstObj, const Object& srcObj,
1753  void* syncer)
1754  {
1755  const size_t n = srcObj.members().size();
1756  const_cast<Map<T_key,T_value>&>(obj).clear();
1757  // translation is neutral except for keys of pointer type (see comments below)
1758  std::map<String,String> memberNameTranslation;
1759  for (size_t i = 0; i < n; ++i) {
1760  const Member& member = srcObj.members()[i];
1761  String name = member.name();
1762  // strip brackets from name
1763  if (name.length() < 2 || name[0] != '[' ||
1764  *name.rbegin() != ']') continue;
1765  name = name.substr(1, name.length() - 2);
1766  T_key srcKey;
1767  const UIDChain uids = UIDChainResolver<T_key>(srcKey);
1768  const DataType type = DataType::dataTypeOf(srcKey);
1769  Object tmpObj(uids, type, Object());
1770  // set the value of "srcKey" variable by abstraction API
1771  tmpObj.setNativeValueFromString(name);
1772  T_key dstKey = srcKey;
1773  // only for keys of pointer type: translation of
1774  // memory address from source archive to destination
1775  // archive required, NOOP for all other data types
1776  ((Syncer*)syncer)->translateKey(dstKey);
1777  memberNameTranslation[member.name()] = "[" + toString(dstKey) + "]";
1778  // insert (translated) key into the destination map
1779  const_cast<Map<T_key,T_value>&>(obj)[dstKey] = T_value();
1780  }
1781  // continue serialization recursion ...
1782  for (const auto& it : obj) {
1783  // ... for map's key ...
1784  SerializationRecursion<T_key>::serializeObject(archive, it.first);
1785  // ... and map's value
1786  archive->serializeHeapMember(
1787  obj, it.second, ("[" + toString(it.first) + "]").c_str()
1788  );
1789  }
1790  // updating dstObj required as serializeHeapMember()
1791  // replaced the original object by a new one
1792  dstObj = archive->objectByUID(dstObj.uid());
1793  // sync map's values
1794  for (size_t i = 0; i < n; ++i) {
1795  Member srcMember = srcObj.members()[i];
1796  Member dstMember = dstObj.memberNamed(
1797  memberNameTranslation[srcMember.name()]
1798  );
1799  ((Syncer*)syncer)->syncMember(dstMember, srcMember);
1800  }
1801  };
1802  }
1803  }
1804  };
1805 
1806  // SerializationRecursion for Map<> pointers (of 1st degree).
1807  template<typename T_key, typename T_value, bool T_isRecursive>
1808  struct SerializationRecursionImpl<Map<T_key,T_value>*,T_isRecursive> {
1809  static void serializeObject(Archive* archive, const Map<T_key,T_value>*& obj) {
1810  if (!obj) return;
1811  SerializationRecursionImpl<Map<T_key,T_value>,T_isRecursive>::serializeObject(
1812  archive, *obj
1813  );
1814  }
1815  };
1816 
1817  // Automatically handles recursion for class/struct types, while ignoring all primitive types.
1818  template<typename T>
1819  struct SerializationRecursion : SerializationRecursionImpl<T, LIBGIG_IS_CLASS(T)> {
1820  };
1821 
1822  class ObjectPool : public std::map<UID,Object> {
1823  public:
1824  // prevent passing obvious invalid UID values from creating a new pair entry
1825  Object& operator[](const UID& k) {
1826  static Object invalid;
1827  if (!k.isValid()) {
1828  invalid = Object();
1829  return invalid;
1830  }
1831  return std::map<UID,Object>::operator[](k);
1832  }
1833  };
1834 
1835  friend String _encode(const ObjectPool& objects);
1836 
1837  private:
1838  String _encodeRootBlob();
1839  void _popRootBlob(const char*& p, const char* end);
1840  void _popObjectsBlob(const char*& p, const char* end);
1841 
1842  protected:
1882  class Syncer {
1883  public:
1884  Syncer(Archive& dst, Archive& src);
1885  void syncObject(const Object& dst, const Object& src);
1886  void syncPrimitive(const Object& dst, const Object& src);
1887  void syncString(const Object& dst, const Object& src);
1888  void syncArray(const Object& dst, const Object& src);
1889  void syncSet(const Object& dst, const Object& src);
1890  void syncMap(const Object& dst, const Object& src);
1891  void syncPointer(const Object& dst, const Object& src);
1892  void syncMember(const Member& dstMember, const Member& srcMember);
1893 
1894  // Address translation for keys of pointer type.
1895  //
1896  // Translates memory address from source archive, to memory address
1897  // of destination archive. For "strong" pointers memory is allocated
1898  // and the pointed data is synced with data from source archive.
1899  template<typename T>
1900  void translateKey(T*& key) {
1901  const UIDChain uids = UIDChainResolver<T*>(key);
1902  assert(uids.size() == 2);
1903  if (!uids[1])
1904  return; // NULL pointer on source side
1905  const Object& pointedSrcObject = m_src.m_allObjects[uids[1]];
1906  assert(pointedSrcObject);
1907  std::map<UID,UID>::iterator uidRelation = m_counterparts.find(uids[1]);
1908  if (pointedSrcObject.parentUID() || uidRelation != m_counterparts.end()) { // "weak" pointer to object ...
1909  assert(uidRelation != m_counterparts.end());
1910  key = (T*) uidRelation->second.id;
1911  } else { // "strong" pointer to object, allocation required ...
1912  assert(pointedSrcObject.type());
1913  Object pointedDstObject = pointedSrcObject.type().newInstance(&m_dst);
1914  assert(pointedDstObject);
1915  m_dst.m_allObjects[pointedDstObject.uid()] = pointedDstObject;
1916  key = (T*) pointedDstObject.uid().id;
1917 
1918  syncObject(pointedDstObject, pointedSrcObject);
1919  }
1920  }
1921 
1922  // NOOP, no key translation required for any other type
1923  template<typename T>
1924  void translateKey(T& key) {}
1925  protected:
1926  static Member dstMemberMatching(const Object& dstObj, const Object& srcObj, const Member& srcMember);
1927  private:
1928  Archive& m_dst;
1929  Archive& m_src;
1930  std::map<UID,UID> m_counterparts;
1931  };
1932 
1933  virtual void encode();
1934 
1935  ObjectPool m_allObjects;
1936  operation_t m_operation;
1937  UID m_root;
1938  RawData m_rawData;
1939  bool m_isModified;
1940  String m_name;
1941  String m_comment;
1942  time_t m_timeCreated;
1943  time_t m_timeModified;
1944 
1945  friend class DataType;
1946  };
1947 
1948  // Manual registration of native data types by application.
1949  template<typename T>
1951  static_assert(
1952  std::is_default_constructible<T>::value,
1953  "missing default constructor for type: registration of data "
1954  "types is only needed for creating instances of that type at "
1955  "runtime by this framework's reflection API; which in turn "
1956  "requires the type to provide a default constructor."
1957  );
1958  const DataType staticType = DataType::dataType<T>();
1959  assert(staticType);
1960  if (m_allocFns.find(staticType.internalID()) != m_allocFns.end()) return;
1961 
1962  // register lambda function for allocating a new instance of this type
1963  m_allocFns[staticType.internalID()] = [](Archive* archive) -> Object {
1964  T* instance = new T;
1965  Archive::SerializationRecursion<T>::serializeObject(archive, *instance);
1966  const UIDChain uids = Archive::UIDChainResolver<T>(*instance);
1967  Object& obj = archive->objectByUID(uids[0]);
1968  if (obj) return obj;
1969  const DataType type = DataType::dataTypeOf(*instance);
1970  return Object(uids, type, Object());
1971  };
1972  }
1973 
1974  // Automatic self-registration of native data types by this framework.
1975  // (SFINAE variant for types WITH default constructor)
1976  template<typename T, typename std::enable_if<std::is_default_constructible<T>::value, bool>::type>
1977  void DataType::registerNativeDataType(const DataType& rttiType, const T& nativeData) {
1978  if (!rttiType) return;
1979  if (m_allocFns.find(rttiType.internalID()) != m_allocFns.end()) return;
1980 
1981  // Ensure compile-time native data type 'T' matches passed runtime
1982  // native data type 'nativeData', because we can only offer to create
1983  // new instances of native data types by our reflection API if this
1984  // framework is aware about the data type already. Usually this happens
1985  // automatically without applications having to do anything. But
1986  // this only works for types this framework gets in touch with at
1987  // compile-time.
1988  //
1989  // Root problem of all of this: ATM there is no way in C++ to create new
1990  // instances of a type by using RTTI (typeid(), std::type_info, etc.).
1991  // If there is a way in a future C++ version then we can get rid of
1992  // manual type registration altogether. Bur for now we must use new T,
1993  // which is a compile-time only construct.
1994  //
1995  // See the discussion in DataType::registerNativeDataType() for an
1996  // example where manual type registration would be required.
1997  const DataType staticType = DataType::dataType<T>();
1998  if (staticType != rttiType) {
1999  fprintf(stderr, "Serialization Failure: run-time data type '%s' does not match compile-time data type '%s'!\n",
2000  rttiType.asLongDescr().c_str(),
2001  staticType.asLongDescr().c_str());
2002  assert(false && "You may need to explicitly register this run-time "
2003  "data type by either calling "
2004  "DataType::registerNativeType<T>() or using class "
2005  "NativeDataTypeRegistry");
2006  }
2007 
2008  // register lambda function for allocating a new instance of this type
2009  m_allocFns[rttiType.internalID()] = [](Archive* archive) -> Object {
2010  T* instance = new T;
2011  Archive::SerializationRecursion<T>::serializeObject(archive, *instance);
2012  const UIDChain uids = Archive::UIDChainResolver<T>(*instance);
2013  Object& obj = archive->objectByUID(uids[0]);
2014  if (obj) return obj;
2015  const DataType type = DataType::dataTypeOf(*instance);
2016  return Object(uids, type, Object());
2017  };
2018  }
2019 
2020  // Automatic self-registration of native data types by this framework.
2021  // (SFINAE variant for types WITHOUT default constructor)
2022  template<typename T, typename std::enable_if<!std::is_default_constructible<T>::value, bool>::type>
2023  void DataType::registerNativeDataType(const DataType& type, const T& nativeData) {
2024  if (!type) return;
2025  if (m_allocFns.find(type.internalID()) != m_allocFns.end()) return;
2026  m_allocFns[type.internalID()] = [](Archive*) -> Object {
2027  assert(false && "instance not possible: native data type does not have default constructor");
2028  return Object();
2029  };
2030  }
2031 
2036  class Exception {
2037  public:
2038  String Message;
2039 
2040  Exception(String format, ...);
2041  Exception(String format, va_list arg);
2042  void PrintMessage() const;
2043  virtual ~Exception() {}
2044 
2045  protected:
2046  Exception();
2047  static String assemble(String format, va_list arg);
2048  };
2049 
2050 } // namespace Serialization
2051 
2052 #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.
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.
Registrator for native data types.
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 dataType()
Construct a DataType object for the given native C++ 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).
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.
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 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.
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.
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< 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...