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