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

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