BsRTTIPrerequisites.h 17 KB

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