libstdc++
compare
Go to the documentation of this file.
1 // -*- C++ -*- operator<=> three-way comparison support.
2 
3 // Copyright (C) 2019-2020 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.
11 //
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.
16 //
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.
20 
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/>.
25 
26 /** @file compare
27  * This is a Standard C++ Library header.
28  */
29 
30 #ifndef _COMPARE
31 #define _COMPARE
32 
33 #pragma GCC system_header
34 
35 #if __cplusplus > 201703L && __cpp_impl_three_way_comparison >= 201907L
36 
37 #pragma GCC visibility push(default)
38 
39 #include <concepts>
40 
41 #if __cpp_lib_concepts
42 # define __cpp_lib_three_way_comparison 201907L
43 #endif
44 
45 namespace std
46 {
47  // [cmp.categories], comparison category types
48 
49  namespace __cmp_cat
50  {
51  using type = signed char;
52 
53  enum class _Ord : type { equivalent = 0, less = -1, greater = 1 };
54 
55  enum class _Ncmp : type { _Unordered = 2 };
56 
57  struct __unspec
58  {
59  constexpr __unspec(__unspec*) noexcept { }
60  };
61  }
62 
63  class partial_ordering
64  {
65  // less=0xff, equiv=0x00, greater=0x01, unordered=0x02
66  __cmp_cat::type _M_value;
67 
68  constexpr explicit
69  partial_ordering(__cmp_cat::_Ord __v) noexcept
70  : _M_value(__cmp_cat::type(__v))
71  { }
72 
73  constexpr explicit
74  partial_ordering(__cmp_cat::_Ncmp __v) noexcept
75  : _M_value(__cmp_cat::type(__v))
76  { }
77 
78  friend class weak_ordering;
79  friend class strong_ordering;
80 
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;
87 
88  // comparisons
89  friend constexpr bool
90  operator==(partial_ordering __v, __cmp_cat::__unspec) noexcept
91  { return __v._M_value == 0; }
92 
93  friend constexpr bool
94  operator==(partial_ordering, partial_ordering) noexcept = default;
95 
96  friend constexpr bool
97  operator< (partial_ordering __v, __cmp_cat::__unspec) noexcept
98  { return __v._M_value == -1; }
99 
100  friend constexpr bool
101  operator> (partial_ordering __v, __cmp_cat::__unspec) noexcept
102  { return __v._M_value == 1; }
103 
104  friend constexpr bool
105  operator<=(partial_ordering __v, __cmp_cat::__unspec) noexcept
106  { return __v._M_value <= 0; }
107 
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; }
111 
112  friend constexpr bool
113  operator< (__cmp_cat::__unspec, partial_ordering __v) noexcept
114  { return __v._M_value == 1; }
115 
116  friend constexpr bool
117  operator> (__cmp_cat::__unspec, partial_ordering __v) noexcept
118  { return __v._M_value == -1; }
119 
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; }
123 
124  friend constexpr bool
125  operator>=(__cmp_cat::__unspec, partial_ordering __v) noexcept
126  { return 0 >= __v._M_value; }
127 
128  friend constexpr partial_ordering
129  operator<=>(partial_ordering __v, __cmp_cat::__unspec) noexcept
130  { return __v; }
131 
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  };
141 
142  // valid values' definitions
143  inline constexpr partial_ordering
144  partial_ordering::less(__cmp_cat::_Ord::less);
145 
146  inline constexpr partial_ordering
147  partial_ordering::equivalent(__cmp_cat::_Ord::equivalent);
148 
149  inline constexpr partial_ordering
150  partial_ordering::greater(__cmp_cat::_Ord::greater);
151 
152  inline constexpr partial_ordering
153  partial_ordering::unordered(__cmp_cat::_Ncmp::_Unordered);
154 
155  class weak_ordering
156  {
157  __cmp_cat::type _M_value;
158 
159  constexpr explicit
160  weak_ordering(__cmp_cat::_Ord __v) noexcept : _M_value(__cmp_cat::type(__v))
161  { }
162 
163  friend class strong_ordering;
164 
165  public:
166  // valid values
167  static const weak_ordering less;
168  static const weak_ordering equivalent;
169  static const weak_ordering greater;
170 
171  constexpr operator partial_ordering() const noexcept
172  { return partial_ordering(__cmp_cat::_Ord(_M_value)); }
173 
174  // comparisons
175  friend constexpr bool
176  operator==(weak_ordering __v, __cmp_cat::__unspec) noexcept
177  { return __v._M_value == 0; }
178 
179  friend constexpr bool
180  operator==(weak_ordering, weak_ordering) noexcept = default;
181 
182  friend constexpr bool
183  operator< (weak_ordering __v, __cmp_cat::__unspec) noexcept
184  { return __v._M_value < 0; }
185 
186  friend constexpr bool
187  operator> (weak_ordering __v, __cmp_cat::__unspec) noexcept
188  { return __v._M_value > 0; }
189 
190  friend constexpr bool
191  operator<=(weak_ordering __v, __cmp_cat::__unspec) noexcept
192  { return __v._M_value <= 0; }
193 
194  friend constexpr bool
195  operator>=(weak_ordering __v, __cmp_cat::__unspec) noexcept
196  { return __v._M_value >= 0; }
197 
198  friend constexpr bool
199  operator< (__cmp_cat::__unspec, weak_ordering __v) noexcept
200  { return 0 < __v._M_value; }
201 
202  friend constexpr bool
203  operator> (__cmp_cat::__unspec, weak_ordering __v) noexcept
204  { return 0 > __v._M_value; }
205 
206  friend constexpr bool
207  operator<=(__cmp_cat::__unspec, weak_ordering __v) noexcept
208  { return 0 <= __v._M_value; }
209 
210  friend constexpr bool
211  operator>=(__cmp_cat::__unspec, weak_ordering __v) noexcept
212  { return 0 >= __v._M_value; }
213 
214  friend constexpr weak_ordering
215  operator<=>(weak_ordering __v, __cmp_cat::__unspec) noexcept
216  { return __v; }
217 
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  };
222 
223  // valid values' definitions
224  inline constexpr weak_ordering
225  weak_ordering::less(__cmp_cat::_Ord::less);
226 
227  inline constexpr weak_ordering
228  weak_ordering::equivalent(__cmp_cat::_Ord::equivalent);
229 
230  inline constexpr weak_ordering
231  weak_ordering::greater(__cmp_cat::_Ord::greater);
232 
233  class strong_ordering
234  {
235  __cmp_cat::type _M_value;
236 
237  constexpr explicit
238  strong_ordering(__cmp_cat::_Ord __v) noexcept
239  : _M_value(__cmp_cat::type(__v))
240  { }
241 
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;
248 
249  constexpr operator partial_ordering() const noexcept
250  { return partial_ordering(__cmp_cat::_Ord(_M_value)); }
251 
252  constexpr operator weak_ordering() const noexcept
253  { return weak_ordering(__cmp_cat::_Ord(_M_value)); }
254 
255  // comparisons
256  friend constexpr bool
257  operator==(strong_ordering __v, __cmp_cat::__unspec) noexcept
258  { return __v._M_value == 0; }
259 
260  friend constexpr bool
261  operator==(strong_ordering, strong_ordering) noexcept = default;
262 
263  friend constexpr bool
264  operator< (strong_ordering __v, __cmp_cat::__unspec) noexcept
265  { return __v._M_value < 0; }
266 
267  friend constexpr bool
268  operator> (strong_ordering __v, __cmp_cat::__unspec) noexcept
269  { return __v._M_value > 0; }
270 
271  friend constexpr bool
272  operator<=(strong_ordering __v, __cmp_cat::__unspec) noexcept
273  { return __v._M_value <= 0; }
274 
275  friend constexpr bool
276  operator>=(strong_ordering __v, __cmp_cat::__unspec) noexcept
277  { return __v._M_value >= 0; }
278 
279  friend constexpr bool
280  operator< (__cmp_cat::__unspec, strong_ordering __v) noexcept
281  { return 0 < __v._M_value; }
282 
283  friend constexpr bool
284  operator> (__cmp_cat::__unspec, strong_ordering __v) noexcept
285  { return 0 > __v._M_value; }
286 
287  friend constexpr bool
288  operator<=(__cmp_cat::__unspec, strong_ordering __v) noexcept
289  { return 0 <= __v._M_value; }
290 
291  friend constexpr bool
292  operator>=(__cmp_cat::__unspec, strong_ordering __v) noexcept
293  { return 0 >= __v._M_value; }
294 
295  friend constexpr strong_ordering
296  operator<=>(strong_ordering __v, __cmp_cat::__unspec) noexcept
297  { return __v; }
298 
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  };
303 
304  // valid values' definitions
305  inline constexpr strong_ordering
306  strong_ordering::less(__cmp_cat::_Ord::less);
307 
308  inline constexpr strong_ordering
309  strong_ordering::equal(__cmp_cat::_Ord::equivalent);
310 
311  inline constexpr strong_ordering
312  strong_ordering::equivalent(__cmp_cat::_Ord::equivalent);
313 
314  inline constexpr strong_ordering
315  strong_ordering::greater(__cmp_cat::_Ord::greater);
316 
317 
318  // named comparison functions
319  constexpr bool
320  is_eq(partial_ordering __cmp) noexcept
321  { return __cmp == 0; }
322 
323  constexpr bool
324  is_neq(partial_ordering __cmp) noexcept
325  { return __cmp != 0; }
326 
327  constexpr bool
328  is_lt (partial_ordering __cmp) noexcept
329  { return __cmp < 0; }
330 
331  constexpr bool
332  is_lteq(partial_ordering __cmp) noexcept
333  { return __cmp <= 0; }
334 
335  constexpr bool
336  is_gt (partial_ordering __cmp) noexcept
337  { return __cmp > 0; }
338 
339  constexpr bool
340  is_gteq(partial_ordering __cmp) noexcept
341  { return __cmp >= 0; }
342 
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;
353 
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
374 
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  };
381 
382  // Partial specializations for one and zero argument cases.
383 
384  template<typename _Tp>
385  struct common_comparison_category<_Tp>
386  { using type = void; };
387 
388  template<>
389  struct common_comparison_category<partial_ordering>
390  { using type = partial_ordering; };
391 
392  template<>
393  struct common_comparison_category<weak_ordering>
394  { using type = weak_ordering; };
395 
396  template<>
397  struct common_comparison_category<strong_ordering>
398  { using type = strong_ordering; };
399 
400  template<>
401  struct common_comparison_category<>
402  { using type = strong_ordering; };
403 
404  template<typename... _Ts>
405  using common_comparison_category_t
406  = typename common_comparison_category<_Ts...>::type;
407 
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
415 
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  };
426 
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  };
444 
445  namespace __detail
446  {
447  template<typename _Tp, typename _Up>
448  using __cmp3way_res_t
449  = decltype(std::declval<_Tp>() <=> std::declval<_Up>());
450 
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  { };
459 
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
467 
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  { };
473 
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;
478 
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
496 
497  // _GLIBCXX_RESOLVE_LIB_DEFECTS
498  // 3530 BUILTIN-PTR-MEOW should not opt the type out of syntactic checks
499 
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  }
522 
523  using is_transparent = void;
524  };
525 
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  };
544 
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  }
569 
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  };
576 
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  };
583 
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  };
590 
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  };
596 
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>;
602 
603  template<typename _Tp, typename _Up>
604  concept __decayed_same_as = same_as<decay_t<_Tp>, decay_t<_Up>>;
605 
606  class _Strong_order
607  {
608  template<typename _Tp, typename _Up>
609  static constexpr bool
610  _S_noexcept()
611  {
612  if constexpr (floating_point<decay_t<_Tp>>)
613  return true;
614  else if constexpr (__adl_strong<_Tp, _Up>)
615  return noexcept(strong_ordering(strong_order(std::declval<_Tp>(),
616  std::declval<_Up>())));
617  else if constexpr (__cmp3way<strong_ordering, _Tp, _Up>)
618  return noexcept(compare_three_way()(std::declval<_Tp>(),
619  std::declval<_Up>()));
620  }
621 
622  friend class _Weak_order;
623  friend class _Strong_fallback;
624 
625  public:
626  template<typename _Tp, __decayed_same_as<_Tp> _Up>
627  requires __strongly_ordered<_Tp, _Up>
628  constexpr strong_ordering
629  operator()(_Tp&& __e, _Up&& __f) const
630  noexcept(_S_noexcept<_Tp, _Up>())
631  {
632  /* FIXME:
633  if constexpr (floating_point<decay_t<_Tp>>)
634  return __cmp_cust::__fp_strong_order(__e, __f);
635  else */ if constexpr (__adl_strong<_Tp, _Up>)
636  return strong_ordering(strong_order(static_cast<_Tp&&>(__e),
637  static_cast<_Up&&>(__f)));
638  else if constexpr (__cmp3way<strong_ordering, _Tp, _Up>)
639  return compare_three_way()(static_cast<_Tp&&>(__e),
640  static_cast<_Up&&>(__f));
641  }
642  };
643 
644  template<typename _Tp, typename _Up>
645  concept __weakly_ordered
646  = floating_point<remove_reference_t<_Tp>>
647  || __adl_weak<_Tp, _Up>
648  || __cmp3way<weak_ordering, _Tp, _Up>
649  || __strongly_ordered<_Tp, _Up>;
650 
651  class _Weak_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_weak<_Tp, _Up>)
660  return noexcept(weak_ordering(weak_order(std::declval<_Tp>(),
661  std::declval<_Up>())));
662  else if constexpr (__cmp3way<weak_ordering, _Tp, _Up>)
663  return noexcept(compare_three_way()(std::declval<_Tp>(),
664  std::declval<_Up>()));
665  else if constexpr (__strongly_ordered<_Tp, _Up>)
666  return _Strong_order::_S_noexcept<_Tp, _Up>();
667  }
668 
669  friend class _Partial_order;
670  friend class _Weak_fallback;
671 
672  public:
673  template<typename _Tp, __decayed_same_as<_Tp> _Up>
674  requires __weakly_ordered<_Tp, _Up>
675  constexpr weak_ordering
676  operator()(_Tp&& __e, _Up&& __f) const
677  noexcept(_S_noexcept<_Tp, _Up>())
678  {
679  if constexpr (floating_point<decay_t<_Tp>>)
680  return __cmp_cust::__fp_weak_ordering(__e, __f);
681  else if constexpr (__adl_weak<_Tp, _Up>)
682  return weak_ordering(weak_order(static_cast<_Tp&&>(__e),
683  static_cast<_Up&&>(__f)));
684  else if constexpr (__cmp3way<weak_ordering, _Tp, _Up>)
685  return compare_three_way()(static_cast<_Tp&&>(__e),
686  static_cast<_Up&&>(__f));
687  else if constexpr (__strongly_ordered<_Tp, _Up>)
688  return _Strong_order{}(static_cast<_Tp&&>(__e),
689  static_cast<_Up&&>(__f));
690  }
691  };
692 
693  template<typename _Tp, typename _Up>
694  concept __partially_ordered
695  = __adl_partial<_Tp, _Up>
696  || __cmp3way<partial_ordering, _Tp, _Up>
697  || __weakly_ordered<_Tp, _Up>;
698 
699  class _Partial_order
700  {
701  template<typename _Tp, typename _Up>
702  static constexpr bool
703  _S_noexcept()
704  {
705  if constexpr (__adl_partial<_Tp, _Up>)
706  return noexcept(partial_ordering(partial_order(std::declval<_Tp>(),
707  std::declval<_Up>())));
708  else if constexpr (__cmp3way<partial_ordering, _Tp, _Up>)
709  return noexcept(compare_three_way()(std::declval<_Tp>(),
710  std::declval<_Up>()));
711  else if constexpr (__weakly_ordered<_Tp, _Up>)
712  return _Weak_order::_S_noexcept<_Tp, _Up>();
713  }
714 
715  friend class _Partial_fallback;
716 
717  public:
718  template<typename _Tp, __decayed_same_as<_Tp> _Up>
719  requires __partially_ordered<_Tp, _Up>
720  constexpr partial_ordering
721  operator()(_Tp&& __e, _Up&& __f) const
722  noexcept(_S_noexcept<_Tp, _Up>())
723  {
724  if constexpr (__adl_partial<_Tp, _Up>)
725  return partial_ordering(partial_order(static_cast<_Tp&&>(__e),
726  static_cast<_Up&&>(__f)));
727  else if constexpr (__cmp3way<partial_ordering, _Tp, _Up>)
728  return compare_three_way()(static_cast<_Tp&&>(__e),
729  static_cast<_Up&&>(__f));
730  else if constexpr (__weakly_ordered<_Tp, _Up>)
731  return _Weak_order{}(static_cast<_Tp&&>(__e),
732  static_cast<_Up&&>(__f));
733  }
734  };
735 
736  template<typename _Tp, typename _Up>
737  concept __op_eq_lt = requires(_Tp&& __t, _Up&& __u)
738  {
739  { static_cast<_Tp&&>(__t) == static_cast<_Up&&>(__u) }
740  -> convertible_to<bool>;
741  { static_cast<_Tp&&>(__t) < static_cast<_Up&&>(__u) }
742  -> convertible_to<bool>;
743  };
744 
745  class _Strong_fallback
746  {
747  template<typename _Tp, typename _Up>
748  static constexpr bool
749  _S_noexcept()
750  {
751  if constexpr (__strongly_ordered<_Tp, _Up>)
752  return _Strong_order::_S_noexcept<_Tp, _Up>();
753  else
754  return noexcept(bool(std::declval<_Tp>() == std::declval<_Up>()))
755  && noexcept(bool(std::declval<_Tp>() < std::declval<_Up>()));
756  }
757 
758  public:
759  template<typename _Tp, __decayed_same_as<_Tp> _Up>
760  requires __strongly_ordered<_Tp, _Up> || __op_eq_lt<_Tp, _Up>
761  constexpr strong_ordering
762  operator()(_Tp&& __e, _Up&& __f) const
763  noexcept(_S_noexcept<_Tp, _Up>())
764  {
765  if constexpr (__strongly_ordered<_Tp, _Up>)
766  return _Strong_order{}(static_cast<_Tp&&>(__e),
767  static_cast<_Up&&>(__f));
768  else // __op_eq_lt<_Tp, _Up>
769  return static_cast<_Tp&&>(__e) == static_cast<_Up&&>(__f)
770  ? strong_ordering::equal
771  : static_cast<_Tp&&>(__e) < static_cast<_Up&&>(__f)
772  ? strong_ordering::less
773  : strong_ordering::greater;
774  }
775  };
776 
777  class _Weak_fallback
778  {
779  template<typename _Tp, typename _Up>
780  static constexpr bool
781  _S_noexcept()
782  {
783  if constexpr (__weakly_ordered<_Tp, _Up>)
784  return _Weak_order::_S_noexcept<_Tp, _Up>();
785  else
786  return noexcept(bool(std::declval<_Tp>() == std::declval<_Up>()))
787  && noexcept(bool(std::declval<_Tp>() < std::declval<_Up>()));
788  }
789 
790  public:
791  template<typename _Tp, __decayed_same_as<_Tp> _Up>
792  requires __weakly_ordered<_Tp, _Up> || __op_eq_lt<_Tp, _Up>
793  constexpr weak_ordering
794  operator()(_Tp&& __e, _Up&& __f) const
795  noexcept(_S_noexcept<_Tp, _Up>())
796  {
797  if constexpr (__weakly_ordered<_Tp, _Up>)
798  return _Weak_order{}(static_cast<_Tp&&>(__e),
799  static_cast<_Up&&>(__f));
800  else // __op_eq_lt<_Tp, _Up>
801  return static_cast<_Tp&&>(__e) == static_cast<_Up&&>(__f)
802  ? weak_ordering::equivalent
803  : static_cast<_Tp&&>(__e) < static_cast<_Up&&>(__f)
804  ? weak_ordering::less
805  : weak_ordering::greater;
806  }
807  };
808 
809  // _GLIBCXX_RESOLVE_LIB_DEFECTS
810  // 3465. compare_partial_order_fallback requires F < E
811  template<typename _Tp, typename _Up>
812  concept __op_eq_lt_lt = __op_eq_lt<_Tp, _Up>
813  && requires(_Tp&& __t, _Up&& __u)
814  {
815  { static_cast<_Up&&>(__u) < static_cast<_Tp&&>(__t) }
816  -> convertible_to<bool>;
817  };
818 
819  class _Partial_fallback
820  {
821  template<typename _Tp, typename _Up>
822  static constexpr bool
823  _S_noexcept()
824  {
825  if constexpr (__partially_ordered<_Tp, _Up>)
826  return _Partial_order::_S_noexcept<_Tp, _Up>();
827  else
828  return noexcept(bool(std::declval<_Tp>() == std::declval<_Up>()))
829  && noexcept(bool(std::declval<_Tp>() < std::declval<_Up>()));
830  }
831 
832  public:
833  template<typename _Tp, __decayed_same_as<_Tp> _Up>
834  requires __partially_ordered<_Tp, _Up> || __op_eq_lt_lt<_Tp, _Up>
835  constexpr partial_ordering
836  operator()(_Tp&& __e, _Up&& __f) const
837  noexcept(_S_noexcept<_Tp, _Up>())
838  {
839  if constexpr (__partially_ordered<_Tp, _Up>)
840  return _Partial_order{}(static_cast<_Tp&&>(__e),
841  static_cast<_Up&&>(__f));
842  else // __op_eq_lt_lt<_Tp, _Up>
843  return static_cast<_Tp&&>(__e) == static_cast<_Up&&>(__f)
844  ? partial_ordering::equivalent
845  : static_cast<_Tp&&>(__e) < static_cast<_Up&&>(__f)
846  ? partial_ordering::less
847  : static_cast<_Up&&>(__f) < static_cast<_Tp&&>(__e)
848  ? partial_ordering::greater
849  : partial_ordering::unordered;
850  }
851  };
852  } // namespace __cmp_cust
853 
854  // [cmp.alg], comparison algorithms
855  inline namespace __cmp_alg
856  {
857  inline constexpr __cmp_cust::_Strong_order strong_order{};
858 
859  inline constexpr __cmp_cust::_Weak_order weak_order{};
860 
861  inline constexpr __cmp_cust::_Partial_order partial_order{};
862 
863  inline constexpr __cmp_cust::_Strong_fallback
864  compare_strong_order_fallback{};
865 
866  inline constexpr __cmp_cust::_Weak_fallback
867  compare_weak_order_fallback{};
868 
869  inline constexpr __cmp_cust::_Partial_fallback
870  compare_partial_order_fallback{};
871  }
872 
873  namespace __detail
874  {
875  // [expos.only.func] synth-three-way
876  inline constexpr struct _Synth3way
877  {
878  template<typename _Tp, typename _Up>
879  static constexpr bool
880  _S_noexcept(const _Tp* __t = nullptr, const _Up* __u = nullptr)
881  {
882  if constexpr (three_way_comparable_with<_Tp, _Up>)
883  return noexcept(*__t <=> *__u);
884  else
885  return noexcept(*__t < *__u) && noexcept(*__u < *__t);
886  }
887 
888  template<typename _Tp, typename _Up>
889  constexpr auto
890  operator()(const _Tp& __t, const _Up& __u) const
891  noexcept(_S_noexcept<_Tp, _Up>())
892  requires requires
893  {
894  { __t < __u } -> __boolean_testable;
895  { __u < __t } -> __boolean_testable;
896  }
897  {
898  if constexpr (three_way_comparable_with<_Tp, _Up>)
899  return __t <=> __u;
900  else
901  {
902  if (__t < __u)
903  return weak_ordering::less;
904  else if (__u < __t)
905  return weak_ordering::greater;
906  else
907  return weak_ordering::equivalent;
908  }
909  }
910  } __synth3way = {};
911 
912  // [expos.only.func] synth-three-way-result
913  template<typename _Tp, typename _Up = _Tp>
914  using __synth3way_t
915  = decltype(__detail::__synth3way(std::declval<_Tp&>(),
916  std::declval<_Up&>()));
917  } // namespace __detail
918 #endif // concepts
919 } // namespace std
920 
921 #pragma GCC visibility pop
922 
923 #endif // C++20
924 
925 #endif // _COMPARE
ISO C++ entities toplevel namespace is std.