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 "number.h"
16 
17 #include <limits>
18 
19 META_BEGIN_NAMESPACE()
20 namespace Internal {
21 
22 template<typename T>
23 struct Type {};
24 
25 template<typename T>
MapToVariant(const T & v)26 static Number::VariantType MapToVariant(const T& v)
27 {
28     if constexpr (std::numeric_limits<T>::is_integer) {
29         if constexpr (std::numeric_limits<T>::is_signed) {
30             return Number::VariantType(static_cast<int64_t>(v));
31         }
32         return Number::VariantType(static_cast<uint64_t>(v));
33     }
34     return Number::VariantType(static_cast<float>(v));
35 }
36 
37 struct CompType {
38     template<typename T>
CompTypeInternal::CompType39     constexpr CompType(Type<T>)
40         : uid(UidFromType<T>()), size(sizeof(T)), load([](const void* data) {
41               T v = *static_cast<const T*>(data);
42               return MapToVariant(v);
43         }),
__anon89f340370202Internal::CompType44         save([](Number::VariantType var, void* data) {
45             T v {};
46             std::visit([&](const auto& arg) {
47                 v = static_cast<T>(arg);
48             }, var);
49             *static_cast<T*>(data) = v;
50         }),
__anon89f340370402Internal::CompType51         loadAny([](const IAny& any, Number::VariantType& var) {
52             T v {};
53             bool res = any.GetValue(v);
54             if (res) {
55                 var = MapToVariant(v);
56             }
57             return res;
58         })
59     {}
60 
61     using LoadFunc = Number::VariantType(const void*);
62     using SaveFunc = void(Number::VariantType, void*);
63     using LoadAnyFunc = bool(const IAny&, Number::VariantType&);
64 
65     const TypeId uid;
66     const size_t size;
67     LoadFunc* const load;
68     SaveFunc* const save;
69     LoadAnyFunc* const loadAny;
70 };
71 
72 constexpr CompType COMPATIBLES[] = {
73     Type<float>(),
74     Type<double>(),
75     Type<bool>(),
76     Type<uint8_t>(),
77     Type<uint16_t>(),
78     Type<uint32_t>(),
79     Type<uint64_t>(),
80     Type<int8_t>(),
81     Type<int16_t>(),
82     Type<int32_t>(),
83     Type<int64_t>(),
84 };
85 
CompatibleTypes()86 static BASE_NS::vector<TypeId> CompatibleTypes()
87 {
88     BASE_NS::vector<TypeId> res;
89     for (auto&& v : COMPATIBLES) {
90         res.push_back(v.uid);
91     }
92     return res;
93 }
94 
FindCompatible(const TypeId & uid,size_t size)95 static const CompType* FindCompatible(const TypeId& uid, size_t size)
96 {
97     for (auto&& v : COMPATIBLES) {
98         if (v.uid == uid && v.size == size) {
99             return &v;
100         }
101     }
102     return nullptr;
103 }
104 
FindCompatible(const IAny & any)105 static const CompType* FindCompatible(const IAny& any)
106 {
107     auto anyComps = any.GetCompatibleTypes(CompatibilityDirection::BOTH);
108     for (auto&& v : COMPATIBLES) {
109         for (auto&& av : anyComps) {
110             if (v.uid == av) {
111                 return &v;
112             }
113         }
114     }
115     return nullptr;
116 }
117 
Number(VariantType v)118 Number::Number(VariantType v) : value_(v) {}
GetCompatibleTypes(CompatibilityDirection dir) const119 const BASE_NS::array_view<const TypeId> Number::GetCompatibleTypes(CompatibilityDirection dir) const
120 {
121     static BASE_NS::vector<TypeId> types = CompatibleTypes();
122     return types;
123 }
GetData(const TypeId & uid,void * data,size_t size) const124 AnyReturnValue Number::GetData(const TypeId& uid, void* data, size_t size) const
125 {
126     if (auto c = FindCompatible(uid, size)) {
127         c->save(value_, data);
128         return AnyReturn::SUCCESS;
129     }
130     return AnyReturn::INCOMPATIBLE_TYPE;
131 }
SetData(const TypeId & uid,const void * data,size_t size)132 AnyReturnValue Number::SetData(const TypeId& uid, const void* data, size_t size)
133 {
134     if (auto c = FindCompatible(uid, size)) {
135         value_ = c->load(data);
136         return AnyReturn::SUCCESS;
137     }
138     return AnyReturn::INCOMPATIBLE_TYPE;
139 }
CopyFrom(const IAny & any)140 AnyReturnValue Number::CopyFrom(const IAny& any)
141 {
142     if (auto c = FindCompatible(any)) {
143         c->loadAny(any, value_);
144     }
145     return AnyReturn::INCOMPATIBLE_TYPE;
146 }
Clone(const AnyCloneOptions & options) const147 IAny::Ptr Number::Clone(const AnyCloneOptions& options) const
148 {
149     if (options.role == TypeIdRole::ARRAY) {
150         CORE_LOG_E("Number: cloning into an array not supported.");
151         return {};
152     }
153     return IAny::Ptr(new Number(options.value == CloneValueType::COPY_VALUE ? value_ : VariantType {}));
154 }
GetTypeId(TypeIdRole role) const155 TypeId Number::GetTypeId(TypeIdRole role) const
156 {
157     if (role == TypeIdRole::ARRAY) {
158         return std::visit([&](auto arg) { return ArrayUidFromType<decltype(arg)>(); }, value_);
159     }
160     return std::visit([&](auto arg) { return UidFromType<decltype(arg)>(); }, value_);
161 }
162 
GetTypeIdString() const163 BASE_NS::string Number::GetTypeIdString() const
164 {
165     return std::visit([&](auto arg) { return MetaType<decltype(arg)>::name; }, value_);
166 }
167 
168 } // namespace Internal
169 META_END_NAMESPACE()
170