1 //===----------------------------------------------------------------------===// 2 // 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 6 // 7 //===----------------------------------------------------------------------===// 8 9 #ifndef _LIBCPP___COMPARE_STRONG_ORDER 10 #define _LIBCPP___COMPARE_STRONG_ORDER 11 12 #include <__bit/bit_cast.h> 13 #include <__compare/compare_three_way.h> 14 #include <__compare/ordering.h> 15 #include <__config> 16 #include <__utility/forward.h> 17 #include <__utility/priority_tag.h> 18 #include <cmath> 19 #include <cstdint> 20 #include <limits> 21 #include <type_traits> 22 23 #ifndef _LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER 24 #pragma GCC system_header 25 #endif 26 27 _LIBCPP_PUSH_MACROS 28 #include <__undef_macros> 29 30 _LIBCPP_BEGIN_NAMESPACE_STD 31 32 #if _LIBCPP_STD_VER > 17 && !defined(_LIBCPP_HAS_NO_CONCEPTS) 33 34 // [cmp.alg] 35 namespace __strong_order { 36 struct __fn { 37 template<class _Tp, class _Up> 38 requires is_same_v<decay_t<_Tp>, decay_t<_Up>> 39 _LIBCPP_HIDE_FROM_ABI static constexpr auto 40 __go(_Tp&& __t, _Up&& __u, __priority_tag<2>) 41 noexcept(noexcept(strong_ordering(strong_order(_VSTD::forward<_Tp>(__t), _VSTD::forward<_Up>(__u))))) 42 -> decltype( strong_ordering(strong_order(_VSTD::forward<_Tp>(__t), _VSTD::forward<_Up>(__u)))) 43 { return strong_ordering(strong_order(_VSTD::forward<_Tp>(__t), _VSTD::forward<_Up>(__u))); } 44 45 template<class _Tp, class _Up, class _Dp = decay_t<_Tp>> 46 requires is_same_v<_Dp, decay_t<_Up>> && is_floating_point_v<_Dp> 47 _LIBCPP_HIDE_FROM_ABI static constexpr strong_ordering 48 __go(_Tp&& __t, _Up&& __u, __priority_tag<1>) noexcept 49 { 50 if constexpr (numeric_limits<_Dp>::is_iec559 && sizeof(_Dp) == sizeof(int32_t)) { 51 int32_t __rx = _VSTD::bit_cast<int32_t>(__t); 52 int32_t __ry = _VSTD::bit_cast<int32_t>(__u); 53 __rx = (__rx < 0) ? (numeric_limits<int32_t>::min() - __rx - 1) : __rx; 54 __ry = (__ry < 0) ? (numeric_limits<int32_t>::min() - __ry - 1) : __ry; 55 return (__rx <=> __ry); 56 } else if constexpr (numeric_limits<_Dp>::is_iec559 && sizeof(_Dp) == sizeof(int64_t)) { 57 int64_t __rx = _VSTD::bit_cast<int64_t>(__t); 58 int64_t __ry = _VSTD::bit_cast<int64_t>(__u); 59 __rx = (__rx < 0) ? (numeric_limits<int64_t>::min() - __rx - 1) : __rx; 60 __ry = (__ry < 0) ? (numeric_limits<int64_t>::min() - __ry - 1) : __ry; 61 return (__rx <=> __ry); 62 } else if (__t < __u) { 63 return strong_ordering::less; 64 } else if (__t > __u) { 65 return strong_ordering::greater; 66 } else if (__t == __u) { 67 if constexpr (numeric_limits<_Dp>::radix == 2) { 68 return _VSTD::signbit(__u) <=> _VSTD::signbit(__t); 69 } else { 70 // This is bullet 3 of the IEEE754 algorithm, relevant 71 // only for decimal floating-point; 72 // see https://stackoverflow.com/questions/69068075/ 73 if (__t == 0 || _VSTD::isinf(__t)) { 74 return _VSTD::signbit(__u) <=> _VSTD::signbit(__t); 75 } else { 76 int __texp, __uexp; 77 (void)_VSTD::frexp(__t, &__texp); 78 (void)_VSTD::frexp(__u, &__uexp); 79 return (__t < 0) ? (__texp <=> __uexp) : (__uexp <=> __texp); 80 } 81 } 82 } else { 83 // They're unordered, so one of them must be a NAN. 84 // The order is -QNAN, -SNAN, numbers, +SNAN, +QNAN. 85 bool __t_is_nan = _VSTD::isnan(__t); 86 bool __u_is_nan = _VSTD::isnan(__u); 87 bool __t_is_negative = _VSTD::signbit(__t); 88 bool __u_is_negative = _VSTD::signbit(__u); 89 using _IntType = conditional_t< 90 sizeof(__t) == sizeof(int32_t), int32_t, conditional_t< 91 sizeof(__t) == sizeof(int64_t), int64_t, void> 92 >; 93 if constexpr (is_same_v<_IntType, void>) { 94 static_assert(sizeof(_Dp) == 0, "std::strong_order is unimplemented for this floating-point type"); 95 } else if (__t_is_nan && __u_is_nan) { 96 // Order by sign bit, then by "payload bits" (we'll just use bit_cast). 97 if (__t_is_negative != __u_is_negative) { 98 return (__u_is_negative <=> __t_is_negative); 99 } else { 100 return _VSTD::bit_cast<_IntType>(__t) <=> _VSTD::bit_cast<_IntType>(__u); 101 } 102 } else if (__t_is_nan) { 103 return __t_is_negative ? strong_ordering::less : strong_ordering::greater; 104 } else { 105 return __u_is_negative ? strong_ordering::greater : strong_ordering::less; 106 } 107 } 108 } 109 110 template<class _Tp, class _Up> 111 requires is_same_v<decay_t<_Tp>, decay_t<_Up>> 112 _LIBCPP_HIDE_FROM_ABI static constexpr auto 113 __go(_Tp&& __t, _Up&& __u, __priority_tag<0>) 114 noexcept(noexcept(strong_ordering(compare_three_way()(_VSTD::forward<_Tp>(__t), _VSTD::forward<_Up>(__u))))) 115 -> decltype( strong_ordering(compare_three_way()(_VSTD::forward<_Tp>(__t), _VSTD::forward<_Up>(__u)))) 116 { return strong_ordering(compare_three_way()(_VSTD::forward<_Tp>(__t), _VSTD::forward<_Up>(__u))); } 117 118 template<class _Tp, class _Up> 119 _LIBCPP_HIDE_FROM_ABI constexpr auto operator()(_Tp&& __t, _Up&& __u) const 120 noexcept(noexcept(__go(_VSTD::forward<_Tp>(__t), _VSTD::forward<_Up>(__u), __priority_tag<2>()))) 121 -> decltype( __go(_VSTD::forward<_Tp>(__t), _VSTD::forward<_Up>(__u), __priority_tag<2>())) 122 { return __go(_VSTD::forward<_Tp>(__t), _VSTD::forward<_Up>(__u), __priority_tag<2>()); } 123 }; 124 } // namespace __strong_order 125 126 inline namespace __cpo { 127 inline constexpr auto strong_order = __strong_order::__fn{}; 128 } // namespace __cpo 129 130 #endif // _LIBCPP_STD_VER > 17 && !defined(_LIBCPP_HAS_NO_CONCEPTS) 131 132 _LIBCPP_END_NAMESPACE_STD 133 134 _LIBCPP_POP_MACROS 135 136 #endif // _LIBCPP___COMPARE_STRONG_ORDER 137