1 | //************************************ bs::framework - Copyright 2018 Marko Pintera **************************************// |
2 | //*********** Licensed under the MIT license. See LICENSE.md for full terms. This notice is not to be removed. ***********// |
3 | #pragma once |
4 | |
5 | #include <string> |
6 | #include <algorithm> |
7 | #include <unordered_map> |
8 | |
9 | #include "Prerequisites/BsPrerequisitesUtil.h" |
10 | #include "Reflection/BsRTTIField.h" |
11 | #include "Reflection/BsRTTIPlainField.h" |
12 | #include "Reflection/BsRTTIReflectableField.h" |
13 | #include "Reflection/BsRTTIReflectablePtrField.h" |
14 | #include "Reflection/BsRTTIManagedDataBlockField.h" |
15 | #include "Reflection/BsIReflectable.h" |
16 | #include "Serialization/BsBinaryDiff.h" |
17 | #include "Serialization/BsBinaryCompare.h" |
18 | |
19 | namespace bs |
20 | { |
21 | /** @addtogroup RTTI |
22 | * @{ |
23 | */ |
24 | |
25 | /** |
26 | * Starts definitions for member fields within a RTTI type. Follow this with calls to BS_RTTI_MEMBER* calls, and finish by |
27 | * calling BS_END_RTTI_MEMBERS. |
28 | */ |
29 | #define BS_BEGIN_RTTI_MEMBERS \ |
30 | struct META_FirstEntry {}; \ |
31 | void META_InitPrevEntry(META_FirstEntry typeId) { } \ |
32 | \ |
33 | typedef META_FirstEntry |
34 | |
35 | /** |
36 | * Same as BS_RTTI_MEMBER_PLAIN, but allows you to specify separate names for the field name and the member variable, |
37 | * as well as an optional info structure further describing the field. |
38 | */ |
39 | #define BS_RTTI_MEMBER_PLAIN_FULL(name, field, id, info) \ |
40 | META_Entry_##name; \ |
41 | \ |
42 | decltype(OwnerType::field)& get##name(OwnerType* obj) { return obj->field; } \ |
43 | void set##name(OwnerType* obj, decltype(OwnerType::field)& val) { obj->field = val; } \ |
44 | \ |
45 | struct META_NextEntry_##name{}; \ |
46 | void META_InitPrevEntry(META_NextEntry_##name typeId) \ |
47 | { \ |
48 | addPlainField(#name, id, &MyType::get##name, &MyType::set##name, info); \ |
49 | META_InitPrevEntry(META_Entry_##name()); \ |
50 | } \ |
51 | \ |
52 | typedef META_NextEntry_##name |
53 | |
54 | /** |
55 | * Registers a new member field in the RTTI type. The field references the @p name member in the owner class. |
56 | * The type of the member must be a valid plain type. Each field must specify a unique ID for @p id. |
57 | * An optional @p RTTIFieldInfo structure can be provided to provide further information about the field. |
58 | */ |
59 | #define BS_RTTI_MEMBER_PLAIN(name, id) BS_RTTI_MEMBER_PLAIN_FULL(name, name, id, bs::RTTIFieldInfo::DEFAULT) |
60 | |
61 | /** Same as BS_RTTI_MEMBER_PLAIN, but allows you to specify separate names for the field name and the member variable. */ |
62 | #define BS_RTTI_MEMBER_PLAIN_NAMED(name, field, id) BS_RTTI_MEMBER_PLAIN_FULL(name, field, id, bs::RTTIFieldInfo::DEFAULT) |
63 | |
64 | /** Same as BS_RTTI_MEMBER_PLAIN, but allows you to specify an info structure that further describes the field. */ |
65 | #define BS_RTTI_MEMBER_PLAIN_INFO(name, id, info) BS_RTTI_MEMBER_PLAIN_FULL(name, name, id, info) |
66 | |
67 | /** |
68 | * Same as BS_RTTI_MEMBER_PLAIN_ARRAY, but allows you to specify separate names for the field name and the member |
69 | * variable, as well as an optional info structure further describing the field. |
70 | */ |
71 | #define BS_RTTI_MEMBER_PLAIN_ARRAY_FULL(name, field, id, info) \ |
72 | META_Entry_##name; \ |
73 | \ |
74 | std::common_type<decltype(OwnerType::field)>::type::value_type& get##name(OwnerType* obj, UINT32 idx) { return obj->field[idx]; } \ |
75 | void set##name(OwnerType* obj, UINT32 idx, std::common_type<decltype(OwnerType::field)>::type::value_type& val) { obj->field[idx] = val; } \ |
76 | UINT32 getSize##name(OwnerType* obj) { return (UINT32)obj->field.size(); } \ |
77 | void setSize##name(OwnerType* obj, UINT32 val) { obj->field.resize(val); } \ |
78 | \ |
79 | struct META_NextEntry_##name{}; \ |
80 | void META_InitPrevEntry(META_NextEntry_##name typeId) \ |
81 | { \ |
82 | addPlainArrayField(#name, id, &MyType::get##name, &MyType::getSize##name, &MyType::set##name, &MyType::setSize##name, info); \ |
83 | META_InitPrevEntry(META_Entry_##name()); \ |
84 | } \ |
85 | \ |
86 | typedef META_NextEntry_##name |
87 | |
88 | /** |
89 | * Registers a new member field in the RTTI type. The field references the @p name member in the owner class. |
90 | * The type of the member must be an array of valid plain types. Each field must specify a unique ID for @p id. |
91 | */ |
92 | #define BS_RTTI_MEMBER_PLAIN_ARRAY(name, id) BS_RTTI_MEMBER_PLAIN_ARRAY_FULL(name, name, id, bs::RTTIFieldInfo::DEFAULT) |
93 | |
94 | /** |
95 | * Same as BS_RTTI_MEMBER_PLAIN_ARRAY, but allows you to specify separate names for the field name and the member variable. |
96 | */ |
97 | #define BS_RTTI_MEMBER_PLAIN_ARRAY_NAMED(name, field, id) BS_RTTI_MEMBER_PLAIN_ARRAY_FULL(name, field, id, bs::RTTIFieldInfo::DEFAULT) |
98 | |
99 | /** |
100 | * Same as BS_RTTI_MEMBER_PLAIN_ARRAY, but allows you to specify an info structure that further describes the field. |
101 | */ |
102 | #define BS_RTTI_MEMBER_PLAIN_ARRAY_INFO(name, id, info) BS_RTTI_MEMBER_PLAIN_ARRAY_FULL(name, name, id, info) |
103 | |
104 | /** |
105 | * Same as BS_RTTI_MEMBER_REFL, but allows you to specify separate names for the field name and the member variable, |
106 | * as well as an optional info structure further describing the field. |
107 | */ |
108 | #define BS_RTTI_MEMBER_REFL_FULL(name, field, id, info) \ |
109 | META_Entry_##name; \ |
110 | \ |
111 | decltype(OwnerType::field)& get##name(OwnerType* obj) { return obj->field; } \ |
112 | void set##name(OwnerType* obj, decltype(OwnerType::field)& val) { obj->field = val; } \ |
113 | \ |
114 | struct META_NextEntry_##name{}; \ |
115 | void META_InitPrevEntry(META_NextEntry_##name typeId) \ |
116 | { \ |
117 | addReflectableField(#name, id, &MyType::get##name, &MyType::set##name, info); \ |
118 | META_InitPrevEntry(META_Entry_##name()); \ |
119 | } \ |
120 | \ |
121 | typedef META_NextEntry_##name |
122 | |
123 | /** |
124 | * Registers a new member field in the RTTI type. The field references the @p name member in the owner class. |
125 | * The type of the member must be a valid reflectable (non-pointer) type. Each field must specify a unique ID for @p id. |
126 | */ |
127 | #define BS_RTTI_MEMBER_REFL(name, id) BS_RTTI_MEMBER_REFL_FULL(name, name, id, bs::RTTIFieldInfo::DEFAULT) |
128 | |
129 | /** Same as BS_RTTI_MEMBER_REFL, but allows you to specify separate names for the field name and the member variable. */ |
130 | #define BS_RTTI_MEMBER_REFL_NAMED(name, field, id) BS_RTTI_MEMBER_REFL_FULL(name, field, id, bs::RTTIFieldInfo::DEFAULT) |
131 | |
132 | /** Same as BS_RTTI_MEMBER_REFL, but allows you to specify an info structure that further describes the field. */ |
133 | #define BS_RTTI_MEMBER_REFL_INFO(name, id, info) BS_RTTI_MEMBER_REFL_FULL(name, name, id, info) |
134 | |
135 | /** |
136 | * Same as BS_RTTI_MEMBER_REFL_ARRAY, but allows you to specify separate names for the field name and the member variable, |
137 | * as well as an optional info structure further describing the field. |
138 | */ |
139 | #define BS_RTTI_MEMBER_REFL_ARRAY_FULL(name, field, id, info) \ |
140 | META_Entry_##name; \ |
141 | \ |
142 | std::common_type<decltype(OwnerType::field)>::type::value_type& get##name(OwnerType* obj, UINT32 idx) { return obj->field[idx]; } \ |
143 | void set##name(OwnerType* obj, UINT32 idx, std::common_type<decltype(OwnerType::field)>::type::value_type& val) { obj->field[idx] = val; } \ |
144 | UINT32 getSize##name(OwnerType* obj) { return (UINT32)obj->field.size(); } \ |
145 | void setSize##name(OwnerType* obj, UINT32 val) { obj->field.resize(val); } \ |
146 | \ |
147 | struct META_NextEntry_##name{}; \ |
148 | void META_InitPrevEntry(META_NextEntry_##name typeId) \ |
149 | { \ |
150 | addReflectableArrayField(#name, id, &MyType::get##name, &MyType::getSize##name, &MyType::set##name, &MyType::setSize##name, info); \ |
151 | META_InitPrevEntry(META_Entry_##name()); \ |
152 | } \ |
153 | \ |
154 | typedef META_NextEntry_##name |
155 | |
156 | /** |
157 | * Registers a new member field in the RTTI type. The field references the @p name member in the owner class. |
158 | * The type of the member must be an array of valid reflectable (non-pointer) types. Each field must specify a unique ID for |
159 | * @p id. |
160 | */ |
161 | #define BS_RTTI_MEMBER_REFL_ARRAY(name, id) BS_RTTI_MEMBER_REFL_ARRAY_FULL(name, name, id, bs::RTTIFieldInfo::DEFAULT) |
162 | |
163 | /** |
164 | * Same as BS_RTTI_MEMBER_REFL_ARRAY, but allows you to specify separate names for the field name and the member variable. |
165 | */ |
166 | #define BS_RTTI_MEMBER_REFL_ARRAY_NAMED(name, field, id) BS_RTTI_MEMBER_REFL_ARRAY_FULL(name, field, id, bs::RTTIFieldInfo::DEFAULT) |
167 | |
168 | /** |
169 | * Same as BS_RTTI_MEMBER_REFL_ARRAY, but allows you to specify an info structure that further describes the field. |
170 | */ |
171 | #define BS_RTTI_MEMBER_REFL_ARRAY_INFO(name, id, info) BS_RTTI_MEMBER_REFL_ARRAY_FULL(name, name, id, info) |
172 | |
173 | /** |
174 | * Same as BS_RTTI_MEMBER_REFLPTR, but allows you to specify separate names for the field name and the member variable, |
175 | * as well as an optional info structure further describing the field. |
176 | */ |
177 | #define BS_RTTI_MEMBER_REFLPTR_FULL(name, field, id, info) \ |
178 | META_Entry_##name; \ |
179 | \ |
180 | decltype(OwnerType::field) get##name(OwnerType* obj) { return obj->field; } \ |
181 | void set##name(OwnerType* obj, decltype(OwnerType::field) val) { obj->field = val; } \ |
182 | \ |
183 | struct META_NextEntry_##name{}; \ |
184 | void META_InitPrevEntry(META_NextEntry_##name typeId) \ |
185 | { \ |
186 | addReflectablePtrField(#name, id, &MyType::get##name, &MyType::set##name, info); \ |
187 | META_InitPrevEntry(META_Entry_##name()); \ |
188 | } \ |
189 | \ |
190 | typedef META_NextEntry_##name |
191 | |
192 | /** |
193 | * Registers a new member field in the RTTI type. The field references the @p name member in the owner class. |
194 | * The type of the member must be a valid reflectable pointer type. Each field must specify a unique ID for @p id. |
195 | */ |
196 | #define BS_RTTI_MEMBER_REFLPTR(name, id) BS_RTTI_MEMBER_REFLPTR_FULL(name, name, id, bs::RTTIFieldInfo::DEFAULT) |
197 | |
198 | /** Same as BS_RTTI_MEMBER_REFLPTR, but allows you to specify separate names for the field name and the member variable. */ |
199 | #define BS_RTTI_MEMBER_REFLPTR_NAMED(name, field, id) BS_RTTI_MEMBER_REFLPTR_FULL(name, field, id, RTTIFieldInfo::DEFAULT) |
200 | |
201 | /** Same as BS_RTTI_MEMBER_REFLPTR, but allows you to specify an info structure that further describes the field. */ |
202 | #define BS_RTTI_MEMBER_REFLPTR_INFO(name, id, info) BS_RTTI_MEMBER_REFLPTR_FULL(name, name, id, info) |
203 | |
204 | /** |
205 | * Same as BS_RTTI_MEMBER_REFLPTR_ARRAY, but allows you to specify separate names for the field name and the member |
206 | * variable, as well as an optional info structure further describing the field. |
207 | */ |
208 | #define BS_RTTI_MEMBER_REFLPTR_ARRAY_FULL(name, field, id, info) \ |
209 | META_Entry_##name; \ |
210 | \ |
211 | std::common_type<decltype(OwnerType::field)>::type::value_type get##name(OwnerType* obj, UINT32 idx) { return obj->field[idx]; } \ |
212 | void set##name(OwnerType* obj, UINT32 idx, std::common_type<decltype(OwnerType::field)>::type::value_type val) { obj->field[idx] = val; } \ |
213 | UINT32 getSize##name(OwnerType* obj) { return (UINT32)obj->field.size(); } \ |
214 | void setSize##name(OwnerType* obj, UINT32 val) { obj->field.resize(val); } \ |
215 | \ |
216 | struct META_NextEntry_##name{}; \ |
217 | void META_InitPrevEntry(META_NextEntry_##name typeId) \ |
218 | { \ |
219 | addReflectablePtrArrayField(#name, id, &MyType::get##name, &MyType::getSize##name, &MyType::set##name, &MyType::setSize##name, info); \ |
220 | META_InitPrevEntry(META_Entry_##name()); \ |
221 | } \ |
222 | \ |
223 | typedef META_NextEntry_##name |
224 | |
225 | /** |
226 | * Registers a new member field in the RTTI type. The field references the @p name member in the owner class. |
227 | * The type of the member must be a valid reflectable pointer type. Each field must specify a unique ID for @p id. |
228 | */ |
229 | #define BS_RTTI_MEMBER_REFLPTR_ARRAY(name, id) BS_RTTI_MEMBER_REFLPTR_ARRAY_FULL(name, name, id, bs::RTTIFieldInfo::DEFAULT) |
230 | |
231 | /** |
232 | * Same as BS_RTTI_MEMBER_REFLPTR_ARRAY, but allows you to specify separate names for the field name and the member |
233 | * variable. |
234 | */ |
235 | #define BS_RTTI_MEMBER_REFLPTR_ARRAY_NAMED(name, field, id) BS_RTTI_MEMBER_REFLPTR_ARRAY_FULL(name, field, id, bs::RTTIFieldInfo::DEFAULT) |
236 | |
237 | /** Same as BS_RTTI_MEMBER_REFLPTR_ARRAY, but allows you to specify an info structure that further describes the field. */ |
238 | #define BS_RTTI_MEMBER_REFLPTR_ARRAY_INFO(name, id, info) BS_RTTI_MEMBER_REFLPTR_ARRAY_FULL(name, name, id, info) |
239 | |
240 | /** Ends definitions for member fields with a RTTI type. Must follow BS_BEGIN_RTTI_MEMBERS. */ |
241 | #define BS_END_RTTI_MEMBERS \ |
242 | META_LastEntry; \ |
243 | \ |
244 | struct META_InitAllMembers \ |
245 | { \ |
246 | META_InitAllMembers(MyType* owner) \ |
247 | { \ |
248 | static bool sMembersInitialized = false; \ |
249 | if(!sMembersInitialized) \ |
250 | { \ |
251 | owner->META_InitPrevEntry(META_LastEntry()); \ |
252 | sMembersInitialized = true; \ |
253 | } \ |
254 | } \ |
255 | }; \ |
256 | \ |
257 | META_InitAllMembers mInitMembers{this}; |
258 | |
259 | /** @} */ |
260 | |
261 | /** @addtogroup Internal-Utility |
262 | * @{ |
263 | */ |
264 | /** @addtogroup RTTI-Internal |
265 | * @{ |
266 | */ |
267 | |
268 | struct SerializationContext; |
269 | |
270 | /** |
271 | * Provides an interface for accessing fields of a certain class. |
272 | * Data can be easily accessed by getter and setter methods. |
273 | * |
274 | * Supported data types: |
275 | * - Plain types - All types defined in BsRTTIField.h, mostly native types and POD (plain old data) structs. Data is parsed byte by byte. |
276 | * No pointers to plain types are supported. Data is passed around by value. |
277 | * - Reflectable types - Any class deriving from IReflectable. Data is parsed based on fields in its RTTI class. Can be pointer or value type. |
278 | * - Arrays of both plain and reflectable types are supported |
279 | * - Data blocks - A managed or unmanaged block of data. See ManagedDataBlock. |
280 | */ |
281 | class BS_UTILITY_EXPORT RTTITypeBase |
282 | { |
283 | public: |
284 | RTTITypeBase() = default; |
285 | virtual ~RTTITypeBase(); |
286 | |
287 | /** Returns RTTI type information for all classes that derive from the class that owns this RTTI type. */ |
288 | virtual Vector<RTTITypeBase*>& getDerivedClasses() = 0; |
289 | |
290 | /** |
291 | * Returns RTTI type information for the class that owns this RTTI type. If the class has not base type, null is |
292 | * returned instead. |
293 | */ |
294 | virtual RTTITypeBase* getBaseClass() = 0; |
295 | |
296 | /** Returns true if current RTTI class is derived from @p base. (Or if it is the same type as base) */ |
297 | virtual bool isDerivedFrom(RTTITypeBase* base) = 0; |
298 | |
299 | /** Creates a new instance of the class owning this RTTI type. */ |
300 | virtual SPtr<IReflectable> newRTTIObject() = 0; |
301 | |
302 | /** Returns the name of the class owning this RTTI type. */ |
303 | virtual const String& getRTTIName() = 0; |
304 | |
305 | /** Returns an RTTI id that uniquely represents each class in the RTTI system. */ |
306 | virtual UINT32 getRTTIId() = 0; |
307 | |
308 | /** |
309 | * Called by the serializers when serialization for this object has started. Use this to do any preprocessing on |
310 | * data you might need during serialization itself. |
311 | */ |
312 | virtual void onSerializationStarted(IReflectable* obj, SerializationContext* context) {} |
313 | |
314 | /** |
315 | * Called by the serializers when serialization for this object has ended. After serialization has ended you can |
316 | * be sure that the type has been fully serialized, and you may clean up any temporary data. |
317 | */ |
318 | virtual void onSerializationEnded(IReflectable* obj, SerializationContext* context) {} |
319 | |
320 | /** |
321 | * Called by the serializers when deserialization for this object has started. Use this to do any preprocessing |
322 | * on data you might need during deserialization itself. |
323 | */ |
324 | virtual void onDeserializationStarted(IReflectable* obj, SerializationContext* context) {} |
325 | |
326 | /** |
327 | * Called by the serializers when deserialization for this object has ended. At this point you can be sure the |
328 | * instance has been fully deserialized and you may safely use it. |
329 | * |
330 | * One exception being are fields you marked with RTTI_Flag_WeakRef, as they might be resolved only after |
331 | * deserialization has fully completed for all objects. |
332 | */ |
333 | virtual void onDeserializationEnded(IReflectable* obj, SerializationContext* context) {} |
334 | |
335 | /** |
336 | * Returns a handler that determines how are "diffs" generated and applied when it comes to objects of this RTTI |
337 | * type. A "diff" is a list of differences between two objects that may be saved, viewed or applied to another |
338 | * object to transform it. |
339 | */ |
340 | virtual IDiff& getDiffHandler() const |
341 | { |
342 | static BinaryDiff diffHandler; |
343 | return diffHandler; |
344 | } |
345 | |
346 | /** Returns a handler that determines how are IReflectable objects compared for equality. */ |
347 | virtual ICompare& getCompareHandler() const |
348 | { |
349 | static BinaryCompare compareHandler; |
350 | return compareHandler; |
351 | } |
352 | |
353 | /** Returns the total number of fields in this RTTI type. */ |
354 | UINT32 getNumFields() const { return (UINT32)mFields.size(); } |
355 | |
356 | /** Returns a field based on the field index. Use getNumFields() to get total number of fields available. */ |
357 | RTTIField* getField(UINT32 idx) { return mFields.at(idx); } |
358 | |
359 | /** |
360 | * Tries to find a field with the specified name. Throws an exception if it can't. |
361 | * |
362 | * @param name The name of the field. |
363 | */ |
364 | RTTIField* findField(const String& name); |
365 | |
366 | /** |
367 | * Tries to find a field with the specified unique ID. Doesn't throw an exception if it can't find the field |
368 | * (Unlike findField(const String&)). |
369 | * |
370 | * @param uniqueFieldId Unique identifier for the field. |
371 | * |
372 | * @return nullptr if it can't find the field. |
373 | */ |
374 | RTTIField* findField(int uniqueFieldId); |
375 | |
376 | /** @name Internal |
377 | * @{ |
378 | */ |
379 | |
380 | /** Called by the RTTI system when a class is first found in order to form child/parent class hierarchy. */ |
381 | virtual void _registerDerivedClass(RTTITypeBase* derivedClass) = 0; |
382 | |
383 | /** |
384 | * Constucts a cloned version of the underlying class. The cloned version will not have any field information and |
385 | * should instead be used for passing to various RTTIField methods during serialization/deserialization. This |
386 | * allows each object instance to have a unique places to store temporary instance-specific data. |
387 | */ |
388 | virtual RTTITypeBase* _clone(FrameAlloc& alloc) = 0; |
389 | |
390 | /** @} */ |
391 | |
392 | protected: |
393 | /** |
394 | * Tries to add a new field to the fields array, and throws an exception if a field with the same name or id |
395 | * already exists. |
396 | * |
397 | * @param[in] field Field, must be non-null. |
398 | */ |
399 | void addNewField(RTTIField* field); |
400 | |
401 | private: |
402 | Vector<RTTIField*> mFields; |
403 | }; |
404 | |
405 | /** Used for initializing a certain type as soon as the program is loaded. */ |
406 | template<typename Type, typename BaseType> |
407 | struct InitRTTIOnStart |
408 | { |
409 | public: |
410 | InitRTTIOnStart() |
411 | { |
412 | IReflectable::_registerRTTIType(Type::getRTTIStatic()); |
413 | BaseType::getRTTIStatic()->_registerDerivedClass(Type::getRTTIStatic()); |
414 | } |
415 | |
416 | void makeSureIAmInstantiated() { } |
417 | }; |
418 | |
419 | /** Specialization for root class of RTTI hierarchy - IReflectable */ |
420 | template<typename Type> |
421 | struct InitRTTIOnStart<Type, IReflectable> |
422 | { |
423 | public: |
424 | InitRTTIOnStart() |
425 | { |
426 | IReflectable::_registerRTTIType(Type::getRTTIStatic()); |
427 | } |
428 | |
429 | void makeSureIAmInstantiated() { } |
430 | }; |
431 | |
432 | /** |
433 | * Template that returns RTTI type of the specified type, unless the specified type is IReflectable in which case it |
434 | * returns a null. |
435 | */ |
436 | template<typename Type> |
437 | struct GetRTTIType |
438 | { |
439 | RTTITypeBase* operator()() { return Type::getRTTIStatic(); } |
440 | }; |
441 | |
442 | /** Specialization for root class of RTTI hierarchy - IReflectable. */ |
443 | template<> |
444 | struct GetRTTIType<IReflectable> |
445 | { |
446 | RTTITypeBase* operator()() { return nullptr; } |
447 | }; |
448 | |
449 | /** @} */ |
450 | /** @} */ |
451 | |
452 | /** @addtogroup RTTI |
453 | * @{ |
454 | */ |
455 | |
456 | /** |
457 | * Allows you to provide a run-time type information for a specific class, along with support for |
458 | * serialization/deserialization. |
459 | * |
460 | * Derive from this class and return the that class from IReflectable::getRTTI. This way you can separate serialization |
461 | * logic from the actual class you're serializing. |
462 | * |
463 | * This class will provide a way to register individual fields in the class, together with ways to read and write them, |
464 | * as well a providing information about class hierarchy, and run-time type checking. |
465 | */ |
466 | template <typename Type, typename BaseType, typename MyRTTIType> |
467 | class RTTIType : public RTTITypeBase |
468 | { |
469 | protected: |
470 | /************************************************************************/ |
471 | /* RTTI CLASS META DATA */ |
472 | /************************************************************************/ |
473 | |
474 | static InitRTTIOnStart<Type, BaseType> initOnStart; |
475 | |
476 | public: |
477 | RTTIType() |
478 | { |
479 | // Compiler will only generate code for stuff that is directly used, including static data members, |
480 | // so we fool it here like we're using the class directly. Otherwise compiler won't generate the code for the member |
481 | // and our type won't get initialized on start (Actual behavior is a bit more random) |
482 | initOnStart.makeSureIAmInstantiated(); |
483 | } |
484 | virtual ~RTTIType() = default; |
485 | |
486 | /** Returns a singleton of this RTTI type. */ |
487 | static MyRTTIType* instance() |
488 | { |
489 | static MyRTTIType inst; |
490 | return &inst; |
491 | } |
492 | |
493 | /** @copydoc RTTITypeBase::getDerivedClasses */ |
494 | Vector<RTTITypeBase*>& getDerivedClasses() override |
495 | { |
496 | static Vector<RTTITypeBase*> mRTTIDerivedClasses; |
497 | return mRTTIDerivedClasses; |
498 | } |
499 | |
500 | /** @copydoc RTTITypeBase::getBaseClass */ |
501 | RTTITypeBase* getBaseClass() override |
502 | { |
503 | return GetRTTIType<BaseType>()(); |
504 | } |
505 | |
506 | /** @copydoc RTTITypeBase::isDerivedFrom */ |
507 | bool isDerivedFrom(RTTITypeBase* base) override |
508 | { |
509 | assert(base != nullptr); |
510 | |
511 | Stack<RTTITypeBase*> todo; |
512 | todo.push(base); |
513 | |
514 | while (!todo.empty()) |
515 | { |
516 | RTTITypeBase* currentType = todo.top(); |
517 | todo.pop(); |
518 | |
519 | if (currentType->getRTTIId() == getRTTIId()) |
520 | return true; |
521 | |
522 | for (const auto& item : currentType->getDerivedClasses()) |
523 | todo.push(item); |
524 | } |
525 | |
526 | return false; |
527 | } |
528 | |
529 | /** @copydoc RTTITypeBase::_registerDerivedClass */ |
530 | void _registerDerivedClass(RTTITypeBase* derivedClass) override |
531 | { |
532 | getDerivedClasses().push_back(derivedClass); |
533 | } |
534 | |
535 | /** @copydoc RTTITypeBase::_clone */ |
536 | RTTITypeBase* _clone(FrameAlloc& alloc) override |
537 | { |
538 | return alloc.construct<MyRTTIType>(); |
539 | } |
540 | |
541 | protected: |
542 | typedef Type OwnerType; |
543 | typedef MyRTTIType MyType; |
544 | |
545 | /** Registers a field referencing a plain type. */ |
546 | template<class InterfaceType, class ObjectType, class DataType> |
547 | void addPlainField(const String& name, UINT32 uniqueId, |
548 | DataType& (InterfaceType::*getter)(ObjectType*), |
549 | void (InterfaceType::*setter)(ObjectType*, DataType&), |
550 | const RTTIFieldInfo& info = RTTIFieldInfo::DEFAULT) |
551 | { |
552 | static_assert((std::is_base_of<bs::RTTIType<Type, BaseType, MyRTTIType>, InterfaceType>::value), |
553 | "Class with the get/set methods must derive from bs::RTTIType." ); |
554 | |
555 | static_assert(!(std::is_base_of<bs::IReflectable, DataType>::value), |
556 | "Data type derives from IReflectable but it is being added as a plain field." ); |
557 | |
558 | auto newField = bs_new<RTTIPlainField<InterfaceType, DataType, ObjectType>>(); |
559 | newField->initSingle(name, uniqueId, getter, setter, info); |
560 | addNewField(newField); |
561 | } |
562 | |
563 | /** Registers a field referencing an IReflectable type passed by value. */ |
564 | template<class InterfaceType, class ObjectType, class DataType> |
565 | void addReflectableField(const String& name, UINT32 uniqueId, |
566 | DataType& (InterfaceType::*getter)(ObjectType*), |
567 | void (InterfaceType::*setter)(ObjectType*, DataType&), |
568 | const RTTIFieldInfo& info = RTTIFieldInfo::DEFAULT) |
569 | { |
570 | static_assert((std::is_base_of<bs::IReflectable, DataType>::value), |
571 | "Invalid data type for complex field. It needs to derive from bs::IReflectable." ); |
572 | |
573 | auto newField = bs_new<RTTIReflectableField<InterfaceType, DataType, ObjectType>>(); |
574 | newField->initSingle(name, uniqueId, getter, setter, info); |
575 | addNewField(newField); |
576 | } |
577 | |
578 | /** Registers a field referencing an IReflectable type passed by pointer. */ |
579 | template<class InterfaceType, class ObjectType, class DataType> |
580 | void addReflectablePtrField(const String& name, UINT32 uniqueId, |
581 | SPtr<DataType> (InterfaceType::*getter)(ObjectType*), |
582 | void (InterfaceType::*setter)(ObjectType*, SPtr<DataType>), |
583 | const RTTIFieldInfo& info = RTTIFieldInfo::DEFAULT) |
584 | { |
585 | static_assert((std::is_base_of<bs::IReflectable, DataType>::value), |
586 | "Invalid data type for complex field. It needs to derive from bs::IReflectable." ); |
587 | |
588 | auto newField = bs_new<RTTIReflectablePtrField<InterfaceType, DataType, ObjectType>>(); |
589 | newField->initSingle(name, uniqueId, getter, setter, info); |
590 | addNewField(newField); |
591 | } |
592 | |
593 | /** Registers a field referencing an array of plain types. */ |
594 | template<class InterfaceType, class ObjectType, class DataType> |
595 | void addPlainArrayField(const String& name, UINT32 uniqueId, |
596 | DataType& (InterfaceType::*getter)(ObjectType*, UINT32), |
597 | UINT32(InterfaceType::*getSize)(ObjectType*), |
598 | void (InterfaceType::*setter)(ObjectType*, UINT32, DataType&), |
599 | void(InterfaceType::*setSize)(ObjectType*, UINT32), |
600 | const RTTIFieldInfo& info = RTTIFieldInfo::DEFAULT) |
601 | { |
602 | static_assert((std::is_base_of<bs::RTTIType<Type, BaseType, MyRTTIType>, InterfaceType>::value), |
603 | "Class with the get/set methods must derive from bs::RTTIType." ); |
604 | |
605 | static_assert(!(std::is_base_of<bs::IReflectable, DataType>::value), |
606 | "Data type derives from IReflectable but it is being added as a plain field." ); |
607 | |
608 | auto newField = bs_new<RTTIPlainField<InterfaceType, DataType, ObjectType>>(); |
609 | newField->initArray(name, uniqueId, getter, getSize, setter, setSize, info); |
610 | addNewField(newField); |
611 | } |
612 | |
613 | /** Registers a field referencing an array of IReflectable objects. */ |
614 | template<class InterfaceType, class ObjectType, class DataType> |
615 | void addReflectableArrayField(const String& name, UINT32 uniqueId, |
616 | DataType& (InterfaceType::*getter)(ObjectType*, UINT32), |
617 | UINT32 (InterfaceType::*getSize)(ObjectType*), |
618 | void (InterfaceType::*setter)(ObjectType*, UINT32, DataType&), |
619 | void(InterfaceType::*setSize)(ObjectType*, UINT32), |
620 | const RTTIFieldInfo& info = RTTIFieldInfo::DEFAULT) |
621 | { |
622 | static_assert((std::is_base_of<bs::IReflectable, DataType>::value), |
623 | "Invalid data type for complex field. It needs to derive from bs::IReflectable." ); |
624 | |
625 | auto newField = bs_new<RTTIReflectableField<InterfaceType, DataType, ObjectType>>(); |
626 | newField->initArray(name, uniqueId, getter, getSize, setter, setSize, info); |
627 | addNewField(newField); |
628 | } |
629 | |
630 | /** Registers a field referencing an array of IReflectable pointers. */ |
631 | template<class InterfaceType, class ObjectType, class DataType> |
632 | void addReflectablePtrArrayField(const String& name, UINT32 uniqueId, |
633 | SPtr<DataType> (InterfaceType::*getter)(ObjectType*, UINT32), |
634 | UINT32 (InterfaceType::*getSize)(ObjectType*), |
635 | void (InterfaceType::*setter)(ObjectType*, UINT32, SPtr<DataType>), |
636 | void(InterfaceType::*setSize)(ObjectType*, UINT32), |
637 | const RTTIFieldInfo& info = RTTIFieldInfo::DEFAULT) |
638 | { |
639 | static_assert((std::is_base_of<bs::IReflectable, DataType>::value), |
640 | "Invalid data type for complex field. It needs to derive from bs::IReflectable." ); |
641 | |
642 | auto newField = bs_new<RTTIReflectablePtrField<InterfaceType, DataType, ObjectType>>(); |
643 | newField->initArray(name, uniqueId, getter, getSize, setter, setSize, info); |
644 | addNewField(newField); |
645 | } |
646 | |
647 | /** Registers a field referencing a blob of memory. */ |
648 | template<class InterfaceType, class ObjectType> |
649 | void addDataBlockField(const String& name, UINT32 uniqueId, SPtr<DataStream> (InterfaceType::*getter)(ObjectType*, UINT32&), |
650 | void (InterfaceType::*setter)(ObjectType*, const SPtr<DataStream>&, UINT32), |
651 | const RTTIFieldInfo& info = RTTIFieldInfo::DEFAULT) |
652 | { |
653 | auto newField = bs_new<RTTIManagedDataBlockField<InterfaceType, UINT8*, ObjectType>>(); |
654 | newField->initSingle(name, uniqueId, getter, setter, info); |
655 | addNewField(newField); |
656 | } |
657 | }; |
658 | |
659 | template <typename Type, typename BaseType, typename MyRTTIType> |
660 | InitRTTIOnStart<Type, BaseType> RTTIType<Type, BaseType, MyRTTIType>::initOnStart; |
661 | |
662 | /** Extendable class to be used by the user to provide extra information to RTTIType objects during serialization. */ |
663 | struct BS_UTILITY_EXPORT SerializationContext : IReflectable |
664 | { |
665 | UINT32 flags = 0; |
666 | |
667 | static RTTITypeBase* getRTTIStatic(); |
668 | RTTITypeBase* getRTTI() const override; |
669 | }; |
670 | |
671 | /** Returns true if the provided object can be safely cast into type T. */ |
672 | template<class T> |
673 | bool rtti_is_of_type(IReflectable* object) |
674 | { |
675 | static_assert((std::is_base_of<bs::IReflectable, T>::value), |
676 | "Invalid data type for type checking. It needs to derive from bs::IReflectable." ); |
677 | |
678 | return object->getTypeId() == T::getRTTIStatic()->getRTTIId(); |
679 | } |
680 | |
681 | /** Returns true if the provided object can be safely cast into type T. */ |
682 | template<class T> |
683 | bool rtti_is_of_type(SPtr<IReflectable> object) |
684 | { |
685 | static_assert((std::is_base_of<bs::IReflectable, T>::value), |
686 | "Invalid data type for type checking. It needs to derive from bs::IReflectable." ); |
687 | |
688 | return object->getTypeId() == T::getRTTIStatic()->getRTTIId(); |
689 | } |
690 | |
691 | /** Creates a new object just from its type ID. */ |
692 | BS_UTILITY_EXPORT SPtr<IReflectable> rtti_create(UINT32 rttiId); |
693 | |
694 | /** Checks is the current object a subclass of some type. */ |
695 | template<class T> |
696 | bool rtti_is_subclass(IReflectable* object) |
697 | { |
698 | static_assert((std::is_base_of<bs::IReflectable, T>::value), |
699 | "Invalid data type for type checking. It needs to derive from bs::IReflectable." ); |
700 | |
701 | return object && object->isDerivedFrom(T::getRTTIStatic()); |
702 | } |
703 | |
704 | /** Checks is the current object a subclass of some type. */ |
705 | template<class T> |
706 | bool rtti_is_subclass(const SPtr<IReflectable>& object) |
707 | { |
708 | static_assert((std::is_base_of<bs::IReflectable, T>::value), |
709 | "Invalid data type for type checking. It needs to derive from bs::IReflectable." ); |
710 | |
711 | return object && object->isDerivedFrom(T::getRTTIStatic()); |
712 | } |
713 | |
714 | /** Attempts to cast the object to the provided type, or returns null if cast is not valid. */ |
715 | template<class T> |
716 | T* rtti_cast(IReflectable* object) |
717 | { |
718 | if(rtti_is_subclass<T>(object)) |
719 | return (T*)object; |
720 | |
721 | return nullptr; |
722 | } |
723 | |
724 | /** Attempts to cast the object to the provided type, or returns null if cast is not valid. */ |
725 | template<class T> |
726 | SPtr<T> rtti_cast(const SPtr<IReflectable> object) |
727 | { |
728 | if(rtti_is_subclass<T>(object)) |
729 | return std::static_pointer_cast<T>(object); |
730 | |
731 | return nullptr; |
732 | } |
733 | /** @} */ |
734 | } |
735 | |