2
0

BsRTTIPrerequisites.h 17 KB

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