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
29QT_BEGIN_NAMESPACE
30
31class QPartialOrdering;
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 * Noexcept - a noexcept specifier. By default the relational operators are
71 expected to be noexcept. However, there are some cases when
72 this cannot be achieved (e.g. QDir). The public macros will
73 pass noexcept(true) or noexcept(false) in this parameter,
74 because conditional noexcept is known to cause some issues.
75 However, internally we might want to pass a predicate here
76 for some specific classes (e.g. QList, etc).
77 * Attributes - an optional list of attributes. For example, pass
78 \c QT_ASCII_CAST_WARN when defining comparisons between
79 C-style string and an encoding-aware string type.
80
81 The macros require two helper functions. For operators to be constexpr,
82 these must be constexpr, too. Additionally, other attributes (like
83 Q_<Module>_EXPORT, Q_DECL_CONST_FUNCTION, etc) can be applied to them.
84 Aside from that, their declaration should match:
85 bool comparesEqual(LeftType, RightType) noexcept;
86 ReturnType compareThreeWay(LeftType, RightType) noexcept;
87
88 The ReturnType can be one of Qt::{partial,weak,strong}_ordering. The actual
89 type depends on the macro being used.
90 It makes sense to define the helper functions as hidden friends of the
91 class, so that they could be found via ADL, and don't participate in
92 unintended implicit conversions.
93*/
94
95/*
96 Some systems (e.g. QNX and Integrity (GHS compiler)) have bugs in
97 handling conditional noexcept in lambdas.
98 This macro is needed to overcome such bugs and provide a noexcept check only
99 on platforms that behave normally.
100 It does nothing on the systems that have problems.
101*/
102#if !defined(Q_OS_QNX) && !defined(Q_CC_GHS)
103# define QT_COMPARISON_NOEXCEPT_CHECK(Noexcept, Func) \
104 constexpr auto f = []() Noexcept {}; \
105 static_assert(!noexcept(f()) || noexcept(Func(lhs, rhs)), \
106 "Use *_NON_NOEXCEPT version of the macro, " \
107 "or make the helper function noexcept")
108#else
109# define QT_COMPARISON_NOEXCEPT_CHECK(Noexcept, Func) /* no check */
110#endif
111
112
113// Seems that qdoc uses C++20 even when Qt is compiled in C++17 mode.
114// Or at least it defines __cpp_lib_three_way_comparison.
115// Let qdoc see only the C++17 operators for now, because that's what our docs
116// currently describe.
117#if defined(__cpp_lib_three_way_comparison) && !defined(Q_QDOC)
118// C++20 - provide operator==() for equality, and operator<=>() for ordering
119
120#define QT_DECLARE_EQUALITY_OPERATORS_HELPER(LeftType, RightType, Constexpr, \
121 Noexcept, Attributes) \
122 Attributes \
123 friend Constexpr bool operator==(LeftType const &lhs, RightType const &rhs) Noexcept \
124 { \
125 QT_COMPARISON_NOEXCEPT_CHECK(Noexcept, comparesEqual); \
126 return comparesEqual(lhs, rhs); \
127 }
128
129#define QT_DECLARE_3WAY_HELPER_STRONG(LeftType, RightType, Constexpr, Noexcept, Attributes) \
130 Attributes \
131 friend Constexpr std::strong_ordering \
132 operator<=>(LeftType const &lhs, RightType const &rhs) Noexcept \
133 { \
134 QT_COMPARISON_NOEXCEPT_CHECK(Noexcept, compareThreeWay); \
135 return compareThreeWay(lhs, rhs); \
136 }
137
138#define QT_DECLARE_3WAY_HELPER_WEAK(LeftType, RightType, Constexpr, Noexcept, Attributes) \
139 Attributes \
140 friend Constexpr std::weak_ordering \
141 operator<=>(LeftType const &lhs, RightType const &rhs) Noexcept \
142 { \
143 QT_COMPARISON_NOEXCEPT_CHECK(Noexcept, compareThreeWay); \
144 return compareThreeWay(lhs, rhs); \
145 }
146
147#define QT_DECLARE_3WAY_HELPER_PARTIAL(LeftType, RightType, Constexpr, Noexcept, Attributes) \
148 Attributes \
149 friend Constexpr std::partial_ordering \
150 operator<=>(LeftType const &lhs, RightType const &rhs) Noexcept \
151 { \
152 QT_COMPARISON_NOEXCEPT_CHECK(Noexcept, compareThreeWay); \
153 return compareThreeWay(lhs, rhs); \
154 }
155
156#define QT_DECLARE_ORDERING_OPERATORS_HELPER(OrderingType, LeftType, RightType, Constexpr, \
157 Noexcept, Attributes) \
158 QT_DECLARE_EQUALITY_OPERATORS_HELPER(LeftType, RightType, Constexpr, Noexcept, Attributes) \
159 QT_DECLARE_3WAY_HELPER_ ## OrderingType (LeftType, RightType, Constexpr, Noexcept, Attributes)
160
161#ifdef Q_COMPILER_LACKS_THREE_WAY_COMPARE_SYMMETRY
162
163// define reversed versions of the operators manually, because buggy MSVC versions do not do it
164#define QT_DECLARE_EQUALITY_OPERATORS_REVERSED_HELPER(LeftType, RightType, Constexpr, \
165 Noexcept, Attributes) \
166 Attributes \
167 friend Constexpr bool operator==(RightType const &lhs, LeftType const &rhs) Noexcept \
168 { return comparesEqual(rhs, lhs); }
169
170#define QT_DECLARE_REVERSED_3WAY_HELPER_STRONG(LeftType, RightType, Constexpr, \
171 Noexcept, Attributes) \
172 Attributes \
173 friend Constexpr std::strong_ordering \
174 operator<=>(RightType const &lhs, LeftType const &rhs) Noexcept \
175 { \
176 const auto r = compareThreeWay(rhs, lhs); \
177 return QtOrderingPrivate::reversed(r); \
178 }
179
180#define QT_DECLARE_REVERSED_3WAY_HELPER_WEAK(LeftType, RightType, Constexpr, \
181 Noexcept, Attributes) \
182 Attributes \
183 friend Constexpr std::weak_ordering \
184 operator<=>(RightType const &lhs, LeftType const &rhs) Noexcept \
185 { \
186 const auto r = compareThreeWay(rhs, lhs); \
187 return QtOrderingPrivate::reversed(r); \
188 }
189
190#define QT_DECLARE_REVERSED_3WAY_HELPER_PARTIAL(LeftType, RightType, Constexpr, \
191 Noexcept, Attributes) \
192 Attributes \
193 friend Constexpr std::partial_ordering \
194 operator<=>(RightType const &lhs, LeftType const &rhs) Noexcept \
195 { \
196 const auto r = compareThreeWay(rhs, lhs); \
197 return QtOrderingPrivate::reversed(r); \
198 }
199
200#define QT_DECLARE_ORDERING_OPERATORS_REVERSED_HELPER(OrderingString, LeftType, RightType, \
201 Constexpr, Noexcept, Attributes) \
202 QT_DECLARE_EQUALITY_OPERATORS_REVERSED_HELPER(LeftType, RightType, Constexpr, \
203 Noexcept, Attributes) \
204 QT_DECLARE_REVERSED_3WAY_HELPER_ ## OrderingString (LeftType, RightType, Constexpr, \
205 Noexcept, Attributes)
206
207#else
208
209// dummy macros for C++17 compatibility, reversed operators are generated by the compiler
210#define QT_DECLARE_EQUALITY_OPERATORS_REVERSED_HELPER(LeftType, RightType, Constexpr, \
211 Noexcept, Attributes)
212#define QT_DECLARE_ORDERING_OPERATORS_REVERSED_HELPER(OrderingString, LeftType, RightType, \
213 Constexpr, Noexcept, Attributes)
214
215#endif // Q_COMPILER_LACKS_THREE_WAY_COMPARE_SYMMETRY
216
217#else
218// C++17 - provide operator==() and operator!=() for equality,
219// and all 4 comparison operators for ordering
220
221#define QT_DECLARE_EQUALITY_OPERATORS_HELPER(LeftType, RightType, Constexpr, \
222 Noexcept, Attributes) \
223 Attributes \
224 friend Constexpr bool operator==(LeftType const &lhs, RightType const &rhs) Noexcept \
225 { \
226 QT_COMPARISON_NOEXCEPT_CHECK(Noexcept, comparesEqual); \
227 return comparesEqual(lhs, rhs); \
228 } \
229 Attributes \
230 friend Constexpr bool operator!=(LeftType const &lhs, RightType const &rhs) Noexcept \
231 { return !comparesEqual(lhs, rhs); }
232
233// Helpers for reversed comparison, using the existing comparesEqual() function.
234#define QT_DECLARE_EQUALITY_OPERATORS_REVERSED_HELPER(LeftType, RightType, Constexpr, \
235 Noexcept, Attributes) \
236 Attributes \
237 friend Constexpr bool operator==(RightType const &lhs, LeftType const &rhs) Noexcept \
238 { return comparesEqual(rhs, lhs); } \
239 Attributes \
240 friend Constexpr bool operator!=(RightType const &lhs, LeftType const &rhs) Noexcept \
241 { return !comparesEqual(rhs, lhs); }
242
243#define QT_DECLARE_ORDERING_HELPER_TEMPLATE(OrderingType, LeftType, RightType, Constexpr, \
244 Noexcept, Attributes) \
245 Attributes \
246 friend Constexpr bool operator<(LeftType const &lhs, RightType const &rhs) Noexcept \
247 { \
248 QT_COMPARISON_NOEXCEPT_CHECK(Noexcept, compareThreeWay); \
249 return is_lt(compareThreeWay(lhs, rhs)); \
250 } \
251 Attributes \
252 friend Constexpr bool operator>(LeftType const &lhs, RightType const &rhs) Noexcept \
253 { return is_gt(compareThreeWay(lhs, rhs)); } \
254 Attributes \
255 friend Constexpr bool operator<=(LeftType const &lhs, RightType const &rhs) Noexcept \
256 { return is_lteq(compareThreeWay(lhs, rhs)); } \
257 Attributes \
258 friend Constexpr bool operator>=(LeftType const &lhs, RightType const &rhs) Noexcept \
259 { return is_gteq(compareThreeWay(lhs, rhs)); }
260
261#define QT_DECLARE_ORDERING_HELPER_PARTIAL(LeftType, RightType, Constexpr, Noexcept, Attributes) \
262 QT_DECLARE_ORDERING_HELPER_TEMPLATE(Qt::partial_ordering, LeftType, RightType, Constexpr, \
263 Noexcept, Attributes)
264
265#define QT_DECLARE_ORDERING_HELPER_WEAK(LeftType, RightType, Constexpr, Noexcept, Attributes) \
266 QT_DECLARE_ORDERING_HELPER_TEMPLATE(Qt::weak_ordering, LeftType, RightType, Constexpr, \
267 Noexcept, Attributes)
268
269#define QT_DECLARE_ORDERING_HELPER_STRONG(LeftType, RightType, Constexpr, Noexcept, Attributes) \
270 QT_DECLARE_ORDERING_HELPER_TEMPLATE(Qt::strong_ordering, LeftType, RightType, Constexpr, \
271 Noexcept, Attributes)
272
273#define QT_DECLARE_ORDERING_OPERATORS_HELPER(OrderingString, LeftType, RightType, Constexpr, \
274 Noexcept, Attributes) \
275 QT_DECLARE_EQUALITY_OPERATORS_HELPER(LeftType, RightType, Constexpr, Noexcept, Attributes) \
276 QT_DECLARE_ORDERING_HELPER_ ## OrderingString (LeftType, RightType, Constexpr, Noexcept, \
277 Attributes)
278
279// Helpers for reversed ordering, using the existing compareThreeWay() function.
280#define QT_DECLARE_REVERSED_ORDERING_HELPER_TEMPLATE(OrderingType, LeftType, RightType, Constexpr, \
281 Noexcept, Attributes) \
282 Attributes \
283 friend Constexpr bool operator<(RightType const &lhs, LeftType const &rhs) Noexcept \
284 { return is_gt(compareThreeWay(rhs, lhs)); } \
285 Attributes \
286 friend Constexpr bool operator>(RightType const &lhs, LeftType const &rhs) Noexcept \
287 { return is_lt(compareThreeWay(rhs, lhs)); } \
288 Attributes \
289 friend Constexpr bool operator<=(RightType const &lhs, LeftType const &rhs) Noexcept \
290 { return is_gteq(compareThreeWay(rhs, lhs)); } \
291 Attributes \
292 friend Constexpr bool operator>=(RightType const &lhs, LeftType const &rhs) Noexcept \
293 { return is_lteq(compareThreeWay(rhs, lhs)); }
294
295#define QT_DECLARE_REVERSED_ORDERING_HELPER_PARTIAL(LeftType, RightType, Constexpr, Noexcept, \
296 Attributes) \
297 QT_DECLARE_REVERSED_ORDERING_HELPER_TEMPLATE(Qt::partial_ordering, LeftType, RightType, \
298 Constexpr, Noexcept, Attributes)
299
300#define QT_DECLARE_REVERSED_ORDERING_HELPER_WEAK(LeftType, RightType, Constexpr, Noexcept, \
301 Attributes) \
302 QT_DECLARE_REVERSED_ORDERING_HELPER_TEMPLATE(Qt::weak_ordering, LeftType, RightType, \
303 Constexpr, Noexcept, Attributes)
304
305#define QT_DECLARE_REVERSED_ORDERING_HELPER_STRONG(LeftType, RightType, Constexpr, Noexcept, \
306 Attributes) \
307 QT_DECLARE_REVERSED_ORDERING_HELPER_TEMPLATE(Qt::strong_ordering, LeftType, RightType, \
308 Constexpr, Noexcept, Attributes)
309
310#define QT_DECLARE_ORDERING_OPERATORS_REVERSED_HELPER(OrderingString, LeftType, RightType, \
311 Constexpr, Noexcept, Attributes) \
312 QT_DECLARE_EQUALITY_OPERATORS_REVERSED_HELPER(LeftType, RightType, Constexpr, Noexcept, \
313 Attributes) \
314 QT_DECLARE_REVERSED_ORDERING_HELPER_ ## OrderingString (LeftType, RightType, Constexpr, \
315 Noexcept, Attributes)
316
317#endif // __cpp_lib_three_way_comparison
318
319/* Public API starts here */
320
321// Equality operators
322#define QT_DECLARE_EQUALITY_COMPARABLE_1(Type) \
323 QT_DECLARE_EQUALITY_OPERATORS_HELPER(Type, Type, /* non-constexpr */, noexcept(true), \
324 /* no attributes */)
325
326#define QT_DECLARE_EQUALITY_COMPARABLE_2(LeftType, RightType) \
327 QT_DECLARE_EQUALITY_OPERATORS_HELPER(LeftType, RightType, /* non-constexpr */, \
328 noexcept(true), /* no attributes */) \
329 QT_DECLARE_EQUALITY_OPERATORS_REVERSED_HELPER(LeftType, RightType, /* non-constexpr */, \
330 noexcept(true), /* no attributes */)
331
332#define QT_DECLARE_EQUALITY_COMPARABLE_3(LeftType, RightType, Attributes) \
333 QT_DECLARE_EQUALITY_OPERATORS_HELPER(LeftType, RightType, /* non-constexpr */, \
334 noexcept(true), Attributes) \
335 QT_DECLARE_EQUALITY_OPERATORS_REVERSED_HELPER(LeftType, RightType, /* non-constexpr */, \
336 noexcept(true), Attributes)
337
338#define Q_DECLARE_EQUALITY_COMPARABLE(...) \
339 QT_OVERLOADED_MACRO(QT_DECLARE_EQUALITY_COMPARABLE, __VA_ARGS__)
340
341#define QT_DECLARE_EQUALITY_COMPARABLE_LITERAL_TYPE_1(Type) \
342 QT_DECLARE_EQUALITY_OPERATORS_HELPER(Type, Type, constexpr, noexcept(true), \
343 /* no attributes */)
344
345#define QT_DECLARE_EQUALITY_COMPARABLE_LITERAL_TYPE_2(LeftType, RightType) \
346 QT_DECLARE_EQUALITY_OPERATORS_HELPER(LeftType, RightType, constexpr, noexcept(true), \
347 /* no attributes */) \
348 QT_DECLARE_EQUALITY_OPERATORS_REVERSED_HELPER(LeftType, RightType, constexpr, \
349 noexcept(true), /* no attributes */)
350
351#define QT_DECLARE_EQUALITY_COMPARABLE_LITERAL_TYPE_3(LeftType, RightType, Attributes) \
352 QT_DECLARE_EQUALITY_OPERATORS_HELPER(LeftType, RightType, constexpr, noexcept(true), \
353 Attributes) \
354 QT_DECLARE_EQUALITY_OPERATORS_REVERSED_HELPER(LeftType, RightType, constexpr, noexcept(true), \
355 Attributes)
356
357#define Q_DECLARE_EQUALITY_COMPARABLE_LITERAL_TYPE(...) \
358 QT_OVERLOADED_MACRO(QT_DECLARE_EQUALITY_COMPARABLE_LITERAL_TYPE, __VA_ARGS__)
359
360#define QT_DECLARE_EQUALITY_COMPARABLE_NON_NOEXCEPT_1(Type) \
361 QT_DECLARE_EQUALITY_OPERATORS_HELPER(Type, Type, /* non-constexpr */, noexcept(false), \
362 /* no attributes */)
363
364#define QT_DECLARE_EQUALITY_COMPARABLE_NON_NOEXCEPT_2(LeftType, RightType) \
365 QT_DECLARE_EQUALITY_OPERATORS_HELPER(LeftType, RightType, /* non-constexpr */, \
366 noexcept(false), /* no attributes */) \
367 QT_DECLARE_EQUALITY_OPERATORS_REVERSED_HELPER(LeftType, RightType, /* non-constexpr */, \
368 noexcept(false), /* no attributes */)
369
370#define QT_DECLARE_EQUALITY_COMPARABLE_NON_NOEXCEPT_3(LeftType, RightType, Attributes) \
371 QT_DECLARE_EQUALITY_OPERATORS_HELPER(LeftType, RightType, /* non-constexpr */, \
372 noexcept(false), Attributes) \
373 QT_DECLARE_EQUALITY_OPERATORS_REVERSED_HELPER(LeftType, RightType, /* non-constexpr */, \
374 noexcept(false), Attributes)
375
376#define Q_DECLARE_EQUALITY_COMPARABLE_NON_NOEXCEPT(...) \
377 QT_OVERLOADED_MACRO(QT_DECLARE_EQUALITY_COMPARABLE_NON_NOEXCEPT, __VA_ARGS__)
378
379// Partial ordering operators
380#define QT_DECLARE_PARTIALLY_ORDERED_1(Type) \
381 QT_DECLARE_ORDERING_OPERATORS_HELPER(PARTIAL, Type, Type, /* non-constexpr */, \
382 noexcept(true), /* no attributes */)
383
384#define QT_DECLARE_PARTIALLY_ORDERED_2(LeftType, RightType) \
385 QT_DECLARE_ORDERING_OPERATORS_HELPER(PARTIAL, LeftType, RightType, /* non-constexpr */, \
386 noexcept(true), /* no attributes */) \
387 QT_DECLARE_ORDERING_OPERATORS_REVERSED_HELPER(PARTIAL, LeftType, RightType, \
388 /* non-constexpr */, noexcept(true), \
389 /* no attributes */)
390
391#define QT_DECLARE_PARTIALLY_ORDERED_3(LeftType, RightType, Attributes) \
392 QT_DECLARE_ORDERING_OPERATORS_HELPER(PARTIAL, LeftType, RightType, /* non-constexpr */, \
393 noexcept(true), Attributes) \
394 QT_DECLARE_ORDERING_OPERATORS_REVERSED_HELPER(PARTIAL, LeftType, RightType, \
395 /* non-constexpr */, noexcept(true), Attributes)
396
397#define Q_DECLARE_PARTIALLY_ORDERED(...) \
398 QT_OVERLOADED_MACRO(QT_DECLARE_PARTIALLY_ORDERED, __VA_ARGS__)
399
400#define QT_DECLARE_PARTIALLY_ORDERED_LITERAL_TYPE_1(Type) \
401 QT_DECLARE_ORDERING_OPERATORS_HELPER(PARTIAL, Type, Type, constexpr, noexcept(true), \
402 /* no attributes */)
403
404#define QT_DECLARE_PARTIALLY_ORDERED_LITERAL_TYPE_2(LeftType, RightType) \
405 QT_DECLARE_ORDERING_OPERATORS_HELPER(PARTIAL, LeftType, RightType, constexpr, \
406 noexcept(true), /* no attributes */) \
407 QT_DECLARE_ORDERING_OPERATORS_REVERSED_HELPER(PARTIAL, LeftType, RightType, constexpr, \
408 noexcept(true), /* no attributes */)
409
410#define QT_DECLARE_PARTIALLY_ORDERED_LITERAL_TYPE_3(LeftType, RightType, Attributes) \
411 QT_DECLARE_ORDERING_OPERATORS_HELPER(PARTIAL, LeftType, RightType, constexpr, noexcept(true), \
412 Attributes) \
413 QT_DECLARE_ORDERING_OPERATORS_REVERSED_HELPER(PARTIAL, LeftType, RightType, constexpr, \
414 noexcept(true), Attributes)
415
416#define Q_DECLARE_PARTIALLY_ORDERED_LITERAL_TYPE(...) \
417 QT_OVERLOADED_MACRO(QT_DECLARE_PARTIALLY_ORDERED_LITERAL_TYPE, __VA_ARGS__)
418
419#define QT_DECLARE_PARTIALLY_ORDERED_NON_NOEXCEPT_1(Type) \
420 QT_DECLARE_ORDERING_OPERATORS_HELPER(PARTIAL, Type, Type, /* non-constexpr */, \
421 noexcept(false), /* no attributes */)
422
423#define QT_DECLARE_PARTIALLY_ORDERED_NON_NOEXCEPT_2(LeftType, RightType) \
424 QT_DECLARE_ORDERING_OPERATORS_HELPER(PARTIAL, LeftType, RightType, /* non-constexpr */, \
425 noexcept(false), /* no attributes */) \
426 QT_DECLARE_ORDERING_OPERATORS_REVERSED_HELPER(PARTIAL, LeftType, RightType, \
427 /* non-constexpr */, noexcept(false), \
428 /* no attributes */)
429
430#define QT_DECLARE_PARTIALLY_ORDERED_NON_NOEXCEPT_3(LeftType, RightType, Attributes) \
431 QT_DECLARE_ORDERING_OPERATORS_HELPER(PARTIAL, LeftType, RightType, /* non-constexpr */, \
432 noexcept(false), Attributes) \
433 QT_DECLARE_ORDERING_OPERATORS_REVERSED_HELPER(PARTIAL, LeftType, RightType, \
434 /* non-constexpr */, noexcept(false), Attributes)
435
436#define Q_DECLARE_PARTIALLY_ORDERED_NON_NOEXCEPT(...) \
437 QT_OVERLOADED_MACRO(QT_DECLARE_PARTIALLY_ORDERED_NON_NOEXCEPT, __VA_ARGS__)
438
439// Weak ordering operators
440#define QT_DECLARE_WEAKLY_ORDERED_1(Type) \
441 QT_DECLARE_ORDERING_OPERATORS_HELPER(WEAK, Type, Type, /* non-constexpr */, noexcept(true), \
442 /* no attributes */)
443
444#define QT_DECLARE_WEAKLY_ORDERED_2(LeftType, RightType) \
445 QT_DECLARE_ORDERING_OPERATORS_HELPER(WEAK, LeftType, RightType, /* non-constexpr */, \
446 noexcept(true), /* no attributes */) \
447 QT_DECLARE_ORDERING_OPERATORS_REVERSED_HELPER(WEAK, LeftType, RightType, /* non-constexpr */, \
448 noexcept(true), /* no attributes */)
449
450#define QT_DECLARE_WEAKLY_ORDERED_3(LeftType, RightType, Attributes) \
451 QT_DECLARE_ORDERING_OPERATORS_HELPER(WEAK, LeftType, RightType, /* non-constexpr */, \
452 noexcept(true), Attributes) \
453 QT_DECLARE_ORDERING_OPERATORS_REVERSED_HELPER(WEAK, LeftType, RightType, /* non-constexpr */, \
454 noexcept(true), Attributes)
455
456#define Q_DECLARE_WEAKLY_ORDERED(...) \
457 QT_OVERLOADED_MACRO(QT_DECLARE_WEAKLY_ORDERED, __VA_ARGS__)
458
459#define QT_DECLARE_WEAKLY_ORDERED_LITERAL_TYPE_1(Type) \
460 QT_DECLARE_ORDERING_OPERATORS_HELPER(WEAK, Type, Type, constexpr, noexcept(true), \
461 /* no attributes */)
462
463#define QT_DECLARE_WEAKLY_ORDERED_LITERAL_TYPE_2(LeftType, RightType) \
464 QT_DECLARE_ORDERING_OPERATORS_HELPER(WEAK, LeftType, RightType, constexpr, \
465 noexcept(true), /* no attributes */) \
466 QT_DECLARE_ORDERING_OPERATORS_REVERSED_HELPER(WEAK, LeftType, RightType, constexpr, \
467 noexcept(true), /* no attributes */)
468
469#define QT_DECLARE_WEAKLY_ORDERED_LITERAL_TYPE_3(LeftType, RightType, Attributes) \
470 QT_DECLARE_ORDERING_OPERATORS_HELPER(WEAK, LeftType, RightType, constexpr, noexcept(true), \
471 Attributes) \
472 QT_DECLARE_ORDERING_OPERATORS_REVERSED_HELPER(WEAK, LeftType, RightType, constexpr, \
473 noexcept(true), Attributes)
474
475#define Q_DECLARE_WEAKLY_ORDERED_LITERAL_TYPE(...) \
476 QT_OVERLOADED_MACRO(QT_DECLARE_WEAKLY_ORDERED_LITERAL_TYPE, __VA_ARGS__)
477
478#define QT_DECLARE_WEAKLY_ORDERED_NON_NOEXCEPT_1(Type) \
479 QT_DECLARE_ORDERING_OPERATORS_HELPER(WEAK, Type, Type, /* non-constexpr */, noexcept(false), \
480 /* no attributes */)
481
482#define QT_DECLARE_WEAKLY_ORDERED_NON_NOEXCEPT_2(LeftType, RightType) \
483 QT_DECLARE_ORDERING_OPERATORS_HELPER(WEAK, LeftType, RightType, /* non-constexpr */, \
484 noexcept(false), /* no attributes */) \
485 QT_DECLARE_ORDERING_OPERATORS_REVERSED_HELPER(WEAK, LeftType, RightType, /* non-constexpr */, \
486 noexcept(false), /* no attributes */)
487
488#define QT_DECLARE_WEAKLY_ORDERED_NON_NOEXCEPT_3(LeftType, RightType, Attributes) \
489 QT_DECLARE_ORDERING_OPERATORS_HELPER(WEAK, LeftType, RightType, /* non-constexpr */, \
490 noexcept(false), Attributes) \
491 QT_DECLARE_ORDERING_OPERATORS_REVERSED_HELPER(WEAK, LeftType, RightType, /* non-constexpr */, \
492 noexcept(false), Attributes)
493
494#define Q_DECLARE_WEAKLY_ORDERED_NON_NOEXCEPT(...) \
495 QT_OVERLOADED_MACRO(QT_DECLARE_WEAKLY_ORDERED_NON_NOEXCEPT, __VA_ARGS__)
496
497// Strong ordering operators
498#define QT_DECLARE_STRONGLY_ORDERED_1(Type) \
499 QT_DECLARE_ORDERING_OPERATORS_HELPER(STRONG, Type, Type, /* non-constexpr */, \
500 noexcept(true), /* no attributes */)
501
502#define QT_DECLARE_STRONGLY_ORDERED_2(LeftType, RightType) \
503 QT_DECLARE_ORDERING_OPERATORS_HELPER(STRONG, LeftType, RightType, /* non-constexpr */, \
504 noexcept(true), /* no attributes */) \
505 QT_DECLARE_ORDERING_OPERATORS_REVERSED_HELPER(STRONG, LeftType, RightType, \
506 /* non-constexpr */, noexcept(true), \
507 /* no attributes */)
508
509#define QT_DECLARE_STRONGLY_ORDERED_3(LeftType, RightType, Attributes) \
510 QT_DECLARE_ORDERING_OPERATORS_HELPER(STRONG, LeftType, RightType, /* non-constexpr */, \
511 noexcept(true), Attributes) \
512 QT_DECLARE_ORDERING_OPERATORS_REVERSED_HELPER(STRONG, LeftType, RightType, \
513 /* non-constexpr */, noexcept(true), Attributes)
514
515#define Q_DECLARE_STRONGLY_ORDERED(...) \
516 QT_OVERLOADED_MACRO(QT_DECLARE_STRONGLY_ORDERED, __VA_ARGS__)
517
518#define QT_DECLARE_STRONGLY_ORDERED_LITERAL_TYPE_1(Type) \
519 QT_DECLARE_ORDERING_OPERATORS_HELPER(STRONG, Type, Type, constexpr, noexcept(true), \
520 /* no attributes */)
521
522#define QT_DECLARE_STRONGLY_ORDERED_LITERAL_TYPE_2(LeftType, RightType) \
523 QT_DECLARE_ORDERING_OPERATORS_HELPER(STRONG, LeftType, RightType, constexpr, \
524 noexcept(true), /* no attributes */) \
525 QT_DECLARE_ORDERING_OPERATORS_REVERSED_HELPER(STRONG, LeftType, RightType, constexpr, \
526 noexcept(true), /* no attributes */)
527
528#define QT_DECLARE_STRONGLY_ORDERED_LITERAL_TYPE_3(LeftType, RightType, Attributes) \
529 QT_DECLARE_ORDERING_OPERATORS_HELPER(STRONG, LeftType, RightType, constexpr, noexcept(true), \
530 Attributes) \
531 QT_DECLARE_ORDERING_OPERATORS_REVERSED_HELPER(STRONG, LeftType, RightType, constexpr, \
532 noexcept(true), Attributes)
533
534#define Q_DECLARE_STRONGLY_ORDERED_LITERAL_TYPE(...) \
535 QT_OVERLOADED_MACRO(QT_DECLARE_STRONGLY_ORDERED_LITERAL_TYPE, __VA_ARGS__)
536
537#define QT_DECLARE_STRONGLY_ORDERED_NON_NOEXCEPT_1(Type) \
538 QT_DECLARE_ORDERING_OPERATORS_HELPER(STRONG, Type, Type, /* non-constexpr */, \
539 noexcept(false), /* no attributes */)
540
541#define QT_DECLARE_STRONGLY_ORDERED_NON_NOEXCEPT_2(LeftType, RightType) \
542 QT_DECLARE_ORDERING_OPERATORS_HELPER(STRONG, LeftType, RightType, /* non-constexpr */, \
543 noexcept(false), /* no attributes */) \
544 QT_DECLARE_ORDERING_OPERATORS_REVERSED_HELPER(STRONG, LeftType, RightType, \
545 /* non-constexpr */, noexcept(false), \
546 /* no attributes */)
547
548#define QT_DECLARE_STRONGLY_ORDERED_NON_NOEXCEPT_3(LeftType, RightType, Attributes) \
549 QT_DECLARE_ORDERING_OPERATORS_HELPER(STRONG, LeftType, RightType, /* non-constexpr */, \
550 noexcept(false), Attributes) \
551 QT_DECLARE_ORDERING_OPERATORS_REVERSED_HELPER(STRONG, LeftType, RightType, \
552 /* non-constexpr */, noexcept(false), Attributes)
553
554#define Q_DECLARE_STRONGLY_ORDERED_NON_NOEXCEPT(...) \
555 QT_OVERLOADED_MACRO(QT_DECLARE_STRONGLY_ORDERED_NON_NOEXCEPT, __VA_ARGS__)
556
557namespace QtPrivate {
558
559template <typename T>
560constexpr bool IsIntegralType_v = std::numeric_limits<std::remove_const_t<T>>::is_specialized
561 && std::numeric_limits<std::remove_const_t<T>>::is_integer;
562
563template <typename T>
564constexpr bool IsFloatType_v = std::is_floating_point_v<T>;
565
566#if QFLOAT16_IS_NATIVE
567template <>
568inline constexpr bool IsFloatType_v<QtPrivate::NativeFloat16Type> = true;
569#endif
570
571} // namespace QtPrivate
572
573namespace QtOrderingPrivate {
574
575template <typename T, typename U>
576constexpr Qt::strong_ordering
577strongOrderingCompareDefaultImpl(T lhs, U rhs) noexcept
578{
579#ifdef __cpp_lib_three_way_comparison
580 return lhs <=> rhs;
581#else
582 if (lhs == rhs)
583 return Qt::strong_ordering::equivalent;
584 else if (lhs < rhs)
585 return Qt::strong_ordering::less;
586 else
587 return Qt::strong_ordering::greater;
588#endif // __cpp_lib_three_way_comparison
589}
590
591} // namespace QtOrderingPrivate
592
593namespace Qt {
594
595template <typename T>
596using if_integral = std::enable_if_t<QtPrivate::IsIntegralType_v<T>, bool>;
597
598template <typename T>
599using if_floating_point = std::enable_if_t<QtPrivate::IsFloatType_v<T>, bool>;
600
601template <typename T, typename U>
602using if_compatible_pointers =
603 std::enable_if_t<std::disjunction_v<std::is_same<T, U>,
604 std::is_base_of<T, U>,
605 std::is_base_of<U, T>>,
606 bool>;
607
608template <typename Enum>
609using if_enum = std::enable_if_t<std::is_enum_v<Enum>, bool>;
610
611template <typename LeftInt, typename RightInt,
612 if_integral<LeftInt> = true,
613 if_integral<RightInt> = true>
614constexpr Qt::strong_ordering compareThreeWay(LeftInt lhs, RightInt rhs) noexcept
615{
616 static_assert(std::is_signed_v<LeftInt> == std::is_signed_v<RightInt>,
617 "Qt::compareThreeWay() does not allow mixed-sign comparison.");
618
619#ifdef __cpp_lib_three_way_comparison
620 return lhs <=> rhs;
621#else
622 if (lhs == rhs)
623 return Qt::strong_ordering::equivalent;
624 else if (lhs < rhs)
625 return Qt::strong_ordering::less;
626 else
627 return Qt::strong_ordering::greater;
628#endif // __cpp_lib_three_way_comparison
629}
630
631template <typename LeftFloat, typename RightFloat,
632 if_floating_point<LeftFloat> = true,
633 if_floating_point<RightFloat> = true>
634constexpr Qt::partial_ordering compareThreeWay(LeftFloat lhs, RightFloat rhs) noexcept
635{
636QT_WARNING_PUSH
637QT_WARNING_DISABLE_FLOAT_COMPARE
638#ifdef __cpp_lib_three_way_comparison
639 return lhs <=> rhs;
640#else
641 if (lhs < rhs)
642 return Qt::partial_ordering::less;
643 else if (lhs > rhs)
644 return Qt::partial_ordering::greater;
645 else if (lhs == rhs)
646 return Qt::partial_ordering::equivalent;
647 else
648 return Qt::partial_ordering::unordered;
649#endif // __cpp_lib_three_way_comparison
650QT_WARNING_POP
651}
652
653template <typename IntType, typename FloatType,
654 if_integral<IntType> = true,
655 if_floating_point<FloatType> = true>
656constexpr Qt::partial_ordering compareThreeWay(IntType lhs, FloatType rhs) noexcept
657{
658 return compareThreeWay(FloatType(lhs), rhs);
659}
660
661template <typename FloatType, typename IntType,
662 if_floating_point<FloatType> = true,
663 if_integral<IntType> = true>
664constexpr Qt::partial_ordering compareThreeWay(FloatType lhs, IntType rhs) noexcept
665{
666 return compareThreeWay(lhs, FloatType(rhs));
667}
668
669#if QT_DEPRECATED_SINCE(6, 8)
670
671template <typename LeftType, typename RightType,
672 if_compatible_pointers<LeftType, RightType> = true>
673QT_DEPRECATED_VERSION_X_6_8("Wrap the pointers into Qt::totally_ordered_wrapper and use the respective overload instead.")
674constexpr Qt::strong_ordering compareThreeWay(const LeftType *lhs, const RightType *rhs) noexcept
675{
676#ifdef __cpp_lib_three_way_comparison
677 return std::compare_three_way{}(lhs, rhs);
678#else
679 if (lhs == rhs)
680 return Qt::strong_ordering::equivalent;
681 else if (std::less<>{}(lhs, rhs))
682 return Qt::strong_ordering::less;
683 else
684 return Qt::strong_ordering::greater;
685#endif // __cpp_lib_three_way_comparison
686}
687
688template <typename T>
689QT_DEPRECATED_VERSION_X_6_8("Wrap the pointer into Qt::totally_ordered_wrapper and use the respective overload instead.")
690constexpr Qt::strong_ordering compareThreeWay(const T *lhs, std::nullptr_t rhs) noexcept
691{
692 return compareThreeWay(lhs, static_cast<const T *>(rhs));
693}
694
695template <typename T>
696QT_DEPRECATED_VERSION_X_6_8("Wrap the pointer into Qt::totally_ordered_wrapper and use the respective overload instead.")
697constexpr Qt::strong_ordering compareThreeWay(std::nullptr_t lhs, const T *rhs) noexcept
698{
699 return compareThreeWay(static_cast<const T *>(lhs), rhs);
700}
701
702#endif // QT_DEPRECATED_SINCE(6, 8)
703
704template <class Enum, if_enum<Enum> = true>
705constexpr Qt::strong_ordering compareThreeWay(Enum lhs, Enum rhs) noexcept
706{
707 return compareThreeWay(qToUnderlying(lhs), qToUnderlying(rhs));
708}
709} // namespace Qt
710
711namespace QtOrderingPrivate {
712
713template <typename Head, typename...Tail, std::size_t...Is>
714constexpr std::tuple<Tail...> qt_tuple_pop_front_impl(const std::tuple<Head, Tail...> &t,
715 std::index_sequence<Is...>) noexcept
716{
717 return std::tuple<Tail...>(std::get<Is + 1>(t)...);
718}
719
720template <typename Head, typename...Tail>
721constexpr std::tuple<Tail...> qt_tuple_pop_front(const std::tuple<Head, Tail...> &t) noexcept
722{
723 return qt_tuple_pop_front_impl(t, std::index_sequence_for<Tail...>{});
724}
725
726template <typename LhsHead, typename...LhsTail, typename RhsHead, typename...RhsTail>
727constexpr auto compareThreeWayMulti(const std::tuple<LhsHead, LhsTail...> &lhs, // ie. not empty
728 const std::tuple<RhsHead, RhsTail...> &rhs) noexcept
729{
730 static_assert(sizeof...(LhsTail) == sizeof...(RhsTail),
731 // expanded together below, but provide a nicer error message:
732 "The tuple arguments have to have the same size.");
733
734 using Qt::compareThreeWay;
735 using R = std::common_type_t<
736 decltype(compareThreeWay(std::declval<LhsHead>(), std::declval<RhsHead>())),
737 decltype(compareThreeWay(std::declval<LhsTail>(), std::declval<RhsTail>()))...
738 >;
739
740 const auto &l = std::get<0>(lhs);
741 const auto &r = std::get<0>(rhs);
742 static_assert(noexcept(compareThreeWay(l, r)),
743 "This function requires all relational operators to be noexcept.");
744 const auto res = compareThreeWay(l, r);
745 if constexpr (sizeof...(LhsTail) > 0) {
746 if (is_eq(res))
747 return R{compareThreeWayMulti(qt_tuple_pop_front(lhs), qt_tuple_pop_front(rhs))};
748 }
749 return R{res};
750}
751
752} //QtOrderingPrivate
753
754namespace Qt {
755// A wrapper class that adapts the wrappee to use the strongly-ordered
756// <functional> function objects for implementing the relational operators.
757// Mostly useful to avoid UB on pointers (which it currently mandates P to be),
758// because all the comparison helpers (incl. std::compare_three_way on
759// std::tuple<T*>!) will use the language-level operators.
760//
761template <typename P>
762class totally_ordered_wrapper
763{
764 static_assert(std::is_pointer_v<P>);
765 using T = std::remove_pointer_t<P>;
766
767 P ptr;
768public:
769 totally_ordered_wrapper() noexcept = default;
770 Q_IMPLICIT constexpr totally_ordered_wrapper(std::nullptr_t)
771 // requires std::is_pointer_v<P>
772 : totally_ordered_wrapper(P{nullptr}) {}
773 explicit constexpr totally_ordered_wrapper(P p) noexcept : ptr(p) {}
774
775 constexpr P get() const noexcept { return ptr; }
776 constexpr void reset(P p) noexcept { ptr = p; }
777 constexpr P operator->() const noexcept { return get(); }
778 template <typename U = T, std::enable_if_t<!std::is_void_v<U>, bool> = true>
779 constexpr U &operator*() const noexcept { return *get(); }
780
781 explicit constexpr operator bool() const noexcept { return get(); }
782
783private:
784 // TODO: Replace the constraints with std::common_type_t<P, U> when
785 // a bug in VxWorks is fixed!
786 template <typename T, typename U>
787 using if_compatible_types =
788 std::enable_if_t<std::conjunction_v<std::is_pointer<T>,
789 std::is_pointer<U>,
790 std::disjunction<std::is_convertible<T, U>,
791 std::is_convertible<U, T>>>,
792 bool>;
793
794#define MAKE_RELOP(Ret, op, Op) \
795 template <typename U = P, if_compatible_types<P, U> = true> \
796 friend constexpr Ret operator op (const totally_ordered_wrapper<P> &lhs, const totally_ordered_wrapper<U> &rhs) noexcept \
797 { return std:: Op {}(lhs.ptr, rhs.get()); } \
798 template <typename U = P, if_compatible_types<P, U> = true> \
799 friend constexpr Ret operator op (const totally_ordered_wrapper<P> &lhs, const U &rhs) noexcept \
800 { return std:: Op {}(lhs.ptr, rhs ); } \
801 template <typename U = P, if_compatible_types<P, U> = true> \
802 friend constexpr Ret operator op (const U &lhs, const totally_ordered_wrapper<P> &rhs) noexcept \
803 { return std:: Op {}(lhs, rhs.ptr); } \
804 friend constexpr Ret operator op (const totally_ordered_wrapper &lhs, std::nullptr_t) noexcept \
805 { return std:: Op {}(lhs.ptr, P(nullptr)); } \
806 friend constexpr Ret operator op (std::nullptr_t, const totally_ordered_wrapper &rhs) noexcept \
807 { return std:: Op {}(P(nullptr), rhs.ptr); } \
808 /* end */
809 MAKE_RELOP(bool, ==, equal_to<>)
810 MAKE_RELOP(bool, !=, not_equal_to<>)
811 MAKE_RELOP(bool, < , less<>)
812 MAKE_RELOP(bool, <=, less_equal<>)
813 MAKE_RELOP(bool, > , greater<>)
814 MAKE_RELOP(bool, >=, greater_equal<>)
815#ifdef __cpp_lib_three_way_comparison
816 MAKE_RELOP(auto, <=>, compare_three_way)
817#endif
818#undef MAKE_RELOP
819 friend void qt_ptr_swap(totally_ordered_wrapper &lhs, totally_ordered_wrapper &rhs) noexcept
820 { qt_ptr_swap(lhs.ptr, rhs.ptr); }
821 friend void swap(totally_ordered_wrapper &lhs, totally_ordered_wrapper &rhs) noexcept
822 { qt_ptr_swap(lhs, rhs); }
823 friend size_t qHash(totally_ordered_wrapper key, size_t seed = 0) noexcept
824 { return qHash(key.ptr, seed); }
825};
826
827template <typename T, typename U, if_compatible_pointers<T, U> = true>
828constexpr Qt::strong_ordering
829compareThreeWay(Qt::totally_ordered_wrapper<T*> lhs, Qt::totally_ordered_wrapper<U*> rhs) noexcept
830{
831 return QtOrderingPrivate::strongOrderingCompareDefaultImpl(lhs, rhs);
832}
833
834template <typename T, typename U, if_compatible_pointers<T, U> = true>
835constexpr Qt::strong_ordering
836compareThreeWay(Qt::totally_ordered_wrapper<T*> lhs, U *rhs) noexcept
837{
838 return QtOrderingPrivate::strongOrderingCompareDefaultImpl(lhs, rhs);
839}
840
841template <typename T, typename U, if_compatible_pointers<T, U> = true>
842constexpr Qt::strong_ordering
843compareThreeWay(U *lhs, Qt::totally_ordered_wrapper<T*> rhs) noexcept
844{
845 return QtOrderingPrivate::strongOrderingCompareDefaultImpl(lhs, rhs);
846}
847
848template <typename T>
849constexpr Qt::strong_ordering
850compareThreeWay(Qt::totally_ordered_wrapper<T*> lhs, std::nullptr_t rhs) noexcept
851{
852 return QtOrderingPrivate::strongOrderingCompareDefaultImpl(lhs, rhs);
853}
854
855template <typename T>
856constexpr Qt::strong_ordering
857compareThreeWay(std::nullptr_t lhs, Qt::totally_ordered_wrapper<T*> rhs) noexcept
858{
859 return QtOrderingPrivate::strongOrderingCompareDefaultImpl(lhs, rhs);
860}
861
862} //Qt
863
864template <typename P>
865class QTypeInfo<Qt::totally_ordered_wrapper<P>> : public QTypeInfo<P> {};
866
867QT_END_NAMESPACE
868
869namespace std {
870 template <typename P>
871 struct hash<QT_PREPEND_NAMESPACE(Qt::totally_ordered_wrapper)<P>>
872 {
873 using argument_type = QT_PREPEND_NAMESPACE(Qt::totally_ordered_wrapper)<P>;
874 using result_type = size_t;
875 constexpr result_type operator()(argument_type w) const noexcept
876 { return std::hash<P>{}(w.get()); }
877 };
878}
879
880#endif // QCOMPAREHELPERS_H
881

Provided by KDAB

Privacy Policy
Learn to use CMake with our Intro Training
Find out more

source code of qtbase/src/corelib/global/qcomparehelpers.h