156 |
template<class T> |
template<class T> |
157 |
using Set = std::set<T>; |
using Set = std::set<T>; |
158 |
|
|
159 |
|
/** @brief Map<> template. |
160 |
|
* |
161 |
|
* This type is used for built-in automatic serialization / deserialization |
162 |
|
* of C++ associative sorted map containers (a.k.a. @c std::map from the |
163 |
|
* STL). This framework supports serializing this common data type out of |
164 |
|
* the box, with the following 2 constraints: |
165 |
|
* |
166 |
|
* 1. The precise key type (i.e. 1st template parameter) used with maps must |
167 |
|
* be either a primitive data type (e.g. @c int, @c double, @c bool, |
168 |
|
* etc.) or a @c String object. |
169 |
|
* |
170 |
|
* 2. The value type (i.e. 2nd template parameter) must be serializable. So |
171 |
|
* the map's value type should either be a) any primitive data type (e.g. |
172 |
|
* @c int, @c double, etc.) or b) any other data structure or class types |
173 |
|
* enjoying out of the box serialization support by this framework, or c) |
174 |
|
* if it is a custom @c struct or @c class then it must have a |
175 |
|
* @c serialize() method implementation. |
176 |
|
*/ |
177 |
|
template<class T_key, class T_value> |
178 |
|
using Map = std::map<T_key,T_value>; |
179 |
|
|
180 |
/** @brief Raw data stream of serialized C++ objects. |
/** @brief Raw data stream of serialized C++ objects. |
181 |
* |
* |
182 |
* 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 |
445 |
bool isEnum() const; |
bool isEnum() const; |
446 |
bool isArray() const; |
bool isArray() const; |
447 |
bool isSet() const; |
bool isSet() const; |
448 |
|
bool isMap() const; |
449 |
bool isSigned() const; |
bool isSigned() const; |
450 |
operator bool() const { return isValid(); } ///< Same as calling isValid(). |
operator bool() const { return isValid(); } ///< Same as calling isValid(). |
451 |
//bool operator()() const { return isValid(); } |
//bool operator()() const { return isValid(); } |
456 |
String asLongDescr() const; |
String asLongDescr() const; |
457 |
String baseTypeName() const; |
String baseTypeName() const; |
458 |
String customTypeName(bool demangle = false) const; |
String customTypeName(bool demangle = false) const; |
459 |
|
String customTypeName2(bool demangle = false) const; |
460 |
|
|
461 |
/** @brief Construct a DataType object for the given native C++ data. |
/** @brief Construct a DataType object for the given native C++ data. |
462 |
* |
* |
474 |
} |
} |
475 |
|
|
476 |
protected: |
protected: |
477 |
DataType(bool isPointer, int size, String baseType, String customType = ""); |
DataType(bool isPointer, int size, String baseType, |
478 |
|
String customType1 = "", String customType2 = ""); |
479 |
|
|
480 |
template<typename T, bool T_isPointer> |
template<typename T, bool T_isPointer> |
481 |
struct ResolverBase { |
struct ResolverBase { |
577 |
} |
} |
578 |
}; |
}; |
579 |
|
|
580 |
|
// DataType resolver for non-pointer Map<> container object types. |
581 |
|
template<typename T_key, typename T_value> |
582 |
|
struct Resolver<Map<T_key,T_value>> { |
583 |
|
static DataType resolve(const Map<T_key,T_value>& data) { |
584 |
|
const int sz = sizeof(data); |
585 |
|
T_key unused1; |
586 |
|
T_value unused2; |
587 |
|
return DataType(false, sz, "Map", rawCppTypeNameOf(unused1), |
588 |
|
rawCppTypeNameOf(unused2)); |
589 |
|
} |
590 |
|
}; |
591 |
|
|
592 |
|
// DataType resolver for Map<> pointer types (of 1st degree). |
593 |
|
template<typename T_key, typename T_value> |
594 |
|
struct Resolver<Map<T_key,T_value>*> { |
595 |
|
static DataType resolve(const Map<T_key,T_value>*& data) { |
596 |
|
const int sz = sizeof(*data); |
597 |
|
T_key unused1; |
598 |
|
T_value unused2; |
599 |
|
return DataType(true, sz, "Map", rawCppTypeNameOf(unused1), |
600 |
|
rawCppTypeNameOf(unused2)); |
601 |
|
} |
602 |
|
}; |
603 |
|
|
604 |
template<typename T> |
template<typename T> |
605 |
static String rawCppTypeNameOf(const T& data) { |
static String rawCppTypeNameOf(const T& data) { |
606 |
#if defined _MSC_VER // Microsoft compiler ... |
#if defined _MSC_VER // Microsoft compiler ... |
616 |
private: |
private: |
617 |
String m_baseTypeName; |
String m_baseTypeName; |
618 |
String m_customTypeName; |
String m_customTypeName; |
619 |
|
String m_customTypeName2; |
620 |
int m_size; |
int m_size; |
621 |
bool m_isPointer; |
bool m_isPointer; |
622 |
|
|
793 |
* a >> myRootObject; |
* a >> myRootObject; |
794 |
* @endcode |
* @endcode |
795 |
* Now this framework automatically handles serialization and |
* Now this framework automatically handles serialization and |
796 |
* deserialization of fundamental data types automatically for you (like |
* deserialization of fundamental data types (like i.e. @c char, @c int, |
797 |
* i.e. char, int, long int, float, double, etc.). However for your own |
* @c long @c int, @c float, @c double, etc.) and common C++ classes |
798 |
* custom C++ classes and structs you must implement one method which |
* (currently: @c std::string, @c std::vector, @c std::set and @c std::map) |
799 |
* defines which members of your class should actually be serialized and |
* automatically for you. However for your own custom C++ classes and |
800 |
* deserialized. That method to be added must have the following signature: |
* structs you must implement one method which defines which members of your |
801 |
|
* class / struct should actually be serialized and deserialized. That |
802 |
|
* method to be added must have the following signature: |
803 |
* @code |
* @code |
804 |
* void serialize(Serialization::Archive* archive); |
* void serialize(Serialization::Archive* archive); |
805 |
* @endcode |
* @endcode |
809 |
* int a; |
* int a; |
810 |
* bool b; |
* bool b; |
811 |
* double c; |
* double c; |
812 |
|
* std::string text; |
813 |
|
* std::vector<int> v; |
814 |
* }; |
* }; |
815 |
* |
* |
816 |
* struct Bar { |
* struct Bar { |
819 |
* Foo foo1; |
* Foo foo1; |
820 |
* Foo* pFoo2; |
* Foo* pFoo2; |
821 |
* Foo* pFoo3DontTouchMe; // shall not be serialized/deserialized |
* Foo* pFoo3DontTouchMe; // shall not be serialized/deserialized |
822 |
|
* std::set<int> someSet; |
823 |
|
* std::map<double,Foo> someMap; |
824 |
* }; |
* }; |
825 |
* @endcode |
* @endcode |
826 |
* So in order to be able to serialize and deserialize objects of those two |
* So in order to be able to serialize and deserialize objects of those two |
831 |
* int a; |
* int a; |
832 |
* bool b; |
* bool b; |
833 |
* double c; |
* double c; |
834 |
|
* std::string text; |
835 |
|
* std::vector<int> v; |
836 |
* |
* |
837 |
* void serialize(Serialization::Archive* archive); |
* void serialize(Serialization::Archive* archive); |
838 |
* }; |
* }; |
843 |
* Foo foo1; |
* Foo foo1; |
844 |
* Foo* pFoo2; |
* Foo* pFoo2; |
845 |
* Foo* pFoo3DontTouchMe; // shall not be serialized/deserialized |
* Foo* pFoo3DontTouchMe; // shall not be serialized/deserialized |
846 |
|
* std::set<int> someSet; |
847 |
|
* std::map<double,Foo> someMap; |
848 |
* |
* |
849 |
* void serialize(Serialization::Archive* archive); |
* void serialize(Serialization::Archive* archive); |
850 |
* }; |
* }; |
859 |
* SRLZ(a); |
* SRLZ(a); |
860 |
* SRLZ(b); |
* SRLZ(b); |
861 |
* SRLZ(c); |
* SRLZ(c); |
862 |
|
* SRLZ(text); |
863 |
|
* SRLZ(v); |
864 |
* } |
* } |
865 |
* |
* |
866 |
* void Bar::serialize(Serialization::Archive* archive) { |
* void Bar::serialize(Serialization::Archive* archive) { |
869 |
* SRLZ(foo1); |
* SRLZ(foo1); |
870 |
* SRLZ(pFoo2); |
* SRLZ(pFoo2); |
871 |
* // leaving out pFoo3DontTouchMe here |
* // leaving out pFoo3DontTouchMe here |
872 |
|
* SRLZ(someSet); |
873 |
|
* SRLZ(someMap); |
874 |
* } |
* } |
875 |
* @endcode |
* @endcode |
876 |
* Now when you serialize such a Bar object, this framework will also |
* And that's it! |
877 |
* automatically serialize the respective Foo object(s) accordingly, also |
* |
878 |
* for the pFoo2 pointer for instance (as long as it is not a NULL pointer |
* Now when you serialize such a @c Bar object, this framework will also |
879 |
* that is). |
* automatically serialize the respective @c Foo object(s) accordingly, also |
880 |
|
* for the @c pFoo2 pointer for instance (as long as it is not a @c NULL |
881 |
|
* pointer that is). |
882 |
* |
* |
883 |
* Note that there is only one method that you need to implement. So the |
* Note that there is only one method that you need to implement. So the |
884 |
* respective serialize() method implementation of your classes/structs are |
* respective @c serialize() method implementation of your classes/structs |
885 |
* both called for serialization, as well as for deserialization! |
* are both called for serialization, as well as for deserialization! |
886 |
|
* Usually you don't need to know whether your @c serialize() method was |
887 |
|
* called for serialization or deserialization, however if you need to do |
888 |
|
* know for some reason you can call @c archive->operation() inside your |
889 |
|
* @c serialize() method to distinguish between the two. |
890 |
* |
* |
891 |
* In case you need to enforce backward incompatiblity for one of your C++ |
* In case you need to enforce backward incompatibility for one of your C++ |
892 |
* classes, you can do so by setting a version and minimum version for your |
* classes, you can do so by setting a version and minimum version for your |
893 |
* class (see @c setVersion() and @c setMinVersion() for details). |
* class (see @c setVersion() and @c setMinVersion() for details). |
894 |
*/ |
*/ |
1119 |
* @discussion To avoid member name conflicts with native members, it is |
* @discussion To avoid member name conflicts with native members, it is |
1120 |
* recommended to always choose member names which would be impossible |
* recommended to always choose member names which would be impossible |
1121 |
* as names to be declared in C/C++ code. For instance this framework |
* as names to be declared in C/C++ code. For instance this framework |
1122 |
* uses heap member names "[0]", "[1]", "[3]", ... in its out of the box |
* uses heap member names "[0]", "[1]", "[2]", ... in its out of the box |
1123 |
* support when serializing elements of @c Array<> objects, since |
* support when serializing elements of @c Array<> objects, since |
1124 |
* brackets in general cannot be used as part of variable names in C++, |
* brackets in general cannot be used as part of variable names in C++, |
1125 |
* so using such or other special characters in heap member names, makes |
* so using such or other special characters in heap member names, makes |
1504 |
} |
} |
1505 |
}; |
}; |
1506 |
|
|
1507 |
|
// SerializationRecursion for Map<> objects. |
1508 |
|
template<typename T_key, typename T_value, bool T_isRecursive> |
1509 |
|
struct SerializationRecursionImpl<Map<T_key,T_value>,T_isRecursive> { |
1510 |
|
static void serializeObject(Archive* archive, const Map<T_key,T_value>& obj) { |
1511 |
|
const UIDChain uids = UIDChainResolver<Map<T_key,T_value>>(obj); |
1512 |
|
const Object& object = archive->objectByUID(uids[0]); |
1513 |
|
if (archive->operation() == OPERATION_SERIALIZE) { |
1514 |
|
for (const auto& it : obj) { |
1515 |
|
archive->serializeHeapMember( |
1516 |
|
obj, it.second, ("[" + toString(it.first) + "]").c_str() |
1517 |
|
); |
1518 |
|
} |
1519 |
|
} else { |
1520 |
|
const_cast<Object&>(object).m_sync = |
1521 |
|
[&obj,archive](Object& dstObj, const Object& srcObj, |
1522 |
|
void* syncer) |
1523 |
|
{ |
1524 |
|
const size_t n = srcObj.members().size(); |
1525 |
|
const_cast<Map<T_key,T_value>&>(obj).clear(); |
1526 |
|
for (size_t i = 0; i < n; ++i) { |
1527 |
|
const Member& member = srcObj.members()[i]; |
1528 |
|
String name = member.name(); |
1529 |
|
if (name.length() < 2 || name[0] != '[' || |
1530 |
|
*name.rbegin() != ']') continue; |
1531 |
|
name = name.substr(1, name.length() - 2); |
1532 |
|
T_key key; |
1533 |
|
const UIDChain uids = UIDChainResolver<T_key>(key); |
1534 |
|
const DataType type = DataType::dataTypeOf(key); |
1535 |
|
Object tmpObj(uids, type); |
1536 |
|
tmpObj.setNativeValueFromString(name); |
1537 |
|
const_cast<Map<T_key,T_value>&>(obj)[key] = T_value(); |
1538 |
|
} |
1539 |
|
for (const auto& it : obj) { |
1540 |
|
archive->serializeHeapMember( |
1541 |
|
obj, it.second, ("[" + toString(it.first) + "]").c_str() |
1542 |
|
); |
1543 |
|
} |
1544 |
|
// updating dstObj required as serializeHeapMember() |
1545 |
|
// replaced the original object by a new one |
1546 |
|
dstObj = archive->objectByUID(dstObj.uid()); |
1547 |
|
for (size_t i = 0; i < n; ++i) { |
1548 |
|
Member srcMember = srcObj.members()[i]; |
1549 |
|
Member dstMember = dstObj.memberNamed(srcMember.name()); |
1550 |
|
((Syncer*)syncer)->syncMember(dstMember, srcMember); |
1551 |
|
} |
1552 |
|
}; |
1553 |
|
} |
1554 |
|
} |
1555 |
|
}; |
1556 |
|
|
1557 |
|
// SerializationRecursion for Map<> pointers (of 1st degree). |
1558 |
|
template<typename T_key, typename T_value, bool T_isRecursive> |
1559 |
|
struct SerializationRecursionImpl<Map<T_key,T_value>*,T_isRecursive> { |
1560 |
|
static void serializeObject(Archive* archive, const Map<T_key,T_value>*& obj) { |
1561 |
|
if (!obj) return; |
1562 |
|
SerializationRecursionImpl<Map<T_key,T_value>,T_isRecursive>::serializeObject( |
1563 |
|
archive, *obj |
1564 |
|
); |
1565 |
|
} |
1566 |
|
}; |
1567 |
|
|
1568 |
// Automatically handles recursion for class/struct types, while ignoring all primitive types. |
// Automatically handles recursion for class/struct types, while ignoring all primitive types. |
1569 |
template<typename T> |
template<typename T> |
1570 |
struct SerializationRecursion : SerializationRecursionImpl<T, LIBGIG_IS_CLASS(T)> { |
struct SerializationRecursion : SerializationRecursionImpl<T, LIBGIG_IS_CLASS(T)> { |
1638 |
void syncString(const Object& dst, const Object& src); |
void syncString(const Object& dst, const Object& src); |
1639 |
void syncArray(const Object& dst, const Object& src); |
void syncArray(const Object& dst, const Object& src); |
1640 |
void syncSet(const Object& dst, const Object& src); |
void syncSet(const Object& dst, const Object& src); |
1641 |
|
void syncMap(const Object& dst, const Object& src); |
1642 |
void syncPointer(const Object& dst, const Object& src); |
void syncPointer(const Object& dst, const Object& src); |
1643 |
void syncMember(const Member& dstMember, const Member& srcMember); |
void syncMember(const Member& dstMember, const Member& srcMember); |
1644 |
protected: |
protected: |