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 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 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