2
0

BsRTTIPrerequisites.h 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615
  1. #pragma once
  2. namespace BansheeEngine
  3. {
  4. /** @addtogroup Utility
  5. * @{
  6. */
  7. /** @addtogroup RTTI
  8. * @{
  9. */
  10. /**
  11. * Helper method when serializing known data types that have valid
  12. * RTTIPlainType specialization.
  13. *
  14. * Returns the size of the element. If elements serializable type is
  15. * specialized with hasDynamicSize == true, the dynamic size is calculated,
  16. * otherwise sizeof() is used.
  17. */
  18. template<class ElemType>
  19. UINT32 rttiGetElemSize(const ElemType& data)
  20. {
  21. if(RTTIPlainType<ElemType>::hasDynamicSize == 1)
  22. return RTTIPlainType<ElemType>::getDynamicSize(data);
  23. else
  24. return sizeof(ElemType);
  25. }
  26. /**
  27. * Helper method when serializing known data types that have valid
  28. * RTTIPlainType specialization.
  29. *
  30. * Writes the specified data into memory, advances the memory pointer by the
  31. * bytes written and returns pointer to new memory.
  32. */
  33. template<class ElemType>
  34. char* rttiWriteElem(const ElemType& data, char* memory)
  35. {
  36. RTTIPlainType<ElemType>::toMemory(data, memory);
  37. return memory + rttiGetElemSize(data);
  38. }
  39. /**
  40. * Helper method when serializing known data types that have valid
  41. * RTTIPlainType specialization.
  42. *
  43. * Writes the specified data into memory, advances the memory pointer by the
  44. * bytes written and returns pointer to new memory. Also increases the size
  45. * value by the size of the written element.
  46. */
  47. template<class ElemType>
  48. char* rttiWriteElem(const ElemType& data, char* memory, UINT32& size)
  49. {
  50. RTTIPlainType<ElemType>::toMemory(data, memory);
  51. UINT32 elemSize = rttiGetElemSize(data);
  52. size += elemSize;
  53. return memory + elemSize;
  54. }
  55. /**
  56. * Helper method when serializing known data types that have valid
  57. * RTTIPlainType specialization.
  58. *
  59. * Reads the specified data into memory, advances the memory pointer by the
  60. * bytes read and returns pointer to new memory.
  61. */
  62. template<class ElemType>
  63. char* rttiReadElem(ElemType& data, char* memory)
  64. {
  65. RTTIPlainType<ElemType>::fromMemory(data, memory);
  66. return memory + rttiGetElemSize(data);
  67. }
  68. /**
  69. * Helper method when serializing known data types that have valid
  70. * RTTIPlainType specialization.
  71. *
  72. * Reads the specified data into memory, advances the memory pointer by the
  73. * bytes read and returns pointer to new memory. Also increases the size
  74. * value by the size of the read element.
  75. */
  76. template<class ElemType>
  77. char* rttiReadElem(ElemType& data, char* memory, UINT32& size)
  78. {
  79. RTTIPlainType<ElemType>::fromMemory(data, memory);
  80. UINT32 elemSize = rttiGetElemSize(data);
  81. size += elemSize;
  82. return memory + elemSize;
  83. }
  84. /**
  85. * Template that you may specialize with a class if you want to provide simple serialization for it.
  86. *
  87. * Any type that uses the "plain" field in the RTTI system must specialize this class.
  88. *
  89. * @note
  90. * Normally you will want to implement IReflectable interface if you want to provide serialization
  91. * as that interface properly handles versioning, nested objects, pointer handling and more.
  92. *
  93. * @note
  94. * This class is useful for types you can easily serialize using a memcpy (built-in types like int/float/etc), or
  95. * types you cannot modify so they implement IReflectable interface (like std::string or std::vector).
  96. *
  97. * @see RTTITypeBase
  98. * @see RTTIField
  99. */
  100. template<class T>
  101. struct RTTIPlainType
  102. {
  103. static_assert(std::is_pod<T>::value,
  104. "Provided type isn't plain-old-data. You need to specialize RTTIPlainType template in order to serialize this type. "\
  105. " (Or call BS_ALLOW_MEMCPY_SERIALIZATION(type) macro if you are sure the type can be properly serialized using just memcpy.)");
  106. enum { id = 0 /**< Unique id for the serializable type. */ };
  107. enum { hasDynamicSize = 0 /**< 0 (Object has static size less than 255 bytes, e.g. int) or 1 (Dynamic size with no size restriction, e.g. string) */ };
  108. /** Serializes the provided object into the provided pre-allocated memory buffer. */
  109. static void toMemory(const T& data, char* memory)
  110. {
  111. memcpy(memory, &data, sizeof(T));
  112. }
  113. /**
  114. * Deserializes a previously allocated object from the provided memory buffer. Return the number of bytes read
  115. * from the memory buffer.
  116. */
  117. static UINT32 fromMemory(T& data, char* memory)
  118. {
  119. memcpy(&data, memory, sizeof(T));
  120. return sizeof(T);
  121. }
  122. /** Returns the size of the provided object. (Works for both static and dynamic size types) */
  123. static UINT32 getDynamicSize(const T& data)
  124. {
  125. return sizeof(T);
  126. }
  127. };
  128. /**
  129. * Tell the RTTI system that the specified type may be serialized just by using a memcpy.
  130. *
  131. * @note Internally this creates a basic RTTIPlainType specialization for the type.
  132. *
  133. * @see RTTIPlainType
  134. */
  135. #define BS_ALLOW_MEMCPY_SERIALIZATION(type) \
  136. template<> struct RTTIPlainType<##type##> \
  137. { enum { id=0 }; enum { hasDynamicSize = 0 }; \
  138. static void toMemory(const type& data, char* memory) \
  139. { memcpy(memory, &data, sizeof(##type##)); } \
  140. static UINT32 fromMemory(##type##& data, char* memory) \
  141. { memcpy(&data, memory, sizeof(##type##)); return sizeof(##type##); } \
  142. static UINT32 getDynamicSize(const type& data) \
  143. { return sizeof(##type##); } \
  144. };
  145. /** @cond SPECIALIZATIONS */
  146. /**
  147. * RTTIPlainType for std::vector.
  148. *
  149. * @see RTTIPlainType
  150. */
  151. template<class T> struct RTTIPlainType<std::vector<T, StdAlloc<T>>>
  152. {
  153. enum { id = TID_Vector }; enum { hasDynamicSize = 1 };
  154. /** @copydoc RTTIPlainType::toMemory */
  155. static void toMemory(const std::vector<T, StdAlloc<T>>& data, char* memory)
  156. {
  157. UINT32 size = sizeof(UINT32);
  158. char* memoryStart = memory;
  159. memory += sizeof(UINT32);
  160. UINT32 numElements = (UINT32)data.size();
  161. memcpy(memory, &numElements, sizeof(UINT32));
  162. memory += sizeof(UINT32);
  163. size += sizeof(UINT32);
  164. for(auto iter = data.begin(); iter != data.end(); ++iter)
  165. {
  166. UINT32 elementSize = RTTIPlainType<T>::getDynamicSize(*iter);
  167. RTTIPlainType<T>::toMemory(*iter, memory);
  168. memory += elementSize;
  169. size += elementSize;
  170. }
  171. memcpy(memoryStart, &size, sizeof(UINT32));
  172. }
  173. /** @copydoc RTTIPlainType::toMemory */
  174. static UINT32 fromMemory(std::vector<T, StdAlloc<T>>& data, char* memory)
  175. {
  176. UINT32 size = 0;
  177. memcpy(&size, memory, sizeof(UINT32));
  178. memory += sizeof(UINT32);
  179. UINT32 numElements;
  180. memcpy(&numElements, memory, sizeof(UINT32));
  181. memory += sizeof(UINT32);
  182. for(UINT32 i = 0; i < numElements; i++)
  183. {
  184. T element;
  185. UINT32 elementSize = RTTIPlainType<T>::fromMemory(element, memory);
  186. data.push_back(element);
  187. memory += elementSize;
  188. }
  189. return size;
  190. }
  191. /** @copydoc RTTIPlainType::toMemory */
  192. static UINT32 getDynamicSize(const std::vector<T, StdAlloc<T>>& data)
  193. {
  194. UINT64 dataSize = sizeof(UINT32) * 2;
  195. for(auto iter = data.begin(); iter != data.end(); ++iter)
  196. dataSize += RTTIPlainType<T>::getDynamicSize(*iter);
  197. assert(dataSize <= std::numeric_limits<UINT32>::max());
  198. return (UINT32)dataSize;
  199. }
  200. };
  201. /**
  202. * RTTIPlainType for std::set.
  203. *
  204. * @see RTTIPlainType
  205. */
  206. template<class T> struct RTTIPlainType<std::set<T, std::less<T>, StdAlloc<T>>>
  207. {
  208. enum { id = TID_Set }; enum { hasDynamicSize = 1 };
  209. /** @copydoc RTTIPlainType::toMemory */
  210. static void toMemory(const std::set<T, std::less<T>, StdAlloc<T>>& data, char* memory)
  211. {
  212. UINT32 size = sizeof(UINT32);
  213. char* memoryStart = memory;
  214. memory += sizeof(UINT32);
  215. UINT32 numElements = (UINT32)data.size();
  216. memcpy(memory, &numElements, sizeof(UINT32));
  217. memory += sizeof(UINT32);
  218. size += sizeof(UINT32);
  219. for(auto iter = data.begin(); iter != data.end(); ++iter)
  220. {
  221. UINT32 elementSize = RTTIPlainType<T>::getDynamicSize(*iter);
  222. RTTIPlainType<T>::toMemory(*iter, memory);
  223. memory += elementSize;
  224. size += elementSize;
  225. }
  226. memcpy(memoryStart, &size, sizeof(UINT32));
  227. }
  228. /** @copydoc RTTIPlainType::toMemory */
  229. static UINT32 fromMemory(std::set<T, std::less<T>, StdAlloc<T>>& data, char* memory)
  230. {
  231. UINT32 size = 0;
  232. memcpy(&size, memory, sizeof(UINT32));
  233. memory += sizeof(UINT32);
  234. UINT32 numElements;
  235. memcpy(&numElements, memory, sizeof(UINT32));
  236. memory += sizeof(UINT32);
  237. for(UINT32 i = 0; i < numElements; i++)
  238. {
  239. T element;
  240. UINT32 elementSize = RTTIPlainType<T>::fromMemory(element, memory);
  241. data.insert(element);
  242. memory += elementSize;
  243. }
  244. return size;
  245. }
  246. /** @copydoc RTTIPlainType::toMemory */
  247. static UINT32 getDynamicSize(const std::set<T, std::less<T>, StdAlloc<T>>& data)
  248. {
  249. UINT64 dataSize = sizeof(UINT32) * 2;
  250. for(auto iter = data.begin(); iter != data.end(); ++iter)
  251. dataSize += RTTIPlainType<T>::getDynamicSize(*iter);
  252. assert(dataSize <= std::numeric_limits<UINT32>::max());
  253. return (UINT32)dataSize;
  254. }
  255. };
  256. /**
  257. * RTTIPlainType for std::map.
  258. *
  259. * @see RTTIPlainType
  260. */
  261. template<class Key, class Value> struct RTTIPlainType<std::map<Key, Value, std::less<Key>, StdAlloc<std::pair<const Key, Value>>>>
  262. {
  263. enum { id = TID_Map }; enum { hasDynamicSize = 1 };
  264. /** @copydoc RTTIPlainType::toMemory */
  265. static void toMemory(const std::map<Key, Value, std::less<Key>, StdAlloc<std::pair<const Key, Value>>>& data, char* memory)
  266. {
  267. UINT32 size = sizeof(UINT32);
  268. char* memoryStart = memory;
  269. memory += sizeof(UINT32);
  270. UINT32 numElements = (UINT32)data.size();
  271. memcpy(memory, &numElements, sizeof(UINT32));
  272. memory += sizeof(UINT32);
  273. size += sizeof(UINT32);
  274. for(auto iter = data.begin(); iter != data.end(); ++iter)
  275. {
  276. UINT32 keySize = RTTIPlainType<Key>::getDynamicSize(iter->first);
  277. RTTIPlainType<Key>::toMemory(iter->first, memory);
  278. memory += keySize;
  279. size += keySize;
  280. UINT32 valueSize = RTTIPlainType<Value>::getDynamicSize(iter->second);
  281. RTTIPlainType<Value>::toMemory(iter->second, memory);
  282. memory += valueSize;
  283. size += valueSize;
  284. }
  285. memcpy(memoryStart, &size, sizeof(UINT32));
  286. }
  287. /** @copydoc RTTIPlainType::fromMemory */
  288. static UINT32 fromMemory(std::map<Key, Value, std::less<Key>, StdAlloc<std::pair<const Key, Value>>>& data, char* memory)
  289. {
  290. UINT32 size = 0;
  291. memcpy(&size, memory, sizeof(UINT32));
  292. memory += sizeof(UINT32);
  293. UINT32 numElements;
  294. memcpy(&numElements, memory, sizeof(UINT32));
  295. memory += sizeof(UINT32);
  296. for(UINT32 i = 0; i < numElements; i++)
  297. {
  298. Key key;
  299. UINT32 keySize = RTTIPlainType<Key>::fromMemory(key, memory);
  300. memory += keySize;
  301. Value value;
  302. UINT32 valueSize = RTTIPlainType<Value>::fromMemory(value, memory);
  303. memory += valueSize;
  304. data[key] = value;
  305. }
  306. return size;
  307. }
  308. /** @copydoc RTTIPlainType::getDynamicSize */
  309. static UINT32 getDynamicSize(const std::map<Key, Value, std::less<Key>, StdAlloc<std::pair<const Key, Value>>>& data)
  310. {
  311. UINT64 dataSize = sizeof(UINT32) * 2;
  312. for(auto iter = data.begin(); iter != data.end(); ++iter)
  313. {
  314. dataSize += RTTIPlainType<Key>::getDynamicSize(iter->first);
  315. dataSize += RTTIPlainType<Value>::getDynamicSize(iter->second);
  316. }
  317. assert(dataSize <= std::numeric_limits<UINT32>::max());
  318. return (UINT32)dataSize;
  319. }
  320. };
  321. /**
  322. * RTTIPlainType for std::unordered_map.
  323. *
  324. * @see RTTIPlainType
  325. */
  326. template<class Key, class Value>
  327. struct RTTIPlainType<std::unordered_map<Key, Value, std::hash<Key>, std::equal_to<Key>, StdAlloc<std::pair<const Key, Value>>>>
  328. {
  329. enum { id = TID_UnorderedMap }; enum { hasDynamicSize = 1 };
  330. typedef std::unordered_map<Key, Value, std::hash<Key>, std::equal_to<Key>, StdAlloc<std::pair<const Key, Value>>> MapType;
  331. /** @copydoc RTTIPlainType::toMemory */
  332. static void toMemory(MapType& data, char* memory)
  333. {
  334. UINT32 size = sizeof(UINT32);
  335. char* memoryStart = memory;
  336. memory += sizeof(UINT32);
  337. UINT32 numElements = (UINT32)data.size();
  338. memcpy(memory, &numElements, sizeof(UINT32));
  339. memory += sizeof(UINT32);
  340. size += sizeof(UINT32);
  341. for (auto iter = data.begin(); iter != data.end(); ++iter)
  342. {
  343. UINT32 keySize = RTTIPlainType<Key>::getDynamicSize(iter->first);
  344. RTTIPlainType<Key>::toMemory(iter->first, memory);
  345. memory += keySize;
  346. size += keySize;
  347. UINT32 valueSize = RTTIPlainType<Value>::getDynamicSize(iter->second);
  348. RTTIPlainType<Value>::toMemory(iter->second, memory);
  349. memory += valueSize;
  350. size += valueSize;
  351. }
  352. memcpy(memoryStart, &size, sizeof(UINT32));
  353. }
  354. /** @copydoc RTTIPlainType::fromMemory */
  355. static UINT32 fromMemory(MapType& data, char* memory)
  356. {
  357. UINT32 size = 0;
  358. memcpy(&size, memory, sizeof(UINT32));
  359. memory += sizeof(UINT32);
  360. UINT32 numElements;
  361. memcpy(&numElements, memory, sizeof(UINT32));
  362. memory += sizeof(UINT32);
  363. for (UINT32 i = 0; i < numElements; i++)
  364. {
  365. Key key;
  366. UINT32 keySize = RTTIPlainType<Key>::fromMemory(key, memory);
  367. memory += keySize;
  368. Value value;
  369. UINT32 valueSize = RTTIPlainType<Value>::fromMemory(value, memory);
  370. memory += valueSize;
  371. data[key] = value;
  372. }
  373. return size;
  374. }
  375. /** @copydoc RTTIPlainType::getDynamicSize */
  376. static UINT32 getDynamicSize(const MapType& data)
  377. {
  378. UINT64 dataSize = sizeof(UINT32)* 2;
  379. for (auto iter = data.begin(); iter != data.end(); ++iter)
  380. {
  381. dataSize += RTTIPlainType<Key>::getDynamicSize(iter->first);
  382. dataSize += RTTIPlainType<Value>::getDynamicSize(iter->second);
  383. }
  384. assert(dataSize <= std::numeric_limits<UINT32>::max());
  385. return (UINT32)dataSize;
  386. }
  387. };
  388. /**
  389. * RTTIPlainType for std::unordered_set.
  390. *
  391. * @see RTTIPlainType
  392. */
  393. template<class Key>
  394. struct RTTIPlainType<std::unordered_set<Key, std::hash<Key>, std::equal_to<Key>, StdAlloc<Key>>>
  395. {
  396. enum { id = TID_UnorderedSet }; enum { hasDynamicSize = 1 };
  397. typedef std::unordered_set<Key, std::hash<Key>, std::equal_to<Key>, StdAlloc<Key>> MapType;
  398. /** @copydoc RTTIPlainType::toMemory */
  399. static void toMemory(MapType& data, char* memory)
  400. {
  401. UINT32 size = sizeof(UINT32);
  402. char* memoryStart = memory;
  403. memory += sizeof(UINT32);
  404. UINT32 numElements = (UINT32)data.size();
  405. memcpy(memory, &numElements, sizeof(UINT32));
  406. memory += sizeof(UINT32);
  407. size += sizeof(UINT32);
  408. for (auto iter = data.begin(); iter != data.end(); ++iter)
  409. {
  410. UINT32 keySize = RTTIPlainType<Key>::getDynamicSize(*iter);
  411. RTTIPlainType<Key>::toMemory(*iter, memory);
  412. memory += keySize;
  413. size += keySize;
  414. }
  415. memcpy(memoryStart, &size, sizeof(UINT32));
  416. }
  417. /** @copydoc RTTIPlainType::fromMemory */
  418. static UINT32 fromMemory(MapType& data, char* memory)
  419. {
  420. UINT32 size = 0;
  421. memcpy(&size, memory, sizeof(UINT32));
  422. memory += sizeof(UINT32);
  423. UINT32 numElements;
  424. memcpy(&numElements, memory, sizeof(UINT32));
  425. memory += sizeof(UINT32);
  426. for (UINT32 i = 0; i < numElements; i++)
  427. {
  428. Key key;
  429. UINT32 keySize = RTTIPlainType<Key>::fromMemory(key, memory);
  430. memory += keySize;
  431. data.insert(key);
  432. }
  433. return size;
  434. }
  435. /** @copydoc RTTIPlainType::getDynamicSize */
  436. static UINT32 getDynamicSize(const MapType& data)
  437. {
  438. UINT64 dataSize = sizeof(UINT32)* 2;
  439. for (auto iter = data.begin(); iter != data.end(); ++iter)
  440. {
  441. dataSize += RTTIPlainType<Key>::getDynamicSize(*iter);
  442. }
  443. assert(dataSize <= std::numeric_limits<UINT32>::max());
  444. return (UINT32)dataSize;
  445. }
  446. };
  447. /**
  448. * RTTIPlainType for std::pair.
  449. *
  450. * @see RTTIPlainType
  451. */
  452. template<class A, class B> struct RTTIPlainType<std::pair<A, B>>
  453. {
  454. enum { id = TID_Pair }; enum { hasDynamicSize = 1 };
  455. /** @copydoc RTTIPlainType::toMemory */
  456. static void toMemory(const std::pair<A, B>& data, char* memory)
  457. {
  458. UINT32 size = sizeof(UINT32);
  459. char* memoryStart = memory;
  460. memory += sizeof(UINT32);
  461. UINT32 firstSize = RTTIPlainType<A>::getDynamicSize(data.first);
  462. RTTIPlainType<A>::toMemory(data.first, memory);
  463. memory += firstSize;
  464. size += firstSize;
  465. UINT32 secondSize = RTTIPlainType<B>::getDynamicSize(data.second);
  466. RTTIPlainType<B>::toMemory(data.second, memory);
  467. memory += secondSize;
  468. size += secondSize;
  469. memcpy(memoryStart, &size, sizeof(UINT32));
  470. }
  471. /** @copydoc RTTIPlainType::fromMemory */
  472. static UINT32 fromMemory(std::pair<A, B>& data, char* memory)
  473. {
  474. UINT32 size = 0;
  475. memcpy(&size, memory, sizeof(UINT32));
  476. memory += sizeof(UINT32);
  477. UINT32 firstSize = RTTIPlainType<A>::fromMemory(data.first, memory);
  478. memory += firstSize;
  479. UINT32 secondSize = RTTIPlainType<B>::fromMemory(data.second, memory);
  480. memory += secondSize;
  481. return size;
  482. }
  483. /** @copydoc RTTIPlainType::getDynamicSize */
  484. static UINT32 getDynamicSize(const std::pair<A, B>& data)
  485. {
  486. UINT64 dataSize = sizeof(UINT32);
  487. dataSize += RTTIPlainType<A>::getDynamicSize(data.first);
  488. dataSize += RTTIPlainType<B>::getDynamicSize(data.second);
  489. assert(dataSize <= std::numeric_limits<UINT32>::max());
  490. return (UINT32)dataSize;
  491. }
  492. };
  493. /** @endcond */
  494. /** @} */
  495. /** @} */
  496. }