libgig  4.3.0
Serialization.h
1 /***************************************************************************
2  * *
3  * Copyright (C) 2017-2020 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 
43 #ifndef __has_extension
44 # define __has_extension(x) 0
45 #endif
46 
47 #ifndef HAS_BUILTIN_TYPE_TRAITS
48 # if __cplusplus >= 201103L
49 # define HAS_BUILTIN_TYPE_TRAITS 1
50 # elif ( __has_extension(is_class) && __has_extension(is_enum) )
51 # define HAS_BUILTIN_TYPE_TRAITS 1
52 # elif ( __GNUC__ > 4 || ( __GNUC__ == 4 && __GNUC_MINOR__ >= 3 ) )
53 # define HAS_BUILTIN_TYPE_TRAITS 1
54 # elif _MSC_VER >= 1400 /* MS Visual C++ 8.0 (Visual Studio 2005) */
55 # define HAS_BUILTIN_TYPE_TRAITS 1
56 # elif __INTEL_COMPILER >= 1100
57 # define HAS_BUILTIN_TYPE_TRAITS 1
58 # else
59 # define HAS_BUILTIN_TYPE_TRAITS 0
60 # endif
61 #endif
62 
63 #if !HAS_BUILTIN_TYPE_TRAITS
64 # include <tr1/type_traits>
65 # define LIBGIG_IS_CLASS(type) std::tr1::__is_union_or_class<type>::value //NOTE: without compiler support we cannot distinguish union from class
66 #else
67 # define LIBGIG_IS_CLASS(type) __is_class(type)
68 #endif
69 
113 namespace Serialization {
114 
115  // just symbol prototyping
116  class DataType;
117  class Object;
118  class Member;
119  class Archive;
120  class ObjectPool;
121  class Exception;
122 
130  typedef std::string String;
131 
144  template<class T>
145  using Array = std::vector<T>;
146 
156  template<class T>
157  using Set = std::set<T>;
158 
177  template<class T_key, class T_value>
178  using Map = std::map<T_key,T_value>;
179 
188  typedef std::vector<uint8_t> RawData;
189 
200  typedef void* ID;
201 
209  typedef uint32_t Version;
210 
216  enum time_base_t {
218  UTC_TIME
219  };
220 
228  template<typename T>
229  bool IsEnum(const T& data) {
230  #if !HAS_BUILTIN_TYPE_TRAITS
231  return std::tr1::is_enum<T>::value;
232  #else
233  return __is_enum(T);
234  #endif
235  }
236 
247  template<typename T>
248  bool IsUnion(const T& data) {
249  #if !HAS_BUILTIN_TYPE_TRAITS
250  return false; // without compiler support we cannot distinguish union from class
251  #else
252  return __is_union(T);
253  #endif
254  }
255 
265  template<typename T>
266  bool IsClass(const T& data) {
267  #if !HAS_BUILTIN_TYPE_TRAITS
268  return std::tr1::__is_union_or_class<T>::value; // without compiler support we cannot distinguish union from class
269  #else
270  return __is_class(T);
271  #endif
272  }
273 
274  /*template<typename T>
275  bool IsTrivial(T data) {
276  return __is_trivial(T);
277  }*/
278 
279  /*template<typename T>
280  bool IsPOD(T data) {
281  return __is_pod(T);
282  }*/
283 
284  /*template<typename T>
285  bool IsArray(const T& data) {
286  return false;
287  }*/
288 
289  /*template<typename T>
290  bool IsArray(const Array<T>& data) {
291  return true;
292  }*/
293 
294  template<typename T> inline
295  String toString(const T& value) {
296  return std::to_string(value);
297  }
298 
299  template<> inline
300  String toString(const String& value) {
301  return value;
302  }
303 
319  class UID {
320  public:
321  ID id;
322  size_t size;
323 
324  bool isValid() const;
325  operator bool() const { return isValid(); }
326  //bool operator()() const { return isValid(); }
327  bool operator==(const UID& other) const { return id == other.id && size == other.size; }
328  bool operator!=(const UID& other) const { return id != other.id || size != other.size; }
329  bool operator<(const UID& other) const { return id < other.id || (id == other.id && size < other.size); }
330  bool operator>(const UID& other) const { return id > other.id || (id == other.id && size > other.size); }
331 
339  template<typename T>
340  static UID from(const T& obj) {
341  return Resolver<T>::resolve(obj);
342  }
343 
344  protected:
345  // UID resolver for non-pointer types
346  template<typename T>
347  struct Resolver {
348  static UID resolve(const T& obj) {
349  const UID uid = { (ID) &obj, sizeof(obj) };
350  return uid;
351  }
352  };
353 
354  // UID resolver for pointer types (of 1st degree)
355  template<typename T>
356  struct Resolver<T*> {
357  static UID resolve(const T* const & obj) {
358  const UID uid = { (ID) obj, sizeof(*obj) };
359  return uid;
360  }
361  };
362  };
363 
369  extern const UID NO_UID;
370 
402  typedef std::vector<UID> UIDChain;
403 
404 #if LIBGIG_SERIALIZATION_INTERNAL
405  // prototyping of private internal friend functions
406  static String _encodePrimitiveValue(const Object& obj);
407  static DataType _popDataTypeBlob(const char*& p, const char* end);
408  static Member _popMemberBlob(const char*& p, const char* end);
409  static Object _popObjectBlob(const char*& p, const char* end);
410  static void _popPrimitiveValue(const char*& p, const char* end, Object& obj);
411  static String _primitiveObjectValueToString(const Object& obj);
412  // |
413  template<typename T>
414  static T _primitiveObjectValueToNumber(const Object& obj);
415 #endif // LIBGIG_SERIALIZATION_INTERNAL
416 
433  class DataType {
434  public:
435  DataType();
436  size_t size() const { return m_size; }
437  bool isValid() const;
438  bool isPointer() const;
439  bool isClass() const;
440  bool isPrimitive() const;
441  bool isString() const;
442  bool isInteger() const;
443  bool isReal() const;
444  bool isBool() const;
445  bool isEnum() const;
446  bool isArray() const;
447  bool isSet() const;
448  bool isMap() const;
449  bool isSigned() const;
450  operator bool() const { return isValid(); }
451  //bool operator()() const { return isValid(); }
452  bool operator==(const DataType& other) const;
453  bool operator!=(const DataType& other) const;
454  bool operator<(const DataType& other) const;
455  bool operator>(const DataType& other) const;
456  String asLongDescr() const;
457  String baseTypeName() const;
458  String customTypeName(bool demangle = false) const;
459  String customTypeName2(bool demangle = false) const;
460 
471  template<typename T>
472  static DataType dataTypeOf(const T& data) {
473  return Resolver<T>::resolve(data);
474  }
475 
476  protected:
477  DataType(bool isPointer, int size, String baseType,
478  String customType1 = "", String customType2 = "");
479 
480  template<typename T, bool T_isPointer>
481  struct ResolverBase {
482  static DataType resolve(const T& data) {
483  const std::type_info& type = typeid(data);
484  const int sz = sizeof(data);
485 
486  // for primitive types we are using our own type names instead of
487  // using std:::type_info::name(), because the precise output of the
488  // latter may vary between compilers
489  if (type == typeid(int8_t)) return DataType(T_isPointer, sz, "int8");
490  if (type == typeid(uint8_t)) return DataType(T_isPointer, sz, "uint8");
491  if (type == typeid(int16_t)) return DataType(T_isPointer, sz, "int16");
492  if (type == typeid(uint16_t)) return DataType(T_isPointer, sz, "uint16");
493  if (type == typeid(int32_t)) return DataType(T_isPointer, sz, "int32");
494  if (type == typeid(uint32_t)) return DataType(T_isPointer, sz, "uint32");
495  if (type == typeid(int64_t)) return DataType(T_isPointer, sz, "int64");
496  if (type == typeid(uint64_t)) return DataType(T_isPointer, sz, "uint64");
497  if (type == typeid(size_t)) {
498  if (sz == 1) return DataType(T_isPointer, sz, "uint8");
499  if (sz == 2) return DataType(T_isPointer, sz, "uint16");
500  if (sz == 4) return DataType(T_isPointer, sz, "uint32");
501  if (sz == 8) return DataType(T_isPointer, sz, "uint64");
502  else assert(false /* unknown size_t size */);
503  }
504  if (type == typeid(ssize_t)) {
505  if (sz == 1) return DataType(T_isPointer, sz, "int8");
506  if (sz == 2) return DataType(T_isPointer, sz, "int16");
507  if (sz == 4) return DataType(T_isPointer, sz, "int32");
508  if (sz == 8) return DataType(T_isPointer, sz, "int64");
509  else assert(false /* unknown ssize_t size */);
510  }
511  if (type == typeid(bool)) return DataType(T_isPointer, sz, "bool");
512  if (type == typeid(float)) return DataType(T_isPointer, sz, "real32");
513  if (type == typeid(double)) return DataType(T_isPointer, sz, "real64");
514  if (type == typeid(String)) return DataType(T_isPointer, sz, "String");
515 
516  if (IsEnum(data)) return DataType(T_isPointer, sz, "enum", rawCppTypeNameOf(data));
517  if (IsUnion(data)) return DataType(T_isPointer, sz, "union", rawCppTypeNameOf(data));
518  if (IsClass(data)) return DataType(T_isPointer, sz, "class", rawCppTypeNameOf(data));
519 
520  return DataType();
521  }
522  };
523 
524  // DataType resolver for non-pointer types
525  template<typename T>
526  struct Resolver : ResolverBase<T,false> {
527  static DataType resolve(const T& data) {
528  return ResolverBase<T,false>::resolve(data);
529  }
530  };
531 
532  // DataType resolver for pointer types (of 1st degree)
533  template<typename T>
534  struct Resolver<T*> : ResolverBase<T,true> {
535  static DataType resolve(const T*& data) {
536  return ResolverBase<T,true>::resolve(*data);
537  }
538  };
539 
540  // DataType resolver for non-pointer Array<> container object types.
541  template<typename T>
542  struct Resolver<Array<T>> {
543  static DataType resolve(const Array<T>& data) {
544  const int sz = sizeof(data);
545  T unused;
546  return DataType(false, sz, "Array", rawCppTypeNameOf(unused));
547  }
548  };
549 
550  // DataType resolver for Array<> pointer types (of 1st degree).
551  template<typename T>
552  struct Resolver<Array<T>*> {
553  static DataType resolve(const Array<T>*& data) {
554  const int sz = sizeof(*data);
555  T unused;
556  return DataType(true, sz, "Array", rawCppTypeNameOf(unused));
557  }
558  };
559 
560  // DataType resolver for non-pointer Set<> container object types.
561  template<typename T>
562  struct Resolver<Set<T>> {
563  static DataType resolve(const Set<T>& data) {
564  const int sz = sizeof(data);
565  T unused;
566  return DataType(false, sz, "Set", rawCppTypeNameOf(unused));
567  }
568  };
569 
570  // DataType resolver for Set<> pointer types (of 1st degree).
571  template<typename T>
572  struct Resolver<Set<T>*> {
573  static DataType resolve(const Set<T>*& data) {
574  const int sz = sizeof(*data);
575  T unused;
576  return DataType(true, sz, "Set", rawCppTypeNameOf(unused));
577  }
578  };
579 
580  // DataType resolver for non-pointer Map<> container object types.
581  template<typename T_key, typename T_value>
582  struct Resolver<Map<T_key,T_value>> {
583  static DataType resolve(const Map<T_key,T_value>& data) {
584  const int sz = sizeof(data);
585  T_key unused1;
586  T_value unused2;
587  return DataType(false, sz, "Map", rawCppTypeNameOf(unused1),
588  rawCppTypeNameOf(unused2));
589  }
590  };
591 
592  // DataType resolver for Map<> pointer types (of 1st degree).
593  template<typename T_key, typename T_value>
594  struct Resolver<Map<T_key,T_value>*> {
595  static DataType resolve(const Map<T_key,T_value>*& data) {
596  const int sz = sizeof(*data);
597  T_key unused1;
598  T_value unused2;
599  return DataType(true, sz, "Map", rawCppTypeNameOf(unused1),
600  rawCppTypeNameOf(unused2));
601  }
602  };
603 
604  template<typename T>
605  static String rawCppTypeNameOf(const T& data) {
606  #if defined _MSC_VER // Microsoft compiler ...
607  String name = typeid(data).raw_name();
608  #else // i.e. especially GCC and clang ...
609  String name = typeid(data).name();
610  #endif
611  //while (!name.empty() && name[0] >= 0 && name[0] <= 9)
612  // name = name.substr(1);
613  return name;
614  }
615 
616  private:
617  String m_baseTypeName;
618  String m_customTypeName;
619  String m_customTypeName2;
620  int m_size;
621  bool m_isPointer;
622 
623 #if LIBGIG_SERIALIZATION_INTERNAL
624  friend DataType _popDataTypeBlob(const char*& p, const char* end);
625 #endif
626  friend class Archive;
627  };
628 
650  class Member {
651  public:
652  Member();
653  UID uid() const;
654  String name() const;
655  ssize_t offset() const;
656  const DataType& type() const;
657  bool isValid() const;
658  operator bool() const { return isValid(); }
659  //bool operator()() const { return isValid(); }
660  bool operator==(const Member& other) const;
661  bool operator!=(const Member& other) const;
662  bool operator<(const Member& other) const;
663  bool operator>(const Member& other) const;
664 
665  protected:
666  Member(String name, UID uid, ssize_t offset, DataType type);
667  friend class Archive;
668 
669  private:
670  UID m_uid;
671  ssize_t m_offset;
672  String m_name;
673  DataType m_type;
674 
675 #if LIBGIG_SERIALIZATION_INTERNAL
676  friend Member _popMemberBlob(const char*& p, const char* end);
677 #endif
678  };
679 
704  class Object {
705  public:
706  Object();
708 
709  UID uid(int index = 0) const;
710  const UIDChain& uidChain() const;
711  const DataType& type() const;
712  const RawData& rawData() const;
713  Version version() const;
714  Version minVersion() const;
715  bool isVersionCompatibleTo(const Object& other) const;
716  std::vector<Member>& members();
717  const std::vector<Member>& members() const;
718  Member memberNamed(String name) const;
719  Member memberByUID(const UID& uid) const;
720  std::vector<Member> membersOfType(const DataType& type) const;
721  int sequenceIndexOf(const Member& member) const;
722  bool isValid() const;
723  operator bool() const { return isValid(); }
724  //bool operator()() const { return isValid(); }
725  bool operator==(const Object& other) const;
726  bool operator!=(const Object& other) const;
727  bool operator<(const Object& other) const;
728  bool operator>(const Object& other) const;
729  void setNativeValueFromString(const String& s);
730 
731  protected:
732  void remove(const Member& member);
733  void setVersion(Version v);
734  void setMinVersion(Version v);
735 
736  private:
737  DataType m_type;
738  UIDChain m_uid;
739  Version m_version;
740  Version m_minVersion;
741  RawData m_data;
742  std::vector<Member> m_members;
743  std::function<void(Object& dstObj, const Object& srcObj, void* syncer)> m_sync;
744 
745 #if LIBGIG_SERIALIZATION_INTERNAL
746  friend String _encodePrimitiveValue(const Object& obj);
747  friend Object _popObjectBlob(const char*& p, const char* end);
748  friend void _popPrimitiveValue(const char*& p, const char* end, Object& obj);
749  friend String _primitiveObjectValueToString(const Object& obj);
750  // |
751  template<typename T>
752  friend T _primitiveObjectValueToNumber(const Object& obj);
753 #endif // LIBGIG_SERIALIZATION_INTERNAL
754 
755  friend class Archive;
756  };
757 
895  class Archive {
896  public:
899  enum operation_t {
903  };
904 
905  Archive();
906  Archive(const RawData& data);
907  Archive(const uint8_t* data, size_t size);
908  virtual ~Archive();
909 
935  template<typename T>
936  void serialize(const T* obj) {
937  m_operation = OPERATION_SERIALIZE;
938  m_allObjects.clear();
939  m_rawData.clear();
940  m_root = UID::from(obj);
941  const_cast<T*>(obj)->serialize(this);
942  encode();
943  m_operation = OPERATION_NONE;
944  }
945 
970  template<typename T>
971  void deserialize(T* obj) {
972  Archive a;
973  a.m_operation = m_operation = OPERATION_DESERIALIZE;
974  obj->serialize(&a);
975  a.m_root = UID::from(obj);
976  Syncer s(a, *this);
977  a.m_operation = m_operation = OPERATION_NONE;
978  }
979 
994  template<typename T>
995  void operator<<(const T& obj) {
996  serialize(&obj);
997  }
998 
1017  template<typename T>
1018  void operator>>(T& obj) {
1019  deserialize(&obj);
1020  }
1021 
1022  const RawData& rawData();
1023  virtual String rawDataFormat() const;
1024 
1081  template<typename T_classType, typename T_memberType>
1082  void serializeMember(const T_classType& nativeObject, const T_memberType& nativeMember, const char* memberName) {
1083  const ssize_t offset =
1084  ((const uint8_t*)(const void*)&nativeMember) -
1085  ((const uint8_t*)(const void*)&nativeObject);
1086  const UIDChain uids = UIDChainResolver<T_memberType>(nativeMember);
1087  const DataType type = DataType::dataTypeOf(nativeMember);
1088  const Member member(memberName, uids[0], offset, type);
1089  const UID parentUID = UID::from(nativeObject);
1090  Object& parent = m_allObjects[parentUID];
1091  if (!parent) {
1092  const UIDChain uids = UIDChainResolver<T_classType>(nativeObject);
1093  const DataType type = DataType::dataTypeOf(nativeObject);
1094  parent = Object(uids, type);
1095  }
1096  parent.members().push_back(member);
1097  const Object obj(uids, type);
1098  const bool bExistsAlready = m_allObjects.count(uids[0]);
1099  const bool isValidObject = obj;
1100  const bool bExistingObjectIsInvalid = !m_allObjects[uids[0]];
1101  if (!bExistsAlready || (bExistingObjectIsInvalid && isValidObject)) {
1102  m_allObjects[uids[0]] = obj;
1103  // recurse serialization for all members of this member
1104  // (only for struct/class types, noop for primitive types)
1105  SerializationRecursion<T_memberType>::serializeObject(this, nativeMember);
1106  }
1107  }
1108 
1139  template<typename T_classType, typename T_memberType>
1140  void serializeHeapMember(const T_classType& nativeObject, const T_memberType& heapMember, const char* memberName) {
1141  const ssize_t offset = -1; // used for all members on heap
1142  const UIDChain uids = UIDChainResolver<T_memberType>(heapMember);
1143  const DataType type = DataType::dataTypeOf(heapMember);
1144  const Member member(memberName, uids[0], offset, type);
1145  const UID parentUID = UID::from(nativeObject);
1146  Object& parent = m_allObjects[parentUID];
1147  if (!parent) {
1148  const UIDChain uids = UIDChainResolver<T_classType>(nativeObject);
1149  const DataType type = DataType::dataTypeOf(nativeObject);
1150  parent = Object(uids, type);
1151  }
1152  parent.members().push_back(member);
1153  const Object obj(uids, type);
1154  const bool bExistsAlready = m_allObjects.count(uids[0]);
1155  const bool isValidObject = obj;
1156  const bool bExistingObjectIsInvalid = !m_allObjects[uids[0]];
1157  if (!bExistsAlready || (bExistingObjectIsInvalid && isValidObject)) {
1158  m_allObjects[uids[0]] = obj;
1159  // recurse serialization for all members of this member
1160  // (only for struct/class types, noop for primitive types)
1161  SerializationRecursion<T_memberType>::serializeObject(this, heapMember);
1162  }
1163  }
1164 
1244  template<typename T_classType>
1245  void setVersion(const T_classType& nativeObject, Version v) {
1246  const UID uid = UID::from(nativeObject);
1247  Object& obj = m_allObjects[uid];
1248  if (!obj) {
1249  const UIDChain uids = UIDChainResolver<T_classType>(nativeObject);
1250  const DataType type = DataType::dataTypeOf(nativeObject);
1251  obj = Object(uids, type);
1252  }
1253  setVersion(obj, v);
1254  }
1255 
1285  template<typename T_classType>
1286  void setMinVersion(const T_classType& nativeObject, Version v) {
1287  const UID uid = UID::from(nativeObject);
1288  Object& obj = m_allObjects[uid];
1289  if (!obj) {
1290  const UIDChain uids = UIDChainResolver<T_classType>(nativeObject);
1291  const DataType type = DataType::dataTypeOf(nativeObject);
1292  obj = Object(uids, type);
1293  }
1294  setMinVersion(obj, v);
1295  }
1296 
1297  virtual void decode(const RawData& data);
1298  virtual void decode(const uint8_t* data, size_t size);
1299  void clear();
1300  bool isModified() const;
1301  void removeMember(Object& parent, const Member& member);
1302  void remove(const Object& obj);
1303  Object& rootObject();
1304  Object& objectByUID(const UID& uid);
1305  void setAutoValue(Object& object, String value);
1306  void setIntValue(Object& object, int64_t value);
1307  void setRealValue(Object& object, double value);
1308  void setBoolValue(Object& object, bool value);
1309  void setEnumValue(Object& object, uint64_t value);
1310  void setStringValue(Object& object, String value);
1311  String valueAsString(const Object& object);
1312  int64_t valueAsInt(const Object& object);
1313  double valueAsReal(const Object& object);
1314  bool valueAsBool(const Object& object);
1315  void setVersion(Object& object, Version v);
1316  void setMinVersion(Object& object, Version v);
1317  String name() const;
1318  void setName(String name);
1319  String comment() const;
1320  void setComment(String comment);
1321  time_t timeStampCreated() const;
1322  time_t timeStampModified() const;
1323  tm dateTimeCreated(time_base_t base = LOCAL_TIME) const;
1324  tm dateTimeModified(time_base_t base = LOCAL_TIME) const;
1325  operation_t operation() const;
1326 
1327  protected:
1328  // UID resolver for non-pointer types
1329  template<typename T>
1330  class UIDChainResolver {
1331  public:
1332  UIDChainResolver(const T& data) {
1333  m_uid.push_back(UID::from(data));
1334  }
1335 
1336  operator UIDChain() const { return m_uid; }
1337  UIDChain operator()() const { return m_uid; }
1338  private:
1339  UIDChain m_uid;
1340  };
1341 
1342  // UID resolver for pointer types (of 1st degree)
1343  template<typename T>
1344  class UIDChainResolver<T*> {
1345  public:
1346  UIDChainResolver(const T*& data) {
1347  const UID uids[2] = {
1348  { &data, sizeof(data) },
1349  { data, sizeof(*data) }
1350  };
1351  m_uid.push_back(uids[0]);
1352  m_uid.push_back(uids[1]);
1353  }
1354 
1355  operator UIDChain() const { return m_uid; }
1356  UIDChain operator()() const { return m_uid; }
1357  private:
1358  UIDChain m_uid;
1359  };
1360 
1361  // SerializationRecursion for non-pointer class/struct types.
1362  template<typename T, bool T_isRecursive>
1363  struct SerializationRecursionImpl {
1364  static void serializeObject(Archive* archive, const T& obj) {
1365  const_cast<T&>(obj).serialize(archive);
1366  }
1367  };
1368 
1369  // SerializationRecursion for pointers (of 1st degree) to class/structs.
1370  template<typename T, bool T_isRecursive>
1371  struct SerializationRecursionImpl<T*,T_isRecursive> {
1372  static void serializeObject(Archive* archive, const T*& obj) {
1373  if (!obj) return;
1374  const_cast<T*&>(obj)->serialize(archive);
1375  }
1376  };
1377 
1378  // NOOP SerializationRecursion for primitive types.
1379  template<typename T>
1380  struct SerializationRecursionImpl<T,false> {
1381  static void serializeObject(Archive* archive, const T& obj) {}
1382  };
1383 
1384  // NOOP SerializationRecursion for pointers (of 1st degree) to primitive types.
1385  template<typename T>
1386  struct SerializationRecursionImpl<T*,false> {
1387  static void serializeObject(Archive* archive, const T*& obj) {}
1388  };
1389 
1390  // NOOP SerializationRecursion for String objects.
1391  template<bool T_isRecursive>
1392  struct SerializationRecursionImpl<String,T_isRecursive> {
1393  static void serializeObject(Archive* archive, const String& obj) {}
1394  };
1395 
1396  // NOOP SerializationRecursion for String pointers (of 1st degree).
1397  template<bool T_isRecursive>
1398  struct SerializationRecursionImpl<String*,T_isRecursive> {
1399  static void serializeObject(Archive* archive, const String*& obj) {}
1400  };
1401 
1402  // SerializationRecursion for Array<> objects.
1403  template<typename T, bool T_isRecursive>
1404  struct SerializationRecursionImpl<Array<T>,T_isRecursive> {
1405  static void serializeObject(Archive* archive, const Array<T>& obj) {
1406  const UIDChain uids = UIDChainResolver<Array<T>>(obj);
1407  const Object& object = archive->objectByUID(uids[0]);
1408  if (archive->operation() == OPERATION_SERIALIZE) {
1409  for (size_t i = 0; i < obj.size(); ++i) {
1410  archive->serializeHeapMember(
1411  obj, obj[i], ("[" + toString(i) + "]").c_str()
1412  );
1413  }
1414  } else {
1415  const_cast<Object&>(object).m_sync =
1416  [&obj,archive](Object& dstObj, const Object& srcObj,
1417  void* syncer)
1418  {
1419  const size_t n = srcObj.members().size();
1420  const_cast<Array<T>&>(obj).resize(n);
1421  for (size_t i = 0; i < obj.size(); ++i) {
1422  archive->serializeHeapMember(
1423  obj, obj[i], ("[" + toString(i) + "]").c_str()
1424  );
1425  }
1426  // updating dstObj required as serializeHeapMember()
1427  // replaced the original object by a new one
1428  dstObj = archive->objectByUID(dstObj.uid());
1429  for (size_t i = 0; i < obj.size(); ++i) {
1430  String name = "[" + toString(i) + "]";
1431  Member srcMember = srcObj.memberNamed(name);
1432  Member dstMember = dstObj.memberNamed(name);
1433  ((Syncer*)syncer)->syncMember(dstMember, srcMember);
1434  }
1435  };
1436  }
1437  }
1438  };
1439 
1440  // SerializationRecursion for Array<> pointers (of 1st degree).
1441  template<typename T, bool T_isRecursive>
1442  struct SerializationRecursionImpl<Array<T>*,T_isRecursive> {
1443  static void serializeObject(Archive* archive, const Array<T>*& obj) {
1444  if (!obj) return;
1445  SerializationRecursionImpl<Array<T>,T_isRecursive>::serializeObject(
1446  archive, *obj
1447  );
1448  }
1449  };
1450 
1451  // SerializationRecursion for Set<> objects.
1452  template<typename T, bool T_isRecursive>
1453  struct SerializationRecursionImpl<Set<T>,T_isRecursive> {
1454  static void serializeObject(Archive* archive, const Set<T>& obj) {
1455  const UIDChain uids = UIDChainResolver<Set<T>>(obj);
1456  const Object& object = archive->objectByUID(uids[0]);
1457  if (archive->operation() == OPERATION_SERIALIZE) {
1458  for (const T& key : obj) {
1459  archive->serializeHeapMember(
1460  obj, key, ("[" + toString(key) + "]").c_str()
1461  );
1462  }
1463  } else {
1464  const_cast<Object&>(object).m_sync =
1465  [&obj,archive](Object& dstObj, const Object& srcObj,
1466  void* syncer)
1467  {
1468  const size_t n = srcObj.members().size();
1469  const_cast<Set<T>&>(obj).clear();
1470  for (size_t i = 0; i < n; ++i) {
1471  const Member& member = srcObj.members()[i];
1472  String name = member.name();
1473  if (name.length() < 2 || name[0] != '[' ||
1474  *name.rbegin() != ']') continue;
1475  name = name.substr(1, name.length() - 2);
1476  T key;
1477  const UIDChain uids = UIDChainResolver<T>(key);
1478  const DataType type = DataType::dataTypeOf(key);
1479  Object tmpObj(uids, type);
1480  tmpObj.setNativeValueFromString(name);
1481  const_cast<Set<T>&>(obj).insert(key);
1482  }
1483  for (const T& key : obj) {
1484  archive->serializeHeapMember(
1485  obj, key, ("[" + toString(key) + "]").c_str()
1486  );
1487  }
1488  // updating dstObj required as serializeHeapMember()
1489  // replaced the original object by a new one
1490  dstObj = archive->objectByUID(dstObj.uid());
1491  };
1492  }
1493  }
1494  };
1495 
1496  // SerializationRecursion for Set<> pointers (of 1st degree).
1497  template<typename T, bool T_isRecursive>
1498  struct SerializationRecursionImpl<Set<T>*,T_isRecursive> {
1499  static void serializeObject(Archive* archive, const Set<T>*& obj) {
1500  if (!obj) return;
1501  SerializationRecursionImpl<Set<T>,T_isRecursive>::serializeObject(
1502  archive, *obj
1503  );
1504  }
1505  };
1506 
1507  // SerializationRecursion for Map<> objects.
1508  template<typename T_key, typename T_value, bool T_isRecursive>
1509  struct SerializationRecursionImpl<Map<T_key,T_value>,T_isRecursive> {
1510  static void serializeObject(Archive* archive, const Map<T_key,T_value>& obj) {
1511  const UIDChain uids = UIDChainResolver<Map<T_key,T_value>>(obj);
1512  const Object& object = archive->objectByUID(uids[0]);
1513  if (archive->operation() == OPERATION_SERIALIZE) {
1514  for (const auto& it : obj) {
1515  archive->serializeHeapMember(
1516  obj, it.second, ("[" + toString(it.first) + "]").c_str()
1517  );
1518  }
1519  } else {
1520  const_cast<Object&>(object).m_sync =
1521  [&obj,archive](Object& dstObj, const Object& srcObj,
1522  void* syncer)
1523  {
1524  const size_t n = srcObj.members().size();
1525  const_cast<Map<T_key,T_value>&>(obj).clear();
1526  for (size_t i = 0; i < n; ++i) {
1527  const Member& member = srcObj.members()[i];
1528  String name = member.name();
1529  if (name.length() < 2 || name[0] != '[' ||
1530  *name.rbegin() != ']') continue;
1531  name = name.substr(1, name.length() - 2);
1532  T_key key;
1533  const UIDChain uids = UIDChainResolver<T_key>(key);
1534  const DataType type = DataType::dataTypeOf(key);
1535  Object tmpObj(uids, type);
1536  tmpObj.setNativeValueFromString(name);
1537  const_cast<Map<T_key,T_value>&>(obj)[key] = T_value();
1538  }
1539  for (const auto& it : obj) {
1540  archive->serializeHeapMember(
1541  obj, it.second, ("[" + toString(it.first) + "]").c_str()
1542  );
1543  }
1544  // updating dstObj required as serializeHeapMember()
1545  // replaced the original object by a new one
1546  dstObj = archive->objectByUID(dstObj.uid());
1547  for (size_t i = 0; i < n; ++i) {
1548  Member srcMember = srcObj.members()[i];
1549  Member dstMember = dstObj.memberNamed(srcMember.name());
1550  ((Syncer*)syncer)->syncMember(dstMember, srcMember);
1551  }
1552  };
1553  }
1554  }
1555  };
1556 
1557  // SerializationRecursion for Map<> pointers (of 1st degree).
1558  template<typename T_key, typename T_value, bool T_isRecursive>
1559  struct SerializationRecursionImpl<Map<T_key,T_value>*,T_isRecursive> {
1560  static void serializeObject(Archive* archive, const Map<T_key,T_value>*& obj) {
1561  if (!obj) return;
1562  SerializationRecursionImpl<Map<T_key,T_value>,T_isRecursive>::serializeObject(
1563  archive, *obj
1564  );
1565  }
1566  };
1567 
1568  // Automatically handles recursion for class/struct types, while ignoring all primitive types.
1569  template<typename T>
1570  struct SerializationRecursion : SerializationRecursionImpl<T, LIBGIG_IS_CLASS(T)> {
1571  };
1572 
1573  class ObjectPool : public std::map<UID,Object> {
1574  public:
1575  // prevent passing obvious invalid UID values from creating a new pair entry
1576  Object& operator[](const UID& k) {
1577  static Object invalid;
1578  if (!k.isValid()) {
1579  invalid = Object();
1580  return invalid;
1581  }
1582  return std::map<UID,Object>::operator[](k);
1583  }
1584  };
1585 
1586  friend String _encode(const ObjectPool& objects);
1587 
1588  private:
1589  String _encodeRootBlob();
1590  void _popRootBlob(const char*& p, const char* end);
1591  void _popObjectsBlob(const char*& p, const char* end);
1592 
1593  protected:
1633  class Syncer {
1634  public:
1635  Syncer(Archive& dst, Archive& src);
1636  void syncObject(const Object& dst, const Object& src);
1637  void syncPrimitive(const Object& dst, const Object& src);
1638  void syncString(const Object& dst, const Object& src);
1639  void syncArray(const Object& dst, const Object& src);
1640  void syncSet(const Object& dst, const Object& src);
1641  void syncMap(const Object& dst, const Object& src);
1642  void syncPointer(const Object& dst, const Object& src);
1643  void syncMember(const Member& dstMember, const Member& srcMember);
1644  protected:
1645  static Member dstMemberMatching(const Object& dstObj, const Object& srcObj, const Member& srcMember);
1646  private:
1647  Archive& m_dst;
1648  Archive& m_src;
1649  };
1650 
1651  virtual void encode();
1652 
1653  ObjectPool m_allObjects;
1654  operation_t m_operation;
1655  UID m_root;
1656  RawData m_rawData;
1657  bool m_isModified;
1658  String m_name;
1659  String m_comment;
1660  time_t m_timeCreated;
1661  time_t m_timeModified;
1662  };
1663 
1668  class Exception {
1669  public:
1670  String Message;
1671 
1672  Exception(String format, ...);
1673  Exception(String format, va_list arg);
1674  void PrintMessage();
1675  virtual ~Exception() {}
1676 
1677  protected:
1678  Exception();
1679  static String assemble(String format, va_list arg);
1680  };
1681 
1682 } // namespace Serialization
1683 
1684 #endif // LIBGIG_SERIALIZATION_H
Synchronizes 2 archives with each other.
Destination container for serialization, and source container for deserialization.
void setStringValue(Object &object, String value)
Set new textual string for given String object.
void setRealValue(Object &object, double value)
Set new floating point value for given floating point object.
void serializeMember(const T_classType &nativeObject, const T_memberType &nativeMember, const char *memberName)
Serialize a native C/C++ member variable.
void setMinVersion(const T_classType &nativeObject, Version v)
Set a minimum version number for your C++ class.
void setName(String name)
Assign a name to this archive.
void serialize(const T *obj)
Initiate serialization.
time_t timeStampCreated() const
Date and time when this archive was initially created.
void setBoolValue(Object &object, bool value)
Set new boolean value for given boolean object.
void clear()
Clear content of this archive.
double valueAsReal(const Object &object)
Get floating point value of object.
time_t timeStampModified() const
Date and time when this archive was modified for the last time.
virtual String rawDataFormat() const
Name of the encoding format used by this Archive class.
void setIntValue(Object &object, int64_t value)
Set new integer value for given integer object.
operation_t
Current activity of Archive object.
@ OPERATION_DESERIALIZE
Archive is currently deserializing.
@ OPERATION_NONE
Archive is currently neither serializing, nor deserializing.
@ OPERATION_SERIALIZE
Archive is currently serializing.
const RawData & rawData()
Raw data stream of this archive content.
bool isModified() const
Whether this archive was modified.
void deserialize(T *obj)
Initiate deserialization.
virtual void decode(const RawData &data)
Fill this archive with the given serialized raw data.
tm dateTimeCreated(time_base_t base=LOCAL_TIME) const
Date and time when this archive was initially created.
Object & rootObject()
Root C++ object of this archive.
Object & objectByUID(const UID &uid)
Access object by its unique identifier.
String valueAsString(const Object &object)
Get value of object as string.
int64_t valueAsInt(const Object &object)
Get integer value of object.
void setVersion(const T_classType &nativeObject, Version v)
Set current version number for your C++ class.
void removeMember(Object &parent, const Member &member)
Remove a member variable from the given object.
void remove(const Object &obj)
Remove an object from this archive.
bool valueAsBool(const Object &object)
Get boolean value of object.
void setEnumValue(Object &object, uint64_t value)
Set new value for given enum object.
void serializeHeapMember(const T_classType &nativeObject, const T_memberType &heapMember, const char *memberName)
Serialize a C/C++ member variable allocated on the heap.
void operator<<(const T &obj)
Initiate serialization of your C++ objects.
void setComment(String comment)
Assign a comment to this archive.
Archive()
Create an "empty" archive.
String name() const
Optional name of this archive.
void setAutoValue(Object &object, String value)
Automatically cast and assign appropriate value to object.
String comment() const
Optional comments for this archive.
void operator>>(T &obj)
Initiate deserialization of your C++ objects.
tm dateTimeModified(time_base_t base=LOCAL_TIME) const
Date and time when this archive was modified for the last time.
Abstract reflection of a native C++ data type.
bool isPrimitive() const
Whether this is reflecting a fundamental C/C++ data type.
bool isSet() const
Whether this is a C++ Set<> object type.
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).
String asLongDescr() const
Human readable long description for this data type.
bool isBool() const
Whether this is a boolean C/C++ data type.
bool isMap() const
Whether this is a C++ Map<> object type.
bool isValid() const
Check if this is a valid DataType object.
bool isArray() const
Whether this is a C++ Array<> object type.
bool operator>(const DataType &other) const
Greater than comparison.
bool isEnum() const
Whether this is a C/C++ enum data type.
bool operator<(const DataType &other) const
Smaller than comparison.
String customTypeName2(bool demangle=false) const
The 2nd user defined C/C++ data type name of this data type.
bool isClass() const
Whether this is reflecting a C/C++ struct or class type.
bool isInteger() const
Whether this is an integer C/C++ data type.
bool operator==(const DataType &other) const
Comparison for equalness.
static DataType dataTypeOf(const T &data)
Construct a DataType object for the given native C++ data.
bool isString() const
Whether this is a C++ String data type.
String customTypeName(bool demangle=false) const
The 1st user defined C/C++ data type name of this data type.
size_t size() const
Returns native memory size of the respective C++ object or variable.
Will be thrown whenever an error occurs during an serialization or deserialization process.
void PrintMessage()
Print exception message to stdout.
Abstract reflection of a native C++ class/struct's member variable.
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.
std::vector< Member > & members()
All members of the original native C/C++ struct or class instance.
const DataType & type() const
C/C++ data type this Object is reflecting.
bool isVersionCompatibleTo(const Object &other) const
Check version compatibility between Object instances.
Version minVersion() const
Minimum version of original user defined C/C++ struct or class.
bool operator==(const Object &other) const
Comparison for equalness.
Unique identifier referring to one specific native C++ object, member, fundamental variable,...
static UID from(const T &obj)
Create an unique indentifier for a native C++ object/member/variable.
bool isValid() const
Check whether this is a valid unique identifier.
size_t size
Memory size of the object or member in question.
ID id
Abstract non-unique ID of the object or member in question.
Serialization / deserialization framework.
Definition: gig.h:98
bool IsUnion(const T &data)
Check whether data is a C++ union type.
void * ID
Abstract identifier for serialized C++ objects.
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.
bool IsEnum(const T &data)
Check whether data is a C/C++ enum type.
bool IsClass(const T &data)
Check whether data is a C/C++ struct or C++ class type.
std::string String
Textual string.
std::map< T_key, T_value > Map
Map<> template.
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...