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