| // -*- C++ -*- operator<=> three-way comparison support. | 
 |  | 
 | // Copyright (C) 2019-2021 Free Software Foundation, Inc. | 
 | // | 
 | // This file is part of GCC. | 
 | // | 
 | // GCC is free software; you can redistribute it and/or modify | 
 | // it under the terms of the GNU General Public License as published by | 
 | // the Free Software Foundation; either version 3, or (at your option) | 
 | // any later version. | 
 | // | 
 | // GCC is distributed in the hope that it will be useful, | 
 | // but WITHOUT ANY WARRANTY; without even the implied warranty of | 
 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | 
 | // GNU General Public License for more details. | 
 | // | 
 | // Under Section 7 of GPL version 3, you are granted additional | 
 | // permissions described in the GCC Runtime Library Exception, version | 
 | // 3.1, as published by the Free Software Foundation. | 
 |  | 
 | // You should have received a copy of the GNU General Public License and | 
 | // a copy of the GCC Runtime Library Exception along with this program; | 
 | // see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see | 
 | // <http://www.gnu.org/licenses/>. | 
 |  | 
 | /** @file compare | 
 |  *  This is a Standard C++ Library header. | 
 |  */ | 
 |  | 
 | #ifndef _COMPARE | 
 | #define _COMPARE | 
 |  | 
 | #pragma GCC system_header | 
 |  | 
 | #if __cplusplus > 201703L && __cpp_impl_three_way_comparison >= 201907L | 
 |  | 
 | #pragma GCC visibility push(default) | 
 |  | 
 | #include <concepts> | 
 |  | 
 | #if __cpp_lib_concepts | 
 | # define __cpp_lib_three_way_comparison 201907L | 
 | #endif | 
 |  | 
 | namespace std | 
 | { | 
 |   // [cmp.categories], comparison category types | 
 |  | 
 |   namespace __cmp_cat | 
 |   { | 
 |     using type = signed char; | 
 |  | 
 |     enum class _Ord : type { equivalent = 0, less = -1, greater = 1 }; | 
 |  | 
 |     enum class _Ncmp : type { _Unordered = 2 }; | 
 |  | 
 |     struct __unspec | 
 |     { | 
 |       constexpr __unspec(__unspec*) noexcept { } | 
 |     }; | 
 |   } | 
 |  | 
 |   class partial_ordering | 
 |   { | 
 |     // less=0xff, equiv=0x00, greater=0x01, unordered=0x02 | 
 |     __cmp_cat::type _M_value; | 
 |  | 
 |     constexpr explicit | 
 |     partial_ordering(__cmp_cat::_Ord __v) noexcept | 
 |     : _M_value(__cmp_cat::type(__v)) | 
 |     { } | 
 |  | 
 |     constexpr explicit | 
 |     partial_ordering(__cmp_cat::_Ncmp __v) noexcept | 
 |     : _M_value(__cmp_cat::type(__v)) | 
 |     { } | 
 |  | 
 |     friend class weak_ordering; | 
 |     friend class strong_ordering; | 
 |  | 
 |   public: | 
 |     // valid values | 
 |     static const partial_ordering less; | 
 |     static const partial_ordering equivalent; | 
 |     static const partial_ordering greater; | 
 |     static const partial_ordering unordered; | 
 |  | 
 |     // comparisons | 
 |     [[nodiscard]] | 
 |     friend constexpr bool | 
 |     operator==(partial_ordering __v, __cmp_cat::__unspec) noexcept | 
 |     { return __v._M_value == 0; } | 
 |  | 
 |     [[nodiscard]] | 
 |     friend constexpr bool | 
 |     operator==(partial_ordering, partial_ordering) noexcept = default; | 
 |  | 
 |     [[nodiscard]] | 
 |     friend constexpr bool | 
 |     operator< (partial_ordering __v, __cmp_cat::__unspec) noexcept | 
 |     { return __v._M_value == -1; } | 
 |  | 
 |     [[nodiscard]] | 
 |     friend constexpr bool | 
 |     operator> (partial_ordering __v, __cmp_cat::__unspec) noexcept | 
 |     { return __v._M_value == 1; } | 
 |  | 
 |     [[nodiscard]] | 
 |     friend constexpr bool | 
 |     operator<=(partial_ordering __v, __cmp_cat::__unspec) noexcept | 
 |     { return __v._M_value <= 0; } | 
 |  | 
 |     [[nodiscard]] | 
 |     friend constexpr bool | 
 |     operator>=(partial_ordering __v, __cmp_cat::__unspec) noexcept | 
 |     { return __cmp_cat::type(__v._M_value & 1) == __v._M_value; } | 
 |  | 
 |     [[nodiscard]] | 
 |     friend constexpr bool | 
 |     operator< (__cmp_cat::__unspec, partial_ordering __v) noexcept | 
 |     { return __v._M_value == 1; } | 
 |  | 
 |     [[nodiscard]] | 
 |     friend constexpr bool | 
 |     operator> (__cmp_cat::__unspec, partial_ordering __v) noexcept | 
 |     { return __v._M_value == -1; } | 
 |  | 
 |     [[nodiscard]] | 
 |     friend constexpr bool | 
 |     operator<=(__cmp_cat::__unspec, partial_ordering __v) noexcept | 
 |     { return __cmp_cat::type(__v._M_value & 1) == __v._M_value; } | 
 |  | 
 |     [[nodiscard]] | 
 |     friend constexpr bool | 
 |     operator>=(__cmp_cat::__unspec, partial_ordering __v) noexcept | 
 |     { return 0 >= __v._M_value; } | 
 |  | 
 |     [[nodiscard]] | 
 |     friend constexpr partial_ordering | 
 |     operator<=>(partial_ordering __v, __cmp_cat::__unspec) noexcept | 
 |     { return __v; } | 
 |  | 
 |     [[nodiscard]] | 
 |     friend constexpr partial_ordering | 
 |     operator<=>(__cmp_cat::__unspec, partial_ordering __v) noexcept | 
 |     { | 
 |       if (__v._M_value & 1) | 
 | 	return partial_ordering(__cmp_cat::_Ord(-__v._M_value)); | 
 |       else | 
 | 	return __v; | 
 |     } | 
 |   }; | 
 |  | 
 |   // valid values' definitions | 
 |   inline constexpr partial_ordering | 
 |   partial_ordering::less(__cmp_cat::_Ord::less); | 
 |  | 
 |   inline constexpr partial_ordering | 
 |   partial_ordering::equivalent(__cmp_cat::_Ord::equivalent); | 
 |  | 
 |   inline constexpr partial_ordering | 
 |   partial_ordering::greater(__cmp_cat::_Ord::greater); | 
 |  | 
 |   inline constexpr partial_ordering | 
 |   partial_ordering::unordered(__cmp_cat::_Ncmp::_Unordered); | 
 |  | 
 |   class weak_ordering | 
 |   { | 
 |     __cmp_cat::type _M_value; | 
 |  | 
 |     constexpr explicit | 
 |     weak_ordering(__cmp_cat::_Ord __v) noexcept : _M_value(__cmp_cat::type(__v)) | 
 |     { } | 
 |  | 
 |     friend class strong_ordering; | 
 |  | 
 |   public: | 
 |     // valid values | 
 |     static const weak_ordering less; | 
 |     static const weak_ordering equivalent; | 
 |     static const weak_ordering greater; | 
 |  | 
 |     [[nodiscard]] | 
 |     constexpr operator partial_ordering() const noexcept | 
 |     { return partial_ordering(__cmp_cat::_Ord(_M_value)); } | 
 |  | 
 |     // comparisons | 
 |     [[nodiscard]] | 
 |     friend constexpr bool | 
 |     operator==(weak_ordering __v, __cmp_cat::__unspec) noexcept | 
 |     { return __v._M_value == 0; } | 
 |  | 
 |     [[nodiscard]] | 
 |     friend constexpr bool | 
 |     operator==(weak_ordering, weak_ordering) noexcept = default; | 
 |  | 
 |     [[nodiscard]] | 
 |     friend constexpr bool | 
 |     operator< (weak_ordering __v, __cmp_cat::__unspec) noexcept | 
 |     { return __v._M_value < 0; } | 
 |  | 
 |     [[nodiscard]] | 
 |     friend constexpr bool | 
 |     operator> (weak_ordering __v, __cmp_cat::__unspec) noexcept | 
 |     { return __v._M_value > 0; } | 
 |  | 
 |     [[nodiscard]] | 
 |     friend constexpr bool | 
 |     operator<=(weak_ordering __v, __cmp_cat::__unspec) noexcept | 
 |     { return __v._M_value <= 0; } | 
 |  | 
 |     [[nodiscard]] | 
 |     friend constexpr bool | 
 |     operator>=(weak_ordering __v, __cmp_cat::__unspec) noexcept | 
 |     { return __v._M_value >= 0; } | 
 |  | 
 |     [[nodiscard]] | 
 |     friend constexpr bool | 
 |     operator< (__cmp_cat::__unspec, weak_ordering __v) noexcept | 
 |     { return 0 < __v._M_value; } | 
 |  | 
 |     [[nodiscard]] | 
 |     friend constexpr bool | 
 |     operator> (__cmp_cat::__unspec, weak_ordering __v) noexcept | 
 |     { return 0 > __v._M_value; } | 
 |  | 
 |     [[nodiscard]] | 
 |     friend constexpr bool | 
 |     operator<=(__cmp_cat::__unspec, weak_ordering __v) noexcept | 
 |     { return 0 <= __v._M_value; } | 
 |  | 
 |     [[nodiscard]] | 
 |     friend constexpr bool | 
 |     operator>=(__cmp_cat::__unspec, weak_ordering __v) noexcept | 
 |     { return 0 >= __v._M_value; } | 
 |  | 
 |     [[nodiscard]] | 
 |     friend constexpr weak_ordering | 
 |     operator<=>(weak_ordering __v, __cmp_cat::__unspec) noexcept | 
 |     { return __v; } | 
 |  | 
 |     [[nodiscard]] | 
 |     friend constexpr weak_ordering | 
 |     operator<=>(__cmp_cat::__unspec, weak_ordering __v) noexcept | 
 |     { return weak_ordering(__cmp_cat::_Ord(-__v._M_value)); } | 
 |   }; | 
 |  | 
 |   // valid values' definitions | 
 |   inline constexpr weak_ordering | 
 |   weak_ordering::less(__cmp_cat::_Ord::less); | 
 |  | 
 |   inline constexpr weak_ordering | 
 |   weak_ordering::equivalent(__cmp_cat::_Ord::equivalent); | 
 |  | 
 |   inline constexpr weak_ordering | 
 |   weak_ordering::greater(__cmp_cat::_Ord::greater); | 
 |  | 
 |   class strong_ordering | 
 |   { | 
 |     __cmp_cat::type _M_value; | 
 |  | 
 |     constexpr explicit | 
 |     strong_ordering(__cmp_cat::_Ord __v) noexcept | 
 |     : _M_value(__cmp_cat::type(__v)) | 
 |     { } | 
 |  | 
 |   public: | 
 |     // valid values | 
 |     static const strong_ordering less; | 
 |     static const strong_ordering equal; | 
 |     static const strong_ordering equivalent; | 
 |     static const strong_ordering greater; | 
 |  | 
 |     [[nodiscard]] | 
 |     constexpr operator partial_ordering() const noexcept | 
 |     { return partial_ordering(__cmp_cat::_Ord(_M_value)); } | 
 |  | 
 |     [[nodiscard]] | 
 |     constexpr operator weak_ordering() const noexcept | 
 |     { return weak_ordering(__cmp_cat::_Ord(_M_value)); } | 
 |  | 
 |     // comparisons | 
 |     [[nodiscard]] | 
 |     friend constexpr bool | 
 |     operator==(strong_ordering __v, __cmp_cat::__unspec) noexcept | 
 |     { return __v._M_value == 0; } | 
 |  | 
 |     [[nodiscard]] | 
 |     friend constexpr bool | 
 |     operator==(strong_ordering, strong_ordering) noexcept = default; | 
 |  | 
 |     [[nodiscard]] | 
 |     friend constexpr bool | 
 |     operator< (strong_ordering __v, __cmp_cat::__unspec) noexcept | 
 |     { return __v._M_value < 0; } | 
 |  | 
 |     [[nodiscard]] | 
 |     friend constexpr bool | 
 |     operator> (strong_ordering __v, __cmp_cat::__unspec) noexcept | 
 |     { return __v._M_value > 0; } | 
 |  | 
 |     [[nodiscard]] | 
 |     friend constexpr bool | 
 |     operator<=(strong_ordering __v, __cmp_cat::__unspec) noexcept | 
 |     { return __v._M_value <= 0; } | 
 |  | 
 |     [[nodiscard]] | 
 |     friend constexpr bool | 
 |     operator>=(strong_ordering __v, __cmp_cat::__unspec) noexcept | 
 |     { return __v._M_value >= 0; } | 
 |  | 
 |     [[nodiscard]] | 
 |     friend constexpr bool | 
 |     operator< (__cmp_cat::__unspec, strong_ordering __v) noexcept | 
 |     { return 0 < __v._M_value; } | 
 |  | 
 |     [[nodiscard]] | 
 |     friend constexpr bool | 
 |     operator> (__cmp_cat::__unspec, strong_ordering __v) noexcept | 
 |     { return 0 > __v._M_value; } | 
 |  | 
 |     [[nodiscard]] | 
 |     friend constexpr bool | 
 |     operator<=(__cmp_cat::__unspec, strong_ordering __v) noexcept | 
 |     { return 0 <= __v._M_value; } | 
 |  | 
 |     [[nodiscard]] | 
 |     friend constexpr bool | 
 |     operator>=(__cmp_cat::__unspec, strong_ordering __v) noexcept | 
 |     { return 0 >= __v._M_value; } | 
 |  | 
 |     [[nodiscard]] | 
 |     friend constexpr strong_ordering | 
 |     operator<=>(strong_ordering __v, __cmp_cat::__unspec) noexcept | 
 |     { return __v; } | 
 |  | 
 |     [[nodiscard]] | 
 |     friend constexpr strong_ordering | 
 |     operator<=>(__cmp_cat::__unspec, strong_ordering __v) noexcept | 
 |     { return strong_ordering(__cmp_cat::_Ord(-__v._M_value)); } | 
 |   }; | 
 |  | 
 |   // valid values' definitions | 
 |   inline constexpr strong_ordering | 
 |   strong_ordering::less(__cmp_cat::_Ord::less); | 
 |  | 
 |   inline constexpr strong_ordering | 
 |   strong_ordering::equal(__cmp_cat::_Ord::equivalent); | 
 |  | 
 |   inline constexpr strong_ordering | 
 |   strong_ordering::equivalent(__cmp_cat::_Ord::equivalent); | 
 |  | 
 |   inline constexpr strong_ordering | 
 |   strong_ordering::greater(__cmp_cat::_Ord::greater); | 
 |  | 
 |  | 
 |   // named comparison functions | 
 |   [[nodiscard]] | 
 |   constexpr bool | 
 |   is_eq(partial_ordering __cmp) noexcept | 
 |   { return __cmp == 0; } | 
 |  | 
 |   [[nodiscard]] | 
 |   constexpr bool | 
 |   is_neq(partial_ordering __cmp) noexcept | 
 |   { return __cmp != 0; } | 
 |  | 
 |   [[nodiscard]] | 
 |   constexpr bool | 
 |   is_lt  (partial_ordering __cmp) noexcept | 
 |   { return __cmp < 0; } | 
 |  | 
 |   [[nodiscard]] | 
 |   constexpr bool | 
 |   is_lteq(partial_ordering __cmp) noexcept | 
 |   { return __cmp <= 0; } | 
 |  | 
 |   [[nodiscard]] | 
 |   constexpr bool | 
 |   is_gt  (partial_ordering __cmp) noexcept | 
 |   { return __cmp > 0; } | 
 |  | 
 |   [[nodiscard]] | 
 |   constexpr bool | 
 |   is_gteq(partial_ordering __cmp) noexcept | 
 |   { return __cmp >= 0; } | 
 |  | 
 |   namespace __detail | 
 |   { | 
 |     template<typename _Tp> | 
 |       inline constexpr unsigned __cmp_cat_id = 1; | 
 |     template<> | 
 |       inline constexpr unsigned __cmp_cat_id<partial_ordering> = 2; | 
 |     template<> | 
 |       inline constexpr unsigned __cmp_cat_id<weak_ordering> = 4; | 
 |     template<> | 
 |       inline constexpr unsigned __cmp_cat_id<strong_ordering> = 8; | 
 |  | 
 |     template<typename... _Ts> | 
 |       constexpr auto __common_cmp_cat() | 
 |       { | 
 | 	constexpr unsigned __cats = (__cmp_cat_id<_Ts> | ...); | 
 | 	// If any Ti is not a comparison category type, U is void. | 
 | 	if constexpr (__cats & 1) | 
 | 	  return; | 
 | 	// Otherwise, if at least one Ti is std::partial_ordering, | 
 | 	// U is std::partial_ordering. | 
 | 	else if constexpr (bool(__cats & __cmp_cat_id<partial_ordering>)) | 
 | 	  return partial_ordering::equivalent; | 
 | 	// Otherwise, if at least one Ti is std::weak_ordering, | 
 | 	// U is std::weak_ordering. | 
 | 	else if constexpr (bool(__cats & __cmp_cat_id<weak_ordering>)) | 
 | 	  return weak_ordering::equivalent; | 
 | 	// Otherwise, U is std::strong_ordering. | 
 | 	else | 
 | 	  return strong_ordering::equivalent; | 
 |       } | 
 |   } // namespace __detail | 
 |  | 
 |   // [cmp.common], common comparison category type | 
 |   template<typename... _Ts> | 
 |     struct common_comparison_category | 
 |     { | 
 |       using type = decltype(__detail::__common_cmp_cat<_Ts...>()); | 
 |     }; | 
 |  | 
 |   // Partial specializations for one and zero argument cases. | 
 |  | 
 |   template<typename _Tp> | 
 |     struct common_comparison_category<_Tp> | 
 |     { using type = void; }; | 
 |  | 
 |   template<> | 
 |     struct common_comparison_category<partial_ordering> | 
 |     { using type = partial_ordering; }; | 
 |  | 
 |   template<> | 
 |     struct common_comparison_category<weak_ordering> | 
 |     { using type = weak_ordering; }; | 
 |  | 
 |   template<> | 
 |     struct common_comparison_category<strong_ordering> | 
 |     { using type = strong_ordering; }; | 
 |  | 
 |   template<> | 
 |     struct common_comparison_category<> | 
 |     { using type = strong_ordering; }; | 
 |  | 
 |   template<typename... _Ts> | 
 |     using common_comparison_category_t | 
 |       = typename common_comparison_category<_Ts...>::type; | 
 |  | 
 | #if __cpp_lib_concepts | 
 |   namespace __detail | 
 |   { | 
 |     template<typename _Tp, typename _Cat> | 
 |       concept __compares_as | 
 | 	= same_as<common_comparison_category_t<_Tp, _Cat>, _Cat>; | 
 |   } // namespace __detail | 
 |  | 
 |   // [cmp.concept], concept three_way_comparable | 
 |   template<typename _Tp, typename _Cat = partial_ordering> | 
 |     concept three_way_comparable | 
 |       = __detail::__weakly_eq_cmp_with<_Tp, _Tp> | 
 |       && __detail::__partially_ordered_with<_Tp, _Tp> | 
 |       && requires(const remove_reference_t<_Tp>& __a, | 
 | 		  const remove_reference_t<_Tp>& __b) | 
 |       { | 
 | 	{ __a <=> __b } -> __detail::__compares_as<_Cat>; | 
 |       }; | 
 |  | 
 |   template<typename _Tp, typename _Up, typename _Cat = partial_ordering> | 
 |     concept three_way_comparable_with | 
 |       = three_way_comparable<_Tp, _Cat> | 
 |       && three_way_comparable<_Up, _Cat> | 
 |       && common_reference_with<const remove_reference_t<_Tp>&, | 
 | 			       const remove_reference_t<_Up>&> | 
 |       && three_way_comparable< | 
 | 	  common_reference_t<const remove_reference_t<_Tp>&, | 
 | 			     const remove_reference_t<_Up>&>, _Cat> | 
 |       && __detail::__weakly_eq_cmp_with<_Tp, _Up> | 
 |       && __detail::__partially_ordered_with<_Tp, _Up> | 
 |       && requires(const remove_reference_t<_Tp>& __t, | 
 | 		  const remove_reference_t<_Up>& __u) | 
 |       { | 
 | 	{ __t <=> __u } -> __detail::__compares_as<_Cat>; | 
 | 	{ __u <=> __t } -> __detail::__compares_as<_Cat>; | 
 |       }; | 
 |  | 
 |   namespace __detail | 
 |   { | 
 |     template<typename _Tp, typename _Up> | 
 |       using __cmp3way_res_t | 
 | 	= decltype(std::declval<_Tp>() <=> std::declval<_Up>()); | 
 |  | 
 |     // Implementation of std::compare_three_way_result. | 
 |     // It is undefined for a program to add specializations of | 
 |     // std::compare_three_way_result, so the std::compare_three_way_result_t | 
 |     // alias ignores std::compare_three_way_result and uses | 
 |     // __detail::__cmp3way_res_impl directly instead. | 
 |     template<typename _Tp, typename _Up> | 
 |       struct __cmp3way_res_impl | 
 |       { }; | 
 |  | 
 |     template<typename _Tp, typename _Up> | 
 |       requires requires { typename __cmp3way_res_t<__cref<_Tp>, __cref<_Up>>; } | 
 |       struct __cmp3way_res_impl<_Tp, _Up> | 
 |       { | 
 | 	using type = __cmp3way_res_t<__cref<_Tp>, __cref<_Up>>; | 
 |       }; | 
 |   } // namespace __detail | 
 |  | 
 |   /// [cmp.result], result of three-way comparison | 
 |   template<typename _Tp, typename _Up = _Tp> | 
 |     struct compare_three_way_result | 
 |     : __detail::__cmp3way_res_impl<_Tp, _Up> | 
 |     { }; | 
 |  | 
 |   /// [cmp.result], result of three-way comparison | 
 |   template<typename _Tp, typename _Up = _Tp> | 
 |     using compare_three_way_result_t | 
 |       = typename __detail::__cmp3way_res_impl<_Tp, _Up>::type; | 
 |  | 
 |   namespace __detail | 
 |   { | 
 |     // BUILTIN-PTR-THREE-WAY(T, U) | 
 |     // This determines whether t <=> u results in a call to a built-in | 
 |     // operator<=> comparing pointers. It doesn't work for function pointers | 
 |     // (PR 93628). | 
 |     template<typename _Tp, typename _Up> | 
 |       concept __3way_builtin_ptr_cmp | 
 | 	= requires(_Tp&& __t, _Up&& __u) | 
 | 	  { static_cast<_Tp&&>(__t) <=> static_cast<_Up&&>(__u); } | 
 | 	  && convertible_to<_Tp, const volatile void*> | 
 | 	  && convertible_to<_Up, const volatile void*> | 
 | 	  && ! requires(_Tp&& __t, _Up&& __u) | 
 | 	  { operator<=>(static_cast<_Tp&&>(__t), static_cast<_Up&&>(__u)); } | 
 | 	  && ! requires(_Tp&& __t, _Up&& __u) | 
 | 	  { static_cast<_Tp&&>(__t).operator<=>(static_cast<_Up&&>(__u)); }; | 
 |   } // namespace __detail | 
 |  | 
 |   // _GLIBCXX_RESOLVE_LIB_DEFECTS | 
 |   // 3530 BUILTIN-PTR-MEOW should not opt the type out of syntactic checks | 
 |  | 
 |   // [cmp.object], typename compare_three_way | 
 |   struct compare_three_way | 
 |   { | 
 |     template<typename _Tp, typename _Up> | 
 |       requires three_way_comparable_with<_Tp, _Up> | 
 |       constexpr auto | 
 |       operator() [[nodiscard]] (_Tp&& __t, _Up&& __u) const | 
 |       noexcept(noexcept(std::declval<_Tp>() <=> std::declval<_Up>())) | 
 |       { | 
 | 	if constexpr (__detail::__3way_builtin_ptr_cmp<_Tp, _Up>) | 
 | 	  { | 
 | 	    auto __pt = static_cast<const volatile void*>(__t); | 
 | 	    auto __pu = static_cast<const volatile void*>(__u); | 
 | 	    if (__builtin_is_constant_evaluated()) | 
 | 	      return __pt <=> __pu; | 
 | 	    auto __it = reinterpret_cast<__UINTPTR_TYPE__>(__pt); | 
 | 	    auto __iu = reinterpret_cast<__UINTPTR_TYPE__>(__pu); | 
 | 	    return __it <=> __iu; | 
 | 	  } | 
 | 	else | 
 | 	  return static_cast<_Tp&&>(__t) <=> static_cast<_Up&&>(__u); | 
 |       } | 
 |  | 
 |     using is_transparent = void; | 
 |   }; | 
 |  | 
 |   namespace __cmp_cust | 
 |   { | 
 |     template<floating_point _Tp> | 
 |       constexpr weak_ordering | 
 |       __fp_weak_ordering(_Tp __e, _Tp __f) | 
 |       { | 
 | 	// Returns an integer with the same sign as the argument, and magnitude | 
 | 	// indicating the classification: zero=1 subnorm=2 norm=3 inf=4 nan=5 | 
 | 	auto __cat = [](_Tp __fp) -> int { | 
 | 	  const int __sign = __builtin_signbit(__fp) ? -1 : 1; | 
 | 	  if (__builtin_isnormal(__fp)) | 
 | 	    return (__fp == 0 ? 1 : 3) * __sign; | 
 | 	  if (__builtin_isnan(__fp)) | 
 | 	    return 5 * __sign; | 
 | 	  if (int __inf = __builtin_isinf_sign(__fp)) | 
 | 	    return 4 * __inf; | 
 | 	  return 2 * __sign; | 
 | 	}; | 
 |  | 
 | 	auto __po = __e <=> __f; | 
 | 	if (is_lt(__po)) | 
 | 	  return weak_ordering::less; | 
 | 	else if (is_gt(__po)) | 
 | 	  return weak_ordering::greater; | 
 | 	else if (__po == partial_ordering::equivalent) | 
 | 	  return weak_ordering::equivalent; | 
 | 	else  // unordered, at least one argument is NaN | 
 | 	  { | 
 | 	    // return -1 for negative nan, +1 for positive nan, 0 otherwise. | 
 | 	    auto __isnan_sign = [](_Tp __fp) -> int { | 
 | 	      return __builtin_isnan(__fp) | 
 | 		? __builtin_signbit(__fp) ? -1 : 1 | 
 | 		: 0; | 
 | 	    }; | 
 | 	    auto __ord = __isnan_sign(__e) <=> __isnan_sign(__f); | 
 | 	    if (is_eq(__ord)) | 
 | 	      return weak_ordering::equivalent; | 
 | 	    else if (is_lt(__ord)) | 
 | 	      return weak_ordering::less; | 
 | 	    else | 
 | 	      return weak_ordering::greater; | 
 | 	  } | 
 |       } | 
 |  | 
 |     template<typename _Tp, typename _Up> | 
 |       concept __adl_strong = requires(_Tp&& __t, _Up&& __u) | 
 | 	{ | 
 | 	  strong_ordering(strong_order(static_cast<_Tp&&>(__t), | 
 | 				       static_cast<_Up&&>(__u))); | 
 | 	}; | 
 |  | 
 |     template<typename _Tp, typename _Up> | 
 |       concept __adl_weak = requires(_Tp&& __t, _Up&& __u) | 
 | 	{ | 
 | 	  weak_ordering(weak_order(static_cast<_Tp&&>(__t), | 
 | 				   static_cast<_Up&&>(__u))); | 
 | 	}; | 
 |  | 
 |     template<typename _Tp, typename _Up> | 
 |       concept __adl_partial = requires(_Tp&& __t, _Up&& __u) | 
 | 	{ | 
 | 	  partial_ordering(partial_order(static_cast<_Tp&&>(__t), | 
 | 					 static_cast<_Up&&>(__u))); | 
 | 	}; | 
 |  | 
 |     template<typename _Ord, typename _Tp, typename _Up> | 
 |       concept __cmp3way = requires(_Tp&& __t, _Up&& __u, compare_three_way __c) | 
 | 	{ | 
 | 	  _Ord(__c(static_cast<_Tp&&>(__t), static_cast<_Up&&>(__u))); | 
 | 	}; | 
 |  | 
 |     template<typename _Tp, typename _Up> | 
 |       concept __strongly_ordered | 
 | 	= __adl_strong<_Tp, _Up> | 
 | 	  // FIXME: || floating_point<remove_reference_t<_Tp>> | 
 | 	  || __cmp3way<strong_ordering, _Tp, _Up>; | 
 |  | 
 |     template<typename _Tp, typename _Up> | 
 |       concept __decayed_same_as = same_as<decay_t<_Tp>, decay_t<_Up>>; | 
 |  | 
 |     class _Strong_order | 
 |     { | 
 |       template<typename _Tp, typename _Up> | 
 | 	static constexpr bool | 
 | 	_S_noexcept() | 
 | 	{ | 
 | 	  if constexpr (floating_point<decay_t<_Tp>>) | 
 | 	    return true; | 
 | 	  else if constexpr (__adl_strong<_Tp, _Up>) | 
 | 	    return noexcept(strong_ordering(strong_order(std::declval<_Tp>(), | 
 | 							 std::declval<_Up>()))); | 
 | 	  else if constexpr (__cmp3way<strong_ordering, _Tp, _Up>) | 
 | 	    return noexcept(compare_three_way()(std::declval<_Tp>(), | 
 | 						std::declval<_Up>())); | 
 | 	} | 
 |  | 
 |       friend class _Weak_order; | 
 |       friend class _Strong_fallback; | 
 |  | 
 |     public: | 
 |       template<typename _Tp, __decayed_same_as<_Tp> _Up> | 
 | 	requires __strongly_ordered<_Tp, _Up> | 
 | 	constexpr strong_ordering | 
 | 	operator() [[nodiscard]] (_Tp&& __e, _Up&& __f) const | 
 | 	noexcept(_S_noexcept<_Tp, _Up>()) | 
 | 	{ | 
 | 	  /* FIXME: | 
 | 	  if constexpr (floating_point<decay_t<_Tp>>) | 
 | 	    return __cmp_cust::__fp_strong_order(__e, __f); | 
 | 	  else */ if constexpr (__adl_strong<_Tp, _Up>) | 
 | 	    return strong_ordering(strong_order(static_cast<_Tp&&>(__e), | 
 | 						static_cast<_Up&&>(__f))); | 
 | 	  else if constexpr (__cmp3way<strong_ordering, _Tp, _Up>) | 
 | 	    return compare_three_way()(static_cast<_Tp&&>(__e), | 
 | 				       static_cast<_Up&&>(__f)); | 
 | 	} | 
 |     }; | 
 |  | 
 |     template<typename _Tp, typename _Up> | 
 |       concept __weakly_ordered | 
 | 	= floating_point<remove_reference_t<_Tp>> | 
 | 	  || __adl_weak<_Tp, _Up> | 
 | 	  || __cmp3way<weak_ordering, _Tp, _Up> | 
 | 	  || __strongly_ordered<_Tp, _Up>; | 
 |  | 
 |     class _Weak_order | 
 |     { | 
 |       template<typename _Tp, typename _Up> | 
 | 	static constexpr bool | 
 | 	_S_noexcept() | 
 | 	{ | 
 | 	  if constexpr (floating_point<decay_t<_Tp>>) | 
 | 	    return true; | 
 | 	  else if constexpr (__adl_weak<_Tp, _Up>) | 
 | 	    return noexcept(weak_ordering(weak_order(std::declval<_Tp>(), | 
 | 						     std::declval<_Up>()))); | 
 | 	  else if constexpr (__cmp3way<weak_ordering, _Tp, _Up>) | 
 | 	    return noexcept(compare_three_way()(std::declval<_Tp>(), | 
 | 						std::declval<_Up>())); | 
 | 	  else if constexpr (__strongly_ordered<_Tp, _Up>) | 
 | 	    return _Strong_order::_S_noexcept<_Tp, _Up>(); | 
 | 	} | 
 |  | 
 |       friend class _Partial_order; | 
 |       friend class _Weak_fallback; | 
 |  | 
 |     public: | 
 |       template<typename _Tp, __decayed_same_as<_Tp> _Up> | 
 | 	requires __weakly_ordered<_Tp, _Up> | 
 | 	constexpr weak_ordering | 
 | 	operator() [[nodiscard]] (_Tp&& __e, _Up&& __f) const | 
 | 	noexcept(_S_noexcept<_Tp, _Up>()) | 
 | 	{ | 
 | 	  if constexpr (floating_point<decay_t<_Tp>>) | 
 | 	    return __cmp_cust::__fp_weak_ordering(__e, __f); | 
 | 	  else if constexpr (__adl_weak<_Tp, _Up>) | 
 | 	    return weak_ordering(weak_order(static_cast<_Tp&&>(__e), | 
 | 					    static_cast<_Up&&>(__f))); | 
 | 	  else if constexpr (__cmp3way<weak_ordering, _Tp, _Up>) | 
 | 	    return compare_three_way()(static_cast<_Tp&&>(__e), | 
 | 				       static_cast<_Up&&>(__f)); | 
 | 	  else if constexpr (__strongly_ordered<_Tp, _Up>) | 
 | 	    return _Strong_order{}(static_cast<_Tp&&>(__e), | 
 | 				   static_cast<_Up&&>(__f)); | 
 | 	} | 
 |     }; | 
 |  | 
 |     template<typename _Tp, typename _Up> | 
 |       concept __partially_ordered | 
 | 	= __adl_partial<_Tp, _Up> | 
 | 	|| __cmp3way<partial_ordering, _Tp, _Up> | 
 | 	|| __weakly_ordered<_Tp, _Up>; | 
 |  | 
 |     class _Partial_order | 
 |     { | 
 |       template<typename _Tp, typename _Up> | 
 | 	static constexpr bool | 
 | 	_S_noexcept() | 
 | 	{ | 
 | 	  if constexpr (__adl_partial<_Tp, _Up>) | 
 | 	    return noexcept(partial_ordering(partial_order(std::declval<_Tp>(), | 
 | 							 std::declval<_Up>()))); | 
 | 	  else if constexpr (__cmp3way<partial_ordering, _Tp, _Up>) | 
 | 	    return noexcept(compare_three_way()(std::declval<_Tp>(), | 
 | 						std::declval<_Up>())); | 
 | 	  else if constexpr (__weakly_ordered<_Tp, _Up>) | 
 | 	    return _Weak_order::_S_noexcept<_Tp, _Up>(); | 
 | 	} | 
 |  | 
 |       friend class _Partial_fallback; | 
 |  | 
 |     public: | 
 |       template<typename _Tp, __decayed_same_as<_Tp> _Up> | 
 | 	requires __partially_ordered<_Tp, _Up> | 
 | 	constexpr partial_ordering | 
 | 	operator() [[nodiscard]] (_Tp&& __e, _Up&& __f) const | 
 | 	noexcept(_S_noexcept<_Tp, _Up>()) | 
 | 	{ | 
 | 	  if constexpr (__adl_partial<_Tp, _Up>) | 
 | 	    return partial_ordering(partial_order(static_cast<_Tp&&>(__e), | 
 | 						  static_cast<_Up&&>(__f))); | 
 | 	  else if constexpr (__cmp3way<partial_ordering, _Tp, _Up>) | 
 | 	    return compare_three_way()(static_cast<_Tp&&>(__e), | 
 | 				       static_cast<_Up&&>(__f)); | 
 | 	  else if constexpr (__weakly_ordered<_Tp, _Up>) | 
 | 	    return _Weak_order{}(static_cast<_Tp&&>(__e), | 
 | 				 static_cast<_Up&&>(__f)); | 
 | 	} | 
 |     }; | 
 |  | 
 |     template<typename _Tp, typename _Up> | 
 |       concept __op_eq_lt = requires(_Tp&& __t, _Up&& __u) | 
 | 	{ | 
 | 	  { static_cast<_Tp&&>(__t) == static_cast<_Up&&>(__u) } | 
 | 	    -> convertible_to<bool>; | 
 | 	  { static_cast<_Tp&&>(__t) < static_cast<_Up&&>(__u) } | 
 | 	    -> convertible_to<bool>; | 
 | 	}; | 
 |  | 
 |     class _Strong_fallback | 
 |     { | 
 |       template<typename _Tp, typename _Up> | 
 | 	static constexpr bool | 
 | 	_S_noexcept() | 
 | 	{ | 
 | 	  if constexpr (__strongly_ordered<_Tp, _Up>) | 
 | 	    return _Strong_order::_S_noexcept<_Tp, _Up>(); | 
 | 	  else | 
 | 	    return noexcept(bool(std::declval<_Tp>() == std::declval<_Up>())) | 
 | 	      && noexcept(bool(std::declval<_Tp>() < std::declval<_Up>())); | 
 | 	} | 
 |  | 
 |     public: | 
 |       template<typename _Tp, __decayed_same_as<_Tp> _Up> | 
 | 	requires __strongly_ordered<_Tp, _Up> || __op_eq_lt<_Tp, _Up> | 
 | 	constexpr strong_ordering | 
 | 	operator() [[nodiscard]] (_Tp&& __e, _Up&& __f) const | 
 | 	noexcept(_S_noexcept<_Tp, _Up>()) | 
 | 	{ | 
 | 	  if constexpr (__strongly_ordered<_Tp, _Up>) | 
 | 	    return _Strong_order{}(static_cast<_Tp&&>(__e), | 
 | 				   static_cast<_Up&&>(__f)); | 
 | 	  else // __op_eq_lt<_Tp, _Up> | 
 | 	    return static_cast<_Tp&&>(__e) == static_cast<_Up&&>(__f) | 
 | 	      ? strong_ordering::equal | 
 | 	      : static_cast<_Tp&&>(__e) < static_cast<_Up&&>(__f) | 
 | 	      ? strong_ordering::less | 
 | 	      : strong_ordering::greater; | 
 | 	} | 
 |     }; | 
 |  | 
 |     class _Weak_fallback | 
 |     { | 
 |       template<typename _Tp, typename _Up> | 
 | 	static constexpr bool | 
 | 	_S_noexcept() | 
 | 	{ | 
 | 	  if constexpr (__weakly_ordered<_Tp, _Up>) | 
 | 	    return _Weak_order::_S_noexcept<_Tp, _Up>(); | 
 | 	  else | 
 | 	    return noexcept(bool(std::declval<_Tp>() == std::declval<_Up>())) | 
 | 	      && noexcept(bool(std::declval<_Tp>() < std::declval<_Up>())); | 
 | 	} | 
 |  | 
 |     public: | 
 |       template<typename _Tp, __decayed_same_as<_Tp> _Up> | 
 | 	requires __weakly_ordered<_Tp, _Up> || __op_eq_lt<_Tp, _Up> | 
 | 	constexpr weak_ordering | 
 | 	operator() [[nodiscard]] (_Tp&& __e, _Up&& __f) const | 
 | 	noexcept(_S_noexcept<_Tp, _Up>()) | 
 | 	{ | 
 | 	  if constexpr (__weakly_ordered<_Tp, _Up>) | 
 | 	    return _Weak_order{}(static_cast<_Tp&&>(__e), | 
 | 				 static_cast<_Up&&>(__f)); | 
 | 	  else // __op_eq_lt<_Tp, _Up> | 
 | 	    return static_cast<_Tp&&>(__e) == static_cast<_Up&&>(__f) | 
 | 	      ? weak_ordering::equivalent | 
 | 	      : static_cast<_Tp&&>(__e) < static_cast<_Up&&>(__f) | 
 | 	      ? weak_ordering::less | 
 | 	      : weak_ordering::greater; | 
 | 	} | 
 |     }; | 
 |  | 
 |     // _GLIBCXX_RESOLVE_LIB_DEFECTS | 
 |     // 3465. compare_partial_order_fallback requires F < E | 
 |     template<typename _Tp, typename _Up> | 
 |       concept __op_eq_lt_lt = __op_eq_lt<_Tp, _Up> | 
 | 	&& requires(_Tp&& __t, _Up&& __u) | 
 | 	{ | 
 | 	  { static_cast<_Up&&>(__u) < static_cast<_Tp&&>(__t) } | 
 | 	    -> convertible_to<bool>; | 
 | 	}; | 
 |  | 
 |     class _Partial_fallback | 
 |     { | 
 |       template<typename _Tp, typename _Up> | 
 | 	static constexpr bool | 
 | 	_S_noexcept() | 
 | 	{ | 
 | 	  if constexpr (__partially_ordered<_Tp, _Up>) | 
 | 	    return _Partial_order::_S_noexcept<_Tp, _Up>(); | 
 | 	  else | 
 | 	    return noexcept(bool(std::declval<_Tp>() == std::declval<_Up>())) | 
 | 	      && noexcept(bool(std::declval<_Tp>() < std::declval<_Up>())); | 
 | 	} | 
 |  | 
 |     public: | 
 |       template<typename _Tp, __decayed_same_as<_Tp> _Up> | 
 | 	requires __partially_ordered<_Tp, _Up> || __op_eq_lt_lt<_Tp, _Up> | 
 | 	constexpr partial_ordering | 
 | 	operator() [[nodiscard]] (_Tp&& __e, _Up&& __f) const | 
 | 	noexcept(_S_noexcept<_Tp, _Up>()) | 
 | 	{ | 
 | 	  if constexpr (__partially_ordered<_Tp, _Up>) | 
 | 	    return _Partial_order{}(static_cast<_Tp&&>(__e), | 
 | 				    static_cast<_Up&&>(__f)); | 
 | 	  else // __op_eq_lt_lt<_Tp, _Up> | 
 | 	    return static_cast<_Tp&&>(__e) == static_cast<_Up&&>(__f) | 
 | 	      ? partial_ordering::equivalent | 
 | 	      : static_cast<_Tp&&>(__e) < static_cast<_Up&&>(__f) | 
 | 	      ? partial_ordering::less | 
 | 	      : static_cast<_Up&&>(__f) < static_cast<_Tp&&>(__e) | 
 | 	      ? partial_ordering::greater | 
 | 	      : partial_ordering::unordered; | 
 | 	} | 
 |     }; | 
 |   } // namespace __cmp_cust | 
 |  | 
 |   // [cmp.alg], comparison algorithms | 
 |   inline namespace __cmp_alg | 
 |   { | 
 |     inline constexpr __cmp_cust::_Strong_order strong_order{}; | 
 |  | 
 |     inline constexpr __cmp_cust::_Weak_order weak_order{}; | 
 |  | 
 |     inline constexpr __cmp_cust::_Partial_order partial_order{}; | 
 |  | 
 |     inline constexpr __cmp_cust::_Strong_fallback | 
 |     compare_strong_order_fallback{}; | 
 |  | 
 |     inline constexpr __cmp_cust::_Weak_fallback | 
 |     compare_weak_order_fallback{}; | 
 |  | 
 |     inline constexpr __cmp_cust::_Partial_fallback | 
 |     compare_partial_order_fallback{}; | 
 |   } | 
 |  | 
 |   namespace __detail | 
 |   { | 
 |     // [expos.only.func] synth-three-way | 
 |     inline constexpr struct _Synth3way | 
 |     { | 
 |       template<typename _Tp, typename _Up> | 
 | 	static constexpr bool | 
 | 	_S_noexcept(const _Tp* __t = nullptr, const _Up* __u = nullptr) | 
 | 	{ | 
 | 	  if constexpr (three_way_comparable_with<_Tp, _Up>) | 
 | 	    return noexcept(*__t <=> *__u); | 
 | 	  else | 
 | 	    return noexcept(*__t < *__u) && noexcept(*__u < *__t); | 
 | 	} | 
 |  | 
 |       template<typename _Tp, typename _Up> | 
 | 	[[nodiscard]] | 
 | 	constexpr auto | 
 | 	operator()(const _Tp& __t, const _Up& __u) const | 
 | 	noexcept(_S_noexcept<_Tp, _Up>()) | 
 | 	requires requires | 
 | 	{ | 
 | 	  { __t < __u } -> __boolean_testable; | 
 | 	  { __u < __t } -> __boolean_testable; | 
 | 	} | 
 | 	{ | 
 | 	  if constexpr (three_way_comparable_with<_Tp, _Up>) | 
 | 	    return __t <=> __u; | 
 | 	  else | 
 | 	    { | 
 | 	      if (__t < __u) | 
 | 		return weak_ordering::less; | 
 | 	      else if (__u < __t) | 
 | 		return weak_ordering::greater; | 
 | 	      else | 
 | 		return weak_ordering::equivalent; | 
 | 	    } | 
 | 	} | 
 |     } __synth3way = {}; | 
 |  | 
 |     // [expos.only.func] synth-three-way-result | 
 |     template<typename _Tp, typename _Up = _Tp> | 
 |       using __synth3way_t | 
 | 	= decltype(__detail::__synth3way(std::declval<_Tp&>(), | 
 | 					 std::declval<_Up&>())); | 
 |   } // namespace __detail | 
 | #endif // concepts | 
 | } // namespace std | 
 |  | 
 | #pragma GCC visibility pop | 
 |  | 
 | #endif // C++20 | 
 |  | 
 | #endif // _COMPARE |