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