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