Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-08-13 09:22:50

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