liuxiaolong
2021-07-20 58d904a328c0d849769b483e901a0be9426b8209
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
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
#ifndef BOOST_NUMERIC_SAFE_INTEGER_LITERAL_HPP
#define BOOST_NUMERIC_SAFE_INTEGER_LITERAL_HPP
 
//  Copyright (c) 2012 Robert Ramey
//
// Distributed under the Boost Software License, Version 1.0. (See
// accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
 
#include <cstdint> // for intmax_t/uintmax_t
#include <iosfwd>
#include <type_traits> // conditional, enable_if
#include <boost/mp11/utility.hpp>
 
#include "utility.hpp"
#include "safe_integer.hpp"
#include "checked_integer.hpp"
 
namespace boost {
namespace safe_numerics {
 
template<typename T, T N, class P, class E>
class safe_literal_impl;
 
template<typename T, T N, class P, class E>
struct is_safe<safe_literal_impl<T, N, P, E> > : public std::true_type
{};
 
template<typename T, T N, class P, class E>
struct get_promotion_policy<safe_literal_impl<T, N, P, E> > {
    using type = P;
};
 
template<typename T, T N, class P, class E>
struct get_exception_policy<safe_literal_impl<T, N, P, E> > {
    using type = E;
};
template<typename T, T N, class P, class E>
struct base_type<safe_literal_impl<T, N, P, E> > {
    using type = T;
};
 
template<typename T, T N, class P, class E>
constexpr T base_value(
    const safe_literal_impl<T, N, P, E> &
) {
    return N;
}
 
template<typename CharT, typename Traits, typename T, T N, class P, class E>
inline std::basic_ostream<CharT, Traits> & operator<<(
    std::basic_ostream<CharT, Traits> & os,
    const safe_literal_impl<T, N, P, E> &
){
    return os << (
        (std::is_same<T, signed char>::value
        || std::is_same<T, unsigned char>::value
        ) ?
            static_cast<int>(N)
        :
            N
    );
}
 
template<typename T, T N, class P, class E>
class safe_literal_impl {
 
    template<
        class CharT,
        class Traits
    >
    friend std::basic_ostream<CharT, Traits> & operator<<(
        std::basic_ostream<CharT, Traits> & os,
        const safe_literal_impl &
    ){
        return os << (
            (::std::is_same<T, signed char>::value
            || ::std::is_same<T, unsigned char>::value
            || ::std::is_same<T, wchar_t>::value
            ) ?
                static_cast<int>(N)
            :
                N
        );
    };
 
public:
 
    ////////////////////////////////////////////////////////////
    // constructors
    // default constructor
    constexpr safe_literal_impl(){}
 
    /////////////////////////////////////////////////////////////////
    // casting operators for intrinsic integers
    // convert to any type which is not safe.  safe types need to be
    // excluded to prevent ambiguous function selection which
    // would otherwise occur
    template<
        class R,
        typename std::enable_if<
            ! boost::safe_numerics::is_safe<R>::value,
            int
        >::type = 0
    >
    constexpr operator R () const {
        // if static values don't overlap, the program can never function
        #if 1
        constexpr const interval<R> r_interval;
        static_assert(
            ! r_interval.excludes(N),
            "safe type cannot be constructed with this type"
        );
        #endif
 
        return validate_detail<
            R,
            std::numeric_limits<R>::min(),
            std::numeric_limits<R>::max(),
            E
        >::return_value(*this);
    }
 
    // non mutating unary operators
    constexpr safe_literal_impl<T, N, P, E> operator+() const { // unary plus
        return safe_literal_impl<T, N, P, E>();
    }
    // after much consideration, I've permitted the resulting value of a unary
    // - to change the type in accordance with the promotion policy.
    // The C++ standard does invoke integral promotions so it's changing the type as well.
 
    /*  section 5.3.1 &8 of the C++ standard
    The operand of the unary - operator shall have arithmetic or unscoped
    enumeration type and the result is the negation of its operand. Integral
    promotion is performed on integral or enumeration operands. The negative
    of an unsigned quantity is computed by subtracting its value from 2n,
    where n is the number of bits in the promoted operand. The type of the
    result is the type of the promoted operand.
    */
    template<
        typename Tx, Tx Nx, typename = std::enable_if_t<! checked::minus(Nx).exception()>
    >
    constexpr auto minus_helper() const {
        return safe_literal_impl<Tx, -N, P, E>();
    }
 
    constexpr auto operator-() const { // unary minus
        return minus_helper<T, N>();
    }
 
    /*   section 5.3.1 &10 of the C++ standard
    The operand of ~ shall have integral or unscoped enumeration type; 
    the result is the ones’ complement of its operand. Integral promotions 
    are performed. The type of the result is the type of the promoted operand.
    constexpr safe_literal_impl<T, checked::bitwise_not(N), P, E> operator~() const { // invert bits
        return safe_literal_impl<T, checked::bitwise_not(N), P, E>();
    }
    */
    template<
        typename Tx, Tx Nx, typename = std::enable_if_t<! checked::bitwise_not(Nx).exception()>
    >
    constexpr auto not_helper() const {
        return safe_literal_impl<Tx, ~N, P, E>();
    }
 
    constexpr auto operator~() const { // unary minus
        return not_helper<T, N>();
    }
};
 
template<
    std::intmax_t N,
    class P = void,
    class E = void
>
using safe_signed_literal = safe_literal_impl<
    typename utility::signed_stored_type<N, N>,
    N,
    P,
    E
>;
 
template<
    std::uintmax_t N,
    class P = void,
    class E = void
>
using safe_unsigned_literal = safe_literal_impl<
    typename utility::unsigned_stored_type<N, N>,
    N,
    P,
    E
>;
 
template<
    class T,
    T N,
    class P = void,
    class E = void,
    typename std::enable_if<
        std::is_signed<T>::value,
        int
    >::type = 0
>
constexpr auto make_safe_literal_impl() {
    return boost::safe_numerics::safe_signed_literal<N, P, E>();
}
 
template<
    class T,
    T N,
    class P = void,
    class E = void,
    typename std::enable_if<
        ! std::is_signed<T>::value,
        int
    >::type = 0
>
constexpr auto make_safe_literal_impl() {
    return boost::safe_numerics::safe_unsigned_literal<N, P, E>();
}
 
} // safe_numerics
} // boost
 
#define make_safe_literal(n, P, E)  \
    boost::safe_numerics::make_safe_literal_impl<decltype(n), n, P, E>()
 
/////////////////////////////////////////////////////////////////
// numeric limits for safe_literal etc.
 
#include <limits>
 
namespace std {
 
template<
    typename T,
    T N,
    class P,
    class E
>
class numeric_limits<boost::safe_numerics::safe_literal_impl<T, N, P, E> >
    : public std::numeric_limits<T>
{
    using SL = boost::safe_numerics::safe_literal_impl<T, N, P, E>;
public:
    constexpr static SL lowest() noexcept {
        return SL();
    }
    constexpr static SL min() noexcept {
        return SL();
    }
    constexpr static SL max() noexcept {
        return SL();
    }
};
 
} // std
 
#endif // BOOST_NUMERIC_SAFE_INTEGER_LITERAL_HPP