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 25META_BEGIN_NAMESPACE() 26 27IObject::Ptr FlatContainer::FindAny(const IContainer::FindOptions& options) const 28{ 29 return ContainerBase::FindAnyImpl(options, true); 30} 31 32BASE_NS::vector<IObject::Ptr> FlatContainer::FindAll(const IContainer::FindOptions& options) const 33{ 34 return ContainerBase::FindAllImpl(options, true); 35} 36 37bool 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 71bool 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 104bool 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 163void 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 191META_END_NAMESPACE() 192