CmRTTIField.h 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258
  1. #pragma once
  2. #include <string>
  3. #include <boost/function.hpp>
  4. #include <boost/any.hpp>
  5. #include <boost/static_assert.hpp>
  6. #include "CmPrerequisitesUtil.h"
  7. #include "CmIReflectable.h"
  8. #include "CmManagedDataBlock.h"
  9. #include "CmException.h"
  10. namespace CamelotEngine
  11. {
  12. class RTTITypeBase;
  13. struct RTTIField;
  14. /**
  15. * @brief Helper method when serializing known data types that have valid
  16. * SerializableSimpleType specializations.
  17. *
  18. * Returns the size of the element. If elements serializable type is
  19. * specialized with hasDynamicSize == true, the dynamic size is calculated,
  20. * otherwise sizeof() is used.
  21. */
  22. template<class ElemType>
  23. UINT32 rttiGetElemSize(ElemType& data)
  24. {
  25. if(SerializableSimpleType<ElemType>::hasDynamicSize == 1)
  26. return SerializableSimpleType<ElemType>::getDynamicSize(data);
  27. else
  28. return sizeof(ElemType);
  29. }
  30. /**
  31. * @brief Helper method when serializing known data types that have valid
  32. * SerializableSimpleType specializations.
  33. *
  34. * Writes the specified data into memory, advances the memory pointer by the
  35. * bytes written and returns pointer to new memory.
  36. */
  37. template<class ElemType>
  38. char* rttiWriteElem(ElemType& data, char* memory)
  39. {
  40. SerializableSimpleType<ElemType>::toMemory(data, memory);
  41. return memory + rttiGetElemSize(data);
  42. }
  43. /**
  44. * @brief Helper method when serializing known data types that have valid
  45. * SerializableSimpleType specializations.
  46. *
  47. * Reads the specified data into memory, advances the memory pointer by the
  48. * bytes read and returns pointer to new memory.
  49. */
  50. template<class ElemType>
  51. char* rttiReadElem(ElemType& data, char* memory)
  52. {
  53. SerializableSimpleType<ElemType>::fromMemory(data, memory);
  54. return memory + rttiGetElemSize(data);
  55. }
  56. template<class T>
  57. struct SerializableSimpleType
  58. {
  59. //BOOST_STATIC_ASSERT_MSG(sizeof(T) == 0, // We need this hacky check, otherwise if we only use "false" compiler will evaluate the template and trigger this message
  60. // "Provided data type isn't marked as serializable. Declare SerializableSimpleType template specialization to define a unique ID and needed methods for the type.");
  61. enum { id = 0 };
  62. enum { hasDynamicSize = 0 };
  63. static void toMemory(T& data, char* memory)
  64. {
  65. memcpy(memory, &data, sizeof(T));
  66. }
  67. static void fromMemory(T& data, char* memory)
  68. {
  69. memcpy(&data, memory, sizeof(T));
  70. }
  71. static UINT32 getDynamicSize(T& data)
  72. {
  73. assert(false);
  74. return sizeof(T);
  75. }
  76. };
  77. #define CM_SERIALIZABLE_SIMPLE_TYPE(type, type_id) \
  78. template<> struct SerializableSimpleType<##type##> \
  79. { enum { id=##type_id }; enum { hasDynamicSize = 0 }; \
  80. static void toMemory(##type##& data, char* memory) \
  81. { memcpy(memory, &data, sizeof(##type##)); } \
  82. static void fromMemory(##type##& data, char* memory) \
  83. { memcpy(&data, memory, sizeof(##type##)); } \
  84. static UINT32 getDynamicSize(##type##& data) \
  85. { assert(false); return sizeof(##type##); } \
  86. };
  87. CM_SERIALIZABLE_SIMPLE_TYPE(UINT8, 1);
  88. CM_SERIALIZABLE_SIMPLE_TYPE(UINT16, 2);
  89. CM_SERIALIZABLE_SIMPLE_TYPE(UINT32, 3);
  90. CM_SERIALIZABLE_SIMPLE_TYPE(UINT64, 4);
  91. CM_SERIALIZABLE_SIMPLE_TYPE(INT8, 5);
  92. CM_SERIALIZABLE_SIMPLE_TYPE(INT16, 6);
  93. CM_SERIALIZABLE_SIMPLE_TYPE(INT32, 7);
  94. CM_SERIALIZABLE_SIMPLE_TYPE(INT64, 8);
  95. CM_SERIALIZABLE_SIMPLE_TYPE(float, 9);
  96. CM_SERIALIZABLE_SIMPLE_TYPE(double, 10);
  97. CM_SERIALIZABLE_SIMPLE_TYPE(bool, 11);
  98. /**
  99. * @brief Strings need to copy their data in a slightly more intricate way than just memcpy.
  100. */
  101. template<> struct SerializableSimpleType<String>
  102. {
  103. enum { id = 20 }; enum { hasDynamicSize = 1 };
  104. static void toMemory(String& data, char* memory)
  105. {
  106. UINT32 size = getDynamicSize(data);
  107. memcpy(memory, &size, sizeof(UINT32));
  108. memory += sizeof(UINT32);
  109. size -= sizeof(UINT32);
  110. memcpy(memory, data.data(), size);
  111. }
  112. static void fromMemory(String& data, char* memory)
  113. {
  114. UINT32 size;
  115. memcpy(&size, memory, sizeof(UINT32));
  116. memory += sizeof(UINT32);
  117. size -= sizeof(UINT32);
  118. char* buffer = new char[size + 1]; // TODO - Use a better allocator
  119. memcpy(buffer, memory, size);
  120. buffer[size] = '\0';
  121. data = String(buffer);
  122. delete[] buffer;
  123. }
  124. static UINT32 getDynamicSize(String& data)
  125. {
  126. UINT64 dataSize = data.size() * sizeof(String::value_type) + sizeof(UINT32);
  127. #if CM_DEBUG_MODE
  128. if(dataSize > std::numeric_limits<UINT32>::max())
  129. {
  130. CM_EXCEPT(InternalErrorException, "Data overflow! Size doesn't fit into 32 bits.");
  131. }
  132. #endif
  133. return (UINT32)dataSize;
  134. }
  135. };
  136. /**
  137. * @brief Types of fields we can serialize:
  138. *
  139. * - Simple - Native data types, POD (Plain old data) structures, or in general types we don't want to (or can't) inherit from IReflectable.
  140. *
  141. * - DataBlock - Array of bytes of a certain size. When returning a data block you may specify if its managed or unmanaged.
  142. * Managed data blocks have their buffers deleted after they go out of scope. This is useful if you need to return some
  143. * temporary data. On the other hand if the data in the block belongs to your class, and isn't temporary, keep the data unmanaged.
  144. *
  145. * - Complex - Field that is of IReflectable type. Cannot be a pointer to IReflectable and must be actual value type.
  146. *
  147. * - ComplexPtr - A pointer to IReflectable.
  148. */
  149. enum SerializableFieldType
  150. {
  151. SerializableFT_Plain,
  152. SerializableFT_DataBlock,
  153. SerializableFT_Reflectable,
  154. SerializableFT_ReflectablePtr
  155. };
  156. /**
  157. * @brief Structure that keeps meta-data concerning a single class field.
  158. */
  159. struct CM_UTILITY_EXPORT RTTIField
  160. {
  161. boost::any valueGetter;
  162. boost::any valueSetter;
  163. boost::any arraySizeGetter;
  164. boost::any arraySizeSetter;
  165. std::string mName;
  166. UINT16 mUniqueId;
  167. bool mIsVectorType;
  168. SerializableFieldType mType;
  169. bool isSimpleType() { return mType == SerializableFT_Plain; }
  170. bool isDataBlockType() { return mType == SerializableFT_DataBlock; }
  171. bool isComplexType() { return mType == SerializableFT_Reflectable; }
  172. bool isComplexPtrType() { return mType == SerializableFT_ReflectablePtr; }
  173. virtual UINT32 getArraySize(void* object) = 0;
  174. virtual void setArraySize(void* object, UINT32 size) = 0;
  175. virtual UINT32 getTypeSize() = 0;
  176. virtual bool hasDynamicSize() = 0;
  177. /**
  178. * @brief Throws an exception if this field doesn't contain a simple value.
  179. *
  180. * @param array If true then the field must support simple array types.
  181. */
  182. void checkIsSimple(bool array);
  183. /**
  184. * @brief Throws an exception if this field doesn't contain a complex value.
  185. *
  186. * @param array If true then the field must support complex array types.
  187. */
  188. void checkIsComplex(bool array);
  189. /**
  190. * @brief Throws an exception if this field doesn't contain a complex pointer value.
  191. *
  192. * @param array If true then the field must support complex array types.
  193. */
  194. void checkIsComplexPtr(bool array);
  195. /**
  196. * @brief Throws an exception depending if the field is or isn't an array.
  197. *
  198. * @param array If true, then exception will be thrown if field is not an array.
  199. * If false, then it will be thrown if field is an array.
  200. */
  201. void checkIsArray(bool array);
  202. /**
  203. * @brief Throws an exception if this field doesn't contain a data block value.
  204. */
  205. void checkIsDataBlock();
  206. protected:
  207. void initAll(boost::any valueGetter, boost::any valueSetter, boost::any arraySizeGetter, boost::any arraySizeSetter,
  208. std::string mName, UINT16 mUniqueId, bool mIsVectorType, SerializableFieldType type)
  209. {
  210. this->valueGetter = valueGetter;
  211. this->valueSetter = valueSetter;
  212. this->arraySizeGetter = arraySizeGetter;
  213. this->arraySizeSetter = arraySizeSetter;
  214. this->mName = mName;
  215. this->mUniqueId = mUniqueId;
  216. this->mIsVectorType = mIsVectorType;
  217. this->mType = type;
  218. }
  219. };
  220. }