1#ifndef SEAD_RUNTIMETYPEINFO_H_
2#define SEAD_RUNTIMETYPEINFO_H_
3
4namespace sead
5{
6namespace RuntimeTypeInfo
7{
8class Interface
9{
10public:
11 Interface() {}
12
13 virtual bool isDerived(const Interface* typeInfo) const = 0;
14};
15
16class Root : public Interface
17{
18public:
19 Root() {}
20
21 bool isDerived(const Interface* typeInfo) const override { return typeInfo == this; }
22};
23
24template <typename BaseType>
25class Derive : public Interface
26{
27public:
28 Derive() {}
29
30 bool isDerived(const Interface* typeInfo) const override
31 {
32 if (this == typeInfo)
33 return true;
34
35 const RuntimeTypeInfo::Interface* rootTypeInfo = BaseType::getRuntimeTypeInfoStatic();
36 return rootTypeInfo->isDerived(typeInfo);
37 }
38};
39
40} // namespace RuntimeTypeInfo
41
42/// Tests if the object is a DerivedType or any type that derives from (i.e. inherits) DerivedType.
43template <typename DerivedType, typename Type>
44inline bool IsDerivedFrom(const Type* obj)
45{
46 const RuntimeTypeInfo::Interface* typeInfo = DerivedType::getRuntimeTypeInfoStatic();
47 return obj != nullptr && obj->checkDerivedRuntimeTypeInfo(typeInfo);
48}
49
50/// If the object is a DerivedType or any type that derives from (i.e. inherits) DerivedType,
51/// this returns obj casted to DerivedType* -- otherwise this returns nullptr.
52///
53/// @note This is similar to C++'s dynamic_cast or LLVM's dyn_cast but only works with types
54/// that use the sead RTTI mechanism.
55template <typename DerivedType, typename Type>
56inline DerivedType* DynamicCast(Type* obj)
57{
58 if (IsDerivedFrom<DerivedType, Type>(obj))
59 return static_cast<DerivedType*>(obj);
60
61 return nullptr;
62}
63
64} // namespace sead
65
66/// Use this macro to declare sead RTTI machinery for a base class.
67/// You must use SEAD_RTTI_OVERRIDE in all derived classes.
68/// @param CLASS The name of the class.
69#define SEAD_RTTI_BASE(CLASS) \
70public: \
71 static const sead::RuntimeTypeInfo::Interface* getRuntimeTypeInfoStatic() \
72 { \
73 static const sead::RuntimeTypeInfo::Root typeInfo; \
74 return &typeInfo; \
75 } \
76 \
77 static bool checkDerivedRuntimeTypeInfoStatic( \
78 const sead::RuntimeTypeInfo::Interface* typeInfo) \
79 { \
80 const sead::RuntimeTypeInfo::Interface* clsTypeInfo = CLASS::getRuntimeTypeInfoStatic(); \
81 return typeInfo == clsTypeInfo; \
82 } \
83 \
84 virtual bool checkDerivedRuntimeTypeInfo(const sead::RuntimeTypeInfo::Interface* typeInfo) \
85 const \
86 { \
87 return checkDerivedRuntimeTypeInfoStatic(typeInfo); \
88 } \
89 \
90 virtual const sead::RuntimeTypeInfo::Interface* getRuntimeTypeInfo() const \
91 { \
92 return getRuntimeTypeInfoStatic(); \
93 }
94
95/// Use this macro to declare sead RTTI machinery for a derived class.
96/// @param CLASS The name of the class.
97/// @param BASE The name of the base class of CLASS.
98#define SEAD_RTTI_OVERRIDE(CLASS, BASE) \
99public: \
100 static const sead::RuntimeTypeInfo::Interface* getRuntimeTypeInfoStatic() \
101 { \
102 static const sead::RuntimeTypeInfo::Derive<BASE> typeInfo; \
103 return &typeInfo; \
104 } \
105 \
106 static bool checkDerivedRuntimeTypeInfoStatic( \
107 const sead::RuntimeTypeInfo::Interface* typeInfo) \
108 \
109 { \
110 const sead::RuntimeTypeInfo::Interface* clsTypeInfo = CLASS::getRuntimeTypeInfoStatic(); \
111 if (typeInfo == clsTypeInfo) \
112 return true; \
113 \
114 return BASE::checkDerivedRuntimeTypeInfoStatic(typeInfo); \
115 } \
116 \
117 bool checkDerivedRuntimeTypeInfo(const sead::RuntimeTypeInfo::Interface* typeInfo) \
118 const override \
119 { \
120 return checkDerivedRuntimeTypeInfoStatic(typeInfo); \
121 } \
122 \
123 const sead::RuntimeTypeInfo::Interface* getRuntimeTypeInfo() const override \
124 { \
125 return getRuntimeTypeInfoStatic(); \
126 }
127
128#endif // SEAD_RUNTIMETYPEINFO_H_
129