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