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 "flat_container.h"
17
18 #include <algorithm>
19
20 #include <base/math/mathf.h>
21
22 #include <meta/api/internal/iteration.h>
23 #include <meta/base/interface_utils.h>
24 #include <meta/interface/intf_containable.h>
25
META_BEGIN_NAMESPACE()26 META_BEGIN_NAMESPACE()
27
28 IObject::Ptr FlatContainer::FindAny(const IContainer::FindOptions& options) const
29 {
30 return ContainerBase::FindAnyImpl(options, true);
31 }
32
FindAll(const IContainer::FindOptions & options) const33 BASE_NS::vector<IObject::Ptr> FlatContainer::FindAll(const IContainer::FindOptions& options) const
34 {
35 return ContainerBase::FindAllImpl(options, true);
36 }
37
Add(const META_NS::IObject::Ptr & object)38 bool FlatContainer::Add(const META_NS::IObject::Ptr& object)
39 {
40 return Insert(-1, object);
41 }
42
Insert(SizeType index,const IObject::Ptr & object)43 bool FlatContainer::Insert(SizeType index, const IObject::Ptr& object)
44 {
45 if (!object) {
46 return false;
47 }
48 {
49 std::unique_lock lock(mutex_);
50 if (!IsCompatible(object)) {
51 return false;
52 }
53 index = BASE_NS::Math::min(index, children_.size());
54 children_.insert(children_.begin() + index, object);
55 }
56 ChildChangedInfo info { ContainerChangeType::ADDED, object, parent_, size_t(-1), index };
57 SetObjectParent(object, interface_pointer_cast<IObject>(parent_));
58 Invoke<IOnChildChanged>(EventOnContainerChanged(MetadataQuery::EXISTING), info);
59 return true;
60 }
61
Replace(const IObject::Ptr & child,const IObject::Ptr & replaceWith,bool addAlways)62 bool FlatContainer::Replace(const IObject::Ptr& child, const IObject::Ptr& replaceWith, bool addAlways)
63 {
64 SizeType index = 0;
65 IObject::Ptr added;
66 IObject::Ptr removed;
67 {
68 std::unique_lock lock(mutex_);
69 if (replaceWith && !IsCompatible(replaceWith)) {
70 return false;
71 }
72 auto it = children_.begin();
73 for (; it != children_.end() && *it != child; ++it, ++index) {
74 }
75 if (it != children_.end()) {
76 removed = *it;
77 if (removed == replaceWith) {
78 return removed != nullptr;
79 }
80 if (replaceWith) {
81 *it = replaceWith;
82 added = replaceWith;
83 } else {
84 children_.erase(it);
85 }
86 } else if (addAlways && replaceWith) {
87 children_.push_back(replaceWith);
88 added = replaceWith;
89 }
90 }
91 ChildChangedInfo addedInfo { ContainerChangeType::ADDED, added, parent_, size_t(-1), index };
92 ChildChangedInfo removedInfo { ContainerChangeType::REMOVED, removed, parent_, index };
93 if (removed) {
94 SetObjectParent(removed, nullptr);
95 Invoke<IOnChildChanged>(EventOnContainerChanged(MetadataQuery::EXISTING), removedInfo);
96 }
97 if (added) {
98 SetObjectParent(added, interface_pointer_cast<IObject>(parent_));
99 Invoke<IOnChildChanged>(EventOnContainerChanged(MetadataQuery::EXISTING), addedInfo);
100 }
101 return added || removed;
102 }
103
SetObjectParent(const IObject::Ptr & object,const IObject::Ptr & parent) const104 void FlatContainer::SetObjectParent(const IObject::Ptr& object, const IObject::Ptr& parent) const
105 {
106 const auto set = interface_cast<IMutableContainable>(object);
107 if (!set) {
108 // Object does not support setting a parent
109 return;
110 }
111 if (const auto cont = interface_cast<IContainable>(object)) {
112 // Remove from old parent (if any)
113 if (const auto old = interface_pointer_cast<IContainer>(cont->GetParent())) {
114 if (old == interface_pointer_cast<IContainer>(parent)) {
115 // The object is already a child of the new parent container
116 return;
117 }
118 old->Remove(object);
119 }
120 }
121 if (!parent) {
122 for (auto&& c : children_) {
123 // we have another, don't remove the parent
124 if (c == object) {
125 return;
126 }
127 }
128 }
129 set->SetParent(parent);
130 }
131
EventOnContainerChanged(MetadataQuery q) const132 BASE_NS::shared_ptr<IEvent> FlatContainer::EventOnContainerChanged(MetadataQuery q) const
133 {
134 std::unique_lock lock(this->mutex_);
135 if (!onChanged_ && q == MetadataQuery::CONSTRUCT_ON_REQUEST) {
136 onChanged_ = { CreateShared<EventImpl<IOnChildChanged>>("OnContainerChanged") };
137 }
138 return onChanged_;
139 }
140
141 META_END_NAMESPACE()
142