123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436 |
- // Jolt Physics Library (https://github.com/jrouwe/JoltPhysics)
- // SPDX-FileCopyrightText: 2021 Jorrit Rouwe
- // SPDX-License-Identifier: MIT
- #pragma once
- #include <Jolt/Core/Reference.h>
- #include <Jolt/Core/StaticArray.h>
- #include <Jolt/ObjectStream/SerializableAttribute.h>
- JPH_NAMESPACE_BEGIN
- //////////////////////////////////////////////////////////////////////////////////////////
- // RTTI
- //////////////////////////////////////////////////////////////////////////////////////////
- /// Light weight runtime type information system. This way we don't need to turn
- /// on the default RTTI system of the compiler (introducing a possible overhead for every
- /// class)
- ///
- /// Notes:
- /// - An extra virtual member function is added. This adds 8 bytes to the size of
- /// an instance of the class (unless you are already using virtual functions).
- ///
- /// To use RTTI on a specific class use:
- ///
- /// Header file:
- ///
- /// class Foo
- /// {
- /// JPH_DECLARE_RTTI_VIRTUAL_BASE(Foo)
- /// }
- ///
- /// class Bar : public Foo
- /// {
- /// JPH_DECLARE_RTTI_VIRTUAL(Bar)
- /// };
- ///
- /// Implementation file:
- ///
- /// JPH_IMPLEMENT_RTTI_VIRTUAL_BASE(Foo)
- /// {
- /// }
- ///
- /// JPH_IMPLEMENT_RTTI_VIRTUAL(Bar)
- /// {
- /// JPH_ADD_BASE_CLASS(Bar, Foo) // Multiple inheritance is allowed, just do JPH_ADD_BASE_CLASS for every base class
- /// }
- ///
- /// For abstract classes use:
- ///
- /// Header file:
- ///
- /// class Foo
- /// {
- /// JPH_DECLARE_RTTI_ABSTRACT_BASE(Foo)
- ///
- /// public:
- /// virtual void AbstractFunction() = 0;
- /// }
- ///
- /// class Bar : public Foo
- /// {
- /// JPH_DECLARE_RTTI_VIRTUAL(Bar)
- ///
- /// public:
- /// virtual void AbstractFunction() { } // Function is now implemented so this class is no longer abstract
- /// };
- ///
- /// Implementation file:
- ///
- /// JPH_IMPLEMENT_RTTI_ABSTRACT_BASE(Foo)
- /// {
- /// }
- ///
- /// JPH_IMPLEMENT_RTTI_VIRTUAL(Bar)
- /// {
- /// JPH_ADD_BASE_CLASS(Bar, Foo)
- /// }
- ///
- /// Example of usage in a program:
- ///
- /// Foo *foo_ptr = new Foo;
- /// Foo *bar_ptr = new Bar;
- ///
- /// IsType(foo_ptr, RTTI(Bar)) returns false
- /// IsType(bar_ptr, RTTI(Bar)) returns true
- ///
- /// IsKindOf(foo_ptr, RTTI(Bar)) returns false
- /// IsKindOf(bar_ptr, RTTI(Foo)) returns true
- /// IsKindOf(bar_ptr, RTTI(Bar)) returns true
- ///
- /// StaticCast<Bar>(foo_ptr) asserts and returns foo_ptr casted to pBar
- /// StaticCast<Bar>(bar_ptr) returns bar_ptr casted to pBar
- ///
- /// DynamicCast<Bar>(foo_ptr) returns nullptr
- /// DynamicCast<Bar>(bar_ptr) returns bar_ptr casted to pBar
- ///
- /// Other feature of DynamicCast:
- ///
- /// class A { int data[5]; };
- /// class B { int data[7]; };
- /// class C : public A, public B { int data[9]; };
- ///
- /// C *c = new C;
- /// A *a = c;
- ///
- /// Note that:
- ///
- /// B *b = (B *)a;
- ///
- /// generates an invalid pointer,
- ///
- /// B *b = StaticCast<B>(a);
- ///
- /// doesn't compile, and
- ///
- /// B *b = DynamicCast<B>(a);
- ///
- /// does the correct cast
- class JPH_EXPORT RTTI
- {
- public:
- /// Function to create an object
- using pCreateObjectFunction = void *(*)();
- /// Function to destroy an object
- using pDestructObjectFunction = void (*)(void *inObject);
- /// Function to initialize the runtime type info structure
- using pCreateRTTIFunction = void (*)(RTTI &inRTTI);
- /// Constructor
- RTTI(const char *inName, int inSize, pCreateObjectFunction inCreateObject, pDestructObjectFunction inDestructObject);
- RTTI(const char *inName, int inSize, pCreateObjectFunction inCreateObject, pDestructObjectFunction inDestructObject, pCreateRTTIFunction inCreateRTTI);
- // Properties
- inline const char * GetName() const { return mName; }
- void SetName(const char *inName) { mName = inName; }
- inline int GetSize() const { return mSize; }
- bool IsAbstract() const { return mCreate == nullptr || mDestruct == nullptr; }
- int GetBaseClassCount() const;
- const RTTI * GetBaseClass(int inIdx) const;
- uint32 GetHash() const;
- /// Create an object of this type (returns nullptr if the object is abstract)
- void * CreateObject() const;
- /// Destruct object of this type (does nothing if the object is abstract)
- void DestructObject(void *inObject) const;
- /// Add base class
- void AddBaseClass(const RTTI *inRTTI, int inOffset);
- /// Equality operators
- bool operator == (const RTTI &inRHS) const;
- bool operator != (const RTTI &inRHS) const { return !(*this == inRHS); }
- /// Test if this class is derived from class of type inRTTI
- bool IsKindOf(const RTTI *inRTTI) const;
- /// Cast inObject of this type to object of type inRTTI, returns nullptr if the cast is unsuccessful
- const void * CastTo(const void *inObject, const RTTI *inRTTI) const;
- /// Attribute access
- void AddAttribute(const SerializableAttribute &inAttribute);
- int GetAttributeCount() const;
- const SerializableAttribute & GetAttribute(int inIdx) const;
- protected:
- /// Base class information
- struct BaseClass
- {
- const RTTI * mRTTI;
- int mOffset;
- };
- const char * mName; ///< Class name
- int mSize; ///< Class size
- StaticArray<BaseClass, 4> mBaseClasses; ///< Names of base classes
- pCreateObjectFunction mCreate; ///< Pointer to a function that will create a new instance of this class
- pDestructObjectFunction mDestruct; ///< Pointer to a function that will destruct an object of this class
- StaticArray<SerializableAttribute, 32> mAttributes; ///< All attributes of this class
- };
- //////////////////////////////////////////////////////////////////////////////////////////
- // Add run time type info to types that don't have virtual functions
- //////////////////////////////////////////////////////////////////////////////////////////
- // JPH_DECLARE_RTTI_NON_VIRTUAL
- #define JPH_DECLARE_RTTI_NON_VIRTUAL(linkage, class_name) \
- public: \
- JPH_OVERRIDE_NEW_DELETE \
- friend linkage RTTI * GetRTTIOfType(class_name *); \
- friend inline const RTTI * GetRTTI([[maybe_unused]] const class_name *inObject) { return GetRTTIOfType(static_cast<class_name *>(nullptr)); }\
- static void sCreateRTTI(RTTI &inRTTI); \
- // JPH_IMPLEMENT_RTTI_NON_VIRTUAL
- #define JPH_IMPLEMENT_RTTI_NON_VIRTUAL(class_name) \
- RTTI * GetRTTIOfType(class_name *) \
- { \
- static RTTI rtti(#class_name, sizeof(class_name), []() -> void * { return new class_name; }, [](void *inObject) { delete (class_name *)inObject; }, &class_name::sCreateRTTI); \
- return &rtti; \
- } \
- void class_name::sCreateRTTI(RTTI &inRTTI) \
- //////////////////////////////////////////////////////////////////////////////////////////
- // Same as above, but when you cannot insert the declaration in the class
- // itself, for example for templates and third party classes
- //////////////////////////////////////////////////////////////////////////////////////////
- // JPH_DECLARE_RTTI_OUTSIDE_CLASS
- #define JPH_DECLARE_RTTI_OUTSIDE_CLASS(linkage, class_name) \
- linkage RTTI * GetRTTIOfType(class_name *); \
- inline const RTTI * GetRTTI(const class_name *inObject) { return GetRTTIOfType((class_name *)nullptr); }\
- void CreateRTTI##class_name(RTTI &inRTTI); \
- // JPH_IMPLEMENT_RTTI_OUTSIDE_CLASS
- #define JPH_IMPLEMENT_RTTI_OUTSIDE_CLASS(class_name) \
- RTTI * GetRTTIOfType(class_name *) \
- { \
- static RTTI rtti((const char *)#class_name, sizeof(class_name), []() -> void * { return new class_name; }, [](void *inObject) { delete (class_name *)inObject; }, &CreateRTTI##class_name); \
- return &rtti; \
- } \
- void CreateRTTI##class_name(RTTI &inRTTI)
- //////////////////////////////////////////////////////////////////////////////////////////
- // Same as above, but for classes that have virtual functions
- //////////////////////////////////////////////////////////////////////////////////////////
- #define JPH_DECLARE_RTTI_HELPER(linkage, class_name, modifier) \
- public: \
- JPH_OVERRIDE_NEW_DELETE \
- friend linkage RTTI * GetRTTIOfType(class_name *); \
- friend inline const RTTI * GetRTTI(const class_name *inObject) { return inObject->GetRTTI(); } \
- virtual const RTTI * GetRTTI() const modifier; \
- virtual const void * CastTo(const RTTI *inRTTI) const modifier; \
- static void sCreateRTTI(RTTI &inRTTI); \
- // JPH_DECLARE_RTTI_VIRTUAL - for derived classes with RTTI
- #define JPH_DECLARE_RTTI_VIRTUAL(linkage, class_name) \
- JPH_DECLARE_RTTI_HELPER(linkage, class_name, override)
- // JPH_IMPLEMENT_RTTI_VIRTUAL
- #define JPH_IMPLEMENT_RTTI_VIRTUAL(class_name) \
- RTTI * GetRTTIOfType(class_name *) \
- { \
- static RTTI rtti(#class_name, sizeof(class_name), []() -> void * { return new class_name; }, [](void *inObject) { delete (class_name *)inObject; }, &class_name::sCreateRTTI); \
- return &rtti; \
- } \
- const RTTI * class_name::GetRTTI() const \
- { \
- return JPH_RTTI(class_name); \
- } \
- const void * class_name::CastTo(const RTTI *inRTTI) const \
- { \
- return JPH_RTTI(class_name)->CastTo((const void *)this, inRTTI); \
- } \
- void class_name::sCreateRTTI(RTTI &inRTTI) \
- // JPH_DECLARE_RTTI_VIRTUAL_BASE - for concrete base class that has RTTI
- #define JPH_DECLARE_RTTI_VIRTUAL_BASE(linkage, class_name) \
- JPH_DECLARE_RTTI_HELPER(linkage, class_name, )
- // JPH_IMPLEMENT_RTTI_VIRTUAL_BASE
- #define JPH_IMPLEMENT_RTTI_VIRTUAL_BASE(class_name) \
- JPH_IMPLEMENT_RTTI_VIRTUAL(class_name)
- // JPH_DECLARE_RTTI_ABSTRACT - for derived abstract class that have RTTI
- #define JPH_DECLARE_RTTI_ABSTRACT(linkage, class_name) \
- JPH_DECLARE_RTTI_HELPER(linkage, class_name, override)
- // JPH_IMPLEMENT_RTTI_ABSTRACT
- #define JPH_IMPLEMENT_RTTI_ABSTRACT(class_name) \
- RTTI * GetRTTIOfType(class_name *) \
- { \
- static RTTI rtti(#class_name, sizeof(class_name), nullptr, [](void *inObject) { delete (class_name *)inObject; }, &class_name::sCreateRTTI); \
- return &rtti; \
- } \
- const RTTI * class_name::GetRTTI() const \
- { \
- return JPH_RTTI(class_name); \
- } \
- const void * class_name::CastTo(const RTTI *inRTTI) const \
- { \
- return JPH_RTTI(class_name)->CastTo((const void *)this, inRTTI); \
- } \
- void class_name::sCreateRTTI(RTTI &inRTTI) \
- // JPH_DECLARE_RTTI_ABSTRACT_BASE - for abstract base class that has RTTI
- #define JPH_DECLARE_RTTI_ABSTRACT_BASE(linkage, class_name) \
- JPH_DECLARE_RTTI_HELPER(linkage, class_name, )
- // JPH_IMPLEMENT_RTTI_ABSTRACT_BASE
- #define JPH_IMPLEMENT_RTTI_ABSTRACT_BASE(class_name) \
- JPH_IMPLEMENT_RTTI_ABSTRACT(class_name)
- //////////////////////////////////////////////////////////////////////////////////////////
- // Declare an RTTI class for registering with the factory
- //////////////////////////////////////////////////////////////////////////////////////////
- #define JPH_DECLARE_RTTI_FOR_FACTORY(linkage, class_name) \
- linkage RTTI * GetRTTIOfType(class class_name *);
- #define JPH_DECLARE_RTTI_WITH_NAMESPACE_FOR_FACTORY(linkage, name_space, class_name) \
- namespace name_space { \
- class class_name; \
- linkage RTTI * GetRTTIOfType(class class_name *); \
- }
- //////////////////////////////////////////////////////////////////////////////////////////
- // Find the RTTI of a class
- //////////////////////////////////////////////////////////////////////////////////////////
- #define JPH_RTTI(class_name) GetRTTIOfType(static_cast<class_name *>(nullptr))
- //////////////////////////////////////////////////////////////////////////////////////////
- // Macro to rename a class, useful for embedded classes:
- //
- // class A { class B { }; }
- //
- // Now use JPH_RENAME_CLASS(B, A::B) to avoid conflicts with other classes named B
- //////////////////////////////////////////////////////////////////////////////////////////
- // JPH_RENAME_CLASS
- #define JPH_RENAME_CLASS(class_name, new_name) \
- inRTTI.SetName(#new_name);
- //////////////////////////////////////////////////////////////////////////////////////////
- // Macro to add base classes
- //////////////////////////////////////////////////////////////////////////////////////////
- /// Define very dirty macro to get the offset of a baseclass into a class
- #define JPH_BASE_CLASS_OFFSET(inClass, inBaseClass) ((int(uint64((inBaseClass *)((inClass *)0x10000))))-0x10000)
- // JPH_ADD_BASE_CLASS
- #define JPH_ADD_BASE_CLASS(class_name, base_class_name) \
- inRTTI.AddBaseClass(JPH_RTTI(base_class_name), JPH_BASE_CLASS_OFFSET(class_name, base_class_name));
- //////////////////////////////////////////////////////////////////////////////////////////
- // Macros and templates to identify a class
- //////////////////////////////////////////////////////////////////////////////////////////
- /// Check if inObject is of DstType
- template <class Type>
- inline bool IsType(const Type *inObject, const RTTI *inRTTI)
- {
- return inObject == nullptr || *inObject->GetRTTI() == *inRTTI;
- }
- template <class Type>
- inline bool IsType(const RefConst<Type> &inObject, const RTTI *inRTTI)
- {
- return inObject == nullptr || *inObject->GetRTTI() == *inRTTI;
- }
- template <class Type>
- inline bool IsType(const Ref<Type> &inObject, const RTTI *inRTTI)
- {
- return inObject == nullptr || *inObject->GetRTTI() == *inRTTI;
- }
- /// Check if inObject is or is derived from DstType
- template <class Type>
- inline bool IsKindOf(const Type *inObject, const RTTI *inRTTI)
- {
- return inObject == nullptr || inObject->GetRTTI()->IsKindOf(inRTTI);
- }
- template <class Type>
- inline bool IsKindOf(const RefConst<Type> &inObject, const RTTI *inRTTI)
- {
- return inObject == nullptr || inObject->GetRTTI()->IsKindOf(inRTTI);
- }
- template <class Type>
- inline bool IsKindOf(const Ref<Type> &inObject, const RTTI *inRTTI)
- {
- return inObject == nullptr || inObject->GetRTTI()->IsKindOf(inRTTI);
- }
- /// Cast inObject to DstType, asserts on failure
- template <class DstType, class SrcType>
- inline const DstType *StaticCast(const SrcType *inObject)
- {
- JPH_ASSERT(IsKindOf(inObject, JPH_RTTI(DstType)), "Invalid cast");
- return static_cast<const DstType *>(inObject);
- }
- template <class DstType, class SrcType>
- inline DstType *StaticCast(SrcType *inObject)
- {
- JPH_ASSERT(IsKindOf(inObject, JPH_RTTI(DstType)), "Invalid cast");
- return static_cast<DstType *>(inObject);
- }
- template <class DstType, class SrcType>
- inline RefConst<DstType> StaticCast(RefConst<SrcType> &inObject)
- {
- JPH_ASSERT(IsKindOf(inObject, JPH_RTTI(DstType)), "Invalid cast");
- return static_cast<const DstType *>(inObject.GetPtr());
- }
- template <class DstType, class SrcType>
- inline Ref<DstType> StaticCast(Ref<SrcType> &inObject)
- {
- JPH_ASSERT(IsKindOf(inObject, JPH_RTTI(DstType)), "Invalid cast");
- return static_cast<DstType *>(inObject.GetPtr());
- }
- /// Cast inObject to DstType, returns nullptr on failure
- template <class DstType, class SrcType>
- inline const DstType *DynamicCast(const SrcType *inObject)
- {
- return inObject != nullptr? reinterpret_cast<const DstType *>(inObject->CastTo(JPH_RTTI(DstType))) : nullptr;
- }
- template <class DstType, class SrcType>
- inline DstType *DynamicCast(SrcType *inObject)
- {
- return inObject != nullptr? const_cast<DstType *>(reinterpret_cast<const DstType *>(inObject->CastTo(JPH_RTTI(DstType)))) : nullptr;
- }
- template <class DstType, class SrcType>
- inline RefConst<DstType> DynamicCast(RefConst<SrcType> &inObject)
- {
- return inObject != nullptr? reinterpret_cast<const DstType *>(inObject->CastTo(JPH_RTTI(DstType))) : nullptr;
- }
- template <class DstType, class SrcType>
- inline Ref<DstType> DynamicCast(Ref<SrcType> &inObject)
- {
- return inObject != nullptr? const_cast<DstType *>(reinterpret_cast<const DstType *>(inObject->CastTo(JPH_RTTI(DstType)))) : nullptr;
- }
- JPH_NAMESPACE_END
|