Path: blob/master/thirdparty/jolt_physics/Jolt/Core/RTTI.h
9906 views
// Jolt Physics Library (https://github.com/jrouwe/JoltPhysics)1// SPDX-FileCopyrightText: 2021 Jorrit Rouwe2// SPDX-License-Identifier: MIT34#pragma once56#include <Jolt/Core/Reference.h>7#include <Jolt/Core/StaticArray.h>8#include <Jolt/ObjectStream/SerializableAttribute.h>910JPH_NAMESPACE_BEGIN1112//////////////////////////////////////////////////////////////////////////////////////////13// RTTI14//////////////////////////////////////////////////////////////////////////////////////////1516/// Light weight runtime type information system. This way we don't need to turn17/// on the default RTTI system of the compiler (introducing a possible overhead for every18/// class)19///20/// Notes:21/// - An extra virtual member function is added. This adds 8 bytes to the size of22/// an instance of the class (unless you are already using virtual functions).23///24/// To use RTTI on a specific class use:25///26/// Header file:27///28/// class Foo29/// {30/// JPH_DECLARE_RTTI_VIRTUAL_BASE(Foo)31/// }32///33/// class Bar : public Foo34/// {35/// JPH_DECLARE_RTTI_VIRTUAL(Bar)36/// };37///38/// Implementation file:39///40/// JPH_IMPLEMENT_RTTI_VIRTUAL_BASE(Foo)41/// {42/// }43///44/// JPH_IMPLEMENT_RTTI_VIRTUAL(Bar)45/// {46/// JPH_ADD_BASE_CLASS(Bar, Foo) // Multiple inheritance is allowed, just do JPH_ADD_BASE_CLASS for every base class47/// }48///49/// For abstract classes use:50///51/// Header file:52///53/// class Foo54/// {55/// JPH_DECLARE_RTTI_ABSTRACT_BASE(Foo)56///57/// public:58/// virtual void AbstractFunction() = 0;59/// }60///61/// class Bar : public Foo62/// {63/// JPH_DECLARE_RTTI_VIRTUAL(Bar)64///65/// public:66/// virtual void AbstractFunction() { } // Function is now implemented so this class is no longer abstract67/// };68///69/// Implementation file:70///71/// JPH_IMPLEMENT_RTTI_ABSTRACT_BASE(Foo)72/// {73/// }74///75/// JPH_IMPLEMENT_RTTI_VIRTUAL(Bar)76/// {77/// JPH_ADD_BASE_CLASS(Bar, Foo)78/// }79///80/// Example of usage in a program:81///82/// Foo *foo_ptr = new Foo;83/// Foo *bar_ptr = new Bar;84///85/// IsType(foo_ptr, RTTI(Bar)) returns false86/// IsType(bar_ptr, RTTI(Bar)) returns true87///88/// IsKindOf(foo_ptr, RTTI(Bar)) returns false89/// IsKindOf(bar_ptr, RTTI(Foo)) returns true90/// IsKindOf(bar_ptr, RTTI(Bar)) returns true91///92/// StaticCast<Bar>(foo_ptr) asserts and returns foo_ptr casted to Bar *93/// StaticCast<Bar>(bar_ptr) returns bar_ptr casted to Bar *94///95/// DynamicCast<Bar>(foo_ptr) returns nullptr96/// DynamicCast<Bar>(bar_ptr) returns bar_ptr casted to Bar *97///98/// Other feature of DynamicCast:99///100/// class A { int data[5]; };101/// class B { int data[7]; };102/// class C : public A, public B { int data[9]; };103///104/// C *c = new C;105/// A *a = c;106///107/// Note that:108///109/// B *b = (B *)a;110///111/// generates an invalid pointer,112///113/// B *b = StaticCast<B>(a);114///115/// doesn't compile, and116///117/// B *b = DynamicCast<B>(a);118///119/// does the correct cast120class JPH_EXPORT RTTI121{122public:123/// Function to create an object124using pCreateObjectFunction = void *(*)();125126/// Function to destroy an object127using pDestructObjectFunction = void (*)(void *inObject);128129/// Function to initialize the runtime type info structure130using pCreateRTTIFunction = void (*)(RTTI &inRTTI);131132/// Constructor133RTTI(const char *inName, int inSize, pCreateObjectFunction inCreateObject, pDestructObjectFunction inDestructObject);134RTTI(const char *inName, int inSize, pCreateObjectFunction inCreateObject, pDestructObjectFunction inDestructObject, pCreateRTTIFunction inCreateRTTI);135136// Properties137inline const char * GetName() const { return mName; }138void SetName(const char *inName) { mName = inName; }139inline int GetSize() const { return mSize; }140bool IsAbstract() const { return mCreate == nullptr || mDestruct == nullptr; }141int GetBaseClassCount() const;142const RTTI * GetBaseClass(int inIdx) const;143uint32 GetHash() const;144145/// Create an object of this type (returns nullptr if the object is abstract)146void * CreateObject() const;147148/// Destruct object of this type (does nothing if the object is abstract)149void DestructObject(void *inObject) const;150151/// Add base class152void AddBaseClass(const RTTI *inRTTI, int inOffset);153154/// Equality operators155bool operator == (const RTTI &inRHS) const;156bool operator != (const RTTI &inRHS) const { return !(*this == inRHS); }157158/// Test if this class is derived from class of type inRTTI159bool IsKindOf(const RTTI *inRTTI) const;160161/// Cast inObject of this type to object of type inRTTI, returns nullptr if the cast is unsuccessful162const void * CastTo(const void *inObject, const RTTI *inRTTI) const;163164#ifdef JPH_OBJECT_STREAM165/// Attribute access166void AddAttribute(const SerializableAttribute &inAttribute);167int GetAttributeCount() const;168const SerializableAttribute & GetAttribute(int inIdx) const;169#endif // JPH_OBJECT_STREAM170171protected:172/// Base class information173struct BaseClass174{175const RTTI * mRTTI;176int mOffset;177};178179const char * mName; ///< Class name180int mSize; ///< Class size181StaticArray<BaseClass, 4> mBaseClasses; ///< Names of base classes182pCreateObjectFunction mCreate; ///< Pointer to a function that will create a new instance of this class183pDestructObjectFunction mDestruct; ///< Pointer to a function that will destruct an object of this class184#ifdef JPH_OBJECT_STREAM185StaticArray<SerializableAttribute, 32> mAttributes; ///< All attributes of this class186#endif // JPH_OBJECT_STREAM187};188189//////////////////////////////////////////////////////////////////////////////////////////190// Add run time type info to types that don't have virtual functions191//////////////////////////////////////////////////////////////////////////////////////////192193// JPH_DECLARE_RTTI_NON_VIRTUAL194#define JPH_DECLARE_RTTI_NON_VIRTUAL(linkage, class_name) \195public: \196JPH_OVERRIDE_NEW_DELETE \197friend linkage RTTI * GetRTTIOfType(class_name *); \198friend inline const RTTI * GetRTTI([[maybe_unused]] const class_name *inObject) { return GetRTTIOfType(static_cast<class_name *>(nullptr)); }\199static void sCreateRTTI(RTTI &inRTTI); \200201// JPH_IMPLEMENT_RTTI_NON_VIRTUAL202#define JPH_IMPLEMENT_RTTI_NON_VIRTUAL(class_name) \203RTTI * GetRTTIOfType(class_name *) \204{ \205static RTTI rtti(#class_name, sizeof(class_name), []() -> void * { return new class_name; }, [](void *inObject) { delete (class_name *)inObject; }, &class_name::sCreateRTTI); \206return &rtti; \207} \208void class_name::sCreateRTTI(RTTI &inRTTI) \209210//////////////////////////////////////////////////////////////////////////////////////////211// Same as above, but when you cannot insert the declaration in the class212// itself, for example for templates and third party classes213//////////////////////////////////////////////////////////////////////////////////////////214215// JPH_DECLARE_RTTI_OUTSIDE_CLASS216#define JPH_DECLARE_RTTI_OUTSIDE_CLASS(linkage, class_name) \217linkage RTTI * GetRTTIOfType(class_name *); \218inline const RTTI * GetRTTI(const class_name *inObject) { return GetRTTIOfType((class_name *)nullptr); }\219void CreateRTTI##class_name(RTTI &inRTTI); \220221// JPH_IMPLEMENT_RTTI_OUTSIDE_CLASS222#define JPH_IMPLEMENT_RTTI_OUTSIDE_CLASS(class_name) \223RTTI * GetRTTIOfType(class_name *) \224{ \225static RTTI rtti((const char *)#class_name, sizeof(class_name), []() -> void * { return new class_name; }, [](void *inObject) { delete (class_name *)inObject; }, &CreateRTTI##class_name); \226return &rtti; \227} \228void CreateRTTI##class_name(RTTI &inRTTI)229230//////////////////////////////////////////////////////////////////////////////////////////231// Same as above, but for classes that have virtual functions232//////////////////////////////////////////////////////////////////////////////////////////233234#define JPH_DECLARE_RTTI_HELPER(linkage, class_name, modifier) \235public: \236JPH_OVERRIDE_NEW_DELETE \237friend linkage RTTI * GetRTTIOfType(class_name *); \238friend inline const RTTI * GetRTTI(const class_name *inObject) { return inObject->GetRTTI(); } \239virtual const RTTI * GetRTTI() const modifier; \240virtual const void * CastTo(const RTTI *inRTTI) const modifier; \241static void sCreateRTTI(RTTI &inRTTI); \242243// JPH_DECLARE_RTTI_VIRTUAL - for derived classes with RTTI244#define JPH_DECLARE_RTTI_VIRTUAL(linkage, class_name) \245JPH_DECLARE_RTTI_HELPER(linkage, class_name, override)246247// JPH_IMPLEMENT_RTTI_VIRTUAL248#define JPH_IMPLEMENT_RTTI_VIRTUAL(class_name) \249RTTI * GetRTTIOfType(class_name *) \250{ \251static RTTI rtti(#class_name, sizeof(class_name), []() -> void * { return new class_name; }, [](void *inObject) { delete (class_name *)inObject; }, &class_name::sCreateRTTI); \252return &rtti; \253} \254const RTTI * class_name::GetRTTI() const \255{ \256return JPH_RTTI(class_name); \257} \258const void * class_name::CastTo(const RTTI *inRTTI) const \259{ \260return JPH_RTTI(class_name)->CastTo((const void *)this, inRTTI); \261} \262void class_name::sCreateRTTI(RTTI &inRTTI) \263264// JPH_DECLARE_RTTI_VIRTUAL_BASE - for concrete base class that has RTTI265#define JPH_DECLARE_RTTI_VIRTUAL_BASE(linkage, class_name) \266JPH_DECLARE_RTTI_HELPER(linkage, class_name, )267268// JPH_IMPLEMENT_RTTI_VIRTUAL_BASE269#define JPH_IMPLEMENT_RTTI_VIRTUAL_BASE(class_name) \270JPH_IMPLEMENT_RTTI_VIRTUAL(class_name)271272// JPH_DECLARE_RTTI_ABSTRACT - for derived abstract class that have RTTI273#define JPH_DECLARE_RTTI_ABSTRACT(linkage, class_name) \274JPH_DECLARE_RTTI_HELPER(linkage, class_name, override)275276// JPH_IMPLEMENT_RTTI_ABSTRACT277#define JPH_IMPLEMENT_RTTI_ABSTRACT(class_name) \278RTTI * GetRTTIOfType(class_name *) \279{ \280static RTTI rtti(#class_name, sizeof(class_name), nullptr, [](void *inObject) { delete (class_name *)inObject; }, &class_name::sCreateRTTI); \281return &rtti; \282} \283const RTTI * class_name::GetRTTI() const \284{ \285return JPH_RTTI(class_name); \286} \287const void * class_name::CastTo(const RTTI *inRTTI) const \288{ \289return JPH_RTTI(class_name)->CastTo((const void *)this, inRTTI); \290} \291void class_name::sCreateRTTI(RTTI &inRTTI) \292293// JPH_DECLARE_RTTI_ABSTRACT_BASE - for abstract base class that has RTTI294#define JPH_DECLARE_RTTI_ABSTRACT_BASE(linkage, class_name) \295JPH_DECLARE_RTTI_HELPER(linkage, class_name, )296297// JPH_IMPLEMENT_RTTI_ABSTRACT_BASE298#define JPH_IMPLEMENT_RTTI_ABSTRACT_BASE(class_name) \299JPH_IMPLEMENT_RTTI_ABSTRACT(class_name)300301//////////////////////////////////////////////////////////////////////////////////////////302// Declare an RTTI class for registering with the factory303//////////////////////////////////////////////////////////////////////////////////////////304305#define JPH_DECLARE_RTTI_FOR_FACTORY(linkage, class_name) \306linkage RTTI * GetRTTIOfType(class class_name *);307308#define JPH_DECLARE_RTTI_WITH_NAMESPACE_FOR_FACTORY(linkage, name_space, class_name) \309namespace name_space { \310class class_name; \311linkage RTTI * GetRTTIOfType(class class_name *); \312}313314//////////////////////////////////////////////////////////////////////////////////////////315// Find the RTTI of a class316//////////////////////////////////////////////////////////////////////////////////////////317318#define JPH_RTTI(class_name) GetRTTIOfType(static_cast<class_name *>(nullptr))319320//////////////////////////////////////////////////////////////////////////////////////////321// Macro to rename a class, useful for embedded classes:322//323// class A { class B { }; }324//325// Now use JPH_RENAME_CLASS(B, A::B) to avoid conflicts with other classes named B326//////////////////////////////////////////////////////////////////////////////////////////327328// JPH_RENAME_CLASS329#define JPH_RENAME_CLASS(class_name, new_name) \330inRTTI.SetName(#new_name);331332//////////////////////////////////////////////////////////////////////////////////////////333// Macro to add base classes334//////////////////////////////////////////////////////////////////////////////////////////335336/// Define very dirty macro to get the offset of a baseclass into a class337#define JPH_BASE_CLASS_OFFSET(inClass, inBaseClass) ((int(uint64((inBaseClass *)((inClass *)0x10000))))-0x10000)338339// JPH_ADD_BASE_CLASS340#define JPH_ADD_BASE_CLASS(class_name, base_class_name) \341inRTTI.AddBaseClass(JPH_RTTI(base_class_name), JPH_BASE_CLASS_OFFSET(class_name, base_class_name));342343//////////////////////////////////////////////////////////////////////////////////////////344// Macros and templates to identify a class345//////////////////////////////////////////////////////////////////////////////////////////346347/// Check if inObject is of DstType348template <class Type>349inline bool IsType(const Type *inObject, const RTTI *inRTTI)350{351return inObject == nullptr || *inObject->GetRTTI() == *inRTTI;352}353354template <class Type>355inline bool IsType(const RefConst<Type> &inObject, const RTTI *inRTTI)356{357return inObject == nullptr || *inObject->GetRTTI() == *inRTTI;358}359360template <class Type>361inline bool IsType(const Ref<Type> &inObject, const RTTI *inRTTI)362{363return inObject == nullptr || *inObject->GetRTTI() == *inRTTI;364}365366/// Check if inObject is or is derived from DstType367template <class Type>368inline bool IsKindOf(const Type *inObject, const RTTI *inRTTI)369{370return inObject == nullptr || inObject->GetRTTI()->IsKindOf(inRTTI);371}372373template <class Type>374inline bool IsKindOf(const RefConst<Type> &inObject, const RTTI *inRTTI)375{376return inObject == nullptr || inObject->GetRTTI()->IsKindOf(inRTTI);377}378379template <class Type>380inline bool IsKindOf(const Ref<Type> &inObject, const RTTI *inRTTI)381{382return inObject == nullptr || inObject->GetRTTI()->IsKindOf(inRTTI);383}384385/// Cast inObject to DstType, asserts on failure386template <class DstType, class SrcType, std::enable_if_t<std::is_base_of_v<DstType, SrcType> || std::is_base_of_v<SrcType, DstType>, bool> = true>387inline const DstType *StaticCast(const SrcType *inObject)388{389return static_cast<const DstType *>(inObject);390}391392template <class DstType, class SrcType, std::enable_if_t<std::is_base_of_v<DstType, SrcType> || std::is_base_of_v<SrcType, DstType>, bool> = true>393inline DstType *StaticCast(SrcType *inObject)394{395return static_cast<DstType *>(inObject);396}397398template <class DstType, class SrcType, std::enable_if_t<std::is_base_of_v<DstType, SrcType> || std::is_base_of_v<SrcType, DstType>, bool> = true>399inline const DstType *StaticCast(const RefConst<SrcType> &inObject)400{401return static_cast<const DstType *>(inObject.GetPtr());402}403404template <class DstType, class SrcType, std::enable_if_t<std::is_base_of_v<DstType, SrcType> || std::is_base_of_v<SrcType, DstType>, bool> = true>405inline DstType *StaticCast(const Ref<SrcType> &inObject)406{407return static_cast<DstType *>(inObject.GetPtr());408}409410/// Cast inObject to DstType, returns nullptr on failure411template <class DstType, class SrcType>412inline const DstType *DynamicCast(const SrcType *inObject)413{414return inObject != nullptr? reinterpret_cast<const DstType *>(inObject->CastTo(JPH_RTTI(DstType))) : nullptr;415}416417template <class DstType, class SrcType>418inline DstType *DynamicCast(SrcType *inObject)419{420return inObject != nullptr? const_cast<DstType *>(reinterpret_cast<const DstType *>(inObject->CastTo(JPH_RTTI(DstType)))) : nullptr;421}422423template <class DstType, class SrcType>424inline const DstType *DynamicCast(const RefConst<SrcType> &inObject)425{426return inObject != nullptr? reinterpret_cast<const DstType *>(inObject->CastTo(JPH_RTTI(DstType))) : nullptr;427}428429template <class DstType, class SrcType>430inline DstType *DynamicCast(const Ref<SrcType> &inObject)431{432return inObject != nullptr? const_cast<DstType *>(reinterpret_cast<const DstType *>(inObject->CastTo(JPH_RTTI(DstType)))) : nullptr;433}434435JPH_NAMESPACE_END436437438