Fix declarations of _DINFINITY, _SINFINITY and _SQNAN
[official-gcc.git] / libstdc++-v3 / libsupc++ / compare
blobe08a3ce922fee043933e85da86b52a5bb4de0749
1 // -*- C++ -*- operator<=> three-way comparison support.
3 // Copyright (C) 2019-2022 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     [[nodiscard]]
90     friend constexpr bool
91     operator==(partial_ordering __v, __cmp_cat::__unspec) noexcept
92     { return __v._M_value == 0; }
94     [[nodiscard]]
95     friend constexpr bool
96     operator==(partial_ordering, partial_ordering) noexcept = default;
98     [[nodiscard]]
99     friend constexpr bool
100     operator< (partial_ordering __v, __cmp_cat::__unspec) noexcept
101     { return __v._M_value == -1; }
103     [[nodiscard]]
104     friend constexpr bool
105     operator> (partial_ordering __v, __cmp_cat::__unspec) noexcept
106     { return __v._M_value == 1; }
108     [[nodiscard]]
109     friend constexpr bool
110     operator<=(partial_ordering __v, __cmp_cat::__unspec) noexcept
111     { return __v._M_value <= 0; }
113     [[nodiscard]]
114     friend constexpr bool
115     operator>=(partial_ordering __v, __cmp_cat::__unspec) noexcept
116     { return __cmp_cat::type(__v._M_value & 1) == __v._M_value; }
118     [[nodiscard]]
119     friend constexpr bool
120     operator< (__cmp_cat::__unspec, partial_ordering __v) noexcept
121     { return __v._M_value == 1; }
123     [[nodiscard]]
124     friend constexpr bool
125     operator> (__cmp_cat::__unspec, partial_ordering __v) noexcept
126     { return __v._M_value == -1; }
128     [[nodiscard]]
129     friend constexpr bool
130     operator<=(__cmp_cat::__unspec, partial_ordering __v) noexcept
131     { return __cmp_cat::type(__v._M_value & 1) == __v._M_value; }
133     [[nodiscard]]
134     friend constexpr bool
135     operator>=(__cmp_cat::__unspec, partial_ordering __v) noexcept
136     { return 0 >= __v._M_value; }
138     [[nodiscard]]
139     friend constexpr partial_ordering
140     operator<=>(partial_ordering __v, __cmp_cat::__unspec) noexcept
141     { return __v; }
143     [[nodiscard]]
144     friend constexpr partial_ordering
145     operator<=>(__cmp_cat::__unspec, partial_ordering __v) noexcept
146     {
147       if (__v._M_value & 1)
148         return partial_ordering(__cmp_cat::_Ord(-__v._M_value));
149       else
150         return __v;
151     }
152   };
154   // valid values' definitions
155   inline constexpr partial_ordering
156   partial_ordering::less(__cmp_cat::_Ord::less);
158   inline constexpr partial_ordering
159   partial_ordering::equivalent(__cmp_cat::_Ord::equivalent);
161   inline constexpr partial_ordering
162   partial_ordering::greater(__cmp_cat::_Ord::greater);
164   inline constexpr partial_ordering
165   partial_ordering::unordered(__cmp_cat::_Ncmp::_Unordered);
167   class weak_ordering
168   {
169     __cmp_cat::type _M_value;
171     constexpr explicit
172     weak_ordering(__cmp_cat::_Ord __v) noexcept : _M_value(__cmp_cat::type(__v))
173     { }
175     friend class strong_ordering;
177   public:
178     // valid values
179     static const weak_ordering less;
180     static const weak_ordering equivalent;
181     static const weak_ordering greater;
183     [[nodiscard]]
184     constexpr operator partial_ordering() const noexcept
185     { return partial_ordering(__cmp_cat::_Ord(_M_value)); }
187     // comparisons
188     [[nodiscard]]
189     friend constexpr bool
190     operator==(weak_ordering __v, __cmp_cat::__unspec) noexcept
191     { return __v._M_value == 0; }
193     [[nodiscard]]
194     friend constexpr bool
195     operator==(weak_ordering, weak_ordering) noexcept = default;
197     [[nodiscard]]
198     friend constexpr bool
199     operator< (weak_ordering __v, __cmp_cat::__unspec) noexcept
200     { return __v._M_value < 0; }
202     [[nodiscard]]
203     friend constexpr bool
204     operator> (weak_ordering __v, __cmp_cat::__unspec) noexcept
205     { return __v._M_value > 0; }
207     [[nodiscard]]
208     friend constexpr bool
209     operator<=(weak_ordering __v, __cmp_cat::__unspec) noexcept
210     { return __v._M_value <= 0; }
212     [[nodiscard]]
213     friend constexpr bool
214     operator>=(weak_ordering __v, __cmp_cat::__unspec) noexcept
215     { return __v._M_value >= 0; }
217     [[nodiscard]]
218     friend constexpr bool
219     operator< (__cmp_cat::__unspec, weak_ordering __v) noexcept
220     { return 0 < __v._M_value; }
222     [[nodiscard]]
223     friend constexpr bool
224     operator> (__cmp_cat::__unspec, weak_ordering __v) noexcept
225     { return 0 > __v._M_value; }
227     [[nodiscard]]
228     friend constexpr bool
229     operator<=(__cmp_cat::__unspec, weak_ordering __v) noexcept
230     { return 0 <= __v._M_value; }
232     [[nodiscard]]
233     friend constexpr bool
234     operator>=(__cmp_cat::__unspec, weak_ordering __v) noexcept
235     { return 0 >= __v._M_value; }
237     [[nodiscard]]
238     friend constexpr weak_ordering
239     operator<=>(weak_ordering __v, __cmp_cat::__unspec) noexcept
240     { return __v; }
242     [[nodiscard]]
243     friend constexpr weak_ordering
244     operator<=>(__cmp_cat::__unspec, weak_ordering __v) noexcept
245     { return weak_ordering(__cmp_cat::_Ord(-__v._M_value)); }
246   };
248   // valid values' definitions
249   inline constexpr weak_ordering
250   weak_ordering::less(__cmp_cat::_Ord::less);
252   inline constexpr weak_ordering
253   weak_ordering::equivalent(__cmp_cat::_Ord::equivalent);
255   inline constexpr weak_ordering
256   weak_ordering::greater(__cmp_cat::_Ord::greater);
258   class strong_ordering
259   {
260     __cmp_cat::type _M_value;
262     constexpr explicit
263     strong_ordering(__cmp_cat::_Ord __v) noexcept
264     : _M_value(__cmp_cat::type(__v))
265     { }
267   public:
268     // valid values
269     static const strong_ordering less;
270     static const strong_ordering equal;
271     static const strong_ordering equivalent;
272     static const strong_ordering greater;
274     [[nodiscard]]
275     constexpr operator partial_ordering() const noexcept
276     { return partial_ordering(__cmp_cat::_Ord(_M_value)); }
278     [[nodiscard]]
279     constexpr operator weak_ordering() const noexcept
280     { return weak_ordering(__cmp_cat::_Ord(_M_value)); }
282     // comparisons
283     [[nodiscard]]
284     friend constexpr bool
285     operator==(strong_ordering __v, __cmp_cat::__unspec) noexcept
286     { return __v._M_value == 0; }
288     [[nodiscard]]
289     friend constexpr bool
290     operator==(strong_ordering, strong_ordering) noexcept = default;
292     [[nodiscard]]
293     friend constexpr bool
294     operator< (strong_ordering __v, __cmp_cat::__unspec) noexcept
295     { return __v._M_value < 0; }
297     [[nodiscard]]
298     friend constexpr bool
299     operator> (strong_ordering __v, __cmp_cat::__unspec) noexcept
300     { return __v._M_value > 0; }
302     [[nodiscard]]
303     friend constexpr bool
304     operator<=(strong_ordering __v, __cmp_cat::__unspec) noexcept
305     { return __v._M_value <= 0; }
307     [[nodiscard]]
308     friend constexpr bool
309     operator>=(strong_ordering __v, __cmp_cat::__unspec) noexcept
310     { return __v._M_value >= 0; }
312     [[nodiscard]]
313     friend constexpr bool
314     operator< (__cmp_cat::__unspec, strong_ordering __v) noexcept
315     { return 0 < __v._M_value; }
317     [[nodiscard]]
318     friend constexpr bool
319     operator> (__cmp_cat::__unspec, strong_ordering __v) noexcept
320     { return 0 > __v._M_value; }
322     [[nodiscard]]
323     friend constexpr bool
324     operator<=(__cmp_cat::__unspec, strong_ordering __v) noexcept
325     { return 0 <= __v._M_value; }
327     [[nodiscard]]
328     friend constexpr bool
329     operator>=(__cmp_cat::__unspec, strong_ordering __v) noexcept
330     { return 0 >= __v._M_value; }
332     [[nodiscard]]
333     friend constexpr strong_ordering
334     operator<=>(strong_ordering __v, __cmp_cat::__unspec) noexcept
335     { return __v; }
337     [[nodiscard]]
338     friend constexpr strong_ordering
339     operator<=>(__cmp_cat::__unspec, strong_ordering __v) noexcept
340     { return strong_ordering(__cmp_cat::_Ord(-__v._M_value)); }
341   };
343   // valid values' definitions
344   inline constexpr strong_ordering
345   strong_ordering::less(__cmp_cat::_Ord::less);
347   inline constexpr strong_ordering
348   strong_ordering::equal(__cmp_cat::_Ord::equivalent);
350   inline constexpr strong_ordering
351   strong_ordering::equivalent(__cmp_cat::_Ord::equivalent);
353   inline constexpr strong_ordering
354   strong_ordering::greater(__cmp_cat::_Ord::greater);
357   // named comparison functions
358   [[nodiscard]]
359   constexpr bool
360   is_eq(partial_ordering __cmp) noexcept
361   { return __cmp == 0; }
363   [[nodiscard]]
364   constexpr bool
365   is_neq(partial_ordering __cmp) noexcept
366   { return __cmp != 0; }
368   [[nodiscard]]
369   constexpr bool
370   is_lt  (partial_ordering __cmp) noexcept
371   { return __cmp < 0; }
373   [[nodiscard]]
374   constexpr bool
375   is_lteq(partial_ordering __cmp) noexcept
376   { return __cmp <= 0; }
378   [[nodiscard]]
379   constexpr bool
380   is_gt  (partial_ordering __cmp) noexcept
381   { return __cmp > 0; }
383   [[nodiscard]]
384   constexpr bool
385   is_gteq(partial_ordering __cmp) noexcept
386   { return __cmp >= 0; }
388   namespace __detail
389   {
390     template<typename _Tp>
391       inline constexpr unsigned __cmp_cat_id = 1;
392     template<>
393       inline constexpr unsigned __cmp_cat_id<partial_ordering> = 2;
394     template<>
395       inline constexpr unsigned __cmp_cat_id<weak_ordering> = 4;
396     template<>
397       inline constexpr unsigned __cmp_cat_id<strong_ordering> = 8;
399     template<typename... _Ts>
400       constexpr auto __common_cmp_cat()
401       {
402         constexpr unsigned __cats = (__cmp_cat_id<_Ts> | ...);
403         // If any Ti is not a comparison category type, U is void.
404         if constexpr (__cats & 1)
405           return;
406         // Otherwise, if at least one Ti is std::partial_ordering,
407         // U is std::partial_ordering.
408         else if constexpr (bool(__cats & __cmp_cat_id<partial_ordering>))
409           return partial_ordering::equivalent;
410         // Otherwise, if at least one Ti is std::weak_ordering,
411         // U is std::weak_ordering.
412         else if constexpr (bool(__cats & __cmp_cat_id<weak_ordering>))
413           return weak_ordering::equivalent;
414         // Otherwise, U is std::strong_ordering.
415         else
416           return strong_ordering::equivalent;
417       }
418   } // namespace __detail
420   // [cmp.common], common comparison category type
421   template<typename... _Ts>
422     struct common_comparison_category
423     {
424       using type = decltype(__detail::__common_cmp_cat<_Ts...>());
425     };
427   // Partial specializations for one and zero argument cases.
429   template<typename _Tp>
430     struct common_comparison_category<_Tp>
431     { using type = void; };
433   template<>
434     struct common_comparison_category<partial_ordering>
435     { using type = partial_ordering; };
437   template<>
438     struct common_comparison_category<weak_ordering>
439     { using type = weak_ordering; };
441   template<>
442     struct common_comparison_category<strong_ordering>
443     { using type = strong_ordering; };
445   template<>
446     struct common_comparison_category<>
447     { using type = strong_ordering; };
449   template<typename... _Ts>
450     using common_comparison_category_t
451       = typename common_comparison_category<_Ts...>::type;
453 #if __cpp_lib_concepts
454   namespace __detail
455   {
456     template<typename _Tp, typename _Cat>
457       concept __compares_as
458         = same_as<common_comparison_category_t<_Tp, _Cat>, _Cat>;
459   } // namespace __detail
461   // [cmp.concept], concept three_way_comparable
462   template<typename _Tp, typename _Cat = partial_ordering>
463     concept three_way_comparable
464       = __detail::__weakly_eq_cmp_with<_Tp, _Tp>
465       && __detail::__partially_ordered_with<_Tp, _Tp>
466       && requires(const remove_reference_t<_Tp>& __a,
467                   const remove_reference_t<_Tp>& __b)
468       {
469         { __a <=> __b } -> __detail::__compares_as<_Cat>;
470       };
472   template<typename _Tp, typename _Up, typename _Cat = partial_ordering>
473     concept three_way_comparable_with
474       = three_way_comparable<_Tp, _Cat>
475       && three_way_comparable<_Up, _Cat>
476       && common_reference_with<const remove_reference_t<_Tp>&,
477                                const remove_reference_t<_Up>&>
478       && three_way_comparable<
479           common_reference_t<const remove_reference_t<_Tp>&,
480                              const remove_reference_t<_Up>&>, _Cat>
481       && __detail::__weakly_eq_cmp_with<_Tp, _Up>
482       && __detail::__partially_ordered_with<_Tp, _Up>
483       && requires(const remove_reference_t<_Tp>& __t,
484                   const remove_reference_t<_Up>& __u)
485       {
486         { __t <=> __u } -> __detail::__compares_as<_Cat>;
487         { __u <=> __t } -> __detail::__compares_as<_Cat>;
488       };
490   namespace __detail
491   {
492     template<typename _Tp, typename _Up>
493       using __cmp3way_res_t
494         = decltype(std::declval<_Tp>() <=> std::declval<_Up>());
496     // Implementation of std::compare_three_way_result.
497     // It is undefined for a program to add specializations of
498     // std::compare_three_way_result, so the std::compare_three_way_result_t
499     // alias ignores std::compare_three_way_result and uses
500     // __detail::__cmp3way_res_impl directly instead.
501     template<typename _Tp, typename _Up>
502       struct __cmp3way_res_impl
503       { };
505     template<typename _Tp, typename _Up>
506       requires requires { typename __cmp3way_res_t<__cref<_Tp>, __cref<_Up>>; }
507       struct __cmp3way_res_impl<_Tp, _Up>
508       {
509         using type = __cmp3way_res_t<__cref<_Tp>, __cref<_Up>>;
510       };
511   } // namespace __detail
513   /// [cmp.result], result of three-way comparison
514   template<typename _Tp, typename _Up = _Tp>
515     struct compare_three_way_result
516     : __detail::__cmp3way_res_impl<_Tp, _Up>
517     { };
519   /// [cmp.result], result of three-way comparison
520   template<typename _Tp, typename _Up = _Tp>
521     using compare_three_way_result_t
522       = typename __detail::__cmp3way_res_impl<_Tp, _Up>::type;
524   namespace __detail
525   {
526     // BUILTIN-PTR-THREE-WAY(T, U)
527     // This determines whether t <=> u results in a call to a built-in
528     // operator<=> comparing pointers. It doesn't work for function pointers
529     // (PR 93628).
530     template<typename _Tp, typename _Up>
531       concept __3way_builtin_ptr_cmp
532         = requires(_Tp&& __t, _Up&& __u)
533           { static_cast<_Tp&&>(__t) <=> static_cast<_Up&&>(__u); }
534           && convertible_to<_Tp, const volatile void*>
535           && convertible_to<_Up, const volatile void*>
536           && ! requires(_Tp&& __t, _Up&& __u)
537           { operator<=>(static_cast<_Tp&&>(__t), static_cast<_Up&&>(__u)); }
538           && ! requires(_Tp&& __t, _Up&& __u)
539           { static_cast<_Tp&&>(__t).operator<=>(static_cast<_Up&&>(__u)); };
540   } // namespace __detail
542   // _GLIBCXX_RESOLVE_LIB_DEFECTS
543   // 3530 BUILTIN-PTR-MEOW should not opt the type out of syntactic checks
545   // [cmp.object], typename compare_three_way
546   struct compare_three_way
547   {
548     template<typename _Tp, typename _Up>
549       requires three_way_comparable_with<_Tp, _Up>
550       constexpr auto
551       operator() [[nodiscard]] (_Tp&& __t, _Up&& __u) const
552       noexcept(noexcept(std::declval<_Tp>() <=> std::declval<_Up>()))
553       {
554         if constexpr (__detail::__3way_builtin_ptr_cmp<_Tp, _Up>)
555           {
556             auto __pt = static_cast<const volatile void*>(__t);
557             auto __pu = static_cast<const volatile void*>(__u);
558             if (std::__is_constant_evaluated())
559               return __pt <=> __pu;
560             auto __it = reinterpret_cast<__UINTPTR_TYPE__>(__pt);
561             auto __iu = reinterpret_cast<__UINTPTR_TYPE__>(__pu);
562             return __it <=> __iu;
563           }
564         else
565           return static_cast<_Tp&&>(__t) <=> static_cast<_Up&&>(__u);
566       }
568     using is_transparent = void;
569   };
571   namespace __cmp_cust
572   {
573     template<floating_point _Tp>
574       constexpr weak_ordering
575       __fp_weak_ordering(_Tp __e, _Tp __f)
576       {
577         // Returns an integer with the same sign as the argument, and magnitude
578         // indicating the classification: zero=1 subnorm=2 norm=3 inf=4 nan=5
579         auto __cat = [](_Tp __fp) -> int {
580           const int __sign = __builtin_signbit(__fp) ? -1 : 1;
581           if (__builtin_isnormal(__fp))
582             return (__fp == 0 ? 1 : 3) * __sign;
583           if (__builtin_isnan(__fp))
584             return 5 * __sign;
585           if (int __inf = __builtin_isinf_sign(__fp))
586             return 4 * __inf;
587           return 2 * __sign;
588         };
590         auto __po = __e <=> __f;
591         if (is_lt(__po))
592           return weak_ordering::less;
593         else if (is_gt(__po))
594           return weak_ordering::greater;
595         else if (__po == partial_ordering::equivalent)
596           return weak_ordering::equivalent;
597         else  // unordered, at least one argument is NaN
598           {
599             // return -1 for negative nan, +1 for positive nan, 0 otherwise.
600             auto __isnan_sign = [](_Tp __fp) -> int {
601               return __builtin_isnan(__fp)
602                 ? __builtin_signbit(__fp) ? -1 : 1
603                 : 0;
604             };
605             auto __ord = __isnan_sign(__e) <=> __isnan_sign(__f);
606             if (is_eq(__ord))
607               return weak_ordering::equivalent;
608             else if (is_lt(__ord))
609               return weak_ordering::less;
610             else
611               return weak_ordering::greater;
612           }
613       }
615     template<typename _Tp, typename _Up>
616       concept __adl_strong = requires(_Tp&& __t, _Up&& __u)
617         {
618           strong_ordering(strong_order(static_cast<_Tp&&>(__t),
619                                        static_cast<_Up&&>(__u)));
620         };
622     template<typename _Tp, typename _Up>
623       concept __adl_weak = requires(_Tp&& __t, _Up&& __u)
624         {
625           weak_ordering(weak_order(static_cast<_Tp&&>(__t),
626                                    static_cast<_Up&&>(__u)));
627         };
629     template<typename _Tp, typename _Up>
630       concept __adl_partial = requires(_Tp&& __t, _Up&& __u)
631         {
632           partial_ordering(partial_order(static_cast<_Tp&&>(__t),
633                                          static_cast<_Up&&>(__u)));
634         };
636     template<typename _Ord, typename _Tp, typename _Up>
637       concept __cmp3way = requires(_Tp&& __t, _Up&& __u, compare_three_way __c)
638         {
639           _Ord(__c(static_cast<_Tp&&>(__t), static_cast<_Up&&>(__u)));
640         };
642     template<typename _Tp, typename _Up>
643       concept __strongly_ordered
644         = __adl_strong<_Tp, _Up>
645           // FIXME: || floating_point<remove_reference_t<_Tp>>
646           || __cmp3way<strong_ordering, _Tp, _Up>;
648     template<typename _Tp, typename _Up>
649       concept __decayed_same_as = same_as<decay_t<_Tp>, decay_t<_Up>>;
651     class _Strong_order
652     {
653       template<typename _Tp, typename _Up>
654         static constexpr bool
655         _S_noexcept()
656         {
657           if constexpr (floating_point<decay_t<_Tp>>)
658             return true;
659           else if constexpr (__adl_strong<_Tp, _Up>)
660             return noexcept(strong_ordering(strong_order(std::declval<_Tp>(),
661                                                          std::declval<_Up>())));
662           else if constexpr (__cmp3way<strong_ordering, _Tp, _Up>)
663             return noexcept(compare_three_way()(std::declval<_Tp>(),
664                                                 std::declval<_Up>()));
665         }
667       friend class _Weak_order;
668       friend class _Strong_fallback;
670     public:
671       template<typename _Tp, __decayed_same_as<_Tp> _Up>
672         requires __strongly_ordered<_Tp, _Up>
673         constexpr strong_ordering
674         operator() [[nodiscard]] (_Tp&& __e, _Up&& __f) const
675         noexcept(_S_noexcept<_Tp, _Up>())
676         {
677           /* FIXME:
678           if constexpr (floating_point<decay_t<_Tp>>)
679             return __cmp_cust::__fp_strong_order(__e, __f);
680           else */ if constexpr (__adl_strong<_Tp, _Up>)
681             return strong_ordering(strong_order(static_cast<_Tp&&>(__e),
682                                                 static_cast<_Up&&>(__f)));
683           else if constexpr (__cmp3way<strong_ordering, _Tp, _Up>)
684             return compare_three_way()(static_cast<_Tp&&>(__e),
685                                        static_cast<_Up&&>(__f));
686         }
687     };
689     template<typename _Tp, typename _Up>
690       concept __weakly_ordered
691         = floating_point<remove_reference_t<_Tp>>
692           || __adl_weak<_Tp, _Up>
693           || __cmp3way<weak_ordering, _Tp, _Up>
694           || __strongly_ordered<_Tp, _Up>;
696     class _Weak_order
697     {
698       template<typename _Tp, typename _Up>
699         static constexpr bool
700         _S_noexcept()
701         {
702           if constexpr (floating_point<decay_t<_Tp>>)
703             return true;
704           else if constexpr (__adl_weak<_Tp, _Up>)
705             return noexcept(weak_ordering(weak_order(std::declval<_Tp>(),
706                                                      std::declval<_Up>())));
707           else if constexpr (__cmp3way<weak_ordering, _Tp, _Up>)
708             return noexcept(compare_three_way()(std::declval<_Tp>(),
709                                                 std::declval<_Up>()));
710           else if constexpr (__strongly_ordered<_Tp, _Up>)
711             return _Strong_order::_S_noexcept<_Tp, _Up>();
712         }
714       friend class _Partial_order;
715       friend class _Weak_fallback;
717     public:
718       template<typename _Tp, __decayed_same_as<_Tp> _Up>
719         requires __weakly_ordered<_Tp, _Up>
720         constexpr weak_ordering
721         operator() [[nodiscard]] (_Tp&& __e, _Up&& __f) const
722         noexcept(_S_noexcept<_Tp, _Up>())
723         {
724           if constexpr (floating_point<decay_t<_Tp>>)
725             return __cmp_cust::__fp_weak_ordering(__e, __f);
726           else if constexpr (__adl_weak<_Tp, _Up>)
727             return weak_ordering(weak_order(static_cast<_Tp&&>(__e),
728                                             static_cast<_Up&&>(__f)));
729           else if constexpr (__cmp3way<weak_ordering, _Tp, _Up>)
730             return compare_three_way()(static_cast<_Tp&&>(__e),
731                                        static_cast<_Up&&>(__f));
732           else if constexpr (__strongly_ordered<_Tp, _Up>)
733             return _Strong_order{}(static_cast<_Tp&&>(__e),
734                                    static_cast<_Up&&>(__f));
735         }
736     };
738     template<typename _Tp, typename _Up>
739       concept __partially_ordered
740         = __adl_partial<_Tp, _Up>
741         || __cmp3way<partial_ordering, _Tp, _Up>
742         || __weakly_ordered<_Tp, _Up>;
744     class _Partial_order
745     {
746       template<typename _Tp, typename _Up>
747         static constexpr bool
748         _S_noexcept()
749         {
750           if constexpr (__adl_partial<_Tp, _Up>)
751             return noexcept(partial_ordering(partial_order(std::declval<_Tp>(),
752                                                          std::declval<_Up>())));
753           else if constexpr (__cmp3way<partial_ordering, _Tp, _Up>)
754             return noexcept(compare_three_way()(std::declval<_Tp>(),
755                                                 std::declval<_Up>()));
756           else if constexpr (__weakly_ordered<_Tp, _Up>)
757             return _Weak_order::_S_noexcept<_Tp, _Up>();
758         }
760       friend class _Partial_fallback;
762     public:
763       template<typename _Tp, __decayed_same_as<_Tp> _Up>
764         requires __partially_ordered<_Tp, _Up>
765         constexpr partial_ordering
766         operator() [[nodiscard]] (_Tp&& __e, _Up&& __f) const
767         noexcept(_S_noexcept<_Tp, _Up>())
768         {
769           if constexpr (__adl_partial<_Tp, _Up>)
770             return partial_ordering(partial_order(static_cast<_Tp&&>(__e),
771                                                   static_cast<_Up&&>(__f)));
772           else if constexpr (__cmp3way<partial_ordering, _Tp, _Up>)
773             return compare_three_way()(static_cast<_Tp&&>(__e),
774                                        static_cast<_Up&&>(__f));
775           else if constexpr (__weakly_ordered<_Tp, _Up>)
776             return _Weak_order{}(static_cast<_Tp&&>(__e),
777                                  static_cast<_Up&&>(__f));
778         }
779     };
781     template<typename _Tp, typename _Up>
782       concept __op_eq_lt = requires(_Tp&& __t, _Up&& __u)
783         {
784           { static_cast<_Tp&&>(__t) == static_cast<_Up&&>(__u) }
785             -> convertible_to<bool>;
786           { static_cast<_Tp&&>(__t) < static_cast<_Up&&>(__u) }
787             -> convertible_to<bool>;
788         };
790     class _Strong_fallback
791     {
792       template<typename _Tp, typename _Up>
793         static constexpr bool
794         _S_noexcept()
795         {
796           if constexpr (__strongly_ordered<_Tp, _Up>)
797             return _Strong_order::_S_noexcept<_Tp, _Up>();
798           else
799             return noexcept(bool(std::declval<_Tp>() == std::declval<_Up>()))
800               && noexcept(bool(std::declval<_Tp>() < std::declval<_Up>()));
801         }
803     public:
804       template<typename _Tp, __decayed_same_as<_Tp> _Up>
805         requires __strongly_ordered<_Tp, _Up> || __op_eq_lt<_Tp, _Up>
806         constexpr strong_ordering
807         operator() [[nodiscard]] (_Tp&& __e, _Up&& __f) const
808         noexcept(_S_noexcept<_Tp, _Up>())
809         {
810           if constexpr (__strongly_ordered<_Tp, _Up>)
811             return _Strong_order{}(static_cast<_Tp&&>(__e),
812                                    static_cast<_Up&&>(__f));
813           else // __op_eq_lt<_Tp, _Up>
814             return static_cast<_Tp&&>(__e) == static_cast<_Up&&>(__f)
815               ? strong_ordering::equal
816               : static_cast<_Tp&&>(__e) < static_cast<_Up&&>(__f)
817               ? strong_ordering::less
818               : strong_ordering::greater;
819         }
820     };
822     class _Weak_fallback
823     {
824       template<typename _Tp, typename _Up>
825         static constexpr bool
826         _S_noexcept()
827         {
828           if constexpr (__weakly_ordered<_Tp, _Up>)
829             return _Weak_order::_S_noexcept<_Tp, _Up>();
830           else
831             return noexcept(bool(std::declval<_Tp>() == std::declval<_Up>()))
832               && noexcept(bool(std::declval<_Tp>() < std::declval<_Up>()));
833         }
835     public:
836       template<typename _Tp, __decayed_same_as<_Tp> _Up>
837         requires __weakly_ordered<_Tp, _Up> || __op_eq_lt<_Tp, _Up>
838         constexpr weak_ordering
839         operator() [[nodiscard]] (_Tp&& __e, _Up&& __f) const
840         noexcept(_S_noexcept<_Tp, _Up>())
841         {
842           if constexpr (__weakly_ordered<_Tp, _Up>)
843             return _Weak_order{}(static_cast<_Tp&&>(__e),
844                                  static_cast<_Up&&>(__f));
845           else // __op_eq_lt<_Tp, _Up>
846             return static_cast<_Tp&&>(__e) == static_cast<_Up&&>(__f)
847               ? weak_ordering::equivalent
848               : static_cast<_Tp&&>(__e) < static_cast<_Up&&>(__f)
849               ? weak_ordering::less
850               : weak_ordering::greater;
851         }
852     };
854     // _GLIBCXX_RESOLVE_LIB_DEFECTS
855     // 3465. compare_partial_order_fallback requires F < E
856     template<typename _Tp, typename _Up>
857       concept __op_eq_lt_lt = __op_eq_lt<_Tp, _Up>
858         && requires(_Tp&& __t, _Up&& __u)
859         {
860           { static_cast<_Up&&>(__u) < static_cast<_Tp&&>(__t) }
861             -> convertible_to<bool>;
862         };
864     class _Partial_fallback
865     {
866       template<typename _Tp, typename _Up>
867         static constexpr bool
868         _S_noexcept()
869         {
870           if constexpr (__partially_ordered<_Tp, _Up>)
871             return _Partial_order::_S_noexcept<_Tp, _Up>();
872           else
873             return noexcept(bool(std::declval<_Tp>() == std::declval<_Up>()))
874               && noexcept(bool(std::declval<_Tp>() < std::declval<_Up>()));
875         }
877     public:
878       template<typename _Tp, __decayed_same_as<_Tp> _Up>
879         requires __partially_ordered<_Tp, _Up> || __op_eq_lt_lt<_Tp, _Up>
880         constexpr partial_ordering
881         operator() [[nodiscard]] (_Tp&& __e, _Up&& __f) const
882         noexcept(_S_noexcept<_Tp, _Up>())
883         {
884           if constexpr (__partially_ordered<_Tp, _Up>)
885             return _Partial_order{}(static_cast<_Tp&&>(__e),
886                                     static_cast<_Up&&>(__f));
887           else // __op_eq_lt_lt<_Tp, _Up>
888             return static_cast<_Tp&&>(__e) == static_cast<_Up&&>(__f)
889               ? partial_ordering::equivalent
890               : static_cast<_Tp&&>(__e) < static_cast<_Up&&>(__f)
891               ? partial_ordering::less
892               : static_cast<_Up&&>(__f) < static_cast<_Tp&&>(__e)
893               ? partial_ordering::greater
894               : partial_ordering::unordered;
895         }
896     };
897   } // namespace __cmp_cust
899   // [cmp.alg], comparison algorithms
900   inline namespace __cmp_alg
901   {
902     inline constexpr __cmp_cust::_Strong_order strong_order{};
904     inline constexpr __cmp_cust::_Weak_order weak_order{};
906     inline constexpr __cmp_cust::_Partial_order partial_order{};
908     inline constexpr __cmp_cust::_Strong_fallback
909     compare_strong_order_fallback{};
911     inline constexpr __cmp_cust::_Weak_fallback
912     compare_weak_order_fallback{};
914     inline constexpr __cmp_cust::_Partial_fallback
915     compare_partial_order_fallback{};
916   }
918   namespace __detail
919   {
920     // [expos.only.func] synth-three-way
921     inline constexpr struct _Synth3way
922     {
923       template<typename _Tp, typename _Up>
924         static constexpr bool
925         _S_noexcept(const _Tp* __t = nullptr, const _Up* __u = nullptr)
926         {
927           if constexpr (three_way_comparable_with<_Tp, _Up>)
928             return noexcept(*__t <=> *__u);
929           else
930             return noexcept(*__t < *__u) && noexcept(*__u < *__t);
931         }
933       template<typename _Tp, typename _Up>
934         [[nodiscard]]
935         constexpr auto
936         operator()(const _Tp& __t, const _Up& __u) const
937         noexcept(_S_noexcept<_Tp, _Up>())
938         requires requires
939         {
940           { __t < __u } -> __boolean_testable;
941           { __u < __t } -> __boolean_testable;
942         }
943         {
944           if constexpr (three_way_comparable_with<_Tp, _Up>)
945             return __t <=> __u;
946           else
947             {
948               if (__t < __u)
949                 return weak_ordering::less;
950               else if (__u < __t)
951                 return weak_ordering::greater;
952               else
953                 return weak_ordering::equivalent;
954             }
955         }
956     } __synth3way = {};
958     // [expos.only.func] synth-three-way-result
959     template<typename _Tp, typename _Up = _Tp>
960       using __synth3way_t
961         = decltype(__detail::__synth3way(std::declval<_Tp&>(),
962                                          std::declval<_Up&>()));
963   } // namespace __detail
964 #endif // concepts
965 } // namespace std
967 #pragma GCC visibility pop
969 #endif // C++20
971 #endif // _COMPARE