libgig  4.5.0.svn11
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 
118 namespace 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 
221  enum time_base_t {
223  UTC_TIME
224  };
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:
351  ID id;
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>
616  public:
618  DataType::registerNativeDataType<T>();
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:
1104  };
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;
1580  void setComment(String comment);
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.
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 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.
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...