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#include "Reflection/BsIReflectable.h"
4#include "Reflection/BsRTTIType.h"
5#include "Error/BsException.h"
6#include "Private/RTTI/BsIReflectableRTTI.h"
7
8namespace bs
9{
10 void IReflectable::_registerRTTIType(RTTITypeBase* rttiType)
11 {
12 if(_isTypeIdDuplicate(rttiType->getRTTIId()))
13 {
14 BS_EXCEPT(InternalErrorException, "RTTI type \"" + rttiType->getRTTIName() +
15 "\" has a duplicate ID: " + toString(rttiType->getRTTIId()));
16 }
17
18 getAllRTTITypes()[rttiType->getRTTIId()] = rttiType;
19 }
20
21 SPtr<IReflectable> IReflectable::createInstanceFromTypeId(UINT32 rttiTypeId)
22 {
23 RTTITypeBase* type = _getRTTIfromTypeId(rttiTypeId);
24
25 SPtr<IReflectable> output;
26 if(type != nullptr)
27 output = type->newRTTIObject();
28
29 return output;
30 }
31
32 RTTITypeBase* IReflectable::_getRTTIfromTypeId(UINT32 rttiTypeId)
33 {
34 const auto iterFind = getAllRTTITypes().find(rttiTypeId);
35 if(iterFind != getAllRTTITypes().end())
36 return iterFind->second;
37
38 return nullptr;
39 }
40
41 bool IReflectable::_isTypeIdDuplicate(UINT32 typeId)
42 {
43 if(typeId == TID_Abstract)
44 return false;
45
46 return IReflectable::_getRTTIfromTypeId(typeId) != nullptr;
47 }
48
49 bool IReflectable::isDerivedFrom(RTTITypeBase* base)
50 {
51 return getRTTI()->isDerivedFrom(base);
52 }
53
54 void IReflectable::_checkForCircularReferences()
55 {
56 Stack<RTTITypeBase*> todo;
57
58 const UnorderedMap<UINT32, RTTITypeBase*>& allTypes = getAllRTTITypes();
59 for(auto& entry : allTypes)
60 {
61 RTTITypeBase* myType = entry.second;
62
63 UINT32 myNumFields = myType->getNumFields();
64 for (UINT32 i = 0; i < myNumFields; i++)
65 {
66 RTTIField* myField = myType->getField(i);
67
68 if (!myField->isReflectablePtrType())
69 continue;
70
71 RTTIReflectablePtrFieldBase* myReflectablePtrField = static_cast<RTTIReflectablePtrFieldBase*>(myField);
72
73 RTTITypeBase* otherType = myReflectablePtrField->getType();
74 UINT32 otherNumFields = otherType->getNumFields();
75 for (UINT32 j = 0; j < otherNumFields; j++)
76 {
77 RTTIField* otherField = otherType->getField(j);
78
79 if (!otherField->isReflectablePtrType())
80 continue;
81
82 RTTIReflectablePtrFieldBase* otherReflectablePtrField = static_cast<RTTIReflectablePtrFieldBase*>(otherField);
83
84 if (myType->getRTTIId() == otherReflectablePtrField->getType()->getRTTIId() &&
85 (!myReflectablePtrField->getInfo().flags.isSet(RTTIFieldFlag::WeakRef) &&
86 !otherReflectablePtrField->getInfo().flags.isSet(RTTIFieldFlag::WeakRef)))
87 {
88 BS_EXCEPT(InternalErrorException, "Found circular reference on RTTI type: " + myType->getRTTIName()
89 + " to type: " + otherType->getRTTIName() + ". Either remove one of the references or mark it"
90 + " as a weak reference when defining the RTTI field.");
91 }
92 }
93 }
94 }
95 }
96
97 UINT32 IReflectable::getTypeId() const
98 {
99 return getRTTI()->getRTTIId();
100 }
101
102 const String& IReflectable::getTypeName() const
103 {
104 return getRTTI()->getRTTIName();
105 }
106
107 RTTITypeBase* IReflectable::getRTTIStatic()
108 {
109 return IReflectableRTTI::instance();
110 }
111}
112