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
16 #ifndef META_BASE_INTERFACE_TRAITS_H
17 #define META_BASE_INTERFACE_TRAITS_H
18
19 #include <base/containers/type_traits.h>
20 #include <base/util/uid.h>
21 #include <core/plugin/intf_interface.h>
22
23 #include <meta/base/type_traits.h>
24
BASE_BEGIN_NAMESPACE()25 BASE_BEGIN_NAMESPACE()
26 namespace Internals {
27 class ptr_base;
28 }
29 template<typename>
30 class shared_ptr;
31
32 template<typename>
33 class weak_ptr;
34 BASE_END_NAMESPACE()
35
META_BEGIN_NAMESPACE()36 META_BEGIN_NAMESPACE()
37
38 template<class C>
39 class HasGetInterfaceMethod final {
40 template<class T>
41 static BASE_NS::true_type TestSignature(CORE_NS::IInterface* (T::*)(const BASE_NS::Uid&));
42
43 template<class T>
44 static decltype(TestSignature((CORE_NS::IInterface * (T::*)(const BASE_NS::Uid&)) & T::GetInterface)) Test(
45 std::nullptr_t);
46
47 template<class T>
48 static BASE_NS::false_type Test(...);
49
50 public:
51 static constexpr bool value = decltype(Test<C>(nullptr))::value; // NOLINT(readability-identifier-naming)
52 };
53
54 // NOLINTBEGIN(readability-identifier-naming)
55 /**
56 * @brief Check if type has GetInterface member functions (see IInterface).
57 */
58 template<class C>
59 inline constexpr bool HasGetInterfaceMethod_v = HasGetInterfaceMethod<C>::value;
60
61 /**
62 * @brief Check if type is an interface, i.e. implements reference counting and GetInterface member functions.
63 */
64 template<class C>
65 inline constexpr bool IsKindOfInterface_v =
66 BASE_NS::is_convertible_v<BASE_NS::remove_const_t<C>*, CORE_NS::IInterface*>;
67 // NOLINTEND(readability-identifier-naming)
68
69 // type trait for checking if the type has equality comparison
70 template<class T>
71 struct HasEqualOperator {
72 template<class U, class V>
73 static auto Test(U*) -> decltype(BASE_NS::declval<U>() == BASE_NS::declval<V>());
74 template<typename, typename>
75 static auto Test(...) -> BASE_NS::false_type;
76
77 using type = typename BASE_NS::is_same<bool, decltype(Test<T, T>(nullptr))>::type;
78 };
79
80 /**
81 * @brief Check if the type can be compared with equality operators.
82 */
83 template<class C>
84 inline constexpr bool HasEqualOperator_v = HasEqualOperator<C>::type::value; // NOLINT(readability-identifier-naming)
85
86 template<class T>
87 struct HasInEqualOperator {
88 template<class U, class V>
89 static auto Test(U*) -> decltype(BASE_NS::declval<U>() != BASE_NS::declval<V>());
90 template<typename, typename>
91 static auto Test(...) -> BASE_NS::false_type;
92
93 using type = typename BASE_NS::is_same<bool, decltype(Test<T, T>(nullptr))>::type;
94 };
95
96 // NOLINTBEGIN(readability-identifier-naming)
97 /**
98 * @brief Check if the type can be compared with in-equality operators.
99 */
100 template<class C>
101 inline constexpr bool HasInEqualOperator_v = HasInEqualOperator<C>::type::value;
102 // NOLINTEND(readability-identifier-naming)
103
104 // NOLINTBEGIN(readability-identifier-naming)
105 /**
106 * @brief Check if the type is "kind of" smart pointer, i.e. derived from BASE_NS::ptr_base.
107 */
108 template<typename type>
109 constexpr bool IsKindOfPointer_v =
110 BASE_NS::is_convertible_v<BASE_NS::remove_const_t<type&>, BASE_NS::Internals::ptr_base&>;
111 // NOLINTEND(readability-identifier-naming)
112
113 // NOLINTBEGIN(readability-identifier-naming)
114 /**
115 * @brief Check if the type is a pointer which is convertible to IInterface pointer.
116 */
117 template<typename type>
118 constexpr bool IsKindOfIInterface_v = BASE_NS::is_convertible_v<BASE_NS::remove_const_t<type>, CORE_NS::IInterface*>;
119 // NOLINTEND(readability-identifier-naming)
120
121 /**
122 * @brief SFINAE construct for checking if entity can be used as property bind function.
123 */
124 template<typename Func, typename Type>
125 using EnableIfProperBindFunction = decltype(BASE_NS::declval<void(const Type&)>()(BASE_NS::declval<Func>()()));
126
127 template<typename T>
128 T CallTestFunc(const T&);
129
130 template<typename Func>
131 using EnableIfBindFunction = decltype(CallTestFunc(BASE_NS::declval<Func>()()));
132
133 template<typename Func, typename InvokeType, typename = void>
134 struct CanInvokeWithArgumentsImpl {
135 constexpr static bool value = false; // NOLINT(readability-identifier-naming)
136 };
137
138 template<typename Func, typename Ret, typename... Args>
139 struct CanInvokeWithArgumentsImpl<Func, Ret(Args...),
140 decltype(BASE_NS::declval<Func>()(BASE_NS::declval<Args>()...), void())> {
141 constexpr static bool value = true; // NOLINT(readability-identifier-naming)
142 };
143
144 // NOLINTBEGIN(readability-identifier-naming)
145 /**
146 * @brief Check if callable entity is compatible with given function signature.
147 */
148 template<typename Func, typename InvokeType>
149 constexpr bool CanInvokeWithArguments_v = CanInvokeWithArgumentsImpl<Func, InvokeType>::value;
150 // NOLINTEND(readability-identifier-naming)
151
152 template<typename Func, typename InvokeType>
153 using EnableIfCanInvokeWithArguments = typename BASE_NS::enable_if_t<CanInvokeWithArguments_v<Func, InvokeType>>;
154
155 template<typename Type>
156 using ToggleConst = BASE_NS::conditional_t<BASE_NS::is_const_v<Type>, BASE_NS::remove_const_t<Type>, const Type>;
157
158 template<typename Type>
159 struct ToggleConstSharedPtrImpl;
160
161 template<typename Type>
162 struct ToggleConstSharedPtrImpl<BASE_NS::shared_ptr<Type>> {
163 using type = BASE_NS::shared_ptr<const Type>;
164 };
165
166 template<typename Type>
167 struct ToggleConstSharedPtrImpl<BASE_NS::shared_ptr<const Type>> {
168 using type = BASE_NS::shared_ptr<Type>;
169 };
170
171 template<typename Type>
172 using ToggleConstSharedPtr = typename ToggleConstSharedPtrImpl<Type>::type;
173
174 /*
175 We want to check if one can cast shared_ptr<BaseProp> to PropPtr. This requires in our case baseclass relation.
176 * (1) BaseProp and PropPtr are both const or non-const
177 - This case is easy, just check directly the conversion.
178 * (2) BaseProp is const and PropPtr is non-const
179 - This is not allowed case since we don't cast away constness
180 * (3) BaseProp is non-const and PropPtr is const
181 - This case is just adding a const
182
183 Since PropPtr is the derived class, we need to see if we can convert that to the base class:
184 is_convertible<PropPtr, shared_ptr<BaseProp>> works for (1) and (2) but not for (3)
185 We want it to work for (1) and (3) but not (2), so we can achieve this by swapping the constness of the types.
186 */
187
188 // NOLINTBEGIN(readability-identifier-naming)
189 template<typename BaseProp, typename PropPtr>
190 inline constexpr bool IsCompatibleBaseProperty_v =
191 BASE_NS::is_convertible_v<ToggleConstSharedPtr<PropPtr>, BASE_NS::shared_ptr<ToggleConst<BaseProp>>>;
192 // NOLINTEND(readability-identifier-naming)
193
194 template<typename BaseProp, typename PropPtr>
195 using EnableIfCompatibleBaseProperty = BASE_NS::enable_if_t<IsCompatibleBaseProperty_v<BaseProp, PropPtr>>;
196
197 /**
198 * @brief Check if type is shared_ptr
199 */
200 template<typename>
201 struct IsSharedPtr {
202 static constexpr bool value = false; // NOLINT(readability-identifier-naming)
203 };
204
205 template<typename T>
206 struct IsSharedPtr<BASE_NS::shared_ptr<T>> {
207 static constexpr bool value = true; // NOLINT(readability-identifier-naming)
208 template<typename Type>
209 using rebind = BASE_NS::shared_ptr<Type>;
210 };
211
212 template<typename>
213 struct IsWeakPtr {
214 static constexpr bool value = false; // NOLINT(readability-identifier-naming)
215 };
216
217 template<typename T>
218 struct IsWeakPtr<BASE_NS::weak_ptr<T>> {
219 static constexpr bool value = true; // NOLINT(readability-identifier-naming)
220 template<typename Type>
221 using rebind = BASE_NS::weak_ptr<Type>;
222 };
223
224 template<typename Type>
225 constexpr bool IsWeakPtr_v = IsWeakPtr<Type>::value; // NOLINT(readability-identifier-naming)
226
227 /**
228 * @brief Check if type is shared_ptr or weak_ptr
229 */
230 template<typename>
231 struct IsSharedOrWeakPtr {
232 static constexpr bool value = false; // NOLINT(readability-identifier-naming)
233 };
234
235 template<typename T>
236 struct IsSharedOrWeakPtr<BASE_NS::shared_ptr<T>> {
237 static constexpr bool value = true; // NOLINT(readability-identifier-naming)
238 template<typename Type>
239 using rebind = BASE_NS::shared_ptr<Type>;
240 static constexpr bool is_const = BASE_NS::is_const_v<T>; // NOLINT(readability-identifier-naming)
241 };
242
243 template<typename T>
244 struct IsSharedOrWeakPtr<BASE_NS::weak_ptr<T>> {
245 static constexpr bool value = true; // NOLINT(readability-identifier-naming)
246 template<typename Type>
247 using rebind = BASE_NS::weak_ptr<Type>;
248 static constexpr bool is_const = BASE_NS::is_const_v<T>; // NOLINT(readability-identifier-naming)
249 };
250
251 template<typename Type>
252 constexpr bool IsConstPtr_v = IsSharedOrWeakPtr<Type>::is_const; // NOLINT(readability-identifier-naming)
253
254 /**
255 * @brief Check if type is shared_ptr or weak_ptr
256 */
257 template<typename T>
258 constexpr bool IsSharedOrWeakPtr_v = IsSharedOrWeakPtr<T>::value; // NOLINT(readability-identifier-naming)
259
260 template<typename Type>
261 using InterfaceCheck = META_NS::BoolWrap<IsKindOfIInterface_v<BASE_NS::remove_const_t<typename Type::element_type>*>>;
262
263 // NOLINTBEGIN(readability-identifier-naming)
264 template<typename Type>
265 constexpr bool IsInterfacePtr_v = IsSharedOrWeakPtr_v<Type> && META_NS::IsDetectedWithValue_v<InterfaceCheck, Type>;
266 // NOLINTEND(readability-identifier-naming)
267
268 // NOLINTBEGIN(readability-identifier-naming)
269 template<typename Type>
270 constexpr bool IsInterfaceWeakPtr_v = IsInterfacePtr_v<Type> && IsWeakPtr<Type>::value;
271 // NOLINTEND(readability-identifier-naming)
272
273 template<typename M>
274 struct FuncToSignature;
275
276 template<typename Ret, typename Class, typename... Args>
277 struct FuncToSignature<Ret (Class::*)(Args...)> {
278 using type = Ret(Args...);
279 constexpr static bool IS_CONST = false;
280 };
281
282 template<typename Ret, typename Class, typename... Args>
283 struct FuncToSignature<Ret (Class::*)(Args...) const> {
284 using type = Ret(Args...);
285 constexpr static bool IS_CONST = true;
286 };
287
288 template<typename Ret, typename... Args>
289 struct FuncToSignature<Ret(Args...)> {
290 using type = Ret(Args...);
291 constexpr static bool IS_CONST = false;
292 };
293
294 template<typename Ret, typename... Args>
295 struct FuncToSignature<Ret(Args...) const> {
296 using type = Ret(Args...);
297 constexpr static bool IS_CONST = true;
298 };
299
300 template<typename M>
301 struct FuncToSignature : FuncToSignature<decltype(&M::operator())> {};
302
303 /**
304 * @brief Convert member function types, function types and callable entity types to function signature.
305 * Note: Does not work with multiple overloads of operator().
306 */
307 template<typename M>
308 using FuncToSignature_t = typename FuncToSignature<M>::type;
309
310 META_END_NAMESPACE()
311
312 #endif
313