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 | |
22 | QT_BEGIN_NAMESPACE |
23 | |
24 | namespace QtPrivate { |
25 | using CompareUnderlyingType = qint8; |
26 | |
27 | // [cmp.categories.pre] / 1 |
28 | enum class Ordering : CompareUnderlyingType |
29 | { |
30 | Equal = 0, |
31 | Equivalent = Equal, |
32 | Less = -1, |
33 | Greater = 1 |
34 | }; |
35 | |
36 | enum 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 | |
50 | namespace QtOrderingPrivate { |
51 | |
52 | template <typename O> |
53 | constexpr 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 | |
63 | namespace Qt { |
64 | |
65 | class partial_ordering |
66 | { |
67 | public: |
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 | |
185 | private: |
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 | |
215 | inline constexpr partial_ordering partial_ordering::less(QtPrivate::Ordering::Less); |
216 | inline constexpr partial_ordering partial_ordering::equivalent(QtPrivate::Ordering::Equivalent); |
217 | inline constexpr partial_ordering partial_ordering::greater(QtPrivate::Ordering::Greater); |
218 | inline constexpr partial_ordering partial_ordering::unordered(QtPrivate::Uncomparable::Unordered); |
219 | |
220 | class weak_ordering |
221 | { |
222 | public: |
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 | |
374 | private: |
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 | |
395 | inline constexpr weak_ordering weak_ordering::less(QtPrivate::Ordering::Less); |
396 | inline constexpr weak_ordering weak_ordering::equivalent(QtPrivate::Ordering::Equivalent); |
397 | inline constexpr weak_ordering weak_ordering::greater(QtPrivate::Ordering::Greater); |
398 | |
399 | class strong_ordering |
400 | { |
401 | public: |
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 | |
590 | inline constexpr strong_ordering strong_ordering::less(QtPrivate::Ordering::Less); |
591 | inline constexpr strong_ordering strong_ordering::equivalent(QtPrivate::Ordering::Equivalent); |
592 | inline constexpr strong_ordering strong_ordering::equal(QtPrivate::Ordering::Equal); |
593 | inline constexpr strong_ordering strong_ordering::greater(QtPrivate::Ordering::Greater); |
594 | |
595 | } // namespace Qt |
596 | |
597 | QT_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 | |
603 | QT_END_INCLUDE_NAMESPACE |
604 | |
605 | namespace QtPrivate { |
606 | |
607 | namespace 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 | |
643 | template <typename LeftType, typename RightType> |
644 | auto qCompareThreeWay(const LeftType &lhs, const RightType &rhs); |
645 | |
646 | #else |
647 | |
648 | template <typename LT, typename RT, |
649 | std::enable_if_t<QtPrivate::CompareThreeWayTester::hasCompareThreeWay<LT, RT> |
650 | || QtPrivate::CompareThreeWayTester::hasCompareThreeWay<RT, LT>, |
651 | bool> = true> |
652 | auto 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 | |
670 | namespace QtPrivate { |
671 | enum class LegacyUncomparable : CompareUnderlyingType |
672 | { |
673 | Unordered = -127 |
674 | }; |
675 | } |
676 | |
677 | // [cmp.partialord] |
678 | class QPartialOrdering |
679 | { |
680 | public: |
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 | |
852 | private: |
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 | |
879 | inline constexpr QPartialOrdering QPartialOrdering::Less(QtPrivate::Ordering::Less); |
880 | inline constexpr QPartialOrdering QPartialOrdering::Equivalent(QtPrivate::Ordering::Equivalent); |
881 | inline constexpr QPartialOrdering QPartialOrdering::Greater(QtPrivate::Ordering::Greater); |
882 | inline constexpr QPartialOrdering QPartialOrdering::Unordered(QtPrivate::LegacyUncomparable::Unordered); |
883 | |
884 | inline constexpr QPartialOrdering QPartialOrdering::less(QtPrivate::Ordering::Less); |
885 | inline constexpr QPartialOrdering QPartialOrdering::equivalent(QtPrivate::Ordering::Equivalent); |
886 | inline constexpr QPartialOrdering QPartialOrdering::greater(QtPrivate::Ordering::Greater); |
887 | inline constexpr QPartialOrdering QPartialOrdering::unordered(QtPrivate::LegacyUncomparable::Unordered); |
888 | |
889 | QT_END_NAMESPACE |
890 | |
891 | #endif // QCOMPARE_H |
892 | |