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 | |
28 | QT_BEGIN_NAMESPACE |
29 | |
30 | class QPartialOrdering; |
31 | |
32 | namespace QtOrderingPrivate { |
33 | #ifdef __cpp_lib_three_way_comparison |
34 | |
35 | template <typename QtOrdering> struct StdOrdering; |
36 | template <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 */ |
44 | QT_STD_MAP(partial) |
45 | QT_STD_MAP(weak) |
46 | QT_STD_MAP(strong) |
47 | #undef QT_STD_MAP |
48 | |
49 | template <> struct StdOrdering<QPartialOrdering> : q20::type_identity<std::partial_ordering> {}; |
50 | template <> struct QtOrdering<QPartialOrdering> : q20::type_identity< Qt::partial_ordering> {}; |
51 | |
52 | template <typename In> constexpr auto to_std(In in) noexcept |
53 | -> typename QtOrderingPrivate::StdOrdering<In>::type |
54 | { return in; } |
55 | |
56 | template <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 | |
343 | namespace QtPrivate { |
344 | |
345 | template <typename T> |
346 | constexpr 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 | |
349 | template <typename T> |
350 | constexpr bool IsFloatType_v = std::is_floating_point_v<T>; |
351 | |
352 | #if QFLOAT16_IS_NATIVE |
353 | template <> |
354 | constexpr bool IsFloatType_v<QtPrivate::NativeFloat16Type> = true; |
355 | #endif |
356 | |
357 | } // namespace QtPrivate |
358 | |
359 | namespace Qt { |
360 | |
361 | template <typename T> |
362 | using if_integral = std::enable_if_t<QtPrivate::IsIntegralType_v<T>, bool>; |
363 | |
364 | template <typename T> |
365 | using if_floating_point = std::enable_if_t<QtPrivate::IsFloatType_v<T>, bool>; |
366 | |
367 | template <typename T, typename U> |
368 | using 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 | |
374 | template <typename Enum> |
375 | using if_enum = std::enable_if_t<std::is_enum_v<Enum>, bool>; |
376 | |
377 | template <typename LeftInt, typename RightInt, |
378 | if_integral<LeftInt> = true, |
379 | if_integral<RightInt> = true> |
380 | constexpr 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 | |
397 | template <typename LeftFloat, typename RightFloat, |
398 | if_floating_point<LeftFloat> = true, |
399 | if_floating_point<RightFloat> = true> |
400 | constexpr Qt::partial_ordering compareThreeWay(LeftFloat lhs, RightFloat rhs) noexcept |
401 | { |
402 | QT_WARNING_PUSH |
403 | QT_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 |
416 | QT_WARNING_POP |
417 | } |
418 | |
419 | template <typename IntType, typename FloatType, |
420 | if_integral<IntType> = true, |
421 | if_floating_point<FloatType> = true> |
422 | constexpr Qt::partial_ordering compareThreeWay(IntType lhs, FloatType rhs) noexcept |
423 | { |
424 | return compareThreeWay(FloatType(lhs), rhs); |
425 | } |
426 | |
427 | template <typename FloatType, typename IntType, |
428 | if_floating_point<FloatType> = true, |
429 | if_integral<IntType> = true> |
430 | constexpr Qt::partial_ordering compareThreeWay(FloatType lhs, IntType rhs) noexcept |
431 | { |
432 | return compareThreeWay(lhs, FloatType(rhs)); |
433 | } |
434 | |
435 | template <typename LeftType, typename RightType, |
436 | if_compatible_pointers<LeftType, RightType> = true> |
437 | constexpr 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 | |
451 | template <typename T> |
452 | constexpr Qt::strong_ordering compareThreeWay(const T *lhs, std::nullptr_t rhs) noexcept |
453 | { |
454 | return compareThreeWay(lhs, static_cast<const T *>(rhs)); |
455 | } |
456 | |
457 | template <typename T> |
458 | constexpr Qt::strong_ordering compareThreeWay(std::nullptr_t lhs, const T *rhs) noexcept |
459 | { |
460 | return compareThreeWay(static_cast<const T *>(lhs), rhs); |
461 | } |
462 | |
463 | template <class Enum, if_enum<Enum> = true> |
464 | constexpr Qt::strong_ordering compareThreeWay(Enum lhs, Enum rhs) noexcept |
465 | { |
466 | return compareThreeWay(qToUnderlying(lhs), qToUnderlying(rhs)); |
467 | } |
468 | |
469 | } // namespace Qt |
470 | |
471 | QT_END_NAMESPACE |
472 | |
473 | #endif // QCOMPAREHELPERS_H |
474 | |