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 "Serialization/BsBinaryCloner.h" |
4 | #include "Reflection/BsIReflectable.h" |
5 | #include "Reflection/BsRTTIType.h" |
6 | #include "Reflection/BsRTTIField.h" |
7 | #include "Reflection/BsRTTIPlainField.h" |
8 | #include "Reflection/BsRTTIReflectableField.h" |
9 | #include "Reflection/BsRTTIReflectablePtrField.h" |
10 | #include "Reflection/BsRTTIManagedDataBlockField.h" |
11 | #include "Serialization/BsMemorySerializer.h" |
12 | |
13 | namespace bs |
14 | { |
15 | SPtr<IReflectable> BinaryCloner::clone(IReflectable* object, bool shallow) |
16 | { |
17 | if (object == nullptr) |
18 | return nullptr; |
19 | |
20 | ObjectReferenceData referenceData; |
21 | if (shallow) |
22 | { |
23 | FrameAlloc& alloc = gFrameAlloc(); |
24 | |
25 | alloc.markFrame(); |
26 | gatherReferences(object, alloc, referenceData); |
27 | alloc.clear(); |
28 | } |
29 | |
30 | std::function<void*(UINT32)> allocator = &MemoryAllocator<GenAlloc>::allocate; |
31 | |
32 | MemorySerializer ms; |
33 | UINT32 dataSize = 0; |
34 | UINT8* data = ms.encode(object, dataSize, allocator, shallow); |
35 | SPtr<IReflectable> clonedObj = ms.decode(data, dataSize); |
36 | |
37 | if (shallow) |
38 | { |
39 | FrameAlloc& alloc = gFrameAlloc(); |
40 | |
41 | alloc.markFrame(); |
42 | restoreReferences(clonedObj.get(), alloc, referenceData); |
43 | alloc.clear(); |
44 | } |
45 | |
46 | bs_free(data); |
47 | return clonedObj; |
48 | } |
49 | |
50 | void BinaryCloner::gatherReferences(IReflectable* object, FrameAlloc& alloc, ObjectReferenceData& referenceData) |
51 | { |
52 | if (object == nullptr) |
53 | return; |
54 | |
55 | RTTITypeBase* rtti = object->getRTTI(); |
56 | Stack<RTTITypeBase*> rttiInstances; |
57 | while (rtti != nullptr) |
58 | { |
59 | RTTITypeBase* rttiInstance = rtti->_clone(alloc); |
60 | |
61 | rttiInstance->onSerializationStarted(object, nullptr); |
62 | SubObjectReferenceData* subObjectData = nullptr; |
63 | |
64 | UINT32 numFields = rtti->getNumFields(); |
65 | for (UINT32 i = 0; i < numFields; i++) |
66 | { |
67 | RTTIField* field = rtti->getField(i); |
68 | FieldId fieldId; |
69 | fieldId.field = field; |
70 | fieldId.arrayIdx = -1; |
71 | |
72 | if (field->isArray()) |
73 | { |
74 | const UINT32 numElements = field->getArraySize(rttiInstance, object); |
75 | |
76 | for (UINT32 j = 0; j < numElements; j++) |
77 | { |
78 | fieldId.arrayIdx = j; |
79 | |
80 | if (field->mType == SerializableFT_ReflectablePtr) |
81 | { |
82 | auto* curField = static_cast<RTTIReflectablePtrFieldBase*>(field); |
83 | SPtr<IReflectable> childObj = curField->getArrayValue(rttiInstance, object, j); |
84 | |
85 | if (childObj != nullptr) |
86 | { |
87 | if (subObjectData == nullptr) |
88 | { |
89 | referenceData.subObjectData.push_back(SubObjectReferenceData()); |
90 | subObjectData = &referenceData.subObjectData[referenceData.subObjectData.size() - 1]; |
91 | subObjectData->rtti = rtti; |
92 | } |
93 | |
94 | subObjectData->references.push_back(ObjectReference()); |
95 | ObjectReference& reference = subObjectData->references.back(); |
96 | reference.fieldId = fieldId; |
97 | reference.object = childObj; |
98 | } |
99 | } |
100 | else if (field->mType == SerializableFT_Reflectable) |
101 | { |
102 | auto* curField = static_cast<RTTIReflectableFieldBase*>(field); |
103 | IReflectable* childObj = &curField->getArrayValue(rttiInstance, object, j); |
104 | |
105 | if (subObjectData == nullptr) |
106 | { |
107 | referenceData.subObjectData.push_back(SubObjectReferenceData()); |
108 | subObjectData = &referenceData.subObjectData[referenceData.subObjectData.size() - 1]; |
109 | subObjectData->rtti = rtti; |
110 | } |
111 | |
112 | subObjectData->children.push_back(ObjectReferenceData()); |
113 | ObjectReferenceData& childData = subObjectData->children.back(); |
114 | childData.fieldId = fieldId; |
115 | |
116 | gatherReferences(childObj, alloc, childData); |
117 | } |
118 | } |
119 | } |
120 | else |
121 | { |
122 | if (field->mType == SerializableFT_ReflectablePtr) |
123 | { |
124 | auto* curField = static_cast<RTTIReflectablePtrFieldBase*>(field); |
125 | SPtr<IReflectable> childObj = curField->getValue(rttiInstance, object); |
126 | |
127 | if (childObj != nullptr) |
128 | { |
129 | if (subObjectData == nullptr) |
130 | { |
131 | referenceData.subObjectData.push_back(SubObjectReferenceData()); |
132 | subObjectData = &referenceData.subObjectData[referenceData.subObjectData.size() - 1]; |
133 | subObjectData->rtti = rtti; |
134 | } |
135 | |
136 | subObjectData->references.push_back(ObjectReference()); |
137 | ObjectReference& reference = subObjectData->references.back(); |
138 | reference.fieldId = fieldId; |
139 | reference.object = childObj; |
140 | } |
141 | } |
142 | else if (field->mType == SerializableFT_Reflectable) |
143 | { |
144 | auto* curField = static_cast<RTTIReflectableFieldBase*>(field); |
145 | IReflectable* childObj = &curField->getValue(rttiInstance, object); |
146 | |
147 | if (subObjectData == nullptr) |
148 | { |
149 | referenceData.subObjectData.push_back(SubObjectReferenceData()); |
150 | subObjectData = &referenceData.subObjectData[referenceData.subObjectData.size() - 1]; |
151 | subObjectData->rtti = rtti; |
152 | } |
153 | |
154 | subObjectData->children.push_back(ObjectReferenceData()); |
155 | ObjectReferenceData& childData = subObjectData->children.back(); |
156 | childData.fieldId = fieldId; |
157 | |
158 | gatherReferences(childObj, alloc, childData); |
159 | } |
160 | } |
161 | } |
162 | |
163 | rttiInstances.push(rttiInstance); |
164 | rtti = rtti->getBaseClass(); |
165 | } |
166 | |
167 | while (!rttiInstances.empty()) |
168 | { |
169 | RTTITypeBase* rttiInstance = rttiInstances.top(); |
170 | rttiInstances.pop(); |
171 | |
172 | rttiInstance->onSerializationEnded(object, nullptr); |
173 | alloc.destruct(rttiInstance); |
174 | } |
175 | } |
176 | |
177 | void BinaryCloner::restoreReferences(IReflectable* object, FrameAlloc& alloc, const ObjectReferenceData& referenceData) |
178 | { |
179 | for(auto iter = referenceData.subObjectData.rbegin(); iter != referenceData.subObjectData.rend(); ++iter) |
180 | { |
181 | const SubObjectReferenceData& subObject = *iter; |
182 | |
183 | if (!subObject.references.empty()) |
184 | { |
185 | RTTITypeBase* rttiInstance = subObject.rtti->_clone(alloc); |
186 | rttiInstance->onDeserializationStarted(object, nullptr); |
187 | |
188 | for (auto& reference : subObject.references) |
189 | { |
190 | auto* curField = static_cast<RTTIReflectablePtrFieldBase*>(reference.fieldId.field); |
191 | |
192 | if (curField->isArray()) |
193 | curField->setArrayValue(rttiInstance, object, reference.fieldId.arrayIdx, reference.object); |
194 | else |
195 | curField->setValue(rttiInstance, object, reference.object); |
196 | } |
197 | |
198 | rttiInstance->onDeserializationEnded(object, nullptr); |
199 | alloc.destruct(rttiInstance); |
200 | } |
201 | } |
202 | |
203 | for (auto& subObject : referenceData.subObjectData) |
204 | { |
205 | if (!subObject.children.empty()) |
206 | { |
207 | RTTITypeBase* rttiInstance = subObject.rtti->_clone(alloc); |
208 | rttiInstance->onSerializationStarted(object, nullptr); |
209 | |
210 | for (auto& childObjectData : subObject.children) |
211 | { |
212 | auto* curField = static_cast<RTTIReflectableFieldBase*>(childObjectData.fieldId.field); |
213 | |
214 | IReflectable* childObj = nullptr; |
215 | if (curField->isArray()) |
216 | childObj = &curField->getArrayValue(rttiInstance, object, childObjectData.fieldId.arrayIdx); |
217 | else |
218 | childObj = &curField->getValue(rttiInstance, object); |
219 | |
220 | restoreReferences(childObj, alloc, childObjectData); |
221 | } |
222 | |
223 | rttiInstance->onSerializationEnded(object, nullptr); |
224 | alloc.destruct(rttiInstance); |
225 | } |
226 | } |
227 | } |
228 | } |