]>
Commit | Line | Data |
---|---|---|
b7689b96 JM |
1 | // -*- C++ -*- operator<=> three-way comparison support. |
2 | ||
a945c346 | 3 | // Copyright (C) 2019-2024 Free Software Foundation, Inc. |
b7689b96 JM |
4 | // |
5 | // This file is part of GCC. | |
6 | // | |
7 | // GCC is free software; you can redistribute it and/or modify | |
8 | // it under the terms of the GNU General Public License as published by | |
9 | // the Free Software Foundation; either version 3, or (at your option) | |
10 | // any later version. | |
11 | // | |
12 | // GCC is distributed in the hope that it will be useful, | |
13 | // but WITHOUT ANY WARRANTY; without even the implied warranty of | |
14 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
15 | // GNU General Public License for more details. | |
16 | // | |
17 | // Under Section 7 of GPL version 3, you are granted additional | |
18 | // permissions described in the GCC Runtime Library Exception, version | |
19 | // 3.1, as published by the Free Software Foundation. | |
20 | ||
21 | // You should have received a copy of the GNU General Public License and | |
22 | // a copy of the GCC Runtime Library Exception along with this program; | |
23 | // see the files COPYING3 and COPYING.RUNTIME respectively. If not, see | |
24 | // <http://www.gnu.org/licenses/>. | |
25 | ||
26 | /** @file compare | |
27 | * This is a Standard C++ Library header. | |
28 | */ | |
29 | ||
30 | #ifndef _COMPARE | |
31 | #define _COMPARE | |
32 | ||
33 | #pragma GCC system_header | |
34 | ||
083b7f28 AA |
35 | #define __glibcxx_want_three_way_comparison |
36 | #include <bits/version.h> | |
37 | ||
b7689b96 JM |
38 | #if __cplusplus > 201703L && __cpp_impl_three_way_comparison >= 201907L |
39 | ||
b7689b96 JM |
40 | #include <concepts> |
41 | ||
d3a7302e JM |
42 | #pragma GCC diagnostic push |
43 | #pragma GCC diagnostic ignored "-Wpedantic" // __int128 | |
44 | #pragma GCC diagnostic ignored "-Wzero-as-null-pointer-constant" | |
45 | ||
488d2687 | 46 | namespace std _GLIBCXX_VISIBILITY(default) |
b7689b96 | 47 | { |
b7689b96 JM |
48 | // [cmp.categories], comparison category types |
49 | ||
50 | namespace __cmp_cat | |
51 | { | |
0d57370c | 52 | using type = signed char; |
b7689b96 | 53 | |
0d57370c JW |
54 | enum class _Ord : type { equivalent = 0, less = -1, greater = 1 }; |
55 | ||
56 | enum class _Ncmp : type { _Unordered = 2 }; | |
b7689b96 JM |
57 | |
58 | struct __unspec | |
59 | { | |
84cff28f | 60 | consteval __unspec(__unspec*) noexcept { } |
b7689b96 JM |
61 | }; |
62 | } | |
63 | ||
b7689b96 JM |
64 | class partial_ordering |
65 | { | |
0d57370c JW |
66 | // less=0xff, equiv=0x00, greater=0x01, unordered=0x02 |
67 | __cmp_cat::type _M_value; | |
b7689b96 | 68 | |
b7689b96 JM |
69 | constexpr explicit |
70 | partial_ordering(__cmp_cat::_Ord __v) noexcept | |
0d57370c | 71 | : _M_value(__cmp_cat::type(__v)) |
b7689b96 JM |
72 | { } |
73 | ||
74 | constexpr explicit | |
75 | partial_ordering(__cmp_cat::_Ncmp __v) noexcept | |
0d57370c | 76 | : _M_value(__cmp_cat::type(__v)) |
b7689b96 JM |
77 | { } |
78 | ||
0d57370c JW |
79 | friend class weak_ordering; |
80 | friend class strong_ordering; | |
81 | ||
b7689b96 JM |
82 | public: |
83 | // valid values | |
84 | static const partial_ordering less; | |
85 | static const partial_ordering equivalent; | |
86 | static const partial_ordering greater; | |
87 | static const partial_ordering unordered; | |
88 | ||
b7689b96 | 89 | // comparisons |
8dec72ae | 90 | [[nodiscard]] |
b7689b96 JM |
91 | friend constexpr bool |
92 | operator==(partial_ordering __v, __cmp_cat::__unspec) noexcept | |
0d57370c | 93 | { return __v._M_value == 0; } |
b7689b96 | 94 | |
8dec72ae | 95 | [[nodiscard]] |
b7689b96 JM |
96 | friend constexpr bool |
97 | operator==(partial_ordering, partial_ordering) noexcept = default; | |
98 | ||
8dec72ae | 99 | [[nodiscard]] |
b7689b96 JM |
100 | friend constexpr bool |
101 | operator< (partial_ordering __v, __cmp_cat::__unspec) noexcept | |
0d57370c | 102 | { return __v._M_value == -1; } |
b7689b96 | 103 | |
8dec72ae | 104 | [[nodiscard]] |
b7689b96 JM |
105 | friend constexpr bool |
106 | operator> (partial_ordering __v, __cmp_cat::__unspec) noexcept | |
0d57370c | 107 | { return __v._M_value == 1; } |
b7689b96 | 108 | |
8dec72ae | 109 | [[nodiscard]] |
b7689b96 JM |
110 | friend constexpr bool |
111 | operator<=(partial_ordering __v, __cmp_cat::__unspec) noexcept | |
0d57370c | 112 | { return __v._M_value <= 0; } |
b7689b96 | 113 | |
8dec72ae | 114 | [[nodiscard]] |
b7689b96 JM |
115 | friend constexpr bool |
116 | operator>=(partial_ordering __v, __cmp_cat::__unspec) noexcept | |
0d57370c | 117 | { return __cmp_cat::type(__v._M_value & 1) == __v._M_value; } |
b7689b96 | 118 | |
8dec72ae | 119 | [[nodiscard]] |
b7689b96 JM |
120 | friend constexpr bool |
121 | operator< (__cmp_cat::__unspec, partial_ordering __v) noexcept | |
0d57370c | 122 | { return __v._M_value == 1; } |
b7689b96 | 123 | |
8dec72ae | 124 | [[nodiscard]] |
b7689b96 JM |
125 | friend constexpr bool |
126 | operator> (__cmp_cat::__unspec, partial_ordering __v) noexcept | |
0d57370c | 127 | { return __v._M_value == -1; } |
b7689b96 | 128 | |
8dec72ae | 129 | [[nodiscard]] |
b7689b96 JM |
130 | friend constexpr bool |
131 | operator<=(__cmp_cat::__unspec, partial_ordering __v) noexcept | |
0d57370c | 132 | { return __cmp_cat::type(__v._M_value & 1) == __v._M_value; } |
b7689b96 | 133 | |
8dec72ae | 134 | [[nodiscard]] |
b7689b96 JM |
135 | friend constexpr bool |
136 | operator>=(__cmp_cat::__unspec, partial_ordering __v) noexcept | |
0d57370c | 137 | { return 0 >= __v._M_value; } |
b7689b96 | 138 | |
8dec72ae | 139 | [[nodiscard]] |
b7689b96 JM |
140 | friend constexpr partial_ordering |
141 | operator<=>(partial_ordering __v, __cmp_cat::__unspec) noexcept | |
142 | { return __v; } | |
143 | ||
8dec72ae | 144 | [[nodiscard]] |
b7689b96 JM |
145 | friend constexpr partial_ordering |
146 | operator<=>(__cmp_cat::__unspec, partial_ordering __v) noexcept | |
147 | { | |
0d57370c JW |
148 | if (__v._M_value & 1) |
149 | return partial_ordering(__cmp_cat::_Ord(-__v._M_value)); | |
b7689b96 JM |
150 | else |
151 | return __v; | |
152 | } | |
153 | }; | |
154 | ||
155 | // valid values' definitions | |
156 | inline constexpr partial_ordering | |
482eeff5 | 157 | partial_ordering::less(__cmp_cat::_Ord::less); |
b7689b96 JM |
158 | |
159 | inline constexpr partial_ordering | |
482eeff5 | 160 | partial_ordering::equivalent(__cmp_cat::_Ord::equivalent); |
b7689b96 JM |
161 | |
162 | inline constexpr partial_ordering | |
482eeff5 | 163 | partial_ordering::greater(__cmp_cat::_Ord::greater); |
b7689b96 JM |
164 | |
165 | inline constexpr partial_ordering | |
166 | partial_ordering::unordered(__cmp_cat::_Ncmp::_Unordered); | |
167 | ||
168 | class weak_ordering | |
169 | { | |
0d57370c | 170 | __cmp_cat::type _M_value; |
b7689b96 | 171 | |
b7689b96 | 172 | constexpr explicit |
0d57370c | 173 | weak_ordering(__cmp_cat::_Ord __v) noexcept : _M_value(__cmp_cat::type(__v)) |
b7689b96 JM |
174 | { } |
175 | ||
0d57370c JW |
176 | friend class strong_ordering; |
177 | ||
b7689b96 JM |
178 | public: |
179 | // valid values | |
180 | static const weak_ordering less; | |
181 | static const weak_ordering equivalent; | |
182 | static const weak_ordering greater; | |
183 | ||
8dec72ae | 184 | [[nodiscard]] |
b7689b96 | 185 | constexpr operator partial_ordering() const noexcept |
0d57370c | 186 | { return partial_ordering(__cmp_cat::_Ord(_M_value)); } |
b7689b96 JM |
187 | |
188 | // comparisons | |
8dec72ae | 189 | [[nodiscard]] |
b7689b96 JM |
190 | friend constexpr bool |
191 | operator==(weak_ordering __v, __cmp_cat::__unspec) noexcept | |
192 | { return __v._M_value == 0; } | |
193 | ||
8dec72ae | 194 | [[nodiscard]] |
b7689b96 JM |
195 | friend constexpr bool |
196 | operator==(weak_ordering, weak_ordering) noexcept = default; | |
197 | ||
8dec72ae | 198 | [[nodiscard]] |
b7689b96 JM |
199 | friend constexpr bool |
200 | operator< (weak_ordering __v, __cmp_cat::__unspec) noexcept | |
201 | { return __v._M_value < 0; } | |
202 | ||
8dec72ae | 203 | [[nodiscard]] |
b7689b96 JM |
204 | friend constexpr bool |
205 | operator> (weak_ordering __v, __cmp_cat::__unspec) noexcept | |
206 | { return __v._M_value > 0; } | |
207 | ||
8dec72ae | 208 | [[nodiscard]] |
b7689b96 JM |
209 | friend constexpr bool |
210 | operator<=(weak_ordering __v, __cmp_cat::__unspec) noexcept | |
211 | { return __v._M_value <= 0; } | |
212 | ||
8dec72ae | 213 | [[nodiscard]] |
b7689b96 JM |
214 | friend constexpr bool |
215 | operator>=(weak_ordering __v, __cmp_cat::__unspec) noexcept | |
216 | { return __v._M_value >= 0; } | |
217 | ||
8dec72ae | 218 | [[nodiscard]] |
b7689b96 JM |
219 | friend constexpr bool |
220 | operator< (__cmp_cat::__unspec, weak_ordering __v) noexcept | |
221 | { return 0 < __v._M_value; } | |
222 | ||
8dec72ae | 223 | [[nodiscard]] |
b7689b96 JM |
224 | friend constexpr bool |
225 | operator> (__cmp_cat::__unspec, weak_ordering __v) noexcept | |
226 | { return 0 > __v._M_value; } | |
227 | ||
8dec72ae | 228 | [[nodiscard]] |
b7689b96 JM |
229 | friend constexpr bool |
230 | operator<=(__cmp_cat::__unspec, weak_ordering __v) noexcept | |
231 | { return 0 <= __v._M_value; } | |
232 | ||
8dec72ae | 233 | [[nodiscard]] |
b7689b96 JM |
234 | friend constexpr bool |
235 | operator>=(__cmp_cat::__unspec, weak_ordering __v) noexcept | |
236 | { return 0 >= __v._M_value; } | |
237 | ||
8dec72ae | 238 | [[nodiscard]] |
b7689b96 JM |
239 | friend constexpr weak_ordering |
240 | operator<=>(weak_ordering __v, __cmp_cat::__unspec) noexcept | |
241 | { return __v; } | |
242 | ||
8dec72ae | 243 | [[nodiscard]] |
b7689b96 JM |
244 | friend constexpr weak_ordering |
245 | operator<=>(__cmp_cat::__unspec, weak_ordering __v) noexcept | |
0d57370c | 246 | { return weak_ordering(__cmp_cat::_Ord(-__v._M_value)); } |
b7689b96 JM |
247 | }; |
248 | ||
249 | // valid values' definitions | |
250 | inline constexpr weak_ordering | |
482eeff5 | 251 | weak_ordering::less(__cmp_cat::_Ord::less); |
b7689b96 JM |
252 | |
253 | inline constexpr weak_ordering | |
482eeff5 | 254 | weak_ordering::equivalent(__cmp_cat::_Ord::equivalent); |
b7689b96 JM |
255 | |
256 | inline constexpr weak_ordering | |
482eeff5 | 257 | weak_ordering::greater(__cmp_cat::_Ord::greater); |
b7689b96 JM |
258 | |
259 | class strong_ordering | |
260 | { | |
0d57370c | 261 | __cmp_cat::type _M_value; |
b7689b96 | 262 | |
b7689b96 JM |
263 | constexpr explicit |
264 | strong_ordering(__cmp_cat::_Ord __v) noexcept | |
0d57370c | 265 | : _M_value(__cmp_cat::type(__v)) |
b7689b96 JM |
266 | { } |
267 | ||
268 | public: | |
269 | // valid values | |
270 | static const strong_ordering less; | |
271 | static const strong_ordering equal; | |
272 | static const strong_ordering equivalent; | |
273 | static const strong_ordering greater; | |
274 | ||
8dec72ae | 275 | [[nodiscard]] |
b7689b96 | 276 | constexpr operator partial_ordering() const noexcept |
0d57370c | 277 | { return partial_ordering(__cmp_cat::_Ord(_M_value)); } |
b7689b96 | 278 | |
8dec72ae | 279 | [[nodiscard]] |
b7689b96 | 280 | constexpr operator weak_ordering() const noexcept |
0d57370c | 281 | { return weak_ordering(__cmp_cat::_Ord(_M_value)); } |
b7689b96 JM |
282 | |
283 | // comparisons | |
8dec72ae | 284 | [[nodiscard]] |
b7689b96 JM |
285 | friend constexpr bool |
286 | operator==(strong_ordering __v, __cmp_cat::__unspec) noexcept | |
287 | { return __v._M_value == 0; } | |
288 | ||
8dec72ae | 289 | [[nodiscard]] |
b7689b96 JM |
290 | friend constexpr bool |
291 | operator==(strong_ordering, strong_ordering) noexcept = default; | |
292 | ||
8dec72ae | 293 | [[nodiscard]] |
b7689b96 JM |
294 | friend constexpr bool |
295 | operator< (strong_ordering __v, __cmp_cat::__unspec) noexcept | |
296 | { return __v._M_value < 0; } | |
297 | ||
8dec72ae | 298 | [[nodiscard]] |
b7689b96 JM |
299 | friend constexpr bool |
300 | operator> (strong_ordering __v, __cmp_cat::__unspec) noexcept | |
301 | { return __v._M_value > 0; } | |
302 | ||
8dec72ae | 303 | [[nodiscard]] |
b7689b96 JM |
304 | friend constexpr bool |
305 | operator<=(strong_ordering __v, __cmp_cat::__unspec) noexcept | |
306 | { return __v._M_value <= 0; } | |
307 | ||
8dec72ae | 308 | [[nodiscard]] |
b7689b96 JM |
309 | friend constexpr bool |
310 | operator>=(strong_ordering __v, __cmp_cat::__unspec) noexcept | |
311 | { return __v._M_value >= 0; } | |
312 | ||
8dec72ae | 313 | [[nodiscard]] |
b7689b96 JM |
314 | friend constexpr bool |
315 | operator< (__cmp_cat::__unspec, strong_ordering __v) noexcept | |
316 | { return 0 < __v._M_value; } | |
317 | ||
8dec72ae | 318 | [[nodiscard]] |
b7689b96 JM |
319 | friend constexpr bool |
320 | operator> (__cmp_cat::__unspec, strong_ordering __v) noexcept | |
321 | { return 0 > __v._M_value; } | |
322 | ||
8dec72ae | 323 | [[nodiscard]] |
b7689b96 JM |
324 | friend constexpr bool |
325 | operator<=(__cmp_cat::__unspec, strong_ordering __v) noexcept | |
326 | { return 0 <= __v._M_value; } | |
327 | ||
8dec72ae | 328 | [[nodiscard]] |
b7689b96 JM |
329 | friend constexpr bool |
330 | operator>=(__cmp_cat::__unspec, strong_ordering __v) noexcept | |
331 | { return 0 >= __v._M_value; } | |
332 | ||
8dec72ae | 333 | [[nodiscard]] |
b7689b96 JM |
334 | friend constexpr strong_ordering |
335 | operator<=>(strong_ordering __v, __cmp_cat::__unspec) noexcept | |
336 | { return __v; } | |
337 | ||
8dec72ae | 338 | [[nodiscard]] |
b7689b96 JM |
339 | friend constexpr strong_ordering |
340 | operator<=>(__cmp_cat::__unspec, strong_ordering __v) noexcept | |
0d57370c | 341 | { return strong_ordering(__cmp_cat::_Ord(-__v._M_value)); } |
b7689b96 JM |
342 | }; |
343 | ||
344 | // valid values' definitions | |
345 | inline constexpr strong_ordering | |
482eeff5 | 346 | strong_ordering::less(__cmp_cat::_Ord::less); |
b7689b96 JM |
347 | |
348 | inline constexpr strong_ordering | |
482eeff5 | 349 | strong_ordering::equal(__cmp_cat::_Ord::equivalent); |
b7689b96 JM |
350 | |
351 | inline constexpr strong_ordering | |
482eeff5 | 352 | strong_ordering::equivalent(__cmp_cat::_Ord::equivalent); |
b7689b96 JM |
353 | |
354 | inline constexpr strong_ordering | |
482eeff5 | 355 | strong_ordering::greater(__cmp_cat::_Ord::greater); |
b7689b96 JM |
356 | |
357 | ||
358 | // named comparison functions | |
8dec72ae | 359 | [[nodiscard]] |
b7689b96 | 360 | constexpr bool |
4629ea55 | 361 | is_eq(partial_ordering __cmp) noexcept |
b7689b96 JM |
362 | { return __cmp == 0; } |
363 | ||
8dec72ae | 364 | [[nodiscard]] |
b7689b96 | 365 | constexpr bool |
4629ea55 | 366 | is_neq(partial_ordering __cmp) noexcept |
b7689b96 JM |
367 | { return __cmp != 0; } |
368 | ||
8dec72ae | 369 | [[nodiscard]] |
b7689b96 JM |
370 | constexpr bool |
371 | is_lt (partial_ordering __cmp) noexcept | |
372 | { return __cmp < 0; } | |
373 | ||
8dec72ae | 374 | [[nodiscard]] |
b7689b96 JM |
375 | constexpr bool |
376 | is_lteq(partial_ordering __cmp) noexcept | |
377 | { return __cmp <= 0; } | |
378 | ||
8dec72ae | 379 | [[nodiscard]] |
b7689b96 JM |
380 | constexpr bool |
381 | is_gt (partial_ordering __cmp) noexcept | |
382 | { return __cmp > 0; } | |
383 | ||
8dec72ae | 384 | [[nodiscard]] |
b7689b96 JM |
385 | constexpr bool |
386 | is_gteq(partial_ordering __cmp) noexcept | |
387 | { return __cmp >= 0; } | |
388 | ||
29669521 JW |
389 | namespace __detail |
390 | { | |
391 | template<typename _Tp> | |
392 | inline constexpr unsigned __cmp_cat_id = 1; | |
393 | template<> | |
d1505d01 | 394 | inline constexpr unsigned __cmp_cat_id<partial_ordering> = 2; |
29669521 JW |
395 | template<> |
396 | inline constexpr unsigned __cmp_cat_id<weak_ordering> = 4; | |
397 | template<> | |
d1505d01 | 398 | inline constexpr unsigned __cmp_cat_id<strong_ordering> = 8; |
29669521 JW |
399 | |
400 | template<typename... _Ts> | |
d1505d01 JW |
401 | constexpr auto __common_cmp_cat() |
402 | { | |
403 | constexpr unsigned __cats = (__cmp_cat_id<_Ts> | ...); | |
404 | // If any Ti is not a comparison category type, U is void. | |
405 | if constexpr (__cats & 1) | |
406 | return; | |
407 | // Otherwise, if at least one Ti is std::partial_ordering, | |
408 | // U is std::partial_ordering. | |
409 | else if constexpr (bool(__cats & __cmp_cat_id<partial_ordering>)) | |
410 | return partial_ordering::equivalent; | |
411 | // Otherwise, if at least one Ti is std::weak_ordering, | |
412 | // U is std::weak_ordering. | |
413 | else if constexpr (bool(__cats & __cmp_cat_id<weak_ordering>)) | |
414 | return weak_ordering::equivalent; | |
415 | // Otherwise, U is std::strong_ordering. | |
416 | else | |
417 | return strong_ordering::equivalent; | |
418 | } | |
29669521 JW |
419 | } // namespace __detail |
420 | ||
b7689b96 JM |
421 | // [cmp.common], common comparison category type |
422 | template<typename... _Ts> | |
0c92c862 JW |
423 | struct common_comparison_category |
424 | { | |
d1505d01 | 425 | using type = decltype(__detail::__common_cmp_cat<_Ts...>()); |
b7689b96 JM |
426 | }; |
427 | ||
29669521 JW |
428 | // Partial specializations for one and zero argument cases. |
429 | ||
430 | template<typename _Tp> | |
431 | struct common_comparison_category<_Tp> | |
432 | { using type = void; }; | |
433 | ||
434 | template<> | |
435 | struct common_comparison_category<partial_ordering> | |
436 | { using type = partial_ordering; }; | |
437 | ||
438 | template<> | |
439 | struct common_comparison_category<weak_ordering> | |
440 | { using type = weak_ordering; }; | |
441 | ||
442 | template<> | |
443 | struct common_comparison_category<strong_ordering> | |
444 | { using type = strong_ordering; }; | |
445 | ||
446 | template<> | |
447 | struct common_comparison_category<> | |
448 | { using type = strong_ordering; }; | |
449 | ||
b7689b96 JM |
450 | template<typename... _Ts> |
451 | using common_comparison_category_t | |
452 | = typename common_comparison_category<_Ts...>::type; | |
453 | ||
083b7f28 AA |
454 | #if __cpp_lib_three_way_comparison >= 201907L |
455 | // C++ >= 20 && impl_3way_comparison >= 201907 && lib_concepts | |
b7689b96 JM |
456 | namespace __detail |
457 | { | |
458 | template<typename _Tp, typename _Cat> | |
459 | concept __compares_as | |
460 | = same_as<common_comparison_category_t<_Tp, _Cat>, _Cat>; | |
b7689b96 JM |
461 | } // namespace __detail |
462 | ||
463 | // [cmp.concept], concept three_way_comparable | |
464 | template<typename _Tp, typename _Cat = partial_ordering> | |
465 | concept three_way_comparable | |
466 | = __detail::__weakly_eq_cmp_with<_Tp, _Tp> | |
256f67aa | 467 | && __detail::__partially_ordered_with<_Tp, _Tp> |
b7689b96 | 468 | && requires(const remove_reference_t<_Tp>& __a, |
3fd1c229 JW |
469 | const remove_reference_t<_Tp>& __b) |
470 | { | |
b7689b96 JM |
471 | { __a <=> __b } -> __detail::__compares_as<_Cat>; |
472 | }; | |
473 | ||
474 | template<typename _Tp, typename _Up, typename _Cat = partial_ordering> | |
475 | concept three_way_comparable_with | |
256f67aa | 476 | = three_way_comparable<_Tp, _Cat> |
b7689b96 JM |
477 | && three_way_comparable<_Up, _Cat> |
478 | && common_reference_with<const remove_reference_t<_Tp>&, | |
479 | const remove_reference_t<_Up>&> | |
480 | && three_way_comparable< | |
481 | common_reference_t<const remove_reference_t<_Tp>&, | |
482 | const remove_reference_t<_Up>&>, _Cat> | |
256f67aa JW |
483 | && __detail::__weakly_eq_cmp_with<_Tp, _Up> |
484 | && __detail::__partially_ordered_with<_Tp, _Up> | |
b7689b96 | 485 | && requires(const remove_reference_t<_Tp>& __t, |
3fd1c229 JW |
486 | const remove_reference_t<_Up>& __u) |
487 | { | |
b7689b96 JM |
488 | { __t <=> __u } -> __detail::__compares_as<_Cat>; |
489 | { __u <=> __t } -> __detail::__compares_as<_Cat>; | |
490 | }; | |
b7689b96 | 491 | |
7f397e45 JW |
492 | namespace __detail |
493 | { | |
494 | template<typename _Tp, typename _Up> | |
495 | using __cmp3way_res_t | |
496 | = decltype(std::declval<_Tp>() <=> std::declval<_Up>()); | |
497 | ||
498 | // Implementation of std::compare_three_way_result. | |
499 | // It is undefined for a program to add specializations of | |
500 | // std::compare_three_way_result, so the std::compare_three_way_result_t | |
501 | // alias ignores std::compare_three_way_result and uses | |
502 | // __detail::__cmp3way_res_impl directly instead. | |
503 | template<typename _Tp, typename _Up> | |
504 | struct __cmp3way_res_impl | |
505 | { }; | |
b7689b96 | 506 | |
7f397e45 JW |
507 | template<typename _Tp, typename _Up> |
508 | requires requires { typename __cmp3way_res_t<__cref<_Tp>, __cref<_Up>>; } | |
509 | struct __cmp3way_res_impl<_Tp, _Up> | |
510 | { | |
511 | using type = __cmp3way_res_t<__cref<_Tp>, __cref<_Up>>; | |
512 | }; | |
513 | } // namespace __detail | |
b7689b96 JM |
514 | |
515 | /// [cmp.result], result of three-way comparison | |
516 | template<typename _Tp, typename _Up = _Tp> | |
517 | struct compare_three_way_result | |
7f397e45 | 518 | : __detail::__cmp3way_res_impl<_Tp, _Up> |
b7689b96 JM |
519 | { }; |
520 | ||
7f397e45 | 521 | /// [cmp.result], result of three-way comparison |
b7689b96 JM |
522 | template<typename _Tp, typename _Up = _Tp> |
523 | using compare_three_way_result_t | |
7f397e45 | 524 | = typename __detail::__cmp3way_res_impl<_Tp, _Up>::type; |
b7689b96 | 525 | |
0c92c862 JW |
526 | namespace __detail |
527 | { | |
528 | // BUILTIN-PTR-THREE-WAY(T, U) | |
dddd0111 JW |
529 | // This determines whether t <=> u results in a call to a built-in |
530 | // operator<=> comparing pointers. It doesn't work for function pointers | |
531 | // (PR 93628). | |
0c92c862 JW |
532 | template<typename _Tp, typename _Up> |
533 | concept __3way_builtin_ptr_cmp | |
e1e9e8d7 JW |
534 | = requires(_Tp&& __t, _Up&& __u) |
535 | { static_cast<_Tp&&>(__t) <=> static_cast<_Up&&>(__u); } | |
83b02010 | 536 | && convertible_to<_Tp, const volatile void*> |
0c92c862 JW |
537 | && convertible_to<_Up, const volatile void*> |
538 | && ! requires(_Tp&& __t, _Up&& __u) | |
e1e9e8d7 | 539 | { operator<=>(static_cast<_Tp&&>(__t), static_cast<_Up&&>(__u)); } |
0c92c862 | 540 | && ! requires(_Tp&& __t, _Up&& __u) |
e1e9e8d7 | 541 | { static_cast<_Tp&&>(__t).operator<=>(static_cast<_Up&&>(__u)); }; |
0c92c862 JW |
542 | } // namespace __detail |
543 | ||
dddd0111 JW |
544 | // _GLIBCXX_RESOLVE_LIB_DEFECTS |
545 | // 3530 BUILTIN-PTR-MEOW should not opt the type out of syntactic checks | |
546 | ||
b7689b96 JM |
547 | // [cmp.object], typename compare_three_way |
548 | struct compare_three_way | |
549 | { | |
b7689b96 | 550 | template<typename _Tp, typename _Up> |
f214ffb3 | 551 | requires three_way_comparable_with<_Tp, _Up> |
29669521 | 552 | constexpr auto |
c2a984a3 | 553 | operator() [[nodiscard]] (_Tp&& __t, _Up&& __u) const |
3fd1c229 | 554 | noexcept(noexcept(std::declval<_Tp>() <=> std::declval<_Up>())) |
29669521 JW |
555 | { |
556 | if constexpr (__detail::__3way_builtin_ptr_cmp<_Tp, _Up>) | |
557 | { | |
558 | auto __pt = static_cast<const volatile void*>(__t); | |
559 | auto __pu = static_cast<const volatile void*>(__u); | |
74d14778 | 560 | if (std::__is_constant_evaluated()) |
29669521 JW |
561 | return __pt <=> __pu; |
562 | auto __it = reinterpret_cast<__UINTPTR_TYPE__>(__pt); | |
563 | auto __iu = reinterpret_cast<__UINTPTR_TYPE__>(__pu); | |
564 | return __it <=> __iu; | |
565 | } | |
566 | else | |
567 | return static_cast<_Tp&&>(__t) <=> static_cast<_Up&&>(__u); | |
568 | } | |
b7689b96 JM |
569 | |
570 | using is_transparent = void; | |
571 | }; | |
572 | ||
faea9d92 JW |
573 | /// @cond undocumented |
574 | // Namespace for helpers for the <compare> customization points. | |
575 | namespace __compare | |
0ff15d21 JW |
576 | { |
577 | template<floating_point _Tp> | |
578 | constexpr weak_ordering | |
579 | __fp_weak_ordering(_Tp __e, _Tp __f) | |
580 | { | |
581 | // Returns an integer with the same sign as the argument, and magnitude | |
582 | // indicating the classification: zero=1 subnorm=2 norm=3 inf=4 nan=5 | |
583 | auto __cat = [](_Tp __fp) -> int { | |
584 | const int __sign = __builtin_signbit(__fp) ? -1 : 1; | |
585 | if (__builtin_isnormal(__fp)) | |
586 | return (__fp == 0 ? 1 : 3) * __sign; | |
587 | if (__builtin_isnan(__fp)) | |
588 | return 5 * __sign; | |
589 | if (int __inf = __builtin_isinf_sign(__fp)) | |
590 | return 4 * __inf; | |
591 | return 2 * __sign; | |
592 | }; | |
593 | ||
594 | auto __po = __e <=> __f; | |
595 | if (is_lt(__po)) | |
596 | return weak_ordering::less; | |
597 | else if (is_gt(__po)) | |
598 | return weak_ordering::greater; | |
599 | else if (__po == partial_ordering::equivalent) | |
600 | return weak_ordering::equivalent; | |
601 | else // unordered, at least one argument is NaN | |
602 | { | |
603 | // return -1 for negative nan, +1 for positive nan, 0 otherwise. | |
604 | auto __isnan_sign = [](_Tp __fp) -> int { | |
605 | return __builtin_isnan(__fp) | |
606 | ? __builtin_signbit(__fp) ? -1 : 1 | |
607 | : 0; | |
608 | }; | |
609 | auto __ord = __isnan_sign(__e) <=> __isnan_sign(__f); | |
610 | if (is_eq(__ord)) | |
611 | return weak_ordering::equivalent; | |
612 | else if (is_lt(__ord)) | |
613 | return weak_ordering::less; | |
614 | else | |
615 | return weak_ordering::greater; | |
616 | } | |
617 | } | |
618 | ||
6854e3ac JW |
619 | void strong_order() = delete; |
620 | ||
0ff15d21 JW |
621 | template<typename _Tp, typename _Up> |
622 | concept __adl_strong = requires(_Tp&& __t, _Up&& __u) | |
623 | { | |
624 | strong_ordering(strong_order(static_cast<_Tp&&>(__t), | |
625 | static_cast<_Up&&>(__u))); | |
626 | }; | |
627 | ||
6854e3ac JW |
628 | void weak_order() = delete; |
629 | ||
0ff15d21 JW |
630 | template<typename _Tp, typename _Up> |
631 | concept __adl_weak = requires(_Tp&& __t, _Up&& __u) | |
632 | { | |
633 | weak_ordering(weak_order(static_cast<_Tp&&>(__t), | |
634 | static_cast<_Up&&>(__u))); | |
635 | }; | |
636 | ||
6854e3ac JW |
637 | void partial_order() = delete; |
638 | ||
0ff15d21 JW |
639 | template<typename _Tp, typename _Up> |
640 | concept __adl_partial = requires(_Tp&& __t, _Up&& __u) | |
641 | { | |
642 | partial_ordering(partial_order(static_cast<_Tp&&>(__t), | |
643 | static_cast<_Up&&>(__u))); | |
644 | }; | |
645 | ||
646 | template<typename _Ord, typename _Tp, typename _Up> | |
3fd1c229 | 647 | concept __cmp3way = requires(_Tp&& __t, _Up&& __u, compare_three_way __c) |
0ff15d21 | 648 | { |
3fd1c229 | 649 | _Ord(__c(static_cast<_Tp&&>(__t), static_cast<_Up&&>(__u))); |
0ff15d21 JW |
650 | }; |
651 | ||
652 | template<typename _Tp, typename _Up> | |
653 | concept __strongly_ordered | |
654 | = __adl_strong<_Tp, _Up> | |
9805965e | 655 | || floating_point<remove_reference_t<_Tp>> |
3fd1c229 | 656 | || __cmp3way<strong_ordering, _Tp, _Up>; |
0ff15d21 | 657 | |
e2c79b96 JW |
658 | template<typename _Tp, typename _Up> |
659 | concept __decayed_same_as = same_as<decay_t<_Tp>, decay_t<_Up>>; | |
660 | ||
0ff15d21 JW |
661 | class _Strong_order |
662 | { | |
663 | template<typename _Tp, typename _Up> | |
664 | static constexpr bool | |
665 | _S_noexcept() | |
666 | { | |
667 | if constexpr (floating_point<decay_t<_Tp>>) | |
668 | return true; | |
669 | else if constexpr (__adl_strong<_Tp, _Up>) | |
670 | return noexcept(strong_ordering(strong_order(std::declval<_Tp>(), | |
671 | std::declval<_Up>()))); | |
3fd1c229 JW |
672 | else if constexpr (__cmp3way<strong_ordering, _Tp, _Up>) |
673 | return noexcept(compare_three_way()(std::declval<_Tp>(), | |
674 | std::declval<_Up>())); | |
0ff15d21 JW |
675 | } |
676 | ||
677 | friend class _Weak_order; | |
678 | friend class _Strong_fallback; | |
679 | ||
9805965e JW |
680 | // Names for the supported floating-point representations. |
681 | enum class _Fp_fmt | |
682 | { | |
683 | _Binary16, _Binary32, _Binary64, _Binary128, // IEEE | |
684 | _X86_80bit, // x86 80-bit extended precision | |
685 | _M68k_80bit, // m68k 80-bit extended precision | |
686 | _Dbldbl, // IBM 128-bit double-double | |
0c86a667 | 687 | _Bfloat16, // std::bfloat16_t |
9805965e JW |
688 | }; |
689 | ||
8bbeffc1 JW |
690 | #ifndef __cpp_using_enum |
691 | // XXX Remove these once 'using enum' support is ubiquitous. | |
692 | static constexpr _Fp_fmt _Binary16 = _Fp_fmt::_Binary16; | |
693 | static constexpr _Fp_fmt _Binary32 = _Fp_fmt::_Binary32; | |
694 | static constexpr _Fp_fmt _Binary64 = _Fp_fmt::_Binary64; | |
695 | static constexpr _Fp_fmt _Binary128 = _Fp_fmt::_Binary128; | |
696 | static constexpr _Fp_fmt _X86_80bit = _Fp_fmt::_X86_80bit; | |
697 | static constexpr _Fp_fmt _M68k_80bit = _Fp_fmt::_M68k_80bit; | |
698 | static constexpr _Fp_fmt _Dbldbl = _Fp_fmt::_Dbldbl; | |
0c86a667 | 699 | static constexpr _Fp_fmt _Bfloat16 = _Fp_fmt::_Bfloat16; |
8bbeffc1 JW |
700 | #endif |
701 | ||
9805965e JW |
702 | // Identify the format used by a floating-point type. |
703 | template<typename _Tp> | |
704 | static consteval _Fp_fmt | |
705 | _S_fp_fmt() noexcept | |
706 | { | |
8bbeffc1 | 707 | #ifdef __cpp_using_enum |
9805965e | 708 | using enum _Fp_fmt; |
8bbeffc1 | 709 | #endif |
9805965e JW |
710 | |
711 | // Identify these formats first, then assume anything else is IEEE. | |
712 | // N.B. ARM __fp16 alternative format can be handled as binary16. | |
713 | ||
714 | #ifdef __LONG_DOUBLE_IBM128__ | |
715 | if constexpr (__is_same(_Tp, long double)) | |
716 | return _Dbldbl; | |
717 | #elif defined __LONG_DOUBLE_IEEE128__ && defined __SIZEOF_IBM128__ | |
718 | if constexpr (__is_same(_Tp, __ibm128)) | |
719 | return _Dbldbl; | |
720 | #endif | |
721 | ||
722 | #if __LDBL_MANT_DIG__ == 64 | |
723 | if constexpr (__is_same(_Tp, long double)) | |
724 | return __LDBL_MIN_EXP__ == -16381 ? _X86_80bit : _M68k_80bit; | |
725 | #endif | |
726 | #ifdef __SIZEOF_FLOAT80__ | |
727 | if constexpr (__is_same(_Tp, __float80)) | |
728 | return _X86_80bit; | |
729 | #endif | |
0c86a667 JJ |
730 | #ifdef __STDCPP_BFLOAT16_T__ |
731 | if constexpr (__is_same(_Tp, decltype(0.0bf16))) | |
732 | return _Bfloat16; | |
733 | #endif | |
9805965e JW |
734 | |
735 | constexpr int __width = sizeof(_Tp) * __CHAR_BIT__; | |
736 | ||
737 | if constexpr (__width == 16) // IEEE binary16 (or ARM fp16). | |
738 | return _Binary16; | |
739 | else if constexpr (__width == 32) // IEEE binary32 | |
740 | return _Binary32; | |
741 | else if constexpr (__width == 64) // IEEE binary64 | |
742 | return _Binary64; | |
743 | else if constexpr (__width == 128) // IEEE binary128 | |
744 | return _Binary128; | |
745 | } | |
746 | ||
747 | // So we don't need to include <stdint.h> and pollute the namespace. | |
748 | using int64_t = __INT64_TYPE__; | |
749 | using int32_t = __INT32_TYPE__; | |
750 | using int16_t = __INT16_TYPE__; | |
751 | using uint64_t = __UINT64_TYPE__; | |
752 | using uint16_t = __UINT16_TYPE__; | |
753 | ||
754 | // Used to unpack floating-point types that do not fit into an integer. | |
755 | template<typename _Tp> | |
756 | struct _Int | |
757 | { | |
758 | #if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ | |
759 | uint64_t _M_lo; | |
760 | _Tp _M_hi; | |
761 | #else | |
762 | _Tp _M_hi; | |
763 | uint64_t _M_lo; | |
764 | #endif | |
765 | ||
766 | constexpr explicit | |
767 | _Int(_Tp __hi, uint64_t __lo) noexcept : _M_hi(__hi) | |
768 | { _M_lo = __lo; } | |
769 | ||
770 | constexpr explicit | |
771 | _Int(uint64_t __lo) noexcept : _M_hi(0) | |
772 | { _M_lo = __lo; } | |
773 | ||
774 | constexpr bool operator==(const _Int&) const = default; | |
775 | ||
776 | #if defined __hppa__ || (defined __mips__ && !defined __mips_nan2008) | |
777 | consteval _Int | |
778 | operator<<(int __n) const noexcept | |
779 | { | |
780 | // XXX this assumes n >= 64, which is true for the use below. | |
781 | return _Int(static_cast<_Tp>(_M_lo << (__n - 64)), 0); | |
782 | } | |
783 | #endif | |
784 | ||
785 | constexpr _Int& | |
786 | operator^=(const _Int& __rhs) noexcept | |
787 | { | |
788 | _M_hi ^= __rhs._M_hi; | |
789 | _M_lo ^= __rhs._M_lo; | |
790 | return *this; | |
791 | } | |
792 | ||
793 | constexpr strong_ordering | |
794 | operator<=>(const _Int& __rhs) const noexcept | |
795 | { | |
796 | strong_ordering __cmp = _M_hi <=> __rhs._M_hi; | |
797 | if (__cmp != strong_ordering::equal) | |
798 | return __cmp; | |
799 | return _M_lo <=> __rhs._M_lo; | |
800 | } | |
801 | }; | |
802 | ||
803 | template<typename _Tp> | |
804 | static constexpr _Tp | |
805 | _S_compl(_Tp __t) noexcept | |
806 | { | |
807 | constexpr int __width = sizeof(_Tp) * __CHAR_BIT__; | |
808 | // Sign extend to get all ones or all zeros. | |
809 | make_unsigned_t<_Tp> __sign = __t >> (__width - 1); | |
810 | // If the sign bit was set, this flips all bits below it. | |
811 | // This converts ones' complement to two's complement. | |
812 | return __t ^ (__sign >> 1); | |
813 | } | |
814 | ||
815 | // As above but works on both parts of _Int<T>. | |
816 | template<typename _Tp> | |
817 | static constexpr _Int<_Tp> | |
818 | _S_compl(_Int<_Tp> __t) noexcept | |
819 | { | |
820 | constexpr int __width = sizeof(_Tp) * __CHAR_BIT__; | |
821 | make_unsigned_t<_Tp> __sign = __t._M_hi >> (__width - 1); | |
822 | __t._M_hi ^= (__sign >> 1 ); | |
823 | uint64_t __sign64 = (_Tp)__sign; | |
824 | __t._M_lo ^= __sign64; | |
825 | return __t; | |
826 | } | |
827 | ||
828 | // Bit-cast a floating-point value to an unsigned integer. | |
829 | template<typename _Tp> | |
830 | constexpr static auto | |
831 | _S_fp_bits(_Tp __val) noexcept | |
832 | { | |
833 | if constexpr (sizeof(_Tp) == sizeof(int64_t)) | |
834 | return __builtin_bit_cast(int64_t, __val); | |
835 | else if constexpr (sizeof(_Tp) == sizeof(int32_t)) | |
836 | return __builtin_bit_cast(int32_t, __val); | |
837 | else if constexpr (sizeof(_Tp) == sizeof(int16_t)) | |
838 | return __builtin_bit_cast(int16_t, __val); | |
839 | else | |
840 | { | |
8bbeffc1 | 841 | #ifdef __cpp_using_enum |
9805965e | 842 | using enum _Fp_fmt; |
8bbeffc1 | 843 | #endif |
9805965e | 844 | constexpr auto __fmt = _S_fp_fmt<_Tp>(); |
4bf758b2 | 845 | if constexpr (__fmt == _X86_80bit) |
9805965e JW |
846 | { |
847 | if constexpr (sizeof(_Tp) == 3 * sizeof(int32_t)) | |
848 | { | |
849 | auto __ival = __builtin_bit_cast(_Int<int32_t>, __val); | |
850 | return _Int<int16_t>(__ival._M_hi, __ival._M_lo); | |
851 | } | |
852 | else | |
853 | { | |
854 | auto __ival = __builtin_bit_cast(_Int<int64_t>, __val); | |
855 | return _Int<int16_t>(__ival._M_hi, __ival._M_lo); | |
856 | } | |
857 | } | |
4bf758b2 AS |
858 | else if constexpr (__fmt == _M68k_80bit) |
859 | { | |
860 | auto __ival = __builtin_bit_cast(_Int<int32_t>, __val); | |
861 | return _Int<int16_t>(__ival._M_hi >> 16, __ival._M_lo); | |
862 | } | |
9805965e JW |
863 | else if constexpr (sizeof(_Tp) == 2 * sizeof(int64_t)) |
864 | { | |
865 | #if __SIZEOF_INT128__ | |
866 | return __builtin_bit_cast(__int128, __val); | |
867 | #else | |
868 | return __builtin_bit_cast(_Int<int64_t>, __val); | |
869 | #endif | |
870 | } | |
871 | else | |
872 | static_assert(sizeof(_Tp) == sizeof(int64_t), | |
873 | "unsupported floating-point type"); | |
874 | } | |
875 | } | |
876 | ||
877 | template<typename _Tp> | |
878 | static constexpr strong_ordering | |
879 | _S_fp_cmp(_Tp __x, _Tp __y) noexcept | |
880 | { | |
cfaa2fac | 881 | #ifdef __vax__ |
73f3b8a5 JW |
882 | if (__builtin_isnan(__x) || __builtin_isnan(__y)) |
883 | { | |
884 | int __ix = (bool) __builtin_isnan(__x); | |
885 | int __iy = (bool) __builtin_isnan(__y); | |
886 | __ix *= __builtin_signbit(__x) ? -1 : 1; | |
887 | __iy *= __builtin_signbit(__y) ? -1 : 1; | |
888 | return __ix <=> __iy; | |
889 | } | |
890 | else | |
891 | return __builtin_bit_cast(strong_ordering, __x <=> __y); | |
cfaa2fac JW |
892 | #endif |
893 | ||
9805965e JW |
894 | auto __ix = _S_fp_bits(__x); |
895 | auto __iy = _S_fp_bits(__y); | |
896 | ||
897 | if (__ix == __iy) | |
898 | return strong_ordering::equal; // All bits are equal, we're done. | |
899 | ||
8bbeffc1 | 900 | #ifdef __cpp_using_enum |
9805965e | 901 | using enum _Fp_fmt; |
8bbeffc1 | 902 | #endif |
9805965e JW |
903 | constexpr auto __fmt = _S_fp_fmt<_Tp>(); |
904 | ||
905 | if constexpr (__fmt == _Dbldbl) // double-double | |
906 | { | |
907 | // Unpack the double-double into two parts. | |
908 | // We never inspect the low double as a double, cast to integer. | |
909 | struct _Unpacked { double _M_hi; int64_t _M_lo; }; | |
910 | auto __x2 = __builtin_bit_cast(_Unpacked, __x); | |
911 | auto __y2 = __builtin_bit_cast(_Unpacked, __y); | |
912 | ||
913 | // Compare the high doubles first and use result if unequal. | |
914 | auto __cmp = _S_fp_cmp(__x2._M_hi, __y2._M_hi); | |
915 | if (__cmp != strong_ordering::equal) | |
916 | return __cmp; | |
917 | ||
918 | // For NaN the low double is unused, so if the high doubles | |
919 | // are the same NaN, we don't need to compare the low doubles. | |
920 | if (__builtin_isnan(__x2._M_hi)) | |
921 | return strong_ordering::equal; | |
922 | // Similarly, if the low doubles are +zero or -zero (which is | |
923 | // true for all infinities and some other values), we're done. | |
924 | if (((__x2._M_lo | __y2._M_lo) & 0x7fffffffffffffffULL) == 0) | |
925 | return strong_ordering::equal; | |
926 | ||
927 | // Otherwise, compare the low parts. | |
928 | return _S_compl(__x2._M_lo) <=> _S_compl(__y2._M_lo); | |
929 | } | |
930 | else | |
931 | { | |
932 | if constexpr (__fmt == _M68k_80bit) | |
933 | { | |
934 | // For m68k the MSB of the significand is ignored for the | |
935 | // greatest exponent, so either 0 or 1 is valid there. | |
936 | // Set it before comparing, so that we never have 0 there. | |
937 | constexpr uint16_t __maxexp = 0x7fff; | |
938 | if ((__ix._M_hi & __maxexp) == __maxexp) | |
939 | __ix._M_lo |= 1ull << 63; | |
940 | if ((__iy._M_hi & __maxexp) == __maxexp) | |
941 | __iy._M_lo |= 1ull << 63; | |
942 | } | |
943 | else | |
944 | { | |
945 | #if defined __hppa__ || (defined __mips__ && !defined __mips_nan2008) | |
946 | // IEEE 754-1985 allowed the meaning of the quiet/signaling | |
947 | // bit to be reversed. Flip that to give desired ordering. | |
948 | if (__builtin_isnan(__x) && __builtin_isnan(__y)) | |
949 | { | |
289f65d6 JW |
950 | using _Int = decltype(__ix); |
951 | ||
9805965e JW |
952 | constexpr int __nantype = __fmt == _Binary32 ? 22 |
953 | : __fmt == _Binary64 ? 51 | |
954 | : __fmt == _Binary128 ? 111 | |
955 | : -1; | |
956 | constexpr _Int __bit = _Int(1) << __nantype; | |
957 | __ix ^= __bit; | |
958 | __iy ^= __bit; | |
959 | } | |
960 | #endif | |
961 | } | |
962 | return _S_compl(__ix) <=> _S_compl(__iy); | |
963 | } | |
964 | } | |
965 | ||
0ff15d21 | 966 | public: |
e2c79b96 | 967 | template<typename _Tp, __decayed_same_as<_Tp> _Up> |
0ff15d21 JW |
968 | requires __strongly_ordered<_Tp, _Up> |
969 | constexpr strong_ordering | |
c2a984a3 | 970 | operator() [[nodiscard]] (_Tp&& __e, _Up&& __f) const |
0ff15d21 JW |
971 | noexcept(_S_noexcept<_Tp, _Up>()) |
972 | { | |
0ff15d21 | 973 | if constexpr (floating_point<decay_t<_Tp>>) |
9805965e JW |
974 | return _S_fp_cmp(__e, __f); |
975 | else if constexpr (__adl_strong<_Tp, _Up>) | |
0ff15d21 JW |
976 | return strong_ordering(strong_order(static_cast<_Tp&&>(__e), |
977 | static_cast<_Up&&>(__f))); | |
3fd1c229 JW |
978 | else if constexpr (__cmp3way<strong_ordering, _Tp, _Up>) |
979 | return compare_three_way()(static_cast<_Tp&&>(__e), | |
980 | static_cast<_Up&&>(__f)); | |
0ff15d21 JW |
981 | } |
982 | }; | |
983 | ||
984 | template<typename _Tp, typename _Up> | |
985 | concept __weakly_ordered | |
986 | = floating_point<remove_reference_t<_Tp>> | |
987 | || __adl_weak<_Tp, _Up> | |
3fd1c229 | 988 | || __cmp3way<weak_ordering, _Tp, _Up> |
0ff15d21 JW |
989 | || __strongly_ordered<_Tp, _Up>; |
990 | ||
991 | class _Weak_order | |
992 | { | |
993 | template<typename _Tp, typename _Up> | |
994 | static constexpr bool | |
995 | _S_noexcept() | |
996 | { | |
997 | if constexpr (floating_point<decay_t<_Tp>>) | |
998 | return true; | |
999 | else if constexpr (__adl_weak<_Tp, _Up>) | |
1000 | return noexcept(weak_ordering(weak_order(std::declval<_Tp>(), | |
1001 | std::declval<_Up>()))); | |
3fd1c229 JW |
1002 | else if constexpr (__cmp3way<weak_ordering, _Tp, _Up>) |
1003 | return noexcept(compare_three_way()(std::declval<_Tp>(), | |
1004 | std::declval<_Up>())); | |
0ff15d21 JW |
1005 | else if constexpr (__strongly_ordered<_Tp, _Up>) |
1006 | return _Strong_order::_S_noexcept<_Tp, _Up>(); | |
1007 | } | |
1008 | ||
1009 | friend class _Partial_order; | |
1010 | friend class _Weak_fallback; | |
1011 | ||
1012 | public: | |
e2c79b96 | 1013 | template<typename _Tp, __decayed_same_as<_Tp> _Up> |
0ff15d21 JW |
1014 | requires __weakly_ordered<_Tp, _Up> |
1015 | constexpr weak_ordering | |
c2a984a3 | 1016 | operator() [[nodiscard]] (_Tp&& __e, _Up&& __f) const |
0ff15d21 JW |
1017 | noexcept(_S_noexcept<_Tp, _Up>()) |
1018 | { | |
0ff15d21 | 1019 | if constexpr (floating_point<decay_t<_Tp>>) |
faea9d92 | 1020 | return __compare::__fp_weak_ordering(__e, __f); |
0ff15d21 JW |
1021 | else if constexpr (__adl_weak<_Tp, _Up>) |
1022 | return weak_ordering(weak_order(static_cast<_Tp&&>(__e), | |
1023 | static_cast<_Up&&>(__f))); | |
3fd1c229 JW |
1024 | else if constexpr (__cmp3way<weak_ordering, _Tp, _Up>) |
1025 | return compare_three_way()(static_cast<_Tp&&>(__e), | |
1026 | static_cast<_Up&&>(__f)); | |
0ff15d21 JW |
1027 | else if constexpr (__strongly_ordered<_Tp, _Up>) |
1028 | return _Strong_order{}(static_cast<_Tp&&>(__e), | |
1029 | static_cast<_Up&&>(__f)); | |
1030 | } | |
1031 | }; | |
1032 | ||
1033 | template<typename _Tp, typename _Up> | |
1034 | concept __partially_ordered | |
1035 | = __adl_partial<_Tp, _Up> | |
3fd1c229 | 1036 | || __cmp3way<partial_ordering, _Tp, _Up> |
0ff15d21 JW |
1037 | || __weakly_ordered<_Tp, _Up>; |
1038 | ||
1039 | class _Partial_order | |
1040 | { | |
1041 | template<typename _Tp, typename _Up> | |
1042 | static constexpr bool | |
1043 | _S_noexcept() | |
1044 | { | |
1045 | if constexpr (__adl_partial<_Tp, _Up>) | |
1046 | return noexcept(partial_ordering(partial_order(std::declval<_Tp>(), | |
1047 | std::declval<_Up>()))); | |
3fd1c229 JW |
1048 | else if constexpr (__cmp3way<partial_ordering, _Tp, _Up>) |
1049 | return noexcept(compare_three_way()(std::declval<_Tp>(), | |
1050 | std::declval<_Up>())); | |
0ff15d21 JW |
1051 | else if constexpr (__weakly_ordered<_Tp, _Up>) |
1052 | return _Weak_order::_S_noexcept<_Tp, _Up>(); | |
1053 | } | |
1054 | ||
1055 | friend class _Partial_fallback; | |
1056 | ||
1057 | public: | |
e2c79b96 | 1058 | template<typename _Tp, __decayed_same_as<_Tp> _Up> |
0ff15d21 JW |
1059 | requires __partially_ordered<_Tp, _Up> |
1060 | constexpr partial_ordering | |
c2a984a3 | 1061 | operator() [[nodiscard]] (_Tp&& __e, _Up&& __f) const |
0ff15d21 JW |
1062 | noexcept(_S_noexcept<_Tp, _Up>()) |
1063 | { | |
0ff15d21 JW |
1064 | if constexpr (__adl_partial<_Tp, _Up>) |
1065 | return partial_ordering(partial_order(static_cast<_Tp&&>(__e), | |
1066 | static_cast<_Up&&>(__f))); | |
3fd1c229 JW |
1067 | else if constexpr (__cmp3way<partial_ordering, _Tp, _Up>) |
1068 | return compare_three_way()(static_cast<_Tp&&>(__e), | |
1069 | static_cast<_Up&&>(__f)); | |
0ff15d21 JW |
1070 | else if constexpr (__weakly_ordered<_Tp, _Up>) |
1071 | return _Weak_order{}(static_cast<_Tp&&>(__e), | |
1072 | static_cast<_Up&&>(__f)); | |
1073 | } | |
1074 | }; | |
1075 | ||
1076 | template<typename _Tp, typename _Up> | |
1077 | concept __op_eq_lt = requires(_Tp&& __t, _Up&& __u) | |
1078 | { | |
1079 | { static_cast<_Tp&&>(__t) == static_cast<_Up&&>(__u) } | |
1080 | -> convertible_to<bool>; | |
1081 | { static_cast<_Tp&&>(__t) < static_cast<_Up&&>(__u) } | |
1082 | -> convertible_to<bool>; | |
1083 | }; | |
1084 | ||
1085 | class _Strong_fallback | |
1086 | { | |
1087 | template<typename _Tp, typename _Up> | |
1088 | static constexpr bool | |
1089 | _S_noexcept() | |
1090 | { | |
1091 | if constexpr (__strongly_ordered<_Tp, _Up>) | |
1092 | return _Strong_order::_S_noexcept<_Tp, _Up>(); | |
1093 | else | |
1094 | return noexcept(bool(std::declval<_Tp>() == std::declval<_Up>())) | |
1095 | && noexcept(bool(std::declval<_Tp>() < std::declval<_Up>())); | |
1096 | } | |
1097 | ||
1098 | public: | |
e2c79b96 | 1099 | template<typename _Tp, __decayed_same_as<_Tp> _Up> |
0ff15d21 | 1100 | requires __strongly_ordered<_Tp, _Up> || __op_eq_lt<_Tp, _Up> |
e2c79b96 | 1101 | constexpr strong_ordering |
c2a984a3 | 1102 | operator() [[nodiscard]] (_Tp&& __e, _Up&& __f) const |
0ff15d21 JW |
1103 | noexcept(_S_noexcept<_Tp, _Up>()) |
1104 | { | |
0ff15d21 JW |
1105 | if constexpr (__strongly_ordered<_Tp, _Up>) |
1106 | return _Strong_order{}(static_cast<_Tp&&>(__e), | |
1107 | static_cast<_Up&&>(__f)); | |
e2c79b96 | 1108 | else // __op_eq_lt<_Tp, _Up> |
0ff15d21 JW |
1109 | return static_cast<_Tp&&>(__e) == static_cast<_Up&&>(__f) |
1110 | ? strong_ordering::equal | |
1111 | : static_cast<_Tp&&>(__e) < static_cast<_Up&&>(__f) | |
1112 | ? strong_ordering::less | |
1113 | : strong_ordering::greater; | |
1114 | } | |
1115 | }; | |
1116 | ||
1117 | class _Weak_fallback | |
1118 | { | |
1119 | template<typename _Tp, typename _Up> | |
1120 | static constexpr bool | |
1121 | _S_noexcept() | |
1122 | { | |
1123 | if constexpr (__weakly_ordered<_Tp, _Up>) | |
1124 | return _Weak_order::_S_noexcept<_Tp, _Up>(); | |
1125 | else | |
1126 | return noexcept(bool(std::declval<_Tp>() == std::declval<_Up>())) | |
1127 | && noexcept(bool(std::declval<_Tp>() < std::declval<_Up>())); | |
1128 | } | |
1129 | ||
1130 | public: | |
e2c79b96 | 1131 | template<typename _Tp, __decayed_same_as<_Tp> _Up> |
0ff15d21 | 1132 | requires __weakly_ordered<_Tp, _Up> || __op_eq_lt<_Tp, _Up> |
e2c79b96 | 1133 | constexpr weak_ordering |
c2a984a3 | 1134 | operator() [[nodiscard]] (_Tp&& __e, _Up&& __f) const |
0ff15d21 JW |
1135 | noexcept(_S_noexcept<_Tp, _Up>()) |
1136 | { | |
0ff15d21 JW |
1137 | if constexpr (__weakly_ordered<_Tp, _Up>) |
1138 | return _Weak_order{}(static_cast<_Tp&&>(__e), | |
1139 | static_cast<_Up&&>(__f)); | |
e2c79b96 | 1140 | else // __op_eq_lt<_Tp, _Up> |
0ff15d21 JW |
1141 | return static_cast<_Tp&&>(__e) == static_cast<_Up&&>(__f) |
1142 | ? weak_ordering::equivalent | |
1143 | : static_cast<_Tp&&>(__e) < static_cast<_Up&&>(__f) | |
1144 | ? weak_ordering::less | |
1145 | : weak_ordering::greater; | |
1146 | } | |
1147 | }; | |
1148 | ||
b76a529c JW |
1149 | // _GLIBCXX_RESOLVE_LIB_DEFECTS |
1150 | // 3465. compare_partial_order_fallback requires F < E | |
1151 | template<typename _Tp, typename _Up> | |
1152 | concept __op_eq_lt_lt = __op_eq_lt<_Tp, _Up> | |
1153 | && requires(_Tp&& __t, _Up&& __u) | |
1154 | { | |
1155 | { static_cast<_Up&&>(__u) < static_cast<_Tp&&>(__t) } | |
1156 | -> convertible_to<bool>; | |
1157 | }; | |
1158 | ||
0ff15d21 JW |
1159 | class _Partial_fallback |
1160 | { | |
1161 | template<typename _Tp, typename _Up> | |
1162 | static constexpr bool | |
1163 | _S_noexcept() | |
1164 | { | |
1165 | if constexpr (__partially_ordered<_Tp, _Up>) | |
1166 | return _Partial_order::_S_noexcept<_Tp, _Up>(); | |
1167 | else | |
1168 | return noexcept(bool(std::declval<_Tp>() == std::declval<_Up>())) | |
1169 | && noexcept(bool(std::declval<_Tp>() < std::declval<_Up>())); | |
1170 | } | |
1171 | ||
1172 | public: | |
e2c79b96 | 1173 | template<typename _Tp, __decayed_same_as<_Tp> _Up> |
b76a529c | 1174 | requires __partially_ordered<_Tp, _Up> || __op_eq_lt_lt<_Tp, _Up> |
e2c79b96 | 1175 | constexpr partial_ordering |
c2a984a3 | 1176 | operator() [[nodiscard]] (_Tp&& __e, _Up&& __f) const |
0ff15d21 JW |
1177 | noexcept(_S_noexcept<_Tp, _Up>()) |
1178 | { | |
0ff15d21 JW |
1179 | if constexpr (__partially_ordered<_Tp, _Up>) |
1180 | return _Partial_order{}(static_cast<_Tp&&>(__e), | |
1181 | static_cast<_Up&&>(__f)); | |
b76a529c | 1182 | else // __op_eq_lt_lt<_Tp, _Up> |
0ff15d21 JW |
1183 | return static_cast<_Tp&&>(__e) == static_cast<_Up&&>(__f) |
1184 | ? partial_ordering::equivalent | |
1185 | : static_cast<_Tp&&>(__e) < static_cast<_Up&&>(__f) | |
1186 | ? partial_ordering::less | |
1187 | : static_cast<_Up&&>(__f) < static_cast<_Tp&&>(__e) | |
1188 | ? partial_ordering::greater | |
1189 | : partial_ordering::unordered; | |
1190 | } | |
1191 | }; | |
faea9d92 | 1192 | } // namespace @endcond |
0ff15d21 | 1193 | |
b7689b96 | 1194 | // [cmp.alg], comparison algorithms |
faea9d92 JW |
1195 | |
1196 | inline namespace _Cpo | |
b7689b96 | 1197 | { |
faea9d92 | 1198 | inline constexpr __compare::_Strong_order strong_order{}; |
0ff15d21 | 1199 | |
faea9d92 | 1200 | inline constexpr __compare::_Weak_order weak_order{}; |
0ff15d21 | 1201 | |
faea9d92 | 1202 | inline constexpr __compare::_Partial_order partial_order{}; |
0ff15d21 | 1203 | |
faea9d92 JW |
1204 | inline constexpr __compare::_Strong_fallback |
1205 | compare_strong_order_fallback{}; | |
0ff15d21 | 1206 | |
faea9d92 JW |
1207 | inline constexpr __compare::_Weak_fallback |
1208 | compare_weak_order_fallback{}; | |
0ff15d21 | 1209 | |
faea9d92 JW |
1210 | inline constexpr __compare::_Partial_fallback |
1211 | compare_partial_order_fallback{}; | |
b7689b96 | 1212 | } |
7f397e45 | 1213 | |
faea9d92 | 1214 | /// @cond undocumented |
7f397e45 JW |
1215 | namespace __detail |
1216 | { | |
73a0a21d | 1217 | // [expos.only.func] synth-three-way |
7f397e45 JW |
1218 | inline constexpr struct _Synth3way |
1219 | { | |
73a0a21d JW |
1220 | template<typename _Tp, typename _Up> |
1221 | static constexpr bool | |
1222 | _S_noexcept(const _Tp* __t = nullptr, const _Up* __u = nullptr) | |
1223 | { | |
1224 | if constexpr (three_way_comparable_with<_Tp, _Up>) | |
1225 | return noexcept(*__t <=> *__u); | |
1226 | else | |
1227 | return noexcept(*__t < *__u) && noexcept(*__u < *__t); | |
1228 | } | |
1229 | ||
7f397e45 | 1230 | template<typename _Tp, typename _Up> |
8dec72ae | 1231 | [[nodiscard]] |
7f397e45 JW |
1232 | constexpr auto |
1233 | operator()(const _Tp& __t, const _Up& __u) const | |
73a0a21d | 1234 | noexcept(_S_noexcept<_Tp, _Up>()) |
7f397e45 JW |
1235 | requires requires |
1236 | { | |
c5e1c1d3 JW |
1237 | { __t < __u } -> __boolean_testable; |
1238 | { __u < __t } -> __boolean_testable; | |
7f397e45 JW |
1239 | } |
1240 | { | |
f214ffb3 | 1241 | if constexpr (three_way_comparable_with<_Tp, _Up>) |
7f397e45 JW |
1242 | return __t <=> __u; |
1243 | else | |
1244 | { | |
1245 | if (__t < __u) | |
1246 | return weak_ordering::less; | |
1247 | else if (__u < __t) | |
1248 | return weak_ordering::greater; | |
1249 | else | |
1250 | return weak_ordering::equivalent; | |
1251 | } | |
1252 | } | |
1253 | } __synth3way = {}; | |
1254 | ||
73a0a21d | 1255 | // [expos.only.func] synth-three-way-result |
7f397e45 JW |
1256 | template<typename _Tp, typename _Up = _Tp> |
1257 | using __synth3way_t | |
1258 | = decltype(__detail::__synth3way(std::declval<_Tp&>(), | |
1259 | std::declval<_Up&>())); | |
1260 | } // namespace __detail | |
faea9d92 | 1261 | /// @endcond |
083b7f28 | 1262 | #endif // __cpp_lib_three_way_comparison >= 201907L |
0c92c862 | 1263 | } // namespace std |
b7689b96 | 1264 | |
d3a7302e JM |
1265 | #pragma GCC diagnostic pop |
1266 | ||
b7689b96 JM |
1267 | #endif // C++20 |
1268 | ||
1269 | #endif // _COMPARE |