/* * 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. */ #ifndef META_INTERFACE_DETAIL_ANY_H #define META_INTERFACE_DETAIL_ANY_H #include #include #include #include #include META_BEGIN_NAMESPACE() constexpr char BUILTIN_ANY_TAG[] = "BuiltAny"; constexpr char BUILTIN_ARRAY_ANY_TAG[] = "ArrayAny"; template class BaseTypedAny : public IntroduceInterfaces { public: static constexpr TypeId TYPE_ID = UidFromType(); static constexpr bool IS_PTR_TYPE = IsInterfacePtr_v; static constexpr ObjectId StaticGetClassId() { return MakeUid(BUILTIN_ANY_TAG); } ObjectId GetClassId() const override { return StaticGetClassId(); } const BASE_NS::array_view GetCompatibleTypes(CompatibilityDirection dir) const override { if constexpr (IS_PTR_TYPE) { return AnyPC::template GetCompatibleTypes(dir); } static constexpr TypeId uids[] = { TYPE_ID }; return uids; } AnyReturnValue GetData(const TypeId& id, void* data, size_t size) const override { if (IsValidGetArgs(id, data, size)) { if constexpr (IS_PTR_TYPE) { using PCType = AnyPC; using IIType = typename PCType::IIType; auto ret = PCType::GetData(id, data, interface_pointer_cast(InternalGetValue())); if (ret) { return ret; } } *static_cast(data) = InternalGetValue(); return AnyReturn::SUCCESS; } return AnyReturn::INVALID_ARGUMENT; } AnyReturnValue SetData(const TypeId& id, const void* data, size_t size) override { if (IsValidSetArgs(id, data, size)) { if constexpr (IS_PTR_TYPE) { using PCType = AnyPC; typename PCType::IIPtrType p; if (PCType::SetData(id, data, p)) { if (auto ptr = interface_pointer_cast(p); ptr || !p) { return InternalSetValue(ptr); } } } return InternalSetValue(*static_cast(data)); } return AnyReturn::INVALID_ARGUMENT; } AnyReturnValue CopyFrom(const IAny& any) override { if constexpr (IS_PTR_TYPE) { typename AnyPC::IIPtrType p; if (any.GetValue(p)) { if (auto ptr = interface_pointer_cast(p); ptr || !p) { return InternalSetValue(ptr); } } } else { if (META_NS::IsCompatible(any, TYPE_ID, CompatibilityDirection::GET)) { Type value; if (any.GetValue(value)) { return InternalSetValue(value); } } } return AnyReturn::FAIL; } TypeId GetTypeId(TypeIdRole role) const override { if (role == TypeIdRole::ARRAY) { return ArrayUidFromType(); } if (role == TypeIdRole::ITEM) { return ItemUidFromType(); } return TYPE_ID; } TypeId GetTypeId() const { return TYPE_ID; } BASE_NS::string GetTypeIdString() const override { return MetaType::name; } using IAny::SetValue; AnyReturnValue SetValue(const IAny& value) override { return CopyFrom(value); } using IAny::GetValue; const IAny& GetValue() const override { return *this; } bool IsCompatible(const TypeId& id) const override { return META_NS::IsCompatible(*this, id); } protected: virtual AnyReturnValue InternalSetValue(const Type& value) = 0; virtual const Type& InternalGetValue() const = 0; private: static constexpr bool IsValidGetArgs(const TypeId& uid, const void* data, size_t size) { if constexpr (IS_PTR_TYPE) { if (AnyPC::IsValidGetArgs(uid, data, size)) { return true; } } return data && sizeof(Type) == size && uid == TYPE_ID; /*NOLINT(bugprone-sizeof-expression)*/ } static constexpr bool IsValidSetArgs(const TypeId& uid, const void* data, size_t size) { if constexpr (IS_PTR_TYPE) { if (AnyPC::IsValidSetArgs(uid, data, size)) { return true; } } return data && sizeof(Type) == size && uid == TYPE_ID; /*NOLINT(bugprone-sizeof-expression)*/ } }; template> struct DefaultCompare { static constexpr bool Equal(const T& v1, const T& v2) { if constexpr (Compare) { return v1 == v2; } else { return false; } } }; /** * @brief Default IAny implementation which supports a single type. */ template> class Any : public BaseTypedAny { using Super = BaseTypedAny; public: explicit Any(Type v = {}) : value_(BASE_NS::move(v)) {} AnyReturnValue InternalSetValue(const Type& value) override { if (!Compare::Equal(value, value_)) { value_ = value; return AnyReturn::SUCCESS; } return AnyReturn::NOTHING_TO_DO; } const Type& InternalGetValue() const override { return value_; } IAny::Ptr Clone(const AnyCloneOptions& options) const override; IAny::Ptr Clone(bool withValue) const { return Clone({ withValue ? CloneValueType::COPY_VALUE : CloneValueType::DEFAULT_VALUE }); } bool operator==(const Any& other) const noexcept { return (Compare::Equal(other.InternalGetValue(), value_)); } private: Type value_; }; template class BaseTypedArrayAny : public IntroduceInterfaces { public: static constexpr TypeId VECTOR_TYPE_ID = UidFromType>(); static constexpr TypeId ARRAY_TYPE_ID = ArrayUidFromType(); static constexpr TypeId ITEM_TYPE_ID = ItemUidFromType(); static constexpr TypeId TYPE_ID = ARRAY_TYPE_ID; using ItemType = Type; using ArrayType = BASE_NS::vector; static constexpr ObjectId StaticGetClassId() { return MakeUid(BUILTIN_ARRAY_ANY_TAG); } ObjectId GetClassId() const override { return StaticGetClassId(); } const BASE_NS::array_view GetCompatibleTypes(CompatibilityDirection dir) const override { static constexpr TypeId uids[] = { ARRAY_TYPE_ID, VECTOR_TYPE_ID }; return uids; } AnyReturnValue GetData(const TypeId& id, void* data, size_t size) const override { if (IsValidVectorArgs(id, data, size)) { *static_cast(data) = InternalGetValue(); return AnyReturn::SUCCESS; } if (IsValidArrayArgs(id, data)) { auto& value = InternalGetValue(); const auto valueSize = value.size() * sizeof(Type); /*NOLINT(bugprone-sizeof-expression)*/ if (size >= valueSize) { BASE_NS::CloneData(data, size, value.data(), valueSize); return AnyReturn::SUCCESS; } } return AnyReturn::INVALID_ARGUMENT; } AnyReturnValue SetData(const TypeId& id, const void* data, size_t size) override { if (IsValidVectorArgs(id, data, size)) { return InternalSetValue(*static_cast(data)); } if (IsValidArrayArgs(id, data)) { auto p = static_cast(data); return InternalSetValue( BASE_NS::vector(p, p + size / sizeof(Type))); /*NOLINT(bugprone-sizeof-expression)*/ } return AnyReturn::INVALID_ARGUMENT; } AnyReturnValue CopyFrom(const IAny& any) override { if (META_NS::IsCompatible(any, TYPE_ID, CompatibilityDirection::GET)) { ArrayType value; if (any.GetValue(value)) { return InternalSetValue(value); } } return AnyReturn::FAIL; } TypeId GetTypeId(TypeIdRole role) const override { if (role == TypeIdRole::ARRAY) { return ARRAY_TYPE_ID; } if (role == TypeIdRole::ITEM) { return ITEM_TYPE_ID; } return TYPE_ID; } TypeId GetTypeId() const { return TYPE_ID; } BASE_NS::string GetTypeIdString() const override { return MetaType::name; } using IAny::SetValue; AnyReturnValue SetValue(const IAny& value) override { return CopyFrom(value); } using IAny::GetValue; const IAny& GetValue() const override { return *this; } bool IsCompatible(const TypeId& id) const override { return META_NS::IsCompatible(*this, id); } protected: virtual AnyReturnValue InternalSetValue(const ArrayType& value) = 0; virtual const ArrayType& InternalGetValue() const = 0; private: static constexpr bool IsValidVectorArgs(const TypeId& uid, const void* data, size_t size) { return data && sizeof(ArrayType) == size && uid == VECTOR_TYPE_ID; } static constexpr bool IsValidArrayArgs(const TypeId& uid, const void* data) { return data && uid == ARRAY_TYPE_ID; } }; /** * @brief Default IArrayAny implementation which supports a single type. */ template>> class ArrayAny : public BaseTypedArrayAny { using Super = BaseTypedArrayAny; using ArrayType = typename Super::ArrayType; using ItemType = typename Super::ItemType; using Super::ITEM_TYPE_ID; static constexpr auto ITEM_SIZE = sizeof(ItemType); /*NOLINT(bugprone-sizeof-expression)*/ public: explicit constexpr ArrayAny(ArrayType v = {}) : value_(BASE_NS::move(v)) {} explicit constexpr ArrayAny(const BASE_NS::array_view& v) : value_(v.begin(), v.end()) {} #ifdef BASE_VECTOR_HAS_INITIALIZE_LIST constexpr ArrayAny(std::initializer_list v) : value_(ArrayType(v)) {} #endif AnyReturnValue GetDataAt(size_t index, const TypeId& id, void* data, size_t size) const override { if (IsValidItemArgs(id, data, size) && index < GetSize()) { *static_cast(data) = value_[index]; return AnyReturn::SUCCESS; } return AnyReturn::INVALID_ARGUMENT; } AnyReturnValue SetDataAt(size_t index, const TypeId& id, const void* data, size_t size) override { if (IsValidItemArgs(id, data, size) && index < GetSize()) { value_[index] = *static_cast(data); return AnyReturn::SUCCESS; } return AnyReturn::INVALID_ARGUMENT; } AnyReturnValue SetAnyAt(IArrayAny::IndexType index, const IAny& value) override { ItemType v; if (value.GetData(ITEM_TYPE_ID, &v, ITEM_SIZE)) { return SetDataAt(index, ITEM_TYPE_ID, &v, ITEM_SIZE); } return AnyReturn::INVALID_ARGUMENT; } AnyReturnValue GetAnyAt(IArrayAny::IndexType index, IAny& value) const override { ItemType v; if (GetDataAt(index, ITEM_TYPE_ID, &v, ITEM_SIZE)) { return value.SetData(ITEM_TYPE_ID, &v, ITEM_SIZE); } return AnyReturn::INVALID_ARGUMENT; } AnyReturnValue InsertAnyAt(IArrayAny::IndexType index, const IAny& value) override { ItemType v; if (value.GetData(ITEM_TYPE_ID, &v, ITEM_SIZE)) { index = index < value_.size() ? index : value_.size(); value_.insert(value_.begin() + index, v); return AnyReturn::SUCCESS; } return AnyReturn::INVALID_ARGUMENT; } AnyReturnValue RemoveAt(IArrayAny::IndexType index) override { if (index < value_.size()) { value_.erase(value_.begin() + index); return AnyReturn::SUCCESS; } return AnyReturn::INVALID_ARGUMENT; } void RemoveAll() override { value_.clear(); } IArrayAny::IndexType GetSize() const noexcept override { return value_.size(); } IAny::Ptr Clone(const AnyCloneOptions& options) const override; IAny::Ptr Clone(bool withValue) const { return Clone({ withValue ? CloneValueType::COPY_VALUE : CloneValueType::DEFAULT_VALUE }); } const ArrayType& InternalGetValue() const override { return value_; } void PushBack(ItemType item) { value_.push_back(BASE_NS::move(item)); } private: AnyReturnValue InternalSetValue(const ArrayType& value) override { if (!Compare::Equal(value, value_)) { value_ = value; return AnyReturn::SUCCESS; } return AnyReturn::NOTHING_TO_DO; } static constexpr bool IsValidItemArgs(const TypeId& uid, const void* data, size_t size) { return data && ITEM_SIZE == size && uid == Super::ITEM_TYPE_ID; } private: ArrayType value_; }; template IAny::Ptr Any::Clone(const AnyCloneOptions& options) const { if (options.role == TypeIdRole::ARRAY) { return IAny::Ptr(new ArrayAny()); } return IAny::Ptr(new Any { options.value == CloneValueType::COPY_VALUE ? value_ : Type {} }); } template IAny::Ptr ArrayAny::Clone(const AnyCloneOptions& options) const { if (options.role == TypeIdRole::ITEM) { return IAny::Ptr(new Any()); } return IAny::Ptr(new ArrayAny { options.value == CloneValueType::COPY_VALUE ? value_ : ArrayType {} }); } template> static IAny::Ptr ConstructAny(Type v = {}) { return IAny::Ptr { new Any(BASE_NS::move(v)) }; } template>> static IArrayAny::Ptr ConstructArrayAny(BASE_NS::vector v = {}) { return IArrayAny::Ptr { new ArrayAny(BASE_NS::move(v)) }; } META_END_NAMESPACE() #endif