1 // -*- C++ -*- operator<=> three-way comparison support.
3 // Copyright (C) 2019 Free Software Foundation, Inc.
5 // This file is part of GCC.
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)
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.
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.
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/>.
27 * This is a Standard C++ Library header.
33 #pragma GCC system_header
35 #if __cplusplus > 201703L && __cpp_impl_three_way_comparison >= 201907L
37 #pragma GCC visibility push(default)
43 #define __cpp_lib_three_way_comparison 201711L
45 // [cmp.categories], comparison category types
50 { equal = 0, equivalent = equal, nonequal = 1, nonequivalent = nonequal };
52 enum class _Ord { _Less = -1, _Greater = 1 };
54 enum class _Ncmp { _Unordered = -127 };
58 constexpr __unspec(__unspec*) { }
62 class partial_ordering
68 partial_ordering(__cmp_cat::_Eq __v) noexcept
69 : _M_value(int(__v)), _M_is_ordered(true)
73 partial_ordering(__cmp_cat::_Ord __v) noexcept
74 : _M_value(int(__v)), _M_is_ordered(true)
78 partial_ordering(__cmp_cat::_Ncmp __v) noexcept
79 : _M_value(int(__v)), _M_is_ordered(false)
84 static const partial_ordering less;
85 static const partial_ordering equivalent;
86 static const partial_ordering greater;
87 static const partial_ordering unordered;
91 operator==(partial_ordering __v, __cmp_cat::__unspec) noexcept
92 { return __v._M_is_ordered && __v._M_value == 0; }
95 operator==(partial_ordering, partial_ordering) noexcept = default;
98 operator< (partial_ordering __v, __cmp_cat::__unspec) noexcept
99 { return __v._M_is_ordered && __v._M_value < 0; }
101 friend constexpr bool
102 operator> (partial_ordering __v, __cmp_cat::__unspec) noexcept
103 { return __v._M_is_ordered && __v._M_value > 0; }
105 friend constexpr bool
106 operator<=(partial_ordering __v, __cmp_cat::__unspec) noexcept
107 { return __v._M_is_ordered && __v._M_value <= 0; }
109 friend constexpr bool
110 operator>=(partial_ordering __v, __cmp_cat::__unspec) noexcept
111 { return __v._M_is_ordered && __v._M_value >= 0; }
113 friend constexpr bool
114 operator< (__cmp_cat::__unspec, partial_ordering __v) noexcept
115 { return __v._M_is_ordered && 0 < __v._M_value; }
117 friend constexpr bool
118 operator> (__cmp_cat::__unspec, partial_ordering __v) noexcept
119 { return __v._M_is_ordered && 0 > __v._M_value; }
121 friend constexpr bool
122 operator<=(__cmp_cat::__unspec, partial_ordering __v) noexcept
123 { return __v._M_is_ordered && 0 <= __v._M_value; }
125 friend constexpr bool
126 operator>=(__cmp_cat::__unspec, partial_ordering __v) noexcept
127 { return __v._M_is_ordered && 0 >= __v._M_value; }
129 friend constexpr partial_ordering
130 operator<=>(partial_ordering __v, __cmp_cat::__unspec) noexcept
133 friend constexpr partial_ordering
134 operator<=>(__cmp_cat::__unspec, partial_ordering __v) noexcept
137 return partial_ordering::greater;
139 return partial_ordering::less;
145 // valid values' definitions
146 inline constexpr partial_ordering
147 partial_ordering::less(__cmp_cat::_Ord::_Less);
149 inline constexpr partial_ordering
150 partial_ordering::equivalent(__cmp_cat::_Eq::equivalent);
152 inline constexpr partial_ordering
153 partial_ordering::greater(__cmp_cat::_Ord::_Greater);
155 inline constexpr partial_ordering
156 partial_ordering::unordered(__cmp_cat::_Ncmp::_Unordered);
163 weak_ordering(__cmp_cat::_Eq __v) noexcept : _M_value(int(__v))
167 weak_ordering(__cmp_cat::_Ord __v) noexcept : _M_value(int(__v))
172 static const weak_ordering less;
173 static const weak_ordering equivalent;
174 static const weak_ordering greater;
176 constexpr operator partial_ordering() const noexcept
179 return partial_ordering::equivalent;
180 else if (_M_value < 0)
181 return partial_ordering::less;
183 return partial_ordering::greater;
187 friend constexpr bool
188 operator==(weak_ordering __v, __cmp_cat::__unspec) noexcept
189 { return __v._M_value == 0; }
191 friend constexpr bool
192 operator==(weak_ordering, weak_ordering) noexcept = default;
194 friend constexpr bool
195 operator< (weak_ordering __v, __cmp_cat::__unspec) noexcept
196 { return __v._M_value < 0; }
198 friend constexpr bool
199 operator> (weak_ordering __v, __cmp_cat::__unspec) noexcept
200 { return __v._M_value > 0; }
202 friend constexpr bool
203 operator<=(weak_ordering __v, __cmp_cat::__unspec) noexcept
204 { return __v._M_value <= 0; }
206 friend constexpr bool
207 operator>=(weak_ordering __v, __cmp_cat::__unspec) noexcept
208 { return __v._M_value >= 0; }
210 friend constexpr bool
211 operator< (__cmp_cat::__unspec, weak_ordering __v) noexcept
212 { return 0 < __v._M_value; }
214 friend constexpr bool
215 operator> (__cmp_cat::__unspec, weak_ordering __v) noexcept
216 { return 0 > __v._M_value; }
218 friend constexpr bool
219 operator<=(__cmp_cat::__unspec, weak_ordering __v) noexcept
220 { return 0 <= __v._M_value; }
222 friend constexpr bool
223 operator>=(__cmp_cat::__unspec, weak_ordering __v) noexcept
224 { return 0 >= __v._M_value; }
226 friend constexpr weak_ordering
227 operator<=>(weak_ordering __v, __cmp_cat::__unspec) noexcept
230 friend constexpr weak_ordering
231 operator<=>(__cmp_cat::__unspec, weak_ordering __v) noexcept
234 return weak_ordering::greater;
236 return weak_ordering::less;
242 // valid values' definitions
243 inline constexpr weak_ordering
244 weak_ordering::less(__cmp_cat::_Ord::_Less);
246 inline constexpr weak_ordering
247 weak_ordering::equivalent(__cmp_cat::_Eq::equivalent);
249 inline constexpr weak_ordering
250 weak_ordering::greater(__cmp_cat::_Ord::_Greater);
252 class strong_ordering
257 strong_ordering(__cmp_cat::_Eq __v) noexcept
262 strong_ordering(__cmp_cat::_Ord __v) noexcept
268 static const strong_ordering less;
269 static const strong_ordering equal;
270 static const strong_ordering equivalent;
271 static const strong_ordering greater;
273 constexpr operator partial_ordering() const noexcept
276 return partial_ordering::equivalent;
277 else if (_M_value < 0)
278 return partial_ordering::less;
280 return partial_ordering::greater;
283 constexpr operator weak_ordering() const noexcept
286 return weak_ordering::equivalent;
287 else if (_M_value < 0)
288 return weak_ordering::less;
290 return weak_ordering::greater;
294 friend constexpr bool
295 operator==(strong_ordering __v, __cmp_cat::__unspec) noexcept
296 { return __v._M_value == 0; }
298 friend constexpr bool
299 operator==(strong_ordering, strong_ordering) noexcept = default;
301 friend constexpr bool
302 operator< (strong_ordering __v, __cmp_cat::__unspec) noexcept
303 { return __v._M_value < 0; }
305 friend constexpr bool
306 operator> (strong_ordering __v, __cmp_cat::__unspec) noexcept
307 { return __v._M_value > 0; }
309 friend constexpr bool
310 operator<=(strong_ordering __v, __cmp_cat::__unspec) noexcept
311 { return __v._M_value <= 0; }
313 friend constexpr bool
314 operator>=(strong_ordering __v, __cmp_cat::__unspec) noexcept
315 { return __v._M_value >= 0; }
317 friend constexpr bool
318 operator< (__cmp_cat::__unspec, strong_ordering __v) noexcept
319 { return 0 < __v._M_value; }
321 friend constexpr bool
322 operator> (__cmp_cat::__unspec, strong_ordering __v) noexcept
323 { return 0 > __v._M_value; }
325 friend constexpr bool
326 operator<=(__cmp_cat::__unspec, strong_ordering __v) noexcept
327 { return 0 <= __v._M_value; }
329 friend constexpr bool
330 operator>=(__cmp_cat::__unspec, strong_ordering __v) noexcept
331 { return 0 >= __v._M_value; }
333 friend constexpr strong_ordering
334 operator<=>(strong_ordering __v, __cmp_cat::__unspec) noexcept
337 friend constexpr strong_ordering
338 operator<=>(__cmp_cat::__unspec, strong_ordering __v) noexcept
341 return strong_ordering::greater;
343 return strong_ordering::less;
349 // valid values' definitions
350 inline constexpr strong_ordering
351 strong_ordering::less(__cmp_cat::_Ord::_Less);
353 inline constexpr strong_ordering
354 strong_ordering::equal(__cmp_cat::_Eq::equal);
356 inline constexpr strong_ordering
357 strong_ordering::equivalent(__cmp_cat::_Eq::equivalent);
359 inline constexpr strong_ordering
360 strong_ordering::greater(__cmp_cat::_Ord::_Greater);
363 // named comparison functions
365 is_eq(partial_ordering __cmp) noexcept
366 { return __cmp == 0; }
369 is_neq(partial_ordering __cmp) noexcept
370 { return __cmp != 0; }
373 is_lt (partial_ordering __cmp) noexcept
374 { return __cmp < 0; }
377 is_lteq(partial_ordering __cmp) noexcept
378 { return __cmp <= 0; }
381 is_gt (partial_ordering __cmp) noexcept
382 { return __cmp > 0; }
385 is_gteq(partial_ordering __cmp) noexcept
386 { return __cmp >= 0; }
388 #if __cpp_lib_concepts
391 template<typename _Tp>
392 inline constexpr unsigned __cmp_cat_id = 1;
394 inline constexpr unsigned __cmp_cat_id<strong_ordering> = 2;
396 inline constexpr unsigned __cmp_cat_id<weak_ordering> = 4;
398 inline constexpr unsigned __cmp_cat_id<partial_ordering> = 8;
400 template<typename... _Ts>
401 constexpr unsigned __cmp_cat_ids()
402 { return (__cmp_cat_id<_Ts> | ...); }
405 struct __common_cmp_cat;
407 // If any Ti is not a comparison category type, U is void.
408 template<unsigned _Bits>
409 requires ((_Bits & 1) == 1)
410 struct __common_cmp_cat<_Bits> { using type = void; };
412 // Otherwise, if at least one Ti is std::partial_ordering,
413 // U is std::partial_ordering.
414 template<unsigned _Bits>
415 requires ((_Bits & 0b1001) == 0b1000)
416 struct __common_cmp_cat<_Bits> { using type = partial_ordering; };
418 // Otherwise, if at least one Ti is std::weak_ordering,
419 // U is std::weak_ordering.
420 template<unsigned _Bits>
421 requires ((_Bits & 0b1101) == 0b0100)
422 struct __common_cmp_cat<_Bits> { using type = weak_ordering; };
424 // Otherwise, U is std::strong_ordering.
426 struct __common_cmp_cat<0b0010> { using type = strong_ordering; };
427 } // namespace __detail
429 // [cmp.common], common comparison category type
430 template<typename... _Ts>
431 struct common_comparison_category
434 = __detail::__common_cmp_cat<__detail::__cmp_cat_ids<_Ts...>()>::type;
437 // Partial specializations for one and zero argument cases.
439 template<typename _Tp>
440 struct common_comparison_category<_Tp>
441 { using type = void; };
444 struct common_comparison_category<partial_ordering>
445 { using type = partial_ordering; };
448 struct common_comparison_category<weak_ordering>
449 { using type = weak_ordering; };
452 struct common_comparison_category<strong_ordering>
453 { using type = strong_ordering; };
456 struct common_comparison_category<>
457 { using type = strong_ordering; };
459 template<typename... _Ts>
460 using common_comparison_category_t
461 = typename common_comparison_category<_Ts...>::type;
465 template<typename _Tp, typename _Cat>
466 concept __compares_as
467 = same_as<common_comparison_category_t<_Tp, _Cat>, _Cat>;
469 template<typename _Tp, typename _Up>
470 concept __partially_ordered_with
471 = requires(const remove_reference_t<_Tp>& __t,
472 const remove_reference_t<_Up>& __u) {
473 { __t < __u } -> boolean;
474 { __t > __u } -> boolean;
475 { __t <= __u } -> boolean;
476 { __t >= __u } -> boolean;
477 { __u < __t } -> boolean;
478 { __u > __t } -> boolean;
479 { __u <= __t } -> boolean;
480 { __u >= __t } -> boolean;
482 } // namespace __detail
484 // [cmp.concept], concept three_way_comparable
485 template<typename _Tp, typename _Cat = partial_ordering>
486 concept three_way_comparable
487 = __detail::__weakly_eq_cmp_with<_Tp, _Tp>
488 && (!convertible_to<_Cat, partial_ordering>
489 || __detail::__partially_ordered_with<_Tp, _Tp>)
490 && requires(const remove_reference_t<_Tp>& __a,
491 const remove_reference_t<_Tp>& __b) {
492 { __a <=> __b } -> __detail::__compares_as<_Cat>;
495 template<typename _Tp, typename _Up, typename _Cat = partial_ordering>
496 concept three_way_comparable_with
497 = __detail::__weakly_eq_cmp_with<_Tp, _Up>
498 && (!convertible_to<_Cat, partial_ordering>
499 || __detail::__partially_ordered_with<_Tp, _Up>)
500 && three_way_comparable<_Tp, _Cat>
501 && three_way_comparable<_Up, _Cat>
502 && common_reference_with<const remove_reference_t<_Tp>&,
503 const remove_reference_t<_Up>&>
504 && three_way_comparable<
505 common_reference_t<const remove_reference_t<_Tp>&,
506 const remove_reference_t<_Up>&>, _Cat>
507 && requires(const remove_reference_t<_Tp>& __t,
508 const remove_reference_t<_Up>& __u) {
509 { __t <=> __u } -> __detail::__compares_as<_Cat>;
510 { __u <=> __t } -> __detail::__compares_as<_Cat>;
515 template<typename _Tp, typename _Up>
516 using __cmp3way_res_t
517 = decltype(std::declval<_Tp>() <=> std::declval<_Up>());
519 // Implementation of std::compare_three_way_result.
520 // It is undefined for a program to add specializations of
521 // std::compare_three_way_result, so the std::compare_three_way_result_t
522 // alias ignores std::compare_three_way_result and uses
523 // __detail::__cmp3way_res_impl directly instead.
524 template<typename _Tp, typename _Up>
525 struct __cmp3way_res_impl
528 template<typename _Tp, typename _Up>
529 requires requires { typename __cmp3way_res_t<__cref<_Tp>, __cref<_Up>>; }
530 struct __cmp3way_res_impl<_Tp, _Up>
532 using type = __cmp3way_res_t<__cref<_Tp>, __cref<_Up>>;
534 } // namespace __detail
536 /// [cmp.result], result of three-way comparison
537 template<typename _Tp, typename _Up = _Tp>
538 struct compare_three_way_result
539 : __detail::__cmp3way_res_impl<_Tp, _Up>
542 /// [cmp.result], result of three-way comparison
543 template<typename _Tp, typename _Up = _Tp>
544 using compare_three_way_result_t
545 = typename __detail::__cmp3way_res_impl<_Tp, _Up>::type;
549 // BUILTIN-PTR-THREE-WAY(T, U)
550 template<typename _Tp, typename _Up>
551 concept __3way_builtin_ptr_cmp
552 = convertible_to<_Tp, const volatile void*>
553 && convertible_to<_Up, const volatile void*>
554 && ! requires(_Tp&& __t, _Up&& __u)
555 { operator<=>(static_cast<_Tp&&>(__t), static_cast<_Up&&>(__u)); }
556 && ! requires(_Tp&& __t, _Up&& __u)
557 { static_cast<_Tp&&>(__t).operator<=>(static_cast<_Up&&>(__u)); };
559 // FIXME: workaround for PR c++/91073
560 template<typename _Tp, typename _Up>
561 concept __3way_cmp_with = three_way_comparable_with<_Tp, _Up>;
562 } // namespace __detail
564 // [cmp.object], typename compare_three_way
565 struct compare_three_way
567 template<typename _Tp, typename _Up>
568 requires (__detail::__3way_cmp_with<_Tp, _Up>
569 || __detail::__3way_builtin_ptr_cmp<_Tp, _Up>)
571 operator()(_Tp&& __t, _Up&& __u) const noexcept
573 if constexpr (__detail::__3way_builtin_ptr_cmp<_Tp, _Up>)
575 auto __pt = static_cast<const volatile void*>(__t);
576 auto __pu = static_cast<const volatile void*>(__u);
577 if (__builtin_is_constant_evaluated())
578 return __pt <=> __pu;
579 auto __it = reinterpret_cast<__UINTPTR_TYPE__>(__pt);
580 auto __iu = reinterpret_cast<__UINTPTR_TYPE__>(__pu);
581 return __it <=> __iu;
584 return static_cast<_Tp&&>(__t) <=> static_cast<_Up&&>(__u);
587 using is_transparent = void;
592 template<floating_point _Tp>
593 constexpr weak_ordering
594 __fp_weak_ordering(_Tp __e, _Tp __f)
596 // Returns an integer with the same sign as the argument, and magnitude
597 // indicating the classification: zero=1 subnorm=2 norm=3 inf=4 nan=5
598 auto __cat = [](_Tp __fp) -> int {
599 const int __sign = __builtin_signbit(__fp) ? -1 : 1;
600 if (__builtin_isnormal(__fp))
601 return (__fp == 0 ? 1 : 3) * __sign;
602 if (__builtin_isnan(__fp))
604 if (int __inf = __builtin_isinf_sign(__fp))
609 auto __po = __e <=> __f;
611 return weak_ordering::less;
612 else if (is_gt(__po))
613 return weak_ordering::greater;
614 else if (__po == partial_ordering::equivalent)
615 return weak_ordering::equivalent;
616 else // unordered, at least one argument is NaN
618 // return -1 for negative nan, +1 for positive nan, 0 otherwise.
619 auto __isnan_sign = [](_Tp __fp) -> int {
620 return __builtin_isnan(__fp)
621 ? __builtin_signbit(__fp) ? -1 : 1
624 auto __ord = __isnan_sign(__e) <=> __isnan_sign(__f);
626 return weak_ordering::equivalent;
627 else if (is_lt(__ord))
628 return weak_ordering::less;
630 return weak_ordering::greater;
634 template<typename _Tp, typename _Up>
635 concept __adl_strong = requires(_Tp&& __t, _Up&& __u)
637 strong_ordering(strong_order(static_cast<_Tp&&>(__t),
638 static_cast<_Up&&>(__u)));
641 template<typename _Tp, typename _Up>
642 concept __adl_weak = requires(_Tp&& __t, _Up&& __u)
644 weak_ordering(weak_order(static_cast<_Tp&&>(__t),
645 static_cast<_Up&&>(__u)));
648 template<typename _Tp, typename _Up>
649 concept __adl_partial = requires(_Tp&& __t, _Up&& __u)
651 partial_ordering(partial_order(static_cast<_Tp&&>(__t),
652 static_cast<_Up&&>(__u)));
655 template<typename _Ord, typename _Tp, typename _Up>
656 concept __op_cmp = requires(_Tp&& __t, _Up&& __u)
658 _Ord(static_cast<_Tp&&>(__t) <=> static_cast<_Up&&>(__u));
661 template<typename _Tp, typename _Up>
662 concept __strongly_ordered
663 = __adl_strong<_Tp, _Up>
664 // FIXME: || floating_point<remove_reference_t<_Tp>>
665 || __op_cmp<strong_ordering, _Tp, _Up>;
669 template<typename _Tp, typename _Up>
670 static constexpr bool
673 if constexpr (floating_point<decay_t<_Tp>>)
675 else if constexpr (__adl_strong<_Tp, _Up>)
676 return noexcept(strong_ordering(strong_order(std::declval<_Tp>(),
677 std::declval<_Up>())));
678 else if constexpr (__op_cmp<strong_ordering, _Tp, _Up>)
679 return noexcept(std::declval<_Tp>() <=> std::declval<_Up>());
682 friend class _Weak_order;
683 friend class _Strong_fallback;
686 template<typename _Tp, typename _Up>
687 requires __strongly_ordered<_Tp, _Up>
688 constexpr strong_ordering
689 operator()(_Tp&& __e, _Up&& __f) const
690 noexcept(_S_noexcept<_Tp, _Up>())
692 static_assert(same_as<decay_t<_Tp>, decay_t<_Up>>);
695 if constexpr (floating_point<decay_t<_Tp>>)
696 return __cmp_cust::__fp_strong_order(__e, __f);
697 else */ if constexpr (__adl_strong<_Tp, _Up>)
698 return strong_ordering(strong_order(static_cast<_Tp&&>(__e),
699 static_cast<_Up&&>(__f)));
700 else if constexpr (__op_cmp<strong_ordering, _Tp, _Up>)
701 return static_cast<_Tp&&>(__e) <=> static_cast<_Up&&>(__f);
705 template<typename _Tp, typename _Up>
706 concept __weakly_ordered
707 = floating_point<remove_reference_t<_Tp>>
708 || __adl_weak<_Tp, _Up>
709 || __op_cmp<weak_ordering, _Tp, _Up>
710 || __strongly_ordered<_Tp, _Up>;
714 template<typename _Tp, typename _Up>
715 static constexpr bool
718 if constexpr (floating_point<decay_t<_Tp>>)
720 else if constexpr (__adl_weak<_Tp, _Up>)
721 return noexcept(weak_ordering(weak_order(std::declval<_Tp>(),
722 std::declval<_Up>())));
723 else if constexpr (__op_cmp<weak_ordering, _Tp, _Up>)
724 return noexcept(std::declval<_Tp>() <=> std::declval<_Up>());
725 else if constexpr (__strongly_ordered<_Tp, _Up>)
726 return _Strong_order::_S_noexcept<_Tp, _Up>();
729 friend class _Partial_order;
730 friend class _Weak_fallback;
733 template<typename _Tp, typename _Up>
734 requires __weakly_ordered<_Tp, _Up>
735 constexpr weak_ordering
736 operator()(_Tp&& __e, _Up&& __f) const
737 noexcept(_S_noexcept<_Tp, _Up>())
739 static_assert(same_as<decay_t<_Tp>, decay_t<_Up>>);
741 if constexpr (floating_point<decay_t<_Tp>>)
742 return __cmp_cust::__fp_weak_ordering(__e, __f);
743 else if constexpr (__adl_weak<_Tp, _Up>)
744 return weak_ordering(weak_order(static_cast<_Tp&&>(__e),
745 static_cast<_Up&&>(__f)));
746 else if constexpr (__op_cmp<weak_ordering, _Tp, _Up>)
747 return static_cast<_Tp&&>(__e) <=> static_cast<_Up&&>(__f);
748 else if constexpr (__strongly_ordered<_Tp, _Up>)
749 return _Strong_order{}(static_cast<_Tp&&>(__e),
750 static_cast<_Up&&>(__f));
754 template<typename _Tp, typename _Up>
755 concept __partially_ordered
756 = __adl_partial<_Tp, _Up>
757 || __op_cmp<partial_ordering, _Tp, _Up>
758 || __weakly_ordered<_Tp, _Up>;
762 template<typename _Tp, typename _Up>
763 static constexpr bool
766 if constexpr (__adl_partial<_Tp, _Up>)
767 return noexcept(partial_ordering(partial_order(std::declval<_Tp>(),
768 std::declval<_Up>())));
769 else if constexpr (__op_cmp<partial_ordering, _Tp, _Up>)
770 return noexcept(std::declval<_Tp>() <=> std::declval<_Up>());
771 else if constexpr (__weakly_ordered<_Tp, _Up>)
772 return _Weak_order::_S_noexcept<_Tp, _Up>();
775 friend class _Partial_fallback;
778 template<typename _Tp, typename _Up>
779 requires __partially_ordered<_Tp, _Up>
780 constexpr partial_ordering
781 operator()(_Tp&& __e, _Up&& __f) const
782 noexcept(_S_noexcept<_Tp, _Up>())
784 static_assert(same_as<decay_t<_Tp>, decay_t<_Up>>);
786 if constexpr (__adl_partial<_Tp, _Up>)
787 return partial_ordering(partial_order(static_cast<_Tp&&>(__e),
788 static_cast<_Up&&>(__f)));
789 else if constexpr (__op_cmp<partial_ordering, _Tp, _Up>)
790 return static_cast<_Tp&&>(__e) <=> static_cast<_Up&&>(__f);
791 else if constexpr (__weakly_ordered<_Tp, _Up>)
792 return _Weak_order{}(static_cast<_Tp&&>(__e),
793 static_cast<_Up&&>(__f));
797 template<typename _Tp, typename _Up>
798 concept __op_eq_lt = requires(_Tp&& __t, _Up&& __u)
800 { static_cast<_Tp&&>(__t) == static_cast<_Up&&>(__u) }
801 -> convertible_to<bool>;
802 { static_cast<_Tp&&>(__t) < static_cast<_Up&&>(__u) }
803 -> convertible_to<bool>;
806 class _Strong_fallback
808 template<typename _Tp, typename _Up>
809 static constexpr bool
812 if constexpr (__strongly_ordered<_Tp, _Up>)
813 return _Strong_order::_S_noexcept<_Tp, _Up>();
815 return noexcept(bool(std::declval<_Tp>() == std::declval<_Up>()))
816 && noexcept(bool(std::declval<_Tp>() < std::declval<_Up>()));
820 template<typename _Tp, typename _Up>
821 requires __strongly_ordered<_Tp, _Up> || __op_eq_lt<_Tp, _Up>
822 constexpr decltype(auto)
823 operator()(_Tp&& __e, _Up&& __f) const
824 noexcept(_S_noexcept<_Tp, _Up>())
826 static_assert(same_as<decay_t<_Tp>, decay_t<_Up>>);
828 if constexpr (__strongly_ordered<_Tp, _Up>)
829 return _Strong_order{}(static_cast<_Tp&&>(__e),
830 static_cast<_Up&&>(__f));
831 else if constexpr (__op_eq_lt<_Tp, _Up>)
832 return static_cast<_Tp&&>(__e) == static_cast<_Up&&>(__f)
833 ? strong_ordering::equal
834 : static_cast<_Tp&&>(__e) < static_cast<_Up&&>(__f)
835 ? strong_ordering::less
836 : strong_ordering::greater;
842 template<typename _Tp, typename _Up>
843 static constexpr bool
846 if constexpr (__weakly_ordered<_Tp, _Up>)
847 return _Weak_order::_S_noexcept<_Tp, _Up>();
849 return noexcept(bool(std::declval<_Tp>() == std::declval<_Up>()))
850 && noexcept(bool(std::declval<_Tp>() < std::declval<_Up>()));
854 template<typename _Tp, typename _Up>
855 requires __weakly_ordered<_Tp, _Up> || __op_eq_lt<_Tp, _Up>
856 constexpr decltype(auto)
857 operator()(_Tp&& __e, _Up&& __f) const
858 noexcept(_S_noexcept<_Tp, _Up>())
860 static_assert(same_as<decay_t<_Tp>, decay_t<_Up>>);
862 if constexpr (__weakly_ordered<_Tp, _Up>)
863 return _Weak_order{}(static_cast<_Tp&&>(__e),
864 static_cast<_Up&&>(__f));
865 else if constexpr (__op_eq_lt<_Tp, _Up>)
866 return static_cast<_Tp&&>(__e) == static_cast<_Up&&>(__f)
867 ? weak_ordering::equivalent
868 : static_cast<_Tp&&>(__e) < static_cast<_Up&&>(__f)
869 ? weak_ordering::less
870 : weak_ordering::greater;
874 class _Partial_fallback
876 template<typename _Tp, typename _Up>
877 static constexpr bool
880 if constexpr (__partially_ordered<_Tp, _Up>)
881 return _Partial_order::_S_noexcept<_Tp, _Up>();
883 return noexcept(bool(std::declval<_Tp>() == std::declval<_Up>()))
884 && noexcept(bool(std::declval<_Tp>() < std::declval<_Up>()));
888 template<typename _Tp, typename _Up>
889 requires __partially_ordered<_Tp, _Up> || __op_eq_lt<_Tp, _Up>
890 constexpr decltype(auto)
891 operator()(_Tp&& __e, _Up&& __f) const
892 noexcept(_S_noexcept<_Tp, _Up>())
894 static_assert(same_as<decay_t<_Tp>, decay_t<_Up>>);
896 if constexpr (__partially_ordered<_Tp, _Up>)
897 return _Partial_order{}(static_cast<_Tp&&>(__e),
898 static_cast<_Up&&>(__f));
899 else if constexpr (__op_eq_lt<_Tp, _Up>)
900 return static_cast<_Tp&&>(__e) == static_cast<_Up&&>(__f)
901 ? partial_ordering::equivalent
902 : static_cast<_Tp&&>(__e) < static_cast<_Up&&>(__f)
903 ? partial_ordering::less
904 : static_cast<_Up&&>(__f) < static_cast<_Tp&&>(__e)
905 ? partial_ordering::greater
906 : partial_ordering::unordered;
909 } // namespace __cmp_cust
911 // [cmp.alg], comparison algorithms
912 inline namespace __cmp_alg
914 inline constexpr __cmp_cust::_Strong_order strong_order{};
916 inline constexpr __cmp_cust::_Weak_order weak_order{};
918 inline constexpr __cmp_cust::_Partial_order partial_order{};
920 inline constexpr __cmp_cust::_Strong_fallback
921 compare_strong_order_fallback{};
923 inline constexpr __cmp_cust::_Weak_fallback
924 compare_weak_order_fallback{};
926 inline constexpr __cmp_cust::_Partial_fallback
927 compare_partial_order_fallback{};
933 inline constexpr struct _Synth3way
935 template<typename _Tp, typename _Up>
937 operator()(const _Tp& __t, const _Up& __u) const
940 { __t < __u } -> convertible_to<bool>;
941 { __u < __t } -> convertible_to<bool>;
944 if constexpr (__3way_cmp_with<_Tp, _Up>)
949 return weak_ordering::less;
951 return weak_ordering::greater;
953 return weak_ordering::equivalent;
958 template<typename _Tp, typename _Up = _Tp>
960 = decltype(__detail::__synth3way(std::declval<_Tp&>(),
961 std::declval<_Up&>()));
962 } // namespace __detail
966 #pragma GCC visibility pop