]> git.ipfire.org Git - thirdparty/gcc.git/blame - libstdc++-v3/libsupc++/compare
rtl-optimization/114855 - slow add_store_equivs in IRA
[thirdparty/gcc.git] / libstdc++-v3 / libsupc++ / compare
CommitLineData
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 46namespace 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