Qt
Internal/Contributor docs for the Qt SDK. <b>Note:</b> These are NOT official API docs; those are found <a href='https://doc.qt.io/'>here</a>.
Loading...
Searching...
No Matches
qcomparehelpers.h
Go to the documentation of this file.
1// Copyright (C) 2023 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
4#ifndef QCOMPARE_H
5#error "Do not include qcomparehelpers.h directly. Use qcompare.h instead."
6#endif
7
8#ifndef QCOMPAREHELPERS_H
9#define QCOMPAREHELPERS_H
10
11#if 0
12#pragma qt_no_master_include
13#pragma qt_sync_skip_header_check
14#pragma qt_sync_stop_processing
15#endif
16
17#include <QtCore/qoverload.h>
18#include <QtCore/qttypetraits.h>
19#include <QtCore/qtypeinfo.h>
20#include <QtCore/qtypes.h>
21
22#ifdef __cpp_lib_three_way_comparison
23#include <compare>
24#endif
25#include <QtCore/q20type_traits.h>
26
27#include <functional> // std::less, std::hash
28
30
32
33namespace QtOrderingPrivate {
34#ifdef __cpp_lib_three_way_comparison
35
36template <typename QtOrdering> struct StdOrdering;
37template <typename StdOrdering> struct QtOrdering;
38
39#define QT_STD_MAP(x) \
40 template <> struct StdOrdering< Qt::x##_ordering> : q20::type_identity<std::x##_ordering> {};\
41 template <> struct StdOrdering<std::x##_ordering> : q20::type_identity<std::x##_ordering> {};\
42 template <> struct QtOrdering<std::x##_ordering> : q20::type_identity< Qt::x##_ordering> {};\
43 template <> struct QtOrdering< Qt::x##_ordering> : q20::type_identity< Qt::x##_ordering> {};\
44 /* end */
45QT_STD_MAP(partial)
46QT_STD_MAP(weak)
47QT_STD_MAP(strong)
48#undef QT_STD_MAP
49
50template <> struct StdOrdering<QPartialOrdering> : q20::type_identity<std::partial_ordering> {};
51template <> struct QtOrdering<QPartialOrdering> : q20::type_identity< Qt::partial_ordering> {};
52
53template <typename In> constexpr auto to_std(In in) noexcept
54 -> typename QtOrderingPrivate::StdOrdering<In>::type
55{ return in; }
56
57template <typename In> constexpr auto to_Qt(In in) noexcept
58 -> typename QtOrderingPrivate::QtOrdering<In>::type
59{ return in; }
60
61#endif // __cpp_lib_three_way_comparison
62} // namespace QtOrderingPrivate
63
64/*
65 For all the macros these parameter names are used:
66 * LeftType - the type of the left operand of the comparison
67 * RightType - the type of the right operand of the comparison
68 * Constexpr - must be either constexpr or empty. Defines whether the
69 operator is constexpr or not
70 * Attributes - an optional list of attributes. For example, pass
71 \c QT_ASCII_CAST_WARN when defining comparisons between
72 C-style string and an encoding-aware string type.
73
74 The macros require two helper functions. For operators to be constexpr,
75 these must be constexpr, too. Additionally, other attributes (like
76 Q_<Module>_EXPORT, Q_DECL_CONST_FUNCTION, etc) can be applied to them.
77 Aside from that, their declaration should match:
78 bool comparesEqual(LeftType, RightType) noexcept;
79 ReturnType compareThreeWay(LeftType, RightType) noexcept;
80
81 The ReturnType can be one of Qt::{partial,weak,strong}_ordering. The actual
82 type depends on the macro being used.
83 It makes sense to define the helper functions as hidden friends of the
84 class, so that they could be found via ADL, and don't participate in
85 unintended implicit conversions.
86*/
87
88// Seems that qdoc uses C++20 even when Qt is compiled in C++17 mode.
89// Or at least it defines __cpp_lib_three_way_comparison.
90// Let qdoc see only the C++17 operators for now, because that's what our docs
91// currently describe.
92#if defined(__cpp_lib_three_way_comparison) && !defined(Q_QDOC)
93// C++20 - provide operator==() for equality, and operator<=>() for ordering
94
95#define QT_DECLARE_EQUALITY_OPERATORS_HELPER(LeftType, RightType, Constexpr, Attributes) \
96 Attributes \
97 friend Constexpr bool operator==(LeftType const &lhs, RightType const &rhs) \
98 noexcept(noexcept(comparesEqual(lhs, rhs))) \
99 { return comparesEqual(lhs, rhs); }
100
101#define QT_DECLARE_3WAY_HELPER_STRONG(LeftType, RightType, Constexpr, Attributes) \
102 Attributes \
103 friend Constexpr std::strong_ordering \
104 operator<=>(LeftType const &lhs, RightType const &rhs) \
105 noexcept(noexcept(compareThreeWay(lhs, rhs))) \
106 { \
107 return compareThreeWay(lhs, rhs); \
108 }
109
110#define QT_DECLARE_3WAY_HELPER_WEAK(LeftType, RightType, Constexpr, Attributes) \
111 Attributes \
112 friend Constexpr std::weak_ordering \
113 operator<=>(LeftType const &lhs, RightType const &rhs) \
114 noexcept(noexcept(compareThreeWay(lhs, rhs))) \
115 { \
116 return compareThreeWay(lhs, rhs); \
117 }
118
119#define QT_DECLARE_3WAY_HELPER_PARTIAL(LeftType, RightType, Constexpr, Attributes) \
120 Attributes \
121 friend Constexpr std::partial_ordering \
122 operator<=>(LeftType const &lhs, RightType const &rhs) \
123 noexcept(noexcept(compareThreeWay(lhs, rhs))) \
124 { \
125 return compareThreeWay(lhs, rhs); \
126 }
127
128#define QT_DECLARE_ORDERING_OPERATORS_HELPER(OrderingType, LeftType, RightType, Constexpr, \
129 Attributes) \
130 QT_DECLARE_EQUALITY_OPERATORS_HELPER(LeftType, RightType, Constexpr, Attributes) \
131 QT_DECLARE_3WAY_HELPER_ ## OrderingType (LeftType, RightType, Constexpr, Attributes)
132
133#ifdef Q_COMPILER_LACKS_THREE_WAY_COMPARE_SYMMETRY
134
135// define reversed versions of the operators manually, because buggy MSVC versions do not do it
136#define QT_DECLARE_EQUALITY_OPERATORS_REVERSED_HELPER(LeftType, RightType, Constexpr, Attributes) \
137 Attributes \
138 friend Constexpr bool operator==(RightType const &lhs, LeftType const &rhs) \
139 noexcept(noexcept(comparesEqual(rhs, lhs))) \
140 { return comparesEqual(rhs, lhs); }
141
142#define QT_DECLARE_REVERSED_3WAY_HELPER_STRONG(LeftType, RightType, Constexpr, Attributes) \
143 Attributes \
144 friend Constexpr std::strong_ordering \
145 operator<=>(RightType const &lhs, LeftType const &rhs) \
146 noexcept(noexcept(compareThreeWay(rhs, lhs))) \
147 { \
148 const auto r = compareThreeWay(rhs, lhs); \
149 if (is_gt(r)) return std::strong_ordering::less; \
150 if (is_lt(r)) return std::strong_ordering::greater; \
151 return r; \
152 }
153
154#define QT_DECLARE_REVERSED_3WAY_HELPER_WEAK(LeftType, RightType, Constexpr, Attributes) \
155 Attributes \
156 friend Constexpr std::weak_ordering \
157 operator<=>(RightType const &lhs, LeftType const &rhs) \
158 noexcept(noexcept(compareThreeWay(rhs, lhs))) \
159 { \
160 const auto r = compareThreeWay(rhs, lhs); \
161 if (is_gt(r)) return std::weak_ordering::less; \
162 if (is_lt(r)) return std::weak_ordering::greater; \
163 return r; \
164 }
165
166#define QT_DECLARE_REVERSED_3WAY_HELPER_PARTIAL(LeftType, RightType, Constexpr, Attributes) \
167 Attributes \
168 friend Constexpr std::partial_ordering \
169 operator<=>(RightType const &lhs, LeftType const &rhs) \
170 noexcept(noexcept(compareThreeWay(rhs, lhs))) \
171 { \
172 const auto r = compareThreeWay(rhs, lhs); \
173 if (is_gt(r)) return std::partial_ordering::less; \
174 if (is_lt(r)) return std::partial_ordering::greater; \
175 return r; \
176 }
177
178#define QT_DECLARE_ORDERING_OPERATORS_REVERSED_HELPER(OrderingString, LeftType, RightType, \
179 Constexpr, Attributes) \
180 QT_DECLARE_EQUALITY_OPERATORS_REVERSED_HELPER(LeftType, RightType, Constexpr, Attributes) \
181 QT_DECLARE_REVERSED_3WAY_HELPER_ ## OrderingString (LeftType, RightType, Constexpr, Attributes)
182
183#else
184
185// dummy macros for C++17 compatibility, reversed operators are generated by the compiler
186#define QT_DECLARE_EQUALITY_OPERATORS_REVERSED_HELPER(LeftType, RightType, Constexpr, Attributes)
187#define QT_DECLARE_ORDERING_OPERATORS_REVERSED_HELPER(OrderingString, LeftType, RightType, \
188 Constexpr, Attributes)
189
190#endif // Q_COMPILER_LACKS_THREE_WAY_COMPARE_SYMMETRY
191
192#else
193// C++17 - provide operator==() and operator!=() for equality,
194// and all 4 comparison operators for ordering
195
196#define QT_DECLARE_EQUALITY_OPERATORS_HELPER(LeftType, RightType, Constexpr, Attributes) \
197 Attributes \
198 friend Constexpr bool operator==(LeftType const &lhs, RightType const &rhs) \
199 noexcept(noexcept(comparesEqual(lhs, rhs))) \
200 { return comparesEqual(lhs, rhs); } \
201 Attributes \
202 friend Constexpr bool operator!=(LeftType const &lhs, RightType const &rhs) \
203 noexcept(noexcept(comparesEqual(lhs, rhs))) \
204 { return !comparesEqual(lhs, rhs); }
205
206// Helpers for reversed comparison, using the existing comparesEqual() function.
207#define QT_DECLARE_EQUALITY_OPERATORS_REVERSED_HELPER(LeftType, RightType, Constexpr, Attributes) \
208 Attributes \
209 friend Constexpr bool operator==(RightType const &lhs, LeftType const &rhs) \
210 noexcept(noexcept(comparesEqual(rhs, lhs))) \
211 { return comparesEqual(rhs, lhs); } \
212 Attributes \
213 friend Constexpr bool operator!=(RightType const &lhs, LeftType const &rhs) \
214 noexcept(noexcept(comparesEqual(rhs, lhs))) \
215 { return !comparesEqual(rhs, lhs); }
216
217#define QT_DECLARE_ORDERING_HELPER_TEMPLATE(OrderingType, LeftType, RightType, Constexpr, \
218 Attributes) \
219 Attributes \
220 friend Constexpr bool operator<(LeftType const &lhs, RightType const &rhs) \
221 noexcept(noexcept(compareThreeWay(lhs, rhs))) \
222 { return is_lt(compareThreeWay(lhs, rhs)); } \
223 Attributes \
224 friend Constexpr bool operator>(LeftType const &lhs, RightType const &rhs) \
225 noexcept(noexcept(compareThreeWay(lhs, rhs))) \
226 { return is_gt(compareThreeWay(lhs, rhs)); } \
227 Attributes \
228 friend Constexpr bool operator<=(LeftType const &lhs, RightType const &rhs) \
229 noexcept(noexcept(compareThreeWay(lhs, rhs))) \
230 { return is_lteq(compareThreeWay(lhs, rhs)); } \
231 Attributes \
232 friend Constexpr bool operator>=(LeftType const &lhs, RightType const &rhs) \
233 noexcept(noexcept(compareThreeWay(lhs, rhs))) \
234 { return is_gteq(compareThreeWay(lhs, rhs)); }
235
236#define QT_DECLARE_ORDERING_HELPER_PARTIAL(LeftType, RightType, Constexpr, Attributes) \
237 QT_DECLARE_ORDERING_HELPER_TEMPLATE(Qt::partial_ordering, LeftType, RightType, Constexpr, \
238 Attributes)
239
240#define QT_DECLARE_ORDERING_HELPER_WEAK(LeftType, RightType, Constexpr, Attributes) \
241 QT_DECLARE_ORDERING_HELPER_TEMPLATE(Qt::weak_ordering, LeftType, RightType, Constexpr, \
242 Attributes)
243
244#define QT_DECLARE_ORDERING_HELPER_STRONG(LeftType, RightType, Constexpr, Attributes) \
245 QT_DECLARE_ORDERING_HELPER_TEMPLATE(Qt::strong_ordering, LeftType, RightType, Constexpr, \
246 Attributes)
247
248#define QT_DECLARE_ORDERING_OPERATORS_HELPER(OrderingString, LeftType, RightType, Constexpr, \
249 Attributes) \
250 QT_DECLARE_EQUALITY_OPERATORS_HELPER(LeftType, RightType, Constexpr, Attributes) \
251 QT_DECLARE_ORDERING_HELPER_ ## OrderingString (LeftType, RightType, Constexpr, Attributes)
252
253// Helpers for reversed ordering, using the existing compareThreeWay() function.
254#define QT_DECLARE_REVERSED_ORDERING_HELPER_TEMPLATE(OrderingType, LeftType, RightType, Constexpr, \
255 Attributes) \
256 Attributes \
257 friend Constexpr bool operator<(RightType const &lhs, LeftType const &rhs) \
258 noexcept(noexcept(compareThreeWay(rhs, lhs))) \
259 { return is_gt(compareThreeWay(rhs, lhs)); } \
260 Attributes \
261 friend Constexpr bool operator>(RightType const &lhs, LeftType const &rhs) \
262 noexcept(noexcept(compareThreeWay(rhs, lhs))) \
263 { return is_lt(compareThreeWay(rhs, lhs)); } \
264 Attributes \
265 friend Constexpr bool operator<=(RightType const &lhs, LeftType const &rhs) \
266 noexcept(noexcept(compareThreeWay(rhs, lhs))) \
267 { return is_gteq(compareThreeWay(rhs, lhs)); } \
268 Attributes \
269 friend Constexpr bool operator>=(RightType const &lhs, LeftType const &rhs) \
270 noexcept(noexcept(compareThreeWay(rhs, lhs))) \
271 { return is_lteq(compareThreeWay(rhs, lhs)); }
272
273#define QT_DECLARE_REVERSED_ORDERING_HELPER_PARTIAL(LeftType, RightType, Constexpr, Attributes) \
274 QT_DECLARE_REVERSED_ORDERING_HELPER_TEMPLATE(Qt::partial_ordering, LeftType, RightType, \
275 Constexpr, Attributes)
276
277#define QT_DECLARE_REVERSED_ORDERING_HELPER_WEAK(LeftType, RightType, Constexpr, Attributes) \
278 QT_DECLARE_REVERSED_ORDERING_HELPER_TEMPLATE(Qt::weak_ordering, LeftType, RightType, \
279 Constexpr, Attributes)
280
281#define QT_DECLARE_REVERSED_ORDERING_HELPER_STRONG(LeftType, RightType, Constexpr, Attributes) \
282 QT_DECLARE_REVERSED_ORDERING_HELPER_TEMPLATE(Qt::strong_ordering, LeftType, RightType, \
283 Constexpr, Attributes)
284
285#define QT_DECLARE_ORDERING_OPERATORS_REVERSED_HELPER(OrderingString, LeftType, RightType, \
286 Constexpr, Attributes) \
287 QT_DECLARE_EQUALITY_OPERATORS_REVERSED_HELPER(LeftType, RightType, Constexpr, Attributes) \
288 QT_DECLARE_REVERSED_ORDERING_HELPER_ ## OrderingString (LeftType, RightType, Constexpr, \
289 Attributes)
290
291#endif // __cpp_lib_three_way_comparison
292
293/* Public API starts here */
294
295// Equality operators
296#define QT_DECLARE_EQUALITY_COMPARABLE_1(Type) \
297 QT_DECLARE_EQUALITY_OPERATORS_HELPER(Type, Type, /* non-constexpr */, /* no attributes */)
298
299#define QT_DECLARE_EQUALITY_COMPARABLE_2(LeftType, RightType) \
300 QT_DECLARE_EQUALITY_OPERATORS_HELPER(LeftType, RightType, /* non-constexpr */, \
301 /* no attributes */) \
302 QT_DECLARE_EQUALITY_OPERATORS_REVERSED_HELPER(LeftType, RightType, /* non-constexpr */, \
303 /* no attributes */)
304
305#define QT_DECLARE_EQUALITY_COMPARABLE_3(LeftType, RightType, Attributes) \
306 QT_DECLARE_EQUALITY_OPERATORS_HELPER(LeftType, RightType, /* non-constexpr */, Attributes) \
307 QT_DECLARE_EQUALITY_OPERATORS_REVERSED_HELPER(LeftType, RightType, /* non-constexpr */, \
308 Attributes)
309
310#define Q_DECLARE_EQUALITY_COMPARABLE(...) \
311 QT_OVERLOADED_MACRO(QT_DECLARE_EQUALITY_COMPARABLE, __VA_ARGS__)
312
313#define QT_DECLARE_EQUALITY_COMPARABLE_LITERAL_TYPE_1(Type) \
314 QT_DECLARE_EQUALITY_OPERATORS_HELPER(Type, Type, constexpr, /* no attributes */)
315
316#define QT_DECLARE_EQUALITY_COMPARABLE_LITERAL_TYPE_2(LeftType, RightType) \
317 QT_DECLARE_EQUALITY_OPERATORS_HELPER(LeftType, RightType, constexpr, /* no attributes */) \
318 QT_DECLARE_EQUALITY_OPERATORS_REVERSED_HELPER(LeftType, RightType, constexpr, \
319 /* no attributes */)
320
321#define QT_DECLARE_EQUALITY_COMPARABLE_LITERAL_TYPE_3(LeftType, RightType, Attributes) \
322 QT_DECLARE_EQUALITY_OPERATORS_HELPER(LeftType, RightType, constexpr, Attributes) \
323 QT_DECLARE_EQUALITY_OPERATORS_REVERSED_HELPER(LeftType, RightType, constexpr, Attributes)
324
325#define Q_DECLARE_EQUALITY_COMPARABLE_LITERAL_TYPE(...) \
326 QT_OVERLOADED_MACRO(QT_DECLARE_EQUALITY_COMPARABLE_LITERAL_TYPE, __VA_ARGS__)
327
328// Partial ordering operators
329#define QT_DECLARE_PARTIALLY_ORDERED_1(Type) \
330 QT_DECLARE_ORDERING_OPERATORS_HELPER(PARTIAL, Type, Type, /* non-constexpr */, \
331 /* no attributes */)
332
333#define QT_DECLARE_PARTIALLY_ORDERED_2(LeftType, RightType) \
334 QT_DECLARE_ORDERING_OPERATORS_HELPER(PARTIAL, LeftType, RightType, /* non-constexpr */, \
335 /* no attributes */) \
336 QT_DECLARE_ORDERING_OPERATORS_REVERSED_HELPER(PARTIAL, LeftType, RightType, \
337 /* non-constexpr */, /* no attributes */)
338
339#define QT_DECLARE_PARTIALLY_ORDERED_3(LeftType, RightType, Attributes) \
340 QT_DECLARE_ORDERING_OPERATORS_HELPER(PARTIAL, LeftType, RightType, /* non-constexpr */, \
341 Attributes) \
342 QT_DECLARE_ORDERING_OPERATORS_REVERSED_HELPER(PARTIAL, LeftType, RightType, \
343 /* non-constexpr */, Attributes)
344
345#define Q_DECLARE_PARTIALLY_ORDERED(...) \
346 QT_OVERLOADED_MACRO(QT_DECLARE_PARTIALLY_ORDERED, __VA_ARGS__)
347
348#define QT_DECLARE_PARTIALLY_ORDERED_LITERAL_TYPE_1(Type) \
349 QT_DECLARE_ORDERING_OPERATORS_HELPER(PARTIAL, Type, Type, constexpr, /* no attributes */)
350
351#define QT_DECLARE_PARTIALLY_ORDERED_LITERAL_TYPE_2(LeftType, RightType) \
352 QT_DECLARE_ORDERING_OPERATORS_HELPER(PARTIAL, LeftType, RightType, constexpr, \
353 /* no attributes */) \
354 QT_DECLARE_ORDERING_OPERATORS_REVERSED_HELPER(PARTIAL, LeftType, RightType, constexpr, \
355 /* no attributes */)
356
357#define QT_DECLARE_PARTIALLY_ORDERED_LITERAL_TYPE_3(LeftType, RightType, Attributes) \
358 QT_DECLARE_ORDERING_OPERATORS_HELPER(PARTIAL, LeftType, RightType, constexpr, Attributes) \
359 QT_DECLARE_ORDERING_OPERATORS_REVERSED_HELPER(PARTIAL, LeftType, RightType, constexpr, \
360 Attributes)
361
362#define Q_DECLARE_PARTIALLY_ORDERED_LITERAL_TYPE(...) \
363 QT_OVERLOADED_MACRO(QT_DECLARE_PARTIALLY_ORDERED_LITERAL_TYPE, __VA_ARGS__)
364
365// Weak ordering operators
366#define QT_DECLARE_WEAKLY_ORDERED_1(Type) \
367 QT_DECLARE_ORDERING_OPERATORS_HELPER(WEAK, Type, Type, /* non-constexpr */, /* no attributes */)
368
369#define QT_DECLARE_WEAKLY_ORDERED_2(LeftType, RightType) \
370 QT_DECLARE_ORDERING_OPERATORS_HELPER(WEAK, LeftType, RightType, /* non-constexpr */, \
371 /* no attributes */) \
372 QT_DECLARE_ORDERING_OPERATORS_REVERSED_HELPER(WEAK, LeftType, RightType, /* non-constexpr */, \
373 /* no attributes */)
374
375#define QT_DECLARE_WEAKLY_ORDERED_3(LeftType, RightType, Attributes) \
376 QT_DECLARE_ORDERING_OPERATORS_HELPER(WEAK, LeftType, RightType, /* non-constexpr */, \
377 Attributes) \
378 QT_DECLARE_ORDERING_OPERATORS_REVERSED_HELPER(WEAK, LeftType, RightType, /* non-constexpr */, \
379 Attributes)
380
381#define Q_DECLARE_WEAKLY_ORDERED(...) \
382 QT_OVERLOADED_MACRO(QT_DECLARE_WEAKLY_ORDERED, __VA_ARGS__)
383
384#define QT_DECLARE_WEAKLY_ORDERED_LITERAL_TYPE_1(Type) \
385 QT_DECLARE_ORDERING_OPERATORS_HELPER(WEAK, Type, Type, constexpr, /* no attributes */)
386
387#define QT_DECLARE_WEAKLY_ORDERED_LITERAL_TYPE_2(LeftType, RightType) \
388 QT_DECLARE_ORDERING_OPERATORS_HELPER(WEAK, LeftType, RightType, constexpr, \
389 /* no attributes */) \
390 QT_DECLARE_ORDERING_OPERATORS_REVERSED_HELPER(WEAK, LeftType, RightType, constexpr, \
391 /* no attributes */)
392
393#define QT_DECLARE_WEAKLY_ORDERED_LITERAL_TYPE_3(LeftType, RightType, Attributes) \
394QT_DECLARE_ORDERING_OPERATORS_HELPER(WEAK, LeftType, RightType, constexpr, Attributes) \
395 QT_DECLARE_ORDERING_OPERATORS_REVERSED_HELPER(WEAK, LeftType, RightType, constexpr, \
396 Attributes)
397
398#define Q_DECLARE_WEAKLY_ORDERED_LITERAL_TYPE(...) \
399 QT_OVERLOADED_MACRO(QT_DECLARE_WEAKLY_ORDERED_LITERAL_TYPE, __VA_ARGS__)
400
401// Strong ordering operators
402#define QT_DECLARE_STRONGLY_ORDERED_1(Type) \
403 QT_DECLARE_ORDERING_OPERATORS_HELPER(STRONG, Type, Type, /* non-constexpr */, \
404 /* no attributes */)
405
406#define QT_DECLARE_STRONGLY_ORDERED_2(LeftType, RightType) \
407 QT_DECLARE_ORDERING_OPERATORS_HELPER(STRONG, LeftType, RightType, /* non-constexpr */, \
408 /* no attributes */) \
409 QT_DECLARE_ORDERING_OPERATORS_REVERSED_HELPER(STRONG, LeftType, RightType, \
410 /* non-constexpr */, /* no attributes */)
411
412#define QT_DECLARE_STRONGLY_ORDERED_3(LeftType, RightType, Attributes) \
413 QT_DECLARE_ORDERING_OPERATORS_HELPER(STRONG, LeftType, RightType, /* non-constexpr */, \
414 Attributes) \
415 QT_DECLARE_ORDERING_OPERATORS_REVERSED_HELPER(STRONG, LeftType, RightType, \
416 /* non-constexpr */, Attributes)
417
418#define Q_DECLARE_STRONGLY_ORDERED(...) \
419 QT_OVERLOADED_MACRO(QT_DECLARE_STRONGLY_ORDERED, __VA_ARGS__)
420
421#define QT_DECLARE_STRONGLY_ORDERED_LITERAL_TYPE_1(Type) \
422 QT_DECLARE_ORDERING_OPERATORS_HELPER(STRONG, Type, Type, constexpr, /* no attributes */)
423
424#define QT_DECLARE_STRONGLY_ORDERED_LITERAL_TYPE_2(LeftType, RightType) \
425 QT_DECLARE_ORDERING_OPERATORS_HELPER(STRONG, LeftType, RightType, constexpr, \
426 /* no attributes */) \
427 QT_DECLARE_ORDERING_OPERATORS_REVERSED_HELPER(STRONG, LeftType, RightType, constexpr, \
428 /* no attributes */)
429
430#define QT_DECLARE_STRONGLY_ORDERED_LITERAL_TYPE_3(LeftType, RightType, Attributes) \
431 QT_DECLARE_ORDERING_OPERATORS_HELPER(STRONG, LeftType, RightType, constexpr, Attributes) \
432 QT_DECLARE_ORDERING_OPERATORS_REVERSED_HELPER(STRONG, LeftType, RightType, constexpr, \
433 Attributes)
434
435#define Q_DECLARE_STRONGLY_ORDERED_LITERAL_TYPE(...) \
436 QT_OVERLOADED_MACRO(QT_DECLARE_STRONGLY_ORDERED_LITERAL_TYPE, __VA_ARGS__)
437
438namespace QtPrivate {
439
440template <typename T>
441constexpr bool IsIntegralType_v = std::numeric_limits<std::remove_const_t<T>>::is_specialized
442 && std::numeric_limits<std::remove_const_t<T>>::is_integer;
443
444template <typename T>
445constexpr bool IsFloatType_v = std::is_floating_point_v<T>;
446
447#if QFLOAT16_IS_NATIVE
448template <>
449constexpr bool IsFloatType_v<QtPrivate::NativeFloat16Type> = true;
450#endif
451
452} // namespace QtPrivate
453
454namespace QtOrderingPrivate {
455
456template <typename T, typename U>
457constexpr Qt::strong_ordering
459{
460#ifdef __cpp_lib_three_way_comparison
461 return lhs <=> rhs;
462#else
463 if (lhs == rhs)
465 else if (lhs < rhs)
467 else
469#endif // __cpp_lib_three_way_comparison
470}
471
472} // namespace QtOrderingPrivate
473
474namespace Qt {
475
476template <typename T>
477using if_integral = std::enable_if_t<QtPrivate::IsIntegralType_v<T>, bool>;
478
479template <typename T>
480using if_floating_point = std::enable_if_t<QtPrivate::IsFloatType_v<T>, bool>;
481
482template <typename T, typename U>
484 std::enable_if_t<std::disjunction_v<std::is_same<T, U>,
485 std::is_base_of<T, U>,
486 std::is_base_of<U, T>>,
487 bool>;
488
489template <typename Enum>
490using if_enum = std::enable_if_t<std::is_enum_v<Enum>, bool>;
491
492template <typename LeftInt, typename RightInt,
493 if_integral<LeftInt> = true,
494 if_integral<RightInt> = true>
495constexpr Qt::strong_ordering compareThreeWay(LeftInt lhs, RightInt rhs) noexcept
496{
497 static_assert(std::is_signed_v<LeftInt> == std::is_signed_v<RightInt>,
498 "Qt::compareThreeWay() does not allow mixed-sign comparison.");
499
500#ifdef __cpp_lib_three_way_comparison
501 return lhs <=> rhs;
502#else
503 if (lhs == rhs)
505 else if (lhs < rhs)
507 else
509#endif // __cpp_lib_three_way_comparison
510}
511
512template <typename LeftFloat, typename RightFloat,
513 if_floating_point<LeftFloat> = true,
514 if_floating_point<RightFloat> = true>
515constexpr Qt::partial_ordering compareThreeWay(LeftFloat lhs, RightFloat rhs) noexcept
516{
519#ifdef __cpp_lib_three_way_comparison
520 return lhs <=> rhs;
521#else
522 if (lhs < rhs)
524 else if (lhs > rhs)
526 else if (lhs == rhs)
528 else
530#endif // __cpp_lib_three_way_comparison
532}
533
534template <typename IntType, typename FloatType,
535 if_integral<IntType> = true,
536 if_floating_point<FloatType> = true>
537constexpr Qt::partial_ordering compareThreeWay(IntType lhs, FloatType rhs) noexcept
538{
539 return compareThreeWay(FloatType(lhs), rhs);
540}
541
542template <typename FloatType, typename IntType,
543 if_floating_point<FloatType> = true,
544 if_integral<IntType> = true>
545constexpr Qt::partial_ordering compareThreeWay(FloatType lhs, IntType rhs) noexcept
546{
547 return compareThreeWay(lhs, FloatType(rhs));
548}
549
550#if QT_DEPRECATED_SINCE(6, 8)
551
552template <typename LeftType, typename RightType,
553 if_compatible_pointers<LeftType, RightType> = true>
554QT_DEPRECATED_VERSION_X_6_8("Wrap the pointers into Qt::totally_ordered_wrapper and use the respective overload instead.")
555constexpr Qt::strong_ordering compareThreeWay(const LeftType *lhs, const RightType *rhs) noexcept
556{
557#ifdef __cpp_lib_three_way_comparison
558 return std::compare_three_way{}(lhs, rhs);
559#else
560 if (lhs == rhs)
562 else if (std::less<>{}(lhs, rhs))
564 else
566#endif // __cpp_lib_three_way_comparison
567}
568
569template <typename T>
570QT_DEPRECATED_VERSION_X_6_8("Wrap the pointer into Qt::totally_ordered_wrapper and use the respective overload instead.")
571constexpr Qt::strong_ordering compareThreeWay(const T *lhs, std::nullptr_t rhs) noexcept
572{
573 return compareThreeWay(lhs, static_cast<const T *>(rhs));
574}
575
576template <typename T>
577QT_DEPRECATED_VERSION_X_6_8("Wrap the pointer into Qt::totally_ordered_wrapper and use the respective overload instead.")
578constexpr Qt::strong_ordering compareThreeWay(std::nullptr_t lhs, const T *rhs) noexcept
579{
580 return compareThreeWay(static_cast<const T *>(lhs), rhs);
581}
582
583#endif // QT_DEPRECATED_SINCE(6, 8)
584
585template <class Enum, if_enum<Enum> = true>
586constexpr Qt::strong_ordering compareThreeWay(Enum lhs, Enum rhs) noexcept
587{
589}
590} // namespace Qt
591
592namespace QtOrderingPrivate {
593
594template <typename Head, typename...Tail, std::size_t...Is>
595constexpr std::tuple<Tail...> qt_tuple_pop_front_impl(const std::tuple<Head, Tail...> &t,
596 std::index_sequence<Is...>) noexcept
597{
598 return std::tuple<Tail...>(std::get<Is + 1>(t)...);
599}
600
601template <typename Head, typename...Tail>
602constexpr std::tuple<Tail...> qt_tuple_pop_front(const std::tuple<Head, Tail...> &t) noexcept
603{
604 return qt_tuple_pop_front_impl(t, std::index_sequence_for<Tail...>{});
605}
606
607template <typename LhsHead, typename...LhsTail, typename RhsHead, typename...RhsTail>
608constexpr auto compareThreeWayMulti(const std::tuple<LhsHead, LhsTail...> &lhs, // ie. not empty
609 const std::tuple<RhsHead, RhsTail...> &rhs) noexcept
610{
611 static_assert(sizeof...(LhsTail) == sizeof...(RhsTail),
612 // expanded together below, but provide a nicer error message:
613 "The tuple arguments have to have the same size.");
614
616 using R = std::common_type_t<
617 decltype(compareThreeWay(std::declval<LhsHead>(), std::declval<RhsHead>())),
618 decltype(compareThreeWay(std::declval<LhsTail>(), std::declval<RhsTail>()))...
619 >;
620
621 const auto &l = std::get<0>(lhs);
622 const auto &r = std::get<0>(rhs);
623 static_assert(noexcept(compareThreeWay(l, r)),
624 "This function requires all relational operators to be noexcept.");
625 const auto res = compareThreeWay(l, r);
626 if constexpr (sizeof...(LhsTail) > 0) {
627 if (is_eq(res))
629 }
630 return R{res};
631}
632
633} //QtOrderingPrivate
634
635namespace Qt {
636// A wrapper class that adapts the wrappee to use the strongly-ordered
637// <functional> function objects for implementing the relational operators.
638// Mostly useful to avoid UB on pointers (which it currently mandates P to be),
639// because all the comparison helpers (incl. std::compare_three_way on
640// std::tuple<T*>!) will use the language-level operators.
641//
642template <typename P>
644{
645 static_assert(std::is_pointer_v<P>);
646 using T = std::remove_pointer_t<P>;
647
648 P ptr;
649public:
650 totally_ordered_wrapper() noexcept = default;
652 // requires std::is_pointer_v<P>
653 : totally_ordered_wrapper(P{nullptr}) {}
654 explicit constexpr totally_ordered_wrapper(P p) noexcept : ptr(p) {}
655
656 constexpr P get() const noexcept { return ptr; }
657 constexpr void reset(P p) noexcept { ptr = p; }
658 constexpr P operator->() const noexcept { return get(); }
659 constexpr T& operator*() const noexcept { return *get(); }
660
661 explicit constexpr operator bool() const noexcept { return get(); }
662
663private:
664 // TODO: Replace the constraints with std::common_type_t<P, U> when
665 // a bug in VxWorks is fixed!
666 template <typename T, typename U>
667 using if_compatible_types =
668 std::enable_if_t<std::conjunction_v<std::is_pointer<T>,
669 std::is_pointer<U>,
670 std::disjunction<std::is_convertible<T, U>,
671 std::is_convertible<U, T>>>,
672 bool>;
673
674#define MAKE_RELOP(Ret, op, Op) \
675 template <typename U = P, if_compatible_types<P, U> = true> \
676 friend constexpr Ret operator op (const totally_ordered_wrapper<P> &lhs, const totally_ordered_wrapper<U> &rhs) noexcept \
677 { return std:: Op {}(lhs.ptr, rhs.get()); } \
678 template <typename U = P, if_compatible_types<P, U> = true> \
679 friend constexpr Ret operator op (const totally_ordered_wrapper<P> &lhs, const U &rhs) noexcept \
680 { return std:: Op {}(lhs.ptr, rhs ); } \
681 template <typename U = P, if_compatible_types<P, U> = true> \
682 friend constexpr Ret operator op (const U &lhs, const totally_ordered_wrapper<P> &rhs) noexcept \
683 { return std:: Op {}(lhs, rhs.ptr); } \
684 friend constexpr Ret operator op (const totally_ordered_wrapper &lhs, std::nullptr_t) noexcept \
685 { return std:: Op {}(lhs.ptr, P(nullptr)); } \
686 friend constexpr Ret operator op (std::nullptr_t, const totally_ordered_wrapper &rhs) noexcept \
687 { return std:: Op {}(P(nullptr), rhs.ptr); } \
688 /* end */
689 MAKE_RELOP(bool, ==, equal_to<>)
690 MAKE_RELOP(bool, !=, not_equal_to<>)
691 MAKE_RELOP(bool, < , less<>)
692 MAKE_RELOP(bool, <=, less_equal<>)
693 MAKE_RELOP(bool, > , greater<>)
694 MAKE_RELOP(bool, >=, greater_equal<>)
695#ifdef __cpp_lib_three_way_comparison
696 MAKE_RELOP(auto, <=>, compare_three_way)
697#endif
698#undef MAKE_RELOP
700 { qt_ptr_swap(lhs.ptr, rhs.ptr); }
701 friend void swap(totally_ordered_wrapper &lhs, totally_ordered_wrapper &rhs) noexcept
702 { qt_ptr_swap(lhs, rhs); }
703 friend size_t qHash(totally_ordered_wrapper key, size_t seed = 0) noexcept
704 { return qHash(key.ptr, seed); }
705};
706
707template <typename T, typename U, if_compatible_pointers<T, U> = true>
708constexpr Qt::strong_ordering
713
714template <typename T, typename U, if_compatible_pointers<T, U> = true>
715constexpr Qt::strong_ordering
720
721template <typename T, typename U, if_compatible_pointers<T, U> = true>
722constexpr Qt::strong_ordering
727
728template <typename T>
729constexpr Qt::strong_ordering
730compareThreeWay(Qt::totally_ordered_wrapper<T*> lhs, std::nullptr_t rhs) noexcept
731{
733}
734
735template <typename T>
736constexpr Qt::strong_ordering
737compareThreeWay(std::nullptr_t lhs, Qt::totally_ordered_wrapper<T*> rhs) noexcept
738{
740}
741
742} //Qt
743
744template <typename P>
745class QTypeInfo<Qt::totally_ordered_wrapper<P>> : public QTypeInfo<P> {};
746
748
749namespace std {
750 template <typename P>
751 struct hash<QT_PREPEND_NAMESPACE(Qt::totally_ordered_wrapper)<P>>
752 {
753 using argument_type = QT_PREPEND_NAMESPACE(Qt::totally_ordered_wrapper)<P>;
754 using result_type = size_t;
755 constexpr result_type operator()(argument_type w) const noexcept
756 { return std::hash<P>{}(w.get()); }
757 };
758}
759
760#endif // QCOMPAREHELPERS_H
\variable Qt::partial_ordering::less
Definition qcompare.h:682
\variable Qt::weak_ordering::less
Definition qcompare.h:69
static const partial_ordering equivalent
Definition qcompare.h:72
static const partial_ordering unordered
Definition qcompare.h:74
static const partial_ordering greater
Definition qcompare.h:73
static const partial_ordering less
Definition qcompare.h:71
\inmodule QtCore \title Classes and helpers for defining comparison operators \keyword qtcompare
Definition qcompare.h:403
static const strong_ordering greater
Definition qcompare.h:408
static const strong_ordering less
Definition qcompare.h:405
static const strong_ordering equivalent
Definition qcompare.h:406
\inmodule QtCore \inheaderfile QtCompare
constexpr void reset(P p) noexcept
totally_ordered_wrapper() noexcept=default
constexpr T & operator*() const noexcept
friend void qt_ptr_swap(totally_ordered_wrapper &lhs, totally_ordered_wrapper &rhs) noexcept
friend void swap(totally_ordered_wrapper &lhs, totally_ordered_wrapper &rhs) noexcept
constexpr P get() const noexcept
constexpr P operator->() const noexcept
friend size_t qHash(totally_ordered_wrapper key, size_t seed=0) noexcept
constexpr totally_ordered_wrapper(P p) noexcept
QHash< int, QWidget * > hash
[35multi]
Combined button and popup list for selecting options.
constexpr std::tuple< Tail... > qt_tuple_pop_front(const std::tuple< Head, Tail... > &t) noexcept
constexpr auto compareThreeWayMulti(const std::tuple< LhsHead, LhsTail... > &lhs, const std::tuple< RhsHead, RhsTail... > &rhs) noexcept
constexpr std::tuple< Tail... > qt_tuple_pop_front_impl(const std::tuple< Head, Tail... > &t, std::index_sequence< Is... >) noexcept
constexpr Qt::strong_ordering strongOrderingCompareDefaultImpl(T lhs, U rhs) noexcept
\macro QT_NO_KEYWORDS >
constexpr bool IsFloatType_v
constexpr bool IsIntegralType_v
Definition qcompare.h:63
std::enable_if_t< std::disjunction_v< std::is_same< T, U >, std::is_base_of< T, U >, std::is_base_of< U, T > >, bool > if_compatible_pointers
std::enable_if_t< QtPrivate::IsIntegralType_v< T >, bool > if_integral
std::enable_if_t< std::is_enum_v< Enum >, bool > if_enum
constexpr Qt::strong_ordering compareThreeWay(LeftInt lhs, RightInt rhs) noexcept
std::enable_if_t< QtPrivate::IsFloatType_v< T >, bool > if_floating_point
#define MAKE_RELOP(Ret, op, Op)
#define QT_WARNING_POP
#define QT_WARNING_DISABLE_FLOAT_COMPARE
#define QT_WARNING_PUSH
#define Q_IMPLICIT
GLuint64 key
GLfloat GLfloat GLfloat w
[0]
GLboolean r
[2]
GLuint res
GLdouble GLdouble t
Definition qopenglext.h:243
GLuint in
GLfloat GLfloat p
[1]
static Q_CONSTINIT QBasicAtomicInteger< unsigned > seed
Definition qrandom.cpp:196
#define QT_DEPRECATED_VERSION_X_6_8(text)
QT_BEGIN_NAMESPACE constexpr std::underlying_type_t< Enum > qToUnderlying(Enum e) noexcept
Qt::weak_ordering compareThreeWay(const QUrl &lhs, const QUrl &rhs)
Definition qurl.cpp:3079
QSharedPointer< int > strong
QT_PREPEND_NAMESPACE(Qt::totally_ordered_wrapper)< P > argument_type
constexpr result_type operator()(argument_type w) const noexcept