libstdc++
compare
Go to the documentation of this file.
1 // -*- C++ -*- operator<=> three-way comparison support.
2 
3 // Copyright (C) 2019-2021 Free Software Foundation, Inc.
4 //
5 // This file is part of GCC.
6 //
7 // GCC is free software; you can redistribute it and/or modify
8 // it under the terms of the GNU General Public License as published by
9 // the Free Software Foundation; either version 3, or (at your option)
10 // any later version.
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  [[nodiscard]]
90  friend constexpr bool
91  operator==(partial_ordering __v, __cmp_cat::__unspec) noexcept
92  { return __v._M_value == 0; }
93 
94  [[nodiscard]]
95  friend constexpr bool
96  operator==(partial_ordering, partial_ordering) noexcept = default;
97 
98  [[nodiscard]]
99  friend constexpr bool
100  operator< (partial_ordering __v, __cmp_cat::__unspec) noexcept
101  { return __v._M_value == -1; }
102 
103  [[nodiscard]]
104  friend constexpr bool
105  operator> (partial_ordering __v, __cmp_cat::__unspec) noexcept
106  { return __v._M_value == 1; }
107 
108  [[nodiscard]]
109  friend constexpr bool
110  operator<=(partial_ordering __v, __cmp_cat::__unspec) noexcept
111  { return __v._M_value <= 0; }
112 
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; }
117 
118  [[nodiscard]]
119  friend constexpr bool
120  operator< (__cmp_cat::__unspec, partial_ordering __v) noexcept
121  { return __v._M_value == 1; }
122 
123  [[nodiscard]]
124  friend constexpr bool
125  operator> (__cmp_cat::__unspec, partial_ordering __v) noexcept
126  { return __v._M_value == -1; }
127 
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; }
132 
133  [[nodiscard]]
134  friend constexpr bool
135  operator>=(__cmp_cat::__unspec, partial_ordering __v) noexcept
136  { return 0 >= __v._M_value; }
137 
138  [[nodiscard]]
139  friend constexpr partial_ordering
140  operator<=>(partial_ordering __v, __cmp_cat::__unspec) noexcept
141  { return __v; }
142 
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  };
153 
154  // valid values' definitions
155  inline constexpr partial_ordering
156  partial_ordering::less(__cmp_cat::_Ord::less);
157 
158  inline constexpr partial_ordering
159  partial_ordering::equivalent(__cmp_cat::_Ord::equivalent);
160 
161  inline constexpr partial_ordering
162  partial_ordering::greater(__cmp_cat::_Ord::greater);
163 
164  inline constexpr partial_ordering
165  partial_ordering::unordered(__cmp_cat::_Ncmp::_Unordered);
166 
167  class weak_ordering
168  {
169  __cmp_cat::type _M_value;
170 
171  constexpr explicit
172  weak_ordering(__cmp_cat::_Ord __v) noexcept : _M_value(__cmp_cat::type(__v))
173  { }
174 
175  friend class strong_ordering;
176 
177  public:
178  // valid values
179  static const weak_ordering less;
180  static const weak_ordering equivalent;
181  static const weak_ordering greater;
182 
183  [[nodiscard]]
184  constexpr operator partial_ordering() const noexcept
185  { return partial_ordering(__cmp_cat::_Ord(_M_value)); }
186 
187  // comparisons
188  [[nodiscard]]
189  friend constexpr bool
190  operator==(weak_ordering __v, __cmp_cat::__unspec) noexcept
191  { return __v._M_value == 0; }
192 
193  [[nodiscard]]
194  friend constexpr bool
195  operator==(weak_ordering, weak_ordering) noexcept = default;
196 
197  [[nodiscard]]
198  friend constexpr bool
199  operator< (weak_ordering __v, __cmp_cat::__unspec) noexcept
200  { return __v._M_value < 0; }
201 
202  [[nodiscard]]
203  friend constexpr bool
204  operator> (weak_ordering __v, __cmp_cat::__unspec) noexcept
205  { return __v._M_value > 0; }
206 
207  [[nodiscard]]
208  friend constexpr bool
209  operator<=(weak_ordering __v, __cmp_cat::__unspec) noexcept
210  { return __v._M_value <= 0; }
211 
212  [[nodiscard]]
213  friend constexpr bool
214  operator>=(weak_ordering __v, __cmp_cat::__unspec) noexcept
215  { return __v._M_value >= 0; }
216 
217  [[nodiscard]]
218  friend constexpr bool
219  operator< (__cmp_cat::__unspec, weak_ordering __v) noexcept
220  { return 0 < __v._M_value; }
221 
222  [[nodiscard]]
223  friend constexpr bool
224  operator> (__cmp_cat::__unspec, weak_ordering __v) noexcept
225  { return 0 > __v._M_value; }
226 
227  [[nodiscard]]
228  friend constexpr bool
229  operator<=(__cmp_cat::__unspec, weak_ordering __v) noexcept
230  { return 0 <= __v._M_value; }
231 
232  [[nodiscard]]
233  friend constexpr bool
234  operator>=(__cmp_cat::__unspec, weak_ordering __v) noexcept
235  { return 0 >= __v._M_value; }
236 
237  [[nodiscard]]
238  friend constexpr weak_ordering
239  operator<=>(weak_ordering __v, __cmp_cat::__unspec) noexcept
240  { return __v; }
241 
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  };
247 
248  // valid values' definitions
249  inline constexpr weak_ordering
250  weak_ordering::less(__cmp_cat::_Ord::less);
251 
252  inline constexpr weak_ordering
253  weak_ordering::equivalent(__cmp_cat::_Ord::equivalent);
254 
255  inline constexpr weak_ordering
256  weak_ordering::greater(__cmp_cat::_Ord::greater);
257 
258  class strong_ordering
259  {
260  __cmp_cat::type _M_value;
261 
262  constexpr explicit
263  strong_ordering(__cmp_cat::_Ord __v) noexcept
264  : _M_value(__cmp_cat::type(__v))
265  { }
266 
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;
273 
274  [[nodiscard]]
275  constexpr operator partial_ordering() const noexcept
276  { return partial_ordering(__cmp_cat::_Ord(_M_value)); }
277 
278  [[nodiscard]]
279  constexpr operator weak_ordering() const noexcept
280  { return weak_ordering(__cmp_cat::_Ord(_M_value)); }
281 
282  // comparisons
283  [[nodiscard]]
284  friend constexpr bool
285  operator==(strong_ordering __v, __cmp_cat::__unspec) noexcept
286  { return __v._M_value == 0; }
287 
288  [[nodiscard]]
289  friend constexpr bool
290  operator==(strong_ordering, strong_ordering) noexcept = default;
291 
292  [[nodiscard]]
293  friend constexpr bool
294  operator< (strong_ordering __v, __cmp_cat::__unspec) noexcept
295  { return __v._M_value < 0; }
296 
297  [[nodiscard]]
298  friend constexpr bool
299  operator> (strong_ordering __v, __cmp_cat::__unspec) noexcept
300  { return __v._M_value > 0; }
301 
302  [[nodiscard]]
303  friend constexpr bool
304  operator<=(strong_ordering __v, __cmp_cat::__unspec) noexcept
305  { return __v._M_value <= 0; }
306 
307  [[nodiscard]]
308  friend constexpr bool
309  operator>=(strong_ordering __v, __cmp_cat::__unspec) noexcept
310  { return __v._M_value >= 0; }
311 
312  [[nodiscard]]
313  friend constexpr bool
314  operator< (__cmp_cat::__unspec, strong_ordering __v) noexcept
315  { return 0 < __v._M_value; }
316 
317  [[nodiscard]]
318  friend constexpr bool
319  operator> (__cmp_cat::__unspec, strong_ordering __v) noexcept
320  { return 0 > __v._M_value; }
321 
322  [[nodiscard]]
323  friend constexpr bool
324  operator<=(__cmp_cat::__unspec, strong_ordering __v) noexcept
325  { return 0 <= __v._M_value; }
326 
327  [[nodiscard]]
328  friend constexpr bool
329  operator>=(__cmp_cat::__unspec, strong_ordering __v) noexcept
330  { return 0 >= __v._M_value; }
331 
332  [[nodiscard]]
333  friend constexpr strong_ordering
334  operator<=>(strong_ordering __v, __cmp_cat::__unspec) noexcept
335  { return __v; }
336 
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  };
342 
343  // valid values' definitions
344  inline constexpr strong_ordering
345  strong_ordering::less(__cmp_cat::_Ord::less);
346 
347  inline constexpr strong_ordering
348  strong_ordering::equal(__cmp_cat::_Ord::equivalent);
349 
350  inline constexpr strong_ordering
351  strong_ordering::equivalent(__cmp_cat::_Ord::equivalent);
352 
353  inline constexpr strong_ordering
354  strong_ordering::greater(__cmp_cat::_Ord::greater);
355 
356 
357  // named comparison functions
358  [[nodiscard]]
359  constexpr bool
360  is_eq(partial_ordering __cmp) noexcept
361  { return __cmp == 0; }
362 
363  [[nodiscard]]
364  constexpr bool
365  is_neq(partial_ordering __cmp) noexcept
366  { return __cmp != 0; }
367 
368  [[nodiscard]]
369  constexpr bool
370  is_lt (partial_ordering __cmp) noexcept
371  { return __cmp < 0; }
372 
373  [[nodiscard]]
374  constexpr bool
375  is_lteq(partial_ordering __cmp) noexcept
376  { return __cmp <= 0; }
377 
378  [[nodiscard]]
379  constexpr bool
380  is_gt (partial_ordering __cmp) noexcept
381  { return __cmp > 0; }
382 
383  [[nodiscard]]
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  } // namespace __detail
460 
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  };
471 
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  };
489 
490  namespace __detail
491  {
492  template<typename _Tp, typename _Up>
493  using __cmp3way_res_t
494  = decltype(std::declval<_Tp>() <=> std::declval<_Up>());
495 
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  { };
504 
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
512 
513  /// [cmp.result], result of three-way comparison
514  template<typename _Tp, typename _Up = _Tp>
516  : __detail::__cmp3way_res_impl<_Tp, _Up>
517  { };
518 
519  /// [cmp.result], result of three-way comparison
520  template<typename _Tp, typename _Up = _Tp>
522  = typename __detail::__cmp3way_res_impl<_Tp, _Up>::type;
523 
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
541 
542  // _GLIBCXX_RESOLVE_LIB_DEFECTS
543  // 3530 BUILTIN-PTR-MEOW should not opt the type out of syntactic checks
544 
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 (__builtin_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  }
567 
568  using is_transparent = void;
569  };
570 
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  };
589 
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  }
614 
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  };
621 
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  };
628 
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  };
635 
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  };
641 
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>;
647 
648  template<typename _Tp, typename _Up>
649  concept __decayed_same_as = same_as<decay_t<_Tp>, decay_t<_Up>>;
650 
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  }
666 
667  friend class _Weak_order;
668  friend class _Strong_fallback;
669 
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  };
688 
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>;
695 
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  }
713 
714  friend class _Partial_order;
715  friend class _Weak_fallback;
716 
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  };
737 
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>;
743 
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  }
759 
760  friend class _Partial_fallback;
761 
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  };
780 
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  };
789 
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  }
802 
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  };
821 
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  }
834 
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  };
853 
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  };
863 
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  }
876 
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
898 
899  // [cmp.alg], comparison algorithms
900  inline namespace __cmp_alg
901  {
902  inline constexpr __cmp_cust::_Strong_order strong_order{};
903 
904  inline constexpr __cmp_cust::_Weak_order weak_order{};
905 
906  inline constexpr __cmp_cust::_Partial_order partial_order{};
907 
908  inline constexpr __cmp_cust::_Strong_fallback
909  compare_strong_order_fallback{};
910 
911  inline constexpr __cmp_cust::_Weak_fallback
912  compare_weak_order_fallback{};
913 
914  inline constexpr __cmp_cust::_Partial_fallback
915  compare_partial_order_fallback{};
916  }
917 
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  }
932 
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 = {};
957 
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
966 
967 #pragma GCC visibility pop
968 
969 #endif // C++20
970 
971 #endif // _COMPARE
auto declval() noexcept -> decltype(__declval< _Tp >(0))
Definition: type_traits:2393
ISO C++ entities toplevel namespace is std.
typename __detail::__cmp3way_res_impl< _Tp, _Up >::type compare_three_way_result_t
[cmp.result], result of three-way comparison
Definition: compare:522
[cmp.result], result of three-way comparison
Definition: compare:517