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