libgig  4.5.2.svn9
Serialization.h
1 /***************************************************************************
2  * *
3  * Copyright (C) 2017-2026 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 
166 namespace Serialization {
167 
168  // just symbol prototyping
169  class DataType;
170  class Object;
171  class Member;
172  class Archive;
173  class Exception;
174 
182  typedef std::string String;
183 
196  template<class T>
197  using Array = std::vector<T>;
198 
208  template<class T>
209  using Set = std::set<T>;
210 
229  template<class T_key, class T_value>
230  using Map = std::map<T_key,T_value>;
231 
240  typedef std::vector<uint8_t> RawData;
241 
252  typedef void* ID;
253 
261  typedef uint32_t Version;
262 
268  enum time_base_t {
270  UTC_TIME
271  };
272 
280  template<typename T>
281  bool IsEnum(const T& /*data*/) {
282  #if !HAS_BUILTIN_TYPE_TRAITS
283  return std::tr1::is_enum<T>::value;
284  #else
285  return __is_enum(T);
286  #endif
287  }
288 
299  template<typename T>
300  bool IsUnion(const T& /*data*/) {
301  #if !HAS_BUILTIN_TYPE_TRAITS
302  return false; // without compiler support we cannot distinguish union from class
303  #else
304  return __is_union(T);
305  #endif
306  }
307 
317  template<typename T>
318  bool IsClass(const T& /*data*/) {
319  #if !HAS_BUILTIN_TYPE_TRAITS
320  return std::tr1::__is_union_or_class<T>::value; // without compiler support we cannot distinguish union from class
321  #else
322  return __is_class(T);
323  #endif
324  }
325 
326  /*template<typename T>
327  bool IsTrivial(T data) {
328  return __is_trivial(T);
329  }*/
330 
331  /*template<typename T>
332  bool IsPOD(T data) {
333  return __is_pod(T);
334  }*/
335 
336  /*template<typename T>
337  bool IsArray(const T& data) {
338  return false;
339  }*/
340 
341  /*template<typename T>
342  bool IsArray(const Array<T>& data) {
343  return true;
344  }*/
345 
346  // generalized C-locale guaranteed T to string conversion
347  template<typename T> inline
348  String toString(const T& value) {
349  //TODO: replace by locale-independent, maybe faster std::to_chars() [C++17]
350  std::stringstream ss;
351  ss.imbue(std::locale::classic()); // a.k.a. "C" locale
352  ss << value;
353  return ss.str();
354  }
355 
356  // C-locale guaranteed double to string conversion
357  template<> inline
358  String toString(const double& value) {
359  //TODO: replace by locale-independent, maybe faster std::to_chars() [C++17]
360  std::stringstream ss;
361  ss.imbue(std::locale::classic()); // a.k.a. "C" locale
362  // stringstream has lower precision by default compared to std::to_string()
363  ss.precision(std::numeric_limits<double>::max_digits10);
364  ss << value;
365  return ss.str();
366  }
367 
368  template<typename T> inline
369  String toString(T* ptr) {
370  std::stringstream ss;
371  ss.imbue(std::locale::classic()); // a.k.a. "C" locale
372  ss << "0x" << std::hex << size_t(ptr);
373  return ss.str();
374  }
375 
376  template<> inline
377  String toString(const String& value) {
378  return value;
379  }
380 
381 #if LIBGIG_SERIALIZATION_INTERNAL
382  // prototyping of private internal friend functions
383  template<typename T>
384  static T _primitiveObjectValueToNumber(const Object& obj);
385 #endif // LIBGIG_SERIALIZATION_INTERNAL
386 
403  class DataType {
404  public:
405  DataType();
406  size_t size() const { return m_size; }
407  bool isValid() const;
408  bool isPointer() const;
409  bool isClass() const;
410  bool isPrimitive() const;
411  bool isString() const;
412  bool isChar() const;
413  bool isInteger() const;
414  bool isReal() const;
415  bool isNumber() const;
416  bool isBool() const;
417  bool isEnum() const;
418  bool isArray() const;
419  bool isSet() const;
420  bool isMap() const;
421  bool isSigned() const;
422  operator bool() const { return isValid(); }
423  //bool operator()() const { return isValid(); }
424  bool operator==(const DataType& other) const;
425  bool operator!=(const DataType& other) const;
426  bool operator<(const DataType& other) const;
427  bool operator>(const DataType& other) const;
428  String asLongDescr() const;
429  String baseTypeName() const;
430  String customTypeName(bool demangle = false) const;
431  String customTypeName2(bool demangle = false) const;
432 
448  template<typename T>
449  static DataType dataTypeOf(const T& data, bool registerType = true) {
450  const DataType type = Resolver<T>::resolve(data);
451  if (registerType)
452  registerNativeDataType(type, data);
453  return type;
454  }
455 
469  template<typename T>
470  static DataType dataType(bool registerType = true) {
471  T unused = T();
472  const DataType type = Resolver<T>::resolve(unused);
473  if (registerType)
474  registerNativeDataType(type, unused);
475  return type;
476  }
477 
487  template<typename T>
488  static size_t sizeOf(const T& data) {
489  DataType type = dataTypeOf(data);
490  const auto itNativeType = m_nativeTypes.find(type.internalID());
491  return (itNativeType != m_nativeTypes.end()) ?
492  itNativeType->second.size : sizeof(data);
493  }
494 
530  template<typename T>
531  static void registerNativeDataType();
532 
562  template<typename T>
564  public:
566  DataType::registerNativeDataType<T>();
567  }
568  };
569 
570  protected:
571  DataType(bool isPointer, int size, String baseType,
572  String customType1 = "", String customType2 = "");
573 
574  String internalID() const;
575  Object newInstance(Archive* archive) const;
576 
577  template<typename T, typename std::enable_if<
578  !std::is_pointer<T>::value &&
579  std::is_default_constructible<T>::value, bool>::type = true>
580  static void registerNativeDataType(const DataType& type, const T& nativeData);
581 
582  template<typename T, typename std::enable_if<
583  !std::is_pointer<T>::value &&
584  !std::is_default_constructible<T>::value, bool>::type = true>
585  static void registerNativeDataType(const DataType& type, const T& nativeData);
586 
587  template<typename T, typename std::enable_if<
588  std::is_default_constructible<T>::value, bool>::type = true>
589  static void registerNativeDataType(const DataType& type, const T* const& nativeData);
590 
591  template<typename T, typename std::enable_if<
592  !std::is_default_constructible<T>::value, bool>::type = true>
593  static void registerNativeDataType(const DataType& type, const T* const& nativeData);
594 
595  // DataType resolver for primitive / built-in types
596  template<typename T, bool T_isPointer>
597  struct ResolverBase {
598  static DataType resolve(const T& data);
599  };
600 
601  // DataType resolver for non-pointer types
602  template<typename T>
603  struct Resolver : ResolverBase<T,false> {
604  static DataType resolve(const T& data) {
605  return ResolverBase<T,false>::resolve(data);
606  }
607  };
608 
609  // DataType resolver for pointer types (of 1st degree)
610  template<typename T>
611  struct Resolver<T*> : ResolverBase<T,true> {
612  static DataType resolve(const T* const & data) {
613  return ResolverBase<T,true>::resolve(*data);
614  }
615  };
616 
617  // DataType resolver for non-pointer Array<> container object types.
618  template<typename T>
619  struct Resolver<Array<T>> {
620  static DataType resolve(const Array<T>& data) {
621  const int sz = sizeof(data);
622  T unused = T();
623  return DataType(false, sz, "Array", rawCppTypeNameOf(unused));
624  }
625  };
626 
627  // DataType resolver for Array<> pointer types (of 1st degree).
628  template<typename T>
629  struct Resolver<Array<T>*> {
630  static DataType resolve(const Array<T>*& data) {
631  const int sz = sizeof(*data);
632  T unused = T();
633  return DataType(true, sz, "Array", rawCppTypeNameOf(unused));
634  }
635  };
636 
637  // DataType resolver for non-pointer Set<> container object types.
638  template<typename T>
639  struct Resolver<Set<T>> {
640  static DataType resolve(const Set<T>& data) {
641  const int sz = sizeof(data);
642  T unused = T();
643  return DataType(false, sz, "Set", rawCppTypeNameOf(unused));
644  }
645  };
646 
647  // DataType resolver for Set<> pointer types (of 1st degree).
648  template<typename T>
649  struct Resolver<Set<T>*> {
650  static DataType resolve(const Set<T>*& data) {
651  const int sz = sizeof(*data);
652  T unused = T();
653  return DataType(true, sz, "Set", rawCppTypeNameOf(unused));
654  }
655  };
656 
657  // DataType resolver for non-pointer Map<> container object types.
658  template<typename T_key, typename T_value>
659  struct Resolver<Map<T_key,T_value>> {
660  static DataType resolve(const Map<T_key,T_value>& data) {
661  const int sz = sizeof(data);
662  T_key unused1 = T_key();
663  T_value unused2 = T_value();
664  return DataType(false, sz, "Map", rawCppTypeNameOf(unused1),
665  rawCppTypeNameOf(unused2));
666  }
667  };
668 
669  // DataType resolver for Map<> pointer types (of 1st degree).
670  template<typename T_key, typename T_value>
671  struct Resolver<Map<T_key,T_value>*> {
672  static DataType resolve(const Map<T_key,T_value>*& data) {
673  const int sz = sizeof(*data);
674  T_key unused1 = T_key();
675  T_value unused2 = T_value();
676  return DataType(true, sz, "Map", rawCppTypeNameOf(unused1),
677  rawCppTypeNameOf(unused2));
678  }
679  };
680 
681  // for compile-time known types
682  template<typename T>
683  static String rawCppTypeName() {
684  const std::type_info& type = typeid(T);
685  #if defined _MSC_VER // Microsoft compiler ...
686  String name = type.raw_name();
687  #else // i.e. especially GCC and clang ...
688  String name = type.name();
689  #endif
690  //while (!name.empty() && name[0] >= 0 && name[0] <= 9)
691  // name = name.substr(1);
692  return name;
693  }
694 
695  // for RTTI resolved pointer types
696  template<typename T>
697  static String rawCppTypeNameOf(const T* const & data) {
698  return rawCppTypeName<T*>();
699  }
700 
701  // for RTTI resolved non-pointer types
702  template<typename T>
703  static String rawCppTypeNameOf(const T& data) {
704  const std::type_info& type = typeid(data);
705  #if defined _MSC_VER // Microsoft compiler ...
706  String name = type.raw_name();
707  #else // i.e. especially GCC and clang ...
708  String name = type.name();
709  #endif
710  //while (!name.empty() && name[0] >= 0 && name[0] <= 9)
711  // name = name.substr(1);
712  return name;
713  }
714 
715  private:
716  struct NativeType {
717  size_t size;
718  std::function<Object(Archive*)> allocFn;
719  };
720 
721  int m_size;
722  bool m_isPointer;
723  String m_baseTypeName;
724  String m_customTypeName;
725  String m_customTypeName2;
726 
727  static std::map<String,NativeType> m_nativeTypes;
728 
729  friend class Archive;
730  friend class SrxFormat;
731  friend class SrxJSONDecoder;
732  };
733 
749  class UID {
750  public:
751  ID id;
752  size_t size;
753 
754  bool isValid() const;
755  operator bool() const { return isValid(); }
756  //bool operator()() const { return isValid(); }
757  bool operator==(const UID& other) const { return id == other.id && size == other.size; }
758  bool operator!=(const UID& other) const { return id != other.id || size != other.size; }
759  bool operator<(const UID& other) const { return id < other.id || (id == other.id && size < other.size); }
760  bool operator>(const UID& other) const { return id > other.id || (id == other.id && size > other.size); }
761 
769  template<typename T>
770  static UID from(const T& obj) {
771  return Resolver<T>::resolve(obj);
772  }
773 
774  protected:
775  // UID resolver for non-pointer types
776  template<typename T>
777  struct Resolver {
778  static UID resolve(const T& obj);
779  };
780 
781  // UID resolver for pointer types (of 1st degree)
782  template<typename T>
783  struct Resolver<T*> {
784  static UID resolve(const T* const & obj);
785  };
786  };
787 
793  extern const UID NO_UID;
794 
826  typedef std::vector<UID> UIDChain;
827 
849  class Member {
850  public:
851  Member();
852  UID uid() const;
853  UID parentUID() const;
854  String name() const;
855  ssize_t offset() const;
856  const DataType& type() const;
857  bool isValid() const;
858  operator bool() const { return isValid(); }
859  //bool operator()() const { return isValid(); }
860  bool operator==(const Member& other) const;
861  bool operator!=(const Member& other) const;
862  bool operator<(const Member& other) const;
863  bool operator>(const Member& other) const;
864 
865  protected:
866  Member(String name, UID uid, ssize_t offset, DataType type, const Object& parent);
867  friend class Archive;
868 
869  private:
870  UID m_uid;
871  ssize_t m_offset;
872  String m_name;
873  DataType m_type;
874  UID m_parentUID;
875 
876  friend class SrxFormat;
877  friend class SrxJSONDecoder;
878  };
879 
904  class Object {
905  public:
906  Object();
907  Object(UIDChain uidChain, DataType type, const Object& parent);
908 
909  UID uid(int index = 0) const;
910  const UIDChain& uidChain() const;
911  UID parentUID() const;
912  const DataType& type() const;
913  const RawData& rawData() const;
914  Version version() const;
915  Version minVersion() const;
916  bool isVersionCompatibleTo(const Object& other) const;
917  std::vector<Member>& members();
918  const std::vector<Member>& members() const;
919  Member memberNamed(String name) const;
920  Member memberByUID(const UID& uid) const;
921  std::vector<Member> membersOfType(const DataType& type) const;
922  int sequenceIndexOf(const Member& member) const;
923  bool isValid() const;
924  operator bool() const { return isValid(); }
925  //bool operator()() const { return isValid(); }
926  bool operator==(const Object& other) const;
927  bool operator!=(const Object& other) const;
928  bool operator<(const Object& other) const;
929  bool operator>(const Object& other) const;
930  void setNativeValueFromString(const String& s);
931 
932  protected:
933  void remove(const Member& member);
934  void setVersion(Version v);
935  void setMinVersion(Version v);
936 
937  private:
938  DataType m_type;
939  UIDChain m_uid;
940  UID m_parentUID;
941  Version m_version;
942  Version m_minVersion;
943  RawData m_data;
944  std::vector<Member> m_members;
945  std::function<void(Object& dstObj, const Object& srcObj, void* syncer)> m_sync;
946 
947 #if LIBGIG_SERIALIZATION_INTERNAL
948  template<typename T>
949  friend T _primitiveObjectValueToNumber(const Object& obj);
950 #endif // LIBGIG_SERIALIZATION_INTERNAL
951 
952  friend class Archive;
953  friend class SrxFormat;
954  friend class SrxJSONDecoder;
955  };
956 
1095  class Archive {
1096  public:
1103  };
1104 
1107  enum format_t {
1130  };
1131 
1132  Archive(format_t format = FORMAT_AUTO);
1133  Archive(const RawData& data, format_t format = FORMAT_AUTO);
1134  Archive(const uint8_t* data, size_t size, format_t format = FORMAT_AUTO);
1135  virtual ~Archive();
1136 
1162  template<typename T>
1163  void serialize(const T* obj) {
1164  m_operation = OPERATION_SERIALIZE;
1165  m_allObjects.clear();
1166  m_rawData.clear();
1167  preregisterNativeObject(*obj);
1168  m_root = UID::from(obj);
1169  const_cast<T*>(obj)->serialize(this);
1170  encode();
1171  m_operation = OPERATION_NONE;
1172  }
1173 
1198  template<typename T>
1199  void deserialize(T* obj) {
1200  Archive a;
1201  a.m_operation = m_operation = OPERATION_DESERIALIZE;
1202  a.preregisterNativeObject(*obj);
1203  obj->serialize(&a);
1204  a.m_root = UID::from(obj);
1205  Syncer s(a, *this);
1206  a.m_operation = m_operation = OPERATION_NONE;
1207  }
1208 
1223  template<typename T>
1224  void operator<<(const T& obj) {
1225  serialize(&obj);
1226  }
1227 
1246  template<typename T>
1247  void operator>>(T& obj) {
1248  deserialize(&obj);
1249  }
1250 
1251  const RawData& rawData();
1252  virtual String rawDataFormat() const;
1253 
1310  template<typename T_classType, typename T_memberType>
1311  void serializeMember(const T_classType& nativeObject, const T_memberType& nativeMember, const char* memberName) {
1312  Object& parent = preregisterNativeObject(nativeObject);
1313  const ssize_t offset =
1314  ((const uint8_t*)(const void*)&nativeMember) -
1315  ((const uint8_t*)(const void*)&nativeObject);
1316  const UIDChain uids = UIDChainResolver<T_memberType>(nativeMember);
1317  const DataType type = DataType::dataTypeOf(nativeMember);
1318  const Member member(memberName, uids[0], offset, type, parent);
1319  std::vector<Member>& members = parent.members();
1320  for (const Member& m : members)
1321  assert(m.name() != memberName);
1322  parent.members().push_back(member);
1323  const Object obj(uids, type, parent);
1324  const bool bExistsAlready = m_allObjects.count(uids[0]);
1325  const bool isValidObject = obj;
1326  const Object& existingObj = m_allObjects[uids[0]];
1327  const bool bExistingObjectIsInvalid = !existingObj;
1328  if (isValidObject && (
1329  !bExistsAlready || bExistingObjectIsInvalid || (
1330  obj.parentUID() && !existingObj.parentUID()
1331  )
1332  ))
1333  {
1334  m_allObjects[uids[0]] = obj;
1335  // recurse serialization for all members of this member
1336  // (only for struct/class types, noop for primitive types)
1337  SerializationRecursion<T_memberType>::serializeObject(this, nativeMember);
1338  }
1339  }
1340 
1371  template<typename T_classType, typename T_memberType>
1372  void serializeHeapMember(const T_classType& nativeObject, const T_memberType& heapMember, const char* memberName) {
1373  Object& parent = preregisterNativeObject(nativeObject);
1374  const ssize_t offset = -1; // used for all members on heap
1375  const UIDChain uids = UIDChainResolver<T_memberType>(heapMember);
1376  const DataType type = DataType::dataTypeOf(heapMember);
1377  const Member member(memberName, uids[0], offset, type, parent);
1378  parent.members().push_back(member);
1379  const Object obj(uids, type, parent);
1380  const bool bExistsAlready = m_allObjects.count(uids[0]);
1381  const bool isValidObject = obj;
1382  const Object& existingObj = m_allObjects[uids[0]];
1383  const bool bExistingObjectIsInvalid = !existingObj;
1384  if (isValidObject && (
1385  !bExistsAlready || bExistingObjectIsInvalid || (
1386  obj.parentUID() && !existingObj.parentUID()
1387  )
1388  ))
1389  {
1390  m_allObjects[uids[0]] = obj;
1391  // recurse serialization for all members of this member
1392  // (only for struct/class types, noop for primitive types)
1393  SerializationRecursion<T_memberType>::serializeObject(this, heapMember);
1394  }
1395  }
1396 
1417  template<typename T_objectType>
1418  void serializeAnonymousObject(const T_objectType& heapObject) {
1419  const UIDChain uids = UIDChainResolver<T_objectType>(heapObject);
1420  const DataType type = DataType::dataTypeOf(heapObject);
1421  const Object obj(uids, type, Object());
1422  const bool bExistsAlready = m_allObjects.count(uids[0]);
1423  const bool isValidObject = obj;
1424  const Object& existingObj = m_allObjects[uids[0]];
1425  const bool bExistingObjectIsInvalid = !existingObj;
1426  if (isValidObject && (
1427  !bExistsAlready || bExistingObjectIsInvalid || (
1428  obj.parentUID() && !existingObj.parentUID()
1429  )
1430  ))
1431  {
1432  m_allObjects[uids[0]] = obj;
1433  // recurse serialization for all members of this object
1434  // (only for struct/class types, noop for primitive types)
1435  SerializationRecursion<T_objectType>::serializeObject(this, heapObject);
1436  }
1437  }
1438 
1518  template<typename T_classType>
1519  void setVersion(const T_classType& nativeObject, Version v) {
1520  const UID uid = UID::from(nativeObject);
1521  Object& obj = m_allObjects[uid];
1522  if (!obj) {
1523  const UIDChain uids = UIDChainResolver<T_classType>(nativeObject);
1524  const DataType type = DataType::dataTypeOf(nativeObject);
1525  obj = Object(uids, type, Object());
1526  }
1527  setVersion(obj, v);
1528  }
1529 
1559  template<typename T_classType>
1560  void setMinVersion(const T_classType& nativeObject, Version v) {
1561  const UID uid = UID::from(nativeObject);
1562  Object& obj = m_allObjects[uid];
1563  if (!obj) {
1564  const UIDChain uids = UIDChainResolver<T_classType>(nativeObject);
1565  const DataType type = DataType::dataTypeOf(nativeObject);
1566  obj = Object(uids, type, Object());
1567  }
1568  setMinVersion(obj, v);
1569  }
1570 
1571  virtual void decode(const RawData& data);
1572  virtual void decode(const RawData& data, format_t format);
1573  virtual void decode(const uint8_t* data, size_t size);
1574  virtual void decode(const uint8_t* data, size_t size, format_t format);
1575  void clear();
1576  bool isModified() const;
1577  void removeMember(Object& parent, const Member& member);
1578  void remove(const Object& obj);
1579  Object& rootObject();
1580  Object& objectByUID(const UID& uid);
1581  Object& parentObjectOf(const Object& obj);
1582  Object& parentObjectOf(const Member& member);
1583  void setAutoValue(Object& object, String value);
1584  void setIntValue(Object& object, int64_t value);
1585  void setRealValue(Object& object, double value);
1586  void setCharValue(Object& object, char value);
1587  void setBoolValue(Object& object, bool value);
1588  void setEnumValue(Object& object, uint64_t value);
1589  void setStringValue(Object& object, String value);
1590  String valueAsString(const Object& object);
1591  int64_t valueAsInt(const Object& object);
1592  double valueAsReal(const Object& object);
1593  char valueAsChar(const Object& object);
1594  bool valueAsBool(const Object& object);
1595  void setVersion(Object& object, Version v);
1596  void setMinVersion(Object& object, Version v);
1597  String name() const;
1598  void setName(String name);
1599  String comment() const;
1600  void setComment(String comment);
1601  time_t timeStampCreated() const;
1602  time_t timeStampModified() const;
1603  tm dateTimeCreated(time_base_t base = LOCAL_TIME) const;
1604  tm dateTimeModified(time_base_t base = LOCAL_TIME) const;
1605  operation_t operation() const;
1606 
1607  protected:
1608  Object& objectByBaseUID(const UID& uid);
1609  static String primitiveObjectValueToString(const Object& obj);
1610 
1611  template<typename T_classType>
1612  Object& preregisterNativeObject(const T_classType& nativeObject) {
1613  const UID uid = UID::from(nativeObject);
1614  Object& obj = m_allObjects[uid];
1615  if (!obj) {
1616  const UIDChain uids = UIDChainResolver<T_classType>(nativeObject);
1617  const DataType type = DataType::dataTypeOf(nativeObject);
1618  obj = Object(uids, type, Object());
1619  }
1620  return obj;
1621  }
1622 
1623  // UID resolver for non-pointer types
1624  template<typename T>
1625  class UIDChainResolver {
1626  public:
1627  UIDChainResolver(const T& data) {
1628  m_uid.push_back(UID::from(data));
1629  }
1630 
1631  operator UIDChain() const { return m_uid; }
1632  UIDChain operator()() const { return m_uid; }
1633  private:
1634  UIDChain m_uid;
1635  };
1636 
1637  // UID resolver for pointer types (of 1st degree)
1638  template<typename T>
1639  class UIDChainResolver<T*> {
1640  public:
1641  UIDChainResolver(const T* const & data) {
1642  m_uid.push_back({ (ID) &data, sizeof(data) });
1643  if (data)
1644  m_uid.push_back(UID::from(*data));
1645  else
1646  m_uid.push_back({ (ID) data, sizeof(*data) });
1647  }
1648 
1649  operator UIDChain() const { return m_uid; }
1650  UIDChain operator()() const { return m_uid; }
1651  private:
1652  UIDChain m_uid;
1653  };
1654 
1655  // SerializationRecursion for non-pointer class/struct types.
1656  template<typename T, bool T_isRecursive>
1657  struct SerializationRecursionImpl {
1658  static void serializeObject(Archive* archive, const T& obj) {
1659  const_cast<T&>(obj).serialize(archive);
1660  }
1661  };
1662 
1663  // SerializationRecursion for pointers (of 1st degree) to class/structs.
1664  template<typename T, bool T_isRecursive>
1665  struct SerializationRecursionImpl<T*,T_isRecursive> {
1666  static void serializeObject(Archive* archive, const T*& obj) {
1667  if (!obj) return;
1668  const_cast<T*&>(obj)->serialize(archive);
1669  }
1670  };
1671 
1672  // NOOP SerializationRecursion for primitive types.
1673  template<typename T>
1674  struct SerializationRecursionImpl<T,false> {
1675  static void serializeObject(Archive* /*archive*/, const T& /*obj*/) {}
1676  };
1677 
1678  // SerializationRecursion for pointers (of 1st degree) to primitive types.
1679  template<typename T>
1680  struct SerializationRecursionImpl<T*,false> {
1681  static void serializeObject(Archive* archive, const T* const & obj) {
1682  if (!obj) return;
1683  archive->serializeAnonymousObject(*obj);
1684  }
1685  };
1686 
1687  // NOOP SerializationRecursion for String objects.
1688  template<bool T_isRecursive>
1689  struct SerializationRecursionImpl<String,T_isRecursive> {
1690  static void serializeObject(Archive* archive, const String& obj) {}
1691  };
1692 
1693  // SerializationRecursion for String pointers (of 1st degree).
1694  template<bool T_isRecursive>
1695  struct SerializationRecursionImpl<String*,T_isRecursive> {
1696  static void serializeObject(Archive* archive, const String*& obj) {
1697  if (!obj) return;
1698  archive->serializeAnonymousObject(*obj);
1699  }
1700  };
1701 
1702  // SerializationRecursion for Array<> objects.
1703  template<typename T, bool T_isRecursive>
1704  struct SerializationRecursionImpl<Array<T>,T_isRecursive> {
1705  static void serializeObject(Archive* archive, const Array<T>& obj) {
1706  const UIDChain uids = UIDChainResolver<Array<T>>(obj);
1707  const Object& object = archive->objectByUID(uids[0]);
1708  if (archive->operation() == OPERATION_SERIALIZE) {
1709  for (size_t i = 0; i < obj.size(); ++i) {
1710  archive->serializeHeapMember(
1711  obj, obj[i], ("[" + toString(i) + "]").c_str()
1712  );
1713  }
1714  } else {
1715  const_cast<Object&>(object).m_sync =
1716  [&obj,archive](Object& dstObj, const Object& srcObj,
1717  void* syncer)
1718  {
1719  const size_t n = srcObj.members().size();
1720  const_cast<Array<T>&>(obj).resize(n);
1721  for (size_t i = 0; i < n; ++i) {
1722  archive->serializeHeapMember(
1723  obj, obj[i], ("[" + toString(i) + "]").c_str()
1724  );
1725  }
1726  // updating dstObj required as serializeHeapMember()
1727  // replaced the original object by a new one
1728  dstObj = archive->objectByUID(dstObj.uid());
1729  for (size_t i = 0; i < n; ++i) {
1730  String name = "[" + toString(i) + "]";
1731  Member srcMember = srcObj.memberNamed(name);
1732  Member dstMember = dstObj.memberNamed(name);
1733  ((Syncer*)syncer)->syncMember(dstMember, srcMember);
1734  }
1735  };
1736  }
1737  }
1738  };
1739 
1740  // SerializationRecursion for Array<> pointers (of 1st degree).
1741  template<typename T, bool T_isRecursive>
1742  struct SerializationRecursionImpl<Array<T>*,T_isRecursive> {
1743  static void serializeObject(Archive* archive, const Array<T>*& obj) {
1744  if (!obj) return;
1745  SerializationRecursionImpl<Array<T>,T_isRecursive>::serializeObject(
1746  archive, *obj
1747  );
1748  }
1749  };
1750 
1751  // SerializationRecursion for Set<> objects.
1752  template<typename T, bool T_isRecursive>
1753  struct SerializationRecursionImpl<Set<T>,T_isRecursive> {
1754  static void serializeObject(Archive* archive, const Set<T>& obj) {
1755  const UIDChain uids = UIDChainResolver<Set<T>>(obj);
1756  const Object& object = archive->objectByUID(uids[0]);
1757  if (archive->operation() == OPERATION_SERIALIZE) {
1758  for (const T& key : obj) {
1759  archive->serializeHeapMember(
1760  obj, key, ("[" + toString(key) + "]").c_str()
1761  );
1762  }
1763  } else {
1764  const_cast<Object&>(object).m_sync =
1765  [&obj,archive](Object& dstObj, const Object& srcObj,
1766  void* syncer)
1767  {
1768  const size_t n = srcObj.members().size();
1769  const_cast<Set<T>&>(obj).clear();
1770  for (size_t i = 0; i < n; ++i) {
1771  const Member& member = srcObj.members()[i];
1772  String name = member.name();
1773  // strip brackets from name
1774  if (name.length() < 2 || name[0] != '[' ||
1775  *name.rbegin() != ']') continue;
1776  name = name.substr(1, name.length() - 2);
1777  T key = T();
1778  const UIDChain uids = UIDChainResolver<T>(key);
1779  const DataType type = DataType::dataTypeOf(key);
1780  Object tmpObj(uids, type, Object());
1781  // set the value of "key" variable by abstraction API
1782  tmpObj.setNativeValueFromString(name);
1783  // only for keys of pointer type: translation of
1784  // memory address from source archive to destination
1785  // archive required, NOOP for all other data types
1786  ((Syncer*)syncer)->translateKey(key);
1787  // insert (translated) key into set
1788  const_cast<Set<T>&>(obj).insert(key);
1789  }
1790  // continue serialization recursion
1791  for (const T& key : obj) {
1792  archive->serializeHeapMember(
1793  obj, key, ("[" + toString(key) + "]").c_str()
1794  );
1795  }
1796  // updating dstObj required as serializeHeapMember()
1797  // replaced the original object by a new one
1798  dstObj = archive->objectByUID(dstObj.uid());
1799  };
1800  }
1801  }
1802  };
1803 
1804  // SerializationRecursion for Set<> pointers (of 1st degree).
1805  template<typename T, bool T_isRecursive>
1806  struct SerializationRecursionImpl<Set<T>*,T_isRecursive> {
1807  static void serializeObject(Archive* archive, const Set<T>*& obj) {
1808  if (!obj) return;
1809  SerializationRecursionImpl<Set<T>,T_isRecursive>::serializeObject(
1810  archive, *obj
1811  );
1812  }
1813  };
1814 
1815  // SerializationRecursion for Map<> objects.
1816  template<typename T_key, typename T_value, bool T_isRecursive>
1817  struct SerializationRecursionImpl<Map<T_key,T_value>,T_isRecursive> {
1818  static void serializeObject(Archive* archive, const Map<T_key,T_value>& obj) {
1819  const UIDChain uids = UIDChainResolver<Map<T_key,T_value>>(obj);
1820  const Object& object = archive->objectByUID(uids[0]);
1821  if (archive->operation() == OPERATION_SERIALIZE) {
1822  for (const auto& it : obj) {
1823  // recurse serialization for map's key ...
1824  SerializationRecursion<T_key>::serializeObject(archive, it.first);
1825  // ... and map's value
1826  archive->serializeHeapMember(
1827  obj, it.second, ("[" + toString(it.first) + "]").c_str()
1828  );
1829  }
1830  } else {
1831  const_cast<Object&>(object).m_sync =
1832  [&obj,archive](Object& dstObj, const Object& srcObj,
1833  void* syncer)
1834  {
1835  const size_t n = srcObj.members().size();
1836  const_cast<Map<T_key,T_value>&>(obj).clear();
1837  // translation is neutral except for keys of pointer type (see comments below)
1838  std::map<String,String> memberNameTranslation;
1839  for (size_t i = 0; i < n; ++i) {
1840  const Member& member = srcObj.members()[i];
1841  String name = member.name();
1842  // strip brackets from name
1843  if (name.length() < 2 || name[0] != '[' ||
1844  *name.rbegin() != ']') continue;
1845  name = name.substr(1, name.length() - 2);
1846  T_key srcKey = T_key();
1847  const UIDChain uids = UIDChainResolver<T_key>(srcKey);
1848  const DataType type = DataType::dataTypeOf(srcKey);
1849  Object tmpObj(uids, type, Object());
1850  // set the value of "srcKey" variable by abstraction API
1851  tmpObj.setNativeValueFromString(name);
1852  T_key dstKey = srcKey;
1853  // only for keys of pointer type: translation of
1854  // memory address from source archive to destination
1855  // archive required, NOOP for all other data types
1856  ((Syncer*)syncer)->translateKey(dstKey);
1857  memberNameTranslation[member.name()] = "[" + toString(dstKey) + "]";
1858  // insert (translated) key into the destination map
1859  const_cast<Map<T_key,T_value>&>(obj)[dstKey] = T_value();
1860  }
1861  // continue serialization recursion ...
1862  for (const auto& it : obj) {
1863  // ... for map's key ...
1864  SerializationRecursion<T_key>::serializeObject(archive, it.first);
1865  // ... and map's value
1866  archive->serializeHeapMember(
1867  obj, it.second, ("[" + toString(it.first) + "]").c_str()
1868  );
1869  }
1870  // updating dstObj required as serializeHeapMember()
1871  // replaced the original object by a new one
1872  dstObj = archive->objectByUID(dstObj.uid());
1873  // sync map's values
1874  for (size_t i = 0; i < n; ++i) {
1875  Member srcMember = srcObj.members()[i];
1876  Member dstMember = dstObj.memberNamed(
1877  memberNameTranslation[srcMember.name()]
1878  );
1879  ((Syncer*)syncer)->syncMember(dstMember, srcMember);
1880  }
1881  };
1882  }
1883  }
1884  };
1885 
1886  // SerializationRecursion for Map<> pointers (of 1st degree).
1887  template<typename T_key, typename T_value, bool T_isRecursive>
1888  struct SerializationRecursionImpl<Map<T_key,T_value>*,T_isRecursive> {
1889  static void serializeObject(Archive* archive, const Map<T_key,T_value>*& obj) {
1890  if (!obj) return;
1891  SerializationRecursionImpl<Map<T_key,T_value>,T_isRecursive>::serializeObject(
1892  archive, *obj
1893  );
1894  }
1895  };
1896 
1897  // Automatically handles recursion for class/struct types, while ignoring all primitive types.
1898  template<typename T>
1899  struct SerializationRecursion : SerializationRecursionImpl<T, LIBGIG_IS_CLASS(T)> {
1900  };
1901 
1902  class ObjectPool : public std::map<UID,Object> {
1903  public:
1904  // prevent passing obvious invalid UID values from creating a new pair entry
1905  Object& operator[](const UID& k) {
1906  if (!k.isValid())
1907  return invalidObject();
1908  return std::map<UID,Object>::operator[](k);
1909  }
1910 
1911  static Object& invalidObject() {
1912  static Object invalid;
1913  invalid = Object();
1914  return invalid;
1915  }
1916  };
1917 
1918  protected:
1958  class Syncer {
1959  public:
1960  Syncer(Archive& dst, Archive& src);
1961  void syncObject(const Object& dst, const Object& src);
1962  void syncPrimitive(const Object& dst, const Object& src);
1963  void syncString(const Object& dst, const Object& src);
1964  void syncArray(const Object& dst, const Object& src);
1965  void syncSet(const Object& dst, const Object& src);
1966  void syncMap(const Object& dst, const Object& src);
1967  void syncPointer(const Object& dst, const Object& src);
1968  void syncMember(const Member& dstMember, const Member& srcMember);
1969 
1970  // Address translation for keys of pointer type.
1971  //
1972  // Translates memory address from source archive, to memory address
1973  // of destination archive. For "strong" pointers memory is allocated
1974  // and the pointed data is synced with data from source archive.
1975  template<typename T>
1976  void translateKey(T*& key) {
1977  if (!key) return; // NULL pointer on source side
1978 
1979  // UIDChainResolver can't be used here, since the passed memory
1980  // address is an abstract one that originates from the source
1981  // archive (e.g. potentially even from another machine) and
1982  // UIDChainResolver would then crash on its typeid() operator.
1983  UID uid = { (ID) key, sizeof(*key) };
1984 
1985  const Object& pointedSrcObject = m_src.objectByBaseUID(uid);
1986  assert(pointedSrcObject);
1987  std::map<UID,UID>::iterator uidRelation = m_counterparts.find(uid);
1988  if (pointedSrcObject.parentUID() || uidRelation != m_counterparts.end()) { // "weak" pointer to object ...
1989  assert(uidRelation != m_counterparts.end());
1990  key = (T*) uidRelation->second.id;
1991  } else { // "strong" pointer to object, allocation required ...
1992  assert(pointedSrcObject.type());
1993  Object pointedDstObject = pointedSrcObject.type().newInstance(&m_dst);
1994  assert(pointedDstObject);
1995  m_dst.m_allObjects[pointedDstObject.uid()] = pointedDstObject;
1996  key = (T*) pointedDstObject.uid().id;
1997 
1998  syncObject(pointedDstObject, pointedSrcObject);
1999  }
2000  }
2001 
2002  // NOOP, no key translation required for any other type
2003  template<typename T>
2004  void translateKey(T& key) {}
2005  protected:
2006  static Member dstMemberMatching(const Object& dstObj, const Object& srcObj, const Member& srcMember);
2007  private:
2008  Archive& m_dst;
2009  Archive& m_src;
2010  std::map<UID,UID> m_counterparts;
2011  };
2012 
2013  virtual void encode();
2014  virtual void encode(format_t format);
2015 
2016  ObjectPool m_allObjects;
2017  format_t m_format;
2018  operation_t m_operation;
2019  UID m_root;
2020  RawData m_rawData;
2021  bool m_isModified;
2022  String m_name;
2023  String m_comment;
2024  time_t m_timeCreated;
2025  time_t m_timeModified;
2026 
2027  friend class DataType;
2028  friend class SrxFormat;
2029  friend class SrxJSONEncoder;
2030  friend class SrxJSONDecoder;
2031  };
2032 
2033  // UID resolver implementation for non-pointer types
2034  template<typename T>
2035  UID UID::Resolver<T>::resolve(const T& obj) {
2036  const size_t size = DataType::sizeOf(obj);
2037  const UID uid = { (ID) &obj, size };
2038  return uid;
2039  }
2040 
2041  // UID resolver implementation for pointer types (of 1st degree)
2042  template<typename T>
2043  UID UID::Resolver<T*>::resolve(const T* const & obj) {
2044  const size_t size = DataType::sizeOf(*obj);
2045  const UID uid = { (ID) obj, size };
2046  return uid;
2047  }
2048 
2049  // Manual registration of native data types by application.
2050  template<typename T>
2052  static_assert(
2053  std::is_default_constructible<T>::value,
2054  "missing default constructor for type: registration of data "
2055  "types is only needed for creating instances of that type at "
2056  "runtime by this framework's reflection API; which in turn "
2057  "requires the type to provide a default constructor."
2058  );
2059  const DataType staticType = DataType::dataType<T>(false);
2060  assert(staticType);
2061  const auto itType = m_nativeTypes.find(staticType.internalID());
2062  if (itType != m_nativeTypes.end()) {
2063  assert(itType->second.size >= sizeof(T));
2064  return;
2065  }
2066 
2067  // register lambda function for allocating a new instance of this type
2068  m_nativeTypes[staticType.internalID()] = {
2069  /*.size =*/ sizeof(T),
2070  /*.allocFn =*/ [](Archive* archive) -> Object {
2071  T* instance = new T;
2072  Archive::SerializationRecursion<T>::serializeObject(archive, *instance);
2073  const UIDChain uids = Archive::UIDChainResolver<T>(*instance);
2074  Object& obj = archive->objectByUID(uids[0]);
2075  if (obj) return obj;
2076  const DataType type = DataType::dataTypeOf(*instance);
2077  return Object(uids, type, Object());
2078  }
2079  };
2080  }
2081 
2082  // Automatic self-registration of native data types by this framework.
2083  // (SFINAE variant for types WITH default constructor)
2084  template<typename T, typename std::enable_if<
2085  !std::is_pointer<T>::value &&
2086  std::is_default_constructible<T>::value, bool>::type>
2087  void DataType::registerNativeDataType(const DataType& rttiType, const T& nativeData) {
2088  if (!rttiType) return;
2089  if (m_nativeTypes.find(rttiType.internalID()) != m_nativeTypes.end())
2090  return;
2091 
2092  // Ensure compile-time native data type 'T' matches passed runtime
2093  // native data type 'nativeData', because we can only offer to create
2094  // new instances of native data types by our reflection API if this
2095  // framework is aware about the data type already. Usually this happens
2096  // automatically without applications having to do anything. But
2097  // this only works for types this framework gets in touch with at
2098  // compile-time.
2099  //
2100  // Root problem of all of this: ATM there is no way in C++ to create new
2101  // instances of a type by using RTTI (typeid(), std::type_info, etc.).
2102  // If there is a way in a future C++ version then we can get rid of
2103  // manual type registration altogether. Bur for now we must use new T,
2104  // which is a compile-time only construct.
2105  //
2106  // See the discussion in DataType::registerNativeDataType() for an
2107  // example where manual type registration would be required.
2108  const DataType staticType = DataType::dataType<T>(false);
2109  if (staticType != rttiType) {
2110  fprintf(stderr, "Serialization Failure: run-time data type '%s' does not match compile-time data type '%s'!\n",
2111  rttiType.asLongDescr().c_str(),
2112  staticType.asLongDescr().c_str());
2113  assert(false && "You may need to explicitly register this run-time "
2114  "data type by either calling "
2115  "DataType::registerNativeType<T>() or using class "
2116  "NativeDataTypeRegistry");
2117  }
2118 
2119  // register lambda function for allocating a new instance of this type
2120  m_nativeTypes[rttiType.internalID()] = {
2121  /*.size =*/ sizeof(T),
2122  /*.allocFn =*/ [](Archive* archive) -> Object {
2123  T* instance = new T;
2124  Archive::SerializationRecursion<T>::serializeObject(archive, *instance);
2125  const UIDChain uids = Archive::UIDChainResolver<T>(*instance);
2126  Object& obj = archive->objectByUID(uids[0]);
2127  if (obj) return obj;
2128  const DataType type = DataType::dataTypeOf(*instance);
2129  return Object(uids, type, Object());
2130  }
2131  };
2132  }
2133 
2134  // Automatic self-registration of native data types by this framework.
2135  // (SFINAE variant for types WITHOUT default constructor)
2136  template<typename T, typename std::enable_if<
2137  !std::is_pointer<T>::value &&
2138  !std::is_default_constructible<T>::value, bool>::type>
2139  void DataType::registerNativeDataType(const DataType& type, const T& nativeData) {
2140  if (!type) return;
2141  if (m_nativeTypes.find(type.internalID()) != m_nativeTypes.end())
2142  return;
2143  m_nativeTypes[type.internalID()] = {
2144  /*.size =*/ sizeof(T),
2145  /*.allocFn =*/ [](Archive*) -> Object {
2146  assert(false && "instance not possible: native data type does not have default constructor");
2147  return Object();
2148  }
2149  };
2150  }
2151 
2152  // Automatic self-registration of native data types by this framework.
2153  // (SFINAE variant for pointer types of 1st degree WITH default constructor)
2154  template<typename T, typename std::enable_if<
2155  std::is_default_constructible<T>::value, bool>::type>
2156  void DataType::registerNativeDataType(const DataType& type,
2157  const T* const& nativeData)
2158  {
2159  // register static type
2160  T unused = T();
2161  const DataType staticType = DataType::Resolver<T>::resolve(unused);
2162  registerNativeDataType(staticType, unused);
2163  // register rtti type
2164  if (!nativeData) return;
2165  const DataType rttiType = DataType::Resolver<T>::resolve(*nativeData);
2166  registerNativeDataType(rttiType, *nativeData);
2167  }
2168 
2169  // Automatic self-registration of native data types by this framework.
2170  // (SFINAE variant for pointer types of 1st degree WITHOUT default constructor)
2171  template<typename T, typename std::enable_if<
2172  !std::is_default_constructible<T>::value, bool>::type>
2173  void DataType::registerNativeDataType(const DataType& type,
2174  const T* const& nativeData)
2175  {
2176  // register rtti type only
2177  if (!nativeData) return;
2178  const DataType nonPointerType = DataType::Resolver<T>::resolve(*nativeData);
2179  registerNativeDataType(nonPointerType, *nativeData);
2180  }
2181 
2182  // DataType resolver implementation for primitive / built-in types
2183  template<typename T, bool T_isPointer>
2184  DataType DataType::ResolverBase<T,T_isPointer>::resolve(const T& data) {
2185  // for pointers we must stick to the compile-time declared type
2186  // of pointer to prevent potential type mismatches caused by
2187  // RTTI in a polymorphic scenario
2188  const std::type_info& type = (T_isPointer) ? typeid(T) : typeid(data);
2189  const int sz = sizeof(data);
2190 
2191  // for primitive types we are using our own type names instead of
2192  // using std:::type_info::name(), because the precise output of the
2193  // latter may vary between compilers
2194  if (type == typeid(char))
2195  // special case: C++ defines "char" to be neither type
2196  // equivalent to "signed char" nor to "unsigned char",
2197  // because e.g. char's signedness is implementation specific
2198  return DataType(T_isPointer, sz, "char");
2199  if (type == typeid(int8_t)) return DataType(T_isPointer, sz, "int8");
2200  if (type == typeid(uint8_t)) return DataType(T_isPointer, sz, "uint8");
2201  if (type == typeid(int16_t)) return DataType(T_isPointer, sz, "int16");
2202  if (type == typeid(uint16_t)) return DataType(T_isPointer, sz, "uint16");
2203  if (type == typeid(int32_t)) return DataType(T_isPointer, sz, "int32");
2204  if (type == typeid(uint32_t)) return DataType(T_isPointer, sz, "uint32");
2205  if (type == typeid(int64_t)) return DataType(T_isPointer, sz, "int64");
2206  if (type == typeid(uint64_t)) return DataType(T_isPointer, sz, "uint64");
2207  // CAUTION: depending on the system, "long" or "int" types may not
2208  // already been covered by the typedefs above
2209  if (type == typeid(long) || type == typeid(int)) {
2210  if (sz == 1) return DataType(T_isPointer, sz, "int8");
2211  if (sz == 2) return DataType(T_isPointer, sz, "int16");
2212  if (sz == 4) return DataType(T_isPointer, sz, "int32");
2213  if (sz == 8) return DataType(T_isPointer, sz, "int64");
2214  else assert(false /* unknown int / long size */);
2215  }
2216  if (type == typeid(unsigned long) || type == typeid(unsigned int)) {
2217  if (sz == 1) return DataType(T_isPointer, sz, "uint8");
2218  if (sz == 2) return DataType(T_isPointer, sz, "uint16");
2219  if (sz == 4) return DataType(T_isPointer, sz, "uint32");
2220  if (sz == 8) return DataType(T_isPointer, sz, "uint64");
2221  else assert(false /* unknown unsigned int / unsigned long size */);
2222  }
2223  if (type == typeid(bool)) return DataType(T_isPointer, sz, "bool");
2224  if (type == typeid(float)) return DataType(T_isPointer, sz, "real32");
2225  if (type == typeid(double)) return DataType(T_isPointer, sz, "real64");
2226  if (type == typeid(String)) return DataType(T_isPointer, sz, "String");
2227 
2228  // for pointers we must stick to pointer's compile-time declared
2229  // type and not use RTTI for the pointed object, because the
2230  // latter would easily create a type mismatch conflict for
2231  // pointers and objects in a polymorphic scenario, because the
2232  // pointer might have been declared with a base class type,
2233  // while actually assigned objects to these pointers might be of
2234  // any other derived class and RTTI would resolve the latter
2235  const String rawCppName =
2236  (T_isPointer) ? rawCppTypeName<T>()
2237  : rawCppTypeNameOf(data);
2238 
2239  if (IsEnum(data)) return DataType(T_isPointer, sz, "enum", rawCppName);
2240  if (IsUnion(data)) return DataType(T_isPointer, sz, "union", rawCppName);
2241  if (IsClass(data)) return DataType(T_isPointer, sz, "class", rawCppName);
2242 
2243  assert(false /* unknown data type*/);
2244  return DataType();
2245  }
2246 
2251  class Exception {
2252  public:
2253  String Message;
2254 
2255  Exception(String format, ...);
2256  Exception(String format, va_list arg);
2257  void PrintMessage() const;
2258  virtual ~Exception() {}
2259 
2260  protected:
2261  Exception();
2262  static String assemble(String format, va_list arg);
2263  };
2264 
2265 } // namespace Serialization
2266 
2267 #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 setCharValue(Object &object, char value)
Set new char value for given character object.
char valueAsChar(const Object &object)
Get char value of 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.
Archive(format_t format=FORMAT_AUTO)
Create an "empty" archive.
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.
format_t
Encoding format of serialized data stream.
@ FORMAT_AUTO
Automatically handle the encoding format:
@ FORMAT_SRX_JSON
Use and expect "Srx-JSON" encoding format (user-friendly to read and modify).
@ FORMAT_SRX
Use and expect "Srx" encoding format (simple, reliable, fast).
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 isNumber() const
Whether this is a numeric C/C++ data 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.
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.
bool isChar() const
Whether this is a character C/C++ data type.
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.
C++ 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...