1fb8a8121Smrg// -*- C++ -*- operator<=> three-way comparison support. 2fb8a8121Smrg 3*b1e83836Smrg// Copyright (C) 2019-2022 Free Software Foundation, Inc. 4fb8a8121Smrg// 5fb8a8121Smrg// This file is part of GCC. 6fb8a8121Smrg// 7fb8a8121Smrg// GCC is free software; you can redistribute it and/or modify 8fb8a8121Smrg// it under the terms of the GNU General Public License as published by 9fb8a8121Smrg// the Free Software Foundation; either version 3, or (at your option) 10fb8a8121Smrg// any later version. 11fb8a8121Smrg// 12fb8a8121Smrg// GCC is distributed in the hope that it will be useful, 13fb8a8121Smrg// but WITHOUT ANY WARRANTY; without even the implied warranty of 14fb8a8121Smrg// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15fb8a8121Smrg// GNU General Public License for more details. 16fb8a8121Smrg// 17fb8a8121Smrg// Under Section 7 of GPL version 3, you are granted additional 18fb8a8121Smrg// permissions described in the GCC Runtime Library Exception, version 19fb8a8121Smrg// 3.1, as published by the Free Software Foundation. 20fb8a8121Smrg 21fb8a8121Smrg// You should have received a copy of the GNU General Public License and 22fb8a8121Smrg// a copy of the GCC Runtime Library Exception along with this program; 23fb8a8121Smrg// see the files COPYING3 and COPYING.RUNTIME respectively. If not, see 24fb8a8121Smrg// <http://www.gnu.org/licenses/>. 25fb8a8121Smrg 26fb8a8121Smrg/** @file compare 27fb8a8121Smrg * This is a Standard C++ Library header. 28fb8a8121Smrg */ 29fb8a8121Smrg 30fb8a8121Smrg#ifndef _COMPARE 31fb8a8121Smrg#define _COMPARE 32fb8a8121Smrg 33fb8a8121Smrg#pragma GCC system_header 34fb8a8121Smrg 35fb8a8121Smrg#if __cplusplus > 201703L && __cpp_impl_three_way_comparison >= 201907L 36fb8a8121Smrg 37fb8a8121Smrg#pragma GCC visibility push(default) 38fb8a8121Smrg 39fb8a8121Smrg#include <concepts> 40fb8a8121Smrg 41fb8a8121Smrg#if __cpp_lib_concepts 42fb8a8121Smrg# define __cpp_lib_three_way_comparison 201907L 43fb8a8121Smrg#endif 44fb8a8121Smrg 45fb8a8121Smrgnamespace std 46fb8a8121Smrg{ 47fb8a8121Smrg // [cmp.categories], comparison category types 48fb8a8121Smrg 49fb8a8121Smrg namespace __cmp_cat 50fb8a8121Smrg { 51fb8a8121Smrg using type = signed char; 52fb8a8121Smrg 53fb8a8121Smrg enum class _Ord : type { equivalent = 0, less = -1, greater = 1 }; 54fb8a8121Smrg 55fb8a8121Smrg enum class _Ncmp : type { _Unordered = 2 }; 56fb8a8121Smrg 57fb8a8121Smrg struct __unspec 58fb8a8121Smrg { 59fb8a8121Smrg constexpr __unspec(__unspec*) noexcept { } 60fb8a8121Smrg }; 61fb8a8121Smrg } 62fb8a8121Smrg 63fb8a8121Smrg class partial_ordering 64fb8a8121Smrg { 65fb8a8121Smrg // less=0xff, equiv=0x00, greater=0x01, unordered=0x02 66fb8a8121Smrg __cmp_cat::type _M_value; 67fb8a8121Smrg 68fb8a8121Smrg constexpr explicit 69fb8a8121Smrg partial_ordering(__cmp_cat::_Ord __v) noexcept 70fb8a8121Smrg : _M_value(__cmp_cat::type(__v)) 71fb8a8121Smrg { } 72fb8a8121Smrg 73fb8a8121Smrg constexpr explicit 74fb8a8121Smrg partial_ordering(__cmp_cat::_Ncmp __v) noexcept 75fb8a8121Smrg : _M_value(__cmp_cat::type(__v)) 76fb8a8121Smrg { } 77fb8a8121Smrg 78fb8a8121Smrg friend class weak_ordering; 79fb8a8121Smrg friend class strong_ordering; 80fb8a8121Smrg 81fb8a8121Smrg public: 82fb8a8121Smrg // valid values 83fb8a8121Smrg static const partial_ordering less; 84fb8a8121Smrg static const partial_ordering equivalent; 85fb8a8121Smrg static const partial_ordering greater; 86fb8a8121Smrg static const partial_ordering unordered; 87fb8a8121Smrg 88fb8a8121Smrg // comparisons 89*b1e83836Smrg [[nodiscard]] 90fb8a8121Smrg friend constexpr bool 91fb8a8121Smrg operator==(partial_ordering __v, __cmp_cat::__unspec) noexcept 92fb8a8121Smrg { return __v._M_value == 0; } 93fb8a8121Smrg 94*b1e83836Smrg [[nodiscard]] 95fb8a8121Smrg friend constexpr bool 96fb8a8121Smrg operator==(partial_ordering, partial_ordering) noexcept = default; 97fb8a8121Smrg 98*b1e83836Smrg [[nodiscard]] 99fb8a8121Smrg friend constexpr bool 100fb8a8121Smrg operator< (partial_ordering __v, __cmp_cat::__unspec) noexcept 101fb8a8121Smrg { return __v._M_value == -1; } 102fb8a8121Smrg 103*b1e83836Smrg [[nodiscard]] 104fb8a8121Smrg friend constexpr bool 105fb8a8121Smrg operator> (partial_ordering __v, __cmp_cat::__unspec) noexcept 106fb8a8121Smrg { return __v._M_value == 1; } 107fb8a8121Smrg 108*b1e83836Smrg [[nodiscard]] 109fb8a8121Smrg friend constexpr bool 110fb8a8121Smrg operator<=(partial_ordering __v, __cmp_cat::__unspec) noexcept 111fb8a8121Smrg { return __v._M_value <= 0; } 112fb8a8121Smrg 113*b1e83836Smrg [[nodiscard]] 114fb8a8121Smrg friend constexpr bool 115fb8a8121Smrg operator>=(partial_ordering __v, __cmp_cat::__unspec) noexcept 116fb8a8121Smrg { return __cmp_cat::type(__v._M_value & 1) == __v._M_value; } 117fb8a8121Smrg 118*b1e83836Smrg [[nodiscard]] 119fb8a8121Smrg friend constexpr bool 120fb8a8121Smrg operator< (__cmp_cat::__unspec, partial_ordering __v) noexcept 121fb8a8121Smrg { return __v._M_value == 1; } 122fb8a8121Smrg 123*b1e83836Smrg [[nodiscard]] 124fb8a8121Smrg friend constexpr bool 125fb8a8121Smrg operator> (__cmp_cat::__unspec, partial_ordering __v) noexcept 126fb8a8121Smrg { return __v._M_value == -1; } 127fb8a8121Smrg 128*b1e83836Smrg [[nodiscard]] 129fb8a8121Smrg friend constexpr bool 130fb8a8121Smrg operator<=(__cmp_cat::__unspec, partial_ordering __v) noexcept 131fb8a8121Smrg { return __cmp_cat::type(__v._M_value & 1) == __v._M_value; } 132fb8a8121Smrg 133*b1e83836Smrg [[nodiscard]] 134fb8a8121Smrg friend constexpr bool 135fb8a8121Smrg operator>=(__cmp_cat::__unspec, partial_ordering __v) noexcept 136fb8a8121Smrg { return 0 >= __v._M_value; } 137fb8a8121Smrg 138*b1e83836Smrg [[nodiscard]] 139fb8a8121Smrg friend constexpr partial_ordering 140fb8a8121Smrg operator<=>(partial_ordering __v, __cmp_cat::__unspec) noexcept 141fb8a8121Smrg { return __v; } 142fb8a8121Smrg 143*b1e83836Smrg [[nodiscard]] 144fb8a8121Smrg friend constexpr partial_ordering 145fb8a8121Smrg operator<=>(__cmp_cat::__unspec, partial_ordering __v) noexcept 146fb8a8121Smrg { 147fb8a8121Smrg if (__v._M_value & 1) 148fb8a8121Smrg return partial_ordering(__cmp_cat::_Ord(-__v._M_value)); 149fb8a8121Smrg else 150fb8a8121Smrg return __v; 151fb8a8121Smrg } 152fb8a8121Smrg }; 153fb8a8121Smrg 154fb8a8121Smrg // valid values' definitions 155fb8a8121Smrg inline constexpr partial_ordering 156fb8a8121Smrg partial_ordering::less(__cmp_cat::_Ord::less); 157fb8a8121Smrg 158fb8a8121Smrg inline constexpr partial_ordering 159fb8a8121Smrg partial_ordering::equivalent(__cmp_cat::_Ord::equivalent); 160fb8a8121Smrg 161fb8a8121Smrg inline constexpr partial_ordering 162fb8a8121Smrg partial_ordering::greater(__cmp_cat::_Ord::greater); 163fb8a8121Smrg 164fb8a8121Smrg inline constexpr partial_ordering 165fb8a8121Smrg partial_ordering::unordered(__cmp_cat::_Ncmp::_Unordered); 166fb8a8121Smrg 167fb8a8121Smrg class weak_ordering 168fb8a8121Smrg { 169fb8a8121Smrg __cmp_cat::type _M_value; 170fb8a8121Smrg 171fb8a8121Smrg constexpr explicit 172fb8a8121Smrg weak_ordering(__cmp_cat::_Ord __v) noexcept : _M_value(__cmp_cat::type(__v)) 173fb8a8121Smrg { } 174fb8a8121Smrg 175fb8a8121Smrg friend class strong_ordering; 176fb8a8121Smrg 177fb8a8121Smrg public: 178fb8a8121Smrg // valid values 179fb8a8121Smrg static const weak_ordering less; 180fb8a8121Smrg static const weak_ordering equivalent; 181fb8a8121Smrg static const weak_ordering greater; 182fb8a8121Smrg 183*b1e83836Smrg [[nodiscard]] 184fb8a8121Smrg constexpr operator partial_ordering() const noexcept 185fb8a8121Smrg { return partial_ordering(__cmp_cat::_Ord(_M_value)); } 186fb8a8121Smrg 187fb8a8121Smrg // comparisons 188*b1e83836Smrg [[nodiscard]] 189fb8a8121Smrg friend constexpr bool 190fb8a8121Smrg operator==(weak_ordering __v, __cmp_cat::__unspec) noexcept 191fb8a8121Smrg { return __v._M_value == 0; } 192fb8a8121Smrg 193*b1e83836Smrg [[nodiscard]] 194fb8a8121Smrg friend constexpr bool 195fb8a8121Smrg operator==(weak_ordering, weak_ordering) noexcept = default; 196fb8a8121Smrg 197*b1e83836Smrg [[nodiscard]] 198fb8a8121Smrg friend constexpr bool 199fb8a8121Smrg operator< (weak_ordering __v, __cmp_cat::__unspec) noexcept 200fb8a8121Smrg { return __v._M_value < 0; } 201fb8a8121Smrg 202*b1e83836Smrg [[nodiscard]] 203fb8a8121Smrg friend constexpr bool 204fb8a8121Smrg operator> (weak_ordering __v, __cmp_cat::__unspec) noexcept 205fb8a8121Smrg { return __v._M_value > 0; } 206fb8a8121Smrg 207*b1e83836Smrg [[nodiscard]] 208fb8a8121Smrg friend constexpr bool 209fb8a8121Smrg operator<=(weak_ordering __v, __cmp_cat::__unspec) noexcept 210fb8a8121Smrg { return __v._M_value <= 0; } 211fb8a8121Smrg 212*b1e83836Smrg [[nodiscard]] 213fb8a8121Smrg friend constexpr bool 214fb8a8121Smrg operator>=(weak_ordering __v, __cmp_cat::__unspec) noexcept 215fb8a8121Smrg { return __v._M_value >= 0; } 216fb8a8121Smrg 217*b1e83836Smrg [[nodiscard]] 218fb8a8121Smrg friend constexpr bool 219fb8a8121Smrg operator< (__cmp_cat::__unspec, weak_ordering __v) noexcept 220fb8a8121Smrg { return 0 < __v._M_value; } 221fb8a8121Smrg 222*b1e83836Smrg [[nodiscard]] 223fb8a8121Smrg friend constexpr bool 224fb8a8121Smrg operator> (__cmp_cat::__unspec, weak_ordering __v) noexcept 225fb8a8121Smrg { return 0 > __v._M_value; } 226fb8a8121Smrg 227*b1e83836Smrg [[nodiscard]] 228fb8a8121Smrg friend constexpr bool 229fb8a8121Smrg operator<=(__cmp_cat::__unspec, weak_ordering __v) noexcept 230fb8a8121Smrg { return 0 <= __v._M_value; } 231fb8a8121Smrg 232*b1e83836Smrg [[nodiscard]] 233fb8a8121Smrg friend constexpr bool 234fb8a8121Smrg operator>=(__cmp_cat::__unspec, weak_ordering __v) noexcept 235fb8a8121Smrg { return 0 >= __v._M_value; } 236fb8a8121Smrg 237*b1e83836Smrg [[nodiscard]] 238fb8a8121Smrg friend constexpr weak_ordering 239fb8a8121Smrg operator<=>(weak_ordering __v, __cmp_cat::__unspec) noexcept 240fb8a8121Smrg { return __v; } 241fb8a8121Smrg 242*b1e83836Smrg [[nodiscard]] 243fb8a8121Smrg friend constexpr weak_ordering 244fb8a8121Smrg operator<=>(__cmp_cat::__unspec, weak_ordering __v) noexcept 245fb8a8121Smrg { return weak_ordering(__cmp_cat::_Ord(-__v._M_value)); } 246fb8a8121Smrg }; 247fb8a8121Smrg 248fb8a8121Smrg // valid values' definitions 249fb8a8121Smrg inline constexpr weak_ordering 250fb8a8121Smrg weak_ordering::less(__cmp_cat::_Ord::less); 251fb8a8121Smrg 252fb8a8121Smrg inline constexpr weak_ordering 253fb8a8121Smrg weak_ordering::equivalent(__cmp_cat::_Ord::equivalent); 254fb8a8121Smrg 255fb8a8121Smrg inline constexpr weak_ordering 256fb8a8121Smrg weak_ordering::greater(__cmp_cat::_Ord::greater); 257fb8a8121Smrg 258fb8a8121Smrg class strong_ordering 259fb8a8121Smrg { 260fb8a8121Smrg __cmp_cat::type _M_value; 261fb8a8121Smrg 262fb8a8121Smrg constexpr explicit 263fb8a8121Smrg strong_ordering(__cmp_cat::_Ord __v) noexcept 264fb8a8121Smrg : _M_value(__cmp_cat::type(__v)) 265fb8a8121Smrg { } 266fb8a8121Smrg 267fb8a8121Smrg public: 268fb8a8121Smrg // valid values 269fb8a8121Smrg static const strong_ordering less; 270fb8a8121Smrg static const strong_ordering equal; 271fb8a8121Smrg static const strong_ordering equivalent; 272fb8a8121Smrg static const strong_ordering greater; 273fb8a8121Smrg 274*b1e83836Smrg [[nodiscard]] 275fb8a8121Smrg constexpr operator partial_ordering() const noexcept 276fb8a8121Smrg { return partial_ordering(__cmp_cat::_Ord(_M_value)); } 277fb8a8121Smrg 278*b1e83836Smrg [[nodiscard]] 279fb8a8121Smrg constexpr operator weak_ordering() const noexcept 280fb8a8121Smrg { return weak_ordering(__cmp_cat::_Ord(_M_value)); } 281fb8a8121Smrg 282fb8a8121Smrg // comparisons 283*b1e83836Smrg [[nodiscard]] 284fb8a8121Smrg friend constexpr bool 285fb8a8121Smrg operator==(strong_ordering __v, __cmp_cat::__unspec) noexcept 286fb8a8121Smrg { return __v._M_value == 0; } 287fb8a8121Smrg 288*b1e83836Smrg [[nodiscard]] 289fb8a8121Smrg friend constexpr bool 290fb8a8121Smrg operator==(strong_ordering, strong_ordering) noexcept = default; 291fb8a8121Smrg 292*b1e83836Smrg [[nodiscard]] 293fb8a8121Smrg friend constexpr bool 294fb8a8121Smrg operator< (strong_ordering __v, __cmp_cat::__unspec) noexcept 295fb8a8121Smrg { return __v._M_value < 0; } 296fb8a8121Smrg 297*b1e83836Smrg [[nodiscard]] 298fb8a8121Smrg friend constexpr bool 299fb8a8121Smrg operator> (strong_ordering __v, __cmp_cat::__unspec) noexcept 300fb8a8121Smrg { return __v._M_value > 0; } 301fb8a8121Smrg 302*b1e83836Smrg [[nodiscard]] 303fb8a8121Smrg friend constexpr bool 304fb8a8121Smrg operator<=(strong_ordering __v, __cmp_cat::__unspec) noexcept 305fb8a8121Smrg { return __v._M_value <= 0; } 306fb8a8121Smrg 307*b1e83836Smrg [[nodiscard]] 308fb8a8121Smrg friend constexpr bool 309fb8a8121Smrg operator>=(strong_ordering __v, __cmp_cat::__unspec) noexcept 310fb8a8121Smrg { return __v._M_value >= 0; } 311fb8a8121Smrg 312*b1e83836Smrg [[nodiscard]] 313fb8a8121Smrg friend constexpr bool 314fb8a8121Smrg operator< (__cmp_cat::__unspec, strong_ordering __v) noexcept 315fb8a8121Smrg { return 0 < __v._M_value; } 316fb8a8121Smrg 317*b1e83836Smrg [[nodiscard]] 318fb8a8121Smrg friend constexpr bool 319fb8a8121Smrg operator> (__cmp_cat::__unspec, strong_ordering __v) noexcept 320fb8a8121Smrg { return 0 > __v._M_value; } 321fb8a8121Smrg 322*b1e83836Smrg [[nodiscard]] 323fb8a8121Smrg friend constexpr bool 324fb8a8121Smrg operator<=(__cmp_cat::__unspec, strong_ordering __v) noexcept 325fb8a8121Smrg { return 0 <= __v._M_value; } 326fb8a8121Smrg 327*b1e83836Smrg [[nodiscard]] 328fb8a8121Smrg friend constexpr bool 329fb8a8121Smrg operator>=(__cmp_cat::__unspec, strong_ordering __v) noexcept 330fb8a8121Smrg { return 0 >= __v._M_value; } 331fb8a8121Smrg 332*b1e83836Smrg [[nodiscard]] 333fb8a8121Smrg friend constexpr strong_ordering 334fb8a8121Smrg operator<=>(strong_ordering __v, __cmp_cat::__unspec) noexcept 335fb8a8121Smrg { return __v; } 336fb8a8121Smrg 337*b1e83836Smrg [[nodiscard]] 338fb8a8121Smrg friend constexpr strong_ordering 339fb8a8121Smrg operator<=>(__cmp_cat::__unspec, strong_ordering __v) noexcept 340fb8a8121Smrg { return strong_ordering(__cmp_cat::_Ord(-__v._M_value)); } 341fb8a8121Smrg }; 342fb8a8121Smrg 343fb8a8121Smrg // valid values' definitions 344fb8a8121Smrg inline constexpr strong_ordering 345fb8a8121Smrg strong_ordering::less(__cmp_cat::_Ord::less); 346fb8a8121Smrg 347fb8a8121Smrg inline constexpr strong_ordering 348fb8a8121Smrg strong_ordering::equal(__cmp_cat::_Ord::equivalent); 349fb8a8121Smrg 350fb8a8121Smrg inline constexpr strong_ordering 351fb8a8121Smrg strong_ordering::equivalent(__cmp_cat::_Ord::equivalent); 352fb8a8121Smrg 353fb8a8121Smrg inline constexpr strong_ordering 354fb8a8121Smrg strong_ordering::greater(__cmp_cat::_Ord::greater); 355fb8a8121Smrg 356fb8a8121Smrg 357fb8a8121Smrg // named comparison functions 358*b1e83836Smrg [[nodiscard]] 359fb8a8121Smrg constexpr bool 360fb8a8121Smrg is_eq(partial_ordering __cmp) noexcept 361fb8a8121Smrg { return __cmp == 0; } 362fb8a8121Smrg 363*b1e83836Smrg [[nodiscard]] 364fb8a8121Smrg constexpr bool 365fb8a8121Smrg is_neq(partial_ordering __cmp) noexcept 366fb8a8121Smrg { return __cmp != 0; } 367fb8a8121Smrg 368*b1e83836Smrg [[nodiscard]] 369fb8a8121Smrg constexpr bool 370fb8a8121Smrg is_lt (partial_ordering __cmp) noexcept 371fb8a8121Smrg { return __cmp < 0; } 372fb8a8121Smrg 373*b1e83836Smrg [[nodiscard]] 374fb8a8121Smrg constexpr bool 375fb8a8121Smrg is_lteq(partial_ordering __cmp) noexcept 376fb8a8121Smrg { return __cmp <= 0; } 377fb8a8121Smrg 378*b1e83836Smrg [[nodiscard]] 379fb8a8121Smrg constexpr bool 380fb8a8121Smrg is_gt (partial_ordering __cmp) noexcept 381fb8a8121Smrg { return __cmp > 0; } 382fb8a8121Smrg 383*b1e83836Smrg [[nodiscard]] 384fb8a8121Smrg constexpr bool 385fb8a8121Smrg is_gteq(partial_ordering __cmp) noexcept 386fb8a8121Smrg { return __cmp >= 0; } 387fb8a8121Smrg 388fb8a8121Smrg namespace __detail 389fb8a8121Smrg { 390fb8a8121Smrg template<typename _Tp> 391fb8a8121Smrg inline constexpr unsigned __cmp_cat_id = 1; 392fb8a8121Smrg template<> 393fb8a8121Smrg inline constexpr unsigned __cmp_cat_id<partial_ordering> = 2; 394fb8a8121Smrg template<> 395fb8a8121Smrg inline constexpr unsigned __cmp_cat_id<weak_ordering> = 4; 396fb8a8121Smrg template<> 397fb8a8121Smrg inline constexpr unsigned __cmp_cat_id<strong_ordering> = 8; 398fb8a8121Smrg 399fb8a8121Smrg template<typename... _Ts> 400fb8a8121Smrg constexpr auto __common_cmp_cat() 401fb8a8121Smrg { 402fb8a8121Smrg constexpr unsigned __cats = (__cmp_cat_id<_Ts> | ...); 403fb8a8121Smrg // If any Ti is not a comparison category type, U is void. 404fb8a8121Smrg if constexpr (__cats & 1) 405fb8a8121Smrg return; 406fb8a8121Smrg // Otherwise, if at least one Ti is std::partial_ordering, 407fb8a8121Smrg // U is std::partial_ordering. 408fb8a8121Smrg else if constexpr (bool(__cats & __cmp_cat_id<partial_ordering>)) 409fb8a8121Smrg return partial_ordering::equivalent; 410fb8a8121Smrg // Otherwise, if at least one Ti is std::weak_ordering, 411fb8a8121Smrg // U is std::weak_ordering. 412fb8a8121Smrg else if constexpr (bool(__cats & __cmp_cat_id<weak_ordering>)) 413fb8a8121Smrg return weak_ordering::equivalent; 414fb8a8121Smrg // Otherwise, U is std::strong_ordering. 415fb8a8121Smrg else 416fb8a8121Smrg return strong_ordering::equivalent; 417fb8a8121Smrg } 418fb8a8121Smrg } // namespace __detail 419fb8a8121Smrg 420fb8a8121Smrg // [cmp.common], common comparison category type 421fb8a8121Smrg template<typename... _Ts> 422fb8a8121Smrg struct common_comparison_category 423fb8a8121Smrg { 424fb8a8121Smrg using type = decltype(__detail::__common_cmp_cat<_Ts...>()); 425fb8a8121Smrg }; 426fb8a8121Smrg 427fb8a8121Smrg // Partial specializations for one and zero argument cases. 428fb8a8121Smrg 429fb8a8121Smrg template<typename _Tp> 430fb8a8121Smrg struct common_comparison_category<_Tp> 431fb8a8121Smrg { using type = void; }; 432fb8a8121Smrg 433fb8a8121Smrg template<> 434fb8a8121Smrg struct common_comparison_category<partial_ordering> 435fb8a8121Smrg { using type = partial_ordering; }; 436fb8a8121Smrg 437fb8a8121Smrg template<> 438fb8a8121Smrg struct common_comparison_category<weak_ordering> 439fb8a8121Smrg { using type = weak_ordering; }; 440fb8a8121Smrg 441fb8a8121Smrg template<> 442fb8a8121Smrg struct common_comparison_category<strong_ordering> 443fb8a8121Smrg { using type = strong_ordering; }; 444fb8a8121Smrg 445fb8a8121Smrg template<> 446fb8a8121Smrg struct common_comparison_category<> 447fb8a8121Smrg { using type = strong_ordering; }; 448fb8a8121Smrg 449fb8a8121Smrg template<typename... _Ts> 450fb8a8121Smrg using common_comparison_category_t 451fb8a8121Smrg = typename common_comparison_category<_Ts...>::type; 452fb8a8121Smrg 453fb8a8121Smrg#if __cpp_lib_concepts 454fb8a8121Smrg namespace __detail 455fb8a8121Smrg { 456fb8a8121Smrg template<typename _Tp, typename _Cat> 457fb8a8121Smrg concept __compares_as 458fb8a8121Smrg = same_as<common_comparison_category_t<_Tp, _Cat>, _Cat>; 459fb8a8121Smrg } // namespace __detail 460fb8a8121Smrg 461fb8a8121Smrg // [cmp.concept], concept three_way_comparable 462fb8a8121Smrg template<typename _Tp, typename _Cat = partial_ordering> 463fb8a8121Smrg concept three_way_comparable 464fb8a8121Smrg = __detail::__weakly_eq_cmp_with<_Tp, _Tp> 465fb8a8121Smrg && __detail::__partially_ordered_with<_Tp, _Tp> 466fb8a8121Smrg && requires(const remove_reference_t<_Tp>& __a, 467fb8a8121Smrg const remove_reference_t<_Tp>& __b) 468fb8a8121Smrg { 469fb8a8121Smrg { __a <=> __b } -> __detail::__compares_as<_Cat>; 470fb8a8121Smrg }; 471fb8a8121Smrg 472fb8a8121Smrg template<typename _Tp, typename _Up, typename _Cat = partial_ordering> 473fb8a8121Smrg concept three_way_comparable_with 474fb8a8121Smrg = three_way_comparable<_Tp, _Cat> 475fb8a8121Smrg && three_way_comparable<_Up, _Cat> 476fb8a8121Smrg && common_reference_with<const remove_reference_t<_Tp>&, 477fb8a8121Smrg const remove_reference_t<_Up>&> 478fb8a8121Smrg && three_way_comparable< 479fb8a8121Smrg common_reference_t<const remove_reference_t<_Tp>&, 480fb8a8121Smrg const remove_reference_t<_Up>&>, _Cat> 481fb8a8121Smrg && __detail::__weakly_eq_cmp_with<_Tp, _Up> 482fb8a8121Smrg && __detail::__partially_ordered_with<_Tp, _Up> 483fb8a8121Smrg && requires(const remove_reference_t<_Tp>& __t, 484fb8a8121Smrg const remove_reference_t<_Up>& __u) 485fb8a8121Smrg { 486fb8a8121Smrg { __t <=> __u } -> __detail::__compares_as<_Cat>; 487fb8a8121Smrg { __u <=> __t } -> __detail::__compares_as<_Cat>; 488fb8a8121Smrg }; 489fb8a8121Smrg 490fb8a8121Smrg namespace __detail 491fb8a8121Smrg { 492fb8a8121Smrg template<typename _Tp, typename _Up> 493fb8a8121Smrg using __cmp3way_res_t 494fb8a8121Smrg = decltype(std::declval<_Tp>() <=> std::declval<_Up>()); 495fb8a8121Smrg 496fb8a8121Smrg // Implementation of std::compare_three_way_result. 497fb8a8121Smrg // It is undefined for a program to add specializations of 498fb8a8121Smrg // std::compare_three_way_result, so the std::compare_three_way_result_t 499fb8a8121Smrg // alias ignores std::compare_three_way_result and uses 500fb8a8121Smrg // __detail::__cmp3way_res_impl directly instead. 501fb8a8121Smrg template<typename _Tp, typename _Up> 502fb8a8121Smrg struct __cmp3way_res_impl 503fb8a8121Smrg { }; 504fb8a8121Smrg 505fb8a8121Smrg template<typename _Tp, typename _Up> 506fb8a8121Smrg requires requires { typename __cmp3way_res_t<__cref<_Tp>, __cref<_Up>>; } 507fb8a8121Smrg struct __cmp3way_res_impl<_Tp, _Up> 508fb8a8121Smrg { 509fb8a8121Smrg using type = __cmp3way_res_t<__cref<_Tp>, __cref<_Up>>; 510fb8a8121Smrg }; 511fb8a8121Smrg } // namespace __detail 512fb8a8121Smrg 513fb8a8121Smrg /// [cmp.result], result of three-way comparison 514fb8a8121Smrg template<typename _Tp, typename _Up = _Tp> 515fb8a8121Smrg struct compare_three_way_result 516fb8a8121Smrg : __detail::__cmp3way_res_impl<_Tp, _Up> 517fb8a8121Smrg { }; 518fb8a8121Smrg 519fb8a8121Smrg /// [cmp.result], result of three-way comparison 520fb8a8121Smrg template<typename _Tp, typename _Up = _Tp> 521fb8a8121Smrg using compare_three_way_result_t 522fb8a8121Smrg = typename __detail::__cmp3way_res_impl<_Tp, _Up>::type; 523fb8a8121Smrg 524fb8a8121Smrg namespace __detail 525fb8a8121Smrg { 526fb8a8121Smrg // BUILTIN-PTR-THREE-WAY(T, U) 527fb8a8121Smrg // This determines whether t <=> u results in a call to a built-in 528fb8a8121Smrg // operator<=> comparing pointers. It doesn't work for function pointers 529fb8a8121Smrg // (PR 93628). 530fb8a8121Smrg template<typename _Tp, typename _Up> 531fb8a8121Smrg concept __3way_builtin_ptr_cmp 532fb8a8121Smrg = requires(_Tp&& __t, _Up&& __u) 533fb8a8121Smrg { static_cast<_Tp&&>(__t) <=> static_cast<_Up&&>(__u); } 534fb8a8121Smrg && convertible_to<_Tp, const volatile void*> 535fb8a8121Smrg && convertible_to<_Up, const volatile void*> 536fb8a8121Smrg && ! requires(_Tp&& __t, _Up&& __u) 537fb8a8121Smrg { operator<=>(static_cast<_Tp&&>(__t), static_cast<_Up&&>(__u)); } 538fb8a8121Smrg && ! requires(_Tp&& __t, _Up&& __u) 539fb8a8121Smrg { static_cast<_Tp&&>(__t).operator<=>(static_cast<_Up&&>(__u)); }; 540fb8a8121Smrg } // namespace __detail 541fb8a8121Smrg 542fb8a8121Smrg // _GLIBCXX_RESOLVE_LIB_DEFECTS 543fb8a8121Smrg // 3530 BUILTIN-PTR-MEOW should not opt the type out of syntactic checks 544fb8a8121Smrg 545fb8a8121Smrg // [cmp.object], typename compare_three_way 546fb8a8121Smrg struct compare_three_way 547fb8a8121Smrg { 548fb8a8121Smrg template<typename _Tp, typename _Up> 549fb8a8121Smrg requires three_way_comparable_with<_Tp, _Up> 550fb8a8121Smrg constexpr auto 551*b1e83836Smrg operator() [[nodiscard]] (_Tp&& __t, _Up&& __u) const 552fb8a8121Smrg noexcept(noexcept(std::declval<_Tp>() <=> std::declval<_Up>())) 553fb8a8121Smrg { 554fb8a8121Smrg if constexpr (__detail::__3way_builtin_ptr_cmp<_Tp, _Up>) 555fb8a8121Smrg { 556fb8a8121Smrg auto __pt = static_cast<const volatile void*>(__t); 557fb8a8121Smrg auto __pu = static_cast<const volatile void*>(__u); 558*b1e83836Smrg if (std::__is_constant_evaluated()) 559fb8a8121Smrg return __pt <=> __pu; 560fb8a8121Smrg auto __it = reinterpret_cast<__UINTPTR_TYPE__>(__pt); 561fb8a8121Smrg auto __iu = reinterpret_cast<__UINTPTR_TYPE__>(__pu); 562fb8a8121Smrg return __it <=> __iu; 563fb8a8121Smrg } 564fb8a8121Smrg else 565fb8a8121Smrg return static_cast<_Tp&&>(__t) <=> static_cast<_Up&&>(__u); 566fb8a8121Smrg } 567fb8a8121Smrg 568fb8a8121Smrg using is_transparent = void; 569fb8a8121Smrg }; 570fb8a8121Smrg 571fb8a8121Smrg namespace __cmp_cust 572fb8a8121Smrg { 573fb8a8121Smrg template<floating_point _Tp> 574fb8a8121Smrg constexpr weak_ordering 575fb8a8121Smrg __fp_weak_ordering(_Tp __e, _Tp __f) 576fb8a8121Smrg { 577fb8a8121Smrg // Returns an integer with the same sign as the argument, and magnitude 578fb8a8121Smrg // indicating the classification: zero=1 subnorm=2 norm=3 inf=4 nan=5 579fb8a8121Smrg auto __cat = [](_Tp __fp) -> int { 580fb8a8121Smrg const int __sign = __builtin_signbit(__fp) ? -1 : 1; 581fb8a8121Smrg if (__builtin_isnormal(__fp)) 582fb8a8121Smrg return (__fp == 0 ? 1 : 3) * __sign; 583fb8a8121Smrg if (__builtin_isnan(__fp)) 584fb8a8121Smrg return 5 * __sign; 585fb8a8121Smrg if (int __inf = __builtin_isinf_sign(__fp)) 586fb8a8121Smrg return 4 * __inf; 587fb8a8121Smrg return 2 * __sign; 588fb8a8121Smrg }; 589fb8a8121Smrg 590fb8a8121Smrg auto __po = __e <=> __f; 591fb8a8121Smrg if (is_lt(__po)) 592fb8a8121Smrg return weak_ordering::less; 593fb8a8121Smrg else if (is_gt(__po)) 594fb8a8121Smrg return weak_ordering::greater; 595fb8a8121Smrg else if (__po == partial_ordering::equivalent) 596fb8a8121Smrg return weak_ordering::equivalent; 597fb8a8121Smrg else // unordered, at least one argument is NaN 598fb8a8121Smrg { 599fb8a8121Smrg // return -1 for negative nan, +1 for positive nan, 0 otherwise. 600fb8a8121Smrg auto __isnan_sign = [](_Tp __fp) -> int { 601fb8a8121Smrg return __builtin_isnan(__fp) 602fb8a8121Smrg ? __builtin_signbit(__fp) ? -1 : 1 603fb8a8121Smrg : 0; 604fb8a8121Smrg }; 605fb8a8121Smrg auto __ord = __isnan_sign(__e) <=> __isnan_sign(__f); 606fb8a8121Smrg if (is_eq(__ord)) 607fb8a8121Smrg return weak_ordering::equivalent; 608fb8a8121Smrg else if (is_lt(__ord)) 609fb8a8121Smrg return weak_ordering::less; 610fb8a8121Smrg else 611fb8a8121Smrg return weak_ordering::greater; 612fb8a8121Smrg } 613fb8a8121Smrg } 614fb8a8121Smrg 615fb8a8121Smrg template<typename _Tp, typename _Up> 616fb8a8121Smrg concept __adl_strong = requires(_Tp&& __t, _Up&& __u) 617fb8a8121Smrg { 618fb8a8121Smrg strong_ordering(strong_order(static_cast<_Tp&&>(__t), 619fb8a8121Smrg static_cast<_Up&&>(__u))); 620fb8a8121Smrg }; 621fb8a8121Smrg 622fb8a8121Smrg template<typename _Tp, typename _Up> 623fb8a8121Smrg concept __adl_weak = requires(_Tp&& __t, _Up&& __u) 624fb8a8121Smrg { 625fb8a8121Smrg weak_ordering(weak_order(static_cast<_Tp&&>(__t), 626fb8a8121Smrg static_cast<_Up&&>(__u))); 627fb8a8121Smrg }; 628fb8a8121Smrg 629fb8a8121Smrg template<typename _Tp, typename _Up> 630fb8a8121Smrg concept __adl_partial = requires(_Tp&& __t, _Up&& __u) 631fb8a8121Smrg { 632fb8a8121Smrg partial_ordering(partial_order(static_cast<_Tp&&>(__t), 633fb8a8121Smrg static_cast<_Up&&>(__u))); 634fb8a8121Smrg }; 635fb8a8121Smrg 636fb8a8121Smrg template<typename _Ord, typename _Tp, typename _Up> 637fb8a8121Smrg concept __cmp3way = requires(_Tp&& __t, _Up&& __u, compare_three_way __c) 638fb8a8121Smrg { 639fb8a8121Smrg _Ord(__c(static_cast<_Tp&&>(__t), static_cast<_Up&&>(__u))); 640fb8a8121Smrg }; 641fb8a8121Smrg 642fb8a8121Smrg template<typename _Tp, typename _Up> 643fb8a8121Smrg concept __strongly_ordered 644fb8a8121Smrg = __adl_strong<_Tp, _Up> 645*b1e83836Smrg || floating_point<remove_reference_t<_Tp>> 646fb8a8121Smrg || __cmp3way<strong_ordering, _Tp, _Up>; 647fb8a8121Smrg 648a448f87cSmrg template<typename _Tp, typename _Up> 649a448f87cSmrg concept __decayed_same_as = same_as<decay_t<_Tp>, decay_t<_Up>>; 650a448f87cSmrg 651fb8a8121Smrg class _Strong_order 652fb8a8121Smrg { 653fb8a8121Smrg template<typename _Tp, typename _Up> 654fb8a8121Smrg static constexpr bool 655fb8a8121Smrg _S_noexcept() 656fb8a8121Smrg { 657fb8a8121Smrg if constexpr (floating_point<decay_t<_Tp>>) 658fb8a8121Smrg return true; 659fb8a8121Smrg else if constexpr (__adl_strong<_Tp, _Up>) 660fb8a8121Smrg return noexcept(strong_ordering(strong_order(std::declval<_Tp>(), 661fb8a8121Smrg std::declval<_Up>()))); 662fb8a8121Smrg else if constexpr (__cmp3way<strong_ordering, _Tp, _Up>) 663fb8a8121Smrg return noexcept(compare_three_way()(std::declval<_Tp>(), 664fb8a8121Smrg std::declval<_Up>())); 665fb8a8121Smrg } 666fb8a8121Smrg 667fb8a8121Smrg friend class _Weak_order; 668fb8a8121Smrg friend class _Strong_fallback; 669fb8a8121Smrg 670*b1e83836Smrg // Names for the supported floating-point representations. 671*b1e83836Smrg enum class _Fp_fmt 672*b1e83836Smrg { 673*b1e83836Smrg _Binary16, _Binary32, _Binary64, _Binary128, // IEEE 674*b1e83836Smrg _X86_80bit, // x86 80-bit extended precision 675*b1e83836Smrg _M68k_80bit, // m68k 80-bit extended precision 676*b1e83836Smrg _Dbldbl, // IBM 128-bit double-double 677*b1e83836Smrg // TODO: _Bfloat16, 678*b1e83836Smrg }; 679*b1e83836Smrg 680*b1e83836Smrg#ifndef __cpp_using_enum 681*b1e83836Smrg // XXX Remove these once 'using enum' support is ubiquitous. 682*b1e83836Smrg static constexpr _Fp_fmt _Binary16 = _Fp_fmt::_Binary16; 683*b1e83836Smrg static constexpr _Fp_fmt _Binary32 = _Fp_fmt::_Binary32; 684*b1e83836Smrg static constexpr _Fp_fmt _Binary64 = _Fp_fmt::_Binary64; 685*b1e83836Smrg static constexpr _Fp_fmt _Binary128 = _Fp_fmt::_Binary128; 686*b1e83836Smrg static constexpr _Fp_fmt _X86_80bit = _Fp_fmt::_X86_80bit; 687*b1e83836Smrg static constexpr _Fp_fmt _M68k_80bit = _Fp_fmt::_M68k_80bit; 688*b1e83836Smrg static constexpr _Fp_fmt _Dbldbl = _Fp_fmt::_Dbldbl; 689*b1e83836Smrg#endif 690*b1e83836Smrg 691*b1e83836Smrg // Identify the format used by a floating-point type. 692*b1e83836Smrg template<typename _Tp> 693*b1e83836Smrg static consteval _Fp_fmt 694*b1e83836Smrg _S_fp_fmt() noexcept 695*b1e83836Smrg { 696*b1e83836Smrg#ifdef __cpp_using_enum 697*b1e83836Smrg using enum _Fp_fmt; 698*b1e83836Smrg#endif 699*b1e83836Smrg 700*b1e83836Smrg // Identify these formats first, then assume anything else is IEEE. 701*b1e83836Smrg // N.B. ARM __fp16 alternative format can be handled as binary16. 702*b1e83836Smrg 703*b1e83836Smrg#ifdef __LONG_DOUBLE_IBM128__ 704*b1e83836Smrg if constexpr (__is_same(_Tp, long double)) 705*b1e83836Smrg return _Dbldbl; 706*b1e83836Smrg#elif defined __LONG_DOUBLE_IEEE128__ && defined __SIZEOF_IBM128__ 707*b1e83836Smrg if constexpr (__is_same(_Tp, __ibm128)) 708*b1e83836Smrg return _Dbldbl; 709*b1e83836Smrg#endif 710*b1e83836Smrg 711*b1e83836Smrg#if __LDBL_MANT_DIG__ == 64 712*b1e83836Smrg if constexpr (__is_same(_Tp, long double)) 713*b1e83836Smrg return __LDBL_MIN_EXP__ == -16381 ? _X86_80bit : _M68k_80bit; 714*b1e83836Smrg#endif 715*b1e83836Smrg#ifdef __SIZEOF_FLOAT80__ 716*b1e83836Smrg if constexpr (__is_same(_Tp, __float80)) 717*b1e83836Smrg return _X86_80bit; 718*b1e83836Smrg#endif 719*b1e83836Smrg 720*b1e83836Smrg constexpr int __width = sizeof(_Tp) * __CHAR_BIT__; 721*b1e83836Smrg 722*b1e83836Smrg if constexpr (__width == 16) // IEEE binary16 (or ARM fp16). 723*b1e83836Smrg return _Binary16; 724*b1e83836Smrg else if constexpr (__width == 32) // IEEE binary32 725*b1e83836Smrg return _Binary32; 726*b1e83836Smrg else if constexpr (__width == 64) // IEEE binary64 727*b1e83836Smrg return _Binary64; 728*b1e83836Smrg else if constexpr (__width == 128) // IEEE binary128 729*b1e83836Smrg return _Binary128; 730*b1e83836Smrg } 731*b1e83836Smrg 732*b1e83836Smrg // So we don't need to include <stdint.h> and pollute the namespace. 733*b1e83836Smrg using int64_t = __INT64_TYPE__; 734*b1e83836Smrg using int32_t = __INT32_TYPE__; 735*b1e83836Smrg using int16_t = __INT16_TYPE__; 736*b1e83836Smrg using uint64_t = __UINT64_TYPE__; 737*b1e83836Smrg using uint16_t = __UINT16_TYPE__; 738*b1e83836Smrg 739*b1e83836Smrg // Used to unpack floating-point types that do not fit into an integer. 740*b1e83836Smrg template<typename _Tp> 741*b1e83836Smrg struct _Int 742*b1e83836Smrg { 743*b1e83836Smrg#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ 744*b1e83836Smrg uint64_t _M_lo; 745*b1e83836Smrg _Tp _M_hi; 746*b1e83836Smrg#else 747*b1e83836Smrg _Tp _M_hi; 748*b1e83836Smrg uint64_t _M_lo; 749*b1e83836Smrg#endif 750*b1e83836Smrg 751*b1e83836Smrg constexpr explicit 752*b1e83836Smrg _Int(_Tp __hi, uint64_t __lo) noexcept : _M_hi(__hi) 753*b1e83836Smrg { _M_lo = __lo; } 754*b1e83836Smrg 755*b1e83836Smrg constexpr explicit 756*b1e83836Smrg _Int(uint64_t __lo) noexcept : _M_hi(0) 757*b1e83836Smrg { _M_lo = __lo; } 758*b1e83836Smrg 759*b1e83836Smrg constexpr bool operator==(const _Int&) const = default; 760*b1e83836Smrg 761*b1e83836Smrg#if defined __hppa__ || (defined __mips__ && !defined __mips_nan2008) 762*b1e83836Smrg consteval _Int 763*b1e83836Smrg operator<<(int __n) const noexcept 764*b1e83836Smrg { 765*b1e83836Smrg // XXX this assumes n >= 64, which is true for the use below. 766*b1e83836Smrg return _Int(static_cast<_Tp>(_M_lo << (__n - 64)), 0); 767*b1e83836Smrg } 768*b1e83836Smrg#endif 769*b1e83836Smrg 770*b1e83836Smrg constexpr _Int& 771*b1e83836Smrg operator^=(const _Int& __rhs) noexcept 772*b1e83836Smrg { 773*b1e83836Smrg _M_hi ^= __rhs._M_hi; 774*b1e83836Smrg _M_lo ^= __rhs._M_lo; 775*b1e83836Smrg return *this; 776*b1e83836Smrg } 777*b1e83836Smrg 778*b1e83836Smrg constexpr strong_ordering 779*b1e83836Smrg operator<=>(const _Int& __rhs) const noexcept 780*b1e83836Smrg { 781*b1e83836Smrg strong_ordering __cmp = _M_hi <=> __rhs._M_hi; 782*b1e83836Smrg if (__cmp != strong_ordering::equal) 783*b1e83836Smrg return __cmp; 784*b1e83836Smrg return _M_lo <=> __rhs._M_lo; 785*b1e83836Smrg } 786*b1e83836Smrg }; 787*b1e83836Smrg 788*b1e83836Smrg template<typename _Tp> 789*b1e83836Smrg static constexpr _Tp 790*b1e83836Smrg _S_compl(_Tp __t) noexcept 791*b1e83836Smrg { 792*b1e83836Smrg constexpr int __width = sizeof(_Tp) * __CHAR_BIT__; 793*b1e83836Smrg // Sign extend to get all ones or all zeros. 794*b1e83836Smrg make_unsigned_t<_Tp> __sign = __t >> (__width - 1); 795*b1e83836Smrg // If the sign bit was set, this flips all bits below it. 796*b1e83836Smrg // This converts ones' complement to two's complement. 797*b1e83836Smrg return __t ^ (__sign >> 1); 798*b1e83836Smrg } 799*b1e83836Smrg 800*b1e83836Smrg // As above but works on both parts of _Int<T>. 801*b1e83836Smrg template<typename _Tp> 802*b1e83836Smrg static constexpr _Int<_Tp> 803*b1e83836Smrg _S_compl(_Int<_Tp> __t) noexcept 804*b1e83836Smrg { 805*b1e83836Smrg constexpr int __width = sizeof(_Tp) * __CHAR_BIT__; 806*b1e83836Smrg make_unsigned_t<_Tp> __sign = __t._M_hi >> (__width - 1); 807*b1e83836Smrg __t._M_hi ^= (__sign >> 1 ); 808*b1e83836Smrg uint64_t __sign64 = (_Tp)__sign; 809*b1e83836Smrg __t._M_lo ^= __sign64; 810*b1e83836Smrg return __t; 811*b1e83836Smrg } 812*b1e83836Smrg 813*b1e83836Smrg // Bit-cast a floating-point value to an unsigned integer. 814*b1e83836Smrg template<typename _Tp> 815*b1e83836Smrg constexpr static auto 816*b1e83836Smrg _S_fp_bits(_Tp __val) noexcept 817*b1e83836Smrg { 818*b1e83836Smrg if constexpr (sizeof(_Tp) == sizeof(int64_t)) 819*b1e83836Smrg return __builtin_bit_cast(int64_t, __val); 820*b1e83836Smrg else if constexpr (sizeof(_Tp) == sizeof(int32_t)) 821*b1e83836Smrg return __builtin_bit_cast(int32_t, __val); 822*b1e83836Smrg else if constexpr (sizeof(_Tp) == sizeof(int16_t)) 823*b1e83836Smrg return __builtin_bit_cast(int16_t, __val); 824*b1e83836Smrg else 825*b1e83836Smrg { 826*b1e83836Smrg#ifdef __cpp_using_enum 827*b1e83836Smrg using enum _Fp_fmt; 828*b1e83836Smrg#endif 829*b1e83836Smrg constexpr auto __fmt = _S_fp_fmt<_Tp>(); 830*b1e83836Smrg if constexpr (__fmt == _X86_80bit || __fmt == _M68k_80bit) 831*b1e83836Smrg { 832*b1e83836Smrg if constexpr (sizeof(_Tp) == 3 * sizeof(int32_t)) 833*b1e83836Smrg { 834*b1e83836Smrg auto __ival = __builtin_bit_cast(_Int<int32_t>, __val); 835*b1e83836Smrg return _Int<int16_t>(__ival._M_hi, __ival._M_lo); 836*b1e83836Smrg } 837*b1e83836Smrg else 838*b1e83836Smrg { 839*b1e83836Smrg auto __ival = __builtin_bit_cast(_Int<int64_t>, __val); 840*b1e83836Smrg return _Int<int16_t>(__ival._M_hi, __ival._M_lo); 841*b1e83836Smrg } 842*b1e83836Smrg } 843*b1e83836Smrg else if constexpr (sizeof(_Tp) == 2 * sizeof(int64_t)) 844*b1e83836Smrg { 845*b1e83836Smrg#if __SIZEOF_INT128__ 846*b1e83836Smrg return __builtin_bit_cast(__int128, __val); 847*b1e83836Smrg#else 848*b1e83836Smrg return __builtin_bit_cast(_Int<int64_t>, __val); 849*b1e83836Smrg#endif 850*b1e83836Smrg } 851*b1e83836Smrg else 852*b1e83836Smrg static_assert(sizeof(_Tp) == sizeof(int64_t), 853*b1e83836Smrg "unsupported floating-point type"); 854*b1e83836Smrg } 855*b1e83836Smrg } 856*b1e83836Smrg 857*b1e83836Smrg template<typename _Tp> 858*b1e83836Smrg static constexpr strong_ordering 859*b1e83836Smrg _S_fp_cmp(_Tp __x, _Tp __y) noexcept 860*b1e83836Smrg { 861*b1e83836Smrg#ifdef __vax__ 862*b1e83836Smrg if (__builtin_isnan(__x) || __builtin_isnan(__y)) 863*b1e83836Smrg { 864*b1e83836Smrg int __ix = (bool) __builtin_isnan(__x); 865*b1e83836Smrg int __iy = (bool) __builtin_isnan(__y); 866*b1e83836Smrg __ix *= __builtin_signbit(__x) ? -1 : 1; 867*b1e83836Smrg __iy *= __builtin_signbit(__y) ? -1 : 1; 868*b1e83836Smrg return __ix <=> __iy; 869*b1e83836Smrg } 870*b1e83836Smrg else 871*b1e83836Smrg return __builtin_bit_cast(strong_ordering, __x <=> __y); 872*b1e83836Smrg#endif 873*b1e83836Smrg 874*b1e83836Smrg auto __ix = _S_fp_bits(__x); 875*b1e83836Smrg auto __iy = _S_fp_bits(__y); 876*b1e83836Smrg 877*b1e83836Smrg if (__ix == __iy) 878*b1e83836Smrg return strong_ordering::equal; // All bits are equal, we're done. 879*b1e83836Smrg 880*b1e83836Smrg#ifdef __cpp_using_enum 881*b1e83836Smrg using enum _Fp_fmt; 882*b1e83836Smrg#endif 883*b1e83836Smrg constexpr auto __fmt = _S_fp_fmt<_Tp>(); 884*b1e83836Smrg 885*b1e83836Smrg if constexpr (__fmt == _Dbldbl) // double-double 886*b1e83836Smrg { 887*b1e83836Smrg // Unpack the double-double into two parts. 888*b1e83836Smrg // We never inspect the low double as a double, cast to integer. 889*b1e83836Smrg struct _Unpacked { double _M_hi; int64_t _M_lo; }; 890*b1e83836Smrg auto __x2 = __builtin_bit_cast(_Unpacked, __x); 891*b1e83836Smrg auto __y2 = __builtin_bit_cast(_Unpacked, __y); 892*b1e83836Smrg 893*b1e83836Smrg // Compare the high doubles first and use result if unequal. 894*b1e83836Smrg auto __cmp = _S_fp_cmp(__x2._M_hi, __y2._M_hi); 895*b1e83836Smrg if (__cmp != strong_ordering::equal) 896*b1e83836Smrg return __cmp; 897*b1e83836Smrg 898*b1e83836Smrg // For NaN the low double is unused, so if the high doubles 899*b1e83836Smrg // are the same NaN, we don't need to compare the low doubles. 900*b1e83836Smrg if (__builtin_isnan(__x2._M_hi)) 901*b1e83836Smrg return strong_ordering::equal; 902*b1e83836Smrg // Similarly, if the low doubles are +zero or -zero (which is 903*b1e83836Smrg // true for all infinities and some other values), we're done. 904*b1e83836Smrg if (((__x2._M_lo | __y2._M_lo) & 0x7fffffffffffffffULL) == 0) 905*b1e83836Smrg return strong_ordering::equal; 906*b1e83836Smrg 907*b1e83836Smrg // Otherwise, compare the low parts. 908*b1e83836Smrg return _S_compl(__x2._M_lo) <=> _S_compl(__y2._M_lo); 909*b1e83836Smrg } 910*b1e83836Smrg else 911*b1e83836Smrg { 912*b1e83836Smrg if constexpr (__fmt == _M68k_80bit) 913*b1e83836Smrg { 914*b1e83836Smrg // For m68k the MSB of the significand is ignored for the 915*b1e83836Smrg // greatest exponent, so either 0 or 1 is valid there. 916*b1e83836Smrg // Set it before comparing, so that we never have 0 there. 917*b1e83836Smrg constexpr uint16_t __maxexp = 0x7fff; 918*b1e83836Smrg if ((__ix._M_hi & __maxexp) == __maxexp) 919*b1e83836Smrg __ix._M_lo |= 1ull << 63; 920*b1e83836Smrg if ((__iy._M_hi & __maxexp) == __maxexp) 921*b1e83836Smrg __iy._M_lo |= 1ull << 63; 922*b1e83836Smrg } 923*b1e83836Smrg else 924*b1e83836Smrg { 925*b1e83836Smrg#if defined __hppa__ || (defined __mips__ && !defined __mips_nan2008) 926*b1e83836Smrg // IEEE 754-1985 allowed the meaning of the quiet/signaling 927*b1e83836Smrg // bit to be reversed. Flip that to give desired ordering. 928*b1e83836Smrg if (__builtin_isnan(__x) && __builtin_isnan(__y)) 929*b1e83836Smrg { 930*b1e83836Smrg using _Int = decltype(__ix); 931*b1e83836Smrg 932*b1e83836Smrg constexpr int __nantype = __fmt == _Binary32 ? 22 933*b1e83836Smrg : __fmt == _Binary64 ? 51 934*b1e83836Smrg : __fmt == _Binary128 ? 111 935*b1e83836Smrg : -1; 936*b1e83836Smrg constexpr _Int __bit = _Int(1) << __nantype; 937*b1e83836Smrg __ix ^= __bit; 938*b1e83836Smrg __iy ^= __bit; 939*b1e83836Smrg } 940*b1e83836Smrg#endif 941*b1e83836Smrg } 942*b1e83836Smrg return _S_compl(__ix) <=> _S_compl(__iy); 943*b1e83836Smrg } 944*b1e83836Smrg } 945*b1e83836Smrg 946fb8a8121Smrg public: 947a448f87cSmrg template<typename _Tp, __decayed_same_as<_Tp> _Up> 948fb8a8121Smrg requires __strongly_ordered<_Tp, _Up> 949fb8a8121Smrg constexpr strong_ordering 950*b1e83836Smrg operator() [[nodiscard]] (_Tp&& __e, _Up&& __f) const 951fb8a8121Smrg noexcept(_S_noexcept<_Tp, _Up>()) 952fb8a8121Smrg { 953fb8a8121Smrg if constexpr (floating_point<decay_t<_Tp>>) 954*b1e83836Smrg return _S_fp_cmp(__e, __f); 955*b1e83836Smrg else if constexpr (__adl_strong<_Tp, _Up>) 956fb8a8121Smrg return strong_ordering(strong_order(static_cast<_Tp&&>(__e), 957fb8a8121Smrg static_cast<_Up&&>(__f))); 958fb8a8121Smrg else if constexpr (__cmp3way<strong_ordering, _Tp, _Up>) 959fb8a8121Smrg return compare_three_way()(static_cast<_Tp&&>(__e), 960fb8a8121Smrg static_cast<_Up&&>(__f)); 961fb8a8121Smrg } 962fb8a8121Smrg }; 963fb8a8121Smrg 964fb8a8121Smrg template<typename _Tp, typename _Up> 965fb8a8121Smrg concept __weakly_ordered 966fb8a8121Smrg = floating_point<remove_reference_t<_Tp>> 967fb8a8121Smrg || __adl_weak<_Tp, _Up> 968fb8a8121Smrg || __cmp3way<weak_ordering, _Tp, _Up> 969fb8a8121Smrg || __strongly_ordered<_Tp, _Up>; 970fb8a8121Smrg 971fb8a8121Smrg class _Weak_order 972fb8a8121Smrg { 973fb8a8121Smrg template<typename _Tp, typename _Up> 974fb8a8121Smrg static constexpr bool 975fb8a8121Smrg _S_noexcept() 976fb8a8121Smrg { 977fb8a8121Smrg if constexpr (floating_point<decay_t<_Tp>>) 978fb8a8121Smrg return true; 979fb8a8121Smrg else if constexpr (__adl_weak<_Tp, _Up>) 980fb8a8121Smrg return noexcept(weak_ordering(weak_order(std::declval<_Tp>(), 981fb8a8121Smrg std::declval<_Up>()))); 982fb8a8121Smrg else if constexpr (__cmp3way<weak_ordering, _Tp, _Up>) 983fb8a8121Smrg return noexcept(compare_three_way()(std::declval<_Tp>(), 984fb8a8121Smrg std::declval<_Up>())); 985fb8a8121Smrg else if constexpr (__strongly_ordered<_Tp, _Up>) 986fb8a8121Smrg return _Strong_order::_S_noexcept<_Tp, _Up>(); 987fb8a8121Smrg } 988fb8a8121Smrg 989fb8a8121Smrg friend class _Partial_order; 990fb8a8121Smrg friend class _Weak_fallback; 991fb8a8121Smrg 992fb8a8121Smrg public: 993a448f87cSmrg template<typename _Tp, __decayed_same_as<_Tp> _Up> 994fb8a8121Smrg requires __weakly_ordered<_Tp, _Up> 995fb8a8121Smrg constexpr weak_ordering 996*b1e83836Smrg operator() [[nodiscard]] (_Tp&& __e, _Up&& __f) const 997fb8a8121Smrg noexcept(_S_noexcept<_Tp, _Up>()) 998fb8a8121Smrg { 999fb8a8121Smrg if constexpr (floating_point<decay_t<_Tp>>) 1000fb8a8121Smrg return __cmp_cust::__fp_weak_ordering(__e, __f); 1001fb8a8121Smrg else if constexpr (__adl_weak<_Tp, _Up>) 1002fb8a8121Smrg return weak_ordering(weak_order(static_cast<_Tp&&>(__e), 1003fb8a8121Smrg static_cast<_Up&&>(__f))); 1004fb8a8121Smrg else if constexpr (__cmp3way<weak_ordering, _Tp, _Up>) 1005fb8a8121Smrg return compare_three_way()(static_cast<_Tp&&>(__e), 1006fb8a8121Smrg static_cast<_Up&&>(__f)); 1007fb8a8121Smrg else if constexpr (__strongly_ordered<_Tp, _Up>) 1008fb8a8121Smrg return _Strong_order{}(static_cast<_Tp&&>(__e), 1009fb8a8121Smrg static_cast<_Up&&>(__f)); 1010fb8a8121Smrg } 1011fb8a8121Smrg }; 1012fb8a8121Smrg 1013fb8a8121Smrg template<typename _Tp, typename _Up> 1014fb8a8121Smrg concept __partially_ordered 1015fb8a8121Smrg = __adl_partial<_Tp, _Up> 1016fb8a8121Smrg || __cmp3way<partial_ordering, _Tp, _Up> 1017fb8a8121Smrg || __weakly_ordered<_Tp, _Up>; 1018fb8a8121Smrg 1019fb8a8121Smrg class _Partial_order 1020fb8a8121Smrg { 1021fb8a8121Smrg template<typename _Tp, typename _Up> 1022fb8a8121Smrg static constexpr bool 1023fb8a8121Smrg _S_noexcept() 1024fb8a8121Smrg { 1025fb8a8121Smrg if constexpr (__adl_partial<_Tp, _Up>) 1026fb8a8121Smrg return noexcept(partial_ordering(partial_order(std::declval<_Tp>(), 1027fb8a8121Smrg std::declval<_Up>()))); 1028fb8a8121Smrg else if constexpr (__cmp3way<partial_ordering, _Tp, _Up>) 1029fb8a8121Smrg return noexcept(compare_three_way()(std::declval<_Tp>(), 1030fb8a8121Smrg std::declval<_Up>())); 1031fb8a8121Smrg else if constexpr (__weakly_ordered<_Tp, _Up>) 1032fb8a8121Smrg return _Weak_order::_S_noexcept<_Tp, _Up>(); 1033fb8a8121Smrg } 1034fb8a8121Smrg 1035fb8a8121Smrg friend class _Partial_fallback; 1036fb8a8121Smrg 1037fb8a8121Smrg public: 1038a448f87cSmrg template<typename _Tp, __decayed_same_as<_Tp> _Up> 1039fb8a8121Smrg requires __partially_ordered<_Tp, _Up> 1040fb8a8121Smrg constexpr partial_ordering 1041*b1e83836Smrg operator() [[nodiscard]] (_Tp&& __e, _Up&& __f) const 1042fb8a8121Smrg noexcept(_S_noexcept<_Tp, _Up>()) 1043fb8a8121Smrg { 1044fb8a8121Smrg if constexpr (__adl_partial<_Tp, _Up>) 1045fb8a8121Smrg return partial_ordering(partial_order(static_cast<_Tp&&>(__e), 1046fb8a8121Smrg static_cast<_Up&&>(__f))); 1047fb8a8121Smrg else if constexpr (__cmp3way<partial_ordering, _Tp, _Up>) 1048fb8a8121Smrg return compare_three_way()(static_cast<_Tp&&>(__e), 1049fb8a8121Smrg static_cast<_Up&&>(__f)); 1050fb8a8121Smrg else if constexpr (__weakly_ordered<_Tp, _Up>) 1051fb8a8121Smrg return _Weak_order{}(static_cast<_Tp&&>(__e), 1052fb8a8121Smrg static_cast<_Up&&>(__f)); 1053fb8a8121Smrg } 1054fb8a8121Smrg }; 1055fb8a8121Smrg 1056fb8a8121Smrg template<typename _Tp, typename _Up> 1057fb8a8121Smrg concept __op_eq_lt = requires(_Tp&& __t, _Up&& __u) 1058fb8a8121Smrg { 1059fb8a8121Smrg { static_cast<_Tp&&>(__t) == static_cast<_Up&&>(__u) } 1060fb8a8121Smrg -> convertible_to<bool>; 1061fb8a8121Smrg { static_cast<_Tp&&>(__t) < static_cast<_Up&&>(__u) } 1062fb8a8121Smrg -> convertible_to<bool>; 1063fb8a8121Smrg }; 1064fb8a8121Smrg 1065fb8a8121Smrg class _Strong_fallback 1066fb8a8121Smrg { 1067fb8a8121Smrg template<typename _Tp, typename _Up> 1068fb8a8121Smrg static constexpr bool 1069fb8a8121Smrg _S_noexcept() 1070fb8a8121Smrg { 1071fb8a8121Smrg if constexpr (__strongly_ordered<_Tp, _Up>) 1072fb8a8121Smrg return _Strong_order::_S_noexcept<_Tp, _Up>(); 1073fb8a8121Smrg else 1074fb8a8121Smrg return noexcept(bool(std::declval<_Tp>() == std::declval<_Up>())) 1075fb8a8121Smrg && noexcept(bool(std::declval<_Tp>() < std::declval<_Up>())); 1076fb8a8121Smrg } 1077fb8a8121Smrg 1078fb8a8121Smrg public: 1079a448f87cSmrg template<typename _Tp, __decayed_same_as<_Tp> _Up> 1080fb8a8121Smrg requires __strongly_ordered<_Tp, _Up> || __op_eq_lt<_Tp, _Up> 1081a448f87cSmrg constexpr strong_ordering 1082*b1e83836Smrg operator() [[nodiscard]] (_Tp&& __e, _Up&& __f) const 1083fb8a8121Smrg noexcept(_S_noexcept<_Tp, _Up>()) 1084fb8a8121Smrg { 1085fb8a8121Smrg if constexpr (__strongly_ordered<_Tp, _Up>) 1086fb8a8121Smrg return _Strong_order{}(static_cast<_Tp&&>(__e), 1087fb8a8121Smrg static_cast<_Up&&>(__f)); 1088a448f87cSmrg else // __op_eq_lt<_Tp, _Up> 1089fb8a8121Smrg return static_cast<_Tp&&>(__e) == static_cast<_Up&&>(__f) 1090fb8a8121Smrg ? strong_ordering::equal 1091fb8a8121Smrg : static_cast<_Tp&&>(__e) < static_cast<_Up&&>(__f) 1092fb8a8121Smrg ? strong_ordering::less 1093fb8a8121Smrg : strong_ordering::greater; 1094fb8a8121Smrg } 1095fb8a8121Smrg }; 1096fb8a8121Smrg 1097fb8a8121Smrg class _Weak_fallback 1098fb8a8121Smrg { 1099fb8a8121Smrg template<typename _Tp, typename _Up> 1100fb8a8121Smrg static constexpr bool 1101fb8a8121Smrg _S_noexcept() 1102fb8a8121Smrg { 1103fb8a8121Smrg if constexpr (__weakly_ordered<_Tp, _Up>) 1104fb8a8121Smrg return _Weak_order::_S_noexcept<_Tp, _Up>(); 1105fb8a8121Smrg else 1106fb8a8121Smrg return noexcept(bool(std::declval<_Tp>() == std::declval<_Up>())) 1107fb8a8121Smrg && noexcept(bool(std::declval<_Tp>() < std::declval<_Up>())); 1108fb8a8121Smrg } 1109fb8a8121Smrg 1110fb8a8121Smrg public: 1111a448f87cSmrg template<typename _Tp, __decayed_same_as<_Tp> _Up> 1112fb8a8121Smrg requires __weakly_ordered<_Tp, _Up> || __op_eq_lt<_Tp, _Up> 1113a448f87cSmrg constexpr weak_ordering 1114*b1e83836Smrg operator() [[nodiscard]] (_Tp&& __e, _Up&& __f) const 1115fb8a8121Smrg noexcept(_S_noexcept<_Tp, _Up>()) 1116fb8a8121Smrg { 1117fb8a8121Smrg if constexpr (__weakly_ordered<_Tp, _Up>) 1118fb8a8121Smrg return _Weak_order{}(static_cast<_Tp&&>(__e), 1119fb8a8121Smrg static_cast<_Up&&>(__f)); 1120a448f87cSmrg else // __op_eq_lt<_Tp, _Up> 1121fb8a8121Smrg return static_cast<_Tp&&>(__e) == static_cast<_Up&&>(__f) 1122fb8a8121Smrg ? weak_ordering::equivalent 1123fb8a8121Smrg : static_cast<_Tp&&>(__e) < static_cast<_Up&&>(__f) 1124fb8a8121Smrg ? weak_ordering::less 1125fb8a8121Smrg : weak_ordering::greater; 1126fb8a8121Smrg } 1127fb8a8121Smrg }; 1128fb8a8121Smrg 1129a448f87cSmrg // _GLIBCXX_RESOLVE_LIB_DEFECTS 1130a448f87cSmrg // 3465. compare_partial_order_fallback requires F < E 1131a448f87cSmrg template<typename _Tp, typename _Up> 1132a448f87cSmrg concept __op_eq_lt_lt = __op_eq_lt<_Tp, _Up> 1133a448f87cSmrg && requires(_Tp&& __t, _Up&& __u) 1134a448f87cSmrg { 1135a448f87cSmrg { static_cast<_Up&&>(__u) < static_cast<_Tp&&>(__t) } 1136a448f87cSmrg -> convertible_to<bool>; 1137a448f87cSmrg }; 1138a448f87cSmrg 1139fb8a8121Smrg class _Partial_fallback 1140fb8a8121Smrg { 1141fb8a8121Smrg template<typename _Tp, typename _Up> 1142fb8a8121Smrg static constexpr bool 1143fb8a8121Smrg _S_noexcept() 1144fb8a8121Smrg { 1145fb8a8121Smrg if constexpr (__partially_ordered<_Tp, _Up>) 1146fb8a8121Smrg return _Partial_order::_S_noexcept<_Tp, _Up>(); 1147fb8a8121Smrg else 1148fb8a8121Smrg return noexcept(bool(std::declval<_Tp>() == std::declval<_Up>())) 1149fb8a8121Smrg && noexcept(bool(std::declval<_Tp>() < std::declval<_Up>())); 1150fb8a8121Smrg } 1151fb8a8121Smrg 1152fb8a8121Smrg public: 1153a448f87cSmrg template<typename _Tp, __decayed_same_as<_Tp> _Up> 1154a448f87cSmrg requires __partially_ordered<_Tp, _Up> || __op_eq_lt_lt<_Tp, _Up> 1155a448f87cSmrg constexpr partial_ordering 1156*b1e83836Smrg operator() [[nodiscard]] (_Tp&& __e, _Up&& __f) const 1157fb8a8121Smrg noexcept(_S_noexcept<_Tp, _Up>()) 1158fb8a8121Smrg { 1159fb8a8121Smrg if constexpr (__partially_ordered<_Tp, _Up>) 1160fb8a8121Smrg return _Partial_order{}(static_cast<_Tp&&>(__e), 1161fb8a8121Smrg static_cast<_Up&&>(__f)); 1162a448f87cSmrg else // __op_eq_lt_lt<_Tp, _Up> 1163fb8a8121Smrg return static_cast<_Tp&&>(__e) == static_cast<_Up&&>(__f) 1164fb8a8121Smrg ? partial_ordering::equivalent 1165fb8a8121Smrg : static_cast<_Tp&&>(__e) < static_cast<_Up&&>(__f) 1166fb8a8121Smrg ? partial_ordering::less 1167fb8a8121Smrg : static_cast<_Up&&>(__f) < static_cast<_Tp&&>(__e) 1168fb8a8121Smrg ? partial_ordering::greater 1169fb8a8121Smrg : partial_ordering::unordered; 1170fb8a8121Smrg } 1171fb8a8121Smrg }; 1172fb8a8121Smrg } // namespace __cmp_cust 1173fb8a8121Smrg 1174fb8a8121Smrg // [cmp.alg], comparison algorithms 1175fb8a8121Smrg inline namespace __cmp_alg 1176fb8a8121Smrg { 1177fb8a8121Smrg inline constexpr __cmp_cust::_Strong_order strong_order{}; 1178fb8a8121Smrg 1179fb8a8121Smrg inline constexpr __cmp_cust::_Weak_order weak_order{}; 1180fb8a8121Smrg 1181fb8a8121Smrg inline constexpr __cmp_cust::_Partial_order partial_order{}; 1182fb8a8121Smrg 1183fb8a8121Smrg inline constexpr __cmp_cust::_Strong_fallback 1184fb8a8121Smrg compare_strong_order_fallback{}; 1185fb8a8121Smrg 1186fb8a8121Smrg inline constexpr __cmp_cust::_Weak_fallback 1187fb8a8121Smrg compare_weak_order_fallback{}; 1188fb8a8121Smrg 1189fb8a8121Smrg inline constexpr __cmp_cust::_Partial_fallback 1190fb8a8121Smrg compare_partial_order_fallback{}; 1191fb8a8121Smrg } 1192fb8a8121Smrg 1193fb8a8121Smrg namespace __detail 1194fb8a8121Smrg { 1195fb8a8121Smrg // [expos.only.func] synth-three-way 1196fb8a8121Smrg inline constexpr struct _Synth3way 1197fb8a8121Smrg { 1198fb8a8121Smrg template<typename _Tp, typename _Up> 1199fb8a8121Smrg static constexpr bool 1200fb8a8121Smrg _S_noexcept(const _Tp* __t = nullptr, const _Up* __u = nullptr) 1201fb8a8121Smrg { 1202fb8a8121Smrg if constexpr (three_way_comparable_with<_Tp, _Up>) 1203fb8a8121Smrg return noexcept(*__t <=> *__u); 1204fb8a8121Smrg else 1205fb8a8121Smrg return noexcept(*__t < *__u) && noexcept(*__u < *__t); 1206fb8a8121Smrg } 1207fb8a8121Smrg 1208fb8a8121Smrg template<typename _Tp, typename _Up> 1209*b1e83836Smrg [[nodiscard]] 1210fb8a8121Smrg constexpr auto 1211fb8a8121Smrg operator()(const _Tp& __t, const _Up& __u) const 1212fb8a8121Smrg noexcept(_S_noexcept<_Tp, _Up>()) 1213fb8a8121Smrg requires requires 1214fb8a8121Smrg { 1215fb8a8121Smrg { __t < __u } -> __boolean_testable; 1216fb8a8121Smrg { __u < __t } -> __boolean_testable; 1217fb8a8121Smrg } 1218fb8a8121Smrg { 1219fb8a8121Smrg if constexpr (three_way_comparable_with<_Tp, _Up>) 1220fb8a8121Smrg return __t <=> __u; 1221fb8a8121Smrg else 1222fb8a8121Smrg { 1223fb8a8121Smrg if (__t < __u) 1224fb8a8121Smrg return weak_ordering::less; 1225fb8a8121Smrg else if (__u < __t) 1226fb8a8121Smrg return weak_ordering::greater; 1227fb8a8121Smrg else 1228fb8a8121Smrg return weak_ordering::equivalent; 1229fb8a8121Smrg } 1230fb8a8121Smrg } 1231fb8a8121Smrg } __synth3way = {}; 1232fb8a8121Smrg 1233fb8a8121Smrg // [expos.only.func] synth-three-way-result 1234fb8a8121Smrg template<typename _Tp, typename _Up = _Tp> 1235fb8a8121Smrg using __synth3way_t 1236fb8a8121Smrg = decltype(__detail::__synth3way(std::declval<_Tp&>(), 1237fb8a8121Smrg std::declval<_Up&>())); 1238fb8a8121Smrg } // namespace __detail 1239fb8a8121Smrg#endif // concepts 1240fb8a8121Smrg} // namespace std 1241fb8a8121Smrg 1242fb8a8121Smrg#pragma GCC visibility pop 1243fb8a8121Smrg 1244fb8a8121Smrg#endif // C++20 1245fb8a8121Smrg 1246fb8a8121Smrg#endif // _COMPARE 1247