BsRTTIPrerequisites.h 17 KB

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