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