1 // -*- C++ -*- operator<=> three-way comparison support.
3 // Copyright (C) 2019-2020 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)
41 #if __cpp_lib_concepts
42 # define __cpp_lib_three_way_comparison 201711L
47 // [cmp.categories], comparison category types
52 { equal = 0, equivalent = equal, nonequal = 1, nonequivalent = nonequal };
54 enum class _Ord { _Less = -1, _Greater = 1 };
56 enum class _Ncmp { _Unordered = -127 };
60 constexpr __unspec(__unspec*) { }
64 class partial_ordering
70 partial_ordering(__cmp_cat::_Eq __v) noexcept
71 : _M_value(int(__v)), _M_is_ordered(true)
75 partial_ordering(__cmp_cat::_Ord __v) noexcept
76 : _M_value(int(__v)), _M_is_ordered(true)
80 partial_ordering(__cmp_cat::_Ncmp __v) noexcept
81 : _M_value(int(__v)), _M_is_ordered(false)
86 static const partial_ordering less;
87 static const partial_ordering equivalent;
88 static const partial_ordering greater;
89 static const partial_ordering unordered;
93 operator==(partial_ordering __v, __cmp_cat::__unspec) noexcept
94 { return __v._M_is_ordered && __v._M_value == 0; }
97 operator==(partial_ordering, partial_ordering) noexcept = default;
100 operator< (partial_ordering __v, __cmp_cat::__unspec) noexcept
101 { return __v._M_is_ordered && __v._M_value < 0; }
103 friend constexpr bool
104 operator> (partial_ordering __v, __cmp_cat::__unspec) noexcept
105 { return __v._M_is_ordered && __v._M_value > 0; }
107 friend constexpr bool
108 operator<=(partial_ordering __v, __cmp_cat::__unspec) noexcept
109 { return __v._M_is_ordered && __v._M_value <= 0; }
111 friend constexpr bool
112 operator>=(partial_ordering __v, __cmp_cat::__unspec) noexcept
113 { return __v._M_is_ordered && __v._M_value >= 0; }
115 friend constexpr bool
116 operator< (__cmp_cat::__unspec, partial_ordering __v) noexcept
117 { return __v._M_is_ordered && 0 < __v._M_value; }
119 friend constexpr bool
120 operator> (__cmp_cat::__unspec, partial_ordering __v) noexcept
121 { return __v._M_is_ordered && 0 > __v._M_value; }
123 friend constexpr bool
124 operator<=(__cmp_cat::__unspec, partial_ordering __v) noexcept
125 { return __v._M_is_ordered && 0 <= __v._M_value; }
127 friend constexpr bool
128 operator>=(__cmp_cat::__unspec, partial_ordering __v) noexcept
129 { return __v._M_is_ordered && 0 >= __v._M_value; }
131 friend constexpr partial_ordering
132 operator<=>(partial_ordering __v, __cmp_cat::__unspec) noexcept
135 friend constexpr partial_ordering
136 operator<=>(__cmp_cat::__unspec, partial_ordering __v) noexcept
139 return partial_ordering::greater;
141 return partial_ordering::less;
147 // valid values' definitions
148 inline constexpr partial_ordering
149 partial_ordering::less(__cmp_cat::_Ord::_Less);
151 inline constexpr partial_ordering
152 partial_ordering::equivalent(__cmp_cat::_Eq::equivalent);
154 inline constexpr partial_ordering
155 partial_ordering::greater(__cmp_cat::_Ord::_Greater);
157 inline constexpr partial_ordering
158 partial_ordering::unordered(__cmp_cat::_Ncmp::_Unordered);
165 weak_ordering(__cmp_cat::_Eq __v) noexcept : _M_value(int(__v))
169 weak_ordering(__cmp_cat::_Ord __v) noexcept : _M_value(int(__v))
174 static const weak_ordering less;
175 static const weak_ordering equivalent;
176 static const weak_ordering greater;
178 constexpr operator partial_ordering() const noexcept
181 return partial_ordering::equivalent;
182 else if (_M_value < 0)
183 return partial_ordering::less;
185 return partial_ordering::greater;
189 friend constexpr bool
190 operator==(weak_ordering __v, __cmp_cat::__unspec) noexcept
191 { return __v._M_value == 0; }
193 friend constexpr bool
194 operator==(weak_ordering, weak_ordering) noexcept = default;
196 friend constexpr bool
197 operator< (weak_ordering __v, __cmp_cat::__unspec) noexcept
198 { return __v._M_value < 0; }
200 friend constexpr bool
201 operator> (weak_ordering __v, __cmp_cat::__unspec) noexcept
202 { return __v._M_value > 0; }
204 friend constexpr bool
205 operator<=(weak_ordering __v, __cmp_cat::__unspec) noexcept
206 { return __v._M_value <= 0; }
208 friend constexpr bool
209 operator>=(weak_ordering __v, __cmp_cat::__unspec) noexcept
210 { return __v._M_value >= 0; }
212 friend constexpr bool
213 operator< (__cmp_cat::__unspec, weak_ordering __v) noexcept
214 { return 0 < __v._M_value; }
216 friend constexpr bool
217 operator> (__cmp_cat::__unspec, weak_ordering __v) noexcept
218 { return 0 > __v._M_value; }
220 friend constexpr bool
221 operator<=(__cmp_cat::__unspec, weak_ordering __v) noexcept
222 { return 0 <= __v._M_value; }
224 friend constexpr bool
225 operator>=(__cmp_cat::__unspec, weak_ordering __v) noexcept
226 { return 0 >= __v._M_value; }
228 friend constexpr weak_ordering
229 operator<=>(weak_ordering __v, __cmp_cat::__unspec) noexcept
232 friend constexpr weak_ordering
233 operator<=>(__cmp_cat::__unspec, weak_ordering __v) noexcept
236 return weak_ordering::greater;
238 return weak_ordering::less;
244 // valid values' definitions
245 inline constexpr weak_ordering
246 weak_ordering::less(__cmp_cat::_Ord::_Less);
248 inline constexpr weak_ordering
249 weak_ordering::equivalent(__cmp_cat::_Eq::equivalent);
251 inline constexpr weak_ordering
252 weak_ordering::greater(__cmp_cat::_Ord::_Greater);
254 class strong_ordering
259 strong_ordering(__cmp_cat::_Eq __v) noexcept
264 strong_ordering(__cmp_cat::_Ord __v) noexcept
270 static const strong_ordering less;
271 static const strong_ordering equal;
272 static const strong_ordering equivalent;
273 static const strong_ordering greater;
275 constexpr operator partial_ordering() const noexcept
278 return partial_ordering::equivalent;
279 else if (_M_value < 0)
280 return partial_ordering::less;
282 return partial_ordering::greater;
285 constexpr operator weak_ordering() const noexcept
288 return weak_ordering::equivalent;
289 else if (_M_value < 0)
290 return weak_ordering::less;
292 return weak_ordering::greater;
296 friend constexpr bool
297 operator==(strong_ordering __v, __cmp_cat::__unspec) noexcept
298 { return __v._M_value == 0; }
300 friend constexpr bool
301 operator==(strong_ordering, strong_ordering) noexcept = default;
303 friend constexpr bool
304 operator< (strong_ordering __v, __cmp_cat::__unspec) noexcept
305 { return __v._M_value < 0; }
307 friend constexpr bool
308 operator> (strong_ordering __v, __cmp_cat::__unspec) noexcept
309 { return __v._M_value > 0; }
311 friend constexpr bool
312 operator<=(strong_ordering __v, __cmp_cat::__unspec) noexcept
313 { return __v._M_value <= 0; }
315 friend constexpr bool
316 operator>=(strong_ordering __v, __cmp_cat::__unspec) noexcept
317 { return __v._M_value >= 0; }
319 friend constexpr bool
320 operator< (__cmp_cat::__unspec, strong_ordering __v) noexcept
321 { return 0 < __v._M_value; }
323 friend constexpr bool
324 operator> (__cmp_cat::__unspec, strong_ordering __v) noexcept
325 { return 0 > __v._M_value; }
327 friend constexpr bool
328 operator<=(__cmp_cat::__unspec, strong_ordering __v) noexcept
329 { return 0 <= __v._M_value; }
331 friend constexpr bool
332 operator>=(__cmp_cat::__unspec, strong_ordering __v) noexcept
333 { return 0 >= __v._M_value; }
335 friend constexpr strong_ordering
336 operator<=>(strong_ordering __v, __cmp_cat::__unspec) noexcept
339 friend constexpr strong_ordering
340 operator<=>(__cmp_cat::__unspec, strong_ordering __v) noexcept
343 return strong_ordering::greater;
345 return strong_ordering::less;
351 // valid values' definitions
352 inline constexpr strong_ordering
353 strong_ordering::less(__cmp_cat::_Ord::_Less);
355 inline constexpr strong_ordering
356 strong_ordering::equal(__cmp_cat::_Eq::equal);
358 inline constexpr strong_ordering
359 strong_ordering::equivalent(__cmp_cat::_Eq::equivalent);
361 inline constexpr strong_ordering
362 strong_ordering::greater(__cmp_cat::_Ord::_Greater);
365 // named comparison functions
367 is_eq(partial_ordering __cmp) noexcept
368 { return __cmp == 0; }
371 is_neq(partial_ordering __cmp) noexcept
372 { return __cmp != 0; }
375 is_lt (partial_ordering __cmp) noexcept
376 { return __cmp < 0; }
379 is_lteq(partial_ordering __cmp) noexcept
380 { return __cmp <= 0; }
383 is_gt (partial_ordering __cmp) noexcept
384 { return __cmp > 0; }
387 is_gteq(partial_ordering __cmp) noexcept
388 { return __cmp >= 0; }
392 template<typename _Tp>
393 inline constexpr unsigned __cmp_cat_id = 1;
395 inline constexpr unsigned __cmp_cat_id<partial_ordering> = 2;
397 inline constexpr unsigned __cmp_cat_id<weak_ordering> = 4;
399 inline constexpr unsigned __cmp_cat_id<strong_ordering> = 8;
401 template<typename... _Ts>
402 constexpr auto __common_cmp_cat()
404 constexpr unsigned __cats = (__cmp_cat_id<_Ts> | ...);
405 // If any Ti is not a comparison category type, U is void.
406 if constexpr (__cats & 1)
408 // Otherwise, if at least one Ti is std::partial_ordering,
409 // U is std::partial_ordering.
410 else if constexpr (bool(__cats & __cmp_cat_id<partial_ordering>))
411 return partial_ordering::equivalent;
412 // Otherwise, if at least one Ti is std::weak_ordering,
413 // U is std::weak_ordering.
414 else if constexpr (bool(__cats & __cmp_cat_id<weak_ordering>))
415 return weak_ordering::equivalent;
416 // Otherwise, U is std::strong_ordering.
418 return strong_ordering::equivalent;
420 } // namespace __detail
422 // [cmp.common], common comparison category type
423 template<typename... _Ts>
424 struct common_comparison_category
426 using type = decltype(__detail::__common_cmp_cat<_Ts...>());
429 // Partial specializations for one and zero argument cases.
431 template<typename _Tp>
432 struct common_comparison_category<_Tp>
433 { using type = void; };
436 struct common_comparison_category<partial_ordering>
437 { using type = partial_ordering; };
440 struct common_comparison_category<weak_ordering>
441 { using type = weak_ordering; };
444 struct common_comparison_category<strong_ordering>
445 { using type = strong_ordering; };
448 struct common_comparison_category<>
449 { using type = strong_ordering; };
451 template<typename... _Ts>
452 using common_comparison_category_t
453 = typename common_comparison_category<_Ts...>::type;
455 #if __cpp_lib_concepts
458 template<typename _Tp, typename _Cat>
459 concept __compares_as
460 = same_as<common_comparison_category_t<_Tp, _Cat>, _Cat>;
462 template<typename _Tp, typename _Up>
463 concept __partially_ordered_with
464 = requires(const remove_reference_t<_Tp>& __t,
465 const remove_reference_t<_Up>& __u) {
466 { __t < __u } -> boolean;
467 { __t > __u } -> boolean;
468 { __t <= __u } -> boolean;
469 { __t >= __u } -> boolean;
470 { __u < __t } -> boolean;
471 { __u > __t } -> boolean;
472 { __u <= __t } -> boolean;
473 { __u >= __t } -> boolean;
475 } // namespace __detail
477 // [cmp.concept], concept three_way_comparable
478 template<typename _Tp, typename _Cat = partial_ordering>
479 concept three_way_comparable
480 = __detail::__weakly_eq_cmp_with<_Tp, _Tp>
481 && (!convertible_to<_Cat, partial_ordering>
482 || __detail::__partially_ordered_with<_Tp, _Tp>)
483 && requires(const remove_reference_t<_Tp>& __a,
484 const remove_reference_t<_Tp>& __b) {
485 { __a <=> __b } -> __detail::__compares_as<_Cat>;
488 template<typename _Tp, typename _Up, typename _Cat = partial_ordering>
489 concept three_way_comparable_with
490 = __detail::__weakly_eq_cmp_with<_Tp, _Up>
491 && (!convertible_to<_Cat, partial_ordering>
492 || __detail::__partially_ordered_with<_Tp, _Up>)
493 && three_way_comparable<_Tp, _Cat>
494 && three_way_comparable<_Up, _Cat>
495 && common_reference_with<const remove_reference_t<_Tp>&,
496 const remove_reference_t<_Up>&>
497 && three_way_comparable<
498 common_reference_t<const remove_reference_t<_Tp>&,
499 const remove_reference_t<_Up>&>, _Cat>
500 && requires(const remove_reference_t<_Tp>& __t,
501 const remove_reference_t<_Up>& __u) {
502 { __t <=> __u } -> __detail::__compares_as<_Cat>;
503 { __u <=> __t } -> __detail::__compares_as<_Cat>;
508 template<typename _Tp, typename _Up>
509 using __cmp3way_res_t
510 = decltype(std::declval<_Tp>() <=> std::declval<_Up>());
512 // Implementation of std::compare_three_way_result.
513 // It is undefined for a program to add specializations of
514 // std::compare_three_way_result, so the std::compare_three_way_result_t
515 // alias ignores std::compare_three_way_result and uses
516 // __detail::__cmp3way_res_impl directly instead.
517 template<typename _Tp, typename _Up>
518 struct __cmp3way_res_impl
521 template<typename _Tp, typename _Up>
522 requires requires { typename __cmp3way_res_t<__cref<_Tp>, __cref<_Up>>; }
523 struct __cmp3way_res_impl<_Tp, _Up>
525 using type = __cmp3way_res_t<__cref<_Tp>, __cref<_Up>>;
527 } // namespace __detail
529 /// [cmp.result], result of three-way comparison
530 template<typename _Tp, typename _Up = _Tp>
531 struct compare_three_way_result
532 : __detail::__cmp3way_res_impl<_Tp, _Up>
535 /// [cmp.result], result of three-way comparison
536 template<typename _Tp, typename _Up = _Tp>
537 using compare_three_way_result_t
538 = typename __detail::__cmp3way_res_impl<_Tp, _Up>::type;
542 // BUILTIN-PTR-THREE-WAY(T, U)
543 template<typename _Tp, typename _Up>
544 concept __3way_builtin_ptr_cmp
545 = convertible_to<_Tp, const volatile void*>
546 && convertible_to<_Up, const volatile void*>
547 && ! requires(_Tp&& __t, _Up&& __u)
548 { operator<=>(static_cast<_Tp&&>(__t), static_cast<_Up&&>(__u)); }
549 && ! requires(_Tp&& __t, _Up&& __u)
550 { static_cast<_Tp&&>(__t).operator<=>(static_cast<_Up&&>(__u)); };
552 // FIXME: workaround for PR c++/91073
553 template<typename _Tp, typename _Up>
554 concept __3way_cmp_with = three_way_comparable_with<_Tp, _Up>;
555 } // namespace __detail
557 // [cmp.object], typename compare_three_way
558 struct compare_three_way
560 template<typename _Tp, typename _Up>
561 requires (__detail::__3way_cmp_with<_Tp, _Up>
562 || __detail::__3way_builtin_ptr_cmp<_Tp, _Up>)
564 operator()(_Tp&& __t, _Up&& __u) const noexcept
566 if constexpr (__detail::__3way_builtin_ptr_cmp<_Tp, _Up>)
568 auto __pt = static_cast<const volatile void*>(__t);
569 auto __pu = static_cast<const volatile void*>(__u);
570 if (__builtin_is_constant_evaluated())
571 return __pt <=> __pu;
572 auto __it = reinterpret_cast<__UINTPTR_TYPE__>(__pt);
573 auto __iu = reinterpret_cast<__UINTPTR_TYPE__>(__pu);
574 return __it <=> __iu;
577 return static_cast<_Tp&&>(__t) <=> static_cast<_Up&&>(__u);
580 using is_transparent = void;
585 template<floating_point _Tp>
586 constexpr weak_ordering
587 __fp_weak_ordering(_Tp __e, _Tp __f)
589 // Returns an integer with the same sign as the argument, and magnitude
590 // indicating the classification: zero=1 subnorm=2 norm=3 inf=4 nan=5
591 auto __cat = [](_Tp __fp) -> int {
592 const int __sign = __builtin_signbit(__fp) ? -1 : 1;
593 if (__builtin_isnormal(__fp))
594 return (__fp == 0 ? 1 : 3) * __sign;
595 if (__builtin_isnan(__fp))
597 if (int __inf = __builtin_isinf_sign(__fp))
602 auto __po = __e <=> __f;
604 return weak_ordering::less;
605 else if (is_gt(__po))
606 return weak_ordering::greater;
607 else if (__po == partial_ordering::equivalent)
608 return weak_ordering::equivalent;
609 else // unordered, at least one argument is NaN
611 // return -1 for negative nan, +1 for positive nan, 0 otherwise.
612 auto __isnan_sign = [](_Tp __fp) -> int {
613 return __builtin_isnan(__fp)
614 ? __builtin_signbit(__fp) ? -1 : 1
617 auto __ord = __isnan_sign(__e) <=> __isnan_sign(__f);
619 return weak_ordering::equivalent;
620 else if (is_lt(__ord))
621 return weak_ordering::less;
623 return weak_ordering::greater;
627 template<typename _Tp, typename _Up>
628 concept __adl_strong = requires(_Tp&& __t, _Up&& __u)
630 strong_ordering(strong_order(static_cast<_Tp&&>(__t),
631 static_cast<_Up&&>(__u)));
634 template<typename _Tp, typename _Up>
635 concept __adl_weak = requires(_Tp&& __t, _Up&& __u)
637 weak_ordering(weak_order(static_cast<_Tp&&>(__t),
638 static_cast<_Up&&>(__u)));
641 template<typename _Tp, typename _Up>
642 concept __adl_partial = requires(_Tp&& __t, _Up&& __u)
644 partial_ordering(partial_order(static_cast<_Tp&&>(__t),
645 static_cast<_Up&&>(__u)));
648 template<typename _Ord, typename _Tp, typename _Up>
649 concept __op_cmp = requires(_Tp&& __t, _Up&& __u)
651 _Ord(static_cast<_Tp&&>(__t) <=> static_cast<_Up&&>(__u));
654 template<typename _Tp, typename _Up>
655 concept __strongly_ordered
656 = __adl_strong<_Tp, _Up>
657 // FIXME: || floating_point<remove_reference_t<_Tp>>
658 || __op_cmp<strong_ordering, _Tp, _Up>;
662 template<typename _Tp, typename _Up>
663 static constexpr bool
666 if constexpr (floating_point<decay_t<_Tp>>)
668 else if constexpr (__adl_strong<_Tp, _Up>)
669 return noexcept(strong_ordering(strong_order(std::declval<_Tp>(),
670 std::declval<_Up>())));
671 else if constexpr (__op_cmp<strong_ordering, _Tp, _Up>)
672 return noexcept(std::declval<_Tp>() <=> std::declval<_Up>());
675 friend class _Weak_order;
676 friend class _Strong_fallback;
679 template<typename _Tp, typename _Up>
680 requires __strongly_ordered<_Tp, _Up>
681 constexpr strong_ordering
682 operator()(_Tp&& __e, _Up&& __f) const
683 noexcept(_S_noexcept<_Tp, _Up>())
685 static_assert(same_as<decay_t<_Tp>, decay_t<_Up>>);
688 if constexpr (floating_point<decay_t<_Tp>>)
689 return __cmp_cust::__fp_strong_order(__e, __f);
690 else */ if constexpr (__adl_strong<_Tp, _Up>)
691 return strong_ordering(strong_order(static_cast<_Tp&&>(__e),
692 static_cast<_Up&&>(__f)));
693 else if constexpr (__op_cmp<strong_ordering, _Tp, _Up>)
694 return static_cast<_Tp&&>(__e) <=> static_cast<_Up&&>(__f);
698 template<typename _Tp, typename _Up>
699 concept __weakly_ordered
700 = floating_point<remove_reference_t<_Tp>>
701 || __adl_weak<_Tp, _Up>
702 || __op_cmp<weak_ordering, _Tp, _Up>
703 || __strongly_ordered<_Tp, _Up>;
707 template<typename _Tp, typename _Up>
708 static constexpr bool
711 if constexpr (floating_point<decay_t<_Tp>>)
713 else if constexpr (__adl_weak<_Tp, _Up>)
714 return noexcept(weak_ordering(weak_order(std::declval<_Tp>(),
715 std::declval<_Up>())));
716 else if constexpr (__op_cmp<weak_ordering, _Tp, _Up>)
717 return noexcept(std::declval<_Tp>() <=> std::declval<_Up>());
718 else if constexpr (__strongly_ordered<_Tp, _Up>)
719 return _Strong_order::_S_noexcept<_Tp, _Up>();
722 friend class _Partial_order;
723 friend class _Weak_fallback;
726 template<typename _Tp, typename _Up>
727 requires __weakly_ordered<_Tp, _Up>
728 constexpr weak_ordering
729 operator()(_Tp&& __e, _Up&& __f) const
730 noexcept(_S_noexcept<_Tp, _Up>())
732 static_assert(same_as<decay_t<_Tp>, decay_t<_Up>>);
734 if constexpr (floating_point<decay_t<_Tp>>)
735 return __cmp_cust::__fp_weak_ordering(__e, __f);
736 else if constexpr (__adl_weak<_Tp, _Up>)
737 return weak_ordering(weak_order(static_cast<_Tp&&>(__e),
738 static_cast<_Up&&>(__f)));
739 else if constexpr (__op_cmp<weak_ordering, _Tp, _Up>)
740 return static_cast<_Tp&&>(__e) <=> static_cast<_Up&&>(__f);
741 else if constexpr (__strongly_ordered<_Tp, _Up>)
742 return _Strong_order{}(static_cast<_Tp&&>(__e),
743 static_cast<_Up&&>(__f));
747 template<typename _Tp, typename _Up>
748 concept __partially_ordered
749 = __adl_partial<_Tp, _Up>
750 || __op_cmp<partial_ordering, _Tp, _Up>
751 || __weakly_ordered<_Tp, _Up>;
755 template<typename _Tp, typename _Up>
756 static constexpr bool
759 if constexpr (__adl_partial<_Tp, _Up>)
760 return noexcept(partial_ordering(partial_order(std::declval<_Tp>(),
761 std::declval<_Up>())));
762 else if constexpr (__op_cmp<partial_ordering, _Tp, _Up>)
763 return noexcept(std::declval<_Tp>() <=> std::declval<_Up>());
764 else if constexpr (__weakly_ordered<_Tp, _Up>)
765 return _Weak_order::_S_noexcept<_Tp, _Up>();
768 friend class _Partial_fallback;
771 template<typename _Tp, typename _Up>
772 requires __partially_ordered<_Tp, _Up>
773 constexpr partial_ordering
774 operator()(_Tp&& __e, _Up&& __f) const
775 noexcept(_S_noexcept<_Tp, _Up>())
777 static_assert(same_as<decay_t<_Tp>, decay_t<_Up>>);
779 if constexpr (__adl_partial<_Tp, _Up>)
780 return partial_ordering(partial_order(static_cast<_Tp&&>(__e),
781 static_cast<_Up&&>(__f)));
782 else if constexpr (__op_cmp<partial_ordering, _Tp, _Up>)
783 return static_cast<_Tp&&>(__e) <=> static_cast<_Up&&>(__f);
784 else if constexpr (__weakly_ordered<_Tp, _Up>)
785 return _Weak_order{}(static_cast<_Tp&&>(__e),
786 static_cast<_Up&&>(__f));
790 template<typename _Tp, typename _Up>
791 concept __op_eq_lt = requires(_Tp&& __t, _Up&& __u)
793 { static_cast<_Tp&&>(__t) == static_cast<_Up&&>(__u) }
794 -> convertible_to<bool>;
795 { static_cast<_Tp&&>(__t) < static_cast<_Up&&>(__u) }
796 -> convertible_to<bool>;
799 class _Strong_fallback
801 template<typename _Tp, typename _Up>
802 static constexpr bool
805 if constexpr (__strongly_ordered<_Tp, _Up>)
806 return _Strong_order::_S_noexcept<_Tp, _Up>();
808 return noexcept(bool(std::declval<_Tp>() == std::declval<_Up>()))
809 && noexcept(bool(std::declval<_Tp>() < std::declval<_Up>()));
813 template<typename _Tp, typename _Up>
814 requires __strongly_ordered<_Tp, _Up> || __op_eq_lt<_Tp, _Up>
815 constexpr decltype(auto)
816 operator()(_Tp&& __e, _Up&& __f) const
817 noexcept(_S_noexcept<_Tp, _Up>())
819 static_assert(same_as<decay_t<_Tp>, decay_t<_Up>>);
821 if constexpr (__strongly_ordered<_Tp, _Up>)
822 return _Strong_order{}(static_cast<_Tp&&>(__e),
823 static_cast<_Up&&>(__f));
824 else if constexpr (__op_eq_lt<_Tp, _Up>)
825 return static_cast<_Tp&&>(__e) == static_cast<_Up&&>(__f)
826 ? strong_ordering::equal
827 : static_cast<_Tp&&>(__e) < static_cast<_Up&&>(__f)
828 ? strong_ordering::less
829 : strong_ordering::greater;
835 template<typename _Tp, typename _Up>
836 static constexpr bool
839 if constexpr (__weakly_ordered<_Tp, _Up>)
840 return _Weak_order::_S_noexcept<_Tp, _Up>();
842 return noexcept(bool(std::declval<_Tp>() == std::declval<_Up>()))
843 && noexcept(bool(std::declval<_Tp>() < std::declval<_Up>()));
847 template<typename _Tp, typename _Up>
848 requires __weakly_ordered<_Tp, _Up> || __op_eq_lt<_Tp, _Up>
849 constexpr decltype(auto)
850 operator()(_Tp&& __e, _Up&& __f) const
851 noexcept(_S_noexcept<_Tp, _Up>())
853 static_assert(same_as<decay_t<_Tp>, decay_t<_Up>>);
855 if constexpr (__weakly_ordered<_Tp, _Up>)
856 return _Weak_order{}(static_cast<_Tp&&>(__e),
857 static_cast<_Up&&>(__f));
858 else if constexpr (__op_eq_lt<_Tp, _Up>)
859 return static_cast<_Tp&&>(__e) == static_cast<_Up&&>(__f)
860 ? weak_ordering::equivalent
861 : static_cast<_Tp&&>(__e) < static_cast<_Up&&>(__f)
862 ? weak_ordering::less
863 : weak_ordering::greater;
867 class _Partial_fallback
869 template<typename _Tp, typename _Up>
870 static constexpr bool
873 if constexpr (__partially_ordered<_Tp, _Up>)
874 return _Partial_order::_S_noexcept<_Tp, _Up>();
876 return noexcept(bool(std::declval<_Tp>() == std::declval<_Up>()))
877 && noexcept(bool(std::declval<_Tp>() < std::declval<_Up>()));
881 template<typename _Tp, typename _Up>
882 requires __partially_ordered<_Tp, _Up> || __op_eq_lt<_Tp, _Up>
883 constexpr decltype(auto)
884 operator()(_Tp&& __e, _Up&& __f) const
885 noexcept(_S_noexcept<_Tp, _Up>())
887 static_assert(same_as<decay_t<_Tp>, decay_t<_Up>>);
889 if constexpr (__partially_ordered<_Tp, _Up>)
890 return _Partial_order{}(static_cast<_Tp&&>(__e),
891 static_cast<_Up&&>(__f));
892 else if constexpr (__op_eq_lt<_Tp, _Up>)
893 return static_cast<_Tp&&>(__e) == static_cast<_Up&&>(__f)
894 ? partial_ordering::equivalent
895 : static_cast<_Tp&&>(__e) < static_cast<_Up&&>(__f)
896 ? partial_ordering::less
897 : static_cast<_Up&&>(__f) < static_cast<_Tp&&>(__e)
898 ? partial_ordering::greater
899 : partial_ordering::unordered;
902 } // namespace __cmp_cust
904 // [cmp.alg], comparison algorithms
905 inline namespace __cmp_alg
907 inline constexpr __cmp_cust::_Strong_order strong_order{};
909 inline constexpr __cmp_cust::_Weak_order weak_order{};
911 inline constexpr __cmp_cust::_Partial_order partial_order{};
913 inline constexpr __cmp_cust::_Strong_fallback
914 compare_strong_order_fallback{};
916 inline constexpr __cmp_cust::_Weak_fallback
917 compare_weak_order_fallback{};
919 inline constexpr __cmp_cust::_Partial_fallback
920 compare_partial_order_fallback{};
926 inline constexpr struct _Synth3way
928 template<typename _Tp, typename _Up>
930 operator()(const _Tp& __t, const _Up& __u) const
933 { __t < __u } -> convertible_to<bool>;
934 { __u < __t } -> convertible_to<bool>;
937 if constexpr (__3way_cmp_with<_Tp, _Up>)
942 return weak_ordering::less;
944 return weak_ordering::greater;
946 return weak_ordering::equivalent;
951 template<typename _Tp, typename _Up = _Tp>
953 = decltype(__detail::__synth3way(std::declval<_Tp&>(),
954 std::declval<_Up&>()));
955 } // namespace __detail
959 #pragma GCC visibility pop