1 /*
2 * Copyright (c) 2024 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15 #include "container_base.h"
16
17 #include <algorithm>
18
19 #include <base/math/mathf.h>
20
21 #include <meta/api/iteration.h>
22 #include <meta/base/interface_utils.h>
23 #include <meta/interface/intf_containable.h>
24
META_BEGIN_NAMESPACE()25 META_BEGIN_NAMESPACE()
26
27 void ContainerBase::SetImplementingIContainer(IObject* me, IContainer* c)
28 {
29 me_ = me;
30 impl_ = c;
31 CORE_ASSERT(impl_);
32 implPreTrans_ = interface_cast<IContainerPreTransaction>(impl_);
33 CORE_ASSERT(implPreTrans_);
34 }
35
LockShared() const36 void ContainerBase::LockShared() const
37 {
38 mutex_.lock_shared();
39 }
40
UnlockShared() const41 void ContainerBase::UnlockShared() const
42 {
43 mutex_.unlock_shared();
44 }
45
Lock() const46 void ContainerBase::Lock() const
47 {
48 mutex_.lock();
49 }
50
Unlock() const51 void ContainerBase::Unlock() const
52 {
53 mutex_.unlock();
54 }
55
SetProxyParent(const IContainer::Ptr & parent)56 bool ContainerBase::SetProxyParent(const IContainer::Ptr& parent)
57 {
58 parent_ = parent;
59 return true;
60 }
61
FindAnyImpl(const IContainer::FindOptions & options,bool isFlat) const62 IObject::Ptr ContainerBase::FindAnyImpl(const IContainer::FindOptions& options, bool isFlat) const
63 {
64 IObject::Ptr res;
65 ConstIterate(
66 GetSelf(impl_),
67 [&](const IObject::Ptr& obj) {
68 if (MatchCriteria(options, obj)) {
69 res = obj;
70 }
71 return !res;
72 },
73 IterateStrategy { isFlat ? TraversalType::NO_HIERARCHY : options.behavior, LockType::SHARED_LOCK });
74 return res;
75 }
76
FindAllImpl(const IContainer::FindOptions & options,bool isFlat) const77 BASE_NS::vector<IObject::Ptr> ContainerBase::FindAllImpl(const IContainer::FindOptions& options, bool isFlat) const
78 {
79 BASE_NS::vector<IObject::Ptr> res;
80 ConstIterate(
81 GetSelf(impl_),
82 [&](const IObject::Ptr& obj) {
83 if (options.name.empty() || obj->GetName() == options.name) {
84 if (CheckInterfaces(obj, options.uids, options.strict)) {
85 res.push_back(obj);
86 }
87 }
88 return true;
89 },
90 IterateStrategy { isFlat ? TraversalType::NO_HIERARCHY : options.behavior, LockType::SHARED_LOCK });
91 return res;
92 }
93
GetAll() const94 BASE_NS::vector<IObject::Ptr> ContainerBase::GetAll() const
95 {
96 std::shared_lock lock(mutex_);
97 return children_;
98 }
99
GetAt(SizeType index) const100 IObject::Ptr ContainerBase::GetAt(SizeType index) const
101 {
102 std::shared_lock lock(mutex_);
103 if (index >= children_.size()) {
104 return {};
105 }
106 return children_[index];
107 }
108
GetSize() const109 IContainer::SizeType ContainerBase::GetSize() const
110 {
111 std::shared_lock lock(mutex_);
112 return children_.size();
113 }
114
FindByName(BASE_NS::string_view name) const115 IObject::Ptr ContainerBase::FindByName(BASE_NS::string_view name) const
116 {
117 std::shared_lock lock(mutex_);
118 for (const auto& child : children_) {
119 if (child->GetName() == name) {
120 return child;
121 }
122 }
123 return {};
124 }
125
MatchCriteria(const IContainer::FindOptions & options,const IObject::Ptr & object) const126 bool ContainerBase::MatchCriteria(const IContainer::FindOptions& options, const IObject::Ptr& object) const
127 {
128 return object && (options.name.empty() || object->GetName() == options.name) &&
129 CheckInterfaces(object, options.uids, options.strict);
130 }
131
Remove(SizeType index)132 bool ContainerBase::Remove(SizeType index)
133 {
134 IObject::Ptr child;
135 const auto direct = !implPreTrans_->OnRemoving()->HasHandlers();
136 {
137 std::unique_lock lock(mutex_);
138 if (children_.size() <= index) {
139 return false;
140 }
141 auto it = children_.begin() + index;
142 child = *it;
143 if (direct) {
144 children_.erase(it);
145 }
146 }
147 bool success = true;
148 ChildChangedInfo info { child, index, parent_ };
149 if (!direct) {
150 Invoke<IOnChildChanging>(implPreTrans_->OnRemoving(), info, success);
151 if (success) {
152 std::unique_lock lock(mutex_);
153 children_.erase(children_.begin() + index);
154 }
155 }
156 if (success) {
157 SetObjectParent(child, nullptr);
158 Invoke<IOnChildChanged>(impl_->OnRemoved(), info);
159 }
160 return success;
161 }
162
Remove(const IObject::Ptr & child)163 bool ContainerBase::Remove(const IObject::Ptr& child)
164 {
165 if (!child) {
166 return false;
167 }
168 const auto direct = !implPreTrans_->OnRemoving()->HasHandlers();
169 bool success = false;
170 SizeType index = 0;
171 {
172 std::unique_lock lock(mutex_);
173 for (auto it = children_.cbegin(); it != children_.cend(); ++it) {
174 if (*it == child) {
175 success = true;
176 if (direct) {
177 children_.erase(children_.begin() + index);
178 }
179 break;
180 }
181 index++;
182 }
183 }
184 if (!success) {
185 return false;
186 }
187 ChildChangedInfo info { child, index, parent_ };
188 if (!direct) {
189 Invoke<IOnChildChanging>(implPreTrans_->OnRemoving(), info, success);
190 if (success) {
191 std::unique_lock lock(mutex_);
192 children_.erase(children_.begin() + index);
193 }
194 }
195 if (success) {
196 SetObjectParent(child, nullptr);
197 Invoke<IOnChildChanged>(impl_->OnRemoved(), info);
198 }
199 return success;
200 }
201
MoveInternal(SizeType fromIndex,SizeType toIndex)202 ChildMovedInfo ContainerBase::MoveInternal(SizeType fromIndex, SizeType toIndex)
203 {
204 if (children_.empty()) {
205 return {};
206 }
207 const auto size = children_.size();
208 fromIndex = BASE_NS::Math::min(fromIndex, size - 1);
209 toIndex = BASE_NS::Math::min(toIndex, size - 1);
210 const IObject::Ptr child = children_[fromIndex];
211 if (fromIndex == toIndex) {
212 return { child, 0, 0 };
213 }
214 if (fromIndex > toIndex) {
215 const auto first = children_.rbegin() + (size - fromIndex - 1);
216 const auto last = children_.rbegin() + (size - toIndex);
217 std::rotate(first, first + 1, last);
218 } else {
219 const auto first = children_.begin() + fromIndex;
220 const auto last = children_.begin() + toIndex + 1;
221 std::rotate(first, first + 1, last);
222 }
223 return { child, fromIndex, toIndex, parent_ };
224 }
225
Move(SizeType fromIndex,SizeType toIndex)226 bool ContainerBase::Move(SizeType fromIndex, SizeType toIndex)
227 {
228 ChildMovedInfo info;
229 {
230 std::unique_lock lock(mutex_);
231 info = MoveInternal(fromIndex, toIndex);
232 }
233 if (info.object) {
234 if (info.from != info.to) {
235 Invoke<IOnChildMoved>(impl_->OnMoved(), BASE_NS::move(info));
236 }
237 return true;
238 }
239 return false;
240 }
241
Move(const IObject::Ptr & child,SizeType toIndex)242 bool ContainerBase::Move(const IObject::Ptr& child, SizeType toIndex)
243 {
244 ChildMovedInfo info;
245 {
246 std::unique_lock lock(mutex_);
247 SizeType fromIndex = 0;
248 for (const auto& c : children_) {
249 if (c == child) {
250 info = MoveInternal(fromIndex, toIndex);
251 break;
252 }
253 fromIndex++;
254 }
255 }
256 if (info.object) {
257 if (info.from != info.to) {
258 Invoke<IOnChildMoved>(impl_->OnMoved(), BASE_NS::move(info));
259 }
260 return true;
261 }
262 return false;
263 }
264
RemoveAll()265 void ContainerBase::RemoveAll()
266 {
267 BASE_NS::vector<IObject::Ptr> children;
268 {
269 std::unique_lock lock(mutex_);
270 children_.swap(children);
271 }
272
273 SizeType index = 0;
274 for (const auto& child : children) {
275 ChildChangedInfo info { child, index++, parent_ };
276 bool success = true;
277 Invoke<IOnChildChanging>(implPreTrans_->OnRemoving(), info, success); // Ignore result
278 if (!success) {
279 CORE_LOG_E("Failing a remove transaction during remove all operation is not supported");
280 }
281 SetObjectParent(child, nullptr);
282 Invoke<IOnChildChanged>(impl_->OnRemoved(), info);
283 }
284 }
285
InternalRemoveAll()286 void ContainerBase::InternalRemoveAll()
287 {
288 BASE_NS::vector<IObject::Ptr> children;
289 {
290 std::unique_lock lock(mutex_);
291 children_.swap(children);
292 }
293 for (const auto& child : children) {
294 if (auto c = interface_cast<IMutableContainable>(child)) {
295 c->SetParent(nullptr);
296 }
297 }
298 }
299
SetRequiredInterfaces(const BASE_NS::vector<TypeId> & interfaces)300 bool ContainerBase::SetRequiredInterfaces(const BASE_NS::vector<TypeId>& interfaces)
301 {
302 std::unique_lock lock(mutex_);
303 required_ = interfaces;
304
305 BASE_NS::vector<IObject::Ptr> compatible;
306 compatible.reserve(children_.size());
307 for (const auto& child : children_) {
308 if (IsCompatible(child)) {
309 compatible.push_back(child);
310 }
311 }
312 children_.swap(compatible);
313 return true;
314 }
315
GetRequiredInterfaces() const316 BASE_NS::vector<TypeId> ContainerBase::GetRequiredInterfaces() const
317 {
318 std::shared_lock lock(mutex_);
319 return required_;
320 }
321
IsCompatible(const IObject::Ptr & object) const322 bool ContainerBase::IsCompatible(const IObject::Ptr& object) const
323 {
324 return ObjectImplementsAll(object, required_);
325 }
326
IsAncestorOf(const IObject::ConstPtr & object) const327 bool ContainerBase::IsAncestorOf(const IObject::ConstPtr& object) const
328 {
329 if (!object || !me_) {
330 return false;
331 }
332 if (me_ == object.get()) {
333 return true;
334 }
335 const auto containable = interface_pointer_cast<IContainable>(object);
336 if (!containable) {
337 return false;
338 }
339 auto parent = containable->GetParent();
340 while (parent) {
341 if (parent.get() == me_) {
342 return true;
343 }
344 if (auto parentContainable = interface_cast<IContainable>(parent)) {
345 parent = parentContainable->GetParent();
346 } else {
347 break;
348 }
349 }
350 return false;
351 }
352
EventOnAdded() const353 BASE_NS::shared_ptr<IEvent> ContainerBase::EventOnAdded() const
354 {
355 return impl_->OnAdded();
356 }
357
EventOnRemoved() const358 BASE_NS::shared_ptr<IEvent> ContainerBase::EventOnRemoved() const
359 {
360 return impl_->OnRemoved();
361 }
362
EventOnMoved() const363 BASE_NS::shared_ptr<IEvent> ContainerBase::EventOnMoved() const
364 {
365 return impl_->OnMoved();
366 }
367
EventOnAdding() const368 BASE_NS::shared_ptr<IEvent> ContainerBase::EventOnAdding() const
369 {
370 return implPreTrans_->OnAdding();
371 }
372
EventOnRemoving() const373 BASE_NS::shared_ptr<IEvent> ContainerBase::EventOnRemoving() const
374 {
375 return implPreTrans_->OnRemoving();
376 }
377
378 template<typename Cont, typename Func>
IterateImpl(Cont & cont,const Func & func)379 static IterationResult IterateImpl(Cont& cont, const Func& func)
380 {
381 for (auto&& child : cont) {
382 auto res = func->Invoke(child);
383 if (!res.Continue()) {
384 return res;
385 }
386 }
387 return IterationResult::CONTINUE;
388 }
389
Iterate(const IterationParameters & params)390 IterationResult ContainerBase::Iterate(const IterationParameters& params)
391 {
392 auto f = params.function.GetInterface<IIterableCallable<IObject::Ptr>>();
393 if (!f) {
394 CORE_LOG_W("Incompatible function with Iterate");
395 return IterationResult::FAILED;
396 }
397 return IterateImpl(children_, f);
398 }
399
Iterate(const IterationParameters & params) const400 IterationResult ContainerBase::Iterate(const IterationParameters& params) const
401 {
402 auto f = params.function.GetInterface<IIterableConstCallable<IObject::Ptr>>();
403 if (!f) {
404 CORE_LOG_W("Incompatible function with Iterate");
405 return IterationResult::FAILED;
406 }
407 return IterateImpl(children_, f);
408 }
409
410 META_END_NAMESPACE()
411