LCOV - code coverage report
Current view: top level - 11 - compare (source / functions) Hit Total Coverage
Test: jami-coverage-filtered.info Lines: 34 34 100.0 %
Date: 2026-02-28 10:41:24 Functions: 18 22 81.8 %

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

Generated by: LCOV version 1.14