CmRTTIType.h 43 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014
  1. #pragma once
  2. #include <string>
  3. #include <algorithm>
  4. #include <unordered_map>
  5. #include <boost/preprocessor/punctuation/comma.hpp>
  6. #include "CmPrerequisitesUtil.h"
  7. #include "CmManagedDataBlock.h"
  8. #include "CmRTTIField.h"
  9. #include "CmRTTIPlainField.h"
  10. #include "CmRTTIReflectableField.h"
  11. #include "CmRTTIReflectablePtrField.h"
  12. #include "CmRTTIManagedDataBlockField.h"
  13. #include "CmIReflectable.h"
  14. namespace CamelotFramework
  15. {
  16. #define CM_SETGET_MEMBER(name, type, parentType) \
  17. type##& get##name(parentType##* obj) { return obj->##name; } \
  18. void Set##name(parentType##* obj, type##& val) { obj->##name = val; }
  19. #define CM_ADD_PLAINFIELD(name, id, parentType) \
  20. addPlainField(#name, id##, &##parentType##::get##name, &##parentType##::Set##name);
  21. /**
  22. * @brief Provides an interface for accessing fields of a certain class.
  23. * Data can be easily accessed by getter and setter methods.
  24. *
  25. * Supported data types:
  26. * - Plain types - All types defined in CmRTTIField.h, mostly native types and POD (plain old data) structs. Data is parsed byte by byte.
  27. * No pointers to plain types are supported. Data is passed around by value.
  28. * - Reflectable types - Any class deriving from IReflectable. Data is parsed based on fields in its RTTI class. Can be pointer or value type.
  29. * - Arrays of both plain and reflectable types are supported
  30. * - Data blocks - A managed or unmanaged block of data. See CmManagedDataBlock.h
  31. */
  32. class CM_UTILITY_EXPORT RTTITypeBase
  33. {
  34. public:
  35. RTTITypeBase();
  36. virtual ~RTTITypeBase();
  37. /**
  38. * @brief Returns RTTI type information for all classes that derive from the class
  39. * that owns this RTTI type.
  40. */
  41. virtual Vector<RTTITypeBase*>::type& getDerivedClasses() = 0;
  42. /**
  43. * @brief Returns RTTI type information for the class that owns this RTTI type.
  44. * If the class has not base type, null is returned instead.
  45. */
  46. virtual RTTITypeBase* getBaseClass() = 0;
  47. /**
  48. * @brief Internal method. Called by the RTTI system when a class is first found in
  49. * order to form child/parent class hierarchy.
  50. */
  51. virtual void _registerDerivedClass(RTTITypeBase* derivedClass) = 0;
  52. /**
  53. * @brief Creates a new instance of the class owning this RTTI type.
  54. */
  55. virtual std::shared_ptr<IReflectable> newRTTIObject() = 0;
  56. /**
  57. * @brief Returns the name of the class owning this RTTI type.
  58. */
  59. virtual const String& getRTTIName() = 0;
  60. /**
  61. * @brief Returns an RTTI id that uniquely represents each class in the RTTI
  62. * system.
  63. */
  64. virtual UINT32 getRTTIId() = 0;
  65. /**
  66. * @brief Called by the serializers when serialization for this object has started.
  67. * Use this to do any preprocessing on data you might need during serialization itself.
  68. */
  69. virtual void onSerializationStarted(IReflectable* obj) {}
  70. /**
  71. * @brief Called by the serializers when serialization for this object has ended.
  72. * After serialization has ended you can be sure that the type has been fully serialized,
  73. * and you may clean up any temporary data.
  74. */
  75. virtual void onSerializationEnded(IReflectable* obj) {}
  76. /**
  77. * @brief Called by the serializers when deserialization for this object has started.
  78. * Use this to do any preprocessing on data you might need during deserialization itself.
  79. */
  80. virtual void onDeserializationStarted(IReflectable* obj) {}
  81. /**
  82. * @brief Called by the serializers when deserialization for this object has ended.
  83. * At this point you can be sure the instance has been fully deserialized and you
  84. * may safely use it.
  85. *
  86. * One exception being are fields you marked with "WeakRef" flag, as they might be resolved
  87. * only after deserialization has fully completed for all objects.
  88. */
  89. virtual void onDeserializationEnded(IReflectable* obj) {}
  90. /**
  91. * @brief Allows you to assign a value to a plain field with the specified name on
  92. * the provided instance.
  93. *
  94. * @note Caller must ensure instance and value types are valid for this field.
  95. */
  96. template <class ObjectType, class DataType>
  97. void setPlainValue(ObjectType* object, const String& name, DataType& value)
  98. {
  99. RTTIField* genericField = findField(name);
  100. genericField->checkIsPlain(false);
  101. RTTIPlainFieldBase* field = static_cast<RTTIPlainFieldBase*>(genericField);
  102. UINT32 typeSize = 0;
  103. if(RTTIPlainType<DataType>::hasDynamicSize)
  104. typeSize = RTTIPlainType<DataType>::getDynamicSize(value);
  105. else
  106. typeSize = sizeof(DataType);
  107. UINT8* tempBuffer = (UINT8*)stackAlloc(typeSize);
  108. RTTIPlainType<DataType>::toMemory(value, (char*)tempBuffer);
  109. field->fromBuffer(object, tempBuffer);
  110. stackDeallocLast(tempBuffer);
  111. }
  112. /**
  113. * @brief Allows you to assign a value to a plain field array element with the
  114. * specified name and index on the provided instance.
  115. *
  116. * @note Caller must ensure instance and value types are valid for this field.
  117. */
  118. template <class ObjectType, class DataType>
  119. void setPlainArrayValue(ObjectType* object, const String& name, UINT32 index, DataType& value)
  120. {
  121. RTTIField* genericField = findField(name);
  122. genericField->checkIsPlain(true);
  123. RTTIPlainFieldBase* field = static_cast<RTTIPlainFieldBase*>(genericField);
  124. UINT32 typeSize = 0;
  125. if(RTTIPlainType<DataType>::hasDynamicSize)
  126. typeSize = RTTIPlainType<DataType>::getDynamicSize(value);
  127. else
  128. typeSize = sizeof(DataType);
  129. UINT8* tempBuffer = (UINT8*)stackAlloc(typeSize);
  130. RTTIPlainType<DataType>::toMemory(value, (char*)tempBuffer);
  131. field->arrayElemFromBuffer(object, index, tempBuffer);
  132. stackDeallocLast(tempBuffer);
  133. }
  134. /**
  135. * @brief Allows you to assign a value to a reflectable field with the specified name on
  136. * the provided instance.
  137. *
  138. * @note Caller must ensure instance and value types are valid for this field.
  139. */
  140. template <class ObjectType, class DataType>
  141. void setReflectableValue(ObjectType* object, const String& name, DataType& value)
  142. {
  143. static_assert((std::is_base_of<CamelotFramework::IReflectable, DataType>::value),
  144. "Invalid data type for complex field. It needs to derive from CamelotFramework::IReflectable.");
  145. RTTIField* genericField = findField(name);
  146. genericField->checkIsComplex(false);
  147. RTTIReflectableFieldBase* field = static_cast<RTTIReflectableFieldBase*>(genericField);
  148. field->setValue(object, value);
  149. }
  150. /**
  151. * @brief Allows you to assign a value to a reflectable field array element with the
  152. * specified name and index on the provided instance.
  153. *
  154. * @note Caller must ensure instance and value types are valid for this field.
  155. */
  156. template <class ObjectType, class DataType>
  157. void setReflectableArrayValue(ObjectType* object, const String& name, UINT32 index, DataType& value)
  158. {
  159. static_assert((std::is_base_of<CamelotFramework::IReflectable, DataType>::value),
  160. "Invalid data type for complex field. It needs to derive from CamelotFramework::IReflectable.");
  161. RTTIField* genericField = findField(name);
  162. genericField->checkIsComplex(true);
  163. RTTIReflectableFieldBase* field = static_cast<RTTIReflectableFieldBase*>(genericField);
  164. field->setArrayValue(object, index, value);
  165. }
  166. /**
  167. * @brief Allows you to assign a value to a managed data block field with the specified name on
  168. * the provided instance.
  169. *
  170. * @note Caller must ensure instance type is valid for this field.
  171. */
  172. template <class ObjectType>
  173. void setDataBlockValue(ObjectType* object, const String& name, ManagedDataBlock value)
  174. {
  175. RTTIField* genericField = findField(name);
  176. genericField->checkIsDataBlock();
  177. RTTIManagedDataBlockFieldBase* field = static_cast<RTTIManagedDataBlockFieldBase*>(genericField);
  178. field->setValue(object, value);
  179. }
  180. /**
  181. * @brief Allows you to assign a value to a reflectable pointer field with the specified name on
  182. * the provided instance.
  183. *
  184. * @note Caller must ensure instance and value types are valid for this field.
  185. */
  186. template <class ObjectType, class DataType>
  187. void setReflectablePtrValue(ObjectType* object, const String& name, std::shared_ptr<DataType> value)
  188. {
  189. static_assert((std::is_base_of<CamelotFramework::IReflectable, DataType>::value),
  190. "Invalid data type for complex field. It needs to derive from CamelotFramework::IReflectable.");
  191. RTTIField* genericField = findField(name);
  192. genericField->checkIsComplexPtr(false);
  193. RTTIReflectablePtrFieldBase* field = static_cast<RTTIReflectablePtrFieldBase*>(genericField);
  194. field->setValue(object, value);
  195. }
  196. /**
  197. * @brief Allows you to assign a value to a reflectable pointer field array element with the
  198. * specified name and index on the provided instance.
  199. *
  200. * @note Caller must ensure instance and value types are valid for this field.
  201. */
  202. template <class ObjectType, class DataType>
  203. void setReflectablePtrArrayValue(ObjectType* object, const String& name, UINT32 index, std::shared_ptr<DataType> value)
  204. {
  205. static_assert((std::is_base_of<CamelotFramework::IReflectable, DataType>::value),
  206. "Invalid data type for complex field. It needs to derive from CamelotFramework::IReflectable.");
  207. RTTIField* genericField = findField(name);
  208. genericField->checkIsComplexPtr(true);
  209. RTTIReflectablePtrFieldBase* field = static_cast<RTTIReflectablePtrFieldBase*>(genericField);
  210. field->setArrayValue(object, index, value);
  211. }
  212. /**
  213. * @brief Reads a value from a plain field with the specified name from the provided instance.
  214. *
  215. * @note Caller must ensure instance and value types are valid for this field.
  216. */
  217. template <class ObjectType, class DataType>
  218. void getPlainValue(ObjectType* object, const String& name, DataType& value)
  219. {
  220. RTTIField* genericField = findField(name);
  221. genericField->checkIsPlain(false);
  222. RTTIPlainFieldBase* field = static_cast<RTTIPlainFieldBase*>(genericField);
  223. UINT32 typeSize = 0;
  224. if(field->hasDynamicSize())
  225. typeSize = field->getDynamicSize(object);
  226. else
  227. typeSize = field->getTypeSize();
  228. UINT8* tempBuffer = (UINT8*)stackAlloc(typeSize);
  229. field->toBuffer(object, tempBuffer);
  230. RTTIPlainType<DataType>::fromMemory(value, (char*)tempBuffer);
  231. stackDeallocLast(tempBuffer);
  232. }
  233. /**
  234. * @brief Reads a value from a plain array field with the specified name and index from the provided instance.
  235. *
  236. * @note Caller must ensure instance and value types are valid for this field.
  237. */
  238. template <class ObjectType, class DataType>
  239. void getPlainArrayValue(ObjectType* object, const String& name, UINT32 index, DataType& value)
  240. {
  241. RTTIField* genericField = findField(name);
  242. genericField->checkIsPlain(true);
  243. RTTIPlainFieldBase* field = static_cast<RTTIPlainFieldBase*>(genericField);
  244. UINT32 typeSize = 0;
  245. if(field->hasDynamicSize())
  246. typeSize = field->getArrayElemDynamicSize(object, arrIdx);
  247. else
  248. typeSize = field->getTypeSize();
  249. UINT8* tempBuffer = (UINT8*)stackAlloc(typeSize);
  250. field->arrayElemToBuffer(object, index, tempBuffer);
  251. RTTIPlainType<DataType>::fromMemory(value, (char*)tempBuffer);
  252. stackDeallocLast(tempBuffer);
  253. }
  254. /**
  255. * @brief Reads a value from a reflectable object field with the specified name from the provided instance.
  256. *
  257. * @note Caller must ensure instance and value types are valid for this field.
  258. */
  259. template <class ObjectType>
  260. IReflectable& getReflectableValue(ObjectType* object, const String& name)
  261. {
  262. RTTIField* genericField = findField(name);
  263. genericField->checkIsComplex(false);
  264. RTTIReflectableFieldBase* field = static_cast<RTTIReflectableFieldBase*>(genericField);
  265. return field->getValue(object);
  266. }
  267. /**
  268. * @brief Reads a value from a reflectable object array field with the specified name and index from the provided instance.
  269. *
  270. * @note Caller must ensure instance and value types are valid for this field.
  271. */
  272. template <class ObjectType>
  273. IReflectable& getReflectableArrayValue(ObjectType* object, const String& name, UINT32 index)
  274. {
  275. RTTIField* genericField = findField(name);
  276. genericField->checkIsComplex(true);
  277. RTTIReflectableFieldBase* field = static_cast<RTTIReflectableFieldBase*>(genericField);
  278. return field->getArrayValue(object, index);
  279. }
  280. /**
  281. * @brief Reads a managed data block field with the specified name from the provided instance.
  282. *
  283. * @note Caller must ensure instance type is valid for this field.
  284. */
  285. template <class ObjectType>
  286. ManagedDataBlock getDataBlockValue(ObjectType* object, const String& name)
  287. {
  288. RTTIField* genericField = findField(name);
  289. genericField->checkIsDataBlock();
  290. RTTIManagedDataBlockFieldBase* field = static_cast<RTTIManagedDataBlockFieldBase*>(genericField);
  291. return field->getValue(object);
  292. }
  293. /**
  294. * @brief Reads a value from a reflectable object pointer field with the specified name from the provided instance.
  295. *
  296. * @note Caller must ensure instance and value types are valid for this field.
  297. */
  298. template <class ObjectType>
  299. std::shared_ptr<IReflectable> getReflectablePtrValue(ObjectType* object, const String& name)
  300. {
  301. RTTIField* genericField = findField(name);
  302. genericField->checkIsComplexPtr(false);
  303. RTTIReflectablePtrFieldBase* field = static_cast<RTTIReflectablePtrFieldBase*>(genericField);
  304. return field->getValue(object);
  305. }
  306. /**
  307. * @brief Reads a value from a reflectable pointer array field with the specified name and index from the provided instance.
  308. *
  309. * @note Caller must ensure instance and value types are valid for this field.
  310. */
  311. template <class ObjectType>
  312. std::shared_ptr<IReflectable> getReflectablePtrArrayValue(ObjectType* object, const String& name, UINT32 index)
  313. {
  314. RTTIField* genericField = findField(name);
  315. genericField->checkIsComplexPtr(true);
  316. RTTIReflectablePtrFieldBase* field = static_cast<RTTIReflectablePtrFieldBase*>(genericField);
  317. return field->getArrayValue(object, index);
  318. }
  319. /**
  320. * @brief Returns the size of the array of the field with the specified name on the provided instance.
  321. *
  322. * @note Caller must ensure instance type is valid and that the field as an array.
  323. */
  324. template <class ObjectType>
  325. UINT32 getArraySize(ObjectType* object, const String& name)
  326. {
  327. RTTIField* field = findField(name);
  328. return field->getArraySize(object);
  329. }
  330. /**
  331. * @brief Sets the size of the array of the field with the specified name on the provided instance.
  332. *
  333. * @note Caller must ensure instance type is valid and that the field as an array.
  334. * This might clear any existing data from the array.
  335. */
  336. template <class ObjectType>
  337. void setArraySize(ObjectType* object, const String& name, UINT32 size)
  338. {
  339. RTTIField* field = findField(name);
  340. field->setArraySize(object, size);
  341. }
  342. /**
  343. * @brief Returns the total number of fields in this RTTI type.
  344. */
  345. UINT32 getNumFields() { return (UINT32)mFields.size(); }
  346. /**
  347. * @brief Returns a field based on the field index. Use "getNumFields" to
  348. * get total number of fields available.
  349. */
  350. RTTIField* getField(UINT32 idx) { return mFields.at(idx); }
  351. /**
  352. * @brief Tries to find a field with the specified name. Throws an exception if it can't.
  353. *
  354. * @param name The name of the field.
  355. */
  356. RTTIField* findField(const String& name);
  357. /**
  358. * @brief Tries to find a field with the specified unique ID. Doesn't throw an exception
  359. * if it can't find the field (Unlike findField(name)).
  360. *
  361. * @param uniqueFieldId Unique identifier for the field.
  362. *
  363. * @return nullptr if it can't find the field.
  364. */
  365. RTTIField* findField(int uniqueFieldId);
  366. protected:
  367. /**
  368. * @brief Tries to add a new field to the fields array, and throws an exception
  369. * if a field with the same name or id already exists.
  370. *
  371. * @param [in] field Field, must be non-null.
  372. */
  373. void addNewField(RTTIField* field);
  374. /**
  375. * @brief Checks if the templated DataType has any references back to us, that aren't weak.
  376. *
  377. * @note This method assumes this class holds a non-weak reference to DataType.
  378. * DataType must derive from IReflectable and implement getRTTIStatic method.
  379. */
  380. template<class DataType>
  381. void checkForCircularReferences()
  382. {
  383. RTTITypeBase* type = DataType::getRTTIStatic();
  384. for(UINT32 i = 0; i < type->getNumFields(); i++)
  385. {
  386. RTTIField* field = type->getField(i);
  387. if(!field->isReflectablePtrType())
  388. continue;
  389. RTTIReflectablePtrFieldBase* reflectablePtrField = static_cast<RTTIReflectablePtrFieldBase*>(field);
  390. if(reflectablePtrField->getRTTIId() == getRTTIId() && ((reflectablePtrField->getFlags() & RTTI_Flag_WeakRef) == 0))
  391. {
  392. throwCircularRefException(getRTTIName(), reflectablePtrField->getRTTIName());
  393. }
  394. }
  395. }
  396. /**
  397. * @brief Throws an exception warning the user that a circular reference was found.
  398. *
  399. * @note Only a separate function so I don't need to include CmException header.
  400. */
  401. void throwCircularRefException(const String& myType, const String& otherType) const;
  402. private:
  403. Vector<RTTIField*>::type mFields;
  404. };
  405. /**
  406. * @brief Used for initializing a certain type as soon as the program is loaded.
  407. */
  408. template<typename Type, typename BaseType>
  409. struct InitRTTIOnStart
  410. {
  411. public:
  412. InitRTTIOnStart()
  413. {
  414. BaseType::getRTTIStatic()->_registerDerivedClass(Type::getRTTIStatic());
  415. }
  416. void makeSureIAmInstantiated() { }
  417. };
  418. /**
  419. * @brief Specialization for root class of RTTI hierarchy - IReflectable
  420. */
  421. template<typename Type>
  422. struct InitRTTIOnStart<Type, IReflectable>
  423. {
  424. public:
  425. InitRTTIOnStart()
  426. {
  427. IReflectable::_registerDerivedClass(Type::getRTTIStatic());
  428. }
  429. void makeSureIAmInstantiated() { }
  430. };
  431. /**
  432. * @brief Template that returns RTTI type of the specified type, unless the specified
  433. * type is IReflectable in which case it returns a null.
  434. */
  435. template<typename Type>
  436. struct GetRTTIType
  437. {
  438. RTTITypeBase* operator()() { return Type::getRTTIStatic(); }
  439. };
  440. /**
  441. * @brief Specialization for root class of RTTI hierarchy - IReflectable
  442. */
  443. template<>
  444. struct GetRTTIType<IReflectable>
  445. {
  446. RTTITypeBase* operator()() { return nullptr; }
  447. };
  448. /**
  449. * @brief Allows you to provide a run-time type information for a specific class, along with
  450. * support for serialization/deserialization.
  451. *
  452. * Derive from this class and return the that class from IReflectable::getRTTI.
  453. * This way you can separate serialization logic from the actual class you're serializing.
  454. *
  455. * This class will provide a way to register individual fields in the class, together with ways to
  456. * read and write them, as well a providing information about class hierarchy, and run-time type checking.
  457. */
  458. template <typename Type, typename BaseType, typename MyRTTIType>
  459. class RTTIType : public RTTITypeBase
  460. {
  461. protected:
  462. /************************************************************************/
  463. /* RTTI CLASS META DATA */
  464. /************************************************************************/
  465. static InitRTTIOnStart<Type, BaseType> initOnStart;
  466. public:
  467. RTTIType()
  468. {
  469. // Compiler will only generate code for stuff that is directly used, including static data members,
  470. // so we fool it here like we're using the class directly. Otherwise compiler won't generate the code for the member
  471. // and our type won't get initialized on start (Actual behavior is a bit more random)
  472. initOnStart.makeSureIAmInstantiated();
  473. }
  474. virtual ~RTTIType() {}
  475. /**
  476. * @brief Returns a singleton of this RTTI type.
  477. */
  478. static MyRTTIType* instance()
  479. {
  480. static MyRTTIType inst;
  481. return &inst;
  482. }
  483. /**
  484. * @copydoc RTTITypeBase::getDerivedClasses
  485. */
  486. virtual Vector<RTTITypeBase*>::type& getDerivedClasses()
  487. {
  488. static Vector<RTTITypeBase*>::type mRTTIDerivedClasses;
  489. return mRTTIDerivedClasses;
  490. }
  491. /**
  492. * @copydoc RTTITypeBase::getBaseClass
  493. */
  494. virtual RTTITypeBase* getBaseClass()
  495. {
  496. return GetRTTIType<BaseType>()();
  497. }
  498. /**
  499. * @copydoc RTTITypeBase::_registerDerivedClass
  500. */
  501. virtual void _registerDerivedClass(RTTITypeBase* derivedClass)
  502. {
  503. if(IReflectable::_isTypeIdDuplicate(derivedClass->getRTTIId()))
  504. {
  505. CM_EXCEPT(InternalErrorException, "RTTI type \"" + derivedClass->getRTTIName() +
  506. "\" has a duplicate ID: " + toString(derivedClass->getRTTIId()));
  507. }
  508. getDerivedClasses().push_back(derivedClass);
  509. }
  510. /************************************************************************/
  511. /* FIELDS OPERATING DIRECTLY ON SERIALIZABLE OBJECT */
  512. /************************************************************************/
  513. /**
  514. * @brief Registers a new plain field. This field can then be accessed dynamically from the RTTI system and
  515. * used for automatic serialization. See RTTIField for more information about field types.
  516. *
  517. * @param name Name of the field.
  518. * @param uniqueId Unique identifier for this field. Although name is also a unique
  519. * identifier we want a small data type that can be used for efficiently
  520. * serializing data to disk and similar. It is primarily used for compatibility
  521. * between different versions of serialized data.
  522. * @param getter Method used for retrieving the value of this field.
  523. * @param setter Method used for setting the value of this field.
  524. * @param flags Various flags you can use to specialize how systems handle this field. See RTTIFieldFlag.
  525. */
  526. template<class ObjectType, class DataType>
  527. void addPlainField(const String& name, UINT32 uniqueId, DataType& (ObjectType::*getter)(),
  528. void (ObjectType::*setter)(DataType&) = nullptr, UINT64 flags = 0)
  529. {
  530. addPlainField<ObjectType, DataType>(name, uniqueId,
  531. std::function<DataType&(ObjectType*)>(getter),
  532. std::function<void(ObjectType*, DataType&)>(setter), flags);
  533. }
  534. /**
  535. * @brief Registers a new reflectable object field. This field can then be accessed dynamically from the RTTI system and
  536. * used for automatic serialization. See RTTIField for more information about field types.
  537. *
  538. * @param name Name of the field.
  539. * @param uniqueId Unique identifier for this field. Although name is also a unique
  540. * identifier we want a small data type that can be used for efficiently
  541. * serializing data to disk and similar. It is primarily used for compatibility
  542. * between different versions of serialized data.
  543. * @param getter Method used for retrieving the value of this field.
  544. * @param setter Method used for setting the value of this field.
  545. * @param flags Various flags you can use to specialize how systems handle this field. See RTTIFieldFlag.
  546. */
  547. template<class ObjectType, class DataType>
  548. void addReflectableField(const String& name, UINT32 uniqueId, DataType& (ObjectType::*getter)(),
  549. void (ObjectType::*setter)(DataType&) = nullptr, UINT64 flags = 0)
  550. {
  551. addReflectableField<ObjectType, DataType>(name, uniqueId,
  552. std::function<DataType&(ObjectType*)>(getter),
  553. std::function<void(ObjectType*, DataType&)>(setter), flags);
  554. }
  555. /**
  556. * @brief Registers a new reflectable object pointer field. This field can then be accessed dynamically from the RTTI system and
  557. * used for automatic serialization. See RTTIField for more information about field types.
  558. *
  559. * @param name Name of the field.
  560. * @param uniqueId Unique identifier for this field. Although name is also a unique
  561. * identifier we want a small data type that can be used for efficiently
  562. * serializing data to disk and similar. It is primarily used for compatibility
  563. * between different versions of serialized data.
  564. * @param getter Method used for retrieving the value of this field.
  565. * @param setter Method used for setting the value of this field.
  566. * @param flags Various flags you can use to specialize how systems handle this field. See RTTIFieldFlag.
  567. */
  568. template<class ObjectType, class DataType>
  569. void addReflectablePtrField(const String& name, UINT32 uniqueId, std::shared_ptr<DataType> (ObjectType::*getter)(),
  570. void (ObjectType::*setter)(std::shared_ptr<DataType>) = nullptr, UINT64 flags = 0)
  571. {
  572. addReflectablePtrField<ObjectType, DataType>(name, uniqueId,
  573. std::function<std::shared_ptr<DataType>(ObjectType*)>(getter),
  574. std::function<void(ObjectType*, std::shared_ptr<DataType>)>(setter), flags);
  575. }
  576. /**
  577. * @brief Registers a new field containg an array of plain values. This field can then be accessed dynamically from the RTTI system and
  578. * used for automatic serialization. See RTTIField for more information about field types.
  579. *
  580. * @param name Name of the field.
  581. * @param uniqueId Unique identifier for this field. Although name is also a unique
  582. * identifier we want a small data type that can be used for efficiently
  583. * serializing data to disk and similar. It is primarily used for compatibility
  584. * between different versions of serialized data.
  585. * @param getter Method used for retrieving a single element of the array.
  586. * @param getSize Getter method that returns the size of the array.
  587. * @param setter Method used for setting the a single element of the field.
  588. * @param setSize Setter method that allows you to resize the array.
  589. * @param flags Various flags you can use to specialize how systems handle this field. See RTTIFieldFlag.
  590. */
  591. template<class ObjectType, class DataType>
  592. void addPlainArrayField(const String& name, UINT32 uniqueId, DataType& (ObjectType::*getter)(UINT32), UINT32 (ObjectType::*getSize)(),
  593. void (ObjectType::*setter)(UINT32, DataType&) = nullptr, void(ObjectType::*setSize)(UINT32) = nullptr, UINT64 flags = 0)
  594. {
  595. addPlainArrayField<ObjectType, DataType>(name, uniqueId,
  596. std::function<DataType&(ObjectType*, UINT32)>(getter),
  597. std::function<UINT32(ObjectType*)>(getSize),
  598. std::function<void(ObjectType*, UINT32, DataType&)>(setter),
  599. std::function<void(ObjectType*, UINT32)>(setSize), flags);
  600. }
  601. /**
  602. * @brief Registers a new field containg an array of reflectable object values. This field can then be accessed
  603. * dynamically from the RTTI system and used for automatic serialization. See RTTIField for more information
  604. * about field types.
  605. *
  606. * @param name Name of the field.
  607. * @param uniqueId Unique identifier for this field. Although name is also a unique
  608. * identifier we want a small data type that can be used for efficiently
  609. * serializing data to disk and similar. It is primarily used for compatibility
  610. * between different versions of serialized data.
  611. * @param getter Method used for retrieving a single element of the array.
  612. * @param getSize Getter method that returns the size of the array.
  613. * @param setter Method used for setting the a single element of the field.
  614. * @param setSize Setter method that allows you to resize the array.
  615. * @param flags Various flags you can use to specialize how systems handle this field. See RTTIFieldFlag.
  616. */
  617. template<class ObjectType, class DataType>
  618. void addReflectableArrayField(const String& name, UINT32 uniqueId, DataType& (ObjectType::*getter)(UINT32), UINT32 (ObjectType::*getSize)(),
  619. void (ObjectType::*setter)(UINT32, DataType&) = nullptr, void(ObjectType::*setSize)(UINT32) = nullptr, UINT64 flags = 0)
  620. {
  621. addReflectableArrayField<ObjectType, DataType>(name, uniqueId,
  622. std::function<DataType&(ObjectType*, UINT32)>(getter),
  623. std::function<UINT32(ObjectType*)>(getSize),
  624. std::function<void(ObjectType*, UINT32, DataType&)>(setter),
  625. std::function<void(ObjectType*, UINT32)>(setSize), flags);
  626. }
  627. /**
  628. * @brief Registers a new field containg an array of reflectable obejct pointers. This field can then be accessed
  629. * dynamically from the RTTI system and used for automatic serialization. See RTTIField for more information
  630. * about field types.
  631. *
  632. * @param name Name of the field.
  633. * @param uniqueId Unique identifier for this field. Although name is also a unique
  634. * identifier we want a small data type that can be used for efficiently
  635. * serializing data to disk and similar. It is primarily used for compatibility
  636. * between different versions of serialized data.
  637. * @param getter Method used for retrieving a single element of the array.
  638. * @param getSize Getter method that returns the size of the array.
  639. * @param setter Method used for setting the a single element of the field.
  640. * @param setSize Setter method that allows you to resize the array.
  641. * @param flags Various flags you can use to specialize how systems handle this field. See RTTIFieldFlag.
  642. */
  643. template<class ObjectType, class DataType>
  644. void addReflectablePtrArrayField(const String& name, UINT32 uniqueId, std::shared_ptr<DataType> (ObjectType::*getter)(UINT32), UINT32 (ObjectType::*getSize)(),
  645. void (ObjectType::*setter)(UINT32, std::shared_ptr<DataType>) = nullptr, void(ObjectType::*setSize)(UINT32) = nullptr, UINT64 flags = 0)
  646. {
  647. addReflectablePtrArrayField<ObjectType, DataType>(name, uniqueId,
  648. std::function<std::shared_ptr<DataType>(ObjectType*, UINT32)>(getter),
  649. std::function<UINT32(ObjectType*)>(getSize),
  650. std::function<void(ObjectType*, UINT32, std::shared_ptr<DataType>)>(setter),
  651. std::function<void(ObjectType*, UINT32)>(setSize), flags);
  652. }
  653. /**
  654. * @brief Registers a new managed data block field. This field can then be accessed dynamically from the RTTI system and
  655. * used for automatic serialization. See RTTIField for more information about field types.
  656. *
  657. * @param name Name of the field.
  658. * @param uniqueId Unique identifier for this field. Although name is also a unique
  659. * identifier we want a small data type that can be used for efficiently
  660. * serializing data to disk and similar. It is primarily used for compatibility
  661. * between different versions of serialized data.
  662. * @param getter Method used for retrieving the value of this field.
  663. * @param setter Method used for setting the value of this field.
  664. * @param flags Various flags you can use to specialize how systems handle this field. See RTTIFieldFlag.
  665. */
  666. template<class ObjectType>
  667. void addDataBlockField(const String& name, UINT32 uniqueId, ManagedDataBlock (ObjectType::*getter)(),
  668. void (ObjectType::*setter)(ManagedDataBlock) = nullptr, UINT64 flags = 0, UINT8* (customAllocator)(ObjectType*, UINT32) = 0)
  669. {
  670. addDataBlockField<ObjectType>(name, uniqueId,
  671. std::function<ManagedDataBlock(ObjectType*)>(getter),
  672. std::function<void(ObjectType*, ManagedDataBlock)>(setter), flags, customAllocator);
  673. }
  674. protected:
  675. virtual void initSerializableFields() {}
  676. /************************************************************************/
  677. /* FIELDS OPERATING ON DERIVED SERIALIZATION INTERFACE */
  678. /* (Needs an extra pointer to the actual object) */
  679. /************************************************************************/
  680. template<class InterfaceType, class ObjectType, class DataType>
  681. void addPlainField(const String& name, UINT32 uniqueId,
  682. DataType& (InterfaceType::*getter)(ObjectType*),
  683. void (InterfaceType::*setter)(ObjectType*, DataType&), UINT64 flags = 0)
  684. {
  685. using namespace std::placeholders;
  686. static_assert((std::is_base_of<CamelotFramework::RTTIType<Type, BaseType, MyRTTIType>, InterfaceType>::value),
  687. "Class with the get/set methods must derive from CamelotFramework::RTTIType.");
  688. static_assert(!(std::is_base_of<CamelotFramework::IReflectable, DataType>::value),
  689. "Data type derives from IReflectable but it is being added as a plain field.");
  690. addPlainField<ObjectType, DataType>(name, uniqueId,
  691. std::function<DataType&(ObjectType*)>(std::bind(getter, static_cast<InterfaceType*>(this), _1)),
  692. std::function<void(ObjectType*, DataType&)>(std::bind(setter, static_cast<InterfaceType*>(this), _1, _2)), flags);
  693. }
  694. template<class InterfaceType, class ObjectType, class DataType>
  695. void addReflectableField(const String& name, UINT32 uniqueId,
  696. DataType& (InterfaceType::*getter)(ObjectType*),
  697. void (InterfaceType::*setter)(ObjectType*, DataType&), UINT64 flags = 0)
  698. {
  699. using namespace std::placeholders;
  700. addReflectableField<ObjectType, DataType>(name, uniqueId,
  701. std::function<DataType&(ObjectType*)>(std::bind(getter, static_cast<InterfaceType*>(this), _1)),
  702. std::function<void(ObjectType*, DataType&)>(std::bind(setter, static_cast<InterfaceType*>(this), _1, _2)), flags);
  703. }
  704. template<class InterfaceType, class ObjectType, class DataType>
  705. void addReflectablePtrField(const String& name, UINT32 uniqueId,
  706. std::shared_ptr<DataType> (InterfaceType::*getter)(ObjectType*),
  707. void (InterfaceType::*setter)(ObjectType*, std::shared_ptr<DataType>), UINT64 flags = 0)
  708. {
  709. using namespace std::placeholders;
  710. addReflectablePtrField<ObjectType, DataType>(name, uniqueId,
  711. std::function<std::shared_ptr<DataType>(ObjectType*)>(std::bind(getter, static_cast<InterfaceType*>(this), _1)),
  712. std::function<void(ObjectType*, std::shared_ptr<DataType>)>(std::bind(setter, static_cast<InterfaceType*>(this), _1, _2)), flags);
  713. }
  714. template<class InterfaceType, class ObjectType, class DataType>
  715. void addPlainArrayField(const String& name, UINT32 uniqueId,
  716. DataType& (InterfaceType::*getter)(ObjectType*, UINT32),
  717. UINT32 (InterfaceType::*getSize)(ObjectType*),
  718. void (InterfaceType::*setter)(ObjectType*, UINT32, DataType&),
  719. void(InterfaceType::*setSize)(ObjectType*, UINT32), UINT64 flags = 0)
  720. {
  721. using namespace std::placeholders;
  722. static_assert((std::is_base_of<CamelotFramework::RTTIType<Type, BaseType, MyRTTIType>, InterfaceType>::value),
  723. "Class with the get/set methods must derive from CamelotFramework::RTTIType.");
  724. static_assert(!(std::is_base_of<CamelotFramework::IReflectable, DataType>::value),
  725. "Data type derives from IReflectable but it is being added as a plain field.");
  726. addPlainArrayField<ObjectType, DataType>(name, uniqueId,
  727. std::function<DataType&(ObjectType*, UINT32)>(std::bind(getter, static_cast<InterfaceType*>(this), _1, _2)),
  728. std::function<UINT32(ObjectType*)>(std::bind(getSize, static_cast<InterfaceType*>(this), _1)),
  729. std::function<void(ObjectType*, UINT32, DataType&)>(std::bind(setter, static_cast<InterfaceType*>(this), _1, _2, _3)),
  730. std::function<void(ObjectType*, UINT32)>(std::bind(setSize, static_cast<InterfaceType*>(this), _1, _2)), flags);
  731. }
  732. template<class InterfaceType, class ObjectType, class DataType>
  733. void addReflectableArrayField(const String& name, UINT32 uniqueId,
  734. DataType& (InterfaceType::*getter)(ObjectType*, UINT32),
  735. UINT32 (InterfaceType::*getSize)(ObjectType*),
  736. void (InterfaceType::*setter)(ObjectType*, UINT32, DataType&),
  737. void(InterfaceType::*setSize)(ObjectType*, UINT32), UINT64 flags = 0)
  738. {
  739. using namespace std::placeholders;
  740. addReflectableArrayField<ObjectType, DataType>(name, uniqueId,
  741. std::function<DataType&(ObjectType*, UINT32)>(std::bind(getter, static_cast<InterfaceType*>(this), _1, _2)),
  742. std::function<UINT32(ObjectType*)>(std::bind(getSize, static_cast<InterfaceType*>(this), _1)),
  743. std::function<void(ObjectType*, UINT32, DataType&)>(std::bind(setter, static_cast<InterfaceType*>(this), _1, _2, _3)),
  744. std::function<void(ObjectType*, UINT32)>(std::bind(setSize, static_cast<InterfaceType*>(this), _1, _2)), flags);
  745. }
  746. template<class InterfaceType, class ObjectType, class DataType>
  747. void addReflectablePtrArrayField(const String& name, UINT32 uniqueId,
  748. std::shared_ptr<DataType> (InterfaceType::*getter)(ObjectType*, UINT32),
  749. UINT32 (InterfaceType::*getSize)(ObjectType*),
  750. void (InterfaceType::*setter)(ObjectType*, UINT32, std::shared_ptr<DataType>),
  751. void(InterfaceType::*setSize)(ObjectType*, UINT32), UINT64 flags = 0)
  752. {
  753. using namespace std::placeholders;
  754. addReflectablePtrArrayField<ObjectType, DataType>(name, uniqueId,
  755. std::function<std::shared_ptr<DataType>(ObjectType*, UINT32)>(std::bind(getter, static_cast<InterfaceType*>(this), _1, _2)),
  756. std::function<UINT32(ObjectType*)>(std::bind(getSize, static_cast<InterfaceType*>(this), _1)),
  757. std::function<void(ObjectType*, UINT32, std::shared_ptr<DataType>)>(std::bind(setter, static_cast<InterfaceType*>(this), _1, _2, _3)),
  758. std::function<void(ObjectType*, UINT32)>(std::bind(setSize, static_cast<InterfaceType*>(this), _1, _2)), flags);
  759. }
  760. template<class InterfaceType, class ObjectType>
  761. void addDataBlockField(const String& name, UINT32 uniqueId, ManagedDataBlock (InterfaceType::*getter)(ObjectType*),
  762. void (InterfaceType::*setter)(ObjectType*, ManagedDataBlock), UINT64 flags = 0,
  763. UINT8* (customAllocator)(ObjectType*, UINT32) = 0)
  764. {
  765. using namespace std::placeholders;
  766. if(customAllocator != 0)
  767. {
  768. std::function<UINT8*(ObjectType*, UINT32)> customAllocFunc = std::bind(customAllocator, _1, _2);
  769. addDataBlockField<ObjectType>(name, uniqueId,
  770. std::function<ManagedDataBlock(ObjectType*)>(std::bind(getter, static_cast<InterfaceType*>(this), _1)),
  771. std::function<void(ObjectType*, ManagedDataBlock)>(std::bind(setter, static_cast<InterfaceType*>(this), _1, _2)), flags,
  772. customAllocFunc);
  773. }
  774. else
  775. {
  776. addDataBlockField<ObjectType>(name, uniqueId,
  777. std::function<ManagedDataBlock(ObjectType*)>(std::bind(getter, static_cast<InterfaceType*>(this), _1)),
  778. std::function<void(ObjectType*, ManagedDataBlock)>(std::bind(setter, static_cast<InterfaceType*>(this), _1, _2)), flags);
  779. }
  780. }
  781. private:
  782. template<class ObjectType, class DataType>
  783. void addPlainField(const String& name, UINT32 uniqueId, boost::any getter, boost::any setter, UINT64 flags)
  784. {
  785. RTTIPlainField<DataType, ObjectType>* newField =
  786. cm_new<RTTIPlainField<DataType, ObjectType>>();
  787. newField->initSingle(name, uniqueId, getter, setter, flags);
  788. addNewField(newField);
  789. }
  790. template<class ObjectType, class DataType>
  791. void addReflectableField(const String& name, UINT32 uniqueId, boost::any getter, boost::any setter, UINT64 flags)
  792. {
  793. static_assert((std::is_base_of<CamelotFramework::IReflectable, DataType>::value),
  794. "Invalid data type for complex field. It needs to derive from CamelotFramework::IReflectable.");
  795. RTTIReflectableField<DataType, ObjectType>* newField =
  796. cm_new<RTTIReflectableField<DataType, ObjectType>>();
  797. newField->initSingle(name, uniqueId, getter, setter, flags);
  798. addNewField(newField);
  799. }
  800. template<class ObjectType, class DataType>
  801. void addReflectablePtrField(const String& name, UINT32 uniqueId, boost::any getter, boost::any setter, UINT64 flags)
  802. {
  803. static_assert((std::is_base_of<CamelotFramework::IReflectable, DataType>::value),
  804. "Invalid data type for complex field. It needs to derive from CamelotFramework::IReflectable.");
  805. if((flags & RTTI_Flag_WeakRef) == 0)
  806. checkForCircularReferences<DataType>();
  807. RTTIReflectablePtrField<DataType, ObjectType>* newField =
  808. cm_new<RTTIReflectablePtrField<DataType, ObjectType>>();
  809. newField->initSingle(name, uniqueId, getter, setter, flags);
  810. addNewField(newField);
  811. }
  812. template<class ObjectType, class DataType>
  813. void addPlainArrayField(const String& name, UINT32 uniqueId, boost::any getter, boost::any getSize,
  814. boost::any setter, boost::any setSize, UINT64 flags)
  815. {
  816. RTTIPlainField<DataType, ObjectType>* newField =
  817. cm_new<RTTIPlainField<DataType, ObjectType>>();
  818. newField->initArray(name, uniqueId, getter, getSize, setter, setSize, flags);
  819. addNewField(newField);
  820. }
  821. template<class ObjectType, class DataType>
  822. void addReflectableArrayField(const String& name, UINT32 uniqueId, boost::any getter, boost::any getSize,
  823. boost::any setter, boost::any setSize, UINT64 flags)
  824. {
  825. static_assert((std::is_base_of<CamelotFramework::IReflectable, DataType>::value),
  826. "Invalid data type for complex field. It needs to derive from CamelotFramework::IReflectable.");
  827. RTTIReflectableField<DataType, ObjectType>* newField =
  828. cm_new<RTTIReflectableField<DataType, ObjectType>>();
  829. newField->initArray(name, uniqueId, getter, getSize, setter, setSize, flags);
  830. addNewField(newField);
  831. }
  832. template<class ObjectType, class DataType>
  833. void addReflectablePtrArrayField(const String& name, UINT32 uniqueId, boost::any getter, boost::any getSize,
  834. boost::any setter, boost::any setSize, UINT64 flags)
  835. {
  836. static_assert((std::is_base_of<CamelotFramework::IReflectable, DataType>::value),
  837. "Invalid data type for complex field. It needs to derive from CamelotFramework::IReflectable.");
  838. if((flags & RTTI_Flag_WeakRef) == 0)
  839. checkForCircularReferences<DataType>();
  840. RTTIReflectablePtrField<DataType, ObjectType>* newField =
  841. cm_new<RTTIReflectablePtrField<DataType, ObjectType>>();
  842. newField->initArray(name, uniqueId, getter, getSize, setter, setSize, flags);
  843. addNewField(newField);
  844. }
  845. template<class ObjectType>
  846. void addDataBlockField(const String& name, UINT32 uniqueId, boost::any getter, boost::any setter, UINT64 flags, boost::any customAllocator = boost::any())
  847. {
  848. RTTIManagedDataBlockField<ManagedDataBlock, ObjectType>* newField =
  849. cm_new<RTTIManagedDataBlockField<ManagedDataBlock, ObjectType>>();
  850. newField->initSingle(name, uniqueId, getter, setter, flags, customAllocator);
  851. addNewField(newField);
  852. }
  853. };
  854. template <typename Type, typename BaseType, typename MyRTTIType>
  855. InitRTTIOnStart<Type, BaseType> RTTIType<Type, BaseType, MyRTTIType>::initOnStart;
  856. /**
  857. * @brief Returns true if the provided object can be safely cast into type T.
  858. */
  859. template<class T>
  860. bool rtti_is_of_type(IReflectable* object)
  861. {
  862. static_assert((std::is_base_of<CamelotFramework::IReflectable, T>::value),
  863. "Invalid data type for type checking. It needs to derive from CamelotFramework::IReflectable.");
  864. return object->getTypeId() == T::getRTTIStatic()->getRTTIId();
  865. }
  866. /**
  867. * @brief Returns true if the provided object can be safely cast into type T.
  868. */
  869. template<class T>
  870. bool rtti_is_of_type(std::shared_ptr<IReflectable> object)
  871. {
  872. static_assert((std::is_base_of<CamelotFramework::IReflectable, T>::value),
  873. "Invalid data type for type checking. It needs to derive from CamelotFramework::IReflectable.");
  874. return object->getTypeId() == T::getRTTIStatic()->getRTTIId();
  875. }
  876. }