18bf80f4bSopenharmony_ci/* 28bf80f4bSopenharmony_ci * Copyright (c) 2024 Huawei Device Co., Ltd. 38bf80f4bSopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License"); 48bf80f4bSopenharmony_ci * you may not use this file except in compliance with the License. 58bf80f4bSopenharmony_ci * You may obtain a copy of the License at 68bf80f4bSopenharmony_ci * 78bf80f4bSopenharmony_ci * http://www.apache.org/licenses/LICENSE-2.0 88bf80f4bSopenharmony_ci * 98bf80f4bSopenharmony_ci * Unless required by applicable law or agreed to in writing, software 108bf80f4bSopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS, 118bf80f4bSopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 128bf80f4bSopenharmony_ci * See the License for the specific language governing permissions and 138bf80f4bSopenharmony_ci * limitations under the License. 148bf80f4bSopenharmony_ci */ 158bf80f4bSopenharmony_ci 168bf80f4bSopenharmony_ci#include "container.h" 178bf80f4bSopenharmony_ci 188bf80f4bSopenharmony_ci#include <algorithm> 198bf80f4bSopenharmony_ci 208bf80f4bSopenharmony_ci#include <base/math/mathf.h> 218bf80f4bSopenharmony_ci 228bf80f4bSopenharmony_ci#include <meta/base/interface_utils.h> 238bf80f4bSopenharmony_ci#include <meta/interface/intf_containable.h> 248bf80f4bSopenharmony_ci#include <meta/interface/intf_content.h> 258bf80f4bSopenharmony_ci#include <meta/interface/property/intf_property.h> 268bf80f4bSopenharmony_ci 278bf80f4bSopenharmony_ciMETA_BEGIN_NAMESPACE() 288bf80f4bSopenharmony_ci 298bf80f4bSopenharmony_ciIObject::Ptr Container::FindAny(const META_NS::IContainer::FindOptions& options) const 308bf80f4bSopenharmony_ci{ 318bf80f4bSopenharmony_ci return ContainerBase::FindAnyImpl(options, false); 328bf80f4bSopenharmony_ci} 338bf80f4bSopenharmony_ci 348bf80f4bSopenharmony_ciBASE_NS::vector<IObject::Ptr> Container::FindAll(const META_NS::IContainer::FindOptions& options) const 358bf80f4bSopenharmony_ci{ 368bf80f4bSopenharmony_ci return ContainerBase::FindAllImpl(options, false); 378bf80f4bSopenharmony_ci} 388bf80f4bSopenharmony_ci 398bf80f4bSopenharmony_cibool Container::Add(const META_NS::IObject::Ptr& object) 408bf80f4bSopenharmony_ci{ 418bf80f4bSopenharmony_ci if (!object) { 428bf80f4bSopenharmony_ci return false; 438bf80f4bSopenharmony_ci } 448bf80f4bSopenharmony_ci const auto direct = !OnAdding()->HasHandlers(); 458bf80f4bSopenharmony_ci SizeType index; 468bf80f4bSopenharmony_ci { 478bf80f4bSopenharmony_ci std::unique_lock lock(mutex_); 488bf80f4bSopenharmony_ci if (!IsCompatible(object) || !CheckLoop(object)) { 498bf80f4bSopenharmony_ci return false; 508bf80f4bSopenharmony_ci } 518bf80f4bSopenharmony_ci for (const auto& child : children_) { 528bf80f4bSopenharmony_ci if (child == object) { 538bf80f4bSopenharmony_ci return true; // Already a child of ours 548bf80f4bSopenharmony_ci } 558bf80f4bSopenharmony_ci } 568bf80f4bSopenharmony_ci index = children_.size(); 578bf80f4bSopenharmony_ci if (direct) { 588bf80f4bSopenharmony_ci children_.push_back(object); 598bf80f4bSopenharmony_ci } 608bf80f4bSopenharmony_ci } 618bf80f4bSopenharmony_ci // Calling external interface methods outside of our internal lock 628bf80f4bSopenharmony_ci bool success = true; 638bf80f4bSopenharmony_ci ChildChangedInfo info { object, index, parent_ }; 648bf80f4bSopenharmony_ci if (!direct) { 658bf80f4bSopenharmony_ci Invoke<IOnChildChanging>(OnAdding(), info, success); 668bf80f4bSopenharmony_ci if (success) { 678bf80f4bSopenharmony_ci std::unique_lock lock(mutex_); 688bf80f4bSopenharmony_ci children_.push_back(object); 698bf80f4bSopenharmony_ci } 708bf80f4bSopenharmony_ci } 718bf80f4bSopenharmony_ci if (success) { 728bf80f4bSopenharmony_ci SetObjectParent(object, interface_pointer_cast<IObject>(parent_)); 738bf80f4bSopenharmony_ci Invoke<IOnChildChanged>(OnAdded(), info); 748bf80f4bSopenharmony_ci } 758bf80f4bSopenharmony_ci return success; 768bf80f4bSopenharmony_ci} 778bf80f4bSopenharmony_ci 788bf80f4bSopenharmony_cibool Container::Insert(SizeType index, const IObject::Ptr& object) 798bf80f4bSopenharmony_ci{ 808bf80f4bSopenharmony_ci if (!object) { 818bf80f4bSopenharmony_ci return false; 828bf80f4bSopenharmony_ci } 838bf80f4bSopenharmony_ci const auto direct = !OnAdding()->HasHandlers(); 848bf80f4bSopenharmony_ci { 858bf80f4bSopenharmony_ci std::unique_lock lock(mutex_); 868bf80f4bSopenharmony_ci if (!IsCompatible(object) || !CheckLoop(object)) { 878bf80f4bSopenharmony_ci return false; 888bf80f4bSopenharmony_ci } 898bf80f4bSopenharmony_ci for (auto it = children_.begin(); it != children_.end(); ++it) { 908bf80f4bSopenharmony_ci if (*it == object) { 918bf80f4bSopenharmony_ci // Already in the container, remove from current position 928bf80f4bSopenharmony_ci children_.erase(it); 938bf80f4bSopenharmony_ci break; 948bf80f4bSopenharmony_ci } 958bf80f4bSopenharmony_ci } 968bf80f4bSopenharmony_ci index = BASE_NS::Math::min(index, children_.size()); 978bf80f4bSopenharmony_ci if (direct) { 988bf80f4bSopenharmony_ci children_.insert(children_.begin() + index, object); 998bf80f4bSopenharmony_ci } 1008bf80f4bSopenharmony_ci } 1018bf80f4bSopenharmony_ci // Calling external interface methods outside of our internal lock 1028bf80f4bSopenharmony_ci bool success = true; 1038bf80f4bSopenharmony_ci ChildChangedInfo info { object, index, parent_ }; 1048bf80f4bSopenharmony_ci if (!direct) { 1058bf80f4bSopenharmony_ci Invoke<IOnChildChanging>(OnAdding(), info, success); 1068bf80f4bSopenharmony_ci if (success) { 1078bf80f4bSopenharmony_ci std::unique_lock lock(mutex_); 1088bf80f4bSopenharmony_ci children_.insert(children_.begin() + index, object); 1098bf80f4bSopenharmony_ci } 1108bf80f4bSopenharmony_ci } 1118bf80f4bSopenharmony_ci if (success) { 1128bf80f4bSopenharmony_ci SetObjectParent(object, interface_pointer_cast<IObject>(parent_)); 1138bf80f4bSopenharmony_ci Invoke<IOnChildChanged>(OnAdded(), info); 1148bf80f4bSopenharmony_ci } 1158bf80f4bSopenharmony_ci return success; 1168bf80f4bSopenharmony_ci} 1178bf80f4bSopenharmony_ci 1188bf80f4bSopenharmony_cibool Container::Replace(const META_NS::IObject::Ptr& child, const META_NS::IObject::Ptr& replaceWith, bool addAlways) 1198bf80f4bSopenharmony_ci{ 1208bf80f4bSopenharmony_ci IObject::Ptr removed; 1218bf80f4bSopenharmony_ci IObject::Ptr added; 1228bf80f4bSopenharmony_ci IObject::Ptr moved; 1238bf80f4bSopenharmony_ci IContainer::SizeType fromIndex = 0; 1248bf80f4bSopenharmony_ci IContainer::SizeType toIndex = 0; 1258bf80f4bSopenharmony_ci bool changed = false; // True if any changes were made 1268bf80f4bSopenharmony_ci { 1278bf80f4bSopenharmony_ci std::unique_lock lock(mutex_); 1288bf80f4bSopenharmony_ci if (replaceWith && (!IsCompatible(replaceWith) || !CheckLoop(replaceWith))) { 1298bf80f4bSopenharmony_ci return false; 1308bf80f4bSopenharmony_ci } 1318bf80f4bSopenharmony_ci auto removedIt = children_.end(); 1328bf80f4bSopenharmony_ci auto movedIt = children_.end(); 1338bf80f4bSopenharmony_ci SizeType index = 0; 1348bf80f4bSopenharmony_ci // Check if 'child' and 'replaceWith' can already be found from the container 1358bf80f4bSopenharmony_ci for (auto it = children_.begin(); it != children_.end(); ++it, ++index) { 1368bf80f4bSopenharmony_ci if (*it == child) { 1378bf80f4bSopenharmony_ci removedIt = it; 1388bf80f4bSopenharmony_ci removed = *it; 1398bf80f4bSopenharmony_ci toIndex = index; 1408bf80f4bSopenharmony_ci } 1418bf80f4bSopenharmony_ci if (*it == replaceWith) { 1428bf80f4bSopenharmony_ci movedIt = it; 1438bf80f4bSopenharmony_ci moved = *it; 1448bf80f4bSopenharmony_ci fromIndex = index; 1458bf80f4bSopenharmony_ci } 1468bf80f4bSopenharmony_ci if (removed && moved) { 1478bf80f4bSopenharmony_ci break; 1488bf80f4bSopenharmony_ci } 1498bf80f4bSopenharmony_ci } 1508bf80f4bSopenharmony_ci if (removed && removed == moved) { 1518bf80f4bSopenharmony_ci // 'child' and 'replaceWith' are the same item (which is already in the container) 1528bf80f4bSopenharmony_ci return true; 1538bf80f4bSopenharmony_ci } 1548bf80f4bSopenharmony_ci if (removed) { 1558bf80f4bSopenharmony_ci // 'child' was found 1568bf80f4bSopenharmony_ci if (replaceWith) { 1578bf80f4bSopenharmony_ci *removedIt = replaceWith; 1588bf80f4bSopenharmony_ci if (moved) { 1598bf80f4bSopenharmony_ci // 'replaceWith' was already in the container, remove it from its previous position 1608bf80f4bSopenharmony_ci children_.erase(movedIt); 1618bf80f4bSopenharmony_ci } else { 1628bf80f4bSopenharmony_ci // 'replaceWith' was added 1638bf80f4bSopenharmony_ci added = replaceWith; 1648bf80f4bSopenharmony_ci } 1658bf80f4bSopenharmony_ci } else { 1668bf80f4bSopenharmony_ci // 'replaceWith' == null, remove 'child' 1678bf80f4bSopenharmony_ci children_.erase(removedIt); 1688bf80f4bSopenharmony_ci } 1698bf80f4bSopenharmony_ci changed = true; 1708bf80f4bSopenharmony_ci } else { 1718bf80f4bSopenharmony_ci moved.reset(); 1728bf80f4bSopenharmony_ci } 1738bf80f4bSopenharmony_ci if (!changed && addAlways && replaceWith && movedIt == children_.end()) { 1748bf80f4bSopenharmony_ci // 'child' was not found in container but addAlways is specified with a valid new item which 1758bf80f4bSopenharmony_ci // was not previously in the container, add it 1768bf80f4bSopenharmony_ci toIndex = children_.size(); 1778bf80f4bSopenharmony_ci children_.push_back(replaceWith); 1788bf80f4bSopenharmony_ci added = replaceWith; 1798bf80f4bSopenharmony_ci changed = true; 1808bf80f4bSopenharmony_ci } 1818bf80f4bSopenharmony_ci } 1828bf80f4bSopenharmony_ci if (changed) { 1838bf80f4bSopenharmony_ci // We did some changes to the container 1848bf80f4bSopenharmony_ci ChildChangedInfo addedInfo { added, toIndex, parent_ }; 1858bf80f4bSopenharmony_ci ChildChangedInfo removedInfo { removed, toIndex, parent_ }; 1868bf80f4bSopenharmony_ci bool success = true; 1878bf80f4bSopenharmony_ci // Replace operation does not support 1888bf80f4bSopenharmony_ci if (removed) { 1898bf80f4bSopenharmony_ci Invoke<IOnChildChanging>(OnRemoving(), removedInfo, success); 1908bf80f4bSopenharmony_ci if (!success) { 1918bf80f4bSopenharmony_ci CORE_LOG_E("Failing a remove transaction during replace operation is not supported"); 1928bf80f4bSopenharmony_ci success = true; 1938bf80f4bSopenharmony_ci } 1948bf80f4bSopenharmony_ci } 1958bf80f4bSopenharmony_ci if (added) { 1968bf80f4bSopenharmony_ci Invoke<IOnChildChanging>(OnAdding(), addedInfo, success); 1978bf80f4bSopenharmony_ci if (!success) { 1988bf80f4bSopenharmony_ci CORE_LOG_E("Failing an add transaction during replace operation is not supported"); 1998bf80f4bSopenharmony_ci } 2008bf80f4bSopenharmony_ci } 2018bf80f4bSopenharmony_ci SetObjectParent(removed, nullptr); 2028bf80f4bSopenharmony_ci SetObjectParent(added, interface_pointer_cast<IObject>(parent_)); 2038bf80f4bSopenharmony_ci if (removed) { 2048bf80f4bSopenharmony_ci Invoke<IOnChildChanged>(OnRemoved(), removedInfo); 2058bf80f4bSopenharmony_ci } 2068bf80f4bSopenharmony_ci if (added) { 2078bf80f4bSopenharmony_ci Invoke<IOnChildChanged>(OnAdded(), addedInfo); 2088bf80f4bSopenharmony_ci } 2098bf80f4bSopenharmony_ci if (moved) { 2108bf80f4bSopenharmony_ci Invoke<IOnChildMoved>(OnMoved(), ChildMovedInfo { moved, fromIndex, toIndex, parent_ }); 2118bf80f4bSopenharmony_ci } 2128bf80f4bSopenharmony_ci } 2138bf80f4bSopenharmony_ci return changed; 2148bf80f4bSopenharmony_ci} 2158bf80f4bSopenharmony_ci 2168bf80f4bSopenharmony_civoid Container::SetObjectParent(const IObject::Ptr& object, const IObject::Ptr& parent) const 2178bf80f4bSopenharmony_ci{ 2188bf80f4bSopenharmony_ci const auto set = interface_cast<IMutableContainable>(object); 2198bf80f4bSopenharmony_ci if (!set) { 2208bf80f4bSopenharmony_ci // Object does not support setting a parent 2218bf80f4bSopenharmony_ci return; 2228bf80f4bSopenharmony_ci } 2238bf80f4bSopenharmony_ci if (const auto cont = interface_cast<IContainable>(object)) { 2248bf80f4bSopenharmony_ci // Remove from old parent (if any) 2258bf80f4bSopenharmony_ci if (const auto old = interface_pointer_cast<IContainer>(cont->GetParent())) { 2268bf80f4bSopenharmony_ci if (old == interface_pointer_cast<IContainer>(parent)) { 2278bf80f4bSopenharmony_ci // The object is already a child of the new parent container 2288bf80f4bSopenharmony_ci return; 2298bf80f4bSopenharmony_ci } 2308bf80f4bSopenharmony_ci old->Remove(object); 2318bf80f4bSopenharmony_ci } 2328bf80f4bSopenharmony_ci } 2338bf80f4bSopenharmony_ci set->SetParent(parent); 2348bf80f4bSopenharmony_ci} 2358bf80f4bSopenharmony_ci 2368bf80f4bSopenharmony_cibool Container::CheckLoop(const IObject::Ptr& object) const 2378bf80f4bSopenharmony_ci{ 2388bf80f4bSopenharmony_ci // Check if adding object to "this" would lead to a loop in the hierarchy. 2398bf80f4bSopenharmony_ci // This can only happen if object itself is a container which happens to be 2408bf80f4bSopenharmony_ci // an ancestor of ours. 2418bf80f4bSopenharmony_ci if (const auto cc = interface_cast<const IContainer>(object)) { 2428bf80f4bSopenharmony_ci if (const auto me = interface_cast<IObjectInstance>(impl_)) { 2438bf80f4bSopenharmony_ci if (cc->IsAncestorOf(me->GetSelf())) { 2448bf80f4bSopenharmony_ci CORE_LOG_E("Adding '%s' to '%s' would lead to a loop in the container", object->GetName().c_str(), 2458bf80f4bSopenharmony_ci me->GetName().c_str()); 2468bf80f4bSopenharmony_ci return false; 2478bf80f4bSopenharmony_ci } 2488bf80f4bSopenharmony_ci } 2498bf80f4bSopenharmony_ci } 2508bf80f4bSopenharmony_ci return true; 2518bf80f4bSopenharmony_ci} 2528bf80f4bSopenharmony_ci 2538bf80f4bSopenharmony_ciMETA_END_NAMESPACE() 254