Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-18 10:07:40

0001 // Copyright (C) 2016 The Qt Company Ltd.
0002 // Copyright (C) 2016 Intel Corporation.
0003 // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
0004 
0005 #ifndef QTYPEINFO_H
0006 #define QTYPEINFO_H
0007 
0008 #include <QtCore/qcompilerdetection.h>
0009 #include <QtCore/qcontainerfwd.h>
0010 
0011 #include <variant>
0012 #include <optional>
0013 #include <tuple>
0014 #include <type_traits>
0015 
0016 QT_BEGIN_NAMESPACE
0017 
0018 class QDebug;
0019 
0020 /*
0021    QTypeInfo     - type trait functionality
0022 */
0023 
0024 namespace QtPrivate {
0025 
0026 template <typename T>
0027 inline constexpr bool qIsRelocatable =  std::is_trivially_copyable_v<T> && std::is_trivially_destructible_v<T>;
0028 
0029 // Denotes types that are trivially default constructible, and for which
0030 // value-initialization can be achieved by filling their storage with 0 bits.
0031 // There is no type trait we can use for this, so we hardcode a list of
0032 // possibilities that we know are OK on the architectures that we support.
0033 // The most notable exception are pointers to data members, which for instance
0034 // on the Itanium ABI are initialized to -1.
0035 template <typename T>
0036 inline constexpr bool qIsValueInitializationBitwiseZero =
0037         std::is_scalar_v<T> && !std::is_member_object_pointer_v<T>;
0038 
0039 }
0040 
0041 /*
0042   The catch-all template.
0043 */
0044 
0045 template <typename T>
0046 class QTypeInfo
0047 {
0048 public:
0049     enum {
0050         isPointer [[deprecated("Use std::is_pointer instead")]] = std::is_pointer_v<T>,
0051         isIntegral [[deprecated("Use std::is_integral instead")]] = std::is_integral_v<T>,
0052         isComplex = !std::is_trivial_v<T>,
0053         isRelocatable = QtPrivate::qIsRelocatable<T>,
0054         isValueInitializationBitwiseZero = QtPrivate::qIsValueInitializationBitwiseZero<T>,
0055     };
0056 };
0057 
0058 template<>
0059 class QTypeInfo<void>
0060 {
0061 public:
0062     enum {
0063         isPointer [[deprecated("Use std::is_pointer instead")]] = false,
0064         isIntegral [[deprecated("Use std::is_integral instead")]] = false,
0065         isComplex = false,
0066         isRelocatable = false,
0067         isValueInitializationBitwiseZero = false,
0068     };
0069 };
0070 
0071 /*!
0072     \class QTypeInfoMerger
0073     \inmodule QtCore
0074     \internal
0075 
0076     \brief QTypeInfoMerger merges the QTypeInfo flags of T1, T2... and presents them
0077     as a QTypeInfo<T> would do.
0078 
0079     Let's assume that we have a simple set of structs:
0080 
0081     \snippet code/src_corelib_global_qglobal.cpp 50
0082 
0083     To create a proper QTypeInfo specialization for A struct, we have to check
0084     all sub-components; B, C and D, then take the lowest common denominator and call
0085     Q_DECLARE_TYPEINFO with the resulting flags. An easier and less fragile approach is to
0086     use QTypeInfoMerger, which does that automatically. So struct A would have
0087     the following QTypeInfo definition:
0088 
0089     \snippet code/src_corelib_global_qglobal.cpp 51
0090 */
0091 template <class T, class...Ts>
0092 class QTypeInfoMerger
0093 {
0094     static_assert(sizeof...(Ts) > 0);
0095 public:
0096     static constexpr bool isComplex = ((QTypeInfo<Ts>::isComplex) || ...);
0097     static constexpr bool isRelocatable = ((QTypeInfo<Ts>::isRelocatable) && ...);
0098     [[deprecated("Use std::is_pointer instead")]] static constexpr bool isPointer = false;
0099     [[deprecated("Use std::is_integral instead")]] static constexpr bool isIntegral = false;
0100     static constexpr bool isValueInitializationBitwiseZero = false;
0101     static_assert(!isRelocatable ||
0102                   std::is_copy_constructible_v<T> ||
0103                   std::is_move_constructible_v<T>,
0104                   "All Ts... are Q_RELOCATABLE_TYPE, but T is neither copy- nor move-constructible, "
0105                   "so cannot be Q_RELOCATABLE_TYPE. Please mark T as Q_COMPLEX_TYPE manually.");
0106 };
0107 
0108 // QTypeInfo for std::pair:
0109 //   std::pair is spec'ed to be struct { T1 first; T2 second; }, so, unlike tuple<>,
0110 //   we _can_ specialize QTypeInfo for pair<>:
0111 template <class T1, class T2>
0112 class QTypeInfo<std::pair<T1, T2>> : public QTypeInfoMerger<std::pair<T1, T2>, T1, T2> {};
0113 
0114 #define Q_DECLARE_MOVABLE_CONTAINER(CONTAINER) \
0115 template <typename ...T> \
0116 class QTypeInfo<CONTAINER<T...>> \
0117 { \
0118 public: \
0119     enum { \
0120         isPointer [[deprecated("Use std::is_pointer instead")]] = false, \
0121         isIntegral [[deprecated("Use std::is_integral instead")]] = false, \
0122         isComplex = true, \
0123         isRelocatable = true, \
0124         isValueInitializationBitwiseZero = false, \
0125     }; \
0126 }
0127 
0128 Q_DECLARE_MOVABLE_CONTAINER(QList);
0129 Q_DECLARE_MOVABLE_CONTAINER(QQueue);
0130 Q_DECLARE_MOVABLE_CONTAINER(QStack);
0131 Q_DECLARE_MOVABLE_CONTAINER(QSet);
0132 Q_DECLARE_MOVABLE_CONTAINER(QMap);
0133 Q_DECLARE_MOVABLE_CONTAINER(QMultiMap);
0134 Q_DECLARE_MOVABLE_CONTAINER(QHash);
0135 Q_DECLARE_MOVABLE_CONTAINER(QMultiHash);
0136 Q_DECLARE_MOVABLE_CONTAINER(QCache);
0137 
0138 #undef Q_DECLARE_MOVABLE_CONTAINER
0139 
0140 /*
0141    Specialize a specific type with:
0142 
0143      Q_DECLARE_TYPEINFO(type, flags);
0144 
0145    where 'type' is the name of the type to specialize and 'flags' is
0146    logically-OR'ed combination of the flags below.
0147 */
0148 enum { /* TYPEINFO flags */
0149     Q_COMPLEX_TYPE = 0,
0150     Q_PRIMITIVE_TYPE = 0x1,
0151     Q_RELOCATABLE_TYPE = 0x2,
0152     Q_MOVABLE_TYPE = 0x2,
0153     Q_DUMMY_TYPE = 0x4,
0154 };
0155 
0156 #define Q_DECLARE_TYPEINFO_BODY(TYPE, FLAGS) \
0157 class QTypeInfo<TYPE > \
0158 { \
0159 public: \
0160     enum { \
0161         isComplex = (((FLAGS) & Q_PRIMITIVE_TYPE) == 0) && !std::is_trivial_v<TYPE>, \
0162         isRelocatable = !isComplex || ((FLAGS) & Q_RELOCATABLE_TYPE) || QtPrivate::qIsRelocatable<TYPE>, \
0163         isPointer [[deprecated("Use std::is_pointer instead")]] = std::is_pointer_v< TYPE >, \
0164         isIntegral [[deprecated("Use std::is_integral instead")]] = std::is_integral< TYPE >::value, \
0165         isValueInitializationBitwiseZero = QtPrivate::qIsValueInitializationBitwiseZero<TYPE>, \
0166     }; \
0167     static_assert(!isRelocatable || \
0168                   std::is_copy_constructible_v<TYPE > || \
0169                   std::is_move_constructible_v<TYPE >, \
0170                   #TYPE " is neither copy- nor move-constructible, so cannot be Q_RELOCATABLE_TYPE"); \
0171 }
0172 
0173 #define Q_DECLARE_TYPEINFO(TYPE, FLAGS) \
0174 template<> \
0175 Q_DECLARE_TYPEINFO_BODY(TYPE, FLAGS)
0176 
0177 /* Specialize QTypeInfo for QFlags<T> */
0178 template<typename T> class QFlags;
0179 template<typename T>
0180 Q_DECLARE_TYPEINFO_BODY(QFlags<T>, Q_PRIMITIVE_TYPE);
0181 
0182 namespace QTypeTraits
0183 {
0184 
0185 /*
0186     The templates below aim to find out whether one can safely instantiate an operator==() or
0187     operator<() for a type.
0188 
0189     This is tricky for containers, as most containers have unconstrained comparison operators, even though they
0190     rely on the corresponding operators for its content.
0191     This is especially true for all of the STL template classes that have a comparison operator defined, and
0192     leads to the situation, that the compiler would try to instantiate the operator, and fail if any
0193     of its template arguments does not have the operator implemented.
0194 
0195     The code tries to cover the relevant cases for Qt and the STL, by checking (recusrsively) the value_type
0196     of a container (if it exists), and checking the template arguments of pair, tuple and variant.
0197 */
0198 namespace detail {
0199 
0200 // find out whether T is a conteiner
0201 // this is required to check the value type of containers for the existence of the comparison operator
0202 template <typename, typename = void>
0203 struct is_container : std::false_type {};
0204 template <typename T>
0205 struct is_container<T, std::void_t<
0206         typename T::value_type,
0207         std::is_convertible<decltype(std::declval<T>().begin() != std::declval<T>().end()), bool>
0208 >> : std::true_type {};
0209 
0210 
0211 // Checks the existence of the comparison operator for the class itself
0212 QT_WARNING_PUSH
0213 QT_WARNING_DISABLE_FLOAT_COMPARE
0214 template <typename, typename = void>
0215 struct has_operator_equal : std::false_type {};
0216 template <typename T>
0217 struct has_operator_equal<T, std::void_t<decltype(bool(std::declval<const T&>() == std::declval<const T&>()))>>
0218         : std::true_type {};
0219 QT_WARNING_POP
0220 
0221 // Two forward declarations
0222 template<typename T, bool = is_container<T>::value>
0223 struct expand_operator_equal_container;
0224 template<typename T>
0225 struct expand_operator_equal_tuple;
0226 
0227 // the entry point for the public method
0228 template<typename T>
0229 using expand_operator_equal = expand_operator_equal_container<T>;
0230 
0231 // if T isn't a container check if it's a tuple like object
0232 template<typename T, bool>
0233 struct expand_operator_equal_container : expand_operator_equal_tuple<T> {};
0234 // if T::value_type exists, check first T::value_type, then T itself
0235 template<typename T>
0236 struct expand_operator_equal_container<T, true> :
0237         std::conjunction<
0238         std::disjunction<
0239             std::is_same<T, typename T::value_type>, // avoid endless recursion
0240             expand_operator_equal<typename T::value_type>
0241         >, expand_operator_equal_tuple<T>> {};
0242 
0243 // recursively check the template arguments of a tuple like object
0244 template<typename ...T>
0245 using expand_operator_equal_recursive = std::conjunction<expand_operator_equal<T>...>;
0246 
0247 template<typename T>
0248 struct expand_operator_equal_tuple : has_operator_equal<T> {};
0249 template<typename T>
0250 struct expand_operator_equal_tuple<std::optional<T>> : expand_operator_equal_recursive<T> {};
0251 template<typename T1, typename T2>
0252 struct expand_operator_equal_tuple<std::pair<T1, T2>> : expand_operator_equal_recursive<T1, T2> {};
0253 template<typename ...T>
0254 struct expand_operator_equal_tuple<std::tuple<T...>> : expand_operator_equal_recursive<T...> {};
0255 template<typename ...T>
0256 struct expand_operator_equal_tuple<std::variant<T...>> : expand_operator_equal_recursive<T...> {};
0257 
0258 // the same for operator<(), see above for explanations
0259 template <typename, typename = void>
0260 struct has_operator_less_than : std::false_type{};
0261 template <typename T>
0262 struct has_operator_less_than<T, std::void_t<decltype(bool(std::declval<const T&>() < std::declval<const T&>()))>>
0263         : std::true_type{};
0264 
0265 template<typename T, bool = is_container<T>::value>
0266 struct expand_operator_less_than_container;
0267 template<typename T>
0268 struct expand_operator_less_than_tuple;
0269 
0270 template<typename T>
0271 using expand_operator_less_than = expand_operator_less_than_container<T>;
0272 
0273 template<typename T, bool>
0274 struct expand_operator_less_than_container : expand_operator_less_than_tuple<T> {};
0275 template<typename T>
0276 struct expand_operator_less_than_container<T, true> :
0277         std::conjunction<
0278             std::disjunction<
0279                 std::is_same<T, typename T::value_type>,
0280                 expand_operator_less_than<typename T::value_type>
0281             >, expand_operator_less_than_tuple<T>
0282         > {};
0283 
0284 template<typename ...T>
0285 using expand_operator_less_than_recursive = std::conjunction<expand_operator_less_than<T>...>;
0286 
0287 template<typename T>
0288 struct expand_operator_less_than_tuple : has_operator_less_than<T> {};
0289 template<typename T>
0290 struct expand_operator_less_than_tuple<std::optional<T>> : expand_operator_less_than_recursive<T> {};
0291 template<typename T1, typename T2>
0292 struct expand_operator_less_than_tuple<std::pair<T1, T2>> : expand_operator_less_than_recursive<T1, T2> {};
0293 template<typename ...T>
0294 struct expand_operator_less_than_tuple<std::tuple<T...>> : expand_operator_less_than_recursive<T...> {};
0295 template<typename ...T>
0296 struct expand_operator_less_than_tuple<std::variant<T...>> : expand_operator_less_than_recursive<T...> {};
0297 
0298 }
0299 
0300 template<typename T, typename = void>
0301 struct is_dereferenceable : std::false_type {};
0302 
0303 template<typename T>
0304 struct is_dereferenceable<T, std::void_t<decltype(std::declval<T>().operator->())> >
0305     : std::true_type {};
0306 
0307 template <typename T>
0308 inline constexpr bool is_dereferenceable_v = is_dereferenceable<T>::value;
0309 
0310 template<typename T>
0311 struct has_operator_equal : detail::expand_operator_equal<T> {};
0312 template<typename T>
0313 inline constexpr bool has_operator_equal_v = has_operator_equal<T>::value;
0314 
0315 template <typename Container, typename T>
0316 using has_operator_equal_container = std::disjunction<std::is_base_of<Container, T>, QTypeTraits::has_operator_equal<T>>;
0317 
0318 template<typename T>
0319 struct has_operator_less_than : detail::expand_operator_less_than<T> {};
0320 template<typename T>
0321 inline constexpr bool has_operator_less_than_v = has_operator_less_than<T>::value;
0322 
0323 template <typename Container, typename T>
0324 using has_operator_less_than_container = std::disjunction<std::is_base_of<Container, T>, QTypeTraits::has_operator_less_than<T>>;
0325 
0326 template <typename ...T>
0327 using compare_eq_result = std::enable_if_t<std::conjunction_v<QTypeTraits::has_operator_equal<T>...>, bool>;
0328 
0329 template <typename Container, typename ...T>
0330 using compare_eq_result_container = std::enable_if_t<std::conjunction_v<QTypeTraits::has_operator_equal_container<Container, T>...>, bool>;
0331 
0332 template <typename ...T>
0333 using compare_lt_result = std::enable_if_t<std::conjunction_v<QTypeTraits::has_operator_less_than<T>...>, bool>;
0334 
0335 template <typename Container, typename ...T>
0336 using compare_lt_result_container = std::enable_if_t<std::conjunction_v<QTypeTraits::has_operator_less_than_container<Container, T>...>, bool>;
0337 
0338 namespace detail {
0339 
0340 template<typename T>
0341 const T &const_reference();
0342 template<typename T>
0343 T &reference();
0344 
0345 }
0346 
0347 template <typename Stream, typename, typename = void>
0348 struct has_ostream_operator : std::false_type {};
0349 template <typename Stream, typename T>
0350 struct has_ostream_operator<Stream, T, std::void_t<decltype(detail::reference<Stream>() << detail::const_reference<T>())>>
0351         : std::true_type {};
0352 template <typename Stream, typename T>
0353 inline constexpr bool has_ostream_operator_v = has_ostream_operator<Stream, T>::value;
0354 
0355 template <typename Stream, typename Container, typename T>
0356 using has_ostream_operator_container = std::disjunction<std::is_base_of<Container, T>, QTypeTraits::has_ostream_operator<Stream, T>>;
0357 
0358 template <typename Stream, typename, typename = void>
0359 struct has_istream_operator : std::false_type {};
0360 template <typename Stream, typename T>
0361 struct has_istream_operator<Stream, T, std::void_t<decltype(detail::reference<Stream>() >> detail::reference<T>())>>
0362         : std::true_type {};
0363 template <typename Stream, typename T>
0364 inline constexpr bool has_istream_operator_v = has_istream_operator<Stream, T>::value;
0365 template <typename Stream, typename Container, typename T>
0366 using has_istream_operator_container = std::disjunction<std::is_base_of<Container, T>, QTypeTraits::has_istream_operator<Stream, T>>;
0367 
0368 template <typename Stream, typename T>
0369 inline constexpr bool has_stream_operator_v = has_ostream_operator_v<Stream, T> && has_istream_operator_v<Stream, T>;
0370 
0371 }
0372 
0373 
0374 QT_END_NAMESPACE
0375 #endif // QTYPEINFO_H