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