xref: /netbsd-src/external/gpl3/gcc/dist/libstdc++-v3/libsupc++/compare (revision b1e838363e3c6fc78a55519254d99869742dd33c)
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