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 "flat_container.h"
16
17 #include <algorithm>
18
19 #include <base/math/mathf.h>
20
21 #include <meta/api/internal/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 IObject::Ptr FlatContainer::FindAny(const IContainer::FindOptions& options) const
28 {
29 return ContainerBase::FindAnyImpl(options, true);
30 }
31
FindAll(const IContainer::FindOptions & options) const32 BASE_NS::vector<IObject::Ptr> FlatContainer::FindAll(const IContainer::FindOptions& options) const
33 {
34 return ContainerBase::FindAllImpl(options, true);
35 }
36
Add(const IObject::Ptr & object)37 bool FlatContainer::Add(const IObject::Ptr& object)
38 {
39 if (!object) {
40 return false;
41 }
42 const auto direct = !OnAdding()->HasHandlers();
43 SizeType index = 0;
44 {
45 std::unique_lock lock(mutex_);
46 if (!IsCompatible(object)) {
47 return false;
48 }
49 index = children_.size();
50 if (direct) {
51 children_.push_back(object);
52 }
53 }
54 bool success = true;
55 ChildChangedInfo info { object, index, parent_ };
56 if (!direct) {
57 Invoke<IOnChildChanging>(OnAdding(), info, success);
58 if (success) {
59 std::unique_lock lock(mutex_);
60 children_.push_back(object);
61 }
62 }
63 // Calling external interface methods outside of our internal lock
64 if (success) {
65 SetObjectParent(object, interface_pointer_cast<IObject>(parent_));
66 Invoke<IOnChildChanged>(OnAdded(), info);
67 }
68 return success;
69 }
70
Insert(SizeType index,const IObject::Ptr & object)71 bool FlatContainer::Insert(SizeType index, const IObject::Ptr& object)
72 {
73 if (!object) {
74 return false;
75 }
76 const auto direct = !OnAdding()->HasHandlers();
77 {
78 std::unique_lock lock(mutex_);
79 if (!IsCompatible(object)) {
80 return false;
81 }
82 index = BASE_NS::Math::min(index, children_.size());
83 if (direct) {
84 children_.insert(children_.begin() + index, object);
85 }
86 }
87 bool success = true;
88 ChildChangedInfo info { object, index, parent_ };
89 if (!direct) {
90 Invoke<IOnChildChanging>(OnAdding(), info, success);
91 if (success) {
92 std::unique_lock lock(mutex_);
93 children_.insert(children_.begin() + index, object);
94 }
95 }
96 // Calling external interface methods outside of our internal lock
97 if (success) {
98 SetObjectParent(object, interface_pointer_cast<IObject>(parent_));
99 Invoke<IOnChildChanged>(OnAdded(), ChildChangedInfo { object, index, parent_ });
100 }
101 return success;
102 }
103
Replace(const IObject::Ptr & child,const IObject::Ptr & replaceWith,bool addAlways)104 bool FlatContainer::Replace(const IObject::Ptr& child, const IObject::Ptr& replaceWith, bool addAlways)
105 {
106 SizeType index = 0;
107 IObject::Ptr added;
108 IObject::Ptr removed;
109 {
110 std::unique_lock lock(mutex_);
111 if (replaceWith && !IsCompatible(replaceWith)) {
112 return false;
113 }
114 for (auto&& v : children_) {
115 if (child == v) {
116 break;
117 }
118 ++index;
119 }
120 if (index < children_.size()) {
121 removed = children_[index];
122 if (removed == replaceWith) {
123 return removed != nullptr;
124 }
125 if (replaceWith) {
126 children_[index] = replaceWith;
127 added = replaceWith;
128 } else {
129 children_.erase(children_.begin() + index);
130 }
131 } else if (addAlways && replaceWith) {
132 children_.push_back(replaceWith);
133 added = replaceWith;
134 }
135 }
136 ChildChangedInfo addedInfo { added, index, parent_ };
137 ChildChangedInfo removedInfo { removed, index, parent_ };
138 bool success = true;
139 if (removed) {
140 Invoke<IOnChildChanging>(OnRemoving(), removedInfo, success);
141 if (!success) {
142 CORE_LOG_E("Failing a remove transaction during replace operation is not supported");
143 success = true;
144 }
145 }
146 if (added) {
147 Invoke<IOnChildChanging>(OnAdding(), addedInfo, success);
148 if (!success) {
149 CORE_LOG_E("Failing an add transaction during replace operation is not supported");
150 }
151 }
152 if (removed) {
153 SetObjectParent(removed, nullptr);
154 Invoke<IOnChildChanged>(OnRemoved(), removedInfo);
155 }
156 if (added) {
157 SetObjectParent(added, interface_pointer_cast<IObject>(parent_));
158 Invoke<IOnChildChanged>(OnAdded(), addedInfo);
159 }
160 return added || removed;
161 }
162
SetObjectParent(const IObject::Ptr & object,const IObject::Ptr & parent) const163 void FlatContainer::SetObjectParent(const IObject::Ptr& object, const IObject::Ptr& parent) const
164 {
165 const auto set = interface_cast<IMutableContainable>(object);
166 if (!set) {
167 // Object does not support setting a parent
168 return;
169 }
170 if (const auto cont = interface_cast<IContainable>(object)) {
171 // Remove from old parent (if any)
172 if (const auto old = interface_pointer_cast<IContainer>(cont->GetParent())) {
173 if (old == interface_pointer_cast<IContainer>(parent)) {
174 // The object is already a child of the new parent container
175 return;
176 }
177 old->Remove(object);
178 }
179 }
180 if (!parent) {
181 for (auto&& c : children_) {
182 // we have another, don't remove the parent
183 if (c == object) {
184 return;
185 }
186 }
187 }
188 set->SetParent(parent);
189 }
190
191 META_END_NAMESPACE()
192