36 |
#include <map> |
#include <map> |
37 |
#include <time.h> |
#include <time.h> |
38 |
#include <stdarg.h> |
#include <stdarg.h> |
39 |
|
#include <assert.h> |
40 |
|
#include <functional> |
41 |
|
|
42 |
#ifndef __has_extension |
#ifndef __has_extension |
43 |
# define __has_extension(x) 0 |
# define __has_extension(x) 0 |
119 |
class ObjectPool; |
class ObjectPool; |
120 |
class Exception; |
class Exception; |
121 |
|
|
122 |
|
/** @brief Textual string. |
123 |
|
* |
124 |
|
* This type is used for built-in automatic serialization / deserialization |
125 |
|
* of C++ @c String objects (a.k.a. @c std::string from the STL). This |
126 |
|
* framework supports serializing this common data type out of the box and |
127 |
|
* is handled by this framework as it was a primitive C++ data type. |
128 |
|
*/ |
129 |
typedef std::string String; |
typedef std::string String; |
130 |
|
|
131 |
|
/** @brief Array<> template. |
132 |
|
* |
133 |
|
* This type is used for built-in automatic serialization / deserialization |
134 |
|
* of C++ array containers (a.k.a. @c std::vector from the STL). This |
135 |
|
* framework supports serializing this common data type out of the box, with |
136 |
|
* only one constraint: the precise element type used with arrays must be |
137 |
|
* serializable. So the array's element type should either be a) any |
138 |
|
* primitive data type (e.g. @c int, @c double, etc.) or b) any other data |
139 |
|
* structure or class types enjoying out of the box serialization support by |
140 |
|
* this framework, or c) if it is a custom @c struct or @c class then it |
141 |
|
* must have a @c serialize() method implementation. |
142 |
|
*/ |
143 |
|
template<class T> |
144 |
|
using Array = std::vector<T>; |
145 |
|
|
146 |
/** @brief Raw data stream of serialized C++ objects. |
/** @brief Raw data stream of serialized C++ objects. |
147 |
* |
* |
148 |
* This data type is used for the data stream as a result of serializing |
* This data type is used for the data stream as a result of serializing |
247 |
return __is_pod(T); |
return __is_pod(T); |
248 |
}*/ |
}*/ |
249 |
|
|
250 |
|
/*template<typename T> |
251 |
|
bool IsArray(const T& data) { |
252 |
|
return false; |
253 |
|
}*/ |
254 |
|
|
255 |
|
/*template<typename T> |
256 |
|
bool IsArray(const Array<T>& data) { |
257 |
|
return true; |
258 |
|
}*/ |
259 |
|
|
260 |
/** @brief Unique identifier referring to one specific native C++ object, member, fundamental variable, or any other native C++ data. |
/** @brief Unique identifier referring to one specific native C++ object, member, fundamental variable, or any other native C++ data. |
261 |
* |
* |
262 |
* Reflects a unique identifier for one specific serialized C++ data, i.e. |
* Reflects a unique identifier for one specific serialized C++ data, i.e. |
399 |
bool isReal() const; |
bool isReal() const; |
400 |
bool isBool() const; |
bool isBool() const; |
401 |
bool isEnum() const; |
bool isEnum() const; |
402 |
|
bool isArray() const; |
403 |
bool isSigned() const; |
bool isSigned() const; |
404 |
operator bool() const { return isValid(); } ///< Same as calling isValid(). |
operator bool() const { return isValid(); } ///< Same as calling isValid(). |
405 |
//bool operator()() const { return isValid(); } |
//bool operator()() const { return isValid(); } |
446 |
if (type == typeid(uint32_t)) return DataType(T_isPointer, sz, "uint32"); |
if (type == typeid(uint32_t)) return DataType(T_isPointer, sz, "uint32"); |
447 |
if (type == typeid(int64_t)) return DataType(T_isPointer, sz, "int64"); |
if (type == typeid(int64_t)) return DataType(T_isPointer, sz, "int64"); |
448 |
if (type == typeid(uint64_t)) return DataType(T_isPointer, sz, "uint64"); |
if (type == typeid(uint64_t)) return DataType(T_isPointer, sz, "uint64"); |
449 |
|
if (type == typeid(size_t)) { |
450 |
|
if (sz == 1) return DataType(T_isPointer, sz, "uint8"); |
451 |
|
if (sz == 2) return DataType(T_isPointer, sz, "uint16"); |
452 |
|
if (sz == 4) return DataType(T_isPointer, sz, "uint32"); |
453 |
|
if (sz == 8) return DataType(T_isPointer, sz, "uint64"); |
454 |
|
else assert(false /* unknown size_t size */); |
455 |
|
} |
456 |
|
if (type == typeid(ssize_t)) { |
457 |
|
if (sz == 1) return DataType(T_isPointer, sz, "int8"); |
458 |
|
if (sz == 2) return DataType(T_isPointer, sz, "int16"); |
459 |
|
if (sz == 4) return DataType(T_isPointer, sz, "int32"); |
460 |
|
if (sz == 8) return DataType(T_isPointer, sz, "int64"); |
461 |
|
else assert(false /* unknown ssize_t size */); |
462 |
|
} |
463 |
if (type == typeid(bool)) return DataType(T_isPointer, sz, "bool"); |
if (type == typeid(bool)) return DataType(T_isPointer, sz, "bool"); |
464 |
if (type == typeid(float)) return DataType(T_isPointer, sz, "real32"); |
if (type == typeid(float)) return DataType(T_isPointer, sz, "real32"); |
465 |
if (type == typeid(double)) return DataType(T_isPointer, sz, "real64"); |
if (type == typeid(double)) return DataType(T_isPointer, sz, "real64"); |
489 |
} |
} |
490 |
}; |
}; |
491 |
|
|
492 |
|
// DataType resolver for non-pointer Array<> container object types. |
493 |
|
template<typename T> |
494 |
|
struct Resolver<Array<T>> { |
495 |
|
static DataType resolve(const Array<T>& data) { |
496 |
|
const int sz = sizeof(data); |
497 |
|
T unused; |
498 |
|
return DataType(false, sz, "Array", rawCppTypeNameOf(unused)); |
499 |
|
} |
500 |
|
}; |
501 |
|
|
502 |
|
// DataType resolver for Array<> pointer types (of 1st degree). |
503 |
|
template<typename T> |
504 |
|
struct Resolver<Array<T>*> { |
505 |
|
static DataType resolve(const Array<T>*& data) { |
506 |
|
const int sz = sizeof(*data); |
507 |
|
T unused; |
508 |
|
return DataType(true, sz, "Array", rawCppTypeNameOf(unused)); |
509 |
|
} |
510 |
|
}; |
511 |
|
|
512 |
template<typename T> |
template<typename T> |
513 |
static String rawCppTypeNameOf(const T& data) { |
static String rawCppTypeNameOf(const T& data) { |
514 |
#if defined _MSC_VER // Microsoft compiler ... |
#if defined _MSC_VER // Microsoft compiler ... |
559 |
Member(); |
Member(); |
560 |
UID uid() const; |
UID uid() const; |
561 |
String name() const; |
String name() const; |
562 |
size_t offset() const; |
ssize_t offset() const; |
563 |
const DataType& type() const; |
const DataType& type() const; |
564 |
bool isValid() const; |
bool isValid() const; |
565 |
operator bool() const { return isValid(); } ///< Same as calling isValid(). |
operator bool() const { return isValid(); } ///< Same as calling isValid(). |
570 |
bool operator>(const Member& other) const; |
bool operator>(const Member& other) const; |
571 |
|
|
572 |
protected: |
protected: |
573 |
Member(String name, UID uid, size_t offset, DataType type); |
Member(String name, UID uid, ssize_t offset, DataType type); |
574 |
friend class Archive; |
friend class Archive; |
575 |
|
|
576 |
private: |
private: |
577 |
UID m_uid; |
UID m_uid; |
578 |
size_t m_offset; |
ssize_t m_offset; |
579 |
String m_name; |
String m_name; |
580 |
DataType m_type; |
DataType m_type; |
581 |
|
|
646 |
Version m_minVersion; |
Version m_minVersion; |
647 |
RawData m_data; |
RawData m_data; |
648 |
std::vector<Member> m_members; |
std::vector<Member> m_members; |
649 |
|
std::function<void(Object& dstObj, const Object& srcObj, void* syncer)> m_sync; |
650 |
|
|
651 |
#if LIBGIG_SERIALIZATION_INTERNAL |
#if LIBGIG_SERIALIZATION_INTERNAL |
652 |
friend String _encodePrimitiveValue(const Object& obj); |
friend String _encodePrimitiveValue(const Object& obj); |
780 |
*/ |
*/ |
781 |
class Archive { |
class Archive { |
782 |
public: |
public: |
783 |
|
/** @brief Current activity of @c Archive object. |
784 |
|
*/ |
785 |
|
enum operation_t { |
786 |
|
OPERATION_NONE, ///< Archive is currently neither serializing, nor deserializing. |
787 |
|
OPERATION_SERIALIZE, ///< Archive is currently serializing. |
788 |
|
OPERATION_DESERIALIZE ///< Archive is currently deserializing. |
789 |
|
}; |
790 |
|
|
791 |
Archive(); |
Archive(); |
792 |
Archive(const RawData& data); |
Archive(const RawData& data); |
793 |
Archive(const uint8_t* data, size_t size); |
Archive(const uint8_t* data, size_t size); |
856 |
template<typename T> |
template<typename T> |
857 |
void deserialize(T* obj) { |
void deserialize(T* obj) { |
858 |
Archive a; |
Archive a; |
859 |
m_operation = OPERATION_DESERIALIZE; |
a.m_operation = m_operation = OPERATION_DESERIALIZE; |
860 |
obj->serialize(&a); |
obj->serialize(&a); |
861 |
a.m_root = UID::from(obj); |
a.m_root = UID::from(obj); |
862 |
Syncer s(a, *this); |
Syncer s(a, *this); |
863 |
m_operation = OPERATION_NONE; |
a.m_operation = m_operation = OPERATION_NONE; |
864 |
} |
} |
865 |
|
|
866 |
/** @brief Initiate serialization of your C++ objects. |
/** @brief Initiate serialization of your C++ objects. |
920 |
* #define SRLZ(member) \ |
* #define SRLZ(member) \ |
921 |
* archive->serializeMember(*this, member, #member); |
* archive->serializeMember(*this, member, #member); |
922 |
* |
* |
923 |
|
* struct Foo { |
924 |
|
* int a; |
925 |
|
* Bar b; // a custom struct or class having a serialize() method |
926 |
|
* std::string c; |
927 |
|
* std::vector<double> d; |
928 |
|
* |
929 |
|
* void serialize(Serialization::Archive* archive); |
930 |
|
* }; |
931 |
|
* |
932 |
* void Foo::serialize(Serialization::Archive* archive) { |
* void Foo::serialize(Serialization::Archive* archive) { |
933 |
* SRLZ(a); |
* SRLZ(a); |
934 |
* SRLZ(b); |
* SRLZ(b); |
935 |
* SRLZ(c); |
* SRLZ(c); |
936 |
|
* SRLZ(d); |
937 |
* } |
* } |
938 |
* @endcode |
* @endcode |
939 |
* As you can see, using such a macro makes your code more readable and |
* As you can see, using such a macro makes your code more readable, |
940 |
* less error prone. |
* compact and less error prone. |
941 |
* |
* |
942 |
* It is completely up to you to decide which ones of your member |
* It is completely up to you to decide which ones of your member |
943 |
* variables shall automatically be serialized and deserialized with |
* variables shall automatically be serialized and deserialized with |
962 |
* deserialization |
* deserialization |
963 |
* @param memberName - name of @a nativeMember to be stored with this |
* @param memberName - name of @a nativeMember to be stored with this |
964 |
* archive |
* archive |
965 |
|
* @see serializeHeapMember() for variables on the RAM heap |
966 |
*/ |
*/ |
967 |
template<typename T_classType, typename T_memberType> |
template<typename T_classType, typename T_memberType> |
968 |
void serializeMember(const T_classType& nativeObject, const T_memberType& nativeMember, const char* memberName) { |
void serializeMember(const T_classType& nativeObject, const T_memberType& nativeMember, const char* memberName) { |
969 |
const size_t offset = |
const ssize_t offset = |
970 |
((const uint8_t*)(const void*)&nativeMember) - |
((const uint8_t*)(const void*)&nativeMember) - |
971 |
((const uint8_t*)(const void*)&nativeObject); |
((const uint8_t*)(const void*)&nativeObject); |
972 |
const UIDChain uids = UIDChainResolver<T_memberType>(nativeMember); |
const UIDChain uids = UIDChainResolver<T_memberType>(nativeMember); |
992 |
} |
} |
993 |
} |
} |
994 |
|
|
995 |
|
/** @brief Serialize a C/C++ member variable allocated on the heap. |
996 |
|
* |
997 |
|
* This method is essentially used by applications in the same way as |
998 |
|
* @c serializeMember() above, however @c serializeMember() must only be |
999 |
|
* used for native C/C++ members which are variables that are memory |
1000 |
|
* located within their owning parent data structures. For any variable |
1001 |
|
* that's located on the RAM heap though, applications must use this |
1002 |
|
* method instead to make it clear that there's no constant, static |
1003 |
|
* offset relationship between the passed member and its owning parent. |
1004 |
|
* |
1005 |
|
* @discussion To avoid member name conflicts with native members, it is |
1006 |
|
* recommended to always choose member names which would be impossible |
1007 |
|
* as names to be declared in C/C++ code. For instance this framework |
1008 |
|
* uses heap member names "[0]", "[1]", "[3]", ... in its out of the box |
1009 |
|
* support when serializing elements of @c Array<> objects, since |
1010 |
|
* brackets in general cannot be used as part of variable names in C++, |
1011 |
|
* so using such or other special characters in heap member names, makes |
1012 |
|
* such naming conflicts impossible. |
1013 |
|
* |
1014 |
|
* @param nativeObject - native C++ object to be registered for |
1015 |
|
* serialization / deserialization |
1016 |
|
* @param heapMember - C/C++ variable (located on the heap) of |
1017 |
|
* @a nativeObject to be registered for |
1018 |
|
* serialization / deserialization |
1019 |
|
* @param memberName - name of @a heapMember to be stored with this |
1020 |
|
* archive; an arbitrary but unique name should be |
1021 |
|
* chosen which must not collide with names of |
1022 |
|
* native members (see discussion above) |
1023 |
|
* @see serializeMember() for native member variables |
1024 |
|
*/ |
1025 |
|
template<typename T_classType, typename T_memberType> |
1026 |
|
void serializeHeapMember(const T_classType& nativeObject, const T_memberType& heapMember, const char* memberName) { |
1027 |
|
const ssize_t offset = -1; // used for all members on heap |
1028 |
|
const UIDChain uids = UIDChainResolver<T_memberType>(heapMember); |
1029 |
|
const DataType type = DataType::dataTypeOf(heapMember); |
1030 |
|
const Member member(memberName, uids[0], offset, type); |
1031 |
|
const UID parentUID = UID::from(nativeObject); |
1032 |
|
Object& parent = m_allObjects[parentUID]; |
1033 |
|
if (!parent) { |
1034 |
|
const UIDChain uids = UIDChainResolver<T_classType>(nativeObject); |
1035 |
|
const DataType type = DataType::dataTypeOf(nativeObject); |
1036 |
|
parent = Object(uids, type); |
1037 |
|
} |
1038 |
|
parent.members().push_back(member); |
1039 |
|
const Object obj(uids, type); |
1040 |
|
const bool bExistsAlready = m_allObjects.count(uids[0]); |
1041 |
|
const bool isValidObject = obj; |
1042 |
|
const bool bExistingObjectIsInvalid = !m_allObjects[uids[0]]; |
1043 |
|
if (!bExistsAlready || (bExistingObjectIsInvalid && isValidObject)) { |
1044 |
|
m_allObjects[uids[0]] = obj; |
1045 |
|
// recurse serialization for all members of this member |
1046 |
|
// (only for struct/class types, noop for primitive types) |
1047 |
|
SerializationRecursion<T_memberType>::serializeObject(this, heapMember); |
1048 |
|
} |
1049 |
|
} |
1050 |
|
|
1051 |
/** @brief Set current version number for your C++ class. |
/** @brief Set current version number for your C++ class. |
1052 |
* |
* |
1053 |
* By calling this method you can define a version number for your |
* By calling this method you can define a version number for your |
1065 |
* #define SRLZ(member) \ |
* #define SRLZ(member) \ |
1066 |
* archive->serializeMember(*this, member, #member); |
* archive->serializeMember(*this, member, #member); |
1067 |
* |
* |
1068 |
|
* struct Foo { |
1069 |
|
* int a; |
1070 |
|
* Bar b; // a custom struct or class having a serialize() method |
1071 |
|
* std::string c; |
1072 |
|
* std::vector<double> d; |
1073 |
|
* |
1074 |
|
* void serialize(Serialization::Archive* archive); |
1075 |
|
* }; |
1076 |
|
* |
1077 |
* void Foo::serialize(Serialization::Archive* archive) { |
* void Foo::serialize(Serialization::Archive* archive) { |
1078 |
* // when serializing: the current version of this class that is |
* // when serializing: the current version of this class that is |
1079 |
* // going to be stored with the serialized archive |
* // going to be stored with the serialized archive |
1085 |
* SRLZ(a); |
* SRLZ(a); |
1086 |
* SRLZ(b); |
* SRLZ(b); |
1087 |
* SRLZ(c); |
* SRLZ(c); |
1088 |
|
* SRLZ(d); |
1089 |
* } |
* } |
1090 |
* @endcode |
* @endcode |
1091 |
* In this example above, the C++ class "Foo" would be serialized along |
* In this example above, the C++ class "Foo" would be serialized along |
1208 |
time_t timeStampModified() const; |
time_t timeStampModified() const; |
1209 |
tm dateTimeCreated(time_base_t base = LOCAL_TIME) const; |
tm dateTimeCreated(time_base_t base = LOCAL_TIME) const; |
1210 |
tm dateTimeModified(time_base_t base = LOCAL_TIME) const; |
tm dateTimeModified(time_base_t base = LOCAL_TIME) const; |
1211 |
|
operation_t operation() const; |
1212 |
|
|
1213 |
protected: |
protected: |
1214 |
// UID resolver for non-pointer types |
// UID resolver for non-pointer types |
1285 |
static void serializeObject(Archive* archive, const String*& obj) {} |
static void serializeObject(Archive* archive, const String*& obj) {} |
1286 |
}; |
}; |
1287 |
|
|
1288 |
|
// SerializationRecursion for Array<> objects. |
1289 |
|
template<typename T, bool T_isRecursive> |
1290 |
|
struct SerializationRecursionImpl<Array<T>,T_isRecursive> { |
1291 |
|
static void serializeObject(Archive* archive, const Array<T>& obj) { |
1292 |
|
const UIDChain uids = UIDChainResolver<Array<T>>(obj); |
1293 |
|
const Object& object = archive->objectByUID(uids[0]); |
1294 |
|
if (archive->operation() == OPERATION_SERIALIZE) { |
1295 |
|
for (size_t i = 0; i < obj.size(); ++i) { |
1296 |
|
archive->serializeHeapMember( |
1297 |
|
obj, obj[i], ("[" + std::to_string(i) + "]").c_str() |
1298 |
|
); |
1299 |
|
} |
1300 |
|
} else { |
1301 |
|
const_cast<Object&>(object).m_sync = |
1302 |
|
[&obj,archive](Object& dstObj, const Object& srcObj, |
1303 |
|
void* syncer) |
1304 |
|
{ |
1305 |
|
const size_t n = srcObj.members().size(); |
1306 |
|
const_cast<Array<T>&>(obj).resize(n); |
1307 |
|
for (size_t i = 0; i < obj.size(); ++i) { |
1308 |
|
archive->serializeHeapMember( |
1309 |
|
obj, obj[i], ("[" + std::to_string(i) + "]").c_str() |
1310 |
|
); |
1311 |
|
} |
1312 |
|
// updating dstObj required as serializeHeapMember() |
1313 |
|
// replaced the original object by a new one |
1314 |
|
dstObj = archive->objectByUID(dstObj.uid()); |
1315 |
|
for (size_t i = 0; i < obj.size(); ++i) { |
1316 |
|
String name = "[" + std::to_string(i) + "]"; |
1317 |
|
Member srcMember = srcObj.memberNamed(name); |
1318 |
|
Member dstMember = dstObj.memberNamed(name); |
1319 |
|
((Syncer*)syncer)->syncMember(dstMember, srcMember); |
1320 |
|
} |
1321 |
|
}; |
1322 |
|
} |
1323 |
|
} |
1324 |
|
}; |
1325 |
|
|
1326 |
|
// SerializationRecursion for Array<> pointers (of 1st degree). |
1327 |
|
template<typename T, bool T_isRecursive> |
1328 |
|
struct SerializationRecursionImpl<Array<T>*,T_isRecursive> { |
1329 |
|
static void serializeObject(Archive* archive, const Array<T>*& obj) { |
1330 |
|
if (!obj) return; |
1331 |
|
SerializationRecursionImpl<Array<T>,T_isRecursive>::serializeObject( |
1332 |
|
archive, *obj |
1333 |
|
); |
1334 |
|
} |
1335 |
|
}; |
1336 |
|
|
1337 |
// Automatically handles recursion for class/struct types, while ignoring all primitive types. |
// Automatically handles recursion for class/struct types, while ignoring all primitive types. |
1338 |
template<typename T> |
template<typename T> |
1339 |
struct SerializationRecursion : SerializationRecursionImpl<T, LIBGIG_IS_CLASS(T)> { |
struct SerializationRecursion : SerializationRecursionImpl<T, LIBGIG_IS_CLASS(T)> { |
1360 |
void _popObjectsBlob(const char*& p, const char* end); |
void _popObjectsBlob(const char*& p, const char* end); |
1361 |
|
|
1362 |
protected: |
protected: |
1363 |
|
/** @brief Synchronizes 2 archives with each other. |
1364 |
|
* |
1365 |
|
* This class is used internally at final stage of deserialization. It |
1366 |
|
* is not used for serialization. |
1367 |
|
* |
1368 |
|
* The deserialization algorithm of this framework works like this: |
1369 |
|
* |
1370 |
|
* 1. The (currently running) application constructs an @c Archive |
1371 |
|
* object by passing a previously serialized raw data stream to the |
1372 |
|
* @c Archive constructor. At this stage, the raw data stream is |
1373 |
|
* decoded and this archive's object pool is populated with objects, |
1374 |
|
* which in turn are filled with data (at temporary storage |
1375 |
|
* location inside the respective @c Object instances) of the decoded |
1376 |
|
* data stream. |
1377 |
|
* |
1378 |
|
* 2. A temporary (2nd) @c Archive object is constructed internally by |
1379 |
|
* this framework, reflecting the (currently running) application's |
1380 |
|
* latest data structre layout, without touching any actual data yet. |
1381 |
|
* The individual @c Object instances of this 2nd @c Archive are |
1382 |
|
* bound to the running application's native (target) C/C++ member |
1383 |
|
* variables to be updated (written to) next. |
1384 |
|
* |
1385 |
|
* Note that at this point, the 2 archives might very well have quite |
1386 |
|
* different data structure layouts, due to potential software changes |
1387 |
|
* between the original serializing application and this currently |
1388 |
|
* deserializing software application. |
1389 |
|
* |
1390 |
|
* 3. This Syncer class is used to transfer the actual data from the 1st |
1391 |
|
* to the 2nd (temporary) @c Archive object, it does so by traversing |
1392 |
|
* the 2 archives' object pools, trying to find the respective 2 |
1393 |
|
* objects on the two sides to be synchronized, and if found, it |
1394 |
|
* transfers the data from the 1st archive's object to the 2nd |
1395 |
|
* archive's object, effectively writing to the currently running |
1396 |
|
* application's final C/C++ memory locations. |
1397 |
|
* |
1398 |
|
* This 3 staged approach allows to deserialize data in a much more |
1399 |
|
* relaxed, adaptive and flexible (while still automatic) way than |
1400 |
|
* traditional serialization frameworks would do. |
1401 |
|
*/ |
1402 |
class Syncer { |
class Syncer { |
1403 |
public: |
public: |
1404 |
Syncer(Archive& dst, Archive& src); |
Syncer(Archive& dst, Archive& src); |
|
protected: |
|
1405 |
void syncObject(const Object& dst, const Object& src); |
void syncObject(const Object& dst, const Object& src); |
1406 |
void syncPrimitive(const Object& dst, const Object& src); |
void syncPrimitive(const Object& dst, const Object& src); |
1407 |
void syncString(const Object& dst, const Object& src); |
void syncString(const Object& dst, const Object& src); |
1408 |
|
void syncArray(const Object& dst, const Object& src); |
1409 |
void syncPointer(const Object& dst, const Object& src); |
void syncPointer(const Object& dst, const Object& src); |
1410 |
void syncMember(const Member& dstMember, const Member& srcMember); |
void syncMember(const Member& dstMember, const Member& srcMember); |
1411 |
|
protected: |
1412 |
static Member dstMemberMatching(const Object& dstObj, const Object& srcObj, const Member& srcMember); |
static Member dstMemberMatching(const Object& dstObj, const Object& srcObj, const Member& srcMember); |
1413 |
private: |
private: |
1414 |
Archive& m_dst; |
Archive& m_dst; |
1415 |
Archive& m_src; |
Archive& m_src; |
1416 |
}; |
}; |
1417 |
|
|
|
enum operation_t { |
|
|
OPERATION_NONE, |
|
|
OPERATION_SERIALIZE, |
|
|
OPERATION_DESERIALIZE |
|
|
}; |
|
|
|
|
1418 |
virtual void encode(); |
virtual void encode(); |
1419 |
|
|
1420 |
ObjectPool m_allObjects; |
ObjectPool m_allObjects; |