• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
17 #include "container_base.h"
18 
19 #include <algorithm>
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(impl_);
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