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 #ifndef META_INTERFACE_DETAIL_ANY_H
16 #define META_INTERFACE_DETAIL_ANY_H
17 
18 #include <meta/base/interface_traits.h>
19 #include <meta/interface/detail/any_pointer_compatibility.h>
20 #include <meta/interface/interface_helpers.h>
21 #include <meta/interface/intf_any.h>
22 #include <meta/interface/intf_value.h>
23 
24 META_BEGIN_NAMESPACE()
25 
26 constexpr char BUILTIN_ANY_TAG[] = "BuiltAny";
27 constexpr char BUILTIN_ARRAY_ANY_TAG[] = "ArrayAny";
28 
29 template<typename Type>
30 class BaseTypedAny : public IntroduceInterfaces<IAny, IValue> {
31 public:
32     static constexpr TypeId TYPE_ID = UidFromType<Type>();
33     static constexpr bool IS_PTR_TYPE = IsInterfacePtr_v<Type>;
34 
StaticGetClassId()35     static constexpr ObjectId StaticGetClassId()
36     {
37         return MakeUid<Type>(BUILTIN_ANY_TAG);
38     }
39 
GetClassId()40     ObjectId GetClassId() const override
41     {
42         return StaticGetClassId();
43     }
44 
GetCompatibleTypes(CompatibilityDirection dir)45     const BASE_NS::array_view<const TypeId> GetCompatibleTypes(CompatibilityDirection dir) const override
46     {
47         if constexpr (IS_PTR_TYPE) {
48             return AnyPC<Type>::template GetCompatibleTypes<Type>(dir);
49         }
50 
51         static constexpr TypeId uids[] = { TYPE_ID };
52         return uids;
53     }
GetData(const TypeId & id,void * data,size_t size)54     AnyReturnValue GetData(const TypeId& id, void* data, size_t size) const override
55     {
56         if (IsValidGetArgs(id, data, size)) {
57             if constexpr (IS_PTR_TYPE) {
58                 using PCType = AnyPC<Type>;
59                 using IIType = typename PCType::IIType;
60                 auto ret = PCType::GetData(id, data, interface_pointer_cast<IIType>(InternalGetValue()));
61                 if (ret) {
62                     return ret;
63                 }
64             }
65 
66             *static_cast<Type*>(data) = InternalGetValue();
67             return AnyReturn::SUCCESS;
68         }
69         return AnyReturn::INVALID_ARGUMENT;
70     }
SetData(const TypeId & id,const void * data,size_t size)71     AnyReturnValue SetData(const TypeId& id, const void* data, size_t size) override
72     {
73         if (IsValidSetArgs(id, data, size)) {
74             if constexpr (IS_PTR_TYPE) {
75                 using PCType = AnyPC<Type>;
76                 typename PCType::IIPtrType p;
77                 if (PCType::SetData(id, data, p)) {
78                     if (auto ptr = interface_pointer_cast<typename Type::element_type>(p); ptr || !p) {
79                         return InternalSetValue(ptr);
80                     }
81                 }
82             }
83             return InternalSetValue(*static_cast<const Type*>(data));
84         }
85         return AnyReturn::INVALID_ARGUMENT;
86     }
CopyFrom(const IAny & any)87     AnyReturnValue CopyFrom(const IAny& any) override
88     {
89         if constexpr (IS_PTR_TYPE) {
90             typename AnyPC<Type>::IIPtrType p;
91             if (any.GetValue(p)) {
92                 if (auto ptr = interface_pointer_cast<typename Type::element_type>(p); ptr || !p) {
93                     return InternalSetValue(ptr);
94                 }
95             }
96         } else {
97             if (META_NS::IsCompatible(any, TYPE_ID, CompatibilityDirection::GET)) {
98                 Type value;
99                 if (any.GetValue(value)) {
100                     return InternalSetValue(value);
101                 }
102             }
103         }
104         return AnyReturn::FAIL;
105     }
106 
GetTypeId(TypeIdRole role)107     TypeId GetTypeId(TypeIdRole role) const override
108     {
109         if (role == TypeIdRole::ARRAY) {
110             return ArrayUidFromType<Type>();
111         }
112         if (role == TypeIdRole::ITEM) {
113             return ItemUidFromType<Type>();
114         }
115         return TYPE_ID;
116     }
GetTypeId()117     TypeId GetTypeId() const
118     {
119         return TYPE_ID;
120     }
GetTypeIdString()121     BASE_NS::string GetTypeIdString() const override
122     {
123         return MetaType<Type>::name;
124     }
125     using IAny::SetValue;
SetValue(const IAny & value)126     AnyReturnValue SetValue(const IAny& value) override
127     {
128         return CopyFrom(value);
129     }
130     using IAny::GetValue;
GetValue()131     const IAny& GetValue() const override
132     {
133         return *this;
134     }
IsCompatible(const TypeId & id)135     bool IsCompatible(const TypeId& id) const override
136     {
137         return META_NS::IsCompatible(*this, id);
138     }
139 
140 protected:
141     virtual AnyReturnValue InternalSetValue(const Type& value) = 0;
142     virtual const Type& InternalGetValue() const = 0;
143 
144 private:
IsValidGetArgs(const TypeId & uid,const void * data,size_t size)145     static constexpr bool IsValidGetArgs(const TypeId& uid, const void* data, size_t size)
146     {
147         if constexpr (IS_PTR_TYPE) {
148             if (AnyPC<Type>::IsValidGetArgs(uid, data, size)) {
149                 return true;
150             }
151         }
152         return data && sizeof(Type) == size && uid == TYPE_ID; /*NOLINT(bugprone-sizeof-expression)*/
153     }
IsValidSetArgs(const TypeId & uid,const void * data,size_t size)154     static constexpr bool IsValidSetArgs(const TypeId& uid, const void* data, size_t size)
155     {
156         if constexpr (IS_PTR_TYPE) {
157             if (AnyPC<Type>::IsValidSetArgs(uid, data, size)) {
158                 return true;
159             }
160         }
161         return data && sizeof(Type) == size && uid == TYPE_ID; /*NOLINT(bugprone-sizeof-expression)*/
162     }
163 };
164 
165 template<typename T, bool Compare = HasEqualOperator_v<T>>
166 struct DefaultCompare {
EqualDefaultCompare167     static constexpr bool Equal(const T& v1, const T& v2)
168     {
169         if constexpr (Compare) {
170             return v1 == v2;
171         } else {
172             return false;
173         }
174     }
175 };
176 
177 /**
178  * @brief Default IAny implementation which supports a single type.
179  */
180 template<typename Type, typename Compare = DefaultCompare<Type>>
181 class Any : public BaseTypedAny<Type> {
182     using Super = BaseTypedAny<Type>;
183 
184 public:
185     explicit Any(Type v = {}) : value_(BASE_NS::move(v)) {}
InternalSetValue(const Type & value)186     AnyReturnValue InternalSetValue(const Type& value) override
187     {
188         if (!Compare::Equal(value, value_)) {
189             value_ = value;
190             return AnyReturn::SUCCESS;
191         }
192         return AnyReturn::NOTHING_TO_DO;
193     }
InternalGetValue()194     const Type& InternalGetValue() const override
195     {
196         return value_;
197     }
198     IAny::Ptr Clone(const AnyCloneOptions& options) const override;
Clone(bool withValue)199     IAny::Ptr Clone(bool withValue) const
200     {
201         return Clone({ withValue ? CloneValueType::COPY_VALUE : CloneValueType::DEFAULT_VALUE });
202     }
203 
204     bool operator==(const Any<Type>& other) const noexcept
205     {
206         return (Compare::Equal(other.InternalGetValue(), value_));
207     }
208 
209 private:
210     Type value_;
211 };
212 
213 template<typename Type>
214 class BaseTypedArrayAny : public IntroduceInterfaces<IArrayAny, IValue> {
215 public:
216     static constexpr TypeId VECTOR_TYPE_ID = UidFromType<BASE_NS::vector<Type>>();
217     static constexpr TypeId ARRAY_TYPE_ID = ArrayUidFromType<Type>();
218     static constexpr TypeId ITEM_TYPE_ID = ItemUidFromType<Type>();
219     static constexpr TypeId TYPE_ID = ARRAY_TYPE_ID;
220     using ItemType = Type;
221     using ArrayType = BASE_NS::vector<Type>;
222 
StaticGetClassId()223     static constexpr ObjectId StaticGetClassId()
224     {
225         return MakeUid<Type>(BUILTIN_ARRAY_ANY_TAG);
226     }
227 
GetClassId()228     ObjectId GetClassId() const override
229     {
230         return StaticGetClassId();
231     }
232 
GetCompatibleTypes(CompatibilityDirection dir)233     const BASE_NS::array_view<const TypeId> GetCompatibleTypes(CompatibilityDirection dir) const override
234     {
235         static constexpr TypeId uids[] = { ARRAY_TYPE_ID, VECTOR_TYPE_ID };
236         return uids;
237     }
GetData(const TypeId & id,void * data,size_t size)238     AnyReturnValue GetData(const TypeId& id, void* data, size_t size) const override
239     {
240         if (IsValidVectorArgs(id, data, size)) {
241             *static_cast<ArrayType*>(data) = InternalGetValue();
242             return AnyReturn::SUCCESS;
243         }
244         if (IsValidArrayArgs(id, data)) {
245             auto& value = InternalGetValue();
246             const auto valueSize = value.size() * sizeof(Type); /*NOLINT(bugprone-sizeof-expression)*/
247             if (size >= valueSize) {
248                 BASE_NS::CloneData(data, size, value.data(), valueSize);
249                 return AnyReturn::SUCCESS;
250             }
251         }
252         return AnyReturn::INVALID_ARGUMENT;
253     }
SetData(const TypeId & id,const void * data,size_t size)254     AnyReturnValue SetData(const TypeId& id, const void* data, size_t size) override
255     {
256         if (IsValidVectorArgs(id, data, size)) {
257             return InternalSetValue(*static_cast<const ArrayType*>(data));
258         }
259         if (IsValidArrayArgs(id, data)) {
260             auto p = static_cast<const Type*>(data);
261             return InternalSetValue(
262                 BASE_NS::vector<Type>(p, p + size / sizeof(Type))); /*NOLINT(bugprone-sizeof-expression)*/
263         }
264         return AnyReturn::INVALID_ARGUMENT;
265     }
CopyFrom(const IAny & any)266     AnyReturnValue CopyFrom(const IAny& any) override
267     {
268         if (META_NS::IsCompatible(any, TYPE_ID, CompatibilityDirection::GET)) {
269             ArrayType value;
270             if (any.GetValue(value)) {
271                 return InternalSetValue(value);
272             }
273         }
274         return AnyReturn::FAIL;
275     }
276 
GetTypeId(TypeIdRole role)277     TypeId GetTypeId(TypeIdRole role) const override
278     {
279         if (role == TypeIdRole::ARRAY) {
280             return ARRAY_TYPE_ID;
281         }
282         if (role == TypeIdRole::ITEM) {
283             return ITEM_TYPE_ID;
284         }
285         return TYPE_ID;
286     }
GetTypeId()287     TypeId GetTypeId() const
288     {
289         return TYPE_ID;
290     }
GetTypeIdString()291     BASE_NS::string GetTypeIdString() const override
292     {
293         return MetaType<ArrayType>::name;
294     }
295     using IAny::SetValue;
SetValue(const IAny & value)296     AnyReturnValue SetValue(const IAny& value) override
297     {
298         return CopyFrom(value);
299     }
300     using IAny::GetValue;
GetValue()301     const IAny& GetValue() const override
302     {
303         return *this;
304     }
IsCompatible(const TypeId & id)305     bool IsCompatible(const TypeId& id) const override
306     {
307         return META_NS::IsCompatible(*this, id);
308     }
309 
310 protected:
311     virtual AnyReturnValue InternalSetValue(const ArrayType& value) = 0;
312     virtual const ArrayType& InternalGetValue() const = 0;
313 
314 private:
IsValidVectorArgs(const TypeId & uid,const void * data,size_t size)315     static constexpr bool IsValidVectorArgs(const TypeId& uid, const void* data, size_t size)
316     {
317         return data && sizeof(ArrayType) == size && uid == VECTOR_TYPE_ID;
318     }
IsValidArrayArgs(const TypeId & uid,const void * data)319     static constexpr bool IsValidArrayArgs(const TypeId& uid, const void* data)
320     {
321         return data && uid == ARRAY_TYPE_ID;
322     }
323 };
324 
325 /**
326  * @brief Default IArrayAny implementation which supports a single type.
327  */
328 template<typename Type, typename Compare = DefaultCompare<BASE_NS::vector<Type>>>
329 class ArrayAny : public BaseTypedArrayAny<Type> {
330     using Super = BaseTypedArrayAny<Type>;
331     using ArrayType = typename Super::ArrayType;
332     using ItemType = typename Super::ItemType;
333     using Super::ITEM_TYPE_ID;
334     static constexpr auto ITEM_SIZE = sizeof(ItemType); /*NOLINT(bugprone-sizeof-expression)*/
335 
336 public:
337     explicit constexpr ArrayAny(ArrayType v = {}) : value_(BASE_NS::move(v)) {}
ArrayAny(const BASE_NS::array_view<const Type> & v)338     explicit constexpr ArrayAny(const BASE_NS::array_view<const Type>& v) : value_(v.begin(), v.end()) {}
339 #ifdef BASE_VECTOR_HAS_INITIALIZE_LIST
ArrayAny(std::initializer_list<Type> v)340     constexpr ArrayAny(std::initializer_list<Type> v) : value_(ArrayType(v)) {}
341 #endif
342 
GetDataAt(size_t index,const TypeId & id,void * data,size_t size)343     AnyReturnValue GetDataAt(size_t index, const TypeId& id, void* data, size_t size) const override
344     {
345         if (IsValidItemArgs(id, data, size) && index < GetSize()) {
346             *static_cast<ItemType*>(data) = value_[index];
347             return AnyReturn::SUCCESS;
348         }
349         return AnyReturn::INVALID_ARGUMENT;
350     }
SetDataAt(size_t index,const TypeId & id,const void * data,size_t size)351     AnyReturnValue SetDataAt(size_t index, const TypeId& id, const void* data, size_t size) override
352     {
353         if (IsValidItemArgs(id, data, size) && index < GetSize()) {
354             value_[index] = *static_cast<const ItemType*>(data);
355             return AnyReturn::SUCCESS;
356         }
357         return AnyReturn::INVALID_ARGUMENT;
358     }
SetAnyAt(IArrayAny::IndexType index,const IAny & value)359     AnyReturnValue SetAnyAt(IArrayAny::IndexType index, const IAny& value) override
360     {
361         ItemType v;
362         if (value.GetData(ITEM_TYPE_ID, &v, ITEM_SIZE)) {
363             return SetDataAt(index, ITEM_TYPE_ID, &v, ITEM_SIZE);
364         }
365         return AnyReturn::INVALID_ARGUMENT;
366     }
GetAnyAt(IArrayAny::IndexType index,IAny & value)367     AnyReturnValue GetAnyAt(IArrayAny::IndexType index, IAny& value) const override
368     {
369         ItemType v;
370         if (GetDataAt(index, ITEM_TYPE_ID, &v, ITEM_SIZE)) {
371             return value.SetData(ITEM_TYPE_ID, &v, ITEM_SIZE);
372         }
373         return AnyReturn::INVALID_ARGUMENT;
374     }
InsertAnyAt(IArrayAny::IndexType index,const IAny & value)375     AnyReturnValue InsertAnyAt(IArrayAny::IndexType index, const IAny& value) override
376     {
377         ItemType v;
378         if (value.GetData(ITEM_TYPE_ID, &v, ITEM_SIZE)) {
379             index = index < value_.size() ? index : value_.size();
380             value_.insert(value_.begin() + index, v);
381             return AnyReturn::SUCCESS;
382         }
383         return AnyReturn::INVALID_ARGUMENT;
384     }
RemoveAt(IArrayAny::IndexType index)385     AnyReturnValue RemoveAt(IArrayAny::IndexType index) override
386     {
387         if (index < value_.size()) {
388             value_.erase(value_.begin() + index);
389             return AnyReturn::SUCCESS;
390         }
391         return AnyReturn::INVALID_ARGUMENT;
392     }
RemoveAll()393     void RemoveAll() override
394     {
395         value_.clear();
396     }
397 
GetSize()398     IArrayAny::IndexType GetSize() const noexcept override
399     {
400         return value_.size();
401     }
402     IAny::Ptr Clone(const AnyCloneOptions& options) const override;
Clone(bool withValue)403     IAny::Ptr Clone(bool withValue) const
404     {
405         return Clone({ withValue ? CloneValueType::COPY_VALUE : CloneValueType::DEFAULT_VALUE });
406     }
407 
InternalGetValue()408     const ArrayType& InternalGetValue() const override
409     {
410         return value_;
411     }
412 
PushBack(ItemType item)413     void PushBack(ItemType item)
414     {
415         value_.push_back(BASE_NS::move(item));
416     }
417 
418 private:
InternalSetValue(const ArrayType & value)419     AnyReturnValue InternalSetValue(const ArrayType& value) override
420     {
421         if (!Compare::Equal(value, value_)) {
422             value_ = value;
423             return AnyReturn::SUCCESS;
424         }
425         return AnyReturn::NOTHING_TO_DO;
426     }
427 
IsValidItemArgs(const TypeId & uid,const void * data,size_t size)428     static constexpr bool IsValidItemArgs(const TypeId& uid, const void* data, size_t size)
429     {
430         return data && ITEM_SIZE == size && uid == Super::ITEM_TYPE_ID;
431     }
432 
433 private:
434     ArrayType value_;
435 };
436 
437 template<class Type, class Compare>
Clone(const AnyCloneOptions & options)438 IAny::Ptr Any<Type, Compare>::Clone(const AnyCloneOptions& options) const
439 {
440     if (options.role == TypeIdRole::ARRAY) {
441         return IAny::Ptr(new ArrayAny<Type>());
442     }
443     return IAny::Ptr(new Any { options.value == CloneValueType::COPY_VALUE ? value_ : Type {} });
444 }
445 
446 template<class Type, class Compare>
Clone(const AnyCloneOptions & options)447 IAny::Ptr ArrayAny<Type, Compare>::Clone(const AnyCloneOptions& options) const
448 {
449     if (options.role == TypeIdRole::ITEM) {
450         return IAny::Ptr(new Any<Type>());
451     }
452     return IAny::Ptr(new ArrayAny { options.value == CloneValueType::COPY_VALUE ? value_ : ArrayType {} });
453 }
454 
455 template<class Type, class Compare = DefaultCompare<Type>>
456 static IAny::Ptr ConstructAny(Type v = {})
457 {
458     return IAny::Ptr { new Any<Type, Compare>(BASE_NS::move(v)) };
459 }
460 
461 template<class Type, class Compare = DefaultCompare<BASE_NS::vector<Type>>>
462 static IArrayAny::Ptr ConstructArrayAny(BASE_NS::vector<Type> v = {})
463 {
464     return IArrayAny::Ptr { new ArrayAny<Type, Compare>(BASE_NS::move(v)) };
465 }
466 
467 META_END_NAMESPACE()
468 
469 #endif
470