1 //===----------------------------------------------------------------------===//
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //===----------------------------------------------------------------------===//
9 #ifndef _LIBCPP___COMPARE_STRONG_ORDER
10 #define _LIBCPP___COMPARE_STRONG_ORDER
12 #include <__bit/bit_cast.h>
13 #include <__compare/compare_three_way.h>
14 #include <__compare/ordering.h>
16 #include <__math/exponential_functions.h>
17 #include <__math/traits.h>
18 #include <__type_traits/conditional.h>
19 #include <__type_traits/decay.h>
20 #include <__type_traits/is_floating_point.h>
21 #include <__type_traits/is_same.h>
22 #include <__utility/forward.h>
23 #include <__utility/priority_tag.h>
27 #ifndef _LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER
28 # pragma GCC system_header
32 #include <__undef_macros>
34 _LIBCPP_BEGIN_NAMESPACE_STD
36 #if _LIBCPP_STD_VER >= 20
39 namespace __strong_order
{
40 void strong_order() = delete;
43 // NOLINTBEGIN(libcpp-robust-against-adl) strong_order should use ADL, but only here
44 template <class _Tp
, class _Up
>
45 requires is_same_v
<decay_t
<_Tp
>, decay_t
<_Up
>>
46 _LIBCPP_HIDE_FROM_ABI
static constexpr auto __go(_Tp
&& __t
, _Up
&& __u
, __priority_tag
<2>) noexcept(
47 noexcept(strong_ordering(strong_order(std::forward
<_Tp
>(__t
), std::forward
<_Up
>(__u
)))))
48 -> decltype(strong_ordering(strong_order(std::forward
<_Tp
>(__t
), std::forward
<_Up
>(__u
)))) {
49 return strong_ordering(strong_order(std::forward
<_Tp
>(__t
), std::forward
<_Up
>(__u
)));
51 // NOLINTEND(libcpp-robust-against-adl)
53 template <class _Tp
, class _Up
, class _Dp
= decay_t
<_Tp
>>
54 requires is_same_v
<_Dp
, decay_t
<_Up
>> && is_floating_point_v
<_Dp
>
55 _LIBCPP_HIDE_FROM_ABI
static constexpr strong_ordering
__go(_Tp
&& __t
, _Up
&& __u
, __priority_tag
<1>) noexcept
{
56 if constexpr (numeric_limits
<_Dp
>::is_iec559
&& sizeof(_Dp
) == sizeof(int32_t)) {
57 int32_t __rx
= std::bit_cast
<int32_t>(__t
);
58 int32_t __ry
= std::bit_cast
<int32_t>(__u
);
59 __rx
= (__rx
< 0) ? (numeric_limits
<int32_t>::min() - __rx
- 1) : __rx
;
60 __ry
= (__ry
< 0) ? (numeric_limits
<int32_t>::min() - __ry
- 1) : __ry
;
61 return (__rx
<=> __ry
);
62 } else if constexpr (numeric_limits
<_Dp
>::is_iec559
&& sizeof(_Dp
) == sizeof(int64_t)) {
63 int64_t __rx
= std::bit_cast
<int64_t>(__t
);
64 int64_t __ry
= std::bit_cast
<int64_t>(__u
);
65 __rx
= (__rx
< 0) ? (numeric_limits
<int64_t>::min() - __rx
- 1) : __rx
;
66 __ry
= (__ry
< 0) ? (numeric_limits
<int64_t>::min() - __ry
- 1) : __ry
;
67 return (__rx
<=> __ry
);
68 } else if (__t
< __u
) {
69 return strong_ordering::less
;
70 } else if (__t
> __u
) {
71 return strong_ordering::greater
;
72 } else if (__t
== __u
) {
73 if constexpr (numeric_limits
<_Dp
>::radix
== 2) {
74 return __math::signbit(__u
) <=> __math::signbit(__t
);
76 // This is bullet 3 of the IEEE754 algorithm, relevant
77 // only for decimal floating-point;
78 // see https://stackoverflow.com/questions/69068075/
79 if (__t
== 0 || __math::isinf(__t
)) {
80 return __math::signbit(__u
) <=> __math::signbit(__t
);
83 (void)__math::frexp(__t
, &__texp
);
84 (void)__math::frexp(__u
, &__uexp
);
85 return (__t
< 0) ? (__texp
<=> __uexp
) : (__uexp
<=> __texp
);
89 // They're unordered, so one of them must be a NAN.
90 // The order is -QNAN, -SNAN, numbers, +SNAN, +QNAN.
91 bool __t_is_nan
= __math::isnan(__t
);
92 bool __u_is_nan
= __math::isnan(__u
);
93 bool __t_is_negative
= __math::signbit(__t
);
94 bool __u_is_negative
= __math::signbit(__u
);
96 conditional_t
< sizeof(__t
) == sizeof(int32_t),
98 conditional_t
< sizeof(__t
) == sizeof(int64_t), int64_t, void> >;
99 if constexpr (is_same_v
<_IntType
, void>) {
100 static_assert(sizeof(_Dp
) == 0, "std::strong_order is unimplemented for this floating-point type");
101 } else if (__t_is_nan
&& __u_is_nan
) {
102 // Order by sign bit, then by "payload bits" (we'll just use bit_cast).
103 if (__t_is_negative
!= __u_is_negative
) {
104 return (__u_is_negative
<=> __t_is_negative
);
106 return std::bit_cast
<_IntType
>(__t
) <=> std::bit_cast
<_IntType
>(__u
);
108 } else if (__t_is_nan
) {
109 return __t_is_negative
? strong_ordering::less
: strong_ordering::greater
;
111 return __u_is_negative
? strong_ordering::greater
: strong_ordering::less
;
116 template <class _Tp
, class _Up
>
117 requires is_same_v
<decay_t
<_Tp
>, decay_t
<_Up
>>
118 _LIBCPP_HIDE_FROM_ABI
static constexpr auto __go(_Tp
&& __t
, _Up
&& __u
, __priority_tag
<0>) noexcept(
119 noexcept(strong_ordering(compare_three_way()(std::forward
<_Tp
>(__t
), std::forward
<_Up
>(__u
)))))
120 -> decltype(strong_ordering(compare_three_way()(std::forward
<_Tp
>(__t
), std::forward
<_Up
>(__u
)))) {
121 return strong_ordering(compare_three_way()(std::forward
<_Tp
>(__t
), std::forward
<_Up
>(__u
)));
124 template <class _Tp
, class _Up
>
125 _LIBCPP_HIDE_FROM_ABI
constexpr auto operator()(_Tp
&& __t
, _Up
&& __u
) const
126 noexcept(noexcept(__go(std::forward
<_Tp
>(__t
), std::forward
<_Up
>(__u
), __priority_tag
<2>())))
127 -> decltype(__go(std::forward
<_Tp
>(__t
), std::forward
<_Up
>(__u
), __priority_tag
<2>())) {
128 return __go(std::forward
<_Tp
>(__t
), std::forward
<_Up
>(__u
), __priority_tag
<2>());
131 } // namespace __strong_order
133 inline namespace __cpo
{
134 inline constexpr auto strong_order
= __strong_order::__fn
{};
137 #endif // _LIBCPP_STD_VER >= 20
139 _LIBCPP_END_NAMESPACE_STD
143 #endif // _LIBCPP___COMPARE_STRONG_ORDER