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 "container_base.h" 16 17#include <algorithm> 18 19#include <base/math/mathf.h> 20 21#include <meta/api/iteration.h> 22#include <meta/base/interface_utils.h> 23#include <meta/interface/intf_containable.h> 24 25META_BEGIN_NAMESPACE() 26 27void ContainerBase::SetImplementingIContainer(IObject* me, IContainer* c) 28{ 29 me_ = me; 30 impl_ = c; 31 CORE_ASSERT(impl_); 32 implPreTrans_ = interface_cast<IContainerPreTransaction>(impl_); 33 CORE_ASSERT(implPreTrans_); 34} 35 36void ContainerBase::LockShared() const 37{ 38 mutex_.lock_shared(); 39} 40 41void ContainerBase::UnlockShared() const 42{ 43 mutex_.unlock_shared(); 44} 45 46void ContainerBase::Lock() const 47{ 48 mutex_.lock(); 49} 50 51void ContainerBase::Unlock() const 52{ 53 mutex_.unlock(); 54} 55 56bool ContainerBase::SetProxyParent(const IContainer::Ptr& parent) 57{ 58 parent_ = parent; 59 return true; 60} 61 62IObject::Ptr ContainerBase::FindAnyImpl(const IContainer::FindOptions& options, bool isFlat) const 63{ 64 IObject::Ptr res; 65 ConstIterate( 66 GetSelf(impl_), 67 [&](const IObject::Ptr& obj) { 68 if (MatchCriteria(options, obj)) { 69 res = obj; 70 } 71 return !res; 72 }, 73 IterateStrategy { isFlat ? TraversalType::NO_HIERARCHY : options.behavior, LockType::SHARED_LOCK }); 74 return res; 75} 76 77BASE_NS::vector<IObject::Ptr> ContainerBase::FindAllImpl(const IContainer::FindOptions& options, bool isFlat) const 78{ 79 BASE_NS::vector<IObject::Ptr> res; 80 ConstIterate( 81 GetSelf(impl_), 82 [&](const IObject::Ptr& obj) { 83 if (options.name.empty() || obj->GetName() == options.name) { 84 if (CheckInterfaces(obj, options.uids, options.strict)) { 85 res.push_back(obj); 86 } 87 } 88 return true; 89 }, 90 IterateStrategy { isFlat ? TraversalType::NO_HIERARCHY : options.behavior, LockType::SHARED_LOCK }); 91 return res; 92} 93 94BASE_NS::vector<IObject::Ptr> ContainerBase::GetAll() const 95{ 96 std::shared_lock lock(mutex_); 97 return children_; 98} 99 100IObject::Ptr ContainerBase::GetAt(SizeType index) const 101{ 102 std::shared_lock lock(mutex_); 103 if (index >= children_.size()) { 104 return {}; 105 } 106 return children_[index]; 107} 108 109IContainer::SizeType ContainerBase::GetSize() const 110{ 111 std::shared_lock lock(mutex_); 112 return children_.size(); 113} 114 115IObject::Ptr ContainerBase::FindByName(BASE_NS::string_view name) const 116{ 117 std::shared_lock lock(mutex_); 118 for (const auto& child : children_) { 119 if (child->GetName() == name) { 120 return child; 121 } 122 } 123 return {}; 124} 125 126bool ContainerBase::MatchCriteria(const IContainer::FindOptions& options, const IObject::Ptr& object) const 127{ 128 return object && (options.name.empty() || object->GetName() == options.name) && 129 CheckInterfaces(object, options.uids, options.strict); 130} 131 132bool ContainerBase::Remove(SizeType index) 133{ 134 IObject::Ptr child; 135 const auto direct = !implPreTrans_->OnRemoving()->HasHandlers(); 136 { 137 std::unique_lock lock(mutex_); 138 if (children_.size() <= index) { 139 return false; 140 } 141 auto it = children_.begin() + index; 142 child = *it; 143 if (direct) { 144 children_.erase(it); 145 } 146 } 147 bool success = true; 148 ChildChangedInfo info { child, index, parent_ }; 149 if (!direct) { 150 Invoke<IOnChildChanging>(implPreTrans_->OnRemoving(), info, success); 151 if (success) { 152 std::unique_lock lock(mutex_); 153 children_.erase(children_.begin() + index); 154 } 155 } 156 if (success) { 157 SetObjectParent(child, nullptr); 158 Invoke<IOnChildChanged>(impl_->OnRemoved(), info); 159 } 160 return success; 161} 162 163bool ContainerBase::Remove(const IObject::Ptr& child) 164{ 165 if (!child) { 166 return false; 167 } 168 const auto direct = !implPreTrans_->OnRemoving()->HasHandlers(); 169 bool success = false; 170 SizeType index = 0; 171 { 172 std::unique_lock lock(mutex_); 173 for (auto it = children_.cbegin(); it != children_.cend(); ++it) { 174 if (*it == child) { 175 success = true; 176 if (direct) { 177 children_.erase(children_.begin() + index); 178 } 179 break; 180 } 181 index++; 182 } 183 } 184 if (!success) { 185 return false; 186 } 187 ChildChangedInfo info { child, index, parent_ }; 188 if (!direct) { 189 Invoke<IOnChildChanging>(implPreTrans_->OnRemoving(), info, success); 190 if (success) { 191 std::unique_lock lock(mutex_); 192 children_.erase(children_.begin() + index); 193 } 194 } 195 if (success) { 196 SetObjectParent(child, nullptr); 197 Invoke<IOnChildChanged>(impl_->OnRemoved(), info); 198 } 199 return success; 200} 201 202ChildMovedInfo ContainerBase::MoveInternal(SizeType fromIndex, SizeType toIndex) 203{ 204 if (children_.empty()) { 205 return {}; 206 } 207 const auto size = children_.size(); 208 fromIndex = BASE_NS::Math::min(fromIndex, size - 1); 209 toIndex = BASE_NS::Math::min(toIndex, size - 1); 210 const IObject::Ptr child = children_[fromIndex]; 211 if (fromIndex == toIndex) { 212 return { child, 0, 0 }; 213 } 214 if (fromIndex > toIndex) { 215 const auto first = children_.rbegin() + (size - fromIndex - 1); 216 const auto last = children_.rbegin() + (size - toIndex); 217 std::rotate(first, first + 1, last); 218 } else { 219 const auto first = children_.begin() + fromIndex; 220 const auto last = children_.begin() + toIndex + 1; 221 std::rotate(first, first + 1, last); 222 } 223 return { child, fromIndex, toIndex, parent_ }; 224} 225 226bool ContainerBase::Move(SizeType fromIndex, SizeType toIndex) 227{ 228 ChildMovedInfo info; 229 { 230 std::unique_lock lock(mutex_); 231 info = MoveInternal(fromIndex, toIndex); 232 } 233 if (info.object) { 234 if (info.from != info.to) { 235 Invoke<IOnChildMoved>(impl_->OnMoved(), BASE_NS::move(info)); 236 } 237 return true; 238 } 239 return false; 240} 241 242bool ContainerBase::Move(const IObject::Ptr& child, SizeType toIndex) 243{ 244 ChildMovedInfo info; 245 { 246 std::unique_lock lock(mutex_); 247 SizeType fromIndex = 0; 248 for (const auto& c : children_) { 249 if (c == child) { 250 info = MoveInternal(fromIndex, toIndex); 251 break; 252 } 253 fromIndex++; 254 } 255 } 256 if (info.object) { 257 if (info.from != info.to) { 258 Invoke<IOnChildMoved>(impl_->OnMoved(), BASE_NS::move(info)); 259 } 260 return true; 261 } 262 return false; 263} 264 265void ContainerBase::RemoveAll() 266{ 267 BASE_NS::vector<IObject::Ptr> children; 268 { 269 std::unique_lock lock(mutex_); 270 children_.swap(children); 271 } 272 273 SizeType index = 0; 274 for (const auto& child : children) { 275 ChildChangedInfo info { child, index++, parent_ }; 276 bool success = true; 277 Invoke<IOnChildChanging>(implPreTrans_->OnRemoving(), info, success); // Ignore result 278 if (!success) { 279 CORE_LOG_E("Failing a remove transaction during remove all operation is not supported"); 280 } 281 SetObjectParent(child, nullptr); 282 Invoke<IOnChildChanged>(impl_->OnRemoved(), info); 283 } 284} 285 286void ContainerBase::InternalRemoveAll() 287{ 288 BASE_NS::vector<IObject::Ptr> children; 289 { 290 std::unique_lock lock(mutex_); 291 children_.swap(children); 292 } 293 for (const auto& child : children) { 294 if (auto c = interface_cast<IMutableContainable>(child)) { 295 c->SetParent(nullptr); 296 } 297 } 298} 299 300bool ContainerBase::SetRequiredInterfaces(const BASE_NS::vector<TypeId>& interfaces) 301{ 302 std::unique_lock lock(mutex_); 303 required_ = interfaces; 304 305 BASE_NS::vector<IObject::Ptr> compatible; 306 compatible.reserve(children_.size()); 307 for (const auto& child : children_) { 308 if (IsCompatible(child)) { 309 compatible.push_back(child); 310 } 311 } 312 children_.swap(compatible); 313 return true; 314} 315 316BASE_NS::vector<TypeId> ContainerBase::GetRequiredInterfaces() const 317{ 318 std::shared_lock lock(mutex_); 319 return required_; 320} 321 322bool ContainerBase::IsCompatible(const IObject::Ptr& object) const 323{ 324 return ObjectImplementsAll(object, required_); 325} 326 327bool ContainerBase::IsAncestorOf(const IObject::ConstPtr& object) const 328{ 329 if (!object || !me_) { 330 return false; 331 } 332 if (me_ == object.get()) { 333 return true; 334 } 335 const auto containable = interface_pointer_cast<IContainable>(object); 336 if (!containable) { 337 return false; 338 } 339 auto parent = containable->GetParent(); 340 while (parent) { 341 if (parent.get() == me_) { 342 return true; 343 } 344 if (auto parentContainable = interface_cast<IContainable>(parent)) { 345 parent = parentContainable->GetParent(); 346 } else { 347 break; 348 } 349 } 350 return false; 351} 352 353BASE_NS::shared_ptr<IEvent> ContainerBase::EventOnAdded() const 354{ 355 return impl_->OnAdded(); 356} 357 358BASE_NS::shared_ptr<IEvent> ContainerBase::EventOnRemoved() const 359{ 360 return impl_->OnRemoved(); 361} 362 363BASE_NS::shared_ptr<IEvent> ContainerBase::EventOnMoved() const 364{ 365 return impl_->OnMoved(); 366} 367 368BASE_NS::shared_ptr<IEvent> ContainerBase::EventOnAdding() const 369{ 370 return implPreTrans_->OnAdding(); 371} 372 373BASE_NS::shared_ptr<IEvent> ContainerBase::EventOnRemoving() const 374{ 375 return implPreTrans_->OnRemoving(); 376} 377 378template<typename Cont, typename Func> 379static IterationResult IterateImpl(Cont& cont, const Func& func) 380{ 381 for (auto&& child : cont) { 382 auto res = func->Invoke(child); 383 if (!res.Continue()) { 384 return res; 385 } 386 } 387 return IterationResult::CONTINUE; 388} 389 390IterationResult ContainerBase::Iterate(const IterationParameters& params) 391{ 392 auto f = params.function.GetInterface<IIterableCallable<IObject::Ptr>>(); 393 if (!f) { 394 CORE_LOG_W("Incompatible function with Iterate"); 395 return IterationResult::FAILED; 396 } 397 return IterateImpl(children_, f); 398} 399 400IterationResult ContainerBase::Iterate(const IterationParameters& params) const 401{ 402 auto f = params.function.GetInterface<IIterableConstCallable<IObject::Ptr>>(); 403 if (!f) { 404 CORE_LOG_W("Incompatible function with Iterate"); 405 return IterationResult::FAILED; 406 } 407 return IterateImpl(children_, f); 408} 409 410META_END_NAMESPACE() 411