1// Copyright (C) 2023 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
4#ifndef QCOMPARE_H
5#error "Do not include qcomparehelpers.h directly. Use qcompare.h instead."
6#endif
7
8#ifndef QCOMPAREHELPERS_H
9#define QCOMPAREHELPERS_H
10
11#if 0
12#pragma qt_no_master_include
13#pragma qt_sync_skip_header_check
14#pragma qt_sync_stop_processing
15#endif
16
17#include <QtCore/qoverload.h>
18#include <QtCore/qttypetraits.h>
19#include <QtCore/qtypes.h>
20
21#ifdef __cpp_lib_three_way_comparison
22#include <compare>
23#endif
24#include <QtCore/q20type_traits.h>
25
26#include <functional> // std::less
27
28QT_BEGIN_NAMESPACE
29
30class QPartialOrdering;
31
32namespace QtOrderingPrivate {
33#ifdef __cpp_lib_three_way_comparison
34
35template <typename QtOrdering> struct StdOrdering;
36template <typename StdOrdering> struct QtOrdering;
37
38#define QT_STD_MAP(x) \
39 template <> struct StdOrdering< Qt::x##_ordering> : q20::type_identity<std::x##_ordering> {};\
40 template <> struct StdOrdering<std::x##_ordering> : q20::type_identity<std::x##_ordering> {};\
41 template <> struct QtOrdering<std::x##_ordering> : q20::type_identity< Qt::x##_ordering> {};\
42 template <> struct QtOrdering< Qt::x##_ordering> : q20::type_identity< Qt::x##_ordering> {};\
43 /* end */
44QT_STD_MAP(partial)
45QT_STD_MAP(weak)
46QT_STD_MAP(strong)
47#undef QT_STD_MAP
48
49template <> struct StdOrdering<QPartialOrdering> : q20::type_identity<std::partial_ordering> {};
50template <> struct QtOrdering<QPartialOrdering> : q20::type_identity< Qt::partial_ordering> {};
51
52template <typename In> constexpr auto to_std(In in) noexcept
53 -> typename QtOrderingPrivate::StdOrdering<In>::type
54{ return in; }
55
56template <typename In> constexpr auto to_Qt(In in) noexcept
57 -> typename QtOrderingPrivate::QtOrdering<In>::type
58{ return in; }
59
60#endif // __cpp_lib_three_way_comparison
61} // namespace QtOrderingPrivate
62
63/*
64 For all the macros these parameter names are used:
65 * LeftType - the type of the left operand of the comparison
66 * RightType - the type of the right operand of the comparison
67 * Constexpr - must be either constexpr or empty. Defines whether the
68 operator is constexpr or not
69
70 The macros require two helper functions. For operators to be constexpr,
71 these must be constexpr, too. Additionally, other attributes (like
72 Q_<Module>_EXPORT, Q_DECL_CONST_FUNCTION, etc) can be applied to them.
73 Aside from that, their declaration should match:
74 bool comparesEqual(LeftType, RightType) noexcept;
75 ReturnType compareThreeWay(LeftType, RightType) noexcept;
76
77 The ReturnType can be one of Qt::{partial,weak,strong}_ordering. The actual
78 type depends on the macro being used.
79 It makes sense to define the helper functions as hidden friends of the
80 class, so that they could be found via ADL, and don't participate in
81 unintended implicit conversions.
82*/
83
84// Seems that qdoc uses C++20 even when Qt is compiled in C++17 mode.
85// Or at least it defines __cpp_lib_three_way_comparison.
86// Let qdoc see only the C++17 operators for now, because that's what our docs
87// currently describe.
88#if defined(__cpp_lib_three_way_comparison) && !defined(Q_QDOC)
89// C++20 - provide operator==() for equality, and operator<=>() for ordering
90
91#define QT_DECLARE_EQUALITY_OPERATORS_HELPER(LeftType, RightType, Constexpr) \
92 friend Constexpr bool operator==(LeftType const &lhs, RightType const &rhs) \
93 noexcept(noexcept(comparesEqual(lhs, rhs))) \
94 { return comparesEqual(lhs, rhs); }
95
96#define QT_DECLARE_3WAY_HELPER_STRONG(LeftType, RightType, Constexpr) \
97 friend Constexpr std::strong_ordering \
98 operator<=>(LeftType const &lhs, RightType const &rhs) \
99 noexcept(noexcept(compareThreeWay(lhs, rhs))) \
100 { \
101 return compareThreeWay(lhs, rhs); \
102 }
103
104#define QT_DECLARE_3WAY_HELPER_WEAK(LeftType, RightType, Constexpr) \
105 friend Constexpr std::weak_ordering \
106 operator<=>(LeftType const &lhs, RightType const &rhs) \
107 noexcept(noexcept(compareThreeWay(lhs, rhs))) \
108 { \
109 return compareThreeWay(lhs, rhs); \
110 }
111
112#define QT_DECLARE_3WAY_HELPER_PARTIAL(LeftType, RightType, Constexpr) \
113 friend Constexpr std::partial_ordering \
114 operator<=>(LeftType const &lhs, RightType const &rhs) \
115 noexcept(noexcept(compareThreeWay(lhs, rhs))) \
116 { \
117 return compareThreeWay(lhs, rhs); \
118 }
119
120#define QT_DECLARE_ORDERING_OPERATORS_HELPER(OrderingType, LeftType, RightType, Constexpr) \
121 QT_DECLARE_EQUALITY_OPERATORS_HELPER(LeftType, RightType, Constexpr) \
122 QT_DECLARE_3WAY_HELPER_ ## OrderingType (LeftType, RightType, Constexpr)
123
124#ifdef Q_COMPILER_LACKS_THREE_WAY_COMPARE_SYMMETRY
125
126// define reversed versions of the operators manually, because buggy MSVC versions do not do it
127#define QT_DECLARE_EQUALITY_OPERATORS_REVERSED_HELPER(LeftType, RightType, Constexpr) \
128 friend Constexpr bool operator==(RightType const &lhs, LeftType const &rhs) \
129 noexcept(noexcept(comparesEqual(rhs, lhs))) \
130 { return comparesEqual(rhs, lhs); }
131
132#define QT_DECLARE_REVERSED_3WAY_HELPER_STRONG(LeftType, RightType, Constexpr) \
133 friend Constexpr std::strong_ordering \
134 operator<=>(RightType const &lhs, LeftType const &rhs) \
135 noexcept(noexcept(compareThreeWay(rhs, lhs))) \
136 { \
137 const auto r = compareThreeWay(rhs, lhs); \
138 if (r > 0) return std::strong_ordering::less; \
139 if (r < 0) return std::strong_ordering::greater; \
140 return r; \
141 }
142
143#define QT_DECLARE_REVERSED_3WAY_HELPER_WEAK(LeftType, RightType, Constexpr) \
144 friend Constexpr std::weak_ordering \
145 operator<=>(RightType const &lhs, LeftType const &rhs) \
146 noexcept(noexcept(compareThreeWay(rhs, lhs))) \
147 { \
148 const auto r = compareThreeWay(rhs, lhs); \
149 if (r > 0) return std::weak_ordering::less; \
150 if (r < 0) return std::weak_ordering::greater; \
151 return r; \
152 }
153
154#define QT_DECLARE_REVERSED_3WAY_HELPER_PARTIAL(LeftType, RightType, Constexpr) \
155 friend Constexpr std::partial_ordering \
156 operator<=>(RightType const &lhs, LeftType const &rhs) \
157 noexcept(noexcept(compareThreeWay(rhs, lhs))) \
158 { \
159 const auto r = compareThreeWay(rhs, lhs); \
160 if (r > 0) return std::partial_ordering::less; \
161 if (r < 0) return std::partial_ordering::greater; \
162 return r; \
163 }
164
165#define QT_DECLARE_ORDERING_OPERATORS_REVERSED_HELPER(OrderingString, LeftType, RightType, \
166 Constexpr) \
167 QT_DECLARE_EQUALITY_OPERATORS_REVERSED_HELPER(LeftType, RightType, Constexpr) \
168 QT_DECLARE_REVERSED_3WAY_HELPER_ ## OrderingString (LeftType, RightType, Constexpr)
169
170#else
171
172// dummy macros for C++17 compatibility, reversed operators are generated by the compiler
173#define QT_DECLARE_EQUALITY_OPERATORS_REVERSED_HELPER(LeftType, RightType, Constexpr)
174#define QT_DECLARE_ORDERING_OPERATORS_REVERSED_HELPER(OrderingString, LeftType, RightType, Constexpr)
175
176#endif // Q_COMPILER_LACKS_THREE_WAY_COMPARE_SYMMETRY
177
178#else
179// C++17 - provide operator==() and operator!=() for equality,
180// and all 4 comparison operators for ordering
181
182#define QT_DECLARE_EQUALITY_OPERATORS_HELPER(LeftType, RightType, Constexpr) \
183 friend Constexpr bool operator==(LeftType const &lhs, RightType const &rhs) \
184 noexcept(noexcept(comparesEqual(lhs, rhs))) \
185 { return comparesEqual(lhs, rhs); } \
186 friend Constexpr bool operator!=(LeftType const &lhs, RightType const &rhs) \
187 noexcept(noexcept(comparesEqual(lhs, rhs))) \
188 { return !comparesEqual(lhs, rhs); }
189
190// Helpers for reversed comparison, using the existing comparesEqual() function.
191#define QT_DECLARE_EQUALITY_OPERATORS_REVERSED_HELPER(LeftType, RightType, Constexpr) \
192 friend Constexpr bool operator==(RightType const &lhs, LeftType const &rhs) \
193 noexcept(noexcept(comparesEqual(rhs, lhs))) \
194 { return comparesEqual(rhs, lhs); } \
195 friend Constexpr bool operator!=(RightType const &lhs, LeftType const &rhs) \
196 noexcept(noexcept(comparesEqual(rhs, lhs))) \
197 { return !comparesEqual(rhs, lhs); }
198
199#define QT_DECLARE_ORDERING_HELPER_TEMPLATE(OrderingType, LeftType, RightType, Constexpr) \
200 friend Constexpr bool operator<(LeftType const &lhs, RightType const &rhs) \
201 noexcept(noexcept(compareThreeWay(lhs, rhs))) \
202 { return compareThreeWay(lhs, rhs) < 0; } \
203 friend Constexpr bool operator>(LeftType const &lhs, RightType const &rhs) \
204 noexcept(noexcept(compareThreeWay(lhs, rhs))) \
205 { return compareThreeWay(lhs, rhs) > 0; } \
206 friend Constexpr bool operator<=(LeftType const &lhs, RightType const &rhs) \
207 noexcept(noexcept(compareThreeWay(lhs, rhs))) \
208 { return compareThreeWay(lhs, rhs) <= 0; } \
209 friend Constexpr bool operator>=(LeftType const &lhs, RightType const &rhs) \
210 noexcept(noexcept(compareThreeWay(lhs, rhs))) \
211 { return compareThreeWay(lhs, rhs) >= 0; }
212
213#define QT_DECLARE_ORDERING_HELPER_PARTIAL(LeftType, RightType, Constexpr) \
214 QT_DECLARE_ORDERING_HELPER_TEMPLATE(Qt::partial_ordering, LeftType, RightType, Constexpr)
215
216#define QT_DECLARE_ORDERING_HELPER_WEAK(LeftType, RightType, Constexpr) \
217 QT_DECLARE_ORDERING_HELPER_TEMPLATE(Qt::weak_ordering, LeftType, RightType, Constexpr)
218
219#define QT_DECLARE_ORDERING_HELPER_STRONG(LeftType, RightType, Constexpr) \
220 QT_DECLARE_ORDERING_HELPER_TEMPLATE(Qt::strong_ordering, LeftType, RightType, Constexpr)
221
222#define QT_DECLARE_ORDERING_OPERATORS_HELPER(OrderingString, LeftType, RightType, Constexpr) \
223 QT_DECLARE_EQUALITY_OPERATORS_HELPER(LeftType, RightType, Constexpr) \
224 QT_DECLARE_ORDERING_HELPER_ ## OrderingString (LeftType, RightType, Constexpr)
225
226// Helpers for reversed ordering, using the existing compareThreeWay() function.
227#define QT_DECLARE_REVERSED_ORDERING_HELPER_TEMPLATE(OrderingType, LeftType, RightType, Constexpr) \
228 friend Constexpr bool operator<(RightType const &lhs, LeftType const &rhs) \
229 noexcept(noexcept(compareThreeWay(rhs, lhs))) \
230 { return compareThreeWay(rhs, lhs) > 0; } \
231 friend Constexpr bool operator>(RightType const &lhs, LeftType const &rhs) \
232 noexcept(noexcept(compareThreeWay(rhs, lhs))) \
233 { return compareThreeWay(rhs, lhs) < 0; } \
234 friend Constexpr bool operator<=(RightType const &lhs, LeftType const &rhs) \
235 noexcept(noexcept(compareThreeWay(rhs, lhs))) \
236 { return compareThreeWay(rhs, lhs) >= 0; } \
237 friend Constexpr bool operator>=(RightType const &lhs, LeftType const &rhs) \
238 noexcept(noexcept(compareThreeWay(rhs, lhs))) \
239 { return compareThreeWay(rhs, lhs) <= 0; }
240
241#define QT_DECLARE_REVERSED_ORDERING_HELPER_PARTIAL(LeftType, RightType, Constexpr) \
242 QT_DECLARE_REVERSED_ORDERING_HELPER_TEMPLATE(Qt::partial_ordering, LeftType, RightType, Constexpr)
243
244#define QT_DECLARE_REVERSED_ORDERING_HELPER_WEAK(LeftType, RightType, Constexpr) \
245 QT_DECLARE_REVERSED_ORDERING_HELPER_TEMPLATE(Qt::weak_ordering, LeftType, RightType, Constexpr)
246
247#define QT_DECLARE_REVERSED_ORDERING_HELPER_STRONG(LeftType, RightType, Constexpr) \
248 QT_DECLARE_REVERSED_ORDERING_HELPER_TEMPLATE(Qt::strong_ordering, LeftType, RightType, Constexpr)
249
250#define QT_DECLARE_ORDERING_OPERATORS_REVERSED_HELPER(OrderingString, LeftType, RightType, \
251 Constexpr) \
252 QT_DECLARE_EQUALITY_OPERATORS_REVERSED_HELPER(LeftType, RightType, Constexpr) \
253 QT_DECLARE_REVERSED_ORDERING_HELPER_ ## OrderingString (LeftType, RightType, Constexpr)
254
255#endif // __cpp_lib_three_way_comparison
256
257/* Public API starts here */
258
259// Equality operators
260#define QT_DECLARE_EQUALITY_COMPARABLE_1(Type) \
261 QT_DECLARE_EQUALITY_OPERATORS_HELPER(Type, Type, /* non-constexpr */)
262
263#define QT_DECLARE_EQUALITY_COMPARABLE_2(LeftType, RightType) \
264 QT_DECLARE_EQUALITY_OPERATORS_HELPER(LeftType, RightType, /* non-constexpr */) \
265 QT_DECLARE_EQUALITY_OPERATORS_REVERSED_HELPER(LeftType, RightType, /* non-constexpr */)
266
267#define Q_DECLARE_EQUALITY_COMPARABLE(...) \
268 QT_OVERLOADED_MACRO(QT_DECLARE_EQUALITY_COMPARABLE, __VA_ARGS__)
269
270#define QT_DECLARE_EQUALITY_COMPARABLE_LITERAL_TYPE_1(Type) \
271 QT_DECLARE_EQUALITY_OPERATORS_HELPER(Type, Type, constexpr)
272
273#define QT_DECLARE_EQUALITY_COMPARABLE_LITERAL_TYPE_2(LeftType, RightType) \
274 QT_DECLARE_EQUALITY_OPERATORS_HELPER(LeftType, RightType, constexpr) \
275 QT_DECLARE_EQUALITY_OPERATORS_REVERSED_HELPER(LeftType, RightType, constexpr)
276
277#define Q_DECLARE_EQUALITY_COMPARABLE_LITERAL_TYPE(...) \
278 QT_OVERLOADED_MACRO(QT_DECLARE_EQUALITY_COMPARABLE_LITERAL_TYPE, __VA_ARGS__)
279
280// Partial ordering operators
281#define QT_DECLARE_PARTIALLY_ORDERED_1(Type) \
282 QT_DECLARE_ORDERING_OPERATORS_HELPER(PARTIAL, Type, Type, /* non-constexpr */)
283
284#define QT_DECLARE_PARTIALLY_ORDERED_2(LeftType, RightType) \
285 QT_DECLARE_ORDERING_OPERATORS_HELPER(PARTIAL, LeftType, RightType, /* non-constexpr */) \
286 QT_DECLARE_ORDERING_OPERATORS_REVERSED_HELPER(PARTIAL, LeftType, RightType, /* non-constexpr */)
287
288#define Q_DECLARE_PARTIALLY_ORDERED(...) \
289 QT_OVERLOADED_MACRO(QT_DECLARE_PARTIALLY_ORDERED, __VA_ARGS__)
290
291#define QT_DECLARE_PARTIALLY_ORDERED_LITERAL_TYPE_1(Type) \
292 QT_DECLARE_ORDERING_OPERATORS_HELPER(PARTIAL, Type, Type, constexpr)
293
294#define QT_DECLARE_PARTIALLY_ORDERED_LITERAL_TYPE_2(LeftType, RightType) \
295 QT_DECLARE_ORDERING_OPERATORS_HELPER(PARTIAL, LeftType, RightType, constexpr) \
296 QT_DECLARE_ORDERING_OPERATORS_REVERSED_HELPER(PARTIAL, LeftType, RightType, constexpr)
297
298#define Q_DECLARE_PARTIALLY_ORDERED_LITERAL_TYPE(...) \
299 QT_OVERLOADED_MACRO(QT_DECLARE_PARTIALLY_ORDERED_LITERAL_TYPE, __VA_ARGS__)
300
301// Weak ordering operators
302#define QT_DECLARE_WEAKLY_ORDERED_1(Type) \
303 QT_DECLARE_ORDERING_OPERATORS_HELPER(WEAK, Type, Type, /* non-constexpr */)
304
305#define QT_DECLARE_WEAKLY_ORDERED_2(LeftType, RightType) \
306 QT_DECLARE_ORDERING_OPERATORS_HELPER(WEAK, LeftType, RightType, /* non-constexpr */) \
307 QT_DECLARE_ORDERING_OPERATORS_REVERSED_HELPER(WEAK, LeftType, RightType, /* non-constexpr */)
308
309#define Q_DECLARE_WEAKLY_ORDERED(...) \
310 QT_OVERLOADED_MACRO(QT_DECLARE_WEAKLY_ORDERED, __VA_ARGS__)
311
312#define QT_DECLARE_WEAKLY_ORDERED_LITERAL_TYPE_1(Type) \
313 QT_DECLARE_ORDERING_OPERATORS_HELPER(WEAK, Type, Type, constexpr)
314
315#define QT_DECLARE_WEAKLY_ORDERED_LITERAL_TYPE_2(LeftType, RightType) \
316 QT_DECLARE_ORDERING_OPERATORS_HELPER(WEAK, LeftType, RightType, constexpr) \
317 QT_DECLARE_ORDERING_OPERATORS_REVERSED_HELPER(WEAK, LeftType, RightType, constexpr)
318
319#define Q_DECLARE_WEAKLY_ORDERED_LITERAL_TYPE(...) \
320 QT_OVERLOADED_MACRO(QT_DECLARE_WEAKLY_ORDERED_LITERAL_TYPE, __VA_ARGS__)
321
322// Strong ordering operators
323#define QT_DECLARE_STRONGLY_ORDERED_1(Type) \
324 QT_DECLARE_ORDERING_OPERATORS_HELPER(STRONG, Type, Type, /* non-constexpr */)
325
326#define QT_DECLARE_STRONGLY_ORDERED_2(LeftType, RightType) \
327 QT_DECLARE_ORDERING_OPERATORS_HELPER(STRONG, LeftType, RightType, /* non-constexpr */) \
328 QT_DECLARE_ORDERING_OPERATORS_REVERSED_HELPER(STRONG, LeftType, RightType, /* non-constexpr */)
329
330#define Q_DECLARE_STRONGLY_ORDERED(...) \
331 QT_OVERLOADED_MACRO(QT_DECLARE_STRONGLY_ORDERED, __VA_ARGS__)
332
333#define QT_DECLARE_STRONGLY_ORDERED_LITERAL_TYPE_1(Type) \
334 QT_DECLARE_ORDERING_OPERATORS_HELPER(STRONG, Type, Type, constexpr)
335
336#define QT_DECLARE_STRONGLY_ORDERED_LITERAL_TYPE_2(LeftType, RightType) \
337 QT_DECLARE_ORDERING_OPERATORS_HELPER(STRONG, LeftType, RightType, constexpr) \
338 QT_DECLARE_ORDERING_OPERATORS_REVERSED_HELPER(STRONG, LeftType, RightType, constexpr)
339
340#define Q_DECLARE_STRONGLY_ORDERED_LITERAL_TYPE(...) \
341 QT_OVERLOADED_MACRO(QT_DECLARE_STRONGLY_ORDERED_LITERAL_TYPE, __VA_ARGS__)
342
343namespace QtPrivate {
344
345template <typename T>
346constexpr bool IsIntegralType_v = std::numeric_limits<std::remove_const_t<T>>::is_specialized
347 && std::numeric_limits<std::remove_const_t<T>>::is_integer;
348
349template <typename T>
350constexpr bool IsFloatType_v = std::is_floating_point_v<T>;
351
352#if QFLOAT16_IS_NATIVE
353template <>
354constexpr bool IsFloatType_v<QtPrivate::NativeFloat16Type> = true;
355#endif
356
357} // namespace QtPrivate
358
359namespace Qt {
360
361template <typename T>
362using if_integral = std::enable_if_t<QtPrivate::IsIntegralType_v<T>, bool>;
363
364template <typename T>
365using if_floating_point = std::enable_if_t<QtPrivate::IsFloatType_v<T>, bool>;
366
367template <typename T, typename U>
368using if_compatible_pointers =
369 std::enable_if_t<std::disjunction_v<std::is_same<T, U>,
370 std::is_base_of<T, U>,
371 std::is_base_of<U, T>>,
372 bool>;
373
374template <typename Enum>
375using if_enum = std::enable_if_t<std::is_enum_v<Enum>, bool>;
376
377template <typename LeftInt, typename RightInt,
378 if_integral<LeftInt> = true,
379 if_integral<RightInt> = true>
380constexpr Qt::strong_ordering compareThreeWay(LeftInt lhs, RightInt rhs) noexcept
381{
382 static_assert(std::is_signed_v<LeftInt> == std::is_signed_v<RightInt>,
383 "Qt::compareThreeWay() does not allow mixed-sign comparison.");
384
385#ifdef __cpp_lib_three_way_comparison
386 return lhs <=> rhs;
387#else
388 if (lhs == rhs)
389 return Qt::strong_ordering::equivalent;
390 else if (lhs < rhs)
391 return Qt::strong_ordering::less;
392 else
393 return Qt::strong_ordering::greater;
394#endif // __cpp_lib_three_way_comparison
395}
396
397template <typename LeftFloat, typename RightFloat,
398 if_floating_point<LeftFloat> = true,
399 if_floating_point<RightFloat> = true>
400constexpr Qt::partial_ordering compareThreeWay(LeftFloat lhs, RightFloat rhs) noexcept
401{
402QT_WARNING_PUSH
403QT_WARNING_DISABLE_FLOAT_COMPARE
404#ifdef __cpp_lib_three_way_comparison
405 return lhs <=> rhs;
406#else
407 if (lhs < rhs)
408 return Qt::partial_ordering::less;
409 else if (lhs > rhs)
410 return Qt::partial_ordering::greater;
411 else if (lhs == rhs)
412 return Qt::partial_ordering::equivalent;
413 else
414 return Qt::partial_ordering::unordered;
415#endif // __cpp_lib_three_way_comparison
416QT_WARNING_POP
417}
418
419template <typename IntType, typename FloatType,
420 if_integral<IntType> = true,
421 if_floating_point<FloatType> = true>
422constexpr Qt::partial_ordering compareThreeWay(IntType lhs, FloatType rhs) noexcept
423{
424 return compareThreeWay(FloatType(lhs), rhs);
425}
426
427template <typename FloatType, typename IntType,
428 if_floating_point<FloatType> = true,
429 if_integral<IntType> = true>
430constexpr Qt::partial_ordering compareThreeWay(FloatType lhs, IntType rhs) noexcept
431{
432 return compareThreeWay(lhs, FloatType(rhs));
433}
434
435template <typename LeftType, typename RightType,
436 if_compatible_pointers<LeftType, RightType> = true>
437constexpr Qt::strong_ordering compareThreeWay(const LeftType *lhs, const RightType *rhs) noexcept
438{
439#ifdef __cpp_lib_three_way_comparison
440 return std::compare_three_way{}(lhs, rhs);
441#else
442 if (lhs == rhs)
443 return Qt::strong_ordering::equivalent;
444 else if (std::less<>{}(lhs, rhs))
445 return Qt::strong_ordering::less;
446 else
447 return Qt::strong_ordering::greater;
448#endif // __cpp_lib_three_way_comparison
449}
450
451template <typename T>
452constexpr Qt::strong_ordering compareThreeWay(const T *lhs, std::nullptr_t rhs) noexcept
453{
454 return compareThreeWay(lhs, static_cast<const T *>(rhs));
455}
456
457template <typename T>
458constexpr Qt::strong_ordering compareThreeWay(std::nullptr_t lhs, const T *rhs) noexcept
459{
460 return compareThreeWay(static_cast<const T *>(lhs), rhs);
461}
462
463template <class Enum, if_enum<Enum> = true>
464constexpr Qt::strong_ordering compareThreeWay(Enum lhs, Enum rhs) noexcept
465{
466 return compareThreeWay(qToUnderlying(lhs), qToUnderlying(rhs));
467}
468
469} // namespace Qt
470
471QT_END_NAMESPACE
472
473#endif // QCOMPAREHELPERS_H
474