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
16 #include "container_base.h"
17
18 #include <algorithm>
19 #include <mutex>
20
21 #include <base/math/mathf.h>
22
23 #include <meta/api/iteration.h>
24 #include <meta/base/interface_utils.h>
25 #include <meta/interface/intf_containable.h>
26
META_BEGIN_NAMESPACE()27 META_BEGIN_NAMESPACE()
28
29 void ContainerBase::SetImplementingIContainer(IObject* me, IContainer* c)
30 {
31 me_ = me;
32 impl_ = c;
33 CORE_ASSERT_MSG(impl_, "ContainerBase with null implementation");
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 Internal::ConstIterate(
66 this,
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 Internal::ConstIterate(
81 this,
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 (BASE_NS::string_view(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 {
136 std::unique_lock lock(mutex_);
137 if (children_.size() <= index) {
138 return false;
139 }
140 auto it = children_.begin() + index;
141 child = *it;
142 children_.erase(it);
143 }
144 ChildChangedInfo info { ContainerChangeType::REMOVED, child, parent_, index };
145 SetObjectParent(child, nullptr);
146 Invoke<IOnChildChanged>(impl_->EventOnContainerChanged(MetadataQuery::EXISTING), info);
147 return true;
148 }
149
Remove(const IObject::Ptr & child)150 bool ContainerBase::Remove(const IObject::Ptr& child)
151 {
152 if (!child) {
153 return false;
154 }
155 SizeType index = 0;
156 {
157 std::unique_lock lock(mutex_);
158 auto it = children_.begin();
159 for (; it != children_.end() && *it != child; ++it, ++index) {
160 }
161 if (it == children_.end()) {
162 return false;
163 }
164 children_.erase(it);
165 }
166 ChildChangedInfo info { ContainerChangeType::REMOVED, child, parent_, index };
167 SetObjectParent(child, nullptr);
168 Invoke<IOnChildChanged>(impl_->EventOnContainerChanged(MetadataQuery::EXISTING), info);
169 return true;
170 }
171
MoveInternal(SizeType fromIndex,SizeType toIndex)172 ChildChangedInfo ContainerBase::MoveInternal(SizeType fromIndex, SizeType toIndex)
173 {
174 if (children_.empty()) {
175 return {};
176 }
177 const auto size = children_.size();
178 fromIndex = BASE_NS::Math::min(fromIndex, size - 1);
179 toIndex = BASE_NS::Math::min(toIndex, size - 1);
180 const IObject::Ptr child = children_[fromIndex];
181 if (fromIndex > toIndex) {
182 const auto first = children_.rbegin() + (size - fromIndex - 1);
183 const auto last = children_.rbegin() + (size - toIndex);
184 std::rotate(first, first + 1, last);
185 } else if (fromIndex < toIndex) {
186 const auto first = children_.begin() + fromIndex;
187 const auto last = children_.begin() + toIndex + 1;
188 std::rotate(first, first + 1, last);
189 }
190 return { ContainerChangeType::MOVED, child, parent_, fromIndex, toIndex };
191 }
192
Move(SizeType fromIndex,SizeType toIndex)193 bool ContainerBase::Move(SizeType fromIndex, SizeType toIndex)
194 {
195 ChildChangedInfo info;
196 {
197 std::unique_lock lock(mutex_);
198 info = MoveInternal(fromIndex, toIndex);
199 }
200 if (info.object) {
201 if (info.from != info.to) {
202 Invoke<IOnChildChanged>(impl_->EventOnContainerChanged(MetadataQuery::EXISTING), info);
203 }
204 return true;
205 }
206 return false;
207 }
208
Move(const IObject::Ptr & child,SizeType toIndex)209 bool ContainerBase::Move(const IObject::Ptr& child, SizeType toIndex)
210 {
211 ChildChangedInfo info;
212 {
213 std::unique_lock lock(mutex_);
214 SizeType fromIndex = 0;
215 for (const auto& c : children_) {
216 if (c == child) {
217 info = MoveInternal(fromIndex, toIndex);
218 break;
219 }
220 fromIndex++;
221 }
222 }
223 if (info.object) {
224 if (info.from != info.to) {
225 Invoke<IOnChildChanged>(impl_->EventOnContainerChanged(MetadataQuery::EXISTING), info);
226 }
227 return true;
228 }
229 return false;
230 }
231
RemoveAll()232 void ContainerBase::RemoveAll()
233 {
234 BASE_NS::vector<IObject::Ptr> children;
235 {
236 std::unique_lock lock(mutex_);
237 children_.swap(children);
238 }
239 SizeType index = 0;
240 for (const auto& child : children) {
241 ChildChangedInfo info { ContainerChangeType::REMOVED, child, parent_, index++ };
242 SetObjectParent(child, nullptr);
243 Invoke<IOnChildChanged>(impl_->EventOnContainerChanged(MetadataQuery::EXISTING), info);
244 }
245 }
246
InternalRemoveAll()247 void ContainerBase::InternalRemoveAll()
248 {
249 BASE_NS::vector<IObject::Ptr> children;
250 {
251 std::unique_lock lock(mutex_);
252 children_.swap(children);
253 }
254 for (const auto& child : children) {
255 if (auto c = interface_cast<IMutableContainable>(child)) {
256 c->SetParent(nullptr);
257 }
258 }
259 }
260
SetRequiredInterfaces(const BASE_NS::vector<TypeId> & interfaces)261 bool ContainerBase::SetRequiredInterfaces(const BASE_NS::vector<TypeId>& interfaces)
262 {
263 std::unique_lock lock(mutex_);
264 required_ = interfaces;
265
266 BASE_NS::vector<IObject::Ptr> compatible;
267 compatible.reserve(children_.size());
268 for (const auto& child : children_) {
269 if (IsCompatible(child)) {
270 compatible.push_back(child);
271 }
272 }
273 children_.swap(compatible);
274 return true;
275 }
276
GetRequiredInterfaces() const277 BASE_NS::vector<TypeId> ContainerBase::GetRequiredInterfaces() const
278 {
279 std::shared_lock lock(mutex_);
280 return required_;
281 }
282
IsCompatible(const IObject::Ptr & object) const283 bool ContainerBase::IsCompatible(const IObject::Ptr& object) const
284 {
285 return ObjectImplementsAll(object, required_);
286 }
287
IsAncestorOf(const IObject::ConstPtr & object) const288 bool ContainerBase::IsAncestorOf(const IObject::ConstPtr& object) const
289 {
290 if (!object || !me_) {
291 return false;
292 }
293 if (me_ == object.get()) {
294 return true;
295 }
296 const auto containable = interface_pointer_cast<IContainable>(object);
297 if (!containable) {
298 return false;
299 }
300 auto parent = containable->GetParent();
301 while (parent) {
302 if (parent.get() == me_) {
303 return true;
304 }
305 if (auto parentContainable = interface_cast<IContainable>(parent)) {
306 parent = parentContainable->GetParent();
307 } else {
308 break;
309 }
310 }
311 return false;
312 }
313
EventOnContainerChanged(MetadataQuery q) const314 BASE_NS::shared_ptr<IEvent> ContainerBase::EventOnContainerChanged(MetadataQuery q) const
315 {
316 return impl_->EventOnContainerChanged(q);
317 }
318
319 template<typename Cont, typename Func>
IterateImpl(Cont & cont,const Func & func)320 static IterationResult IterateImpl(Cont& cont, const Func& func)
321 {
322 for (auto&& child : cont) {
323 auto res = func->Invoke(child);
324 if (!res.Continue()) {
325 return res;
326 }
327 }
328 return IterationResult::CONTINUE;
329 }
330
Iterate(const IterationParameters & params)331 IterationResult ContainerBase::Iterate(const IterationParameters& params)
332 {
333 auto f = params.function.GetInterface<IIterableCallable<IObject::Ptr>>();
334 if (!f) {
335 CORE_LOG_W("Incompatible function with Iterate");
336 return IterationResult::FAILED;
337 }
338 return IterateImpl(children_, f);
339 }
340
Iterate(const IterationParameters & params) const341 IterationResult ContainerBase::Iterate(const IterationParameters& params) const
342 {
343 auto f = params.function.GetInterface<IIterableConstCallable<IObject::Ptr>>();
344 if (!f) {
345 CORE_LOG_W("Incompatible function with Iterate");
346 return IterationResult::FAILED;
347 }
348 return IterateImpl(children_, f);
349 }
350
351 META_END_NAMESPACE()
352