Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-09-18 09:26:51

0001 // Copyright (C) 2022 The Qt Company Ltd.
0002 // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
0003 
0004 #ifndef QTTYPETRAITS_H
0005 #define QTTYPETRAITS_H
0006 
0007 #include <QtCore/qtconfigmacros.h>
0008 #include <QtCore/qtdeprecationmarkers.h>
0009 
0010 #if defined(__cpp_lib_three_way_comparison) && defined(__cpp_lib_concepts)
0011 #include <compare>
0012 #include <concepts>
0013 #endif
0014 #include <optional>
0015 #include <tuple>
0016 #include <type_traits>
0017 #include <utility>
0018 #include <variant>
0019 
0020 #if 0
0021 #pragma qt_class(QtTypeTraits)
0022 #pragma qt_sync_stop_processing
0023 #endif
0024 
0025 QT_BEGIN_NAMESPACE
0026 
0027 // like std::to_underlying
0028 template <typename Enum>
0029 constexpr std::underlying_type_t<Enum> qToUnderlying(Enum e) noexcept
0030 {
0031     return static_cast<std::underlying_type_t<Enum>>(e);
0032 }
0033 
0034 #ifndef QT_NO_QASCONST
0035 #if QT_DEPRECATED_SINCE(6, 6)
0036 
0037 // this adds const to non-const objects (like std::as_const)
0038 template <typename T>
0039 QT_DEPRECATED_VERSION_X_6_6("Use std::as_const() instead.")
0040 constexpr typename std::add_const<T>::type &qAsConst(T &t) noexcept { return t; }
0041 // prevent rvalue arguments:
0042 template <typename T>
0043 void qAsConst(const T &&) = delete;
0044 
0045 #endif // QT_DEPRECATED_SINCE(6, 6)
0046 #endif // QT_NO_QASCONST
0047 
0048 #ifndef QT_NO_QEXCHANGE
0049 
0050 // like std::exchange
0051 template <typename T, typename U = T>
0052 constexpr T qExchange(T &t, U &&newValue)
0053 noexcept(std::conjunction_v<std::is_nothrow_move_constructible<T>,
0054                             std::is_nothrow_assignable<T &, U>>)
0055 {
0056     T old = std::move(t);
0057     t = std::forward<U>(newValue);
0058     return old;
0059 }
0060 
0061 #endif // QT_NO_QEXCHANGE
0062 
0063 namespace QtPrivate {
0064 // helper to be used to trigger a "dependent static_assert(false)"
0065 // (for instance, in a final `else` branch of a `if constexpr`.)
0066 template <typename T> struct type_dependent_false : std::false_type {};
0067 template <auto T> struct value_dependent_false : std::false_type {};
0068 
0069 // helper detects standard integer types and some of extended integer types,
0070 // see https://eel.is/c++draft/basic.fundamental#1
0071 template <typename T> struct is_standard_or_extended_integer_type_helper : std::is_integral<T> {};
0072 // these are integral, but not considered standard or extended integer types
0073 // https://eel.is/c++draft/basic.fundamental#11:
0074 #define QSEIT_EXCLUDE(X) \
0075     template <> struct is_standard_or_extended_integer_type_helper<X> : std::false_type {}
0076 QSEIT_EXCLUDE(bool);
0077 QSEIT_EXCLUDE(char);
0078 #ifdef __cpp_char8_t
0079 QSEIT_EXCLUDE(char8_t);
0080 #endif
0081 QSEIT_EXCLUDE(char16_t);
0082 QSEIT_EXCLUDE(char32_t);
0083 QSEIT_EXCLUDE(wchar_t);
0084 #undef QSEIT_EXCLUDE
0085 template <typename T>
0086 struct is_standard_or_extended_integer_type : is_standard_or_extended_integer_type_helper<std::remove_cv_t<T>> {};
0087 template <typename T>
0088 constexpr bool is_standard_or_extended_integer_type_v = is_standard_or_extended_integer_type<T>::value;
0089 } // QtPrivate
0090 
0091 namespace QTypeTraits {
0092 
0093 namespace detail {
0094 template<typename T, typename U,
0095          typename = std::enable_if_t<std::is_arithmetic_v<T> && std::is_arithmetic_v<U> &&
0096                                      std::is_floating_point_v<T> == std::is_floating_point_v<U> &&
0097                                      std::is_signed_v<T> == std::is_signed_v<U> &&
0098                                      !std::is_same_v<T, bool> && !std::is_same_v<U, bool> &&
0099                                      !std::is_same_v<T, char> && !std::is_same_v<U, char>>>
0100 struct Promoted
0101 {
0102     using type = decltype(T() + U());
0103 };
0104 }
0105 
0106 template <typename T, typename U>
0107 using Promoted = typename detail::Promoted<T, U>::type;
0108 
0109 /*
0110     The templates below aim to find out whether one can safely instantiate an operator==() or
0111     operator<() for a type.
0112 
0113     This is tricky for containers, as most containers have unconstrained comparison operators, even though they
0114     rely on the corresponding operators for its content.
0115     This is especially true for all of the STL template classes that have a comparison operator defined, and
0116     leads to the situation, that the compiler would try to instantiate the operator, and fail if any
0117     of its template arguments does not have the operator implemented.
0118 
0119     The code tries to cover the relevant cases for Qt and the STL, by checking (recusrsively) the value_type
0120     of a container (if it exists), and checking the template arguments of pair, tuple and variant.
0121 */
0122 namespace detail {
0123 
0124 // find out whether T is a conteiner
0125 // this is required to check the value type of containers for the existence of the comparison operator
0126 template <typename, typename = void>
0127 struct is_container : std::false_type {};
0128 template <typename T>
0129 struct is_container<T, std::void_t<
0130         typename T::value_type,
0131         std::is_convertible<decltype(std::declval<T>().begin() != std::declval<T>().end()), bool>
0132 >> : std::true_type {};
0133 
0134 
0135 // Checks the existence of the comparison operator for the class itself
0136 QT_WARNING_PUSH
0137 QT_WARNING_DISABLE_FLOAT_COMPARE
0138 template <typename, typename = void>
0139 struct has_operator_equal : std::false_type {};
0140 template <typename T>
0141 struct has_operator_equal<T, std::void_t<decltype(bool(std::declval<const T&>() == std::declval<const T&>()))>>
0142         : std::true_type {};
0143 QT_WARNING_POP
0144 
0145 // Two forward declarations
0146 template<typename T, bool = is_container<T>::value>
0147 struct expand_operator_equal_container;
0148 template<typename T>
0149 struct expand_operator_equal_tuple;
0150 
0151 // the entry point for the public method
0152 template<typename T>
0153 using expand_operator_equal = expand_operator_equal_container<T>;
0154 
0155 // if T isn't a container check if it's a tuple like object
0156 template<typename T, bool>
0157 struct expand_operator_equal_container : expand_operator_equal_tuple<T> {};
0158 // if T::value_type exists, check first T::value_type, then T itself
0159 template<typename T>
0160 struct expand_operator_equal_container<T, true> :
0161         std::conjunction<
0162         std::disjunction<
0163             std::is_same<T, typename T::value_type>, // avoid endless recursion
0164             expand_operator_equal<typename T::value_type>
0165         >, expand_operator_equal_tuple<T>> {};
0166 
0167 // recursively check the template arguments of a tuple like object
0168 template<typename ...T>
0169 using expand_operator_equal_recursive = std::conjunction<expand_operator_equal<T>...>;
0170 
0171 template<typename T>
0172 struct expand_operator_equal_tuple : has_operator_equal<T> {};
0173 template<typename T>
0174 struct expand_operator_equal_tuple<std::optional<T>> : expand_operator_equal_recursive<T> {};
0175 template<typename T1, typename T2>
0176 struct expand_operator_equal_tuple<std::pair<T1, T2>> : expand_operator_equal_recursive<T1, T2> {};
0177 template<typename ...T>
0178 struct expand_operator_equal_tuple<std::tuple<T...>> : expand_operator_equal_recursive<T...> {};
0179 template<typename ...T>
0180 struct expand_operator_equal_tuple<std::variant<T...>> : expand_operator_equal_recursive<T...> {};
0181 
0182 // the same for operator<(), see above for explanations
0183 template <typename, typename = void>
0184 struct has_operator_less_than : std::false_type{};
0185 template <typename T>
0186 struct has_operator_less_than<T, std::void_t<decltype(bool(std::declval<const T&>() < std::declval<const T&>()))>>
0187         : std::true_type{};
0188 
0189 template<typename T, bool = is_container<T>::value>
0190 struct expand_operator_less_than_container;
0191 template<typename T>
0192 struct expand_operator_less_than_tuple;
0193 
0194 template<typename T>
0195 using expand_operator_less_than = expand_operator_less_than_container<T>;
0196 
0197 template<typename T, bool>
0198 struct expand_operator_less_than_container : expand_operator_less_than_tuple<T> {};
0199 template<typename T>
0200 struct expand_operator_less_than_container<T, true> :
0201         std::conjunction<
0202             std::disjunction<
0203                 std::is_same<T, typename T::value_type>,
0204                 expand_operator_less_than<typename T::value_type>
0205             >, expand_operator_less_than_tuple<T>
0206         > {};
0207 
0208 template<typename ...T>
0209 using expand_operator_less_than_recursive = std::conjunction<expand_operator_less_than<T>...>;
0210 
0211 template<typename T>
0212 struct expand_operator_less_than_tuple : has_operator_less_than<T> {};
0213 template<typename T>
0214 struct expand_operator_less_than_tuple<std::optional<T>> : expand_operator_less_than_recursive<T> {};
0215 template<typename T1, typename T2>
0216 struct expand_operator_less_than_tuple<std::pair<T1, T2>> : expand_operator_less_than_recursive<T1, T2> {};
0217 template<typename ...T>
0218 struct expand_operator_less_than_tuple<std::tuple<T...>> : expand_operator_less_than_recursive<T...> {};
0219 template<typename ...T>
0220 struct expand_operator_less_than_tuple<std::variant<T...>> : expand_operator_less_than_recursive<T...> {};
0221 
0222 } // namespace detail
0223 
0224 template<typename T, typename = void>
0225 struct is_dereferenceable : std::false_type {};
0226 
0227 template<typename T>
0228 struct is_dereferenceable<T, std::void_t<decltype(std::declval<T>().operator->())> >
0229     : std::true_type {};
0230 
0231 template <typename T>
0232 inline constexpr bool is_dereferenceable_v = is_dereferenceable<T>::value;
0233 
0234 template<typename T>
0235 struct has_operator_equal : detail::expand_operator_equal<T> {};
0236 template<typename T>
0237 inline constexpr bool has_operator_equal_v = has_operator_equal<T>::value;
0238 
0239 template <typename Container, typename T>
0240 using has_operator_equal_container = std::disjunction<std::is_base_of<Container, T>, QTypeTraits::has_operator_equal<T>>;
0241 
0242 template<typename T>
0243 struct has_operator_less_than : detail::expand_operator_less_than<T> {};
0244 template<typename T>
0245 inline constexpr bool has_operator_less_than_v = has_operator_less_than<T>::value;
0246 
0247 template <typename Container, typename T>
0248 using has_operator_less_than_container = std::disjunction<std::is_base_of<Container, T>, QTypeTraits::has_operator_less_than<T>>;
0249 
0250 template <typename ...T>
0251 using compare_eq_result = std::enable_if_t<std::conjunction_v<QTypeTraits::has_operator_equal<T>...>, bool>;
0252 
0253 template <typename Container, typename ...T>
0254 using compare_eq_result_container = std::enable_if_t<std::conjunction_v<QTypeTraits::has_operator_equal_container<Container, T>...>, bool>;
0255 
0256 template <typename ...T>
0257 using compare_lt_result = std::enable_if_t<std::conjunction_v<QTypeTraits::has_operator_less_than<T>...>, bool>;
0258 
0259 template <typename Container, typename ...T>
0260 using compare_lt_result_container = std::enable_if_t<std::conjunction_v<QTypeTraits::has_operator_less_than_container<Container, T>...>, bool>;
0261 
0262 template<typename T>
0263 struct has_operator_compare_three_way : std::false_type {};
0264 template <typename T, typename U>
0265 struct has_operator_compare_three_way_with : std::false_type {};
0266 #if defined(__cpp_lib_three_way_comparison) && defined(__cpp_lib_concepts)
0267 template<std::three_way_comparable T>
0268 struct has_operator_compare_three_way<T> : std::true_type {};
0269 template <typename T, typename U>
0270     requires std::three_way_comparable_with<T, U>
0271 struct has_operator_compare_three_way_with<T, U> : std::true_type {};
0272 #endif // __cpp_lib_three_way_comparison && __cpp_lib_concepts
0273 template<typename T>
0274 constexpr inline bool has_operator_compare_three_way_v = has_operator_compare_three_way<T>::value;
0275 template<typename T, typename U>
0276 constexpr inline bool has_operator_compare_three_way_with_v = has_operator_compare_three_way_with<T, U>::value;
0277 
0278 // Intentionally no 'has_operator_compare_three_way_container', because the
0279 // compilers fail to determine the proper return type in this case
0280 // template <typename Container, typename T>
0281 // using has_operator_compare_three_way_container =
0282 //         std::disjunction<std::is_base_of<Container, T>, has_operator_compare_three_way<T>>;
0283 
0284 namespace detail {
0285 
0286 template<typename T>
0287 const T &const_reference();
0288 template<typename T>
0289 T &reference();
0290 
0291 }
0292 
0293 template <typename Stream, typename, typename = void>
0294 struct has_ostream_operator : std::false_type {};
0295 template <typename Stream, typename T>
0296 struct has_ostream_operator<Stream, T, std::void_t<decltype(detail::reference<Stream>() << detail::const_reference<T>())>>
0297         : std::true_type {};
0298 template <typename Stream, typename T>
0299 inline constexpr bool has_ostream_operator_v = has_ostream_operator<Stream, T>::value;
0300 
0301 template <typename Stream, typename Container, typename T>
0302 using has_ostream_operator_container = std::disjunction<std::is_base_of<Container, T>, QTypeTraits::has_ostream_operator<Stream, T>>;
0303 
0304 template <typename Stream, typename, typename = void>
0305 struct has_istream_operator : std::false_type {};
0306 template <typename Stream, typename T>
0307 struct has_istream_operator<Stream, T, std::void_t<decltype(detail::reference<Stream>() >> detail::reference<T>())>>
0308         : std::true_type {};
0309 template <typename Stream, typename T>
0310 inline constexpr bool has_istream_operator_v = has_istream_operator<Stream, T>::value;
0311 template <typename Stream, typename Container, typename T>
0312 using has_istream_operator_container = std::disjunction<std::is_base_of<Container, T>, QTypeTraits::has_istream_operator<Stream, T>>;
0313 
0314 template <typename Stream, typename T>
0315 inline constexpr bool has_stream_operator_v = has_ostream_operator_v<Stream, T> && has_istream_operator_v<Stream, T>;
0316 
0317 } // namespace QTypeTraits
0318 
0319 QT_END_NAMESPACE
0320 
0321 #endif // QTTYPETRAITS_H