RTTI.h 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435
  1. // SPDX-FileCopyrightText: 2021 Jorrit Rouwe
  2. // SPDX-License-Identifier: MIT
  3. #pragma once
  4. #include <Jolt/Core/Reference.h>
  5. #include <Jolt/Core/StaticArray.h>
  6. #include <Jolt/ObjectStream/SerializableAttribute.h>
  7. JPH_NAMESPACE_BEGIN
  8. //////////////////////////////////////////////////////////////////////////////////////////
  9. // RTTI
  10. //////////////////////////////////////////////////////////////////////////////////////////
  11. /// Light weight runtime type information system. This way we don't need to turn
  12. /// on the default RTTI system of the compiler (introducing a possible overhead for every
  13. /// class)
  14. ///
  15. /// Notes:
  16. /// - An extra virtual member function is added. This adds 8 bytes to the size of
  17. /// an instance of the class (unless you are already using virtual functions).
  18. ///
  19. /// To use RTTI on a specific class use:
  20. ///
  21. /// Header file:
  22. ///
  23. /// class Foo
  24. /// {
  25. /// JPH_DECLARE_RTTI_VIRTUAL_BASE(Foo)
  26. /// }
  27. ///
  28. /// class Bar : public Foo
  29. /// {
  30. /// JPH_DECLARE_RTTI_VIRTUAL(Bar)
  31. /// };
  32. ///
  33. /// Implementation file:
  34. ///
  35. /// JPH_IMPLEMENT_RTTI_VIRTUAL_BASE(Foo)
  36. /// {
  37. /// }
  38. ///
  39. /// JPH_IMPLEMENT_RTTI_VIRTUAL(Bar)
  40. /// {
  41. /// JPH_ADD_BASE_CLASS(Bar, Foo) // Multiple inheritance is allowed, just do JPH_ADD_BASE_CLASS for every base class
  42. /// }
  43. ///
  44. /// For abstract classes use:
  45. ///
  46. /// Header file:
  47. ///
  48. /// class Foo
  49. /// {
  50. /// JPH_DECLARE_RTTI_ABSTRACT_BASE(Foo)
  51. ///
  52. /// public:
  53. /// virtual void AbstractFunction() = 0;
  54. /// }
  55. ///
  56. /// class Bar : public Foo
  57. /// {
  58. /// JPH_DECLARE_RTTI_VIRTUAL(Bar)
  59. ///
  60. /// public:
  61. /// virtual void AbstractFunction() { } // Function is now implemented so this class is no longer abstract
  62. /// };
  63. ///
  64. /// Implementation file:
  65. ///
  66. /// JPH_IMPLEMENT_RTTI_ABSTRACT_BASE(Foo)
  67. /// {
  68. /// }
  69. ///
  70. /// JPH_IMPLEMENT_RTTI_VIRTUAL(Bar)
  71. /// {
  72. /// JPH_ADD_BASE_CLASS(Bar, Foo)
  73. /// }
  74. ///
  75. /// Example of usage in a program:
  76. ///
  77. /// Foo *foo_ptr = new Foo;
  78. /// Foo *bar_ptr = new Bar;
  79. ///
  80. /// IsType(foo_ptr, RTTI(Bar)) returns false
  81. /// IsType(bar_ptr, RTTI(Bar)) returns true
  82. ///
  83. /// IsKindOf(foo_ptr, RTTI(Bar)) returns false
  84. /// IsKindOf(bar_ptr, RTTI(Foo)) returns true
  85. /// IsKindOf(bar_ptr, RTTI(Bar)) returns true
  86. ///
  87. /// StaticCast<Bar>(foo_ptr) asserts and returns foo_ptr casted to pBar
  88. /// StaticCast<Bar>(bar_ptr) returns bar_ptr casted to pBar
  89. ///
  90. /// DynamicCast<Bar>(foo_ptr) returns nullptr
  91. /// DynamicCast<Bar>(bar_ptr) returns bar_ptr casted to pBar
  92. ///
  93. /// Other feature of DynamicCast:
  94. ///
  95. /// class A { int data[5]; };
  96. /// class B { int data[7]; };
  97. /// class C : public A, public B { int data[9]; };
  98. ///
  99. /// C *c = new C;
  100. /// A *a = c;
  101. ///
  102. /// Note that:
  103. ///
  104. /// B *b = (B *)a;
  105. ///
  106. /// generates an invalid pointer,
  107. ///
  108. /// B *b = StaticCast<B>(a);
  109. ///
  110. /// doesn't compile, and
  111. ///
  112. /// B *b = DynamicCast<B>(a);
  113. ///
  114. /// does the correct cast
  115. class RTTI
  116. {
  117. public:
  118. /// Function to create an object
  119. using pCreateObjectFunction = void *(*)();
  120. /// Function to destroy an object
  121. using pDestructObjectFunction = void (*)(void *inObject);
  122. /// Function to initialize the runtime type info structure
  123. using pCreateRTTIFunction = void (*)(RTTI &inRTTI);
  124. /// Constructor
  125. RTTI(const char *inName, int inSize, pCreateObjectFunction inCreateObject, pDestructObjectFunction inDestructObject);
  126. RTTI(const char *inName, int inSize, pCreateObjectFunction inCreateObject, pDestructObjectFunction inDestructObject, pCreateRTTIFunction inCreateRTTI);
  127. // Properties
  128. inline const char * GetName() const { return mName; }
  129. void SetName(const char *inName) { mName = inName; }
  130. inline int GetSize() const { return mSize; }
  131. bool IsAbstract() const { return mCreate == nullptr || mDestruct == nullptr; }
  132. int GetBaseClassCount() const;
  133. const RTTI * GetBaseClass(int inIdx) const;
  134. uint32 GetHash() const;
  135. /// Create an object of this type (returns nullptr if the object is abstract)
  136. void * CreateObject() const;
  137. /// Destruct object of this type (does nothing if the object is abstract)
  138. void DestructObject(void *inObject) const;
  139. /// Add base class
  140. void AddBaseClass(const RTTI *inRTTI, int inOffset);
  141. /// Equality operators
  142. bool operator == (const RTTI &inRHS) const;
  143. bool operator != (const RTTI &inRHS) const { return !(*this == inRHS); }
  144. /// Test if this class is derived from class of type inRTTI
  145. bool IsKindOf(const RTTI *inRTTI) const;
  146. /// Cast inObject of this type to object of type inRTTI, returns nullptr if the cast is unsuccessful
  147. const void * CastTo(const void *inObject, const RTTI *inRTTI) const;
  148. /// Attribute access
  149. void AddAttribute(const SerializableAttribute &inAttribute);
  150. int GetAttributeCount() const;
  151. const SerializableAttribute & GetAttribute(int inIdx) const;
  152. protected:
  153. /// Base class information
  154. struct BaseClass
  155. {
  156. const RTTI * mRTTI;
  157. int mOffset;
  158. };
  159. const char * mName; ///< Class name
  160. int mSize; ///< Class size
  161. StaticArray<BaseClass, 4> mBaseClasses; ///< Names of base classes
  162. pCreateObjectFunction mCreate; ///< Pointer to a function that will create a new instance of this class
  163. pDestructObjectFunction mDestruct; ///< Pointer to a function that will destruct an object of this class
  164. StaticArray<SerializableAttribute, 32> mAttributes; ///< All attributes of this class
  165. };
  166. //////////////////////////////////////////////////////////////////////////////////////////
  167. // Add run time type info to types that don't have virtual functions
  168. //////////////////////////////////////////////////////////////////////////////////////////
  169. // JPH_DECLARE_RTTI_NON_VIRTUAL
  170. #define JPH_DECLARE_RTTI_NON_VIRTUAL(class_name) \
  171. public: \
  172. JPH_OVERRIDE_NEW_DELETE \
  173. friend RTTI * GetRTTIOfType(class_name *); \
  174. friend inline const RTTI * GetRTTI(const class_name *inObject) { return GetRTTIOfType((class_name *)nullptr); }\
  175. static void sCreateRTTI(RTTI &inRTTI); \
  176. // JPH_IMPLEMENT_RTTI_NON_VIRTUAL
  177. #define JPH_IMPLEMENT_RTTI_NON_VIRTUAL(class_name) \
  178. RTTI * GetRTTIOfType(class_name *) \
  179. { \
  180. static RTTI rtti(#class_name, sizeof(class_name), []() -> void * { return new class_name; }, [](void *inObject) { delete (class_name *)inObject; }, &class_name::sCreateRTTI); \
  181. return &rtti; \
  182. } \
  183. void class_name::sCreateRTTI(RTTI &inRTTI) \
  184. //////////////////////////////////////////////////////////////////////////////////////////
  185. // Same as above, but when you cannot insert the declaration in the class
  186. // itself, for example for templates and third party classes
  187. //////////////////////////////////////////////////////////////////////////////////////////
  188. // JPH_DECLARE_RTTI_OUTSIDE_CLASS
  189. #define JPH_DECLARE_RTTI_OUTSIDE_CLASS(class_name) \
  190. RTTI * GetRTTIOfType(class_name *); \
  191. inline const RTTI * GetRTTI(const class_name *inObject) { return GetRTTIOfType((class_name *)nullptr); }\
  192. void CreateRTTI##class_name(RTTI &inRTTI); \
  193. // JPH_IMPLEMENT_RTTI_OUTSIDE_CLASS
  194. #define JPH_IMPLEMENT_RTTI_OUTSIDE_CLASS(class_name) \
  195. RTTI * GetRTTIOfType(class_name *) \
  196. { \
  197. static RTTI rtti((const char *)#class_name, sizeof(class_name), []() -> void * { return new class_name; }, [](void *inObject) { delete (class_name *)inObject; }, &CreateRTTI##class_name); \
  198. return &rtti; \
  199. } \
  200. void CreateRTTI##class_name(RTTI &inRTTI)
  201. //////////////////////////////////////////////////////////////////////////////////////////
  202. // Same as above, but for classes that have virtual functions
  203. //////////////////////////////////////////////////////////////////////////////////////////
  204. #define JPH_DECLARE_RTTI_HELPER(class_name, modifier) \
  205. public: \
  206. JPH_OVERRIDE_NEW_DELETE \
  207. friend RTTI * GetRTTIOfType(class_name *); \
  208. friend inline const RTTI * GetRTTI(const class_name *inObject) { return inObject->GetRTTI(); } \
  209. virtual const RTTI * GetRTTI() const modifier; \
  210. virtual const void * CastTo(const RTTI *inRTTI) const modifier; \
  211. static void sCreateRTTI(RTTI &inRTTI); \
  212. // JPH_DECLARE_RTTI_VIRTUAL - for derived classes with RTTI
  213. #define JPH_DECLARE_RTTI_VIRTUAL(class_name) \
  214. JPH_DECLARE_RTTI_HELPER(class_name, override)
  215. // JPH_IMPLEMENT_RTTI_VIRTUAL
  216. #define JPH_IMPLEMENT_RTTI_VIRTUAL(class_name) \
  217. RTTI * GetRTTIOfType(class_name *) \
  218. { \
  219. static RTTI rtti(#class_name, sizeof(class_name), []() -> void * { return new class_name; }, [](void *inObject) { delete (class_name *)inObject; }, &class_name::sCreateRTTI); \
  220. return &rtti; \
  221. } \
  222. const RTTI * class_name::GetRTTI() const \
  223. { \
  224. return JPH_RTTI(class_name); \
  225. } \
  226. const void * class_name::CastTo(const RTTI *inRTTI) const \
  227. { \
  228. return JPH_RTTI(class_name)->CastTo((const void *)this, inRTTI); \
  229. } \
  230. void class_name::sCreateRTTI(RTTI &inRTTI) \
  231. // JPH_DECLARE_RTTI_VIRTUAL_BASE - for concrete base class that has RTTI
  232. #define JPH_DECLARE_RTTI_VIRTUAL_BASE(class_name) \
  233. JPH_DECLARE_RTTI_HELPER(class_name, )
  234. // JPH_IMPLEMENT_RTTI_VIRTUAL_BASE
  235. #define JPH_IMPLEMENT_RTTI_VIRTUAL_BASE(class_name) \
  236. JPH_IMPLEMENT_RTTI_VIRTUAL(class_name)
  237. // JPH_DECLARE_RTTI_ABSTRACT - for derived abstract class that have RTTI
  238. #define JPH_DECLARE_RTTI_ABSTRACT(class_name) \
  239. JPH_DECLARE_RTTI_HELPER(class_name, override)
  240. // JPH_IMPLEMENT_RTTI_ABSTRACT
  241. #define JPH_IMPLEMENT_RTTI_ABSTRACT(class_name) \
  242. RTTI * GetRTTIOfType(class_name *) \
  243. { \
  244. static RTTI rtti(#class_name, sizeof(class_name), nullptr, [](void *inObject) { delete (class_name *)inObject; }, &class_name::sCreateRTTI); \
  245. return &rtti; \
  246. } \
  247. const RTTI * class_name::GetRTTI() const \
  248. { \
  249. return JPH_RTTI(class_name); \
  250. } \
  251. const void * class_name::CastTo(const RTTI *inRTTI) const \
  252. { \
  253. return JPH_RTTI(class_name)->CastTo((const void *)this, inRTTI); \
  254. } \
  255. void class_name::sCreateRTTI(RTTI &inRTTI) \
  256. // JPH_DECLARE_RTTI_ABSTRACT_BASE - for abstract base class that has RTTI
  257. #define JPH_DECLARE_RTTI_ABSTRACT_BASE(class_name) \
  258. JPH_DECLARE_RTTI_HELPER(class_name, )
  259. // JPH_IMPLEMENT_RTTI_ABSTRACT_BASE
  260. #define JPH_IMPLEMENT_RTTI_ABSTRACT_BASE(class_name) \
  261. JPH_IMPLEMENT_RTTI_ABSTRACT(class_name)
  262. //////////////////////////////////////////////////////////////////////////////////////////
  263. // Declare an RTTI class for registering with the factory
  264. //////////////////////////////////////////////////////////////////////////////////////////
  265. #define JPH_DECLARE_RTTI_FOR_FACTORY(class_name) \
  266. RTTI * GetRTTIOfType(class class_name *);
  267. #define JPH_DECLARE_RTTI_WITH_NAMESPACE_FOR_FACTORY(name_space, class_name) \
  268. namespace name_space { \
  269. class class_name; \
  270. RTTI * GetRTTIOfType(class class_name *); \
  271. }
  272. //////////////////////////////////////////////////////////////////////////////////////////
  273. // Find the RTTI of a class
  274. //////////////////////////////////////////////////////////////////////////////////////////
  275. #define JPH_RTTI(class_name) GetRTTIOfType((class_name *)nullptr)
  276. //////////////////////////////////////////////////////////////////////////////////////////
  277. // Macro to rename a class, useful for embedded classes:
  278. //
  279. // class A { class B { }; }
  280. //
  281. // Now use JPH_RENAME_CLASS(B, A::B) to avoid conflicts with other classes named B
  282. //////////////////////////////////////////////////////////////////////////////////////////
  283. // JPH_RENAME_CLASS
  284. #define JPH_RENAME_CLASS(class_name, new_name) \
  285. inRTTI.SetName(#new_name);
  286. //////////////////////////////////////////////////////////////////////////////////////////
  287. // Macro to add base classes
  288. //////////////////////////////////////////////////////////////////////////////////////////
  289. /// Define very dirty macro to get the offset of a baseclass into a class
  290. #define JPH_BASE_CLASS_OFFSET(inClass, inBaseClass) ((int(uint64((inBaseClass *)((inClass *)0x10000))))-0x10000)
  291. // JPH_ADD_BASE_CLASS
  292. #define JPH_ADD_BASE_CLASS(class_name, base_class_name) \
  293. inRTTI.AddBaseClass(JPH_RTTI(base_class_name), JPH_BASE_CLASS_OFFSET(class_name, base_class_name));
  294. //////////////////////////////////////////////////////////////////////////////////////////
  295. // Macros and templates to identify a class
  296. //////////////////////////////////////////////////////////////////////////////////////////
  297. /// Check if inObject is of DstType
  298. template <class Type>
  299. inline bool IsType(const Type *inObject, const RTTI *inRTTI)
  300. {
  301. return inObject == nullptr || *inObject->GetRTTI() == *inRTTI;
  302. }
  303. template <class Type>
  304. inline bool IsType(const RefConst<Type> &inObject, const RTTI *inRTTI)
  305. {
  306. return inObject == nullptr || *inObject->GetRTTI() == *inRTTI;
  307. }
  308. template <class Type>
  309. inline bool IsType(const Ref<Type> &inObject, const RTTI *inRTTI)
  310. {
  311. return inObject == nullptr || *inObject->GetRTTI() == *inRTTI;
  312. }
  313. /// Check if inObject is or is derived from DstType
  314. template <class Type>
  315. inline bool IsKindOf(const Type *inObject, const RTTI *inRTTI)
  316. {
  317. return inObject == nullptr || inObject->GetRTTI()->IsKindOf(inRTTI);
  318. }
  319. template <class Type>
  320. inline bool IsKindOf(const RefConst<Type> &inObject, const RTTI *inRTTI)
  321. {
  322. return inObject == nullptr || inObject->GetRTTI()->IsKindOf(inRTTI);
  323. }
  324. template <class Type>
  325. inline bool IsKindOf(const Ref<Type> &inObject, const RTTI *inRTTI)
  326. {
  327. return inObject == nullptr || inObject->GetRTTI()->IsKindOf(inRTTI);
  328. }
  329. /// Cast inObject to DstType, asserts on failure
  330. template <class DstType, class SrcType>
  331. inline const DstType *StaticCast(const SrcType *inObject)
  332. {
  333. JPH_ASSERT(IsKindOf(inObject, JPH_RTTI(DstType)), "Invalid cast");
  334. return static_cast<const DstType *>(inObject);
  335. }
  336. template <class DstType, class SrcType>
  337. inline DstType *StaticCast(SrcType *inObject)
  338. {
  339. JPH_ASSERT(IsKindOf(inObject, JPH_RTTI(DstType)), "Invalid cast");
  340. return static_cast<DstType *>(inObject);
  341. }
  342. template <class DstType, class SrcType>
  343. inline RefConst<DstType> StaticCast(RefConst<SrcType> &inObject)
  344. {
  345. JPH_ASSERT(IsKindOf(inObject, JPH_RTTI(DstType)), "Invalid cast");
  346. return static_cast<const DstType *>(inObject.GetPtr());
  347. }
  348. template <class DstType, class SrcType>
  349. inline Ref<DstType> StaticCast(Ref<SrcType> &inObject)
  350. {
  351. JPH_ASSERT(IsKindOf(inObject, JPH_RTTI(DstType)), "Invalid cast");
  352. return static_cast<DstType *>(inObject.GetPtr());
  353. }
  354. /// Cast inObject to DstType, returns nullptr on failure
  355. template <class DstType, class SrcType>
  356. inline const DstType *DynamicCast(const SrcType *inObject)
  357. {
  358. return inObject != nullptr? reinterpret_cast<const DstType *>(inObject->CastTo(JPH_RTTI(DstType))) : nullptr;
  359. }
  360. template <class DstType, class SrcType>
  361. inline DstType *DynamicCast(SrcType *inObject)
  362. {
  363. return inObject != nullptr? const_cast<DstType *>(reinterpret_cast<const DstType *>(inObject->CastTo(JPH_RTTI(DstType)))) : nullptr;
  364. }
  365. template <class DstType, class SrcType>
  366. inline RefConst<DstType> DynamicCast(RefConst<SrcType> &inObject)
  367. {
  368. return inObject != nullptr? reinterpret_cast<const DstType *>(inObject->CastTo(JPH_RTTI(DstType))) : nullptr;
  369. }
  370. template <class DstType, class SrcType>
  371. inline Ref<DstType> DynamicCast(Ref<SrcType> &inObject)
  372. {
  373. return inObject != nullptr? const_cast<DstType *>(reinterpret_cast<const DstType *>(inObject->CastTo(JPH_RTTI(DstType)))) : nullptr;
  374. }
  375. JPH_NAMESPACE_END