File indexing completed on 2024-06-23 05:07:15
0001 /* 0002 SPDX-FileCopyrightText: 2019 Daniel Vrátil <dvratil@kde.org> 0003 0004 SPDX-License-Identifier: LGPL-2.0-or-later 0005 */ 0006 0007 #pragma once 0008 0009 #include <type_traits> 0010 #include <utility> 0011 0012 namespace AkTraits 0013 { 0014 namespace detail 0015 { 0016 template<typename...> 0017 struct conjunction : std::true_type { 0018 }; 0019 template<typename T> 0020 struct conjunction<T> : T { 0021 }; 0022 template<typename T, typename... Ts> 0023 struct conjunction<T, Ts...> : std::conditional_t<bool(T::value), conjunction<Ts...>, T> { 0024 }; 0025 0026 #define DECLARE_HAS_MEBER_TYPE(type_name) \ 0027 template<typename T, typename U = std::void_t<>> \ 0028 struct hasMember_##type_name { \ 0029 static constexpr bool value = false; \ 0030 }; \ 0031 \ 0032 template<typename T> \ 0033 struct hasMember_##type_name<T, std::void_t<typename T::type_name>> : std::true_type { \ 0034 }; 0035 0036 DECLARE_HAS_MEBER_TYPE(value_type) 0037 0038 /// TODO: Use Boost TTI instead? 0039 #define DECLARE_HAS_METHOD_GENERIC_IMPL(name, fun, sign) \ 0040 template<typename T, typename F = sign> \ 0041 struct hasMethod_##name { \ 0042 public: \ 0043 template<typename UType, UType> \ 0044 struct helperClass; \ 0045 \ 0046 using True = char; \ 0047 using False = struct { \ 0048 char dummy_[2]; \ 0049 }; \ 0050 \ 0051 template<typename U> \ 0052 static True helper(helperClass<F, &U::fun> *); \ 0053 template<typename> \ 0054 static False helper(...); \ 0055 \ 0056 public: \ 0057 static constexpr bool value = sizeof(helper<T>(nullptr)) == sizeof(True); \ 0058 }; 0059 0060 #define DECLARE_HAS_METHOD_GENERIC_CONST(fun, R, ...) DECLARE_HAS_METHOD_GENERIC_IMPL(fun##_const, fun, R (T::*)(__VA_ARGS__) const) 0061 0062 #define DECLARE_HAS_METHOD_GENERIC(fun, R, ...) DECLARE_HAS_METHOD_GENERIC_IMPL(fun, fun, R (T::*)(__VA_ARGS__)) 0063 0064 // deal with Qt6 interface changes in QList::push_back/QList::insert 0065 template<typename T, typename = std::void_t<>> 0066 struct parameter_type { 0067 typedef const typename T::value_type &type; 0068 }; 0069 template<typename T> 0070 struct parameter_type<T, std::void_t<typename T::parameter_type>> { 0071 typedef typename T::parameter_type type; 0072 }; 0073 0074 DECLARE_HAS_METHOD_GENERIC_CONST(size, qsizetype, void) 0075 DECLARE_HAS_METHOD_GENERIC(push_back, void, typename parameter_type<T>::type) 0076 DECLARE_HAS_METHOD_GENERIC(insert, typename T::iterator, typename parameter_type<T>::type) 0077 DECLARE_HAS_METHOD_GENERIC(reserve, void, qsizetype) 0078 0079 #define DECLARE_HAS_FUNCTION(name, fun) \ 0080 template<typename T> \ 0081 struct has_##name { \ 0082 template<typename U> \ 0083 struct helperClass; \ 0084 \ 0085 using True = char; \ 0086 using False = struct { \ 0087 char dummy_[2]; \ 0088 }; \ 0089 \ 0090 template<typename U> \ 0091 static True helper(helperClass<decltype(fun(std::declval<T>()))> *); \ 0092 template<typename> \ 0093 static False helper(...); \ 0094 \ 0095 public: \ 0096 static constexpr bool value = sizeof(helper<T>(nullptr)) == sizeof(True); \ 0097 }; 0098 0099 // For some obscure reason QList::begin() actually has a default 0100 // argument, but QList::begin() does not, thus a regular hasMethod_* check 0101 // won't cut it here. Instead we check whether the container object can be 0102 // used with std::begin() and std::end() helpers. 0103 // Check for constness can be performed by passing "const T" to the type. 0104 DECLARE_HAS_FUNCTION(begin, std::begin) 0105 DECLARE_HAS_FUNCTION(end, std::end) 0106 0107 /// This is a very incomplete set of Container named requirement, but I'm 0108 /// too lazy to implement all of them, but this should be good enough to match 0109 /// regular Qt containers and /not/ match arbitrary non-container types 0110 template<typename T> 0111 struct isContainer 0112 : conjunction<std::is_constructible<T>, hasMember_value_type<T>, has_begin<T>, has_begin<const T>, has_end<T>, has_end<const T>, hasMethod_size_const<T>> { 0113 }; 0114 0115 /// Matches anything that is a container and has push_back() method. 0116 template<typename T> 0117 struct isAppendable : conjunction<isContainer<T>, hasMethod_push_back<T>> { 0118 }; 0119 0120 /// Matches anything that is a container and has insert() method. 0121 template<typename T> 0122 struct isInsertable : conjunction<isContainer<T>, hasMethod_insert<T>> { 0123 }; 0124 0125 /// Matches anything that is a container and has reserve() method. 0126 template<typename T> 0127 struct isReservable : conjunction<isContainer<T>, hasMethod_reserve<T>> { 0128 }; 0129 } 0130 0131 template<typename T> 0132 constexpr bool isAppendable = detail::isAppendable<T>::value; 0133 0134 template<typename T> 0135 constexpr bool isInsertable = detail::isInsertable<T>::value; 0136 0137 template<typename T> 0138 constexpr bool isReservable = detail::isReservable<T>::value; 0139 0140 } // namespace AkTraits 0141 0142 #define AK_PP_CAT_(X, Y) X##Y 0143 #define AK_PP_CAT(X, Y) AK_PP_CAT_(X, Y) 0144 0145 #define AK_REQUIRES(...) bool AK_PP_CAT(_ak_requires_, __LINE__) = false, std::enable_if_t < AK_PP_CAT(_ak_requires_, __LINE__) || (__VA_ARGS__) > * = nullptr