Serialization.h
/***************************************************************************
* *
* Copyright (C) 2017-2025 Christian Schoenebeck *
* <cuse@users.sourceforge.net> *
* *
* This library is part of libgig. *
* *
* This library is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This library is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this library; if not, write to the Free Software *
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, *
* MA 02111-1307 USA *
***************************************************************************/
#ifndef LIBGIG_SERIALIZATION_H
#define LIBGIG_SERIALIZATION_H
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include <stdint.h>
#include <stdio.h>
#include <typeinfo>
#include <string>
#include <vector>
#include <map>
#include <set>
#include <time.h>
#include <stdarg.h>
#include <assert.h>
#include <functional>
#include <sstream>
#include <locale>
#include <limits>
#include "sysdef.h"
#ifndef __has_extension
# define __has_extension(x) 0
#endif
#ifndef HAS_BUILTIN_TYPE_TRAITS
# if __cplusplus >= 201103L
# define HAS_BUILTIN_TYPE_TRAITS 1
# elif ( __has_extension(is_class) && __has_extension(is_enum) )
# define HAS_BUILTIN_TYPE_TRAITS 1
# elif ( __GNUC__ > 4 || ( __GNUC__ == 4 && __GNUC_MINOR__ >= 3 ) )
# define HAS_BUILTIN_TYPE_TRAITS 1
# elif _MSC_VER >= 1400 /* MS Visual C++ 8.0 (Visual Studio 2005) */
# define HAS_BUILTIN_TYPE_TRAITS 1
# elif __INTEL_COMPILER >= 1100
# define HAS_BUILTIN_TYPE_TRAITS 1
# else
# define HAS_BUILTIN_TYPE_TRAITS 0
# endif
#endif
#if !HAS_BUILTIN_TYPE_TRAITS
# include <tr1/type_traits>
# define LIBGIG_IS_CLASS(type) std::tr1::__is_union_or_class<type>::value //NOTE: without compiler support we cannot distinguish union from class
#else
# define LIBGIG_IS_CLASS(type) __is_class(type)
#endif
namespace Serialization {
// just symbol prototyping
class DataType;
class Object;
class Member;
class Archive;
class ObjectPool;
class Exception;
typedef std::string String;
template<class T>
using Array = std::vector<T>;
template<class T>
using Set = std::set<T>;
template<class T_key, class T_value>
using Map = std::map<T_key,T_value>;
typedef std::vector<uint8_t> RawData;
typedef void* ID;
typedef uint32_t Version;
enum time_base_t {
LOCAL_TIME,
UTC_TIME
};
template<typename T>
bool IsEnum(const T& /*data*/) {
#if !HAS_BUILTIN_TYPE_TRAITS
return std::tr1::is_enum<T>::value;
#else
return __is_enum(T);
#endif
}
template<typename T>
bool IsUnion(const T& /*data*/) {
#if !HAS_BUILTIN_TYPE_TRAITS
return false; // without compiler support we cannot distinguish union from class
#else
return __is_union(T);
#endif
}
template<typename T>
bool IsClass(const T& /*data*/) {
#if !HAS_BUILTIN_TYPE_TRAITS
return std::tr1::__is_union_or_class<T>::value; // without compiler support we cannot distinguish union from class
#else
return __is_class(T);
#endif
}
/*template<typename T>
bool IsTrivial(T data) {
return __is_trivial(T);
}*/
/*template<typename T>
bool IsPOD(T data) {
return __is_pod(T);
}*/
/*template<typename T>
bool IsArray(const T& data) {
return false;
}*/
/*template<typename T>
bool IsArray(const Array<T>& data) {
return true;
}*/
// generalized C-locale guaranteed T to string conversion
template<typename T> inline
String toString(const T& value) {
//TODO: replace by locale-independent, maybe faster std::to_chars() [C++17]
std::stringstream ss;
ss.imbue(std::locale::classic()); // a.k.a. "C" locale
ss << value;
return ss.str();
}
// C-locale guaranteed double to string conversion
template<> inline
String toString(const double& value) {
//TODO: replace by locale-independent, maybe faster std::to_chars() [C++17]
std::stringstream ss;
ss.imbue(std::locale::classic()); // a.k.a. "C" locale
// stringstream has lower precision by default compared to std::to_string()
ss.precision(std::numeric_limits<double>::max_digits10);
ss << value;
return ss.str();
}
template<typename T> inline
String toString(T* ptr) {
std::stringstream ss;
ss.imbue(std::locale::classic()); // a.k.a. "C" locale
ss << "0x" << std::hex << size_t(ptr);
return ss.str();
}
template<> inline
String toString(const String& value) {
return value;
}
class UID {
public:
ID id;
size_t size;
bool isValid() const;
operator bool() const { return isValid(); }
//bool operator()() const { return isValid(); }
bool operator==(const UID& other) const { return id == other.id && size == other.size; }
bool operator!=(const UID& other) const { return id != other.id || size != other.size; }
bool operator<(const UID& other) const { return id < other.id || (id == other.id && size < other.size); }
bool operator>(const UID& other) const { return id > other.id || (id == other.id && size > other.size); }
template<typename T>
static UID from(const T& obj) {
return Resolver<T>::resolve(obj);
}
protected:
// UID resolver for non-pointer types
template<typename T>
struct Resolver {
static UID resolve(const T& obj);
};
// UID resolver for pointer types (of 1st degree)
template<typename T>
struct Resolver<T*> {
static UID resolve(const T* const & obj);
};
};
extern const UID NO_UID;
typedef std::vector<UID> UIDChain;
#if LIBGIG_SERIALIZATION_INTERNAL
// prototyping of private internal friend functions
static String _encodePrimitiveValue(const Object& obj);
static DataType _popDataTypeBlob(const char*& p, const char* end);
static Member _popMemberBlob(const char*& p, const char* end);
static Object _popObjectBlob(const char*& p, const char* end);
static void _popPrimitiveValue(const char*& p, const char* end, Object& obj);
static String _primitiveObjectValueToString(const Object& obj);
// |
template<typename T>
static T _primitiveObjectValueToNumber(const Object& obj);
#endif // LIBGIG_SERIALIZATION_INTERNAL
class DataType {
public:
DataType();
size_t size() const { return m_size; }
bool isValid() const;
bool isPointer() const;
bool isClass() const;
bool isPrimitive() const;
bool isString() const;
bool isInteger() const;
bool isReal() const;
bool isBool() const;
bool isEnum() const;
bool isArray() const;
bool isSet() const;
bool isMap() const;
bool isSigned() const;
operator bool() const { return isValid(); }
//bool operator()() const { return isValid(); }
bool operator==(const DataType& other) const;
bool operator!=(const DataType& other) const;
bool operator<(const DataType& other) const;
bool operator>(const DataType& other) const;
String asLongDescr() const;
String baseTypeName() const;
String customTypeName(bool demangle = false) const;
String customTypeName2(bool demangle = false) const;
template<typename T>
static DataType dataTypeOf(const T& data, bool registerType = true) {
const DataType type = Resolver<T>::resolve(data);
if (registerType)
registerNativeDataType(type, data);
return type;
}
template<typename T>
static DataType dataType(bool registerType = true) {
T unused = T();
const DataType type = Resolver<T>::resolve(unused);
if (registerType)
registerNativeDataType(type, unused);
return type;
}
template<typename T>
static size_t sizeOf(const T& data) {
DataType type = dataTypeOf(data);
const auto itNativeType = m_nativeTypes.find(type.internalID());
return (itNativeType != m_nativeTypes.end()) ?
itNativeType->second.size : sizeof(data);
}
template<typename T>
static void registerNativeDataType();
template<typename T>
class NativeDataTypeRegistry {
public:
NativeDataTypeRegistry() {
DataType::registerNativeDataType<T>();
}
};
protected:
DataType(bool isPointer, int size, String baseType,
String customType1 = "", String customType2 = "");
String internalID() const;
Object newInstance(Archive* archive) const;
template<typename T, typename std::enable_if<std::is_default_constructible<T>::value, bool>::type = true>
static void registerNativeDataType(const DataType& type, const T& nativeData);
template<typename T, typename std::enable_if<!std::is_default_constructible<T>::value, bool>::type = true>
static void registerNativeDataType(const DataType& type, const T& nativeData);
template<typename T, bool T_isPointer>
struct ResolverBase {
static DataType resolve(const T& data) {
// for pointers we must stick to the compile-time declared type
// of pointer to prevent potential type mismatches caused by
// RTTI in a polymorphic scenario
const std::type_info& type = (T_isPointer) ? typeid(T) : typeid(data);
const int sz = sizeof(data);
// for primitive types we are using our own type names instead of
// using std:::type_info::name(), because the precise output of the
// latter may vary between compilers
if (type == typeid(int8_t)) return DataType(T_isPointer, sz, "int8");
if (type == typeid(uint8_t)) return DataType(T_isPointer, sz, "uint8");
if (type == typeid(int16_t)) return DataType(T_isPointer, sz, "int16");
if (type == typeid(uint16_t)) return DataType(T_isPointer, sz, "uint16");
if (type == typeid(int32_t)) return DataType(T_isPointer, sz, "int32");
if (type == typeid(uint32_t)) return DataType(T_isPointer, sz, "uint32");
if (type == typeid(int64_t)) return DataType(T_isPointer, sz, "int64");
if (type == typeid(uint64_t)) return DataType(T_isPointer, sz, "uint64");
if (type == typeid(size_t)) {
if (sz == 1) return DataType(T_isPointer, sz, "uint8");
if (sz == 2) return DataType(T_isPointer, sz, "uint16");
if (sz == 4) return DataType(T_isPointer, sz, "uint32");
if (sz == 8) return DataType(T_isPointer, sz, "uint64");
else assert(false /* unknown size_t size */);
}
if (type == typeid(ssize_t)) {
if (sz == 1) return DataType(T_isPointer, sz, "int8");
if (sz == 2) return DataType(T_isPointer, sz, "int16");
if (sz == 4) return DataType(T_isPointer, sz, "int32");
if (sz == 8) return DataType(T_isPointer, sz, "int64");
else assert(false /* unknown ssize_t size */);
}
if (type == typeid(bool)) return DataType(T_isPointer, sz, "bool");
if (type == typeid(float)) return DataType(T_isPointer, sz, "real32");
if (type == typeid(double)) return DataType(T_isPointer, sz, "real64");
if (type == typeid(String)) return DataType(T_isPointer, sz, "String");
// for pointers we must stick to pointer's compile-time declared
// type and not use RTTI for the pointed object, because the
// latter would easily create a type mismatch conflict for
// pointers and objects in a polymorphic scenario, because the
// pointer might have been declared with a base class type,
// while actually assigned objects to these pointers might be of
// any other derived class and RTTI would resolve the latter
const String rawCppName =
(T_isPointer) ? rawCppTypeName<T>()
: rawCppTypeNameOf(data);
if (IsEnum(data)) return DataType(T_isPointer, sz, "enum", rawCppName);
if (IsUnion(data)) return DataType(T_isPointer, sz, "union", rawCppName);
if (IsClass(data)) return DataType(T_isPointer, sz, "class", rawCppName);
return DataType();
}
};
// DataType resolver for non-pointer types
template<typename T>
struct Resolver : ResolverBase<T,false> {
static DataType resolve(const T& data) {
return ResolverBase<T,false>::resolve(data);
}
};
// DataType resolver for pointer types (of 1st degree)
template<typename T>
struct Resolver<T*> : ResolverBase<T,true> {
static DataType resolve(const T* const & data) {
return ResolverBase<T,true>::resolve(*data);
}
};
// DataType resolver for non-pointer Array<> container object types.
template<typename T>
struct Resolver<Array<T>> {
static DataType resolve(const Array<T>& data) {
const int sz = sizeof(data);
T unused = T();
return DataType(false, sz, "Array", rawCppTypeNameOf(unused));
}
};
// DataType resolver for Array<> pointer types (of 1st degree).
template<typename T>
struct Resolver<Array<T>*> {
static DataType resolve(const Array<T>*& data) {
const int sz = sizeof(*data);
T unused = T();
return DataType(true, sz, "Array", rawCppTypeNameOf(unused));
}
};
// DataType resolver for non-pointer Set<> container object types.
template<typename T>
struct Resolver<Set<T>> {
static DataType resolve(const Set<T>& data) {
const int sz = sizeof(data);
T unused = T();
return DataType(false, sz, "Set", rawCppTypeNameOf(unused));
}
};
// DataType resolver for Set<> pointer types (of 1st degree).
template<typename T>
struct Resolver<Set<T>*> {
static DataType resolve(const Set<T>*& data) {
const int sz = sizeof(*data);
T unused = T();
return DataType(true, sz, "Set", rawCppTypeNameOf(unused));
}
};
// DataType resolver for non-pointer Map<> container object types.
template<typename T_key, typename T_value>
struct Resolver<Map<T_key,T_value>> {
static DataType resolve(const Map<T_key,T_value>& data) {
const int sz = sizeof(data);
T_key unused1 = T_key();
T_value unused2 = T_value();
return DataType(false, sz, "Map", rawCppTypeNameOf(unused1),
rawCppTypeNameOf(unused2));
}
};
// DataType resolver for Map<> pointer types (of 1st degree).
template<typename T_key, typename T_value>
struct Resolver<Map<T_key,T_value>*> {
static DataType resolve(const Map<T_key,T_value>*& data) {
const int sz = sizeof(*data);
T_key unused1 = T_key();
T_value unused2 = T_value();
return DataType(true, sz, "Map", rawCppTypeNameOf(unused1),
rawCppTypeNameOf(unused2));
}
};
// for compile-time known types
template<typename T>
static String rawCppTypeName() {
const std::type_info& type = typeid(T);
#if defined _MSC_VER // Microsoft compiler ...
String name = type.raw_name();
#else // i.e. especially GCC and clang ...
String name = type.name();
#endif
//while (!name.empty() && name[0] >= 0 && name[0] <= 9)
// name = name.substr(1);
return name;
}
// for RTTI resolved pointer types
template<typename T>
static String rawCppTypeNameOf(const T* const & data) {
return rawCppTypeName<T*>();
}
// for RTTI resolved non-pointer types
template<typename T>
static String rawCppTypeNameOf(const T& data) {
const std::type_info& type = typeid(data);
#if defined _MSC_VER // Microsoft compiler ...
String name = type.raw_name();
#else // i.e. especially GCC and clang ...
String name = type.name();
#endif
//while (!name.empty() && name[0] >= 0 && name[0] <= 9)
// name = name.substr(1);
return name;
}
private:
struct NativeType {
size_t size;
std::function<Object(Archive*)> allocFn;
};
String m_baseTypeName;
String m_customTypeName;
String m_customTypeName2;
int m_size;
bool m_isPointer;
static std::map<String,NativeType> m_nativeTypes;
#if LIBGIG_SERIALIZATION_INTERNAL
friend DataType _popDataTypeBlob(const char*& p, const char* end);
#endif
friend class Archive;
};
class Member {
public:
Member();
UID uid() const;
UID parentUID() const;
String name() const;
ssize_t offset() const;
const DataType& type() const;
bool isValid() const;
operator bool() const { return isValid(); }
//bool operator()() const { return isValid(); }
bool operator==(const Member& other) const;
bool operator!=(const Member& other) const;
bool operator<(const Member& other) const;
bool operator>(const Member& other) const;
protected:
Member(String name, UID uid, ssize_t offset, DataType type, const Object& parent);
friend class Archive;
private:
UID m_uid;
ssize_t m_offset;
String m_name;
DataType m_type;
UID m_parentUID;
#if LIBGIG_SERIALIZATION_INTERNAL
friend Member _popMemberBlob(const char*& p, const char* end);
#endif
};
class Object {
public:
Object();
Object(UIDChain uidChain, DataType type, const Object& parent);
UID uid(int index = 0) const;
const UIDChain& uidChain() const;
UID parentUID() const;
const DataType& type() const;
const RawData& rawData() const;
Version version() const;
Version minVersion() const;
bool isVersionCompatibleTo(const Object& other) const;
std::vector<Member>& members();
const std::vector<Member>& members() const;
Member memberNamed(String name) const;
Member memberByUID(const UID& uid) const;
std::vector<Member> membersOfType(const DataType& type) const;
int sequenceIndexOf(const Member& member) const;
bool isValid() const;
operator bool() const { return isValid(); }
//bool operator()() const { return isValid(); }
bool operator==(const Object& other) const;
bool operator!=(const Object& other) const;
bool operator<(const Object& other) const;
bool operator>(const Object& other) const;
void setNativeValueFromString(const String& s);
protected:
void remove(const Member& member);
void setVersion(Version v);
void setMinVersion(Version v);
private:
DataType m_type;
UIDChain m_uid;
UID m_parentUID;
Version m_version;
Version m_minVersion;
RawData m_data;
std::vector<Member> m_members;
std::function<void(Object& dstObj, const Object& srcObj, void* syncer)> m_sync;
#if LIBGIG_SERIALIZATION_INTERNAL
friend String _encodePrimitiveValue(const Object& obj);
friend Object _popObjectBlob(const char*& p, const char* end);
friend void _popPrimitiveValue(const char*& p, const char* end, Object& obj);
friend String _primitiveObjectValueToString(const Object& obj);
// |
template<typename T>
friend T _primitiveObjectValueToNumber(const Object& obj);
#endif // LIBGIG_SERIALIZATION_INTERNAL
friend class Archive;
};
class Archive {
public:
enum operation_t {
OPERATION_NONE,
OPERATION_SERIALIZE,
OPERATION_DESERIALIZE
};
Archive();
Archive(const RawData& data);
Archive(const uint8_t* data, size_t size);
virtual ~Archive();
template<typename T>
void serialize(const T* obj) {
m_operation = OPERATION_SERIALIZE;
m_allObjects.clear();
m_rawData.clear();
m_root = UID::from(obj);
const_cast<T*>(obj)->serialize(this);
encode();
m_operation = OPERATION_NONE;
}
template<typename T>
void deserialize(T* obj) {
Archive a;
a.m_operation = m_operation = OPERATION_DESERIALIZE;
obj->serialize(&a);
a.m_root = UID::from(obj);
Syncer s(a, *this);
a.m_operation = m_operation = OPERATION_NONE;
}
template<typename T>
void operator<<(const T& obj) {
serialize(&obj);
}
template<typename T>
void operator>>(T& obj) {
deserialize(&obj);
}
const RawData& rawData();
virtual String rawDataFormat() const;
template<typename T_classType, typename T_memberType>
void serializeMember(const T_classType& nativeObject, const T_memberType& nativeMember, const char* memberName) {
const ssize_t offset =
((const uint8_t*)(const void*)&nativeMember) -
((const uint8_t*)(const void*)&nativeObject);
const UIDChain uids = UIDChainResolver<T_memberType>(nativeMember);
const DataType type = DataType::dataTypeOf(nativeMember);
const UID parentUID = UID::from(nativeObject);
Object& parent = m_allObjects[parentUID];
if (!parent) {
const UIDChain uids = UIDChainResolver<T_classType>(nativeObject);
const DataType type = DataType::dataTypeOf(nativeObject);
parent = Object(uids, type, Object());
}
const Member member(memberName, uids[0], offset, type, parent);
std::vector<Member>& members = parent.members();
for (const Member& m : members)
assert(m.name() != memberName);
parent.members().push_back(member);
const Object obj(uids, type, parent);
const bool bExistsAlready = m_allObjects.count(uids[0]);
const bool isValidObject = obj;
const Object& existingObj = m_allObjects[uids[0]];
const bool bExistingObjectIsInvalid = !existingObj;
if (isValidObject && (
!bExistsAlready || bExistingObjectIsInvalid || (
obj.parentUID() && !existingObj.parentUID()
)
))
{
m_allObjects[uids[0]] = obj;
// recurse serialization for all members of this member
// (only for struct/class types, noop for primitive types)
SerializationRecursion<T_memberType>::serializeObject(this, nativeMember);
}
}
template<typename T_classType, typename T_memberType>
void serializeHeapMember(const T_classType& nativeObject, const T_memberType& heapMember, const char* memberName) {
const ssize_t offset = -1; // used for all members on heap
const UIDChain uids = UIDChainResolver<T_memberType>(heapMember);
const DataType type = DataType::dataTypeOf(heapMember);
const UID parentUID = UID::from(nativeObject);
Object& parent = m_allObjects[parentUID];
if (!parent) {
const UIDChain uids = UIDChainResolver<T_classType>(nativeObject);
const DataType type = DataType::dataTypeOf(nativeObject);
parent = Object(uids, type, Object());
}
const Member member(memberName, uids[0], offset, type, parent);
parent.members().push_back(member);
const Object obj(uids, type, parent);
const bool bExistsAlready = m_allObjects.count(uids[0]);
const bool isValidObject = obj;
const Object& existingObj = m_allObjects[uids[0]];
const bool bExistingObjectIsInvalid = !existingObj;
if (isValidObject && (
!bExistsAlready || bExistingObjectIsInvalid || (
obj.parentUID() && !existingObj.parentUID()
)
))
{
m_allObjects[uids[0]] = obj;
// recurse serialization for all members of this member
// (only for struct/class types, noop for primitive types)
SerializationRecursion<T_memberType>::serializeObject(this, heapMember);
}
}
template<typename T_objectType>
void serializeAnonymousObject(const T_objectType& heapObject) {
const UIDChain uids = UIDChainResolver<T_objectType>(heapObject);
const DataType type = DataType::dataTypeOf(heapObject);
const Object obj(uids, type, Object());
const bool bExistsAlready = m_allObjects.count(uids[0]);
const bool isValidObject = obj;
const Object& existingObj = m_allObjects[uids[0]];
const bool bExistingObjectIsInvalid = !existingObj;
if (isValidObject && (
!bExistsAlready || bExistingObjectIsInvalid || (
obj.parentUID() && !existingObj.parentUID()
)
))
{
m_allObjects[uids[0]] = obj;
// recurse serialization for all members of this object
// (only for struct/class types, noop for primitive types)
SerializationRecursion<T_objectType>::serializeObject(this, heapObject);
}
}
template<typename T_classType>
void setVersion(const T_classType& nativeObject, Version v) {
const UID uid = UID::from(nativeObject);
Object& obj = m_allObjects[uid];
if (!obj) {
const UIDChain uids = UIDChainResolver<T_classType>(nativeObject);
const DataType type = DataType::dataTypeOf(nativeObject);
obj = Object(uids, type, Object());
}
setVersion(obj, v);
}
template<typename T_classType>
void setMinVersion(const T_classType& nativeObject, Version v) {
const UID uid = UID::from(nativeObject);
Object& obj = m_allObjects[uid];
if (!obj) {
const UIDChain uids = UIDChainResolver<T_classType>(nativeObject);
const DataType type = DataType::dataTypeOf(nativeObject);
obj = Object(uids, type, Object());
}
setMinVersion(obj, v);
}
virtual void decode(const RawData& data);
virtual void decode(const uint8_t* data, size_t size);
void clear();
bool isModified() const;
void removeMember(Object& parent, const Member& member);
void remove(const Object& obj);
Object& rootObject();
Object& objectByUID(const UID& uid);
Object& parentObjectOf(const Object& obj);
Object& parentObjectOf(const Member& member);
void setAutoValue(Object& object, String value);
void setIntValue(Object& object, int64_t value);
void setRealValue(Object& object, double value);
void setBoolValue(Object& object, bool value);
void setEnumValue(Object& object, uint64_t value);
void setStringValue(Object& object, String value);
String valueAsString(const Object& object);
int64_t valueAsInt(const Object& object);
double valueAsReal(const Object& object);
bool valueAsBool(const Object& object);
void setVersion(Object& object, Version v);
void setMinVersion(Object& object, Version v);
String name() const;
void setName(String name);
String comment() const;
void setComment(String comment);
time_t timeStampCreated() const;
time_t timeStampModified() const;
tm dateTimeCreated(time_base_t base = LOCAL_TIME) const;
tm dateTimeModified(time_base_t base = LOCAL_TIME) const;
operation_t operation() const;
protected:
Object& objectByBaseUID(const UID& uid);
// UID resolver for non-pointer types
template<typename T>
class UIDChainResolver {
public:
UIDChainResolver(const T& data) {
m_uid.push_back(UID::from(data));
}
operator UIDChain() const { return m_uid; }
UIDChain operator()() const { return m_uid; }
private:
UIDChain m_uid;
};
// UID resolver for pointer types (of 1st degree)
template<typename T>
class UIDChainResolver<T*> {
public:
UIDChainResolver(const T* const & data) {
m_uid.push_back({ (ID) &data, sizeof(data) });
if (data)
m_uid.push_back(UID::from(*data));
else
m_uid.push_back({ (ID) data, sizeof(*data) });
}
operator UIDChain() const { return m_uid; }
UIDChain operator()() const { return m_uid; }
private:
UIDChain m_uid;
};
// SerializationRecursion for non-pointer class/struct types.
template<typename T, bool T_isRecursive>
struct SerializationRecursionImpl {
static void serializeObject(Archive* archive, const T& obj) {
const_cast<T&>(obj).serialize(archive);
}
};
// SerializationRecursion for pointers (of 1st degree) to class/structs.
template<typename T, bool T_isRecursive>
struct SerializationRecursionImpl<T*,T_isRecursive> {
static void serializeObject(Archive* archive, const T*& obj) {
if (!obj) return;
const_cast<T*&>(obj)->serialize(archive);
}
};
// NOOP SerializationRecursion for primitive types.
template<typename T>
struct SerializationRecursionImpl<T,false> {
static void serializeObject(Archive* /*archive*/, const T& /*obj*/) {}
};
// SerializationRecursion for pointers (of 1st degree) to primitive types.
template<typename T>
struct SerializationRecursionImpl<T*,false> {
static void serializeObject(Archive* archive, const T* const & obj) {
if (!obj) return;
archive->serializeAnonymousObject(*obj);
}
};
// NOOP SerializationRecursion for String objects.
template<bool T_isRecursive>
struct SerializationRecursionImpl<String,T_isRecursive> {
static void serializeObject(Archive* archive, const String& obj) {}
};
// SerializationRecursion for String pointers (of 1st degree).
template<bool T_isRecursive>
struct SerializationRecursionImpl<String*,T_isRecursive> {
static void serializeObject(Archive* archive, const String*& obj) {
if (!obj) return;
archive->serializeAnonymousObject(*obj);
}
};
// SerializationRecursion for Array<> objects.
template<typename T, bool T_isRecursive>
struct SerializationRecursionImpl<Array<T>,T_isRecursive> {
static void serializeObject(Archive* archive, const Array<T>& obj) {
const UIDChain uids = UIDChainResolver<Array<T>>(obj);
const Object& object = archive->objectByUID(uids[0]);
if (archive->operation() == OPERATION_SERIALIZE) {
for (size_t i = 0; i < obj.size(); ++i) {
archive->serializeHeapMember(
obj, obj[i], ("[" + toString(i) + "]").c_str()
);
}
} else {
const_cast<Object&>(object).m_sync =
[&obj,archive](Object& dstObj, const Object& srcObj,
void* syncer)
{
const size_t n = srcObj.members().size();
const_cast<Array<T>&>(obj).resize(n);
for (size_t i = 0; i < n; ++i) {
archive->serializeHeapMember(
obj, obj[i], ("[" + toString(i) + "]").c_str()
);
}
// updating dstObj required as serializeHeapMember()
// replaced the original object by a new one
dstObj = archive->objectByUID(dstObj.uid());
for (size_t i = 0; i < n; ++i) {
String name = "[" + toString(i) + "]";
Member srcMember = srcObj.memberNamed(name);
Member dstMember = dstObj.memberNamed(name);
((Syncer*)syncer)->syncMember(dstMember, srcMember);
}
};
}
}
};
// SerializationRecursion for Array<> pointers (of 1st degree).
template<typename T, bool T_isRecursive>
struct SerializationRecursionImpl<Array<T>*,T_isRecursive> {
static void serializeObject(Archive* archive, const Array<T>*& obj) {
if (!obj) return;
SerializationRecursionImpl<Array<T>,T_isRecursive>::serializeObject(
archive, *obj
);
}
};
// SerializationRecursion for Set<> objects.
template<typename T, bool T_isRecursive>
struct SerializationRecursionImpl<Set<T>,T_isRecursive> {
static void serializeObject(Archive* archive, const Set<T>& obj) {
const UIDChain uids = UIDChainResolver<Set<T>>(obj);
const Object& object = archive->objectByUID(uids[0]);
if (archive->operation() == OPERATION_SERIALIZE) {
for (const T& key : obj) {
archive->serializeHeapMember(
obj, key, ("[" + toString(key) + "]").c_str()
);
}
} else {
const_cast<Object&>(object).m_sync =
[&obj,archive](Object& dstObj, const Object& srcObj,
void* syncer)
{
const size_t n = srcObj.members().size();
const_cast<Set<T>&>(obj).clear();
for (size_t i = 0; i < n; ++i) {
const Member& member = srcObj.members()[i];
String name = member.name();
// strip brackets from name
if (name.length() < 2 || name[0] != '[' ||
*name.rbegin() != ']') continue;
name = name.substr(1, name.length() - 2);
T key = T();
const UIDChain uids = UIDChainResolver<T>(key);
const DataType type = DataType::dataTypeOf(key);
Object tmpObj(uids, type, Object());
// set the value of "key" variable by abstraction API
tmpObj.setNativeValueFromString(name);
// only for keys of pointer type: translation of
// memory address from source archive to destination
// archive required, NOOP for all other data types
((Syncer*)syncer)->translateKey(key);
// insert (translated) key into set
const_cast<Set<T>&>(obj).insert(key);
}
// continue serialization recursion
for (const T& key : obj) {
archive->serializeHeapMember(
obj, key, ("[" + toString(key) + "]").c_str()
);
}
// updating dstObj required as serializeHeapMember()
// replaced the original object by a new one
dstObj = archive->objectByUID(dstObj.uid());
};
}
}
};
// SerializationRecursion for Set<> pointers (of 1st degree).
template<typename T, bool T_isRecursive>
struct SerializationRecursionImpl<Set<T>*,T_isRecursive> {
static void serializeObject(Archive* archive, const Set<T>*& obj) {
if (!obj) return;
SerializationRecursionImpl<Set<T>,T_isRecursive>::serializeObject(
archive, *obj
);
}
};
// SerializationRecursion for Map<> objects.
template<typename T_key, typename T_value, bool T_isRecursive>
struct SerializationRecursionImpl<Map<T_key,T_value>,T_isRecursive> {
static void serializeObject(Archive* archive, const Map<T_key,T_value>& obj) {
const UIDChain uids = UIDChainResolver<Map<T_key,T_value>>(obj);
const Object& object = archive->objectByUID(uids[0]);
if (archive->operation() == OPERATION_SERIALIZE) {
for (const auto& it : obj) {
// recurse serialization for map's key ...
SerializationRecursion<T_key>::serializeObject(archive, it.first);
// ... and map's value
archive->serializeHeapMember(
obj, it.second, ("[" + toString(it.first) + "]").c_str()
);
}
} else {
const_cast<Object&>(object).m_sync =
[&obj,archive](Object& dstObj, const Object& srcObj,
void* syncer)
{
const size_t n = srcObj.members().size();
const_cast<Map<T_key,T_value>&>(obj).clear();
// translation is neutral except for keys of pointer type (see comments below)
std::map<String,String> memberNameTranslation;
for (size_t i = 0; i < n; ++i) {
const Member& member = srcObj.members()[i];
String name = member.name();
// strip brackets from name
if (name.length() < 2 || name[0] != '[' ||
*name.rbegin() != ']') continue;
name = name.substr(1, name.length() - 2);
T_key srcKey = T_key();
const UIDChain uids = UIDChainResolver<T_key>(srcKey);
const DataType type = DataType::dataTypeOf(srcKey);
Object tmpObj(uids, type, Object());
// set the value of "srcKey" variable by abstraction API
tmpObj.setNativeValueFromString(name);
T_key dstKey = srcKey;
// only for keys of pointer type: translation of
// memory address from source archive to destination
// archive required, NOOP for all other data types
((Syncer*)syncer)->translateKey(dstKey);
memberNameTranslation[member.name()] = "[" + toString(dstKey) + "]";
// insert (translated) key into the destination map
const_cast<Map<T_key,T_value>&>(obj)[dstKey] = T_value();
}
// continue serialization recursion ...
for (const auto& it : obj) {
// ... for map's key ...
SerializationRecursion<T_key>::serializeObject(archive, it.first);
// ... and map's value
archive->serializeHeapMember(
obj, it.second, ("[" + toString(it.first) + "]").c_str()
);
}
// updating dstObj required as serializeHeapMember()
// replaced the original object by a new one
dstObj = archive->objectByUID(dstObj.uid());
// sync map's values
for (size_t i = 0; i < n; ++i) {
Member srcMember = srcObj.members()[i];
Member dstMember = dstObj.memberNamed(
memberNameTranslation[srcMember.name()]
);
((Syncer*)syncer)->syncMember(dstMember, srcMember);
}
};
}
}
};
// SerializationRecursion for Map<> pointers (of 1st degree).
template<typename T_key, typename T_value, bool T_isRecursive>
struct SerializationRecursionImpl<Map<T_key,T_value>*,T_isRecursive> {
static void serializeObject(Archive* archive, const Map<T_key,T_value>*& obj) {
if (!obj) return;
SerializationRecursionImpl<Map<T_key,T_value>,T_isRecursive>::serializeObject(
archive, *obj
);
}
};
// Automatically handles recursion for class/struct types, while ignoring all primitive types.
template<typename T>
struct SerializationRecursion : SerializationRecursionImpl<T, LIBGIG_IS_CLASS(T)> {
};
class ObjectPool : public std::map<UID,Object> {
public:
// prevent passing obvious invalid UID values from creating a new pair entry
Object& operator[](const UID& k) {
if (!k.isValid())
return invalidObject();
return std::map<UID,Object>::operator[](k);
}
static Object& invalidObject() {
static Object invalid;
invalid = Object();
return invalid;
}
};
friend String _encode(const ObjectPool& objects);
private:
String _encodeRootBlob();
void _popRootBlob(const char*& p, const char* end);
void _popObjectsBlob(const char*& p, const char* end);
protected:
class Syncer {
public:
Syncer(Archive& dst, Archive& src);
void syncObject(const Object& dst, const Object& src);
void syncPrimitive(const Object& dst, const Object& src);
void syncString(const Object& dst, const Object& src);
void syncArray(const Object& dst, const Object& src);
void syncSet(const Object& dst, const Object& src);
void syncMap(const Object& dst, const Object& src);
void syncPointer(const Object& dst, const Object& src);
void syncMember(const Member& dstMember, const Member& srcMember);
// Address translation for keys of pointer type.
//
// Translates memory address from source archive, to memory address
// of destination archive. For "strong" pointers memory is allocated
// and the pointed data is synced with data from source archive.
template<typename T>
void translateKey(T*& key) {
if (!key) return; // NULL pointer on source side
// UIDChainResolver can't be used here, since the passed memory
// address is an abstract one that originates from the source
// archive (e.g. potentially even from another machine) and
// UIDChainResolver would then crash on its typeid() operator.
UID uid = { (ID) key, sizeof(*key) };
const Object& pointedSrcObject = m_src.objectByBaseUID(uid);
assert(pointedSrcObject);
std::map<UID,UID>::iterator uidRelation = m_counterparts.find(uid);
if (pointedSrcObject.parentUID() || uidRelation != m_counterparts.end()) { // "weak" pointer to object ...
assert(uidRelation != m_counterparts.end());
key = (T*) uidRelation->second.id;
} else { // "strong" pointer to object, allocation required ...
assert(pointedSrcObject.type());
Object pointedDstObject = pointedSrcObject.type().newInstance(&m_dst);
assert(pointedDstObject);
m_dst.m_allObjects[pointedDstObject.uid()] = pointedDstObject;
key = (T*) pointedDstObject.uid().id;
syncObject(pointedDstObject, pointedSrcObject);
}
}
// NOOP, no key translation required for any other type
template<typename T>
void translateKey(T& key) {}
protected:
static Member dstMemberMatching(const Object& dstObj, const Object& srcObj, const Member& srcMember);
private:
Archive& m_dst;
Archive& m_src;
std::map<UID,UID> m_counterparts;
};
virtual void encode();
ObjectPool m_allObjects;
operation_t m_operation;
UID m_root;
RawData m_rawData;
bool m_isModified;
String m_name;
String m_comment;
time_t m_timeCreated;
time_t m_timeModified;
friend class DataType;
};
// UID resolver implementation for non-pointer types
template<typename T>
UID UID::Resolver<T>::resolve(const T& obj) {
const size_t size = DataType::sizeOf(obj);
const UID uid = { (ID) &obj, size };
return uid;
}
// UID resolver implementation for pointer types (of 1st degree)
template<typename T>
UID UID::Resolver<T*>::resolve(const T* const & obj) {
const size_t size = DataType::sizeOf(*obj);
const UID uid = { (ID) obj, size };
return uid;
}
// Manual registration of native data types by application.
template<typename T>
void DataType::registerNativeDataType() {
static_assert(
std::is_default_constructible<T>::value,
"missing default constructor for type: registration of data "
"types is only needed for creating instances of that type at "
"runtime by this framework's reflection API; which in turn "
"requires the type to provide a default constructor."
);
const DataType staticType = DataType::dataType<T>(false);
assert(staticType);
const auto itType = m_nativeTypes.find(staticType.internalID());
if (itType != m_nativeTypes.end()) {
assert(itType->second.size >= sizeof(T));
return;
}
// register lambda function for allocating a new instance of this type
m_nativeTypes[staticType.internalID()] = {
/*.size =*/ sizeof(T),
/*.allocFn =*/ [](Archive* archive) -> Object {
T* instance = new T;
Archive::SerializationRecursion<T>::serializeObject(archive, *instance);
const UIDChain uids = Archive::UIDChainResolver<T>(*instance);
Object& obj = archive->objectByUID(uids[0]);
if (obj) return obj;
const DataType type = DataType::dataTypeOf(*instance);
return Object(uids, type, Object());
}
};
}
// Automatic self-registration of native data types by this framework.
// (SFINAE variant for types WITH default constructor)
template<typename T, typename std::enable_if<std::is_default_constructible<T>::value, bool>::type>
void DataType::registerNativeDataType(const DataType& rttiType, const T& nativeData) {
if (!rttiType) return;
if (m_nativeTypes.find(rttiType.internalID()) != m_nativeTypes.end())
return;
// Ensure compile-time native data type 'T' matches passed runtime
// native data type 'nativeData', because we can only offer to create
// new instances of native data types by our reflection API if this
// framework is aware about the data type already. Usually this happens
// automatically without applications having to do anything. But
// this only works for types this framework gets in touch with at
// compile-time.
//
// Root problem of all of this: ATM there is no way in C++ to create new
// instances of a type by using RTTI (typeid(), std::type_info, etc.).
// If there is a way in a future C++ version then we can get rid of
// manual type registration altogether. Bur for now we must use new T,
// which is a compile-time only construct.
//
// See the discussion in DataType::registerNativeDataType() for an
// example where manual type registration would be required.
const DataType staticType = DataType::dataType<T>(false);
if (staticType != rttiType) {
fprintf(stderr, "Serialization Failure: run-time data type '%s' does not match compile-time data type '%s'!\n",
rttiType.asLongDescr().c_str(),
staticType.asLongDescr().c_str());
assert(false && "You may need to explicitly register this run-time "
"data type by either calling "
"DataType::registerNativeType<T>() or using class "
"NativeDataTypeRegistry");
}
// register lambda function for allocating a new instance of this type
m_nativeTypes[rttiType.internalID()] = {
/*.size =*/ sizeof(T),
/*.allocFn =*/ [](Archive* archive) -> Object {
T* instance = new T;
Archive::SerializationRecursion<T>::serializeObject(archive, *instance);
const UIDChain uids = Archive::UIDChainResolver<T>(*instance);
Object& obj = archive->objectByUID(uids[0]);
if (obj) return obj;
const DataType type = DataType::dataTypeOf(*instance);
return Object(uids, type, Object());
}
};
}
// Automatic self-registration of native data types by this framework.
// (SFINAE variant for types WITHOUT default constructor)
template<typename T, typename std::enable_if<!std::is_default_constructible<T>::value, bool>::type>
void DataType::registerNativeDataType(const DataType& type, const T& nativeData) {
if (!type) return;
if (m_nativeTypes.find(type.internalID()) != m_nativeTypes.end())
return;
m_nativeTypes[type.internalID()] = {
/*.size =*/ sizeof(T),
/*.allocFn =*/ [](Archive*) -> Object {
assert(false && "instance not possible: native data type does not have default constructor");
return Object();
}
};
}
class Exception {
public:
String Message;
Exception(String format, ...);
Exception(String format, va_list arg);
void PrintMessage() const;
virtual ~Exception() {}
protected:
Exception();
static String assemble(String format, va_list arg);
};
} // namespace Serialization
#endif // LIBGIG_SERIALIZATION_H
Serialization::Archive::Syncer
Synchronizes 2 archives with each other.
Definition Serialization.h:1932
Serialization::Archive
Destination container for serialization, and source container for deserialization.
Definition Serialization.h:1096
Serialization::Archive::setStringValue
void setStringValue(Object &object, String value)
Set new textual string for given String object.
Definition Serialization.cpp:2517
Serialization::Archive::setRealValue
void setRealValue(Object &object, double value)
Set new floating point value for given floating point object.
Definition Serialization.cpp:2462
Serialization::Archive::serializeMember
void serializeMember(const T_classType &nativeObject, const T_memberType &nativeMember, const char *memberName)
Serialize a native C/C++ member variable.
Definition Serialization.h:1283
Serialization::Archive::setMinVersion
void setMinVersion(const T_classType &nativeObject, Version v)
Set a minimum version number for your C++ class.
Definition Serialization.h:1544
Serialization::Archive::setName
void setName(String name)
Assign a name to this archive.
Definition Serialization.cpp:2121
Serialization::Archive::serialize
void serialize(const T *obj)
Initiate serialization.
Definition Serialization.h:1137
Serialization::Archive::timeStampCreated
time_t timeStampCreated() const
Date and time when this archive was initially created.
Definition Serialization.cpp:2175
Serialization::Archive::setBoolValue
void setBoolValue(Object &object, bool value)
Set new boolean value for given boolean object.
Definition Serialization.cpp:2492
Serialization::Archive::clear
void clear()
Clear content of this archive.
Definition Serialization.cpp:2092
Serialization::Archive::valueAsReal
double valueAsReal(const Object &object)
Get floating point value of object.
Definition Serialization.cpp:2624
Serialization::Archive::timeStampModified
time_t timeStampModified() const
Date and time when this archive was modified for the last time.
Definition Serialization.cpp:2184
Serialization::Archive::rawDataFormat
virtual String rawDataFormat() const
Name of the encoding format used by this Archive class.
Definition Serialization.cpp:2065
Serialization::Archive::setIntValue
void setIntValue(Object &object, int64_t value)
Set new integer value for given integer object.
Definition Serialization.cpp:2412
Serialization::Archive::operation_t
operation_t
Current activity of Archive object.
Definition Serialization.h:1100
Serialization::Archive::OPERATION_DESERIALIZE
@ OPERATION_DESERIALIZE
Archive is currently deserializing.
Definition Serialization.h:1103
Serialization::Archive::OPERATION_NONE
@ OPERATION_NONE
Archive is currently neither serializing, nor deserializing.
Definition Serialization.h:1101
Serialization::Archive::OPERATION_SERIALIZE
@ OPERATION_SERIALIZE
Archive is currently serializing.
Definition Serialization.h:1102
Serialization::Archive::rawData
const RawData & rawData()
Raw data stream of this archive content.
Definition Serialization.cpp:2055
Serialization::Archive::isModified
bool isModified() const
Whether this archive was modified.
Definition Serialization.cpp:2083
Serialization::Archive::deserialize
void deserialize(T *obj)
Initiate deserialization.
Definition Serialization.h:1172
Serialization::Archive::decode
virtual void decode(const RawData &data)
Fill this archive with the given serialized raw data.
Definition Serialization.cpp:2000
Serialization::Archive::serializeAnonymousObject
void serializeAnonymousObject(const T_objectType &heapObject)
Serialize anonymous C/C++ data.
Definition Serialization.h:1402
Serialization::Archive::dateTimeCreated
tm dateTimeCreated(time_base_t base=LOCAL_TIME) const
Date and time when this archive was initially created.
Definition Serialization.cpp:2198
Serialization::Archive::rootObject
Object & rootObject()
Root C++ object of this archive.
Definition Serialization.cpp:1426
Serialization::Archive::objectByUID
Object & objectByUID(const UID &uid)
Access object by its unique identifier.
Definition Serialization.cpp:2272
Serialization::Archive::valueAsString
String valueAsString(const Object &object)
Get value of object as string.
Definition Serialization.cpp:2578
Serialization::Archive::valueAsInt
int64_t valueAsInt(const Object &object)
Get integer value of object.
Definition Serialization.cpp:2601
Serialization::Archive::setVersion
void setVersion(const T_classType &nativeObject, Version v)
Set current version number for your C++ class.
Definition Serialization.h:1503
Serialization::Archive::objectByBaseUID
Object & objectByBaseUID(const UID &uid)
Find true object for a base pointer.
Definition Serialization.cpp:2290
Serialization::Archive::removeMember
void removeMember(Object &parent, const Member &member)
Remove a member variable from the given object.
Definition Serialization.cpp:2233
Serialization::Archive::remove
void remove(const Object &obj)
Remove an object from this archive.
Definition Serialization.cpp:2253
Serialization::Archive::valueAsBool
bool valueAsBool(const Object &object)
Get boolean value of object.
Definition Serialization.cpp:2646
Serialization::Archive::setEnumValue
void setEnumValue(Object &object, uint64_t value)
Set new value for given enum object.
Definition Serialization.cpp:2370
Serialization::Archive::serializeHeapMember
void serializeHeapMember(const T_classType &nativeObject, const T_memberType &heapMember, const char *memberName)
Serialize a C/C++ member variable allocated on the heap.
Definition Serialization.h:1350
Serialization::Archive::parentObjectOf
Object & parentObjectOf(const Object &obj)
Access parent of supplied object.
Definition Serialization.cpp:2317
Serialization::Archive::operator<<
void operator<<(const T &obj)
Initiate serialization of your C++ objects.
Definition Serialization.h:1196
Serialization::Archive::setComment
void setComment(String comment)
Assign a comment to this archive.
Definition Serialization.cpp:2147
Serialization::Archive::Archive
Archive()
Create an "empty" archive.
Definition Serialization.cpp:1355
Serialization::Archive::name
String name() const
Optional name of this archive.
Definition Serialization.cpp:2108
Serialization::Archive::setAutoValue
void setAutoValue(Object &object, String value)
Automatically cast and assign appropriate value to object.
Definition Serialization.cpp:2546
Serialization::Archive::comment
String comment() const
Optional comments for this archive.
Definition Serialization.cpp:2134
Serialization::Archive::operator>>
void operator>>(T &obj)
Initiate deserialization of your C++ objects.
Definition Serialization.h:1219
Serialization::Archive::dateTimeModified
tm dateTimeModified(time_base_t base=LOCAL_TIME) const
Date and time when this archive was modified for the last time.
Definition Serialization.cpp:2212
Serialization::DataType
Abstract reflection of a native C++ data type.
Definition Serialization.h:457
Serialization::DataType::isPrimitive
bool isPrimitive() const
Whether this is reflecting a fundamental C/C++ data type.
Definition Serialization.cpp:209
Serialization::DataType::isSet
bool isSet() const
Whether this is a C++ Set<> object type.
Definition Serialization.cpp:320
Serialization::DataType::dataTypeOf
static DataType dataTypeOf(const T &data, bool registerType=true)
Construct a DataType object for the given native C++ data.
Definition Serialization.h:501
Serialization::DataType::isPointer
bool isPointer() const
Whether this is reflecting a C/C++ pointer type.
Definition Serialization.cpp:156
Serialization::DataType::isSigned
bool isSigned() const
Whether this is a signed integer C/C++ data type.
Definition Serialization.cpp:353
Serialization::DataType::baseTypeName
String baseTypeName() const
The base type name of this data type.
Definition Serialization.cpp:505
Serialization::DataType::operator!=
bool operator!=(const DataType &other) const
Comparison for inequalness.
Definition Serialization.cpp:409
Serialization::DataType::isReal
bool isReal() const
Whether this is a floating point based C/C++ data type.
Definition Serialization.cpp:258
Serialization::DataType::DataType
DataType()
Default constructor (as "invalid" DataType).
Definition Serialization.cpp:95
Serialization::DataType::registerNativeDataType
static void registerNativeDataType()
Manual registration of native C++ data types.
Definition Serialization.h:2020
Serialization::DataType::asLongDescr
String asLongDescr() const
Human readable long description for this data type.
Definition Serialization.cpp:465
Serialization::DataType::isBool
bool isBool() const
Whether this is a boolean C/C++ data type.
Definition Serialization.cpp:273
Serialization::DataType::sizeOf
static size_t sizeOf(const T &data)
True size of passed native data in bytes.
Definition Serialization.h:540
Serialization::DataType::isMap
bool isMap() const
Whether this is a C++ Map<> object type.
Definition Serialization.cpp:336
Serialization::DataType::isValid
bool isValid() const
Check if this is a valid DataType object.
Definition Serialization.cpp:147
Serialization::DataType::isArray
bool isArray() const
Whether this is a C++ Array<> object type.
Definition Serialization.cpp:304
Serialization::DataType::operator>
bool operator>(const DataType &other) const
Greater than comparison.
Definition Serialization.cpp:447
Serialization::DataType::isEnum
bool isEnum() const
Whether this is a C/C++ enum data type.
Definition Serialization.cpp:288
Serialization::DataType::operator<
bool operator<(const DataType &other) const
Smaller than comparison.
Definition Serialization.cpp:424
Serialization::DataType::customTypeName2
String customTypeName2(bool demangle=false) const
The 2nd user defined C/C++ data type name of this data type.
Definition Serialization.cpp:580
Serialization::DataType::isClass
bool isClass() const
Whether this is reflecting a C/C++ struct or class type.
Definition Serialization.cpp:185
Serialization::DataType::isInteger
bool isInteger() const
Whether this is an integer C/C++ data type.
Definition Serialization.cpp:241
Serialization::DataType::operator==
bool operator==(const DataType &other) const
Comparison for equalness.
Definition Serialization.cpp:376
Serialization::DataType::internalID
String internalID() const
Unique key for native data type, for internal purposes only.
Definition Serialization.cpp:396
Serialization::DataType::dataType
static DataType dataType(bool registerType=true)
Construct a DataType object for the given native C++ type.
Definition Serialization.h:522
Serialization::DataType::isString
bool isString() const
Whether this is a C++ String data type.
Definition Serialization.cpp:223
Serialization::DataType::customTypeName
String customTypeName(bool demangle=false) const
The 1st user defined C/C++ data type name of this data type.
Definition Serialization.cpp:568
Serialization::DataType::size
size_t size() const
Returns native memory size of the respective C++ object or variable.
Definition Serialization.h:460
Serialization::DataType::newInstance
Object newInstance(Archive *archive) const
Allocate and initialize a native instance of data type.
Definition Serialization.cpp:598
Serialization::Exception
Will be thrown whenever an error occurs during an serialization or deserialization process.
Definition Serialization.h:2121
Serialization::Exception::PrintMessage
void PrintMessage() const
Print exception message to stdout.
Definition Serialization.cpp:2857
Serialization::Member
Abstract reflection of a native C++ class/struct's member variable.
Definition Serialization.h:847
Serialization::Member::parentUID
UID parentUID() const
Unique identifier of parent object.
Definition Serialization.cpp:669
Serialization::Member::Member
Member()
Default constructor.
Definition Serialization.cpp:630
Serialization::Member::operator!=
bool operator!=(const Member &other) const
Comparison for inequalness.
Definition Serialization.cpp:784
Serialization::Member::operator<
bool operator<(const Member &other) const
Smaller than comparison.
Definition Serialization.cpp:800
Serialization::Member::operator>
bool operator>(const Member &other) const
Greater than comparison.
Definition Serialization.cpp:822
Serialization::Member::offset
ssize_t offset() const
Offset of member in its containing parent data structure.
Definition Serialization.cpp:738
Serialization::Member::name
String name() const
Name of the member.
Definition Serialization.cpp:693
Serialization::Member::operator==
bool operator==(const Member &other) const
Comparison for equalness.
Definition Serialization.cpp:772
Serialization::Member::type
const DataType & type() const
C/C++ Data type of this member.
Definition Serialization.cpp:746
Serialization::Member::isValid
bool isValid() const
Check if this is a valid Member object.
Definition Serialization.cpp:760
Serialization::Member::uid
UID uid() const
Unique identifier of this member instance.
Definition Serialization.cpp:658
Serialization::Object
Abstract reflection of some native serialized C/C++ data.
Definition Serialization.h:903
Serialization::Object::isValid
bool isValid() const
Check if this is a valid Object instance.
Definition Serialization.cpp:882
Serialization::Object::memberNamed
Member memberNamed(String name) const
Get the member of this Object with given name.
Definition Serialization.cpp:1233
Serialization::Object::version
Version version() const
Version of original user defined C/C++ struct or class.
Definition Serialization.cpp:1042
Serialization::Object::uid
UID uid(int index=0) const
Unique identifier of this Object.
Definition Serialization.cpp:897
Serialization::Object::uidChain
const UIDChain & uidChain() const
Unique identifier chain of this Object.
Definition Serialization.cpp:993
Serialization::Object::rawData
const RawData & rawData() const
Raw data of the original native C/C++ data.
Definition Serialization.cpp:1028
Serialization::Object::operator<
bool operator<(const Object &other) const
Smaller than comparison.
Definition Serialization.cpp:1145
Serialization::Object::Object
Object()
Default constructor (for an "invalid" Object).
Definition Serialization.cpp:840
Serialization::Object::memberByUID
Member memberByUID(const UID &uid) const
Get the member of this Object with given unique identifier.
Definition Serialization.cpp:1254
Serialization::Object::membersOfType
std::vector< Member > membersOfType(const DataType &type) const
Get all members of this Object with given data type.
Definition Serialization.cpp:1286
Serialization::Object::sequenceIndexOf
int sequenceIndexOf(const Member &member) const
Serialization/deserialization sequence number of the requested member.
Definition Serialization.cpp:1327
Serialization::Object::setNativeValueFromString
void setNativeValueFromString(const String &s)
Cast from string to object's data type and assign value natively.
Definition Serialization.cpp:981
Serialization::Object::operator!=
bool operator!=(const Object &other) const
Comparison for inequalness.
Definition Serialization.cpp:1129
Serialization::Object::operator>
bool operator>(const Object &other) const
Greater than comparison.
Definition Serialization.cpp:1165
Serialization::Object::parentUID
UID parentUID() const
Unique identifier of parent object.
Definition Serialization.cpp:913
Serialization::Object::members
std::vector< Member > & members()
All members of the original native C/C++ struct or class instance.
Definition Serialization.cpp:1093
Serialization::Object::type
const DataType & type() const
C/C++ data type this Object is reflecting.
Definition Serialization.cpp:1002
Serialization::Object::isVersionCompatibleTo
bool isVersionCompatibleTo(const Object &other) const
Check version compatibility between Object instances.
Definition Serialization.cpp:1187
Serialization::Object::minVersion
Version minVersion() const
Minimum version of original user defined C/C++ struct or class.
Definition Serialization.cpp:1057
Serialization::Object::operator==
bool operator==(const Object &other) const
Comparison for equalness.
Definition Serialization.cpp:1117
Serialization::UID
Unique identifier referring to one specific native C++ object, member, fundamental variable,...
Definition Serialization.h:349
Serialization::UID::from
static UID from(const T &obj)
Create an unique indentifier for a native C++ object/member/variable.
Definition Serialization.h:370
Serialization::UID::isValid
bool isValid() const
Check whether this is a valid unique identifier.
Definition Serialization.cpp:66
Serialization::UID::size
size_t size
Memory size of the object or member in question.
Definition Serialization.h:352
Serialization::UID::id
ID id
Abstract non-unique ID of the object or member in question.
Definition Serialization.h:351
Serialization
Serialization / deserialization framework.
Definition gig.h:98
Serialization::IsUnion
bool IsUnion(const T &)
Check whether data is a C++ union type.
Definition Serialization.h:253
Serialization::ID
void * ID
Abstract identifier for serialized C++ objects.
Definition Serialization.h:205
Serialization::IsClass
bool IsClass(const T &)
Check whether data is a C/C++ struct or C++ class type.
Definition Serialization.h:271
Serialization::Array
std::vector< T > Array
Array<> template.
Definition Serialization.h:150
Serialization::NO_UID
const UID NO_UID
Reflects an invalid UID and behaves similar to NULL as invalid value for pointer types.
Definition Serialization.cpp:53
Serialization::Set
std::set< T > Set
Set<> template.
Definition Serialization.h:162
Serialization::String
std::string String
Textual string.
Definition Serialization.h:135
Serialization::Map
std::map< T_key, T_value > Map
Map<> template.
Definition Serialization.h:183
Serialization::IsEnum
bool IsEnum(const T &)
Check whether data is a C/C++ enum type.
Definition Serialization.h:234
Serialization::Version
uint32_t Version
Version number data type.
Definition Serialization.h:214
Serialization::UIDChain
std::vector< UID > UIDChain
Chain of UIDs.
Definition Serialization.h:426
Serialization::RawData
std::vector< uint8_t > RawData
Raw data stream of serialized C++ objects.
Definition Serialization.h:193
Serialization::time_base_t
time_base_t
To which time zone a certain timing information relates to.
Definition Serialization.h:221
Serialization::UTC_TIME
@ UTC_TIME
The time stamp relates to "Greenwhich Mean Time" zone, also known as "Coordinated Universal Time"....
Definition Serialization.h:223
Serialization::LOCAL_TIME
@ LOCAL_TIME
The time stamp relates to the machine's local time zone. Request a time stamp in local time if you wa...
Definition Serialization.h:222