CmRTTIField.h 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200
  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. namespace CamelotEngine
  10. {
  11. class RTTITypeBase;
  12. struct RTTIField;
  13. template<class T>
  14. struct SerializableSimpleType
  15. {
  16. //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
  17. // "Provided data type isn't marked as serializable. Declare SerializableSimpleType template specialization to define a unique ID and needed methods for the type.");
  18. enum { id = 0 };
  19. enum { hasDynamicSize = 0 };
  20. static void toMemory(T& data, char* memory)
  21. {
  22. memcpy(memory, &data, sizeof(T));
  23. }
  24. static void fromMemory(T& data, char* memory)
  25. {
  26. memcpy(&data, memory, sizeof(T));
  27. }
  28. static UINT32 getDynamicSize(T& data)
  29. {
  30. assert(false);
  31. return sizeof(T);
  32. }
  33. };
  34. #define CM_SERIALIZABLE_SIMPLE_TYPE(type, type_id) \
  35. template<> struct SerializableSimpleType<##type##> \
  36. { enum { id=##type_id }; enum { hasDynamicSize = 0 }; \
  37. static void toMemory(##type##& data, char* memory) \
  38. { memcpy(memory, &data, sizeof(##type##)); } \
  39. static void fromMemory(##type##& data, char* memory) \
  40. { memcpy(&data, memory, sizeof(##type##)); } \
  41. static UINT32 getDynamicSize(##type##& data) \
  42. { assert(false); return sizeof(##type##); } \
  43. };
  44. CM_SERIALIZABLE_SIMPLE_TYPE(UINT8, 1);
  45. CM_SERIALIZABLE_SIMPLE_TYPE(UINT16, 2);
  46. CM_SERIALIZABLE_SIMPLE_TYPE(UINT32, 3);
  47. CM_SERIALIZABLE_SIMPLE_TYPE(UINT64, 4);
  48. CM_SERIALIZABLE_SIMPLE_TYPE(INT8, 5);
  49. CM_SERIALIZABLE_SIMPLE_TYPE(INT16, 6);
  50. CM_SERIALIZABLE_SIMPLE_TYPE(INT32, 7);
  51. CM_SERIALIZABLE_SIMPLE_TYPE(INT64, 8);
  52. CM_SERIALIZABLE_SIMPLE_TYPE(float, 9);
  53. CM_SERIALIZABLE_SIMPLE_TYPE(double, 10);
  54. CM_SERIALIZABLE_SIMPLE_TYPE(bool, 11);
  55. /**
  56. * @brief Strings need to copy their data in a slightly more intricate way than just memcpy.
  57. */
  58. template<> struct SerializableSimpleType<String>
  59. {
  60. enum { id = 20 }; enum { hasDynamicSize = 1 };
  61. static void toMemory(String& data, char* memory)
  62. {
  63. UINT32 size = getDynamicSize(data);
  64. memcpy(memory, &size, sizeof(UINT32));
  65. memory += sizeof(UINT32);
  66. memcpy(memory, data.data(), size);
  67. }
  68. static void fromMemory(String& data, char* memory)
  69. {
  70. UINT32 size;
  71. memcpy(&size, memory, sizeof(UINT32));
  72. memory += sizeof(UINT32);
  73. size -= sizeof(UINT32);
  74. char* buffer = new char[size + 1]; // TODO - Use a better allocator
  75. memcpy(buffer, memory, size);
  76. buffer[size] = '\0';
  77. data = String(buffer);
  78. delete[] buffer;
  79. }
  80. static UINT32 getDynamicSize(String& data)
  81. {
  82. return data.size() + sizeof(UINT32);
  83. }
  84. };
  85. /**
  86. * @brief Types of fields we can serialize:
  87. *
  88. * - Simple - Native data types, POD (Plain old data) structures, or in general types we don't want to (or can't) inherit from IReflectable.
  89. *
  90. * - DataBlock - Array of bytes of a certain size. When returning a data block you may specify if its managed or unmanaged.
  91. * Managed data blocks have their buffers deleted after they go out of scope. This is useful if you need to return some
  92. * temporary data. On the other hand if the data in the block belongs to your class, and isn't temporary, keep the data unmanaged.
  93. *
  94. * - Complex - Field that is of IReflectable type. Cannot be a pointer to IReflectable and must be actual value type.
  95. *
  96. * - ComplexPtr - A pointer to IReflectable.
  97. */
  98. enum SerializableFieldType
  99. {
  100. SerializableFT_Plain,
  101. SerializableFT_DataBlock,
  102. SerializableFT_Reflectable,
  103. SerializableFT_ReflectablePtr
  104. };
  105. /**
  106. * @brief Structure that keeps meta-data concerning a single class field.
  107. */
  108. struct CM_UTILITY_EXPORT RTTIField
  109. {
  110. boost::any valueGetter;
  111. boost::any valueSetter;
  112. boost::any arraySizeGetter;
  113. boost::any arraySizeSetter;
  114. std::string mName;
  115. UINT16 mUniqueId;
  116. bool mIsVectorType;
  117. SerializableFieldType mType;
  118. bool isSimpleType() { return mType == SerializableFT_Plain; }
  119. bool isDataBlockType() { return mType == SerializableFT_DataBlock; }
  120. bool isComplexType() { return mType == SerializableFT_Reflectable; }
  121. bool isComplexPtrType() { return mType == SerializableFT_ReflectablePtr; }
  122. virtual UINT32 getArraySize(void* object) = 0;
  123. virtual void setArraySize(void* object, UINT32 size) = 0;
  124. virtual UINT32 getTypeSize() = 0;
  125. virtual bool hasDynamicSize() = 0;
  126. /**
  127. * @brief Throws an exception if this field doesn't contain a simple value.
  128. *
  129. * @param array If true then the field must support simple array types.
  130. */
  131. void checkIsSimple(bool array);
  132. /**
  133. * @brief Throws an exception if this field doesn't contain a complex value.
  134. *
  135. * @param array If true then the field must support complex array types.
  136. */
  137. void checkIsComplex(bool array);
  138. /**
  139. * @brief Throws an exception if this field doesn't contain a complex pointer value.
  140. *
  141. * @param array If true then the field must support complex array types.
  142. */
  143. void checkIsComplexPtr(bool array);
  144. /**
  145. * @brief Throws an exception depending if the field is or isn't an array.
  146. *
  147. * @param array If true, then exception will be thrown if field is not an array.
  148. * If false, then it will be thrown if field is an array.
  149. */
  150. void checkIsArray(bool array);
  151. /**
  152. * @brief Throws an exception if this field doesn't contain a data block value.
  153. */
  154. void checkIsDataBlock();
  155. protected:
  156. void initAll(boost::any valueGetter, boost::any valueSetter, boost::any arraySizeGetter, boost::any arraySizeSetter,
  157. std::string mName, UINT16 mUniqueId, bool mIsVectorType, SerializableFieldType type)
  158. {
  159. this->valueGetter = valueGetter;
  160. this->valueSetter = valueSetter;
  161. this->arraySizeGetter = arraySizeGetter;
  162. this->arraySizeSetter = arraySizeSetter;
  163. this->mName = mName;
  164. this->mUniqueId = mUniqueId;
  165. this->mIsVectorType = mIsVectorType;
  166. this->mType = type;
  167. }
  168. };
  169. }