1 // -*- C++ -*- operator<=> three-way comparison support.
3 // Copyright (C) 2019-2020 Free Software Foundation, Inc.
5 // This file is part of GCC.
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)
12 // GCC is distributed in the hope that it will be useful,
13 // but WITHOUT ANY WARRANTY; without even the implied warranty of
14 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 // GNU General Public License for more details.
17 // Under Section 7 of GPL version 3, you are granted additional
18 // permissions described in the GCC Runtime Library Exception, version
19 // 3.1, as published by the Free Software Foundation.
21 // You should have received a copy of the GNU General Public License and
22 // a copy of the GCC Runtime Library Exception along with this program;
23 // see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
24 // <http://www.gnu.org/licenses/>.
27 * This is a Standard C++ Library header.
33 #pragma GCC system_header
35 #if __cplusplus > 201703L && __cpp_impl_three_way_comparison >= 201907L
37 #pragma GCC visibility push(default)
41 #if __cpp_lib_concepts
42 # define __cpp_lib_three_way_comparison 201711L
47 // [cmp.categories], comparison category types
51 using type = signed char;
53 enum class _Ord : type { equivalent = 0, less = -1, greater = 1 };
55 enum class _Ncmp : type { _Unordered = 2 };
59 constexpr __unspec(__unspec*) { }
63 class partial_ordering
65 // less=0xff, equiv=0x00, greater=0x01, unordered=0x02
66 __cmp_cat::type _M_value;
69 partial_ordering(__cmp_cat::_Ord __v) noexcept
70 : _M_value(__cmp_cat::type(__v))
74 partial_ordering(__cmp_cat::_Ncmp __v) noexcept
75 : _M_value(__cmp_cat::type(__v))
78 friend class weak_ordering;
79 friend class strong_ordering;
83 static const partial_ordering less;
84 static const partial_ordering equivalent;
85 static const partial_ordering greater;
86 static const partial_ordering unordered;
90 operator==(partial_ordering __v, __cmp_cat::__unspec) noexcept
91 { return __v._M_value == 0; }
94 operator==(partial_ordering, partial_ordering) noexcept = default;
97 operator< (partial_ordering __v, __cmp_cat::__unspec) noexcept
98 { return __v._M_value == -1; }
100 friend constexpr bool
101 operator> (partial_ordering __v, __cmp_cat::__unspec) noexcept
102 { return __v._M_value == 1; }
104 friend constexpr bool
105 operator<=(partial_ordering __v, __cmp_cat::__unspec) noexcept
106 { return __v._M_value <= 0; }
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; }
112 friend constexpr bool
113 operator< (__cmp_cat::__unspec, partial_ordering __v) noexcept
114 { return __v._M_value == 1; }
116 friend constexpr bool
117 operator> (__cmp_cat::__unspec, partial_ordering __v) noexcept
118 { return __v._M_value == -1; }
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; }
124 friend constexpr bool
125 operator>=(__cmp_cat::__unspec, partial_ordering __v) noexcept
126 { return 0 >= __v._M_value; }
128 friend constexpr partial_ordering
129 operator<=>(partial_ordering __v, __cmp_cat::__unspec) noexcept
132 friend constexpr partial_ordering
133 operator<=>(__cmp_cat::__unspec, partial_ordering __v) noexcept
135 if (__v._M_value & 1)
136 return partial_ordering(__cmp_cat::_Ord(-__v._M_value));
142 // valid values' definitions
143 inline constexpr partial_ordering
144 partial_ordering::less(__cmp_cat::_Ord::less);
146 inline constexpr partial_ordering
147 partial_ordering::equivalent(__cmp_cat::_Ord::equivalent);
149 inline constexpr partial_ordering
150 partial_ordering::greater(__cmp_cat::_Ord::greater);
152 inline constexpr partial_ordering
153 partial_ordering::unordered(__cmp_cat::_Ncmp::_Unordered);
157 __cmp_cat::type _M_value;
160 weak_ordering(__cmp_cat::_Ord __v) noexcept : _M_value(__cmp_cat::type(__v))
163 friend class strong_ordering;
167 static const weak_ordering less;
168 static const weak_ordering equivalent;
169 static const weak_ordering greater;
171 constexpr operator partial_ordering() const noexcept
172 { return partial_ordering(__cmp_cat::_Ord(_M_value)); }
175 friend constexpr bool
176 operator==(weak_ordering __v, __cmp_cat::__unspec) noexcept
177 { return __v._M_value == 0; }
179 friend constexpr bool
180 operator==(weak_ordering, weak_ordering) noexcept = default;
182 friend constexpr bool
183 operator< (weak_ordering __v, __cmp_cat::__unspec) noexcept
184 { return __v._M_value < 0; }
186 friend constexpr bool
187 operator> (weak_ordering __v, __cmp_cat::__unspec) noexcept
188 { return __v._M_value > 0; }
190 friend constexpr bool
191 operator<=(weak_ordering __v, __cmp_cat::__unspec) noexcept
192 { return __v._M_value <= 0; }
194 friend constexpr bool
195 operator>=(weak_ordering __v, __cmp_cat::__unspec) noexcept
196 { return __v._M_value >= 0; }
198 friend constexpr bool
199 operator< (__cmp_cat::__unspec, weak_ordering __v) noexcept
200 { return 0 < __v._M_value; }
202 friend constexpr bool
203 operator> (__cmp_cat::__unspec, weak_ordering __v) noexcept
204 { return 0 > __v._M_value; }
206 friend constexpr bool
207 operator<=(__cmp_cat::__unspec, weak_ordering __v) noexcept
208 { return 0 <= __v._M_value; }
210 friend constexpr bool
211 operator>=(__cmp_cat::__unspec, weak_ordering __v) noexcept
212 { return 0 >= __v._M_value; }
214 friend constexpr weak_ordering
215 operator<=>(weak_ordering __v, __cmp_cat::__unspec) noexcept
218 friend constexpr weak_ordering
219 operator<=>(__cmp_cat::__unspec, weak_ordering __v) noexcept
220 { return weak_ordering(__cmp_cat::_Ord(-__v._M_value)); }
223 // valid values' definitions
224 inline constexpr weak_ordering
225 weak_ordering::less(__cmp_cat::_Ord::less);
227 inline constexpr weak_ordering
228 weak_ordering::equivalent(__cmp_cat::_Ord::equivalent);
230 inline constexpr weak_ordering
231 weak_ordering::greater(__cmp_cat::_Ord::greater);
233 class strong_ordering
235 __cmp_cat::type _M_value;
238 strong_ordering(__cmp_cat::_Ord __v) noexcept
239 : _M_value(__cmp_cat::type(__v))
244 static const strong_ordering less;
245 static const strong_ordering equal;
246 static const strong_ordering equivalent;
247 static const strong_ordering greater;
249 constexpr operator partial_ordering() const noexcept
250 { return partial_ordering(__cmp_cat::_Ord(_M_value)); }
252 constexpr operator weak_ordering() const noexcept
253 { return weak_ordering(__cmp_cat::_Ord(_M_value)); }
256 friend constexpr bool
257 operator==(strong_ordering __v, __cmp_cat::__unspec) noexcept
258 { return __v._M_value == 0; }
260 friend constexpr bool
261 operator==(strong_ordering, strong_ordering) noexcept = default;
263 friend constexpr bool
264 operator< (strong_ordering __v, __cmp_cat::__unspec) noexcept
265 { return __v._M_value < 0; }
267 friend constexpr bool
268 operator> (strong_ordering __v, __cmp_cat::__unspec) noexcept
269 { return __v._M_value > 0; }
271 friend constexpr bool
272 operator<=(strong_ordering __v, __cmp_cat::__unspec) noexcept
273 { return __v._M_value <= 0; }
275 friend constexpr bool
276 operator>=(strong_ordering __v, __cmp_cat::__unspec) noexcept
277 { return __v._M_value >= 0; }
279 friend constexpr bool
280 operator< (__cmp_cat::__unspec, strong_ordering __v) noexcept
281 { return 0 < __v._M_value; }
283 friend constexpr bool
284 operator> (__cmp_cat::__unspec, strong_ordering __v) noexcept
285 { return 0 > __v._M_value; }
287 friend constexpr bool
288 operator<=(__cmp_cat::__unspec, strong_ordering __v) noexcept
289 { return 0 <= __v._M_value; }
291 friend constexpr bool
292 operator>=(__cmp_cat::__unspec, strong_ordering __v) noexcept
293 { return 0 >= __v._M_value; }
295 friend constexpr strong_ordering
296 operator<=>(strong_ordering __v, __cmp_cat::__unspec) noexcept
299 friend constexpr strong_ordering
300 operator<=>(__cmp_cat::__unspec, strong_ordering __v) noexcept
301 { return strong_ordering(__cmp_cat::_Ord(-__v._M_value)); }
304 // valid values' definitions
305 inline constexpr strong_ordering
306 strong_ordering::less(__cmp_cat::_Ord::less);
308 inline constexpr strong_ordering
309 strong_ordering::equal(__cmp_cat::_Ord::equivalent);
311 inline constexpr strong_ordering
312 strong_ordering::equivalent(__cmp_cat::_Ord::equivalent);
314 inline constexpr strong_ordering
315 strong_ordering::greater(__cmp_cat::_Ord::greater);
318 // named comparison functions
320 is_eq(partial_ordering __cmp) noexcept
321 { return __cmp == 0; }
324 is_neq(partial_ordering __cmp) noexcept
325 { return __cmp != 0; }
328 is_lt (partial_ordering __cmp) noexcept
329 { return __cmp < 0; }
332 is_lteq(partial_ordering __cmp) noexcept
333 { return __cmp <= 0; }
336 is_gt (partial_ordering __cmp) noexcept
337 { return __cmp > 0; }
340 is_gteq(partial_ordering __cmp) noexcept
341 { return __cmp >= 0; }
345 template<typename _Tp>
346 inline constexpr unsigned __cmp_cat_id = 1;
348 inline constexpr unsigned __cmp_cat_id<partial_ordering> = 2;
350 inline constexpr unsigned __cmp_cat_id<weak_ordering> = 4;
352 inline constexpr unsigned __cmp_cat_id<strong_ordering> = 8;
354 template<typename... _Ts>
355 constexpr auto __common_cmp_cat()
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)
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.
371 return strong_ordering::equivalent;
373 } // namespace __detail
375 // [cmp.common], common comparison category type
376 template<typename... _Ts>
377 struct common_comparison_category
379 using type = decltype(__detail::__common_cmp_cat<_Ts...>());
382 // Partial specializations for one and zero argument cases.
384 template<typename _Tp>
385 struct common_comparison_category<_Tp>
386 { using type = void; };
389 struct common_comparison_category<partial_ordering>
390 { using type = partial_ordering; };
393 struct common_comparison_category<weak_ordering>
394 { using type = weak_ordering; };
397 struct common_comparison_category<strong_ordering>
398 { using type = strong_ordering; };
401 struct common_comparison_category<>
402 { using type = strong_ordering; };
404 template<typename... _Ts>
405 using common_comparison_category_t
406 = typename common_comparison_category<_Ts...>::type;
408 #if __cpp_lib_concepts
411 template<typename _Tp, typename _Cat>
412 concept __compares_as
413 = same_as<common_comparison_category_t<_Tp, _Cat>, _Cat>;
414 } // namespace __detail
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 { __a <=> __b } -> __detail::__compares_as<_Cat>;
426 template<typename _Tp, typename _Up, typename _Cat = partial_ordering>
427 concept three_way_comparable_with
428 = three_way_comparable<_Tp, _Cat>
429 && three_way_comparable<_Up, _Cat>
430 && common_reference_with<const remove_reference_t<_Tp>&,
431 const remove_reference_t<_Up>&>
432 && three_way_comparable<
433 common_reference_t<const remove_reference_t<_Tp>&,
434 const remove_reference_t<_Up>&>, _Cat>
435 && __detail::__weakly_eq_cmp_with<_Tp, _Up>
436 && __detail::__partially_ordered_with<_Tp, _Up>
437 && requires(const remove_reference_t<_Tp>& __t,
438 const remove_reference_t<_Up>& __u) {
439 { __t <=> __u } -> __detail::__compares_as<_Cat>;
440 { __u <=> __t } -> __detail::__compares_as<_Cat>;
445 template<typename _Tp, typename _Up>
446 using __cmp3way_res_t
447 = decltype(std::declval<_Tp>() <=> std::declval<_Up>());
449 // Implementation of std::compare_three_way_result.
450 // It is undefined for a program to add specializations of
451 // std::compare_three_way_result, so the std::compare_three_way_result_t
452 // alias ignores std::compare_three_way_result and uses
453 // __detail::__cmp3way_res_impl directly instead.
454 template<typename _Tp, typename _Up>
455 struct __cmp3way_res_impl
458 template<typename _Tp, typename _Up>
459 requires requires { typename __cmp3way_res_t<__cref<_Tp>, __cref<_Up>>; }
460 struct __cmp3way_res_impl<_Tp, _Up>
462 using type = __cmp3way_res_t<__cref<_Tp>, __cref<_Up>>;
464 } // namespace __detail
466 /// [cmp.result], result of three-way comparison
467 template<typename _Tp, typename _Up = _Tp>
468 struct compare_three_way_result
469 : __detail::__cmp3way_res_impl<_Tp, _Up>
472 /// [cmp.result], result of three-way comparison
473 template<typename _Tp, typename _Up = _Tp>
474 using compare_three_way_result_t
475 = typename __detail::__cmp3way_res_impl<_Tp, _Up>::type;
479 // BUILTIN-PTR-THREE-WAY(T, U)
480 template<typename _Tp, typename _Up>
481 concept __3way_builtin_ptr_cmp
482 = three_way_comparable_with<_Tp, _Up>
483 && convertible_to<_Tp, const volatile void*>
484 && convertible_to<_Up, const volatile void*>
485 && ! requires(_Tp&& __t, _Up&& __u)
486 { operator<=>(static_cast<_Tp&&>(__t), static_cast<_Up&&>(__u)); }
487 && ! requires(_Tp&& __t, _Up&& __u)
488 { static_cast<_Tp&&>(__t).operator<=>(static_cast<_Up&&>(__u)); };
489 } // namespace __detail
491 // [cmp.object], typename compare_three_way
492 struct compare_three_way
494 template<typename _Tp, typename _Up>
495 requires three_way_comparable_with<_Tp, _Up>
497 operator()(_Tp&& __t, _Up&& __u) const noexcept
499 if constexpr (__detail::__3way_builtin_ptr_cmp<_Tp, _Up>)
501 auto __pt = static_cast<const volatile void*>(__t);
502 auto __pu = static_cast<const volatile void*>(__u);
503 if (__builtin_is_constant_evaluated())
504 return __pt <=> __pu;
505 auto __it = reinterpret_cast<__UINTPTR_TYPE__>(__pt);
506 auto __iu = reinterpret_cast<__UINTPTR_TYPE__>(__pu);
507 return __it <=> __iu;
510 return static_cast<_Tp&&>(__t) <=> static_cast<_Up&&>(__u);
513 using is_transparent = void;
518 template<floating_point _Tp>
519 constexpr weak_ordering
520 __fp_weak_ordering(_Tp __e, _Tp __f)
522 // Returns an integer with the same sign as the argument, and magnitude
523 // indicating the classification: zero=1 subnorm=2 norm=3 inf=4 nan=5
524 auto __cat = [](_Tp __fp) -> int {
525 const int __sign = __builtin_signbit(__fp) ? -1 : 1;
526 if (__builtin_isnormal(__fp))
527 return (__fp == 0 ? 1 : 3) * __sign;
528 if (__builtin_isnan(__fp))
530 if (int __inf = __builtin_isinf_sign(__fp))
535 auto __po = __e <=> __f;
537 return weak_ordering::less;
538 else if (is_gt(__po))
539 return weak_ordering::greater;
540 else if (__po == partial_ordering::equivalent)
541 return weak_ordering::equivalent;
542 else // unordered, at least one argument is NaN
544 // return -1 for negative nan, +1 for positive nan, 0 otherwise.
545 auto __isnan_sign = [](_Tp __fp) -> int {
546 return __builtin_isnan(__fp)
547 ? __builtin_signbit(__fp) ? -1 : 1
550 auto __ord = __isnan_sign(__e) <=> __isnan_sign(__f);
552 return weak_ordering::equivalent;
553 else if (is_lt(__ord))
554 return weak_ordering::less;
556 return weak_ordering::greater;
560 template<typename _Tp, typename _Up>
561 concept __adl_strong = requires(_Tp&& __t, _Up&& __u)
563 strong_ordering(strong_order(static_cast<_Tp&&>(__t),
564 static_cast<_Up&&>(__u)));
567 template<typename _Tp, typename _Up>
568 concept __adl_weak = requires(_Tp&& __t, _Up&& __u)
570 weak_ordering(weak_order(static_cast<_Tp&&>(__t),
571 static_cast<_Up&&>(__u)));
574 template<typename _Tp, typename _Up>
575 concept __adl_partial = requires(_Tp&& __t, _Up&& __u)
577 partial_ordering(partial_order(static_cast<_Tp&&>(__t),
578 static_cast<_Up&&>(__u)));
581 template<typename _Ord, typename _Tp, typename _Up>
582 concept __op_cmp = requires(_Tp&& __t, _Up&& __u)
584 _Ord(static_cast<_Tp&&>(__t) <=> static_cast<_Up&&>(__u));
587 template<typename _Tp, typename _Up>
588 concept __strongly_ordered
589 = __adl_strong<_Tp, _Up>
590 // FIXME: || floating_point<remove_reference_t<_Tp>>
591 || __op_cmp<strong_ordering, _Tp, _Up>;
595 template<typename _Tp, typename _Up>
596 static constexpr bool
599 if constexpr (floating_point<decay_t<_Tp>>)
601 else if constexpr (__adl_strong<_Tp, _Up>)
602 return noexcept(strong_ordering(strong_order(std::declval<_Tp>(),
603 std::declval<_Up>())));
604 else if constexpr (__op_cmp<strong_ordering, _Tp, _Up>)
605 return noexcept(std::declval<_Tp>() <=> std::declval<_Up>());
608 friend class _Weak_order;
609 friend class _Strong_fallback;
612 template<typename _Tp, typename _Up>
613 requires __strongly_ordered<_Tp, _Up>
614 constexpr strong_ordering
615 operator()(_Tp&& __e, _Up&& __f) const
616 noexcept(_S_noexcept<_Tp, _Up>())
618 static_assert(same_as<decay_t<_Tp>, decay_t<_Up>>);
621 if constexpr (floating_point<decay_t<_Tp>>)
622 return __cmp_cust::__fp_strong_order(__e, __f);
623 else */ if constexpr (__adl_strong<_Tp, _Up>)
624 return strong_ordering(strong_order(static_cast<_Tp&&>(__e),
625 static_cast<_Up&&>(__f)));
626 else if constexpr (__op_cmp<strong_ordering, _Tp, _Up>)
627 return static_cast<_Tp&&>(__e) <=> static_cast<_Up&&>(__f);
631 template<typename _Tp, typename _Up>
632 concept __weakly_ordered
633 = floating_point<remove_reference_t<_Tp>>
634 || __adl_weak<_Tp, _Up>
635 || __op_cmp<weak_ordering, _Tp, _Up>
636 || __strongly_ordered<_Tp, _Up>;
640 template<typename _Tp, typename _Up>
641 static constexpr bool
644 if constexpr (floating_point<decay_t<_Tp>>)
646 else if constexpr (__adl_weak<_Tp, _Up>)
647 return noexcept(weak_ordering(weak_order(std::declval<_Tp>(),
648 std::declval<_Up>())));
649 else if constexpr (__op_cmp<weak_ordering, _Tp, _Up>)
650 return noexcept(std::declval<_Tp>() <=> std::declval<_Up>());
651 else if constexpr (__strongly_ordered<_Tp, _Up>)
652 return _Strong_order::_S_noexcept<_Tp, _Up>();
655 friend class _Partial_order;
656 friend class _Weak_fallback;
659 template<typename _Tp, typename _Up>
660 requires __weakly_ordered<_Tp, _Up>
661 constexpr weak_ordering
662 operator()(_Tp&& __e, _Up&& __f) const
663 noexcept(_S_noexcept<_Tp, _Up>())
665 static_assert(same_as<decay_t<_Tp>, decay_t<_Up>>);
667 if constexpr (floating_point<decay_t<_Tp>>)
668 return __cmp_cust::__fp_weak_ordering(__e, __f);
669 else if constexpr (__adl_weak<_Tp, _Up>)
670 return weak_ordering(weak_order(static_cast<_Tp&&>(__e),
671 static_cast<_Up&&>(__f)));
672 else if constexpr (__op_cmp<weak_ordering, _Tp, _Up>)
673 return static_cast<_Tp&&>(__e) <=> static_cast<_Up&&>(__f);
674 else if constexpr (__strongly_ordered<_Tp, _Up>)
675 return _Strong_order{}(static_cast<_Tp&&>(__e),
676 static_cast<_Up&&>(__f));
680 template<typename _Tp, typename _Up>
681 concept __partially_ordered
682 = __adl_partial<_Tp, _Up>
683 || __op_cmp<partial_ordering, _Tp, _Up>
684 || __weakly_ordered<_Tp, _Up>;
688 template<typename _Tp, typename _Up>
689 static constexpr bool
692 if constexpr (__adl_partial<_Tp, _Up>)
693 return noexcept(partial_ordering(partial_order(std::declval<_Tp>(),
694 std::declval<_Up>())));
695 else if constexpr (__op_cmp<partial_ordering, _Tp, _Up>)
696 return noexcept(std::declval<_Tp>() <=> std::declval<_Up>());
697 else if constexpr (__weakly_ordered<_Tp, _Up>)
698 return _Weak_order::_S_noexcept<_Tp, _Up>();
701 friend class _Partial_fallback;
704 template<typename _Tp, typename _Up>
705 requires __partially_ordered<_Tp, _Up>
706 constexpr partial_ordering
707 operator()(_Tp&& __e, _Up&& __f) const
708 noexcept(_S_noexcept<_Tp, _Up>())
710 static_assert(same_as<decay_t<_Tp>, decay_t<_Up>>);
712 if constexpr (__adl_partial<_Tp, _Up>)
713 return partial_ordering(partial_order(static_cast<_Tp&&>(__e),
714 static_cast<_Up&&>(__f)));
715 else if constexpr (__op_cmp<partial_ordering, _Tp, _Up>)
716 return static_cast<_Tp&&>(__e) <=> static_cast<_Up&&>(__f);
717 else if constexpr (__weakly_ordered<_Tp, _Up>)
718 return _Weak_order{}(static_cast<_Tp&&>(__e),
719 static_cast<_Up&&>(__f));
723 template<typename _Tp, typename _Up>
724 concept __op_eq_lt = requires(_Tp&& __t, _Up&& __u)
726 { static_cast<_Tp&&>(__t) == static_cast<_Up&&>(__u) }
727 -> convertible_to<bool>;
728 { static_cast<_Tp&&>(__t) < static_cast<_Up&&>(__u) }
729 -> convertible_to<bool>;
732 class _Strong_fallback
734 template<typename _Tp, typename _Up>
735 static constexpr bool
738 if constexpr (__strongly_ordered<_Tp, _Up>)
739 return _Strong_order::_S_noexcept<_Tp, _Up>();
741 return noexcept(bool(std::declval<_Tp>() == std::declval<_Up>()))
742 && noexcept(bool(std::declval<_Tp>() < std::declval<_Up>()));
746 template<typename _Tp, typename _Up>
747 requires __strongly_ordered<_Tp, _Up> || __op_eq_lt<_Tp, _Up>
748 constexpr decltype(auto)
749 operator()(_Tp&& __e, _Up&& __f) const
750 noexcept(_S_noexcept<_Tp, _Up>())
752 static_assert(same_as<decay_t<_Tp>, decay_t<_Up>>);
754 if constexpr (__strongly_ordered<_Tp, _Up>)
755 return _Strong_order{}(static_cast<_Tp&&>(__e),
756 static_cast<_Up&&>(__f));
757 else if constexpr (__op_eq_lt<_Tp, _Up>)
758 return static_cast<_Tp&&>(__e) == static_cast<_Up&&>(__f)
759 ? strong_ordering::equal
760 : static_cast<_Tp&&>(__e) < static_cast<_Up&&>(__f)
761 ? strong_ordering::less
762 : strong_ordering::greater;
768 template<typename _Tp, typename _Up>
769 static constexpr bool
772 if constexpr (__weakly_ordered<_Tp, _Up>)
773 return _Weak_order::_S_noexcept<_Tp, _Up>();
775 return noexcept(bool(std::declval<_Tp>() == std::declval<_Up>()))
776 && noexcept(bool(std::declval<_Tp>() < std::declval<_Up>()));
780 template<typename _Tp, typename _Up>
781 requires __weakly_ordered<_Tp, _Up> || __op_eq_lt<_Tp, _Up>
782 constexpr decltype(auto)
783 operator()(_Tp&& __e, _Up&& __f) const
784 noexcept(_S_noexcept<_Tp, _Up>())
786 static_assert(same_as<decay_t<_Tp>, decay_t<_Up>>);
788 if constexpr (__weakly_ordered<_Tp, _Up>)
789 return _Weak_order{}(static_cast<_Tp&&>(__e),
790 static_cast<_Up&&>(__f));
791 else if constexpr (__op_eq_lt<_Tp, _Up>)
792 return static_cast<_Tp&&>(__e) == static_cast<_Up&&>(__f)
793 ? weak_ordering::equivalent
794 : static_cast<_Tp&&>(__e) < static_cast<_Up&&>(__f)
795 ? weak_ordering::less
796 : weak_ordering::greater;
800 class _Partial_fallback
802 template<typename _Tp, typename _Up>
803 static constexpr bool
806 if constexpr (__partially_ordered<_Tp, _Up>)
807 return _Partial_order::_S_noexcept<_Tp, _Up>();
809 return noexcept(bool(std::declval<_Tp>() == std::declval<_Up>()))
810 && noexcept(bool(std::declval<_Tp>() < std::declval<_Up>()));
814 template<typename _Tp, typename _Up>
815 requires __partially_ordered<_Tp, _Up> || __op_eq_lt<_Tp, _Up>
816 constexpr decltype(auto)
817 operator()(_Tp&& __e, _Up&& __f) const
818 noexcept(_S_noexcept<_Tp, _Up>())
820 static_assert(same_as<decay_t<_Tp>, decay_t<_Up>>);
822 if constexpr (__partially_ordered<_Tp, _Up>)
823 return _Partial_order{}(static_cast<_Tp&&>(__e),
824 static_cast<_Up&&>(__f));
825 else if constexpr (__op_eq_lt<_Tp, _Up>)
826 return static_cast<_Tp&&>(__e) == static_cast<_Up&&>(__f)
827 ? partial_ordering::equivalent
828 : static_cast<_Tp&&>(__e) < static_cast<_Up&&>(__f)
829 ? partial_ordering::less
830 : static_cast<_Up&&>(__f) < static_cast<_Tp&&>(__e)
831 ? partial_ordering::greater
832 : partial_ordering::unordered;
835 } // namespace __cmp_cust
837 // [cmp.alg], comparison algorithms
838 inline namespace __cmp_alg
840 inline constexpr __cmp_cust::_Strong_order strong_order{};
842 inline constexpr __cmp_cust::_Weak_order weak_order{};
844 inline constexpr __cmp_cust::_Partial_order partial_order{};
846 inline constexpr __cmp_cust::_Strong_fallback
847 compare_strong_order_fallback{};
849 inline constexpr __cmp_cust::_Weak_fallback
850 compare_weak_order_fallback{};
852 inline constexpr __cmp_cust::_Partial_fallback
853 compare_partial_order_fallback{};
859 inline constexpr struct _Synth3way
861 template<typename _Tp, typename _Up>
863 operator()(const _Tp& __t, const _Up& __u) const
866 { __t < __u } -> __boolean_testable;
867 { __u < __t } -> __boolean_testable;
870 if constexpr (three_way_comparable_with<_Tp, _Up>)
875 return weak_ordering::less;
877 return weak_ordering::greater;
879 return weak_ordering::equivalent;
884 template<typename _Tp, typename _Up = _Tp>
886 = decltype(__detail::__synth3way(std::declval<_Tp&>(),
887 std::declval<_Up&>()));
888 } // namespace __detail
892 #pragma GCC visibility pop