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_BASE_META_TYPES_H
16 #define META_BASE_META_TYPES_H
17 
18 #include <stdint.h>
19 
20 #include <base/namespace.h>
21 #include <base/util/compile_time_hashes.h>
22 #include <base/util/uid.h>
23 #include <core/property/property_types.h>
24 
25 #include <meta/base/type_traits.h>
26 
27 META_BEGIN_NAMESPACE()
28 
29 template<typename t>
30 struct MetaType;
31 
32 template<class T, class B>
CorePropertyTypeDeclFromType()33 inline constexpr auto CorePropertyTypeDeclFromType()
34 {
35     if constexpr (CORE_NS::PropertySystem::is_defined<T>().value) {
36         return CORE_NS::PropertySystem::PropertyTypeDeclFromType<T, B>();
37     }
38     return CORE_NS::PropertyTypeDecl {};
39 }
40 
MakeUidImpl(uint64_t hash,const char (& type)[9])41 inline constexpr BASE_NS::Uid MakeUidImpl(uint64_t hash, const char (&type)[9])
42 {
43     uint8_t data[16u] { static_cast<uint8_t>((hash >> 56) & 0xFF), static_cast<uint8_t>((hash >> 48) & 0xFF),
44         static_cast<uint8_t>((hash >> 40) & 0xFF), static_cast<uint8_t>((hash >> 32) & 0xFF),
45         static_cast<uint8_t>((hash >> 24) & 0xFF), static_cast<uint8_t>((hash >> 16) & 0xFF),
46         static_cast<uint8_t>((hash >> 8) & 0xFF), static_cast<uint8_t>(hash & 0xFF), static_cast<uint8_t>(type[0]),
47         static_cast<uint8_t>(type[1]), static_cast<uint8_t>(type[2]), static_cast<uint8_t>(type[3]),
48         static_cast<uint8_t>(type[4]), static_cast<uint8_t>(type[5]), static_cast<uint8_t>(type[6]),
49         static_cast<uint8_t>(type[7]) };
50     return BASE_NS::Uid(data);
51 }
52 
53 /**
54  * @brief Generate UID from name and type string.
55  */
MakeUid(const char * const name,const char (& type)[9])56 inline constexpr BASE_NS::Uid MakeUid(const char* const name, const char (&type)[9])
57 {
58     return MakeUidImpl(BASE_NS::CompileTime::FNV1aHash(name), type);
59 }
60 
61 template<typename Type>
62 using EnableIfDefined = decltype(sizeof(Type));
63 
64 template<typename Type>
65 constexpr bool IsDefined_v = META_NS::IsDetected_v<EnableIfDefined, Type>; // NOLINT(readability-identifier-naming)
66 
67 template<typename Type>
68 constexpr bool HasUid_v = IsDefined_v<MetaType<Type>>; // NOLINT(readability-identifier-naming)
69 
70 /**
71  * @brief Generate UID from registered type and type string.
72  */
73 template<typename Type>
MakeUid(const char (& type)[9])74 inline constexpr BASE_NS::Uid MakeUid(const char (&type)[9])
75 {
76     static_assert(HasUid_v<Type>, "META_TYPE missing for given type");
77     return MakeUidImpl(BASE_NS::CompileTime::FNV1aHash(MetaType<Type>::name), type);
78 }
79 
80 template<typename Type>
CombineHash(uint64_t hash)81 inline constexpr uint64_t CombineHash(uint64_t hash)
82 {
83     static_assert(HasUid_v<Type>, "META_TYPE missing for given type");
84     return hash ^
85            (BASE_NS::CompileTime::FNV1aHash(MetaType<Type>::name) + 0x9e3779b97f4a7c15LLU +
86            (hash << 12) + (hash >> 4)); // 12 4 shift multiple
87 }
88 
89 /**
90  * @brief Generate UID from multiple registered types and type string.
91  */
92 template<typename... Types>
MakeUidFromTypes(const char (& type)[9])93 inline constexpr BASE_NS::Uid MakeUidFromTypes(const char (&type)[9])
94 {
95     uint64_t hash {};
96     if constexpr (sizeof...(Types) != 0) {
97         hash = (CombineHash<Types>(hash), ...);
98     }
99     return MakeUidImpl(hash, type);
100 }
101 
102 /**
103  * @brief Check if UID is valid.
104  */
IsValidUid(const BASE_NS::Uid & uid)105 inline constexpr bool IsValidUid(const BASE_NS::Uid& uid)
106 {
107     for (const auto& v : uid.data) {
108         if (v != 0) {
109             return true;
110         }
111     }
112     return false;
113 }
114 
115 /**
116  * @brief Generate UID for read-only property type.
117  */
118 template<typename Type>
UidFromReadOnlyType()119 inline constexpr BASE_NS::Uid UidFromReadOnlyType()
120 {
121 // At least visual c++ 2017 has a bug that causes this uid variable to be uninitialised at runtime and so crashing
122 // We know at least visual c++ 2022 works...
123 #if defined(_MSC_VER) && _MSC_VER < 1930
124     return MakeUid<Type>("ReadOnly");
125 #else
126     constexpr auto uid = MakeUid<Type>("ReadOnly");
127     static_assert(IsValidUid(uid));
128     return uid;
129 #endif
130 }
131 /**
132  * @brief Generate UID for property type.
133  */
134 
135 template<typename Type>
UidFromType()136 inline constexpr BASE_NS::Uid UidFromType()
137 {
138 // At least visual c++ 2017 has a bug that causes this uid variable to be uninitialised at runtime and so crashing
139 // We know at least visual c++ 2022 works...
140 #if defined(_MSC_VER) && _MSC_VER < 1930
141     return MakeUid<Type>("Property");
142 #else
143     constexpr auto uid = MakeUid<Type>("Property");
144     static_assert(IsValidUid(uid));
145     return uid;
146 #endif
147 }
148 
149 template<typename Type>
ArrayUidFromType()150 inline constexpr BASE_NS::Uid ArrayUidFromType()
151 {
152     if constexpr (BASE_NS::is_array_v<Type>) {
153         return UidFromType<Type>();
154     }
155     return UidFromType<Type[]>();
156 }
157 
158 template<typename Type>
ItemUidFromType()159 inline constexpr BASE_NS::Uid ItemUidFromType()
160 {
161     return UidFromType<BASE_NS::remove_extent_t<Type>>();
162 }
163 
164 template<>
165 struct MetaType<void> {
166     // NOLINTBEGIN(readability-identifier-naming)
167     static constexpr char name[] = "void";
168     static constexpr CORE_NS::PropertyTypeDecl coreType = CorePropertyTypeDeclFromType<void, BASE_NS::false_type>();
169     // NOLINTEND(readability-identifier-naming)
170 };
171 
172 META_END_NAMESPACE()
173 
174 /**
175  * @brief To introduce new types to the property system, call META_TYPE(<type>) in global namespace.
176  */
177 #define META_TYPE_IMPL(a, n)                                                                    \
178     template<>                                                                                  \
179     struct ::META_NS::MetaType<a> {                                                             \
180         static constexpr char name[] = n;                                                       \
181         static constexpr CORE_NS::PropertyTypeDecl coreType =                                   \
182             ::META_NS::CorePropertyTypeDeclFromType<a, BASE_NS::false_type>();                  \
183     };                                                                                          \
184     template<>                                                                                  \
185     struct ::META_NS::MetaType<a[]> {                                                           \
186         static constexpr char name[] = n "[]";                                                  \
187         static constexpr CORE_NS::PropertyTypeDecl coreType =                                   \
188             ::META_NS::CorePropertyTypeDeclFromType<a, BASE_NS::true_type>();                   \
189     };                                                                                          \
190     template<>                                                                                  \
191     struct ::META_NS::MetaType<BASE_NS::vector<a>> {                                            \
192         static constexpr char name[] = "BASE_NS::vector<" n ">";                                \
193         static constexpr CORE_NS::PropertyTypeDecl coreType =                                   \
194             ::META_NS::CorePropertyTypeDeclFromType<BASE_NS::vector<a>, BASE_NS::false_type>(); \
195     };
196 
197 #define META_TYPE(a) META_TYPE_IMPL(a, #a)
198 #define META_INTERFACE_TYPE(a)                   \
199     META_TYPE_IMPL(a::Ptr, #a "::Ptr")           \
200     META_TYPE_IMPL(a::ConstPtr, #a "::ConstPtr") \
201     META_TYPE_IMPL(a::WeakPtr, #a "::WeakPtr")   \
202     META_TYPE_IMPL(a::ConstWeakPtr, #a "::ConstWeakPtr")
203 
204 META_TYPE(float);
205 META_TYPE(double);
206 META_TYPE(bool);
207 META_TYPE(uint8_t);
208 META_TYPE(uint16_t);
209 META_TYPE(uint32_t);
210 META_TYPE(uint64_t);
211 META_TYPE(int8_t);
212 META_TYPE(int16_t);
213 META_TYPE(int32_t);
214 META_TYPE(int64_t);
215 #ifdef __APPLE__
216 META_TYPE(size_t);
217 #endif
218 META_TYPE(BASE_NS::Uid);
219 META_TYPE(BASE_NS::string);
220 META_TYPE(BASE_NS::string_view);
221 META_TYPE(BASE_NS::Math::Vec2);
222 META_TYPE(BASE_NS::Math::UVec2);
223 META_TYPE(BASE_NS::Math::IVec2);
224 META_TYPE(BASE_NS::Math::Vec3);
225 META_TYPE(BASE_NS::Math::UVec3);
226 META_TYPE(BASE_NS::Math::IVec3);
227 META_TYPE(BASE_NS::Math::Vec4);
228 META_TYPE(BASE_NS::Math::UVec4);
229 META_TYPE(BASE_NS::Math::IVec4);
230 META_TYPE(BASE_NS::Math::Quat);
231 META_TYPE(BASE_NS::Math::Mat3X3);
232 META_TYPE(BASE_NS::Math::Mat4X4);
233 META_TYPE(CORE_NS::Entity);
234 META_TYPE(CORE_NS::EntityReference);
235 
236 CORE_BEGIN_NAMESPACE()
237 class IPropertyHandle;
238 DECLARE_PROPERTY_TYPE(CORE_NS::IPropertyHandle*);
239 CORE_END_NAMESPACE()
240 
241 META_TYPE(CORE_NS::IPropertyHandle*);
242 
243 #endif
244