File indexing completed on 2025-01-18 10:07:40
0001
0002
0003
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
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
0030
0031
0032
0033
0034
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
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
0073
0074
0075
0076
0077
0078
0079
0080
0081
0082
0083
0084
0085
0086
0087
0088
0089
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
0109
0110
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
0142
0143
0144
0145
0146
0147
0148 enum {
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
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
0187
0188
0189
0190
0191
0192
0193
0194
0195
0196
0197
0198 namespace detail {
0199
0200
0201
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
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
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
0228 template<typename T>
0229 using expand_operator_equal = expand_operator_equal_container<T>;
0230
0231
0232 template<typename T, bool>
0233 struct expand_operator_equal_container : expand_operator_equal_tuple<T> {};
0234
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>,
0240 expand_operator_equal<typename T::value_type>
0241 >, expand_operator_equal_tuple<T>> {};
0242
0243
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
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