123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924 |
- // -*- C++ -*- operator<=> three-way comparison support.
- // Copyright (C) 2019-2020 Free Software Foundation, Inc.
- //
- // This file is part of GCC.
- //
- // GCC is free software; you can redistribute it and/or modify
- // it under the terms of the GNU General Public License as published by
- // the Free Software Foundation; either version 3, or (at your option)
- // any later version.
- //
- // GCC is distributed in the hope that it will be useful,
- // but WITHOUT ANY WARRANTY; without even the implied warranty of
- // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- // GNU General Public License for more details.
- //
- // Under Section 7 of GPL version 3, you are granted additional
- // permissions described in the GCC Runtime Library Exception, version
- // 3.1, as published by the Free Software Foundation.
- // You should have received a copy of the GNU General Public License and
- // a copy of the GCC Runtime Library Exception along with this program;
- // see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
- // <http://www.gnu.org/licenses/>.
- /** @file compare
- * This is a Standard C++ Library header.
- */
- #ifndef _COMPARE
- #define _COMPARE
- #pragma GCC system_header
- #if __cplusplus > 201703L && __cpp_impl_three_way_comparison >= 201907L
- #pragma GCC visibility push(default)
- #include <concepts>
- #if __cpp_lib_concepts
- # define __cpp_lib_three_way_comparison 201907L
- #endif
- namespace std
- {
- // [cmp.categories], comparison category types
- namespace __cmp_cat
- {
- using type = signed char;
- enum class _Ord : type { equivalent = 0, less = -1, greater = 1 };
- enum class _Ncmp : type { _Unordered = 2 };
- struct __unspec
- {
- constexpr __unspec(__unspec*) noexcept { }
- };
- }
- class partial_ordering
- {
- // less=0xff, equiv=0x00, greater=0x01, unordered=0x02
- __cmp_cat::type _M_value;
- constexpr explicit
- partial_ordering(__cmp_cat::_Ord __v) noexcept
- : _M_value(__cmp_cat::type(__v))
- { }
- constexpr explicit
- partial_ordering(__cmp_cat::_Ncmp __v) noexcept
- : _M_value(__cmp_cat::type(__v))
- { }
- friend class weak_ordering;
- friend class strong_ordering;
- public:
- // valid values
- static const partial_ordering less;
- static const partial_ordering equivalent;
- static const partial_ordering greater;
- static const partial_ordering unordered;
- // comparisons
- friend constexpr bool
- operator==(partial_ordering __v, __cmp_cat::__unspec) noexcept
- { return __v._M_value == 0; }
- friend constexpr bool
- operator==(partial_ordering, partial_ordering) noexcept = default;
- friend constexpr bool
- operator< (partial_ordering __v, __cmp_cat::__unspec) noexcept
- { return __v._M_value == -1; }
- friend constexpr bool
- operator> (partial_ordering __v, __cmp_cat::__unspec) noexcept
- { return __v._M_value == 1; }
- friend constexpr bool
- operator<=(partial_ordering __v, __cmp_cat::__unspec) noexcept
- { return __v._M_value <= 0; }
- friend constexpr bool
- operator>=(partial_ordering __v, __cmp_cat::__unspec) noexcept
- { return __cmp_cat::type(__v._M_value & 1) == __v._M_value; }
- friend constexpr bool
- operator< (__cmp_cat::__unspec, partial_ordering __v) noexcept
- { return __v._M_value == 1; }
- friend constexpr bool
- operator> (__cmp_cat::__unspec, partial_ordering __v) noexcept
- { return __v._M_value == -1; }
- friend constexpr bool
- operator<=(__cmp_cat::__unspec, partial_ordering __v) noexcept
- { return __cmp_cat::type(__v._M_value & 1) == __v._M_value; }
- friend constexpr bool
- operator>=(__cmp_cat::__unspec, partial_ordering __v) noexcept
- { return 0 >= __v._M_value; }
- friend constexpr partial_ordering
- operator<=>(partial_ordering __v, __cmp_cat::__unspec) noexcept
- { return __v; }
- friend constexpr partial_ordering
- operator<=>(__cmp_cat::__unspec, partial_ordering __v) noexcept
- {
- if (__v._M_value & 1)
- return partial_ordering(__cmp_cat::_Ord(-__v._M_value));
- else
- return __v;
- }
- };
- // valid values' definitions
- inline constexpr partial_ordering
- partial_ordering::less(__cmp_cat::_Ord::less);
- inline constexpr partial_ordering
- partial_ordering::equivalent(__cmp_cat::_Ord::equivalent);
- inline constexpr partial_ordering
- partial_ordering::greater(__cmp_cat::_Ord::greater);
- inline constexpr partial_ordering
- partial_ordering::unordered(__cmp_cat::_Ncmp::_Unordered);
- class weak_ordering
- {
- __cmp_cat::type _M_value;
- constexpr explicit
- weak_ordering(__cmp_cat::_Ord __v) noexcept : _M_value(__cmp_cat::type(__v))
- { }
- friend class strong_ordering;
- public:
- // valid values
- static const weak_ordering less;
- static const weak_ordering equivalent;
- static const weak_ordering greater;
- constexpr operator partial_ordering() const noexcept
- { return partial_ordering(__cmp_cat::_Ord(_M_value)); }
- // comparisons
- friend constexpr bool
- operator==(weak_ordering __v, __cmp_cat::__unspec) noexcept
- { return __v._M_value == 0; }
- friend constexpr bool
- operator==(weak_ordering, weak_ordering) noexcept = default;
- friend constexpr bool
- operator< (weak_ordering __v, __cmp_cat::__unspec) noexcept
- { return __v._M_value < 0; }
- friend constexpr bool
- operator> (weak_ordering __v, __cmp_cat::__unspec) noexcept
- { return __v._M_value > 0; }
- friend constexpr bool
- operator<=(weak_ordering __v, __cmp_cat::__unspec) noexcept
- { return __v._M_value <= 0; }
- friend constexpr bool
- operator>=(weak_ordering __v, __cmp_cat::__unspec) noexcept
- { return __v._M_value >= 0; }
- friend constexpr bool
- operator< (__cmp_cat::__unspec, weak_ordering __v) noexcept
- { return 0 < __v._M_value; }
- friend constexpr bool
- operator> (__cmp_cat::__unspec, weak_ordering __v) noexcept
- { return 0 > __v._M_value; }
- friend constexpr bool
- operator<=(__cmp_cat::__unspec, weak_ordering __v) noexcept
- { return 0 <= __v._M_value; }
- friend constexpr bool
- operator>=(__cmp_cat::__unspec, weak_ordering __v) noexcept
- { return 0 >= __v._M_value; }
- friend constexpr weak_ordering
- operator<=>(weak_ordering __v, __cmp_cat::__unspec) noexcept
- { return __v; }
- friend constexpr weak_ordering
- operator<=>(__cmp_cat::__unspec, weak_ordering __v) noexcept
- { return weak_ordering(__cmp_cat::_Ord(-__v._M_value)); }
- };
- // valid values' definitions
- inline constexpr weak_ordering
- weak_ordering::less(__cmp_cat::_Ord::less);
- inline constexpr weak_ordering
- weak_ordering::equivalent(__cmp_cat::_Ord::equivalent);
- inline constexpr weak_ordering
- weak_ordering::greater(__cmp_cat::_Ord::greater);
- class strong_ordering
- {
- __cmp_cat::type _M_value;
- constexpr explicit
- strong_ordering(__cmp_cat::_Ord __v) noexcept
- : _M_value(__cmp_cat::type(__v))
- { }
- public:
- // valid values
- static const strong_ordering less;
- static const strong_ordering equal;
- static const strong_ordering equivalent;
- static const strong_ordering greater;
- constexpr operator partial_ordering() const noexcept
- { return partial_ordering(__cmp_cat::_Ord(_M_value)); }
- constexpr operator weak_ordering() const noexcept
- { return weak_ordering(__cmp_cat::_Ord(_M_value)); }
- // comparisons
- friend constexpr bool
- operator==(strong_ordering __v, __cmp_cat::__unspec) noexcept
- { return __v._M_value == 0; }
- friend constexpr bool
- operator==(strong_ordering, strong_ordering) noexcept = default;
- friend constexpr bool
- operator< (strong_ordering __v, __cmp_cat::__unspec) noexcept
- { return __v._M_value < 0; }
- friend constexpr bool
- operator> (strong_ordering __v, __cmp_cat::__unspec) noexcept
- { return __v._M_value > 0; }
- friend constexpr bool
- operator<=(strong_ordering __v, __cmp_cat::__unspec) noexcept
- { return __v._M_value <= 0; }
- friend constexpr bool
- operator>=(strong_ordering __v, __cmp_cat::__unspec) noexcept
- { return __v._M_value >= 0; }
- friend constexpr bool
- operator< (__cmp_cat::__unspec, strong_ordering __v) noexcept
- { return 0 < __v._M_value; }
- friend constexpr bool
- operator> (__cmp_cat::__unspec, strong_ordering __v) noexcept
- { return 0 > __v._M_value; }
- friend constexpr bool
- operator<=(__cmp_cat::__unspec, strong_ordering __v) noexcept
- { return 0 <= __v._M_value; }
- friend constexpr bool
- operator>=(__cmp_cat::__unspec, strong_ordering __v) noexcept
- { return 0 >= __v._M_value; }
- friend constexpr strong_ordering
- operator<=>(strong_ordering __v, __cmp_cat::__unspec) noexcept
- { return __v; }
- friend constexpr strong_ordering
- operator<=>(__cmp_cat::__unspec, strong_ordering __v) noexcept
- { return strong_ordering(__cmp_cat::_Ord(-__v._M_value)); }
- };
- // valid values' definitions
- inline constexpr strong_ordering
- strong_ordering::less(__cmp_cat::_Ord::less);
- inline constexpr strong_ordering
- strong_ordering::equal(__cmp_cat::_Ord::equivalent);
- inline constexpr strong_ordering
- strong_ordering::equivalent(__cmp_cat::_Ord::equivalent);
- inline constexpr strong_ordering
- strong_ordering::greater(__cmp_cat::_Ord::greater);
- // named comparison functions
- constexpr bool
- is_eq(partial_ordering __cmp) noexcept
- { return __cmp == 0; }
- constexpr bool
- is_neq(partial_ordering __cmp) noexcept
- { return __cmp != 0; }
- constexpr bool
- is_lt (partial_ordering __cmp) noexcept
- { return __cmp < 0; }
- constexpr bool
- is_lteq(partial_ordering __cmp) noexcept
- { return __cmp <= 0; }
- constexpr bool
- is_gt (partial_ordering __cmp) noexcept
- { return __cmp > 0; }
- constexpr bool
- is_gteq(partial_ordering __cmp) noexcept
- { return __cmp >= 0; }
- namespace __detail
- {
- template<typename _Tp>
- inline constexpr unsigned __cmp_cat_id = 1;
- template<>
- inline constexpr unsigned __cmp_cat_id<partial_ordering> = 2;
- template<>
- inline constexpr unsigned __cmp_cat_id<weak_ordering> = 4;
- template<>
- inline constexpr unsigned __cmp_cat_id<strong_ordering> = 8;
- template<typename... _Ts>
- constexpr auto __common_cmp_cat()
- {
- constexpr unsigned __cats = (__cmp_cat_id<_Ts> | ...);
- // If any Ti is not a comparison category type, U is void.
- if constexpr (__cats & 1)
- return;
- // Otherwise, if at least one Ti is std::partial_ordering,
- // U is std::partial_ordering.
- else if constexpr (bool(__cats & __cmp_cat_id<partial_ordering>))
- return partial_ordering::equivalent;
- // Otherwise, if at least one Ti is std::weak_ordering,
- // U is std::weak_ordering.
- else if constexpr (bool(__cats & __cmp_cat_id<weak_ordering>))
- return weak_ordering::equivalent;
- // Otherwise, U is std::strong_ordering.
- else
- return strong_ordering::equivalent;
- }
- } // namespace __detail
- // [cmp.common], common comparison category type
- template<typename... _Ts>
- struct common_comparison_category
- {
- using type = decltype(__detail::__common_cmp_cat<_Ts...>());
- };
- // Partial specializations for one and zero argument cases.
- template<typename _Tp>
- struct common_comparison_category<_Tp>
- { using type = void; };
- template<>
- struct common_comparison_category<partial_ordering>
- { using type = partial_ordering; };
- template<>
- struct common_comparison_category<weak_ordering>
- { using type = weak_ordering; };
- template<>
- struct common_comparison_category<strong_ordering>
- { using type = strong_ordering; };
- template<>
- struct common_comparison_category<>
- { using type = strong_ordering; };
- template<typename... _Ts>
- using common_comparison_category_t
- = typename common_comparison_category<_Ts...>::type;
- #if __cpp_lib_concepts
- namespace __detail
- {
- template<typename _Tp, typename _Cat>
- concept __compares_as
- = same_as<common_comparison_category_t<_Tp, _Cat>, _Cat>;
- } // namespace __detail
- // [cmp.concept], concept three_way_comparable
- template<typename _Tp, typename _Cat = partial_ordering>
- concept three_way_comparable
- = __detail::__weakly_eq_cmp_with<_Tp, _Tp>
- && __detail::__partially_ordered_with<_Tp, _Tp>
- && requires(const remove_reference_t<_Tp>& __a,
- const remove_reference_t<_Tp>& __b)
- {
- { __a <=> __b } -> __detail::__compares_as<_Cat>;
- };
- template<typename _Tp, typename _Up, typename _Cat = partial_ordering>
- concept three_way_comparable_with
- = three_way_comparable<_Tp, _Cat>
- && three_way_comparable<_Up, _Cat>
- && common_reference_with<const remove_reference_t<_Tp>&,
- const remove_reference_t<_Up>&>
- && three_way_comparable<
- common_reference_t<const remove_reference_t<_Tp>&,
- const remove_reference_t<_Up>&>, _Cat>
- && __detail::__weakly_eq_cmp_with<_Tp, _Up>
- && __detail::__partially_ordered_with<_Tp, _Up>
- && requires(const remove_reference_t<_Tp>& __t,
- const remove_reference_t<_Up>& __u)
- {
- { __t <=> __u } -> __detail::__compares_as<_Cat>;
- { __u <=> __t } -> __detail::__compares_as<_Cat>;
- };
- namespace __detail
- {
- template<typename _Tp, typename _Up>
- using __cmp3way_res_t
- = decltype(std::declval<_Tp>() <=> std::declval<_Up>());
- // Implementation of std::compare_three_way_result.
- // It is undefined for a program to add specializations of
- // std::compare_three_way_result, so the std::compare_three_way_result_t
- // alias ignores std::compare_three_way_result and uses
- // __detail::__cmp3way_res_impl directly instead.
- template<typename _Tp, typename _Up>
- struct __cmp3way_res_impl
- { };
- template<typename _Tp, typename _Up>
- requires requires { typename __cmp3way_res_t<__cref<_Tp>, __cref<_Up>>; }
- struct __cmp3way_res_impl<_Tp, _Up>
- {
- using type = __cmp3way_res_t<__cref<_Tp>, __cref<_Up>>;
- };
- } // namespace __detail
- /// [cmp.result], result of three-way comparison
- template<typename _Tp, typename _Up = _Tp>
- struct compare_three_way_result
- : __detail::__cmp3way_res_impl<_Tp, _Up>
- { };
- /// [cmp.result], result of three-way comparison
- template<typename _Tp, typename _Up = _Tp>
- using compare_three_way_result_t
- = typename __detail::__cmp3way_res_impl<_Tp, _Up>::type;
- namespace __detail
- {
- // BUILTIN-PTR-THREE-WAY(T, U)
- // This determines whether t <=> u results in a call to a built-in
- // operator<=> comparing pointers. It doesn't work for function pointers
- // (PR 93628).
- template<typename _Tp, typename _Up>
- concept __3way_builtin_ptr_cmp
- = requires(_Tp&& __t, _Up&& __u)
- { static_cast<_Tp&&>(__t) <=> static_cast<_Up&&>(__u); }
- && convertible_to<_Tp, const volatile void*>
- && convertible_to<_Up, const volatile void*>
- && ! requires(_Tp&& __t, _Up&& __u)
- { operator<=>(static_cast<_Tp&&>(__t), static_cast<_Up&&>(__u)); }
- && ! requires(_Tp&& __t, _Up&& __u)
- { static_cast<_Tp&&>(__t).operator<=>(static_cast<_Up&&>(__u)); };
- } // namespace __detail
- // _GLIBCXX_RESOLVE_LIB_DEFECTS
- // 3530 BUILTIN-PTR-MEOW should not opt the type out of syntactic checks
- // [cmp.object], typename compare_three_way
- struct compare_three_way
- {
- template<typename _Tp, typename _Up>
- requires three_way_comparable_with<_Tp, _Up>
- constexpr auto
- operator()(_Tp&& __t, _Up&& __u) const
- noexcept(noexcept(std::declval<_Tp>() <=> std::declval<_Up>()))
- {
- if constexpr (__detail::__3way_builtin_ptr_cmp<_Tp, _Up>)
- {
- auto __pt = static_cast<const volatile void*>(__t);
- auto __pu = static_cast<const volatile void*>(__u);
- if (__builtin_is_constant_evaluated())
- return __pt <=> __pu;
- auto __it = reinterpret_cast<__UINTPTR_TYPE__>(__pt);
- auto __iu = reinterpret_cast<__UINTPTR_TYPE__>(__pu);
- return __it <=> __iu;
- }
- else
- return static_cast<_Tp&&>(__t) <=> static_cast<_Up&&>(__u);
- }
- using is_transparent = void;
- };
- namespace __cmp_cust
- {
- template<floating_point _Tp>
- constexpr weak_ordering
- __fp_weak_ordering(_Tp __e, _Tp __f)
- {
- // Returns an integer with the same sign as the argument, and magnitude
- // indicating the classification: zero=1 subnorm=2 norm=3 inf=4 nan=5
- auto __cat = [](_Tp __fp) -> int {
- const int __sign = __builtin_signbit(__fp) ? -1 : 1;
- if (__builtin_isnormal(__fp))
- return (__fp == 0 ? 1 : 3) * __sign;
- if (__builtin_isnan(__fp))
- return 5 * __sign;
- if (int __inf = __builtin_isinf_sign(__fp))
- return 4 * __inf;
- return 2 * __sign;
- };
- auto __po = __e <=> __f;
- if (is_lt(__po))
- return weak_ordering::less;
- else if (is_gt(__po))
- return weak_ordering::greater;
- else if (__po == partial_ordering::equivalent)
- return weak_ordering::equivalent;
- else // unordered, at least one argument is NaN
- {
- // return -1 for negative nan, +1 for positive nan, 0 otherwise.
- auto __isnan_sign = [](_Tp __fp) -> int {
- return __builtin_isnan(__fp)
- ? __builtin_signbit(__fp) ? -1 : 1
- : 0;
- };
- auto __ord = __isnan_sign(__e) <=> __isnan_sign(__f);
- if (is_eq(__ord))
- return weak_ordering::equivalent;
- else if (is_lt(__ord))
- return weak_ordering::less;
- else
- return weak_ordering::greater;
- }
- }
- template<typename _Tp, typename _Up>
- concept __adl_strong = requires(_Tp&& __t, _Up&& __u)
- {
- strong_ordering(strong_order(static_cast<_Tp&&>(__t),
- static_cast<_Up&&>(__u)));
- };
- template<typename _Tp, typename _Up>
- concept __adl_weak = requires(_Tp&& __t, _Up&& __u)
- {
- weak_ordering(weak_order(static_cast<_Tp&&>(__t),
- static_cast<_Up&&>(__u)));
- };
- template<typename _Tp, typename _Up>
- concept __adl_partial = requires(_Tp&& __t, _Up&& __u)
- {
- partial_ordering(partial_order(static_cast<_Tp&&>(__t),
- static_cast<_Up&&>(__u)));
- };
- template<typename _Ord, typename _Tp, typename _Up>
- concept __cmp3way = requires(_Tp&& __t, _Up&& __u, compare_three_way __c)
- {
- _Ord(__c(static_cast<_Tp&&>(__t), static_cast<_Up&&>(__u)));
- };
- template<typename _Tp, typename _Up>
- concept __strongly_ordered
- = __adl_strong<_Tp, _Up>
- // FIXME: || floating_point<remove_reference_t<_Tp>>
- || __cmp3way<strong_ordering, _Tp, _Up>;
- class _Strong_order
- {
- template<typename _Tp, typename _Up>
- static constexpr bool
- _S_noexcept()
- {
- if constexpr (floating_point<decay_t<_Tp>>)
- return true;
- else if constexpr (__adl_strong<_Tp, _Up>)
- return noexcept(strong_ordering(strong_order(std::declval<_Tp>(),
- std::declval<_Up>())));
- else if constexpr (__cmp3way<strong_ordering, _Tp, _Up>)
- return noexcept(compare_three_way()(std::declval<_Tp>(),
- std::declval<_Up>()));
- }
- friend class _Weak_order;
- friend class _Strong_fallback;
- public:
- template<typename _Tp, typename _Up>
- requires __strongly_ordered<_Tp, _Up>
- constexpr strong_ordering
- operator()(_Tp&& __e, _Up&& __f) const
- noexcept(_S_noexcept<_Tp, _Up>())
- {
- static_assert(same_as<decay_t<_Tp>, decay_t<_Up>>);
- /* FIXME:
- if constexpr (floating_point<decay_t<_Tp>>)
- return __cmp_cust::__fp_strong_order(__e, __f);
- else */ if constexpr (__adl_strong<_Tp, _Up>)
- return strong_ordering(strong_order(static_cast<_Tp&&>(__e),
- static_cast<_Up&&>(__f)));
- else if constexpr (__cmp3way<strong_ordering, _Tp, _Up>)
- return compare_three_way()(static_cast<_Tp&&>(__e),
- static_cast<_Up&&>(__f));
- }
- };
- template<typename _Tp, typename _Up>
- concept __weakly_ordered
- = floating_point<remove_reference_t<_Tp>>
- || __adl_weak<_Tp, _Up>
- || __cmp3way<weak_ordering, _Tp, _Up>
- || __strongly_ordered<_Tp, _Up>;
- class _Weak_order
- {
- template<typename _Tp, typename _Up>
- static constexpr bool
- _S_noexcept()
- {
- if constexpr (floating_point<decay_t<_Tp>>)
- return true;
- else if constexpr (__adl_weak<_Tp, _Up>)
- return noexcept(weak_ordering(weak_order(std::declval<_Tp>(),
- std::declval<_Up>())));
- else if constexpr (__cmp3way<weak_ordering, _Tp, _Up>)
- return noexcept(compare_three_way()(std::declval<_Tp>(),
- std::declval<_Up>()));
- else if constexpr (__strongly_ordered<_Tp, _Up>)
- return _Strong_order::_S_noexcept<_Tp, _Up>();
- }
- friend class _Partial_order;
- friend class _Weak_fallback;
- public:
- template<typename _Tp, typename _Up>
- requires __weakly_ordered<_Tp, _Up>
- constexpr weak_ordering
- operator()(_Tp&& __e, _Up&& __f) const
- noexcept(_S_noexcept<_Tp, _Up>())
- {
- static_assert(same_as<decay_t<_Tp>, decay_t<_Up>>);
- if constexpr (floating_point<decay_t<_Tp>>)
- return __cmp_cust::__fp_weak_ordering(__e, __f);
- else if constexpr (__adl_weak<_Tp, _Up>)
- return weak_ordering(weak_order(static_cast<_Tp&&>(__e),
- static_cast<_Up&&>(__f)));
- else if constexpr (__cmp3way<weak_ordering, _Tp, _Up>)
- return compare_three_way()(static_cast<_Tp&&>(__e),
- static_cast<_Up&&>(__f));
- else if constexpr (__strongly_ordered<_Tp, _Up>)
- return _Strong_order{}(static_cast<_Tp&&>(__e),
- static_cast<_Up&&>(__f));
- }
- };
- template<typename _Tp, typename _Up>
- concept __partially_ordered
- = __adl_partial<_Tp, _Up>
- || __cmp3way<partial_ordering, _Tp, _Up>
- || __weakly_ordered<_Tp, _Up>;
- class _Partial_order
- {
- template<typename _Tp, typename _Up>
- static constexpr bool
- _S_noexcept()
- {
- if constexpr (__adl_partial<_Tp, _Up>)
- return noexcept(partial_ordering(partial_order(std::declval<_Tp>(),
- std::declval<_Up>())));
- else if constexpr (__cmp3way<partial_ordering, _Tp, _Up>)
- return noexcept(compare_three_way()(std::declval<_Tp>(),
- std::declval<_Up>()));
- else if constexpr (__weakly_ordered<_Tp, _Up>)
- return _Weak_order::_S_noexcept<_Tp, _Up>();
- }
- friend class _Partial_fallback;
- public:
- template<typename _Tp, typename _Up>
- requires __partially_ordered<_Tp, _Up>
- constexpr partial_ordering
- operator()(_Tp&& __e, _Up&& __f) const
- noexcept(_S_noexcept<_Tp, _Up>())
- {
- static_assert(same_as<decay_t<_Tp>, decay_t<_Up>>);
- if constexpr (__adl_partial<_Tp, _Up>)
- return partial_ordering(partial_order(static_cast<_Tp&&>(__e),
- static_cast<_Up&&>(__f)));
- else if constexpr (__cmp3way<partial_ordering, _Tp, _Up>)
- return compare_three_way()(static_cast<_Tp&&>(__e),
- static_cast<_Up&&>(__f));
- else if constexpr (__weakly_ordered<_Tp, _Up>)
- return _Weak_order{}(static_cast<_Tp&&>(__e),
- static_cast<_Up&&>(__f));
- }
- };
- template<typename _Tp, typename _Up>
- concept __op_eq_lt = requires(_Tp&& __t, _Up&& __u)
- {
- { static_cast<_Tp&&>(__t) == static_cast<_Up&&>(__u) }
- -> convertible_to<bool>;
- { static_cast<_Tp&&>(__t) < static_cast<_Up&&>(__u) }
- -> convertible_to<bool>;
- };
- class _Strong_fallback
- {
- template<typename _Tp, typename _Up>
- static constexpr bool
- _S_noexcept()
- {
- if constexpr (__strongly_ordered<_Tp, _Up>)
- return _Strong_order::_S_noexcept<_Tp, _Up>();
- else
- return noexcept(bool(std::declval<_Tp>() == std::declval<_Up>()))
- && noexcept(bool(std::declval<_Tp>() < std::declval<_Up>()));
- }
- public:
- template<typename _Tp, typename _Up>
- requires __strongly_ordered<_Tp, _Up> || __op_eq_lt<_Tp, _Up>
- constexpr decltype(auto)
- operator()(_Tp&& __e, _Up&& __f) const
- noexcept(_S_noexcept<_Tp, _Up>())
- {
- static_assert(same_as<decay_t<_Tp>, decay_t<_Up>>);
- if constexpr (__strongly_ordered<_Tp, _Up>)
- return _Strong_order{}(static_cast<_Tp&&>(__e),
- static_cast<_Up&&>(__f));
- else if constexpr (__op_eq_lt<_Tp, _Up>)
- return static_cast<_Tp&&>(__e) == static_cast<_Up&&>(__f)
- ? strong_ordering::equal
- : static_cast<_Tp&&>(__e) < static_cast<_Up&&>(__f)
- ? strong_ordering::less
- : strong_ordering::greater;
- }
- };
- class _Weak_fallback
- {
- template<typename _Tp, typename _Up>
- static constexpr bool
- _S_noexcept()
- {
- if constexpr (__weakly_ordered<_Tp, _Up>)
- return _Weak_order::_S_noexcept<_Tp, _Up>();
- else
- return noexcept(bool(std::declval<_Tp>() == std::declval<_Up>()))
- && noexcept(bool(std::declval<_Tp>() < std::declval<_Up>()));
- }
- public:
- template<typename _Tp, typename _Up>
- requires __weakly_ordered<_Tp, _Up> || __op_eq_lt<_Tp, _Up>
- constexpr decltype(auto)
- operator()(_Tp&& __e, _Up&& __f) const
- noexcept(_S_noexcept<_Tp, _Up>())
- {
- static_assert(same_as<decay_t<_Tp>, decay_t<_Up>>);
- if constexpr (__weakly_ordered<_Tp, _Up>)
- return _Weak_order{}(static_cast<_Tp&&>(__e),
- static_cast<_Up&&>(__f));
- else if constexpr (__op_eq_lt<_Tp, _Up>)
- return static_cast<_Tp&&>(__e) == static_cast<_Up&&>(__f)
- ? weak_ordering::equivalent
- : static_cast<_Tp&&>(__e) < static_cast<_Up&&>(__f)
- ? weak_ordering::less
- : weak_ordering::greater;
- }
- };
- class _Partial_fallback
- {
- template<typename _Tp, typename _Up>
- static constexpr bool
- _S_noexcept()
- {
- if constexpr (__partially_ordered<_Tp, _Up>)
- return _Partial_order::_S_noexcept<_Tp, _Up>();
- else
- return noexcept(bool(std::declval<_Tp>() == std::declval<_Up>()))
- && noexcept(bool(std::declval<_Tp>() < std::declval<_Up>()));
- }
- public:
- template<typename _Tp, typename _Up>
- requires __partially_ordered<_Tp, _Up> || __op_eq_lt<_Tp, _Up>
- constexpr decltype(auto)
- operator()(_Tp&& __e, _Up&& __f) const
- noexcept(_S_noexcept<_Tp, _Up>())
- {
- static_assert(same_as<decay_t<_Tp>, decay_t<_Up>>);
- if constexpr (__partially_ordered<_Tp, _Up>)
- return _Partial_order{}(static_cast<_Tp&&>(__e),
- static_cast<_Up&&>(__f));
- else if constexpr (__op_eq_lt<_Tp, _Up>)
- return static_cast<_Tp&&>(__e) == static_cast<_Up&&>(__f)
- ? partial_ordering::equivalent
- : static_cast<_Tp&&>(__e) < static_cast<_Up&&>(__f)
- ? partial_ordering::less
- : static_cast<_Up&&>(__f) < static_cast<_Tp&&>(__e)
- ? partial_ordering::greater
- : partial_ordering::unordered;
- }
- };
- } // namespace __cmp_cust
- // [cmp.alg], comparison algorithms
- inline namespace __cmp_alg
- {
- inline constexpr __cmp_cust::_Strong_order strong_order{};
- inline constexpr __cmp_cust::_Weak_order weak_order{};
- inline constexpr __cmp_cust::_Partial_order partial_order{};
- inline constexpr __cmp_cust::_Strong_fallback
- compare_strong_order_fallback{};
- inline constexpr __cmp_cust::_Weak_fallback
- compare_weak_order_fallback{};
- inline constexpr __cmp_cust::_Partial_fallback
- compare_partial_order_fallback{};
- }
- namespace __detail
- {
- // [expos.only.func] synth-three-way
- inline constexpr struct _Synth3way
- {
- template<typename _Tp, typename _Up>
- static constexpr bool
- _S_noexcept(const _Tp* __t = nullptr, const _Up* __u = nullptr)
- {
- if constexpr (three_way_comparable_with<_Tp, _Up>)
- return noexcept(*__t <=> *__u);
- else
- return noexcept(*__t < *__u) && noexcept(*__u < *__t);
- }
- template<typename _Tp, typename _Up>
- constexpr auto
- operator()(const _Tp& __t, const _Up& __u) const
- noexcept(_S_noexcept<_Tp, _Up>())
- requires requires
- {
- { __t < __u } -> __boolean_testable;
- { __u < __t } -> __boolean_testable;
- }
- {
- if constexpr (three_way_comparable_with<_Tp, _Up>)
- return __t <=> __u;
- else
- {
- if (__t < __u)
- return weak_ordering::less;
- else if (__u < __t)
- return weak_ordering::greater;
- else
- return weak_ordering::equivalent;
- }
- }
- } __synth3way = {};
- // [expos.only.func] synth-three-way-result
- template<typename _Tp, typename _Up = _Tp>
- using __synth3way_t
- = decltype(__detail::__synth3way(std::declval<_Tp&>(),
- std::declval<_Up&>()));
- } // namespace __detail
- #endif // concepts
- } // namespace std
- #pragma GCC visibility pop
- #endif // C++20
- #endif // _COMPARE
|