RTTI.h 17 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 Bar *
  89. /// StaticCast<Bar>(bar_ptr) returns bar_ptr casted to Bar *
  90. ///
  91. /// DynamicCast<Bar>(foo_ptr) returns nullptr
  92. /// DynamicCast<Bar>(bar_ptr) returns bar_ptr casted to Bar *
  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. #ifdef JPH_OBJECT_STREAM
  150. /// Attribute access
  151. void AddAttribute(const SerializableAttribute &inAttribute);
  152. int GetAttributeCount() const;
  153. const SerializableAttribute & GetAttribute(int inIdx) const;
  154. #endif // JPH_OBJECT_STREAM
  155. protected:
  156. /// Base class information
  157. struct BaseClass
  158. {
  159. const RTTI * mRTTI;
  160. int mOffset;
  161. };
  162. const char * mName; ///< Class name
  163. int mSize; ///< Class size
  164. StaticArray<BaseClass, 4> mBaseClasses; ///< Names of base classes
  165. pCreateObjectFunction mCreate; ///< Pointer to a function that will create a new instance of this class
  166. pDestructObjectFunction mDestruct; ///< Pointer to a function that will destruct an object of this class
  167. #ifdef JPH_OBJECT_STREAM
  168. StaticArray<SerializableAttribute, 32> mAttributes; ///< All attributes of this class
  169. #endif // JPH_OBJECT_STREAM
  170. };
  171. //////////////////////////////////////////////////////////////////////////////////////////
  172. // Add run time type info to types that don't have virtual functions
  173. //////////////////////////////////////////////////////////////////////////////////////////
  174. // JPH_DECLARE_RTTI_NON_VIRTUAL
  175. #define JPH_DECLARE_RTTI_NON_VIRTUAL(linkage, class_name) \
  176. public: \
  177. JPH_OVERRIDE_NEW_DELETE \
  178. friend linkage RTTI * GetRTTIOfType(class_name *); \
  179. friend inline const RTTI * GetRTTI([[maybe_unused]] const class_name *inObject) { return GetRTTIOfType(static_cast<class_name *>(nullptr)); }\
  180. static void sCreateRTTI(RTTI &inRTTI); \
  181. // JPH_IMPLEMENT_RTTI_NON_VIRTUAL
  182. #define JPH_IMPLEMENT_RTTI_NON_VIRTUAL(class_name) \
  183. RTTI * GetRTTIOfType(class_name *) \
  184. { \
  185. static RTTI rtti(#class_name, sizeof(class_name), []() -> void * { return new class_name; }, [](void *inObject) { delete (class_name *)inObject; }, &class_name::sCreateRTTI); \
  186. return &rtti; \
  187. } \
  188. void class_name::sCreateRTTI(RTTI &inRTTI) \
  189. //////////////////////////////////////////////////////////////////////////////////////////
  190. // Same as above, but when you cannot insert the declaration in the class
  191. // itself, for example for templates and third party classes
  192. //////////////////////////////////////////////////////////////////////////////////////////
  193. // JPH_DECLARE_RTTI_OUTSIDE_CLASS
  194. #define JPH_DECLARE_RTTI_OUTSIDE_CLASS(linkage, class_name) \
  195. linkage RTTI * GetRTTIOfType(class_name *); \
  196. inline const RTTI * GetRTTI(const class_name *inObject) { return GetRTTIOfType((class_name *)nullptr); }\
  197. void CreateRTTI##class_name(RTTI &inRTTI); \
  198. // JPH_IMPLEMENT_RTTI_OUTSIDE_CLASS
  199. #define JPH_IMPLEMENT_RTTI_OUTSIDE_CLASS(class_name) \
  200. RTTI * GetRTTIOfType(class_name *) \
  201. { \
  202. static RTTI rtti((const char *)#class_name, sizeof(class_name), []() -> void * { return new class_name; }, [](void *inObject) { delete (class_name *)inObject; }, &CreateRTTI##class_name); \
  203. return &rtti; \
  204. } \
  205. void CreateRTTI##class_name(RTTI &inRTTI)
  206. //////////////////////////////////////////////////////////////////////////////////////////
  207. // Same as above, but for classes that have virtual functions
  208. //////////////////////////////////////////////////////////////////////////////////////////
  209. #define JPH_DECLARE_RTTI_HELPER(linkage, class_name, modifier) \
  210. public: \
  211. JPH_OVERRIDE_NEW_DELETE \
  212. friend linkage RTTI * GetRTTIOfType(class_name *); \
  213. friend inline const RTTI * GetRTTI(const class_name *inObject) { return inObject->GetRTTI(); } \
  214. virtual const RTTI * GetRTTI() const modifier; \
  215. virtual const void * CastTo(const RTTI *inRTTI) const modifier; \
  216. static void sCreateRTTI(RTTI &inRTTI); \
  217. // JPH_DECLARE_RTTI_VIRTUAL - for derived classes with RTTI
  218. #define JPH_DECLARE_RTTI_VIRTUAL(linkage, class_name) \
  219. JPH_DECLARE_RTTI_HELPER(linkage, class_name, override)
  220. // JPH_IMPLEMENT_RTTI_VIRTUAL
  221. #define JPH_IMPLEMENT_RTTI_VIRTUAL(class_name) \
  222. RTTI * GetRTTIOfType(class_name *) \
  223. { \
  224. static RTTI rtti(#class_name, sizeof(class_name), []() -> void * { return new class_name; }, [](void *inObject) { delete (class_name *)inObject; }, &class_name::sCreateRTTI); \
  225. return &rtti; \
  226. } \
  227. const RTTI * class_name::GetRTTI() const \
  228. { \
  229. return JPH_RTTI(class_name); \
  230. } \
  231. const void * class_name::CastTo(const RTTI *inRTTI) const \
  232. { \
  233. return JPH_RTTI(class_name)->CastTo((const void *)this, inRTTI); \
  234. } \
  235. void class_name::sCreateRTTI(RTTI &inRTTI) \
  236. // JPH_DECLARE_RTTI_VIRTUAL_BASE - for concrete base class that has RTTI
  237. #define JPH_DECLARE_RTTI_VIRTUAL_BASE(linkage, class_name) \
  238. JPH_DECLARE_RTTI_HELPER(linkage, class_name, )
  239. // JPH_IMPLEMENT_RTTI_VIRTUAL_BASE
  240. #define JPH_IMPLEMENT_RTTI_VIRTUAL_BASE(class_name) \
  241. JPH_IMPLEMENT_RTTI_VIRTUAL(class_name)
  242. // JPH_DECLARE_RTTI_ABSTRACT - for derived abstract class that have RTTI
  243. #define JPH_DECLARE_RTTI_ABSTRACT(linkage, class_name) \
  244. JPH_DECLARE_RTTI_HELPER(linkage, class_name, override)
  245. // JPH_IMPLEMENT_RTTI_ABSTRACT
  246. #define JPH_IMPLEMENT_RTTI_ABSTRACT(class_name) \
  247. RTTI * GetRTTIOfType(class_name *) \
  248. { \
  249. static RTTI rtti(#class_name, sizeof(class_name), nullptr, [](void *inObject) { delete (class_name *)inObject; }, &class_name::sCreateRTTI); \
  250. return &rtti; \
  251. } \
  252. const RTTI * class_name::GetRTTI() const \
  253. { \
  254. return JPH_RTTI(class_name); \
  255. } \
  256. const void * class_name::CastTo(const RTTI *inRTTI) const \
  257. { \
  258. return JPH_RTTI(class_name)->CastTo((const void *)this, inRTTI); \
  259. } \
  260. void class_name::sCreateRTTI(RTTI &inRTTI) \
  261. // JPH_DECLARE_RTTI_ABSTRACT_BASE - for abstract base class that has RTTI
  262. #define JPH_DECLARE_RTTI_ABSTRACT_BASE(linkage, class_name) \
  263. JPH_DECLARE_RTTI_HELPER(linkage, class_name, )
  264. // JPH_IMPLEMENT_RTTI_ABSTRACT_BASE
  265. #define JPH_IMPLEMENT_RTTI_ABSTRACT_BASE(class_name) \
  266. JPH_IMPLEMENT_RTTI_ABSTRACT(class_name)
  267. //////////////////////////////////////////////////////////////////////////////////////////
  268. // Declare an RTTI class for registering with the factory
  269. //////////////////////////////////////////////////////////////////////////////////////////
  270. #define JPH_DECLARE_RTTI_FOR_FACTORY(linkage, class_name) \
  271. linkage RTTI * GetRTTIOfType(class class_name *);
  272. #define JPH_DECLARE_RTTI_WITH_NAMESPACE_FOR_FACTORY(linkage, name_space, class_name) \
  273. namespace name_space { \
  274. class class_name; \
  275. linkage RTTI * GetRTTIOfType(class class_name *); \
  276. }
  277. //////////////////////////////////////////////////////////////////////////////////////////
  278. // Find the RTTI of a class
  279. //////////////////////////////////////////////////////////////////////////////////////////
  280. #define JPH_RTTI(class_name) GetRTTIOfType(static_cast<class_name *>(nullptr))
  281. //////////////////////////////////////////////////////////////////////////////////////////
  282. // Macro to rename a class, useful for embedded classes:
  283. //
  284. // class A { class B { }; }
  285. //
  286. // Now use JPH_RENAME_CLASS(B, A::B) to avoid conflicts with other classes named B
  287. //////////////////////////////////////////////////////////////////////////////////////////
  288. // JPH_RENAME_CLASS
  289. #define JPH_RENAME_CLASS(class_name, new_name) \
  290. inRTTI.SetName(#new_name);
  291. //////////////////////////////////////////////////////////////////////////////////////////
  292. // Macro to add base classes
  293. //////////////////////////////////////////////////////////////////////////////////////////
  294. /// Define very dirty macro to get the offset of a baseclass into a class
  295. #define JPH_BASE_CLASS_OFFSET(inClass, inBaseClass) ((int(uint64((inBaseClass *)((inClass *)0x10000))))-0x10000)
  296. // JPH_ADD_BASE_CLASS
  297. #define JPH_ADD_BASE_CLASS(class_name, base_class_name) \
  298. inRTTI.AddBaseClass(JPH_RTTI(base_class_name), JPH_BASE_CLASS_OFFSET(class_name, base_class_name));
  299. //////////////////////////////////////////////////////////////////////////////////////////
  300. // Macros and templates to identify a class
  301. //////////////////////////////////////////////////////////////////////////////////////////
  302. /// Check if inObject is of DstType
  303. template <class Type>
  304. inline bool IsType(const Type *inObject, const RTTI *inRTTI)
  305. {
  306. return inObject == nullptr || *inObject->GetRTTI() == *inRTTI;
  307. }
  308. template <class Type>
  309. inline bool IsType(const RefConst<Type> &inObject, const RTTI *inRTTI)
  310. {
  311. return inObject == nullptr || *inObject->GetRTTI() == *inRTTI;
  312. }
  313. template <class Type>
  314. inline bool IsType(const Ref<Type> &inObject, const RTTI *inRTTI)
  315. {
  316. return inObject == nullptr || *inObject->GetRTTI() == *inRTTI;
  317. }
  318. /// Check if inObject is or is derived from DstType
  319. template <class Type>
  320. inline bool IsKindOf(const Type *inObject, const RTTI *inRTTI)
  321. {
  322. return inObject == nullptr || inObject->GetRTTI()->IsKindOf(inRTTI);
  323. }
  324. template <class Type>
  325. inline bool IsKindOf(const RefConst<Type> &inObject, const RTTI *inRTTI)
  326. {
  327. return inObject == nullptr || inObject->GetRTTI()->IsKindOf(inRTTI);
  328. }
  329. template <class Type>
  330. inline bool IsKindOf(const Ref<Type> &inObject, const RTTI *inRTTI)
  331. {
  332. return inObject == nullptr || inObject->GetRTTI()->IsKindOf(inRTTI);
  333. }
  334. /// Cast inObject to DstType, asserts on failure
  335. template <class DstType, class SrcType, std::enable_if_t<std::is_base_of_v<DstType, SrcType> || std::is_base_of_v<SrcType, DstType>, bool> = true>
  336. inline const DstType *StaticCast(const SrcType *inObject)
  337. {
  338. return static_cast<const DstType *>(inObject);
  339. }
  340. template <class DstType, class SrcType, std::enable_if_t<std::is_base_of_v<DstType, SrcType> || std::is_base_of_v<SrcType, DstType>, bool> = true>
  341. inline DstType *StaticCast(SrcType *inObject)
  342. {
  343. return static_cast<DstType *>(inObject);
  344. }
  345. template <class DstType, class SrcType, std::enable_if_t<std::is_base_of_v<DstType, SrcType> || std::is_base_of_v<SrcType, DstType>, bool> = true>
  346. inline const DstType *StaticCast(const RefConst<SrcType> &inObject)
  347. {
  348. return static_cast<const DstType *>(inObject.GetPtr());
  349. }
  350. template <class DstType, class SrcType, std::enable_if_t<std::is_base_of_v<DstType, SrcType> || std::is_base_of_v<SrcType, DstType>, bool> = true>
  351. inline DstType *StaticCast(const Ref<SrcType> &inObject)
  352. {
  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 const DstType *DynamicCast(const 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 DstType *DynamicCast(const 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