RTTI.h 16 KB

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