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 ObjectPool;
174  class Exception;
175 
183  typedef std::string String;
184 
197  template<class T>
198  using Array = std::vector<T>;
199 
209  template<class T>
210  using Set = std::set<T>;
211 
230  template<class T_key, class T_value>
231  using Map = std::map<T_key,T_value>;
232 
241  typedef std::vector<uint8_t> RawData;
242 
253  typedef void* ID;
254 
262  typedef uint32_t Version;
263 
269  enum time_base_t {
271  UTC_TIME
272  };
273 
281  template<typename T>
282  bool IsEnum(const T& /*data*/) {
283  #if !HAS_BUILTIN_TYPE_TRAITS
284  return std::tr1::is_enum<T>::value;
285  #else
286  return __is_enum(T);
287  #endif
288  }
289 
300  template<typename T>
301  bool IsUnion(const T& /*data*/) {
302  #if !HAS_BUILTIN_TYPE_TRAITS
303  return false; // without compiler support we cannot distinguish union from class
304  #else
305  return __is_union(T);
306  #endif
307  }
308 
318  template<typename T>
319  bool IsClass(const T& /*data*/) {
320  #if !HAS_BUILTIN_TYPE_TRAITS
321  return std::tr1::__is_union_or_class<T>::value; // without compiler support we cannot distinguish union from class
322  #else
323  return __is_class(T);
324  #endif
325  }
326 
327  /*template<typename T>
328  bool IsTrivial(T data) {
329  return __is_trivial(T);
330  }*/
331 
332  /*template<typename T>
333  bool IsPOD(T data) {
334  return __is_pod(T);
335  }*/
336 
337  /*template<typename T>
338  bool IsArray(const T& data) {
339  return false;
340  }*/
341 
342  /*template<typename T>
343  bool IsArray(const Array<T>& data) {
344  return true;
345  }*/
346 
347  // generalized C-locale guaranteed T to string conversion
348  template<typename T> inline
349  String toString(const T& value) {
350  //TODO: replace by locale-independent, maybe faster std::to_chars() [C++17]
351  std::stringstream ss;
352  ss.imbue(std::locale::classic()); // a.k.a. "C" locale
353  ss << value;
354  return ss.str();
355  }
356 
357  // C-locale guaranteed double to string conversion
358  template<> inline
359  String toString(const double& value) {
360  //TODO: replace by locale-independent, maybe faster std::to_chars() [C++17]
361  std::stringstream ss;
362  ss.imbue(std::locale::classic()); // a.k.a. "C" locale
363  // stringstream has lower precision by default compared to std::to_string()
364  ss.precision(std::numeric_limits<double>::max_digits10);
365  ss << value;
366  return ss.str();
367  }
368 
369  template<typename T> inline
370  String toString(T* ptr) {
371  std::stringstream ss;
372  ss.imbue(std::locale::classic()); // a.k.a. "C" locale
373  ss << "0x" << std::hex << size_t(ptr);
374  return ss.str();
375  }
376 
377  template<> inline
378  String toString(const String& value) {
379  return value;
380  }
381 
382 #if LIBGIG_SERIALIZATION_INTERNAL
383  // prototyping of private internal friend functions
384  template<typename T>
385  static T _primitiveObjectValueToNumber(const Object& obj);
386 #endif // LIBGIG_SERIALIZATION_INTERNAL
387 
404  class DataType {
405  public:
406  DataType();
407  size_t size() const { return m_size; }
408  bool isValid() const;
409  bool isPointer() const;
410  bool isClass() const;
411  bool isPrimitive() const;
412  bool isString() const;
413  bool isChar() const;
414  bool isInteger() const;
415  bool isReal() const;
416  bool isNumber() const;
417  bool isBool() const;
418  bool isEnum() const;
419  bool isArray() const;
420  bool isSet() const;
421  bool isMap() const;
422  bool isSigned() const;
423  operator bool() const { return isValid(); }
424  //bool operator()() const { return isValid(); }
425  bool operator==(const DataType& other) const;
426  bool operator!=(const DataType& other) const;
427  bool operator<(const DataType& other) const;
428  bool operator>(const DataType& other) const;
429  String asLongDescr() const;
430  String baseTypeName() const;
431  String customTypeName(bool demangle = false) const;
432  String customTypeName2(bool demangle = false) const;
433 
449  template<typename T>
450  static DataType dataTypeOf(const T& data, bool registerType = true) {
451  const DataType type = Resolver<T>::resolve(data);
452  if (registerType)
453  registerNativeDataType(type, data);
454  return type;
455  }
456 
470  template<typename T>
471  static DataType dataType(bool registerType = true) {
472  T unused = T();
473  const DataType type = Resolver<T>::resolve(unused);
474  if (registerType)
475  registerNativeDataType(type, unused);
476  return type;
477  }
478 
488  template<typename T>
489  static size_t sizeOf(const T& data) {
490  DataType type = dataTypeOf(data);
491  const auto itNativeType = m_nativeTypes.find(type.internalID());
492  return (itNativeType != m_nativeTypes.end()) ?
493  itNativeType->second.size : sizeof(data);
494  }
495 
531  template<typename T>
532  static void registerNativeDataType();
533 
563  template<typename T>
565  public:
567  DataType::registerNativeDataType<T>();
568  }
569  };
570 
571  protected:
572  DataType(bool isPointer, int size, String baseType,
573  String customType1 = "", String customType2 = "");
574 
575  String internalID() const;
576  Object newInstance(Archive* archive) const;
577 
578  template<typename T, typename std::enable_if<std::is_default_constructible<T>::value, bool>::type = true>
579  static void registerNativeDataType(const DataType& type, const T& nativeData);
580 
581  template<typename T, typename std::enable_if<!std::is_default_constructible<T>::value, bool>::type = true>
582  static void registerNativeDataType(const DataType& type, const T& nativeData);
583 
584  // DataType resolver for primitive / built-in types
585  template<typename T, bool T_isPointer>
586  struct ResolverBase {
587  static DataType resolve(const T& data);
588  };
589 
590  // DataType resolver for non-pointer types
591  template<typename T>
592  struct Resolver : ResolverBase<T,false> {
593  static DataType resolve(const T& data) {
594  return ResolverBase<T,false>::resolve(data);
595  }
596  };
597 
598  // DataType resolver for pointer types (of 1st degree)
599  template<typename T>
600  struct Resolver<T*> : ResolverBase<T,true> {
601  static DataType resolve(const T* const & data) {
602  return ResolverBase<T,true>::resolve(*data);
603  }
604  };
605 
606  // DataType resolver for non-pointer Array<> container object types.
607  template<typename T>
608  struct Resolver<Array<T>> {
609  static DataType resolve(const Array<T>& data) {
610  const int sz = sizeof(data);
611  T unused = T();
612  return DataType(false, sz, "Array", rawCppTypeNameOf(unused));
613  }
614  };
615 
616  // DataType resolver for Array<> pointer types (of 1st degree).
617  template<typename T>
618  struct Resolver<Array<T>*> {
619  static DataType resolve(const Array<T>*& data) {
620  const int sz = sizeof(*data);
621  T unused = T();
622  return DataType(true, sz, "Array", rawCppTypeNameOf(unused));
623  }
624  };
625 
626  // DataType resolver for non-pointer Set<> container object types.
627  template<typename T>
628  struct Resolver<Set<T>> {
629  static DataType resolve(const Set<T>& data) {
630  const int sz = sizeof(data);
631  T unused = T();
632  return DataType(false, sz, "Set", rawCppTypeNameOf(unused));
633  }
634  };
635 
636  // DataType resolver for Set<> pointer types (of 1st degree).
637  template<typename T>
638  struct Resolver<Set<T>*> {
639  static DataType resolve(const Set<T>*& data) {
640  const int sz = sizeof(*data);
641  T unused = T();
642  return DataType(true, sz, "Set", rawCppTypeNameOf(unused));
643  }
644  };
645 
646  // DataType resolver for non-pointer Map<> container object types.
647  template<typename T_key, typename T_value>
648  struct Resolver<Map<T_key,T_value>> {
649  static DataType resolve(const Map<T_key,T_value>& data) {
650  const int sz = sizeof(data);
651  T_key unused1 = T_key();
652  T_value unused2 = T_value();
653  return DataType(false, sz, "Map", rawCppTypeNameOf(unused1),
654  rawCppTypeNameOf(unused2));
655  }
656  };
657 
658  // DataType resolver for Map<> pointer types (of 1st degree).
659  template<typename T_key, typename T_value>
660  struct Resolver<Map<T_key,T_value>*> {
661  static DataType resolve(const Map<T_key,T_value>*& data) {
662  const int sz = sizeof(*data);
663  T_key unused1 = T_key();
664  T_value unused2 = T_value();
665  return DataType(true, sz, "Map", rawCppTypeNameOf(unused1),
666  rawCppTypeNameOf(unused2));
667  }
668  };
669 
670  // for compile-time known types
671  template<typename T>
672  static String rawCppTypeName() {
673  const std::type_info& type = typeid(T);
674  #if defined _MSC_VER // Microsoft compiler ...
675  String name = type.raw_name();
676  #else // i.e. especially GCC and clang ...
677  String name = type.name();
678  #endif
679  //while (!name.empty() && name[0] >= 0 && name[0] <= 9)
680  // name = name.substr(1);
681  return name;
682  }
683 
684  // for RTTI resolved pointer types
685  template<typename T>
686  static String rawCppTypeNameOf(const T* const & data) {
687  return rawCppTypeName<T*>();
688  }
689 
690  // for RTTI resolved non-pointer types
691  template<typename T>
692  static String rawCppTypeNameOf(const T& data) {
693  const std::type_info& type = typeid(data);
694  #if defined _MSC_VER // Microsoft compiler ...
695  String name = type.raw_name();
696  #else // i.e. especially GCC and clang ...
697  String name = type.name();
698  #endif
699  //while (!name.empty() && name[0] >= 0 && name[0] <= 9)
700  // name = name.substr(1);
701  return name;
702  }
703 
704  private:
705  struct NativeType {
706  size_t size;
707  std::function<Object(Archive*)> allocFn;
708  };
709 
710  int m_size;
711  bool m_isPointer;
712  String m_baseTypeName;
713  String m_customTypeName;
714  String m_customTypeName2;
715 
716  static std::map<String,NativeType> m_nativeTypes;
717 
718  friend class Archive;
719  friend class SrxFormat;
720  friend class SrxJSONDecoder;
721  };
722 
738  class UID {
739  public:
740  ID id;
741  size_t size;
742 
743  bool isValid() const;
744  operator bool() const { return isValid(); }
745  //bool operator()() const { return isValid(); }
746  bool operator==(const UID& other) const { return id == other.id && size == other.size; }
747  bool operator!=(const UID& other) const { return id != other.id || size != other.size; }
748  bool operator<(const UID& other) const { return id < other.id || (id == other.id && size < other.size); }
749  bool operator>(const UID& other) const { return id > other.id || (id == other.id && size > other.size); }
750 
758  template<typename T>
759  static UID from(const T& obj) {
760  return Resolver<T>::resolve(obj);
761  }
762 
763  protected:
764  // UID resolver for non-pointer types
765  template<typename T>
766  struct Resolver {
767  static UID resolve(const T& obj);
768  };
769 
770  // UID resolver for pointer types (of 1st degree)
771  template<typename T>
772  struct Resolver<T*> {
773  static UID resolve(const T* const & obj);
774  };
775  };
776 
782  extern const UID NO_UID;
783 
815  typedef std::vector<UID> UIDChain;
816 
838  class Member {
839  public:
840  Member();
841  UID uid() const;
842  UID parentUID() const;
843  String name() const;
844  ssize_t offset() const;
845  const DataType& type() const;
846  bool isValid() const;
847  operator bool() const { return isValid(); }
848  //bool operator()() const { return isValid(); }
849  bool operator==(const Member& other) const;
850  bool operator!=(const Member& other) const;
851  bool operator<(const Member& other) const;
852  bool operator>(const Member& other) const;
853 
854  protected:
855  Member(String name, UID uid, ssize_t offset, DataType type, const Object& parent);
856  friend class Archive;
857 
858  private:
859  UID m_uid;
860  ssize_t m_offset;
861  String m_name;
862  DataType m_type;
863  UID m_parentUID;
864 
865  friend class SrxFormat;
866  friend class SrxJSONDecoder;
867  };
868 
893  class Object {
894  public:
895  Object();
896  Object(UIDChain uidChain, DataType type, const Object& parent);
897 
898  UID uid(int index = 0) const;
899  const UIDChain& uidChain() const;
900  UID parentUID() const;
901  const DataType& type() const;
902  const RawData& rawData() const;
903  Version version() const;
904  Version minVersion() const;
905  bool isVersionCompatibleTo(const Object& other) const;
906  std::vector<Member>& members();
907  const std::vector<Member>& members() const;
908  Member memberNamed(String name) const;
909  Member memberByUID(const UID& uid) const;
910  std::vector<Member> membersOfType(const DataType& type) const;
911  int sequenceIndexOf(const Member& member) const;
912  bool isValid() const;
913  operator bool() const { return isValid(); }
914  //bool operator()() const { return isValid(); }
915  bool operator==(const Object& other) const;
916  bool operator!=(const Object& other) const;
917  bool operator<(const Object& other) const;
918  bool operator>(const Object& other) const;
919  void setNativeValueFromString(const String& s);
920 
921  protected:
922  void remove(const Member& member);
923  void setVersion(Version v);
924  void setMinVersion(Version v);
925 
926  private:
927  DataType m_type;
928  UIDChain m_uid;
929  UID m_parentUID;
930  Version m_version;
931  Version m_minVersion;
932  RawData m_data;
933  std::vector<Member> m_members;
934  std::function<void(Object& dstObj, const Object& srcObj, void* syncer)> m_sync;
935 
936 #if LIBGIG_SERIALIZATION_INTERNAL
937  template<typename T>
938  friend T _primitiveObjectValueToNumber(const Object& obj);
939 #endif // LIBGIG_SERIALIZATION_INTERNAL
940 
941  friend class Archive;
942  friend class SrxFormat;
943  friend class SrxJSONDecoder;
944  };
945 
1084  class Archive {
1085  public:
1092  };
1093 
1096  enum format_t {
1119  };
1120 
1121  Archive(format_t format = FORMAT_AUTO);
1122  Archive(const RawData& data, format_t format = FORMAT_AUTO);
1123  Archive(const uint8_t* data, size_t size, format_t format = FORMAT_AUTO);
1124  virtual ~Archive();
1125 
1151  template<typename T>
1152  void serialize(const T* obj) {
1153  m_operation = OPERATION_SERIALIZE;
1154  m_allObjects.clear();
1155  m_rawData.clear();
1156  preregisterNativeObject(*obj);
1157  m_root = UID::from(obj);
1158  const_cast<T*>(obj)->serialize(this);
1159  encode();
1160  m_operation = OPERATION_NONE;
1161  }
1162 
1187  template<typename T>
1188  void deserialize(T* obj) {
1189  Archive a;
1190  a.m_operation = m_operation = OPERATION_DESERIALIZE;
1191  a.preregisterNativeObject(*obj);
1192  obj->serialize(&a);
1193  a.m_root = UID::from(obj);
1194  Syncer s(a, *this);
1195  a.m_operation = m_operation = OPERATION_NONE;
1196  }
1197 
1212  template<typename T>
1213  void operator<<(const T& obj) {
1214  serialize(&obj);
1215  }
1216 
1235  template<typename T>
1236  void operator>>(T& obj) {
1237  deserialize(&obj);
1238  }
1239 
1240  const RawData& rawData();
1241  virtual String rawDataFormat() const;
1242 
1299  template<typename T_classType, typename T_memberType>
1300  void serializeMember(const T_classType& nativeObject, const T_memberType& nativeMember, const char* memberName) {
1301  Object& parent = preregisterNativeObject(nativeObject);
1302  const ssize_t offset =
1303  ((const uint8_t*)(const void*)&nativeMember) -
1304  ((const uint8_t*)(const void*)&nativeObject);
1305  const UIDChain uids = UIDChainResolver<T_memberType>(nativeMember);
1306  const DataType type = DataType::dataTypeOf(nativeMember);
1307  const Member member(memberName, uids[0], offset, type, parent);
1308  std::vector<Member>& members = parent.members();
1309  for (const Member& m : members)
1310  assert(m.name() != memberName);
1311  parent.members().push_back(member);
1312  const Object obj(uids, type, parent);
1313  const bool bExistsAlready = m_allObjects.count(uids[0]);
1314  const bool isValidObject = obj;
1315  const Object& existingObj = m_allObjects[uids[0]];
1316  const bool bExistingObjectIsInvalid = !existingObj;
1317  if (isValidObject && (
1318  !bExistsAlready || bExistingObjectIsInvalid || (
1319  obj.parentUID() && !existingObj.parentUID()
1320  )
1321  ))
1322  {
1323  m_allObjects[uids[0]] = obj;
1324  // recurse serialization for all members of this member
1325  // (only for struct/class types, noop for primitive types)
1326  SerializationRecursion<T_memberType>::serializeObject(this, nativeMember);
1327  }
1328  }
1329 
1360  template<typename T_classType, typename T_memberType>
1361  void serializeHeapMember(const T_classType& nativeObject, const T_memberType& heapMember, const char* memberName) {
1362  Object& parent = preregisterNativeObject(nativeObject);
1363  const ssize_t offset = -1; // used for all members on heap
1364  const UIDChain uids = UIDChainResolver<T_memberType>(heapMember);
1365  const DataType type = DataType::dataTypeOf(heapMember);
1366  const Member member(memberName, uids[0], offset, type, parent);
1367  parent.members().push_back(member);
1368  const Object obj(uids, type, parent);
1369  const bool bExistsAlready = m_allObjects.count(uids[0]);
1370  const bool isValidObject = obj;
1371  const Object& existingObj = m_allObjects[uids[0]];
1372  const bool bExistingObjectIsInvalid = !existingObj;
1373  if (isValidObject && (
1374  !bExistsAlready || bExistingObjectIsInvalid || (
1375  obj.parentUID() && !existingObj.parentUID()
1376  )
1377  ))
1378  {
1379  m_allObjects[uids[0]] = obj;
1380  // recurse serialization for all members of this member
1381  // (only for struct/class types, noop for primitive types)
1382  SerializationRecursion<T_memberType>::serializeObject(this, heapMember);
1383  }
1384  }
1385 
1406  template<typename T_objectType>
1407  void serializeAnonymousObject(const T_objectType& heapObject) {
1408  const UIDChain uids = UIDChainResolver<T_objectType>(heapObject);
1409  const DataType type = DataType::dataTypeOf(heapObject);
1410  const Object obj(uids, type, Object());
1411  const bool bExistsAlready = m_allObjects.count(uids[0]);
1412  const bool isValidObject = obj;
1413  const Object& existingObj = m_allObjects[uids[0]];
1414  const bool bExistingObjectIsInvalid = !existingObj;
1415  if (isValidObject && (
1416  !bExistsAlready || bExistingObjectIsInvalid || (
1417  obj.parentUID() && !existingObj.parentUID()
1418  )
1419  ))
1420  {
1421  m_allObjects[uids[0]] = obj;
1422  // recurse serialization for all members of this object
1423  // (only for struct/class types, noop for primitive types)
1424  SerializationRecursion<T_objectType>::serializeObject(this, heapObject);
1425  }
1426  }
1427 
1507  template<typename T_classType>
1508  void setVersion(const T_classType& nativeObject, Version v) {
1509  const UID uid = UID::from(nativeObject);
1510  Object& obj = m_allObjects[uid];
1511  if (!obj) {
1512  const UIDChain uids = UIDChainResolver<T_classType>(nativeObject);
1513  const DataType type = DataType::dataTypeOf(nativeObject);
1514  obj = Object(uids, type, Object());
1515  }
1516  setVersion(obj, v);
1517  }
1518 
1548  template<typename T_classType>
1549  void setMinVersion(const T_classType& nativeObject, Version v) {
1550  const UID uid = UID::from(nativeObject);
1551  Object& obj = m_allObjects[uid];
1552  if (!obj) {
1553  const UIDChain uids = UIDChainResolver<T_classType>(nativeObject);
1554  const DataType type = DataType::dataTypeOf(nativeObject);
1555  obj = Object(uids, type, Object());
1556  }
1557  setMinVersion(obj, v);
1558  }
1559 
1560  virtual void decode(const RawData& data);
1561  virtual void decode(const RawData& data, format_t format);
1562  virtual void decode(const uint8_t* data, size_t size);
1563  virtual void decode(const uint8_t* data, size_t size, format_t format);
1564  void clear();
1565  bool isModified() const;
1566  void removeMember(Object& parent, const Member& member);
1567  void remove(const Object& obj);
1568  Object& rootObject();
1569  Object& objectByUID(const UID& uid);
1570  Object& parentObjectOf(const Object& obj);
1571  Object& parentObjectOf(const Member& member);
1572  void setAutoValue(Object& object, String value);
1573  void setIntValue(Object& object, int64_t value);
1574  void setRealValue(Object& object, double value);
1575  void setCharValue(Object& object, char value);
1576  void setBoolValue(Object& object, bool value);
1577  void setEnumValue(Object& object, uint64_t value);
1578  void setStringValue(Object& object, String value);
1579  String valueAsString(const Object& object);
1580  int64_t valueAsInt(const Object& object);
1581  double valueAsReal(const Object& object);
1582  char valueAsChar(const Object& object);
1583  bool valueAsBool(const Object& object);
1584  void setVersion(Object& object, Version v);
1585  void setMinVersion(Object& object, Version v);
1586  String name() const;
1587  void setName(String name);
1588  String comment() const;
1589  void setComment(String comment);
1590  time_t timeStampCreated() const;
1591  time_t timeStampModified() const;
1592  tm dateTimeCreated(time_base_t base = LOCAL_TIME) const;
1593  tm dateTimeModified(time_base_t base = LOCAL_TIME) const;
1594  operation_t operation() const;
1595 
1596  protected:
1597  Object& objectByBaseUID(const UID& uid);
1598  static String primitiveObjectValueToString(const Object& obj);
1599 
1600  template<typename T_classType>
1601  Object& preregisterNativeObject(const T_classType& nativeObject) {
1602  const UID uid = UID::from(nativeObject);
1603  Object& obj = m_allObjects[uid];
1604  if (!obj) {
1605  const UIDChain uids = UIDChainResolver<T_classType>(nativeObject);
1606  const DataType type = DataType::dataTypeOf(nativeObject);
1607  obj = Object(uids, type, Object());
1608  }
1609  return obj;
1610  }
1611 
1612  // UID resolver for non-pointer types
1613  template<typename T>
1614  class UIDChainResolver {
1615  public:
1616  UIDChainResolver(const T& data) {
1617  m_uid.push_back(UID::from(data));
1618  }
1619 
1620  operator UIDChain() const { return m_uid; }
1621  UIDChain operator()() const { return m_uid; }
1622  private:
1623  UIDChain m_uid;
1624  };
1625 
1626  // UID resolver for pointer types (of 1st degree)
1627  template<typename T>
1628  class UIDChainResolver<T*> {
1629  public:
1630  UIDChainResolver(const T* const & data) {
1631  m_uid.push_back({ (ID) &data, sizeof(data) });
1632  if (data)
1633  m_uid.push_back(UID::from(*data));
1634  else
1635  m_uid.push_back({ (ID) data, sizeof(*data) });
1636  }
1637 
1638  operator UIDChain() const { return m_uid; }
1639  UIDChain operator()() const { return m_uid; }
1640  private:
1641  UIDChain m_uid;
1642  };
1643 
1644  // SerializationRecursion for non-pointer class/struct types.
1645  template<typename T, bool T_isRecursive>
1646  struct SerializationRecursionImpl {
1647  static void serializeObject(Archive* archive, const T& obj) {
1648  const_cast<T&>(obj).serialize(archive);
1649  }
1650  };
1651 
1652  // SerializationRecursion for pointers (of 1st degree) to class/structs.
1653  template<typename T, bool T_isRecursive>
1654  struct SerializationRecursionImpl<T*,T_isRecursive> {
1655  static void serializeObject(Archive* archive, const T*& obj) {
1656  if (!obj) return;
1657  const_cast<T*&>(obj)->serialize(archive);
1658  }
1659  };
1660 
1661  // NOOP SerializationRecursion for primitive types.
1662  template<typename T>
1663  struct SerializationRecursionImpl<T,false> {
1664  static void serializeObject(Archive* /*archive*/, const T& /*obj*/) {}
1665  };
1666 
1667  // SerializationRecursion for pointers (of 1st degree) to primitive types.
1668  template<typename T>
1669  struct SerializationRecursionImpl<T*,false> {
1670  static void serializeObject(Archive* archive, const T* const & obj) {
1671  if (!obj) return;
1672  archive->serializeAnonymousObject(*obj);
1673  }
1674  };
1675 
1676  // NOOP SerializationRecursion for String objects.
1677  template<bool T_isRecursive>
1678  struct SerializationRecursionImpl<String,T_isRecursive> {
1679  static void serializeObject(Archive* archive, const String& obj) {}
1680  };
1681 
1682  // SerializationRecursion for String pointers (of 1st degree).
1683  template<bool T_isRecursive>
1684  struct SerializationRecursionImpl<String*,T_isRecursive> {
1685  static void serializeObject(Archive* archive, const String*& obj) {
1686  if (!obj) return;
1687  archive->serializeAnonymousObject(*obj);
1688  }
1689  };
1690 
1691  // SerializationRecursion for Array<> objects.
1692  template<typename T, bool T_isRecursive>
1693  struct SerializationRecursionImpl<Array<T>,T_isRecursive> {
1694  static void serializeObject(Archive* archive, const Array<T>& obj) {
1695  const UIDChain uids = UIDChainResolver<Array<T>>(obj);
1696  const Object& object = archive->objectByUID(uids[0]);
1697  if (archive->operation() == OPERATION_SERIALIZE) {
1698  for (size_t i = 0; i < obj.size(); ++i) {
1699  archive->serializeHeapMember(
1700  obj, obj[i], ("[" + toString(i) + "]").c_str()
1701  );
1702  }
1703  } else {
1704  const_cast<Object&>(object).m_sync =
1705  [&obj,archive](Object& dstObj, const Object& srcObj,
1706  void* syncer)
1707  {
1708  const size_t n = srcObj.members().size();
1709  const_cast<Array<T>&>(obj).resize(n);
1710  for (size_t i = 0; i < n; ++i) {
1711  archive->serializeHeapMember(
1712  obj, obj[i], ("[" + toString(i) + "]").c_str()
1713  );
1714  }
1715  // updating dstObj required as serializeHeapMember()
1716  // replaced the original object by a new one
1717  dstObj = archive->objectByUID(dstObj.uid());
1718  for (size_t i = 0; i < n; ++i) {
1719  String name = "[" + toString(i) + "]";
1720  Member srcMember = srcObj.memberNamed(name);
1721  Member dstMember = dstObj.memberNamed(name);
1722  ((Syncer*)syncer)->syncMember(dstMember, srcMember);
1723  }
1724  };
1725  }
1726  }
1727  };
1728 
1729  // SerializationRecursion for Array<> pointers (of 1st degree).
1730  template<typename T, bool T_isRecursive>
1731  struct SerializationRecursionImpl<Array<T>*,T_isRecursive> {
1732  static void serializeObject(Archive* archive, const Array<T>*& obj) {
1733  if (!obj) return;
1734  SerializationRecursionImpl<Array<T>,T_isRecursive>::serializeObject(
1735  archive, *obj
1736  );
1737  }
1738  };
1739 
1740  // SerializationRecursion for Set<> objects.
1741  template<typename T, bool T_isRecursive>
1742  struct SerializationRecursionImpl<Set<T>,T_isRecursive> {
1743  static void serializeObject(Archive* archive, const Set<T>& obj) {
1744  const UIDChain uids = UIDChainResolver<Set<T>>(obj);
1745  const Object& object = archive->objectByUID(uids[0]);
1746  if (archive->operation() == OPERATION_SERIALIZE) {
1747  for (const T& key : obj) {
1748  archive->serializeHeapMember(
1749  obj, key, ("[" + toString(key) + "]").c_str()
1750  );
1751  }
1752  } else {
1753  const_cast<Object&>(object).m_sync =
1754  [&obj,archive](Object& dstObj, const Object& srcObj,
1755  void* syncer)
1756  {
1757  const size_t n = srcObj.members().size();
1758  const_cast<Set<T>&>(obj).clear();
1759  for (size_t i = 0; i < n; ++i) {
1760  const Member& member = srcObj.members()[i];
1761  String name = member.name();
1762  // strip brackets from name
1763  if (name.length() < 2 || name[0] != '[' ||
1764  *name.rbegin() != ']') continue;
1765  name = name.substr(1, name.length() - 2);
1766  T key = T();
1767  const UIDChain uids = UIDChainResolver<T>(key);
1768  const DataType type = DataType::dataTypeOf(key);
1769  Object tmpObj(uids, type, Object());
1770  // set the value of "key" variable by abstraction API
1771  tmpObj.setNativeValueFromString(name);
1772  // only for keys of pointer type: translation of
1773  // memory address from source archive to destination
1774  // archive required, NOOP for all other data types
1775  ((Syncer*)syncer)->translateKey(key);
1776  // insert (translated) key into set
1777  const_cast<Set<T>&>(obj).insert(key);
1778  }
1779  // continue serialization recursion
1780  for (const T& key : obj) {
1781  archive->serializeHeapMember(
1782  obj, key, ("[" + toString(key) + "]").c_str()
1783  );
1784  }
1785  // updating dstObj required as serializeHeapMember()
1786  // replaced the original object by a new one
1787  dstObj = archive->objectByUID(dstObj.uid());
1788  };
1789  }
1790  }
1791  };
1792 
1793  // SerializationRecursion for Set<> pointers (of 1st degree).
1794  template<typename T, bool T_isRecursive>
1795  struct SerializationRecursionImpl<Set<T>*,T_isRecursive> {
1796  static void serializeObject(Archive* archive, const Set<T>*& obj) {
1797  if (!obj) return;
1798  SerializationRecursionImpl<Set<T>,T_isRecursive>::serializeObject(
1799  archive, *obj
1800  );
1801  }
1802  };
1803 
1804  // SerializationRecursion for Map<> objects.
1805  template<typename T_key, typename T_value, bool T_isRecursive>
1806  struct SerializationRecursionImpl<Map<T_key,T_value>,T_isRecursive> {
1807  static void serializeObject(Archive* archive, const Map<T_key,T_value>& obj) {
1808  const UIDChain uids = UIDChainResolver<Map<T_key,T_value>>(obj);
1809  const Object& object = archive->objectByUID(uids[0]);
1810  if (archive->operation() == OPERATION_SERIALIZE) {
1811  for (const auto& it : obj) {
1812  // recurse serialization for map's key ...
1813  SerializationRecursion<T_key>::serializeObject(archive, it.first);
1814  // ... and map's value
1815  archive->serializeHeapMember(
1816  obj, it.second, ("[" + toString(it.first) + "]").c_str()
1817  );
1818  }
1819  } else {
1820  const_cast<Object&>(object).m_sync =
1821  [&obj,archive](Object& dstObj, const Object& srcObj,
1822  void* syncer)
1823  {
1824  const size_t n = srcObj.members().size();
1825  const_cast<Map<T_key,T_value>&>(obj).clear();
1826  // translation is neutral except for keys of pointer type (see comments below)
1827  std::map<String,String> memberNameTranslation;
1828  for (size_t i = 0; i < n; ++i) {
1829  const Member& member = srcObj.members()[i];
1830  String name = member.name();
1831  // strip brackets from name
1832  if (name.length() < 2 || name[0] != '[' ||
1833  *name.rbegin() != ']') continue;
1834  name = name.substr(1, name.length() - 2);
1835  T_key srcKey = T_key();
1836  const UIDChain uids = UIDChainResolver<T_key>(srcKey);
1837  const DataType type = DataType::dataTypeOf(srcKey);
1838  Object tmpObj(uids, type, Object());
1839  // set the value of "srcKey" variable by abstraction API
1840  tmpObj.setNativeValueFromString(name);
1841  T_key dstKey = srcKey;
1842  // only for keys of pointer type: translation of
1843  // memory address from source archive to destination
1844  // archive required, NOOP for all other data types
1845  ((Syncer*)syncer)->translateKey(dstKey);
1846  memberNameTranslation[member.name()] = "[" + toString(dstKey) + "]";
1847  // insert (translated) key into the destination map
1848  const_cast<Map<T_key,T_value>&>(obj)[dstKey] = T_value();
1849  }
1850  // continue serialization recursion ...
1851  for (const auto& it : obj) {
1852  // ... for map's key ...
1853  SerializationRecursion<T_key>::serializeObject(archive, it.first);
1854  // ... and map's value
1855  archive->serializeHeapMember(
1856  obj, it.second, ("[" + toString(it.first) + "]").c_str()
1857  );
1858  }
1859  // updating dstObj required as serializeHeapMember()
1860  // replaced the original object by a new one
1861  dstObj = archive->objectByUID(dstObj.uid());
1862  // sync map's values
1863  for (size_t i = 0; i < n; ++i) {
1864  Member srcMember = srcObj.members()[i];
1865  Member dstMember = dstObj.memberNamed(
1866  memberNameTranslation[srcMember.name()]
1867  );
1868  ((Syncer*)syncer)->syncMember(dstMember, srcMember);
1869  }
1870  };
1871  }
1872  }
1873  };
1874 
1875  // SerializationRecursion for Map<> pointers (of 1st degree).
1876  template<typename T_key, typename T_value, bool T_isRecursive>
1877  struct SerializationRecursionImpl<Map<T_key,T_value>*,T_isRecursive> {
1878  static void serializeObject(Archive* archive, const Map<T_key,T_value>*& obj) {
1879  if (!obj) return;
1880  SerializationRecursionImpl<Map<T_key,T_value>,T_isRecursive>::serializeObject(
1881  archive, *obj
1882  );
1883  }
1884  };
1885 
1886  // Automatically handles recursion for class/struct types, while ignoring all primitive types.
1887  template<typename T>
1888  struct SerializationRecursion : SerializationRecursionImpl<T, LIBGIG_IS_CLASS(T)> {
1889  };
1890 
1891  class ObjectPool : public std::map<UID,Object> {
1892  public:
1893  // prevent passing obvious invalid UID values from creating a new pair entry
1894  Object& operator[](const UID& k) {
1895  if (!k.isValid())
1896  return invalidObject();
1897  return std::map<UID,Object>::operator[](k);
1898  }
1899 
1900  static Object& invalidObject() {
1901  static Object invalid;
1902  invalid = Object();
1903  return invalid;
1904  }
1905  };
1906 
1907  protected:
1947  class Syncer {
1948  public:
1949  Syncer(Archive& dst, Archive& src);
1950  void syncObject(const Object& dst, const Object& src);
1951  void syncPrimitive(const Object& dst, const Object& src);
1952  void syncString(const Object& dst, const Object& src);
1953  void syncArray(const Object& dst, const Object& src);
1954  void syncSet(const Object& dst, const Object& src);
1955  void syncMap(const Object& dst, const Object& src);
1956  void syncPointer(const Object& dst, const Object& src);
1957  void syncMember(const Member& dstMember, const Member& srcMember);
1958 
1959  // Address translation for keys of pointer type.
1960  //
1961  // Translates memory address from source archive, to memory address
1962  // of destination archive. For "strong" pointers memory is allocated
1963  // and the pointed data is synced with data from source archive.
1964  template<typename T>
1965  void translateKey(T*& key) {
1966  if (!key) return; // NULL pointer on source side
1967 
1968  // UIDChainResolver can't be used here, since the passed memory
1969  // address is an abstract one that originates from the source
1970  // archive (e.g. potentially even from another machine) and
1971  // UIDChainResolver would then crash on its typeid() operator.
1972  UID uid = { (ID) key, sizeof(*key) };
1973 
1974  const Object& pointedSrcObject = m_src.objectByBaseUID(uid);
1975  assert(pointedSrcObject);
1976  std::map<UID,UID>::iterator uidRelation = m_counterparts.find(uid);
1977  if (pointedSrcObject.parentUID() || uidRelation != m_counterparts.end()) { // "weak" pointer to object ...
1978  assert(uidRelation != m_counterparts.end());
1979  key = (T*) uidRelation->second.id;
1980  } else { // "strong" pointer to object, allocation required ...
1981  assert(pointedSrcObject.type());
1982  Object pointedDstObject = pointedSrcObject.type().newInstance(&m_dst);
1983  assert(pointedDstObject);
1984  m_dst.m_allObjects[pointedDstObject.uid()] = pointedDstObject;
1985  key = (T*) pointedDstObject.uid().id;
1986 
1987  syncObject(pointedDstObject, pointedSrcObject);
1988  }
1989  }
1990 
1991  // NOOP, no key translation required for any other type
1992  template<typename T>
1993  void translateKey(T& key) {}
1994  protected:
1995  static Member dstMemberMatching(const Object& dstObj, const Object& srcObj, const Member& srcMember);
1996  private:
1997  Archive& m_dst;
1998  Archive& m_src;
1999  std::map<UID,UID> m_counterparts;
2000  };
2001 
2002  virtual void encode();
2003  virtual void encode(format_t format);
2004 
2005  ObjectPool m_allObjects;
2006  format_t m_format;
2007  operation_t m_operation;
2008  UID m_root;
2009  RawData m_rawData;
2010  bool m_isModified;
2011  String m_name;
2012  String m_comment;
2013  time_t m_timeCreated;
2014  time_t m_timeModified;
2015 
2016  friend class DataType;
2017  friend class SrxFormat;
2018  friend class SrxJSONEncoder;
2019  friend class SrxJSONDecoder;
2020  };
2021 
2022  // UID resolver implementation for non-pointer types
2023  template<typename T>
2024  UID UID::Resolver<T>::resolve(const T& obj) {
2025  const size_t size = DataType::sizeOf(obj);
2026  const UID uid = { (ID) &obj, size };
2027  return uid;
2028  }
2029 
2030  // UID resolver implementation for pointer types (of 1st degree)
2031  template<typename T>
2032  UID UID::Resolver<T*>::resolve(const T* const & obj) {
2033  const size_t size = DataType::sizeOf(*obj);
2034  const UID uid = { (ID) obj, size };
2035  return uid;
2036  }
2037 
2038  // Manual registration of native data types by application.
2039  template<typename T>
2041  static_assert(
2042  std::is_default_constructible<T>::value,
2043  "missing default constructor for type: registration of data "
2044  "types is only needed for creating instances of that type at "
2045  "runtime by this framework's reflection API; which in turn "
2046  "requires the type to provide a default constructor."
2047  );
2048  const DataType staticType = DataType::dataType<T>(false);
2049  assert(staticType);
2050  const auto itType = m_nativeTypes.find(staticType.internalID());
2051  if (itType != m_nativeTypes.end()) {
2052  assert(itType->second.size >= sizeof(T));
2053  return;
2054  }
2055 
2056  // register lambda function for allocating a new instance of this type
2057  m_nativeTypes[staticType.internalID()] = {
2058  /*.size =*/ sizeof(T),
2059  /*.allocFn =*/ [](Archive* archive) -> Object {
2060  T* instance = new T;
2061  Archive::SerializationRecursion<T>::serializeObject(archive, *instance);
2062  const UIDChain uids = Archive::UIDChainResolver<T>(*instance);
2063  Object& obj = archive->objectByUID(uids[0]);
2064  if (obj) return obj;
2065  const DataType type = DataType::dataTypeOf(*instance);
2066  return Object(uids, type, Object());
2067  }
2068  };
2069  }
2070 
2071  // Automatic self-registration of native data types by this framework.
2072  // (SFINAE variant for types WITH default constructor)
2073  template<typename T, typename std::enable_if<std::is_default_constructible<T>::value, bool>::type>
2074  void DataType::registerNativeDataType(const DataType& rttiType, const T& nativeData) {
2075  if (!rttiType) return;
2076  if (m_nativeTypes.find(rttiType.internalID()) != m_nativeTypes.end())
2077  return;
2078 
2079  // Ensure compile-time native data type 'T' matches passed runtime
2080  // native data type 'nativeData', because we can only offer to create
2081  // new instances of native data types by our reflection API if this
2082  // framework is aware about the data type already. Usually this happens
2083  // automatically without applications having to do anything. But
2084  // this only works for types this framework gets in touch with at
2085  // compile-time.
2086  //
2087  // Root problem of all of this: ATM there is no way in C++ to create new
2088  // instances of a type by using RTTI (typeid(), std::type_info, etc.).
2089  // If there is a way in a future C++ version then we can get rid of
2090  // manual type registration altogether. Bur for now we must use new T,
2091  // which is a compile-time only construct.
2092  //
2093  // See the discussion in DataType::registerNativeDataType() for an
2094  // example where manual type registration would be required.
2095  const DataType staticType = DataType::dataType<T>(false);
2096  if (staticType != rttiType) {
2097  fprintf(stderr, "Serialization Failure: run-time data type '%s' does not match compile-time data type '%s'!\n",
2098  rttiType.asLongDescr().c_str(),
2099  staticType.asLongDescr().c_str());
2100  assert(false && "You may need to explicitly register this run-time "
2101  "data type by either calling "
2102  "DataType::registerNativeType<T>() or using class "
2103  "NativeDataTypeRegistry");
2104  }
2105 
2106  // register lambda function for allocating a new instance of this type
2107  m_nativeTypes[rttiType.internalID()] = {
2108  /*.size =*/ sizeof(T),
2109  /*.allocFn =*/ [](Archive* archive) -> Object {
2110  T* instance = new T;
2111  Archive::SerializationRecursion<T>::serializeObject(archive, *instance);
2112  const UIDChain uids = Archive::UIDChainResolver<T>(*instance);
2113  Object& obj = archive->objectByUID(uids[0]);
2114  if (obj) return obj;
2115  const DataType type = DataType::dataTypeOf(*instance);
2116  return Object(uids, type, Object());
2117  }
2118  };
2119  }
2120 
2121  // Automatic self-registration of native data types by this framework.
2122  // (SFINAE variant for types WITHOUT default constructor)
2123  template<typename T, typename std::enable_if<!std::is_default_constructible<T>::value, bool>::type>
2124  void DataType::registerNativeDataType(const DataType& type, const T& nativeData) {
2125  if (!type) return;
2126  if (m_nativeTypes.find(type.internalID()) != m_nativeTypes.end())
2127  return;
2128  m_nativeTypes[type.internalID()] = {
2129  /*.size =*/ sizeof(T),
2130  /*.allocFn =*/ [](Archive*) -> Object {
2131  assert(false && "instance not possible: native data type does not have default constructor");
2132  return Object();
2133  }
2134  };
2135  }
2136 
2137  // DataType resolver implementation for primitive / built-in types
2138  template<typename T, bool T_isPointer>
2139  DataType DataType::ResolverBase<T,T_isPointer>::resolve(const T& data) {
2140  // for pointers we must stick to the compile-time declared type
2141  // of pointer to prevent potential type mismatches caused by
2142  // RTTI in a polymorphic scenario
2143  const std::type_info& type = (T_isPointer) ? typeid(T) : typeid(data);
2144  const int sz = sizeof(data);
2145 
2146  // for primitive types we are using our own type names instead of
2147  // using std:::type_info::name(), because the precise output of the
2148  // latter may vary between compilers
2149  if (type == typeid(char))
2150  // special case: C++ defines "char" to be neither type
2151  // equivalent to "signed char" nor to "unsigned char",
2152  // because e.g. char's signedness is implementation specific
2153  return DataType(T_isPointer, sz, "char");
2154  if (type == typeid(int8_t)) return DataType(T_isPointer, sz, "int8");
2155  if (type == typeid(uint8_t)) return DataType(T_isPointer, sz, "uint8");
2156  if (type == typeid(int16_t)) return DataType(T_isPointer, sz, "int16");
2157  if (type == typeid(uint16_t)) return DataType(T_isPointer, sz, "uint16");
2158  if (type == typeid(int32_t)) return DataType(T_isPointer, sz, "int32");
2159  if (type == typeid(uint32_t)) return DataType(T_isPointer, sz, "uint32");
2160  if (type == typeid(int64_t)) return DataType(T_isPointer, sz, "int64");
2161  if (type == typeid(uint64_t)) return DataType(T_isPointer, sz, "uint64");
2162  // CAUTION: depending on the system, "long" or "int" types may not
2163  // already been covered by the typedefs above
2164  if (type == typeid(long) || type == typeid(int)) {
2165  if (sz == 1) return DataType(T_isPointer, sz, "int8");
2166  if (sz == 2) return DataType(T_isPointer, sz, "int16");
2167  if (sz == 4) return DataType(T_isPointer, sz, "int32");
2168  if (sz == 8) return DataType(T_isPointer, sz, "int64");
2169  else assert(false /* unknown int / long size */);
2170  }
2171  if (type == typeid(unsigned long) || type == typeid(unsigned int)) {
2172  if (sz == 1) return DataType(T_isPointer, sz, "uint8");
2173  if (sz == 2) return DataType(T_isPointer, sz, "uint16");
2174  if (sz == 4) return DataType(T_isPointer, sz, "uint32");
2175  if (sz == 8) return DataType(T_isPointer, sz, "uint64");
2176  else assert(false /* unknown unsigned int / unsigned long size */);
2177  }
2178  if (type == typeid(bool)) return DataType(T_isPointer, sz, "bool");
2179  if (type == typeid(float)) return DataType(T_isPointer, sz, "real32");
2180  if (type == typeid(double)) return DataType(T_isPointer, sz, "real64");
2181  if (type == typeid(String)) return DataType(T_isPointer, sz, "String");
2182 
2183  // for pointers we must stick to pointer's compile-time declared
2184  // type and not use RTTI for the pointed object, because the
2185  // latter would easily create a type mismatch conflict for
2186  // pointers and objects in a polymorphic scenario, because the
2187  // pointer might have been declared with a base class type,
2188  // while actually assigned objects to these pointers might be of
2189  // any other derived class and RTTI would resolve the latter
2190  const String rawCppName =
2191  (T_isPointer) ? rawCppTypeName<T>()
2192  : rawCppTypeNameOf(data);
2193 
2194  if (IsEnum(data)) return DataType(T_isPointer, sz, "enum", rawCppName);
2195  if (IsUnion(data)) return DataType(T_isPointer, sz, "union", rawCppName);
2196  if (IsClass(data)) return DataType(T_isPointer, sz, "class", rawCppName);
2197 
2198  assert(false /* unknown data type*/);
2199  return DataType();
2200  }
2201 
2206  class Exception {
2207  public:
2208  String Message;
2209 
2210  Exception(String format, ...);
2211  Exception(String format, va_list arg);
2212  void PrintMessage() const;
2213  virtual ~Exception() {}
2214 
2215  protected:
2216  Exception();
2217  static String assemble(String format, va_list arg);
2218  };
2219 
2220 } // namespace Serialization
2221 
2222 #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...