aboutsummaryrefslogtreecommitdiffstats
path: root/contrib/libs/cxxsupp/libcxx/include/__compare/strong_order.h
blob: 05856c2093905522ded9f954b84fe037e6252fe3 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//

#ifndef _LIBCPP___COMPARE_STRONG_ORDER
#define _LIBCPP___COMPARE_STRONG_ORDER

#include <__bit/bit_cast.h>
#include <__compare/compare_three_way.h>
#include <__compare/ordering.h>
#include <__config>
#include <__type_traits/conditional.h>
#include <__type_traits/decay.h>
#include <__utility/forward.h>
#include <__utility/priority_tag.h>
#include <cmath>
#include <cstdint>
#include <limits>

#ifndef _LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER
#  pragma GCC system_header
#endif

_LIBCPP_PUSH_MACROS
#include <__undef_macros>

_LIBCPP_BEGIN_NAMESPACE_STD

#if _LIBCPP_STD_VER > 17

// [cmp.alg]
namespace __strong_order {
    struct __fn {
    // NOLINTBEGIN(libcpp-robust-against-adl) strong_order should use ADL, but only here
        template<class _Tp, class _Up>
            requires is_same_v<decay_t<_Tp>, decay_t<_Up>>
        _LIBCPP_HIDE_FROM_ABI static constexpr auto
        __go(_Tp&& __t, _Up&& __u, __priority_tag<2>)
            noexcept(noexcept(strong_ordering(strong_order(_VSTD::forward<_Tp>(__t), _VSTD::forward<_Up>(__u)))))
            -> decltype(      strong_ordering(strong_order(_VSTD::forward<_Tp>(__t), _VSTD::forward<_Up>(__u))))
            { return          strong_ordering(strong_order(_VSTD::forward<_Tp>(__t), _VSTD::forward<_Up>(__u))); }
    // NOLINTEND(libcpp-robust-against-adl)

        template<class _Tp, class _Up, class _Dp = decay_t<_Tp>>
            requires is_same_v<_Dp, decay_t<_Up>> && is_floating_point_v<_Dp>
        _LIBCPP_HIDE_FROM_ABI static constexpr strong_ordering
        __go(_Tp&& __t, _Up&& __u, __priority_tag<1>) noexcept
        {
            if constexpr (numeric_limits<_Dp>::is_iec559 && sizeof(_Dp) == sizeof(int32_t)) {
                int32_t __rx = _VSTD::bit_cast<int32_t>(__t);
                int32_t __ry = _VSTD::bit_cast<int32_t>(__u);
                __rx = (__rx < 0) ? (numeric_limits<int32_t>::min() - __rx - 1) : __rx;
                __ry = (__ry < 0) ? (numeric_limits<int32_t>::min() - __ry - 1) : __ry;
                return (__rx <=> __ry);
            } else if constexpr (numeric_limits<_Dp>::is_iec559 && sizeof(_Dp) == sizeof(int64_t)) {
                int64_t __rx = _VSTD::bit_cast<int64_t>(__t);
                int64_t __ry = _VSTD::bit_cast<int64_t>(__u);
                __rx = (__rx < 0) ? (numeric_limits<int64_t>::min() - __rx - 1) : __rx;
                __ry = (__ry < 0) ? (numeric_limits<int64_t>::min() - __ry - 1) : __ry;
                return (__rx <=> __ry);
            } else if (__t < __u) {
                return strong_ordering::less;
            } else if (__t > __u) {
                return strong_ordering::greater;
            } else if (__t == __u) {
                if constexpr (numeric_limits<_Dp>::radix == 2) {
                    return _VSTD::signbit(__u) <=> _VSTD::signbit(__t);
                } else {
                    // This is bullet 3 of the IEEE754 algorithm, relevant
                    // only for decimal floating-point;
                    // see https://stackoverflow.com/questions/69068075/
                    if (__t == 0 || _VSTD::isinf(__t)) {
                        return _VSTD::signbit(__u) <=> _VSTD::signbit(__t);
                    } else {
                        int __texp, __uexp;
                        (void)_VSTD::frexp(__t, &__texp);
                        (void)_VSTD::frexp(__u, &__uexp);
                        return (__t < 0) ? (__texp <=> __uexp) : (__uexp <=> __texp);
                    }
                }
            } else {
                // They're unordered, so one of them must be a NAN.
                // The order is -QNAN, -SNAN, numbers, +SNAN, +QNAN.
                bool __t_is_nan = _VSTD::isnan(__t);
                bool __u_is_nan = _VSTD::isnan(__u);
                bool __t_is_negative = _VSTD::signbit(__t);
                bool __u_is_negative = _VSTD::signbit(__u);
                using _IntType = conditional_t<
                    sizeof(__t) == sizeof(int32_t), int32_t, conditional_t<
                    sizeof(__t) == sizeof(int64_t), int64_t, void>
                >;
                if constexpr (is_same_v<_IntType, void>) {
                    static_assert(sizeof(_Dp) == 0, "std::strong_order is unimplemented for this floating-point type");
                } else if (__t_is_nan && __u_is_nan) {
                    // Order by sign bit, then by "payload bits" (we'll just use bit_cast).
                    if (__t_is_negative != __u_is_negative) {
                        return (__u_is_negative <=> __t_is_negative);
                    } else {
                        return _VSTD::bit_cast<_IntType>(__t) <=> _VSTD::bit_cast<_IntType>(__u);
                    }
                } else if (__t_is_nan) {
                    return __t_is_negative ? strong_ordering::less : strong_ordering::greater;
                } else {
                    return __u_is_negative ? strong_ordering::greater : strong_ordering::less;
                }
            }
        }

        template<class _Tp, class _Up>
            requires is_same_v<decay_t<_Tp>, decay_t<_Up>>
        _LIBCPP_HIDE_FROM_ABI static constexpr auto
        __go(_Tp&& __t, _Up&& __u, __priority_tag<0>)
            noexcept(noexcept(strong_ordering(compare_three_way()(_VSTD::forward<_Tp>(__t), _VSTD::forward<_Up>(__u)))))
            -> decltype(      strong_ordering(compare_three_way()(_VSTD::forward<_Tp>(__t), _VSTD::forward<_Up>(__u))))
            { return          strong_ordering(compare_three_way()(_VSTD::forward<_Tp>(__t), _VSTD::forward<_Up>(__u))); }

        template<class _Tp, class _Up>
        _LIBCPP_HIDE_FROM_ABI constexpr auto operator()(_Tp&& __t, _Up&& __u) const
            noexcept(noexcept(__go(_VSTD::forward<_Tp>(__t), _VSTD::forward<_Up>(__u), __priority_tag<2>())))
            -> decltype(      __go(_VSTD::forward<_Tp>(__t), _VSTD::forward<_Up>(__u), __priority_tag<2>()))
            { return          __go(_VSTD::forward<_Tp>(__t), _VSTD::forward<_Up>(__u), __priority_tag<2>()); }
    };
} // namespace __strong_order

inline namespace __cpo {
    inline constexpr auto strong_order = __strong_order::__fn{};
} // namespace __cpo

#endif // _LIBCPP_STD_VER > 17

_LIBCPP_END_NAMESPACE_STD

_LIBCPP_POP_MACROS

#endif // _LIBCPP___COMPARE_STRONG_ORDER