* Copyright (c) 2024 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "flat_container.h"
#include <algorithm>
#include <mutex>
#include <base/math/mathf.h>
#include <meta/api/internal/iteration.h>
#include <meta/base/interface_utils.h>
#include <meta/interface/intf_containable.h>
META_BEGIN_NAMESPACE()
IObject::Ptr FlatContainer::FindAny(const IContainer::FindOptions& options) const
{
return ContainerBase::FindAnyImpl(options, true);
}
BASE_NS::vector<IObject::Ptr> FlatContainer::FindAll(const IContainer::FindOptions& options) const
{
return ContainerBase::FindAllImpl(options, true);
}
bool FlatContainer::Add(const META_NS::IObject::Ptr& object)
{
return Insert(-1, object);
}
bool FlatContainer::Insert(SizeType index, const IObject::Ptr& object)
{
if (!object) {
return false;
}
{
std::unique_lock lock(mutex_);
if (!IsCompatible(object)) {
return false;
}
index = BASE_NS::Math::min(index, children_.size());
children_.insert(children_.begin() + index, object);
}
ChildChangedInfo info{ContainerChangeType::ADDED, object, parent_, size_t(-1), index};
SetObjectParent(object, interface_pointer_cast<IObject>(parent_));
Invoke<IOnChildChanged>(EventOnContainerChanged(MetadataQuery::EXISTING), info);
return true;
}
bool FlatContainer::Replace(const IObject::Ptr& child, const IObject::Ptr& replaceWith, bool addAlways)
{
SizeType index = 0;
IObject::Ptr added;
IObject::Ptr removed;
{
std::unique_lock lock(mutex_);
if (replaceWith && !IsCompatible(replaceWith)) {
return false;
}
auto it = children_.begin();
for (; it != children_.end() && *it != child; ++it, ++index) {
}
if (it != children_.end()) {
removed = *it;
if (removed == replaceWith) {
return removed != nullptr;
}
if (replaceWith) {
*it = replaceWith;
added = replaceWith;
} else {
children_.erase(it);
}
} else if (addAlways && replaceWith) {
children_.push_back(replaceWith);
added = replaceWith;
}
}
ChildChangedInfo addedInfo{ContainerChangeType::ADDED, added, parent_, size_t(-1), index};
ChildChangedInfo removedInfo{ContainerChangeType::REMOVED, removed, parent_, index};
if (removed) {
SetObjectParent(removed, nullptr);
Invoke<IOnChildChanged>(EventOnContainerChanged(MetadataQuery::EXISTING), removedInfo);
}
if (added) {
SetObjectParent(added, interface_pointer_cast<IObject>(parent_));
Invoke<IOnChildChanged>(EventOnContainerChanged(MetadataQuery::EXISTING), addedInfo);
}
return added || removed;
}
void FlatContainer::SetObjectParent(const IObject::Ptr& object, const IObject::Ptr& parent) const
{
const auto set = interface_cast<IMutableContainable>(object);
if (!set) {
return;
}
if (const auto cont = interface_cast<IContainable>(object)) {
if (const auto old = interface_pointer_cast<IContainer>(cont->GetParent())) {
if (old == interface_pointer_cast<IContainer>(parent)) {
return;
}
old->Remove(object);
}
}
if (!parent) {
for (auto&& c : children_) {
if (c == object) {
return;
}
}
}
set->SetParent(parent);
}
BASE_NS::shared_ptr<IEvent> FlatContainer::EventOnContainerChanged(MetadataQuery q) const
{
std::unique_lock lock(this->mutex_);
if (!onChanged_ && q == MetadataQuery::CONSTRUCT_ON_REQUEST) {
onChanged_ = {CreateShared<EventImpl<IOnChildChanged>>("OnContainerChanged")};
}
return onChanged_;
}
META_END_NAMESPACE()