]> git.ipfire.org Git - thirdparty/gcc.git/blame - libstdc++-v3/libsupc++/compare
Update copyright years.
[thirdparty/gcc.git] / libstdc++-v3 / libsupc++ / compare
CommitLineData
b7689b96
JM
1// -*- C++ -*- operator<=> three-way comparison support.
2
8d9254fc 3// Copyright (C) 2019-2020 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
35#if __cplusplus > 201703L && __cpp_impl_three_way_comparison >= 201907L
36
37#pragma GCC visibility push(default)
38
39#include <concepts>
40
41namespace std
42{
43#define __cpp_lib_three_way_comparison 201711L
44
45 // [cmp.categories], comparison category types
46
47 namespace __cmp_cat
48 {
49 enum class _Eq
50 { equal = 0, equivalent = equal, nonequal = 1, nonequivalent = nonequal };
51
52 enum class _Ord { _Less = -1, _Greater = 1 };
53
54 enum class _Ncmp { _Unordered = -127 };
55
56 struct __unspec
57 {
58 constexpr __unspec(__unspec*) { }
59 };
60 }
61
b7689b96
JM
62 class partial_ordering
63 {
64 int _M_value;
65 bool _M_is_ordered;
66
67 constexpr explicit
68 partial_ordering(__cmp_cat::_Eq __v) noexcept
69 : _M_value(int(__v)), _M_is_ordered(true)
70 { }
71
72 constexpr explicit
73 partial_ordering(__cmp_cat::_Ord __v) noexcept
74 : _M_value(int(__v)), _M_is_ordered(true)
75 { }
76
77 constexpr explicit
78 partial_ordering(__cmp_cat::_Ncmp __v) noexcept
79 : _M_value(int(__v)), _M_is_ordered(false)
80 { }
81
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
JM
89 // comparisons
90 friend constexpr bool
91 operator==(partial_ordering __v, __cmp_cat::__unspec) noexcept
92 { return __v._M_is_ordered && __v._M_value == 0; }
93
94 friend constexpr bool
95 operator==(partial_ordering, partial_ordering) noexcept = default;
96
97 friend constexpr bool
98 operator< (partial_ordering __v, __cmp_cat::__unspec) noexcept
99 { return __v._M_is_ordered && __v._M_value < 0; }
100
101 friend constexpr bool
102 operator> (partial_ordering __v, __cmp_cat::__unspec) noexcept
103 { return __v._M_is_ordered && __v._M_value > 0; }
104
105 friend constexpr bool
106 operator<=(partial_ordering __v, __cmp_cat::__unspec) noexcept
107 { return __v._M_is_ordered && __v._M_value <= 0; }
108
109 friend constexpr bool
110 operator>=(partial_ordering __v, __cmp_cat::__unspec) noexcept
111 { return __v._M_is_ordered && __v._M_value >= 0; }
112
113 friend constexpr bool
114 operator< (__cmp_cat::__unspec, partial_ordering __v) noexcept
115 { return __v._M_is_ordered && 0 < __v._M_value; }
116
117 friend constexpr bool
118 operator> (__cmp_cat::__unspec, partial_ordering __v) noexcept
119 { return __v._M_is_ordered && 0 > __v._M_value; }
120
121 friend constexpr bool
122 operator<=(__cmp_cat::__unspec, partial_ordering __v) noexcept
123 { return __v._M_is_ordered && 0 <= __v._M_value; }
124
125 friend constexpr bool
126 operator>=(__cmp_cat::__unspec, partial_ordering __v) noexcept
127 { return __v._M_is_ordered && 0 >= __v._M_value; }
128
129 friend constexpr partial_ordering
130 operator<=>(partial_ordering __v, __cmp_cat::__unspec) noexcept
131 { return __v; }
132
133 friend constexpr partial_ordering
134 operator<=>(__cmp_cat::__unspec, partial_ordering __v) noexcept
135 {
136 if (__v < 0)
137 return partial_ordering::greater;
138 else if (__v > 0)
139 return partial_ordering::less;
140 else
141 return __v;
142 }
143 };
144
145 // valid values' definitions
146 inline constexpr partial_ordering
147 partial_ordering::less(__cmp_cat::_Ord::_Less);
148
149 inline constexpr partial_ordering
150 partial_ordering::equivalent(__cmp_cat::_Eq::equivalent);
151
152 inline constexpr partial_ordering
153 partial_ordering::greater(__cmp_cat::_Ord::_Greater);
154
155 inline constexpr partial_ordering
156 partial_ordering::unordered(__cmp_cat::_Ncmp::_Unordered);
157
158 class weak_ordering
159 {
160 int _M_value;
161
162 constexpr explicit
163 weak_ordering(__cmp_cat::_Eq __v) noexcept : _M_value(int(__v))
164 { }
165
166 constexpr explicit
167 weak_ordering(__cmp_cat::_Ord __v) noexcept : _M_value(int(__v))
168 { }
169
170 public:
171 // valid values
172 static const weak_ordering less;
173 static const weak_ordering equivalent;
174 static const weak_ordering greater;
175
b7689b96
JM
176 constexpr operator partial_ordering() const noexcept
177 {
178 if (_M_value == 0)
179 return partial_ordering::equivalent;
180 else if (_M_value < 0)
181 return partial_ordering::less;
182 else
183 return partial_ordering::greater;
184 }
185
186 // comparisons
187 friend constexpr bool
188 operator==(weak_ordering __v, __cmp_cat::__unspec) noexcept
189 { return __v._M_value == 0; }
190
191 friend constexpr bool
192 operator==(weak_ordering, weak_ordering) noexcept = default;
193
194 friend constexpr bool
195 operator< (weak_ordering __v, __cmp_cat::__unspec) noexcept
196 { return __v._M_value < 0; }
197
198 friend constexpr bool
199 operator> (weak_ordering __v, __cmp_cat::__unspec) noexcept
200 { return __v._M_value > 0; }
201
202 friend constexpr bool
203 operator<=(weak_ordering __v, __cmp_cat::__unspec) noexcept
204 { return __v._M_value <= 0; }
205
206 friend constexpr bool
207 operator>=(weak_ordering __v, __cmp_cat::__unspec) noexcept
208 { return __v._M_value >= 0; }
209
210 friend constexpr bool
211 operator< (__cmp_cat::__unspec, weak_ordering __v) noexcept
212 { return 0 < __v._M_value; }
213
214 friend constexpr bool
215 operator> (__cmp_cat::__unspec, weak_ordering __v) noexcept
216 { return 0 > __v._M_value; }
217
218 friend constexpr bool
219 operator<=(__cmp_cat::__unspec, weak_ordering __v) noexcept
220 { return 0 <= __v._M_value; }
221
222 friend constexpr bool
223 operator>=(__cmp_cat::__unspec, weak_ordering __v) noexcept
224 { return 0 >= __v._M_value; }
225
226 friend constexpr weak_ordering
227 operator<=>(weak_ordering __v, __cmp_cat::__unspec) noexcept
228 { return __v; }
229
230 friend constexpr weak_ordering
231 operator<=>(__cmp_cat::__unspec, weak_ordering __v) noexcept
232 {
233 if (__v < 0)
234 return weak_ordering::greater;
235 else if (__v > 0)
236 return weak_ordering::less;
237 else
238 return __v;
239 }
240 };
241
242 // valid values' definitions
243 inline constexpr weak_ordering
244 weak_ordering::less(__cmp_cat::_Ord::_Less);
245
246 inline constexpr weak_ordering
247 weak_ordering::equivalent(__cmp_cat::_Eq::equivalent);
248
249 inline constexpr weak_ordering
250 weak_ordering::greater(__cmp_cat::_Ord::_Greater);
251
252 class strong_ordering
253 {
254 int _M_value;
255
256 constexpr explicit
257 strong_ordering(__cmp_cat::_Eq __v) noexcept
258 : _M_value(int(__v))
259 { }
260
261 constexpr explicit
262 strong_ordering(__cmp_cat::_Ord __v) noexcept
263 : _M_value(int(__v))
264 { }
265
266 public:
267 // valid values
268 static const strong_ordering less;
269 static const strong_ordering equal;
270 static const strong_ordering equivalent;
271 static const strong_ordering greater;
272
b7689b96
JM
273 constexpr operator partial_ordering() const noexcept
274 {
275 if (_M_value == 0)
276 return partial_ordering::equivalent;
277 else if (_M_value < 0)
278 return partial_ordering::less;
279 else
280 return partial_ordering::greater;
281 }
282
283 constexpr operator weak_ordering() const noexcept
284 {
285 if (_M_value == 0)
286 return weak_ordering::equivalent;
287 else if (_M_value < 0)
288 return weak_ordering::less;
289 else
290 return weak_ordering::greater;
291 }
292
293 // comparisons
294 friend constexpr bool
295 operator==(strong_ordering __v, __cmp_cat::__unspec) noexcept
296 { return __v._M_value == 0; }
297
298 friend constexpr bool
299 operator==(strong_ordering, strong_ordering) noexcept = default;
300
301 friend constexpr bool
302 operator< (strong_ordering __v, __cmp_cat::__unspec) noexcept
303 { return __v._M_value < 0; }
304
305 friend constexpr bool
306 operator> (strong_ordering __v, __cmp_cat::__unspec) noexcept
307 { return __v._M_value > 0; }
308
309 friend constexpr bool
310 operator<=(strong_ordering __v, __cmp_cat::__unspec) noexcept
311 { return __v._M_value <= 0; }
312
313 friend constexpr bool
314 operator>=(strong_ordering __v, __cmp_cat::__unspec) noexcept
315 { return __v._M_value >= 0; }
316
317 friend constexpr bool
318 operator< (__cmp_cat::__unspec, strong_ordering __v) noexcept
319 { return 0 < __v._M_value; }
320
321 friend constexpr bool
322 operator> (__cmp_cat::__unspec, strong_ordering __v) noexcept
323 { return 0 > __v._M_value; }
324
325 friend constexpr bool
326 operator<=(__cmp_cat::__unspec, strong_ordering __v) noexcept
327 { return 0 <= __v._M_value; }
328
329 friend constexpr bool
330 operator>=(__cmp_cat::__unspec, strong_ordering __v) noexcept
331 { return 0 >= __v._M_value; }
332
333 friend constexpr strong_ordering
334 operator<=>(strong_ordering __v, __cmp_cat::__unspec) noexcept
335 { return __v; }
336
337 friend constexpr strong_ordering
338 operator<=>(__cmp_cat::__unspec, strong_ordering __v) noexcept
339 {
340 if (__v < 0)
341 return strong_ordering::greater;
342 else if (__v > 0)
343 return strong_ordering::less;
344 else
345 return __v;
346 }
347 };
348
349 // valid values' definitions
350 inline constexpr strong_ordering
351 strong_ordering::less(__cmp_cat::_Ord::_Less);
352
353 inline constexpr strong_ordering
354 strong_ordering::equal(__cmp_cat::_Eq::equal);
355
356 inline constexpr strong_ordering
357 strong_ordering::equivalent(__cmp_cat::_Eq::equivalent);
358
359 inline constexpr strong_ordering
360 strong_ordering::greater(__cmp_cat::_Ord::_Greater);
361
362
363 // named comparison functions
364 constexpr bool
4629ea55 365 is_eq(partial_ordering __cmp) noexcept
b7689b96
JM
366 { return __cmp == 0; }
367
368 constexpr bool
4629ea55 369 is_neq(partial_ordering __cmp) noexcept
b7689b96
JM
370 { return __cmp != 0; }
371
372 constexpr bool
373 is_lt (partial_ordering __cmp) noexcept
374 { return __cmp < 0; }
375
376 constexpr bool
377 is_lteq(partial_ordering __cmp) noexcept
378 { return __cmp <= 0; }
379
380 constexpr bool
381 is_gt (partial_ordering __cmp) noexcept
382 { return __cmp > 0; }
383
384 constexpr bool
385 is_gteq(partial_ordering __cmp) noexcept
386 { return __cmp >= 0; }
387
29669521
JW
388 namespace __detail
389 {
390 template<typename _Tp>
391 inline constexpr unsigned __cmp_cat_id = 1;
392 template<>
d1505d01 393 inline constexpr unsigned __cmp_cat_id<partial_ordering> = 2;
29669521
JW
394 template<>
395 inline constexpr unsigned __cmp_cat_id<weak_ordering> = 4;
396 template<>
d1505d01 397 inline constexpr unsigned __cmp_cat_id<strong_ordering> = 8;
29669521
JW
398
399 template<typename... _Ts>
d1505d01
JW
400 constexpr auto __common_cmp_cat()
401 {
402 constexpr unsigned __cats = (__cmp_cat_id<_Ts> | ...);
403 // If any Ti is not a comparison category type, U is void.
404 if constexpr (__cats & 1)
405 return;
406 // Otherwise, if at least one Ti is std::partial_ordering,
407 // U is std::partial_ordering.
408 else if constexpr (bool(__cats & __cmp_cat_id<partial_ordering>))
409 return partial_ordering::equivalent;
410 // Otherwise, if at least one Ti is std::weak_ordering,
411 // U is std::weak_ordering.
412 else if constexpr (bool(__cats & __cmp_cat_id<weak_ordering>))
413 return weak_ordering::equivalent;
414 // Otherwise, U is std::strong_ordering.
415 else
416 return strong_ordering::equivalent;
417 }
29669521
JW
418 } // namespace __detail
419
b7689b96
JM
420 // [cmp.common], common comparison category type
421 template<typename... _Ts>
0c92c862
JW
422 struct common_comparison_category
423 {
d1505d01 424 using type = decltype(__detail::__common_cmp_cat<_Ts...>());
b7689b96
JM
425 };
426
29669521
JW
427 // Partial specializations for one and zero argument cases.
428
429 template<typename _Tp>
430 struct common_comparison_category<_Tp>
431 { using type = void; };
432
433 template<>
434 struct common_comparison_category<partial_ordering>
435 { using type = partial_ordering; };
436
437 template<>
438 struct common_comparison_category<weak_ordering>
439 { using type = weak_ordering; };
440
441 template<>
442 struct common_comparison_category<strong_ordering>
443 { using type = strong_ordering; };
444
445 template<>
446 struct common_comparison_category<>
447 { using type = strong_ordering; };
448
b7689b96
JM
449 template<typename... _Ts>
450 using common_comparison_category_t
451 = typename common_comparison_category<_Ts...>::type;
452
d1505d01 453#if __cpp_lib_concepts
b7689b96
JM
454 namespace __detail
455 {
456 template<typename _Tp, typename _Cat>
457 concept __compares_as
458 = same_as<common_comparison_category_t<_Tp, _Cat>, _Cat>;
459
460 template<typename _Tp, typename _Up>
461 concept __partially_ordered_with
462 = requires(const remove_reference_t<_Tp>& __t,
463 const remove_reference_t<_Up>& __u) {
464 { __t < __u } -> boolean;
465 { __t > __u } -> boolean;
466 { __t <= __u } -> boolean;
467 { __t >= __u } -> boolean;
468 { __u < __t } -> boolean;
469 { __u > __t } -> boolean;
470 { __u <= __t } -> boolean;
471 { __u >= __t } -> boolean;
472 };
473 } // namespace __detail
474
475 // [cmp.concept], concept three_way_comparable
476 template<typename _Tp, typename _Cat = partial_ordering>
477 concept three_way_comparable
478 = __detail::__weakly_eq_cmp_with<_Tp, _Tp>
479 && (!convertible_to<_Cat, partial_ordering>
480 || __detail::__partially_ordered_with<_Tp, _Tp>)
481 && requires(const remove_reference_t<_Tp>& __a,
482 const remove_reference_t<_Tp>& __b) {
483 { __a <=> __b } -> __detail::__compares_as<_Cat>;
484 };
485
486 template<typename _Tp, typename _Up, typename _Cat = partial_ordering>
487 concept three_way_comparable_with
488 = __detail::__weakly_eq_cmp_with<_Tp, _Up>
489 && (!convertible_to<_Cat, partial_ordering>
490 || __detail::__partially_ordered_with<_Tp, _Up>)
491 && three_way_comparable<_Tp, _Cat>
492 && three_way_comparable<_Up, _Cat>
493 && common_reference_with<const remove_reference_t<_Tp>&,
494 const remove_reference_t<_Up>&>
495 && three_way_comparable<
496 common_reference_t<const remove_reference_t<_Tp>&,
497 const remove_reference_t<_Up>&>, _Cat>
498 && requires(const remove_reference_t<_Tp>& __t,
499 const remove_reference_t<_Up>& __u) {
500 { __t <=> __u } -> __detail::__compares_as<_Cat>;
501 { __u <=> __t } -> __detail::__compares_as<_Cat>;
502 };
b7689b96 503
7f397e45
JW
504 namespace __detail
505 {
506 template<typename _Tp, typename _Up>
507 using __cmp3way_res_t
508 = decltype(std::declval<_Tp>() <=> std::declval<_Up>());
509
510 // Implementation of std::compare_three_way_result.
511 // It is undefined for a program to add specializations of
512 // std::compare_three_way_result, so the std::compare_three_way_result_t
513 // alias ignores std::compare_three_way_result and uses
514 // __detail::__cmp3way_res_impl directly instead.
515 template<typename _Tp, typename _Up>
516 struct __cmp3way_res_impl
517 { };
b7689b96 518
7f397e45
JW
519 template<typename _Tp, typename _Up>
520 requires requires { typename __cmp3way_res_t<__cref<_Tp>, __cref<_Up>>; }
521 struct __cmp3way_res_impl<_Tp, _Up>
522 {
523 using type = __cmp3way_res_t<__cref<_Tp>, __cref<_Up>>;
524 };
525 } // namespace __detail
b7689b96
JM
526
527 /// [cmp.result], result of three-way comparison
528 template<typename _Tp, typename _Up = _Tp>
529 struct compare_three_way_result
7f397e45 530 : __detail::__cmp3way_res_impl<_Tp, _Up>
b7689b96
JM
531 { };
532
7f397e45 533 /// [cmp.result], result of three-way comparison
b7689b96
JM
534 template<typename _Tp, typename _Up = _Tp>
535 using compare_three_way_result_t
7f397e45 536 = typename __detail::__cmp3way_res_impl<_Tp, _Up>::type;
b7689b96 537
0c92c862
JW
538 namespace __detail
539 {
540 // BUILTIN-PTR-THREE-WAY(T, U)
541 template<typename _Tp, typename _Up>
542 concept __3way_builtin_ptr_cmp
543 = convertible_to<_Tp, const volatile void*>
544 && convertible_to<_Up, const volatile void*>
545 && ! requires(_Tp&& __t, _Up&& __u)
546 { operator<=>(static_cast<_Tp&&>(__t), static_cast<_Up&&>(__u)); }
547 && ! requires(_Tp&& __t, _Up&& __u)
548 { static_cast<_Tp&&>(__t).operator<=>(static_cast<_Up&&>(__u)); };
7f397e45
JW
549
550 // FIXME: workaround for PR c++/91073
551 template<typename _Tp, typename _Up>
552 concept __3way_cmp_with = three_way_comparable_with<_Tp, _Up>;
0c92c862
JW
553 } // namespace __detail
554
b7689b96
JM
555 // [cmp.object], typename compare_three_way
556 struct compare_three_way
557 {
b7689b96 558 template<typename _Tp, typename _Up>
7f397e45 559 requires (__detail::__3way_cmp_with<_Tp, _Up>
0c92c862 560 || __detail::__3way_builtin_ptr_cmp<_Tp, _Up>)
29669521
JW
561 constexpr auto
562 operator()(_Tp&& __t, _Up&& __u) const noexcept
563 {
564 if constexpr (__detail::__3way_builtin_ptr_cmp<_Tp, _Up>)
565 {
566 auto __pt = static_cast<const volatile void*>(__t);
567 auto __pu = static_cast<const volatile void*>(__u);
568 if (__builtin_is_constant_evaluated())
569 return __pt <=> __pu;
570 auto __it = reinterpret_cast<__UINTPTR_TYPE__>(__pt);
571 auto __iu = reinterpret_cast<__UINTPTR_TYPE__>(__pu);
572 return __it <=> __iu;
573 }
574 else
575 return static_cast<_Tp&&>(__t) <=> static_cast<_Up&&>(__u);
576 }
b7689b96
JM
577
578 using is_transparent = void;
579 };
580
0ff15d21
JW
581 namespace __cmp_cust
582 {
583 template<floating_point _Tp>
584 constexpr weak_ordering
585 __fp_weak_ordering(_Tp __e, _Tp __f)
586 {
587 // Returns an integer with the same sign as the argument, and magnitude
588 // indicating the classification: zero=1 subnorm=2 norm=3 inf=4 nan=5
589 auto __cat = [](_Tp __fp) -> int {
590 const int __sign = __builtin_signbit(__fp) ? -1 : 1;
591 if (__builtin_isnormal(__fp))
592 return (__fp == 0 ? 1 : 3) * __sign;
593 if (__builtin_isnan(__fp))
594 return 5 * __sign;
595 if (int __inf = __builtin_isinf_sign(__fp))
596 return 4 * __inf;
597 return 2 * __sign;
598 };
599
600 auto __po = __e <=> __f;
601 if (is_lt(__po))
602 return weak_ordering::less;
603 else if (is_gt(__po))
604 return weak_ordering::greater;
605 else if (__po == partial_ordering::equivalent)
606 return weak_ordering::equivalent;
607 else // unordered, at least one argument is NaN
608 {
609 // return -1 for negative nan, +1 for positive nan, 0 otherwise.
610 auto __isnan_sign = [](_Tp __fp) -> int {
611 return __builtin_isnan(__fp)
612 ? __builtin_signbit(__fp) ? -1 : 1
613 : 0;
614 };
615 auto __ord = __isnan_sign(__e) <=> __isnan_sign(__f);
616 if (is_eq(__ord))
617 return weak_ordering::equivalent;
618 else if (is_lt(__ord))
619 return weak_ordering::less;
620 else
621 return weak_ordering::greater;
622 }
623 }
624
625 template<typename _Tp, typename _Up>
626 concept __adl_strong = requires(_Tp&& __t, _Up&& __u)
627 {
628 strong_ordering(strong_order(static_cast<_Tp&&>(__t),
629 static_cast<_Up&&>(__u)));
630 };
631
632 template<typename _Tp, typename _Up>
633 concept __adl_weak = requires(_Tp&& __t, _Up&& __u)
634 {
635 weak_ordering(weak_order(static_cast<_Tp&&>(__t),
636 static_cast<_Up&&>(__u)));
637 };
638
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>
647 concept __op_cmp = requires(_Tp&& __t, _Up&& __u)
648 {
649 _Ord(static_cast<_Tp&&>(__t) <=> static_cast<_Up&&>(__u));
650 };
651
652 template<typename _Tp, typename _Up>
653 concept __strongly_ordered
654 = __adl_strong<_Tp, _Up>
655 // FIXME: || floating_point<remove_reference_t<_Tp>>
656 || __op_cmp<strong_ordering, _Tp, _Up>;
657
658 class _Strong_order
659 {
660 template<typename _Tp, typename _Up>
661 static constexpr bool
662 _S_noexcept()
663 {
664 if constexpr (floating_point<decay_t<_Tp>>)
665 return true;
666 else if constexpr (__adl_strong<_Tp, _Up>)
667 return noexcept(strong_ordering(strong_order(std::declval<_Tp>(),
668 std::declval<_Up>())));
669 else if constexpr (__op_cmp<strong_ordering, _Tp, _Up>)
670 return noexcept(std::declval<_Tp>() <=> std::declval<_Up>());
671 }
672
673 friend class _Weak_order;
674 friend class _Strong_fallback;
675
676 public:
677 template<typename _Tp, typename _Up>
678 requires __strongly_ordered<_Tp, _Up>
679 constexpr strong_ordering
680 operator()(_Tp&& __e, _Up&& __f) const
681 noexcept(_S_noexcept<_Tp, _Up>())
682 {
683 static_assert(same_as<decay_t<_Tp>, decay_t<_Up>>);
684
685 /* FIXME:
686 if constexpr (floating_point<decay_t<_Tp>>)
687 return __cmp_cust::__fp_strong_order(__e, __f);
688 else */ if constexpr (__adl_strong<_Tp, _Up>)
689 return strong_ordering(strong_order(static_cast<_Tp&&>(__e),
690 static_cast<_Up&&>(__f)));
691 else if constexpr (__op_cmp<strong_ordering, _Tp, _Up>)
692 return static_cast<_Tp&&>(__e) <=> static_cast<_Up&&>(__f);
693 }
694 };
695
696 template<typename _Tp, typename _Up>
697 concept __weakly_ordered
698 = floating_point<remove_reference_t<_Tp>>
699 || __adl_weak<_Tp, _Up>
700 || __op_cmp<weak_ordering, _Tp, _Up>
701 || __strongly_ordered<_Tp, _Up>;
702
703 class _Weak_order
704 {
705 template<typename _Tp, typename _Up>
706 static constexpr bool
707 _S_noexcept()
708 {
709 if constexpr (floating_point<decay_t<_Tp>>)
710 return true;
711 else if constexpr (__adl_weak<_Tp, _Up>)
712 return noexcept(weak_ordering(weak_order(std::declval<_Tp>(),
713 std::declval<_Up>())));
714 else if constexpr (__op_cmp<weak_ordering, _Tp, _Up>)
715 return noexcept(std::declval<_Tp>() <=> std::declval<_Up>());
716 else if constexpr (__strongly_ordered<_Tp, _Up>)
717 return _Strong_order::_S_noexcept<_Tp, _Up>();
718 }
719
720 friend class _Partial_order;
721 friend class _Weak_fallback;
722
723 public:
724 template<typename _Tp, typename _Up>
725 requires __weakly_ordered<_Tp, _Up>
726 constexpr weak_ordering
727 operator()(_Tp&& __e, _Up&& __f) const
728 noexcept(_S_noexcept<_Tp, _Up>())
729 {
730 static_assert(same_as<decay_t<_Tp>, decay_t<_Up>>);
731
732 if constexpr (floating_point<decay_t<_Tp>>)
733 return __cmp_cust::__fp_weak_ordering(__e, __f);
734 else if constexpr (__adl_weak<_Tp, _Up>)
735 return weak_ordering(weak_order(static_cast<_Tp&&>(__e),
736 static_cast<_Up&&>(__f)));
737 else if constexpr (__op_cmp<weak_ordering, _Tp, _Up>)
738 return static_cast<_Tp&&>(__e) <=> static_cast<_Up&&>(__f);
739 else if constexpr (__strongly_ordered<_Tp, _Up>)
740 return _Strong_order{}(static_cast<_Tp&&>(__e),
741 static_cast<_Up&&>(__f));
742 }
743 };
744
745 template<typename _Tp, typename _Up>
746 concept __partially_ordered
747 = __adl_partial<_Tp, _Up>
748 || __op_cmp<partial_ordering, _Tp, _Up>
749 || __weakly_ordered<_Tp, _Up>;
750
751 class _Partial_order
752 {
753 template<typename _Tp, typename _Up>
754 static constexpr bool
755 _S_noexcept()
756 {
757 if constexpr (__adl_partial<_Tp, _Up>)
758 return noexcept(partial_ordering(partial_order(std::declval<_Tp>(),
759 std::declval<_Up>())));
760 else if constexpr (__op_cmp<partial_ordering, _Tp, _Up>)
761 return noexcept(std::declval<_Tp>() <=> std::declval<_Up>());
762 else if constexpr (__weakly_ordered<_Tp, _Up>)
763 return _Weak_order::_S_noexcept<_Tp, _Up>();
764 }
765
766 friend class _Partial_fallback;
767
768 public:
769 template<typename _Tp, typename _Up>
770 requires __partially_ordered<_Tp, _Up>
771 constexpr partial_ordering
772 operator()(_Tp&& __e, _Up&& __f) const
773 noexcept(_S_noexcept<_Tp, _Up>())
774 {
775 static_assert(same_as<decay_t<_Tp>, decay_t<_Up>>);
776
777 if constexpr (__adl_partial<_Tp, _Up>)
778 return partial_ordering(partial_order(static_cast<_Tp&&>(__e),
779 static_cast<_Up&&>(__f)));
780 else if constexpr (__op_cmp<partial_ordering, _Tp, _Up>)
781 return static_cast<_Tp&&>(__e) <=> static_cast<_Up&&>(__f);
782 else if constexpr (__weakly_ordered<_Tp, _Up>)
783 return _Weak_order{}(static_cast<_Tp&&>(__e),
784 static_cast<_Up&&>(__f));
785 }
786 };
787
788 template<typename _Tp, typename _Up>
789 concept __op_eq_lt = requires(_Tp&& __t, _Up&& __u)
790 {
791 { static_cast<_Tp&&>(__t) == static_cast<_Up&&>(__u) }
792 -> convertible_to<bool>;
793 { static_cast<_Tp&&>(__t) < static_cast<_Up&&>(__u) }
794 -> convertible_to<bool>;
795 };
796
797 class _Strong_fallback
798 {
799 template<typename _Tp, typename _Up>
800 static constexpr bool
801 _S_noexcept()
802 {
803 if constexpr (__strongly_ordered<_Tp, _Up>)
804 return _Strong_order::_S_noexcept<_Tp, _Up>();
805 else
806 return noexcept(bool(std::declval<_Tp>() == std::declval<_Up>()))
807 && noexcept(bool(std::declval<_Tp>() < std::declval<_Up>()));
808 }
809
810 public:
811 template<typename _Tp, typename _Up>
812 requires __strongly_ordered<_Tp, _Up> || __op_eq_lt<_Tp, _Up>
813 constexpr decltype(auto)
814 operator()(_Tp&& __e, _Up&& __f) const
815 noexcept(_S_noexcept<_Tp, _Up>())
816 {
817 static_assert(same_as<decay_t<_Tp>, decay_t<_Up>>);
818
819 if constexpr (__strongly_ordered<_Tp, _Up>)
820 return _Strong_order{}(static_cast<_Tp&&>(__e),
821 static_cast<_Up&&>(__f));
822 else if constexpr (__op_eq_lt<_Tp, _Up>)
823 return static_cast<_Tp&&>(__e) == static_cast<_Up&&>(__f)
824 ? strong_ordering::equal
825 : static_cast<_Tp&&>(__e) < static_cast<_Up&&>(__f)
826 ? strong_ordering::less
827 : strong_ordering::greater;
828 }
829 };
830
831 class _Weak_fallback
832 {
833 template<typename _Tp, typename _Up>
834 static constexpr bool
835 _S_noexcept()
836 {
837 if constexpr (__weakly_ordered<_Tp, _Up>)
838 return _Weak_order::_S_noexcept<_Tp, _Up>();
839 else
840 return noexcept(bool(std::declval<_Tp>() == std::declval<_Up>()))
841 && noexcept(bool(std::declval<_Tp>() < std::declval<_Up>()));
842 }
843
844 public:
845 template<typename _Tp, typename _Up>
846 requires __weakly_ordered<_Tp, _Up> || __op_eq_lt<_Tp, _Up>
847 constexpr decltype(auto)
848 operator()(_Tp&& __e, _Up&& __f) const
849 noexcept(_S_noexcept<_Tp, _Up>())
850 {
851 static_assert(same_as<decay_t<_Tp>, decay_t<_Up>>);
852
853 if constexpr (__weakly_ordered<_Tp, _Up>)
854 return _Weak_order{}(static_cast<_Tp&&>(__e),
855 static_cast<_Up&&>(__f));
856 else if constexpr (__op_eq_lt<_Tp, _Up>)
857 return static_cast<_Tp&&>(__e) == static_cast<_Up&&>(__f)
858 ? weak_ordering::equivalent
859 : static_cast<_Tp&&>(__e) < static_cast<_Up&&>(__f)
860 ? weak_ordering::less
861 : weak_ordering::greater;
862 }
863 };
864
865 class _Partial_fallback
866 {
867 template<typename _Tp, typename _Up>
868 static constexpr bool
869 _S_noexcept()
870 {
871 if constexpr (__partially_ordered<_Tp, _Up>)
872 return _Partial_order::_S_noexcept<_Tp, _Up>();
873 else
874 return noexcept(bool(std::declval<_Tp>() == std::declval<_Up>()))
875 && noexcept(bool(std::declval<_Tp>() < std::declval<_Up>()));
876 }
877
878 public:
879 template<typename _Tp, typename _Up>
880 requires __partially_ordered<_Tp, _Up> || __op_eq_lt<_Tp, _Up>
881 constexpr decltype(auto)
882 operator()(_Tp&& __e, _Up&& __f) const
883 noexcept(_S_noexcept<_Tp, _Up>())
884 {
885 static_assert(same_as<decay_t<_Tp>, decay_t<_Up>>);
886
887 if constexpr (__partially_ordered<_Tp, _Up>)
888 return _Partial_order{}(static_cast<_Tp&&>(__e),
889 static_cast<_Up&&>(__f));
890 else if constexpr (__op_eq_lt<_Tp, _Up>)
891 return static_cast<_Tp&&>(__e) == static_cast<_Up&&>(__f)
892 ? partial_ordering::equivalent
893 : static_cast<_Tp&&>(__e) < static_cast<_Up&&>(__f)
894 ? partial_ordering::less
895 : static_cast<_Up&&>(__f) < static_cast<_Tp&&>(__e)
896 ? partial_ordering::greater
897 : partial_ordering::unordered;
898 }
899 };
900 } // namespace __cmp_cust
901
b7689b96
JM
902 // [cmp.alg], comparison algorithms
903 inline namespace __cmp_alg
904 {
0ff15d21
JW
905 inline constexpr __cmp_cust::_Strong_order strong_order{};
906
907 inline constexpr __cmp_cust::_Weak_order weak_order{};
908
909 inline constexpr __cmp_cust::_Partial_order partial_order{};
910
911 inline constexpr __cmp_cust::_Strong_fallback
912 compare_strong_order_fallback{};
913
914 inline constexpr __cmp_cust::_Weak_fallback
915 compare_weak_order_fallback{};
916
917 inline constexpr __cmp_cust::_Partial_fallback
918 compare_partial_order_fallback{};
b7689b96 919 }
7f397e45
JW
920
921 namespace __detail
922 {
923 // [expos.only.func]
924 inline constexpr struct _Synth3way
925 {
926 template<typename _Tp, typename _Up>
927 constexpr auto
928 operator()(const _Tp& __t, const _Up& __u) const
929 requires requires
930 {
931 { __t < __u } -> convertible_to<bool>;
932 { __u < __t } -> convertible_to<bool>;
933 }
934 {
935 if constexpr (__3way_cmp_with<_Tp, _Up>)
936 return __t <=> __u;
937 else
938 {
939 if (__t < __u)
940 return weak_ordering::less;
941 else if (__u < __t)
942 return weak_ordering::greater;
943 else
944 return weak_ordering::equivalent;
945 }
946 }
947 } __synth3way = {};
948
949 template<typename _Tp, typename _Up = _Tp>
950 using __synth3way_t
951 = decltype(__detail::__synth3way(std::declval<_Tp&>(),
952 std::declval<_Up&>()));
953 } // namespace __detail
0ff15d21 954#endif // concepts
0c92c862 955} // namespace std
b7689b96
JM
956
957#pragma GCC visibility pop
958
959#endif // C++20
960
961#endif // _COMPARE