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