1// Copyright (C) 2020 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Giuseppe D'Angelo <giuseppe.dangelo@kdab.com>
2// Copyright (C) 2023 The Qt Company Ltd.
3// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
4
5#ifndef QCOMPARE_H
6#define QCOMPARE_H
7
8#if 0
9#pragma qt_class(QtCompare)
10#endif
11
12#include <QtCore/qglobal.h>
13#include <QtCore/qcompare_impl.h>
14
15#ifdef __cpp_lib_bit_cast
16#include <bit>
17#endif
18#ifdef __cpp_lib_three_way_comparison
19#include <compare>
20#endif
21
22QT_BEGIN_NAMESPACE
23
24namespace QtPrivate {
25using CompareUnderlyingType = qint8;
26
27// [cmp.categories.pre] / 1
28enum class Ordering : CompareUnderlyingType
29{
30 Equal = 0,
31 Equivalent = Equal,
32 Less = -1,
33 Greater = 1
34};
35
36enum class Uncomparable : CompareUnderlyingType
37{
38 Unordered =
39 #if defined(_LIBCPP_VERSION) // libc++
40 -127
41 #elif defined(__GLIBCXX__) // libstdc++
42 2
43 #else // assume MSSTL
44 -128
45 #endif
46};
47
48} // namespace QtPrivate
49
50namespace QtOrderingPrivate {
51
52template <typename O>
53constexpr O reversed(O o) noexcept
54{
55 // https://eel.is/c++draft/cmp.partialord#5
56 return is_lt(o) ? O::greater :
57 is_gt(o) ? O::less :
58 /*else*/ o ;
59}
60
61} // namespace QtOrderingPrivate
62
63namespace Qt {
64
65class weak_ordering;
66class strong_ordering;
67
68class partial_ordering
69{
70public:
71 static const partial_ordering less;
72 static const partial_ordering equivalent;
73 static const partial_ordering greater;
74 static const partial_ordering unordered;
75
76 friend constexpr bool operator==(partial_ordering lhs,
77 QtPrivate::CompareAgainstLiteralZero) noexcept
78 { return lhs.isOrdered() && lhs.m_order == 0; }
79
80 friend constexpr bool operator!=(partial_ordering lhs,
81 QtPrivate::CompareAgainstLiteralZero) noexcept
82 { return !lhs.isOrdered() || lhs.m_order != 0; }
83
84 friend constexpr bool operator< (partial_ordering lhs,
85 QtPrivate::CompareAgainstLiteralZero) noexcept
86 { return lhs.isOrdered() && lhs.m_order < 0; }
87
88 friend constexpr bool operator<=(partial_ordering lhs,
89 QtPrivate::CompareAgainstLiteralZero) noexcept
90 { return lhs.isOrdered() && lhs.m_order <= 0; }
91
92 friend constexpr bool operator> (partial_ordering lhs,
93 QtPrivate::CompareAgainstLiteralZero) noexcept
94 { return lhs.isOrdered() && lhs.m_order > 0; }
95
96 friend constexpr bool operator>=(partial_ordering lhs,
97 QtPrivate::CompareAgainstLiteralZero) noexcept
98 { return lhs.isOrdered() && lhs.m_order >= 0; }
99
100
101 friend constexpr bool operator==(QtPrivate::CompareAgainstLiteralZero,
102 partial_ordering rhs) noexcept
103 { return rhs.isOrdered() && 0 == rhs.m_order; }
104
105 friend constexpr bool operator!=(QtPrivate::CompareAgainstLiteralZero,
106 partial_ordering rhs) noexcept
107 { return !rhs.isOrdered() || 0 != rhs.m_order; }
108
109 friend constexpr bool operator< (QtPrivate::CompareAgainstLiteralZero,
110 partial_ordering rhs) noexcept
111 { return rhs.isOrdered() && 0 < rhs.m_order; }
112
113 friend constexpr bool operator<=(QtPrivate::CompareAgainstLiteralZero,
114 partial_ordering rhs) noexcept
115 { return rhs.isOrdered() && 0 <= rhs.m_order; }
116
117 friend constexpr bool operator> (QtPrivate::CompareAgainstLiteralZero,
118 partial_ordering rhs) noexcept
119 { return rhs.isOrdered() && 0 > rhs.m_order; }
120
121 friend constexpr bool operator>=(QtPrivate::CompareAgainstLiteralZero,
122 partial_ordering rhs) noexcept
123 { return rhs.isOrdered() && 0 >= rhs.m_order; }
124
125
126#ifdef __cpp_lib_three_way_comparison
127 friend constexpr std::partial_ordering
128 operator<=>(partial_ordering lhs, QtPrivate::CompareAgainstLiteralZero) noexcept
129 { return lhs; } // https://eel.is/c++draft/cmp.partialord#4
130
131 friend constexpr std::partial_ordering
132 operator<=>(QtPrivate::CompareAgainstLiteralZero, partial_ordering rhs) noexcept
133 { return QtOrderingPrivate::reversed(o: rhs); }
134#endif // __cpp_lib_three_way_comparison
135
136
137 friend constexpr bool operator==(partial_ordering lhs, partial_ordering rhs) noexcept
138 { return lhs.m_order == rhs.m_order; }
139
140 friend constexpr bool operator!=(partial_ordering lhs, partial_ordering rhs) noexcept
141 { return lhs.m_order != rhs.m_order; }
142
143#ifdef __cpp_lib_three_way_comparison
144 constexpr Q_IMPLICIT partial_ordering(std::partial_ordering stdorder) noexcept
145 {
146 if (stdorder == std::partial_ordering::less)
147 m_order = static_cast<QtPrivate::CompareUnderlyingType>(QtPrivate::Ordering::Less);
148 else if (stdorder == std::partial_ordering::equivalent)
149 m_order = static_cast<QtPrivate::CompareUnderlyingType>(QtPrivate::Ordering::Equivalent);
150 else if (stdorder == std::partial_ordering::greater)
151 m_order = static_cast<QtPrivate::CompareUnderlyingType>(QtPrivate::Ordering::Greater);
152 else if (stdorder == std::partial_ordering::unordered)
153 m_order = static_cast<QtPrivate::CompareUnderlyingType>(QtPrivate::Uncomparable::Unordered);
154 }
155
156 constexpr Q_IMPLICIT operator std::partial_ordering() const noexcept
157 {
158 static_assert(sizeof(*this) == sizeof(std::partial_ordering));
159#ifdef __cpp_lib_bit_cast
160 return std::bit_cast<std::partial_ordering>(from: *this);
161#else
162 using O = QtPrivate::Ordering;
163 using U = QtPrivate::Uncomparable;
164 using R = std::partial_ordering;
165 switch (m_order) {
166 case qToUnderlying(O::Less): return R::less;
167 case qToUnderlying(O::Greater): return R::greater;
168 case qToUnderlying(O::Equivalent): return R::equivalent;
169 case qToUnderlying(U::Unordered): return R::unordered;
170 }
171 Q_UNREACHABLE_RETURN(R::unordered);
172#endif // __cpp_lib_bit_cast
173 }
174
175 friend constexpr bool operator==(partial_ordering lhs, std::partial_ordering rhs) noexcept
176 { return static_cast<std::partial_ordering>(lhs) == rhs; }
177
178 friend constexpr bool operator!=(partial_ordering lhs, std::partial_ordering rhs) noexcept
179 { return static_cast<std::partial_ordering>(lhs) != rhs; }
180
181 friend constexpr bool operator==(std::partial_ordering lhs, partial_ordering rhs) noexcept
182 { return lhs == static_cast<std::partial_ordering>(rhs); }
183
184 friend constexpr bool operator!=(std::partial_ordering lhs, partial_ordering rhs) noexcept
185 { return lhs != static_cast<std::partial_ordering>(rhs); }
186
187 friend constexpr bool operator==(partial_ordering lhs, std::strong_ordering rhs) noexcept
188 { return static_cast<std::partial_ordering>(lhs) == rhs; }
189
190 friend constexpr bool operator!=(partial_ordering lhs, std::strong_ordering rhs) noexcept
191 { return static_cast<std::partial_ordering>(lhs) != rhs; }
192
193 friend constexpr bool operator==(std::strong_ordering lhs, partial_ordering rhs) noexcept
194 { return lhs == static_cast<std::partial_ordering>(rhs); }
195
196 friend constexpr bool operator!=(std::strong_ordering lhs, partial_ordering rhs) noexcept
197 { return lhs != static_cast<std::partial_ordering>(rhs); }
198
199 friend constexpr bool operator==(partial_ordering lhs, std::weak_ordering rhs) noexcept
200 { return static_cast<std::partial_ordering>(lhs) == rhs; }
201
202 friend constexpr bool operator!=(partial_ordering lhs, std::weak_ordering rhs) noexcept
203 { return static_cast<std::partial_ordering>(lhs) != rhs; }
204
205 friend constexpr bool operator==(std::weak_ordering lhs, partial_ordering rhs) noexcept
206 { return lhs == static_cast<std::partial_ordering>(rhs); }
207
208 friend constexpr bool operator!=(std::weak_ordering lhs, partial_ordering rhs) noexcept
209 { return lhs != static_cast<std::partial_ordering>(rhs); }
210#endif // __cpp_lib_three_way_comparison
211
212private:
213 friend class weak_ordering;
214 friend class strong_ordering;
215
216 constexpr explicit partial_ordering(QtPrivate::Ordering order) noexcept
217 : m_order(static_cast<QtPrivate::CompareUnderlyingType>(order))
218 {}
219 constexpr explicit partial_ordering(QtPrivate::Uncomparable order) noexcept
220 : m_order(static_cast<QtPrivate::CompareUnderlyingType>(order))
221 {}
222
223 QT_WARNING_PUSH
224 // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=100903
225 QT_WARNING_DISABLE_GCC("-Wzero-as-null-pointer-constant")
226 QT_WARNING_DISABLE_CLANG("-Wzero-as-null-pointer-constant")
227 friend constexpr bool is_eq (partial_ordering o) noexcept { return o == 0; }
228 friend constexpr bool is_neq (partial_ordering o) noexcept { return o != 0; }
229 friend constexpr bool is_lt (partial_ordering o) noexcept { return o < 0; }
230 friend constexpr bool is_lteq(partial_ordering o) noexcept { return o <= 0; }
231 friend constexpr bool is_gt (partial_ordering o) noexcept { return o > 0; }
232 friend constexpr bool is_gteq(partial_ordering o) noexcept { return o >= 0; }
233 QT_WARNING_POP
234
235 // instead of the exposition only is_ordered member in [cmp.partialord],
236 // use a private function
237 constexpr bool isOrdered() const noexcept
238 { return m_order != static_cast<QtPrivate::CompareUnderlyingType>(QtPrivate::Uncomparable::Unordered); }
239
240 QtPrivate::CompareUnderlyingType m_order;
241};
242
243inline constexpr partial_ordering partial_ordering::less(QtPrivate::Ordering::Less);
244inline constexpr partial_ordering partial_ordering::equivalent(QtPrivate::Ordering::Equivalent);
245inline constexpr partial_ordering partial_ordering::greater(QtPrivate::Ordering::Greater);
246inline constexpr partial_ordering partial_ordering::unordered(QtPrivate::Uncomparable::Unordered);
247
248class weak_ordering
249{
250public:
251 static const weak_ordering less;
252 static const weak_ordering equivalent;
253 static const weak_ordering greater;
254
255 constexpr Q_IMPLICIT operator partial_ordering() const noexcept
256 { return partial_ordering(static_cast<QtPrivate::Ordering>(m_order)); }
257
258 friend constexpr bool operator==(weak_ordering lhs,
259 QtPrivate::CompareAgainstLiteralZero) noexcept
260 { return lhs.m_order == 0; }
261
262 friend constexpr bool operator!=(weak_ordering lhs,
263 QtPrivate::CompareAgainstLiteralZero) noexcept
264 { return lhs.m_order != 0; }
265
266 friend constexpr bool operator< (weak_ordering lhs,
267 QtPrivate::CompareAgainstLiteralZero) noexcept
268 { return lhs.m_order < 0; }
269
270 friend constexpr bool operator<=(weak_ordering lhs,
271 QtPrivate::CompareAgainstLiteralZero) noexcept
272 { return lhs.m_order <= 0; }
273
274 friend constexpr bool operator> (weak_ordering lhs,
275 QtPrivate::CompareAgainstLiteralZero) noexcept
276 { return lhs.m_order > 0; }
277
278 friend constexpr bool operator>=(weak_ordering lhs,
279 QtPrivate::CompareAgainstLiteralZero) noexcept
280 { return lhs.m_order >= 0; }
281
282
283 friend constexpr bool operator==(QtPrivate::CompareAgainstLiteralZero,
284 weak_ordering rhs) noexcept
285 { return 0 == rhs.m_order; }
286
287 friend constexpr bool operator!=(QtPrivate::CompareAgainstLiteralZero,
288 weak_ordering rhs) noexcept
289 { return 0 != rhs.m_order; }
290
291 friend constexpr bool operator< (QtPrivate::CompareAgainstLiteralZero,
292 weak_ordering rhs) noexcept
293 { return 0 < rhs.m_order; }
294
295 friend constexpr bool operator<=(QtPrivate::CompareAgainstLiteralZero,
296 weak_ordering rhs) noexcept
297 { return 0 <= rhs.m_order; }
298
299 friend constexpr bool operator> (QtPrivate::CompareAgainstLiteralZero,
300 weak_ordering rhs) noexcept
301 { return 0 > rhs.m_order; }
302
303 friend constexpr bool operator>=(QtPrivate::CompareAgainstLiteralZero,
304 weak_ordering rhs) noexcept
305 { return 0 >= rhs.m_order; }
306
307
308#ifdef __cpp_lib_three_way_comparison
309 friend constexpr std::weak_ordering
310 operator<=>(weak_ordering lhs, QtPrivate::CompareAgainstLiteralZero) noexcept
311 { return lhs; } // https://eel.is/c++draft/cmp.weakord#5
312
313 friend constexpr std::weak_ordering
314 operator<=>(QtPrivate::CompareAgainstLiteralZero, weak_ordering rhs) noexcept
315 { return QtOrderingPrivate::reversed(o: rhs); }
316#endif // __cpp_lib_three_way_comparison
317
318
319 friend constexpr bool operator==(weak_ordering lhs, weak_ordering rhs) noexcept
320 { return lhs.m_order == rhs.m_order; }
321
322 friend constexpr bool operator!=(weak_ordering lhs, weak_ordering rhs) noexcept
323 { return lhs.m_order != rhs.m_order; }
324
325 friend constexpr bool operator==(weak_ordering lhs, partial_ordering rhs) noexcept
326 { return static_cast<partial_ordering>(lhs) == rhs; }
327
328 friend constexpr bool operator!=(weak_ordering lhs, partial_ordering rhs) noexcept
329 { return static_cast<partial_ordering>(lhs) != rhs; }
330
331 friend constexpr bool operator==(partial_ordering lhs, weak_ordering rhs) noexcept
332 { return lhs == static_cast<partial_ordering>(rhs); }
333
334 friend constexpr bool operator!=(partial_ordering lhs, weak_ordering rhs) noexcept
335 { return lhs != static_cast<partial_ordering>(rhs); }
336
337#ifdef __cpp_lib_three_way_comparison
338 constexpr Q_IMPLICIT weak_ordering(std::weak_ordering stdorder) noexcept
339 {
340 if (stdorder == std::weak_ordering::less)
341 m_order = static_cast<QtPrivate::CompareUnderlyingType>(QtPrivate::Ordering::Less);
342 else if (stdorder == std::weak_ordering::equivalent)
343 m_order = static_cast<QtPrivate::CompareUnderlyingType>(QtPrivate::Ordering::Equivalent);
344 else if (stdorder == std::weak_ordering::greater)
345 m_order = static_cast<QtPrivate::CompareUnderlyingType>(QtPrivate::Ordering::Greater);
346 }
347
348 constexpr Q_IMPLICIT operator std::weak_ordering() const noexcept
349 {
350 static_assert(sizeof(*this) == sizeof(std::weak_ordering));
351#ifdef __cpp_lib_bit_cast
352 return std::bit_cast<std::weak_ordering>(from: *this);
353#else
354 using O = QtPrivate::Ordering;
355 using R = std::weak_ordering;
356 switch (m_order) {
357 case qToUnderlying(O::Less): return R::less;
358 case qToUnderlying(O::Greater): return R::greater;
359 case qToUnderlying(O::Equivalent): return R::equivalent;
360 }
361 Q_UNREACHABLE_RETURN(R::equivalent);
362#endif // __cpp_lib_bit_cast
363 }
364
365 friend constexpr bool operator==(weak_ordering lhs, std::weak_ordering rhs) noexcept
366 { return static_cast<std::weak_ordering>(lhs) == rhs; }
367
368 friend constexpr bool operator!=(weak_ordering lhs, std::weak_ordering rhs) noexcept
369 { return static_cast<std::weak_ordering>(lhs) != rhs; }
370
371 friend constexpr bool operator==(weak_ordering lhs, std::partial_ordering rhs) noexcept
372 { return static_cast<std::weak_ordering>(lhs) == rhs; }
373
374 friend constexpr bool operator!=(weak_ordering lhs, std::partial_ordering rhs) noexcept
375 { return static_cast<std::weak_ordering>(lhs) != rhs; }
376
377 friend constexpr bool operator==(weak_ordering lhs, std::strong_ordering rhs) noexcept
378 { return static_cast<std::weak_ordering>(lhs) == rhs; }
379
380 friend constexpr bool operator!=(weak_ordering lhs, std::strong_ordering rhs) noexcept
381 { return static_cast<std::weak_ordering>(lhs) != rhs; }
382
383 friend constexpr bool operator==(std::weak_ordering lhs, weak_ordering rhs) noexcept
384 { return lhs == static_cast<std::weak_ordering>(rhs); }
385
386 friend constexpr bool operator!=(std::weak_ordering lhs, weak_ordering rhs) noexcept
387 { return lhs != static_cast<std::weak_ordering>(rhs); }
388
389 friend constexpr bool operator==(std::partial_ordering lhs, weak_ordering rhs) noexcept
390 { return lhs == static_cast<std::weak_ordering>(rhs); }
391
392 friend constexpr bool operator!=(std::partial_ordering lhs, weak_ordering rhs) noexcept
393 { return lhs != static_cast<std::weak_ordering>(rhs); }
394
395 friend constexpr bool operator==(std::strong_ordering lhs, weak_ordering rhs) noexcept
396 { return lhs == static_cast<std::weak_ordering>(rhs); }
397
398 friend constexpr bool operator!=(std::strong_ordering lhs, weak_ordering rhs) noexcept
399 { return lhs != static_cast<std::weak_ordering>(rhs); }
400#endif // __cpp_lib_three_way_comparison
401
402private:
403 friend class strong_ordering;
404
405 constexpr explicit weak_ordering(QtPrivate::Ordering order) noexcept
406 : m_order(static_cast<QtPrivate::CompareUnderlyingType>(order))
407 {}
408
409 QT_WARNING_PUSH
410 // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=100903
411 QT_WARNING_DISABLE_GCC("-Wzero-as-null-pointer-constant")
412 QT_WARNING_DISABLE_CLANG("-Wzero-as-null-pointer-constant")
413 friend constexpr bool is_eq (weak_ordering o) noexcept { return o == 0; }
414 friend constexpr bool is_neq (weak_ordering o) noexcept { return o != 0; }
415 friend constexpr bool is_lt (weak_ordering o) noexcept { return o < 0; }
416 friend constexpr bool is_lteq(weak_ordering o) noexcept { return o <= 0; }
417 friend constexpr bool is_gt (weak_ordering o) noexcept { return o > 0; }
418 friend constexpr bool is_gteq(weak_ordering o) noexcept { return o >= 0; }
419 QT_WARNING_POP
420
421 QtPrivate::CompareUnderlyingType m_order;
422};
423
424inline constexpr weak_ordering weak_ordering::less(QtPrivate::Ordering::Less);
425inline constexpr weak_ordering weak_ordering::equivalent(QtPrivate::Ordering::Equivalent);
426inline constexpr weak_ordering weak_ordering::greater(QtPrivate::Ordering::Greater);
427
428class strong_ordering
429{
430public:
431 static const strong_ordering less;
432 static const strong_ordering equivalent;
433 static const strong_ordering equal;
434 static const strong_ordering greater;
435
436 constexpr Q_IMPLICIT operator partial_ordering() const noexcept
437 { return partial_ordering(static_cast<QtPrivate::Ordering>(m_order)); }
438
439 constexpr Q_IMPLICIT operator weak_ordering() const noexcept
440 { return weak_ordering(static_cast<QtPrivate::Ordering>(m_order)); }
441
442 friend constexpr bool operator==(strong_ordering lhs,
443 QtPrivate::CompareAgainstLiteralZero) noexcept
444 { return lhs.m_order == 0; }
445
446 friend constexpr bool operator!=(strong_ordering lhs,
447 QtPrivate::CompareAgainstLiteralZero) noexcept
448 { return lhs.m_order != 0; }
449
450 friend constexpr bool operator< (strong_ordering lhs,
451 QtPrivate::CompareAgainstLiteralZero) noexcept
452 { return lhs.m_order < 0; }
453
454 friend constexpr bool operator<=(strong_ordering lhs,
455 QtPrivate::CompareAgainstLiteralZero) noexcept
456 { return lhs.m_order <= 0; }
457
458 friend constexpr bool operator> (strong_ordering lhs,
459 QtPrivate::CompareAgainstLiteralZero) noexcept
460 { return lhs.m_order > 0; }
461
462 friend constexpr bool operator>=(strong_ordering lhs,
463 QtPrivate::CompareAgainstLiteralZero) noexcept
464 { return lhs.m_order >= 0; }
465
466
467 friend constexpr bool operator==(QtPrivate::CompareAgainstLiteralZero,
468 strong_ordering rhs) noexcept
469 { return 0 == rhs.m_order; }
470
471 friend constexpr bool operator!=(QtPrivate::CompareAgainstLiteralZero,
472 strong_ordering rhs) noexcept
473 { return 0 != rhs.m_order; }
474
475 friend constexpr bool operator< (QtPrivate::CompareAgainstLiteralZero,
476 strong_ordering rhs) noexcept
477 { return 0 < rhs.m_order; }
478
479 friend constexpr bool operator<=(QtPrivate::CompareAgainstLiteralZero,
480 strong_ordering rhs) noexcept
481 { return 0 <= rhs.m_order; }
482
483 friend constexpr bool operator> (QtPrivate::CompareAgainstLiteralZero,
484 strong_ordering rhs) noexcept
485 { return 0 > rhs.m_order; }
486
487 friend constexpr bool operator>=(QtPrivate::CompareAgainstLiteralZero,
488 strong_ordering rhs) noexcept
489 { return 0 >= rhs.m_order; }
490
491
492#ifdef __cpp_lib_three_way_comparison
493 friend constexpr std::strong_ordering
494 operator<=>(strong_ordering lhs, QtPrivate::CompareAgainstLiteralZero) noexcept
495 { return lhs; } // https://eel.is/c++draft/cmp.strongord#6
496
497 friend constexpr std::strong_ordering
498 operator<=>(QtPrivate::CompareAgainstLiteralZero, strong_ordering rhs) noexcept
499 { return QtOrderingPrivate::reversed(o: rhs); }
500#endif // __cpp_lib_three_way_comparison
501
502
503 friend constexpr bool operator==(strong_ordering lhs, strong_ordering rhs) noexcept
504 { return lhs.m_order == rhs.m_order; }
505
506 friend constexpr bool operator!=(strong_ordering lhs, strong_ordering rhs) noexcept
507 { return lhs.m_order != rhs.m_order; }
508
509 friend constexpr bool operator==(strong_ordering lhs, partial_ordering rhs) noexcept
510 { return static_cast<partial_ordering>(lhs) == rhs; }
511
512 friend constexpr bool operator!=(strong_ordering lhs, partial_ordering rhs) noexcept
513 { return static_cast<partial_ordering>(lhs) == rhs; }
514
515 friend constexpr bool operator==(partial_ordering lhs, strong_ordering rhs) noexcept
516 { return lhs == static_cast<partial_ordering>(rhs); }
517
518 friend constexpr bool operator!=(partial_ordering lhs, strong_ordering rhs) noexcept
519 { return lhs != static_cast<partial_ordering>(rhs); }
520
521 friend constexpr bool operator==(strong_ordering lhs, weak_ordering rhs) noexcept
522 { return static_cast<weak_ordering>(lhs) == rhs; }
523
524 friend constexpr bool operator!=(strong_ordering lhs, weak_ordering rhs) noexcept
525 { return static_cast<weak_ordering>(lhs) == rhs; }
526
527 friend constexpr bool operator==(weak_ordering lhs, strong_ordering rhs) noexcept
528 { return lhs == static_cast<weak_ordering>(rhs); }
529
530 friend constexpr bool operator!=(weak_ordering lhs, strong_ordering rhs) noexcept
531 { return lhs != static_cast<weak_ordering>(rhs); }
532
533#ifdef __cpp_lib_three_way_comparison
534 constexpr Q_IMPLICIT strong_ordering(std::strong_ordering stdorder) noexcept
535 {
536 if (stdorder == std::strong_ordering::less)
537 m_order = static_cast<QtPrivate::CompareUnderlyingType>(QtPrivate::Ordering::Less);
538 else if (stdorder == std::strong_ordering::equivalent)
539 m_order = static_cast<QtPrivate::CompareUnderlyingType>(QtPrivate::Ordering::Equivalent);
540 else if (stdorder == std::strong_ordering::equal)
541 m_order = static_cast<QtPrivate::CompareUnderlyingType>(QtPrivate::Ordering::Equal);
542 else if (stdorder == std::strong_ordering::greater)
543 m_order = static_cast<QtPrivate::CompareUnderlyingType>(QtPrivate::Ordering::Greater);
544 }
545
546 constexpr Q_IMPLICIT operator std::strong_ordering() const noexcept
547 {
548 static_assert(sizeof(*this) == sizeof(std::strong_ordering));
549#ifdef __cpp_lib_bit_cast
550 return std::bit_cast<std::strong_ordering>(from: *this);
551#else
552 using O = QtPrivate::Ordering;
553 using R = std::strong_ordering;
554 switch (m_order) {
555 case qToUnderlying(O::Less): return R::less;
556 case qToUnderlying(O::Greater): return R::greater;
557 case qToUnderlying(O::Equal): return R::equal;
558 }
559 Q_UNREACHABLE_RETURN(R::equal);
560#endif // __cpp_lib_bit_cast
561 }
562
563 friend constexpr bool operator==(strong_ordering lhs, std::strong_ordering rhs) noexcept
564 { return static_cast<std::strong_ordering>(lhs) == rhs; }
565
566 friend constexpr bool operator!=(strong_ordering lhs, std::strong_ordering rhs) noexcept
567 { return static_cast<std::strong_ordering>(lhs) != rhs; }
568
569 friend constexpr bool operator==(strong_ordering lhs, std::partial_ordering rhs) noexcept
570 { return static_cast<std::strong_ordering>(lhs) == rhs; }
571
572 friend constexpr bool operator!=(strong_ordering lhs, std::partial_ordering rhs) noexcept
573 { return static_cast<std::strong_ordering>(lhs) != rhs; }
574
575 friend constexpr bool operator==(strong_ordering lhs, std::weak_ordering rhs) noexcept
576 { return static_cast<std::strong_ordering>(lhs) == rhs; }
577
578 friend constexpr bool operator!=(strong_ordering lhs, std::weak_ordering rhs) noexcept
579 { return static_cast<std::strong_ordering>(lhs) != rhs; }
580
581 friend constexpr bool operator==(std::strong_ordering lhs, strong_ordering rhs) noexcept
582 { return lhs == static_cast<std::strong_ordering>(rhs); }
583
584 friend constexpr bool operator!=(std::strong_ordering lhs, strong_ordering rhs) noexcept
585 { return lhs != static_cast<std::strong_ordering>(rhs); }
586
587 friend constexpr bool operator==(std::partial_ordering lhs, strong_ordering rhs) noexcept
588 { return lhs == static_cast<std::strong_ordering>(rhs); }
589
590 friend constexpr bool operator!=(std::partial_ordering lhs, strong_ordering rhs) noexcept
591 { return lhs != static_cast<std::strong_ordering>(rhs); }
592
593 friend constexpr bool operator==(std::weak_ordering lhs, strong_ordering rhs) noexcept
594 { return lhs == static_cast<std::strong_ordering>(rhs); }
595
596 friend constexpr bool operator!=(std::weak_ordering lhs, strong_ordering rhs) noexcept
597 { return lhs != static_cast<std::strong_ordering>(rhs); }
598#endif // __cpp_lib_three_way_comparison
599
600 private:
601 constexpr explicit strong_ordering(QtPrivate::Ordering order) noexcept
602 : m_order(static_cast<QtPrivate::CompareUnderlyingType>(order))
603 {}
604
605 QT_WARNING_PUSH
606 // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=100903
607 QT_WARNING_DISABLE_GCC("-Wzero-as-null-pointer-constant")
608 QT_WARNING_DISABLE_CLANG("-Wzero-as-null-pointer-constant")
609 friend constexpr bool is_eq (strong_ordering o) noexcept { return o == 0; }
610 friend constexpr bool is_neq (strong_ordering o) noexcept { return o != 0; }
611 friend constexpr bool is_lt (strong_ordering o) noexcept { return o < 0; }
612 friend constexpr bool is_lteq(strong_ordering o) noexcept { return o <= 0; }
613 friend constexpr bool is_gt (strong_ordering o) noexcept { return o > 0; }
614 friend constexpr bool is_gteq(strong_ordering o) noexcept { return o >= 0; }
615 QT_WARNING_POP
616
617 QtPrivate::CompareUnderlyingType m_order;
618};
619
620inline constexpr strong_ordering strong_ordering::less(QtPrivate::Ordering::Less);
621inline constexpr strong_ordering strong_ordering::equivalent(QtPrivate::Ordering::Equivalent);
622inline constexpr strong_ordering strong_ordering::equal(QtPrivate::Ordering::Equal);
623inline constexpr strong_ordering strong_ordering::greater(QtPrivate::Ordering::Greater);
624
625} // namespace Qt
626
627QT_BEGIN_INCLUDE_NAMESPACE
628
629// This is intentionally included after Qt::*_ordering types and before
630// qCompareThreeWay. Do not change!
631#include <QtCore/qcomparehelpers.h>
632
633QT_END_INCLUDE_NAMESPACE
634
635#if defined(Q_QDOC)
636
637template <typename LeftType, typename RightType>
638auto qCompareThreeWay(const LeftType &lhs, const RightType &rhs);
639
640#else
641
642template <typename LT, typename RT,
643 std::enable_if_t<
644 QtOrderingPrivate::CompareThreeWayTester::hasCompareThreeWay<LT, RT>
645 || QtOrderingPrivate::CompareThreeWayTester::hasCompareThreeWay<RT, LT>,
646 bool> = true>
647auto qCompareThreeWay(const LT &lhs, const RT &rhs)
648 noexcept(QtOrderingPrivate::CompareThreeWayTester::compareThreeWayNoexcept<LT, RT>())
649{
650 using Qt::compareThreeWay;
651 if constexpr (QtOrderingPrivate::CompareThreeWayTester::hasCompareThreeWay<LT, RT>) {
652 return compareThreeWay(lhs, rhs);
653 } else {
654 const auto retval = compareThreeWay(rhs, lhs);
655 return QtOrderingPrivate::reversed(retval);
656 }
657}
658
659#endif // defined(Q_QDOC)
660
661//
662// Legacy QPartialOrdering
663//
664
665namespace QtPrivate {
666enum class LegacyUncomparable : CompareUnderlyingType
667{
668 Unordered = -127
669};
670}
671
672// [cmp.partialord]
673class QPartialOrdering
674{
675public:
676 static const QPartialOrdering Less;
677 static const QPartialOrdering Equivalent;
678 static const QPartialOrdering Greater;
679 static const QPartialOrdering Unordered;
680
681 static const QPartialOrdering less;
682 static const QPartialOrdering equivalent;
683 static const QPartialOrdering greater;
684 static const QPartialOrdering unordered;
685
686 friend constexpr bool operator==(QPartialOrdering lhs,
687 QtPrivate::CompareAgainstLiteralZero) noexcept
688 { return lhs.isOrdered() && lhs.m_order == 0; }
689
690 friend constexpr bool operator!=(QPartialOrdering lhs,
691 QtPrivate::CompareAgainstLiteralZero) noexcept
692 { return !lhs.isOrdered() || lhs.m_order != 0; }
693
694 friend constexpr bool operator< (QPartialOrdering lhs,
695 QtPrivate::CompareAgainstLiteralZero) noexcept
696 { return lhs.isOrdered() && lhs.m_order < 0; }
697
698 friend constexpr bool operator<=(QPartialOrdering lhs,
699 QtPrivate::CompareAgainstLiteralZero) noexcept
700 { return lhs.isOrdered() && lhs.m_order <= 0; }
701
702 friend constexpr bool operator> (QPartialOrdering lhs,
703 QtPrivate::CompareAgainstLiteralZero) noexcept
704 { return lhs.isOrdered() && lhs.m_order > 0; }
705
706 friend constexpr bool operator>=(QPartialOrdering lhs,
707 QtPrivate::CompareAgainstLiteralZero) noexcept
708 { return lhs.isOrdered() && lhs.m_order >= 0; }
709
710
711 friend constexpr bool operator==(QtPrivate::CompareAgainstLiteralZero,
712 QPartialOrdering rhs) noexcept
713 { return rhs.isOrdered() && 0 == rhs.m_order; }
714
715 friend constexpr bool operator!=(QtPrivate::CompareAgainstLiteralZero,
716 QPartialOrdering rhs) noexcept
717 { return !rhs.isOrdered() || 0 != rhs.m_order; }
718
719 friend constexpr bool operator< (QtPrivate::CompareAgainstLiteralZero,
720 QPartialOrdering rhs) noexcept
721 { return rhs.isOrdered() && 0 < rhs.m_order; }
722
723 friend constexpr bool operator<=(QtPrivate::CompareAgainstLiteralZero,
724 QPartialOrdering rhs) noexcept
725 { return rhs.isOrdered() && 0 <= rhs.m_order; }
726
727 friend constexpr bool operator> (QtPrivate::CompareAgainstLiteralZero,
728 QPartialOrdering rhs) noexcept
729 { return rhs.isOrdered() && 0 > rhs.m_order; }
730
731 friend constexpr bool operator>=(QtPrivate::CompareAgainstLiteralZero,
732 QPartialOrdering rhs) noexcept
733 { return rhs.isOrdered() && 0 >= rhs.m_order; }
734
735
736#ifdef __cpp_lib_three_way_comparison
737 friend constexpr std::partial_ordering
738 operator<=>(QPartialOrdering lhs, QtPrivate::CompareAgainstLiteralZero) noexcept
739 { return lhs; } // https://eel.is/c++draft/cmp.partialord#4
740
741 friend constexpr std::partial_ordering
742 operator<=>(QtPrivate::CompareAgainstLiteralZero, QPartialOrdering rhs) noexcept
743 { return QtOrderingPrivate::reversed(o: rhs); }
744#endif // __cpp_lib_three_way_comparison
745
746
747 friend constexpr bool operator==(QPartialOrdering lhs, QPartialOrdering rhs) noexcept
748 { return lhs.m_order == rhs.m_order; }
749
750 friend constexpr bool operator!=(QPartialOrdering lhs, QPartialOrdering rhs) noexcept
751 { return lhs.m_order != rhs.m_order; }
752
753 constexpr Q_IMPLICIT QPartialOrdering(Qt::partial_ordering order) noexcept
754 : m_order{} // == equivalent
755 {
756 if (order == Qt::partial_ordering::less)
757 m_order = static_cast<QtPrivate::CompareUnderlyingType>(QtPrivate::Ordering::Less);
758 else if (order == Qt::partial_ordering::greater)
759 m_order = static_cast<QtPrivate::CompareUnderlyingType>(QtPrivate::Ordering::Greater);
760 else if (order == Qt::partial_ordering::unordered)
761 m_order = static_cast<QtPrivate::CompareUnderlyingType>(QtPrivate::LegacyUncomparable::Unordered);
762 }
763
764 constexpr Q_IMPLICIT QPartialOrdering(Qt::weak_ordering stdorder) noexcept
765 : QPartialOrdering(Qt::partial_ordering{stdorder}) {}
766
767 constexpr Q_IMPLICIT QPartialOrdering(Qt::strong_ordering stdorder) noexcept
768 : QPartialOrdering(Qt::partial_ordering{stdorder}) {}
769
770 constexpr Q_IMPLICIT operator Qt::partial_ordering() const noexcept
771 {
772 using O = QtPrivate::Ordering;
773 using U = QtPrivate::LegacyUncomparable;
774 using R = Qt::partial_ordering;
775 switch (m_order) {
776 case qToUnderlying(e: O::Less): return R::less;
777 case qToUnderlying(e: O::Greater): return R::greater;
778 case qToUnderlying(e: O::Equivalent): return R::equivalent;
779 case qToUnderlying(e: U::Unordered): return R::unordered;
780 }
781 // GCC 8.x does not treat __builtin_unreachable() as constexpr
782#if !defined(Q_CC_GNU_ONLY) || (Q_CC_GNU >= 900)
783 // NOLINTNEXTLINE(qt-use-unreachable-return): Triggers on Clang, breaking GCC 8
784 Q_UNREACHABLE();
785#endif
786 return R::unordered;
787 }
788
789 friend constexpr bool operator==(QPartialOrdering lhs, Qt::partial_ordering rhs) noexcept
790 { Qt::partial_ordering qt = lhs; return qt == rhs; }
791
792 friend constexpr bool operator!=(QPartialOrdering lhs, Qt::partial_ordering rhs) noexcept
793 { Qt::partial_ordering qt = lhs; return qt != rhs; }
794
795 friend constexpr bool operator==(Qt::partial_ordering lhs, QPartialOrdering rhs) noexcept
796 { Qt::partial_ordering qt = rhs; return lhs == qt; }
797
798 friend constexpr bool operator!=(Qt::partial_ordering lhs, QPartialOrdering rhs) noexcept
799 { Qt::partial_ordering qt = rhs; return lhs != qt; }
800
801#ifdef __cpp_lib_three_way_comparison
802 constexpr Q_IMPLICIT QPartialOrdering(std::partial_ordering stdorder) noexcept
803 {
804 if (stdorder == std::partial_ordering::less)
805 m_order = static_cast<QtPrivate::CompareUnderlyingType>(QtPrivate::Ordering::Less);
806 else if (stdorder == std::partial_ordering::equivalent)
807 m_order = static_cast<QtPrivate::CompareUnderlyingType>(QtPrivate::Ordering::Equivalent);
808 else if (stdorder == std::partial_ordering::greater)
809 m_order = static_cast<QtPrivate::CompareUnderlyingType>(QtPrivate::Ordering::Greater);
810 else if (stdorder == std::partial_ordering::unordered)
811 m_order = static_cast<QtPrivate::CompareUnderlyingType>(QtPrivate::LegacyUncomparable::Unordered);
812 }
813
814 constexpr Q_IMPLICIT QPartialOrdering(std::weak_ordering stdorder) noexcept
815 : QPartialOrdering(std::partial_ordering(stdorder)) {}
816
817 constexpr Q_IMPLICIT QPartialOrdering(std::strong_ordering stdorder) noexcept
818 : QPartialOrdering(std::partial_ordering(stdorder)) {}
819
820 constexpr Q_IMPLICIT operator std::partial_ordering() const noexcept
821 {
822 using O = QtPrivate::Ordering;
823 using U = QtPrivate::LegacyUncomparable;
824 using R = std::partial_ordering;
825 switch (m_order) {
826 case qToUnderlying(e: O::Less): return R::less;
827 case qToUnderlying(e: O::Greater): return R::greater;
828 case qToUnderlying(e: O::Equivalent): return R::equivalent;
829 case qToUnderlying(e: U::Unordered): return R::unordered;
830 }
831 Q_UNREACHABLE_RETURN(R::unordered);
832 }
833
834 friend constexpr bool operator==(QPartialOrdering lhs, std::partial_ordering rhs) noexcept
835 { return static_cast<std::partial_ordering>(lhs) == rhs; }
836
837 friend constexpr bool operator!=(QPartialOrdering lhs, std::partial_ordering rhs) noexcept
838 { return static_cast<std::partial_ordering>(lhs) != rhs; }
839
840 friend constexpr bool operator==(std::partial_ordering lhs, QPartialOrdering rhs) noexcept
841 { return lhs == static_cast<std::partial_ordering>(rhs); }
842
843 friend constexpr bool operator!=(std::partial_ordering lhs, QPartialOrdering rhs) noexcept
844 { return lhs != static_cast<std::partial_ordering>(rhs); }
845#endif // __cpp_lib_three_way_comparison
846
847private:
848 constexpr explicit QPartialOrdering(QtPrivate::Ordering order) noexcept
849 : m_order(static_cast<QtPrivate::CompareUnderlyingType>(order))
850 {}
851 constexpr explicit QPartialOrdering(QtPrivate::LegacyUncomparable order) noexcept
852 : m_order(static_cast<QtPrivate::CompareUnderlyingType>(order))
853 {}
854
855 QT_WARNING_PUSH
856 // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=100903
857 QT_WARNING_DISABLE_GCC("-Wzero-as-null-pointer-constant")
858 QT_WARNING_DISABLE_CLANG("-Wzero-as-null-pointer-constant")
859 friend constexpr bool is_eq (QPartialOrdering o) noexcept { return o == 0; }
860 friend constexpr bool is_neq (QPartialOrdering o) noexcept { return o != 0; }
861 friend constexpr bool is_lt (QPartialOrdering o) noexcept { return o < 0; }
862 friend constexpr bool is_lteq(QPartialOrdering o) noexcept { return o <= 0; }
863 friend constexpr bool is_gt (QPartialOrdering o) noexcept { return o > 0; }
864 friend constexpr bool is_gteq(QPartialOrdering o) noexcept { return o >= 0; }
865 QT_WARNING_POP
866
867 // instead of the exposition only is_ordered member in [cmp.partialord],
868 // use a private function
869 constexpr bool isOrdered() const noexcept
870 { return m_order != static_cast<QtPrivate::CompareUnderlyingType>(QtPrivate::LegacyUncomparable::Unordered); }
871
872 QtPrivate::CompareUnderlyingType m_order;
873};
874
875inline constexpr QPartialOrdering QPartialOrdering::Less(QtPrivate::Ordering::Less);
876inline constexpr QPartialOrdering QPartialOrdering::Equivalent(QtPrivate::Ordering::Equivalent);
877inline constexpr QPartialOrdering QPartialOrdering::Greater(QtPrivate::Ordering::Greater);
878inline constexpr QPartialOrdering QPartialOrdering::Unordered(QtPrivate::LegacyUncomparable::Unordered);
879
880inline constexpr QPartialOrdering QPartialOrdering::less(QtPrivate::Ordering::Less);
881inline constexpr QPartialOrdering QPartialOrdering::equivalent(QtPrivate::Ordering::Equivalent);
882inline constexpr QPartialOrdering QPartialOrdering::greater(QtPrivate::Ordering::Greater);
883inline constexpr QPartialOrdering QPartialOrdering::unordered(QtPrivate::LegacyUncomparable::Unordered);
884
885QT_END_NAMESPACE
886
887#endif // QCOMPARE_H
888