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