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
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
#ifndef BOOST_NUMERIC_SAFE_BASE_HPP
#define BOOST_NUMERIC_SAFE_BASE_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 <limits>
#include <type_traits> // is_integral, enable_if, conditional is_convertible
#include <boost/config.hpp> // BOOST_CLANG
#include "concept/exception_policy.hpp"
#include "concept/promotion_policy.hpp"
 
#include "safe_common.hpp"
#include "exception_policies.hpp"
 
#include "boost/concept/assert.hpp"
 
namespace boost {
namespace safe_numerics {
 
/////////////////////////////////////////////////////////////////
// forward declarations to support friend function declarations
// in safe_base
 
template<
    class Stored,
    Stored Min,
    Stored Max,
    class P, // promotion polic
    class E  // exception policy
>
class safe_base;
 
template<
    class T,
    T Min,
    T Max,
    class P,
    class E
>
struct is_safe<safe_base<T, Min, Max, P, E> > : public std::true_type
{};
 
template<
    class T,
    T Min,
    T Max,
    class P,
    class E
>
struct get_promotion_policy<safe_base<T, Min, Max, P, E> > {
    using type = P;
};
 
template<
    class T,
    T Min,
    T Max,
    class P,
    class E
>
struct get_exception_policy<safe_base<T, Min, Max, P, E> > {
    using type = E;
};
 
template<
    class T,
    T Min,
    T Max,
    class P,
    class E
>
struct base_type<safe_base<T, Min, Max, P, E> > {
    using type = T;
};
 
template<
    class T,
    T Min,
    T Max,
    class P,
    class E
>
constexpr T base_value(
    const safe_base<T, Min, Max, P, E>  & st
) {
    return static_cast<T>(st);
}
 
template<
    typename T,
    T N,
    class P, // promotion policy
    class E  // exception policy
>
class safe_literal_impl;
 
// works for both GCC and clang
#if BOOST_CLANG==1
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wmismatched-tags"
#endif
 
/////////////////////////////////////////////////////////////////
// Main implementation
 
template<
    class Stored,
    Stored Min,
    Stored Max,
    class P, // promotion polic
    class E  // exception policy
>
class safe_base {
private:
    BOOST_CONCEPT_ASSERT((PromotionPolicy<P>));
    BOOST_CONCEPT_ASSERT((ExceptionPolicy<E>));
    Stored m_t;
 
    template<
        class StoredX,
        StoredX MinX,
        StoredX MaxX,
        class PX, // promotion polic
        class EX  // exception policy
    >
    friend class safe_base;
 
    friend class std::numeric_limits<safe_base>;
 
    template<class T>
    constexpr Stored validated_cast(const T & t) const;
 
    // stream support
 
    template<class CharT, class Traits>
    void output(std::basic_ostream<CharT, Traits> & os) const;
 
    // note usage of friend declaration to mark function as
    // a global function rather than a member function.  If
    // this is not done, the compiler will confuse this with
    // a member operator overload on the << operator.  Weird
    // I know.  But it's documented here
    // http://en.cppreference.com/w/cpp/language/friend
    // under the heading "Template friend operators"
    template<class CharT, class Traits>
    friend std::basic_ostream<CharT, Traits> &
    operator<<(
        std::basic_ostream<CharT, Traits> & os,
        const safe_base & t
    ){
        t.output(os);
        return os;
    }
 
    template<class CharT, class Traits>
    void input(std::basic_istream<CharT, Traits> & is);
 
    // see above
    template<class CharT, class Traits>
    friend inline std::basic_istream<CharT, Traits> &
    operator>>(
        std::basic_istream<CharT, Traits> & is,
        safe_base & t
    ){
        t.input(is);
        return is;
    }
    
public:
    ////////////////////////////////////////////////////////////
    // constructors
 
    constexpr safe_base();
 
    struct skip_validation{};
 
    constexpr explicit safe_base(const Stored & rhs, skip_validation);
 
    // construct an instance of a safe type from an instance of a convertible underlying type.
    template<
        class T,
        typename std::enable_if<
            std::is_convertible<T, Stored>::value,
            bool
        >::type = 0
    >
    constexpr /*explicit*/ safe_base(const T & t);
 
    // construct an instance of a safe type from a literal value
    template<typename T, T N, class Px, class Ex>
    constexpr /*explicit*/ safe_base(const safe_literal_impl<T, N, Px, Ex> & t);
 
    // note: Rule of Five. Supply all or none of the following
    // a) user-defined destructor
    ~safe_base() = default;
    // b) copy-constructor
    constexpr safe_base(const safe_base &) = default;
    // c) copy-assignment
    constexpr safe_base & operator=(const safe_base &) = default;
    // d) move constructor
    constexpr safe_base(safe_base &&) = default;
    // e) move assignment operator
    constexpr safe_base & operator=(safe_base &&) = default;
 
    /////////////////////////////////////////////////////////////////
    // 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.  validity of safe types is checked in
    // the constructor of safe types
    template<
        class R,
        typename std::enable_if<
            ! boost::safe_numerics::is_safe<R>::value,
            int
        >::type = 0
    >
    constexpr /*explicit*/ operator R () const;
 
    /////////////////////////////////////////////////////////////////
    // modification binary operators
    template<class T>
    constexpr safe_base &
    operator=(const T & rhs){
        m_t = validated_cast(rhs);
        return *this;
    }
 
    // mutating unary operators
    safe_base & operator++(){      // pre increment
        return *this = *this + 1;
    }
    safe_base & operator--(){      // pre decrement
        return *this = *this - 1;
    }
    safe_base operator++(int){   // post increment
        safe_base old_t = *this;
        ++(*this);
        return old_t;
    }
    safe_base operator--(int){ // post decrement
        safe_base old_t = *this;
        --(*this);
        return old_t;
    }
    // non mutating unary operators
    constexpr auto operator+() const { // unary plus
        return *this;
    }
    // after much consideration, I've permited the resulting value of a unary
    // - to change the type.  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.
    */
    constexpr auto operator-() const { // unary minus
        // if this is a unsigned type and the promotion policy is native
        // the result will be unsigned. But then the operation will fail
        // according to the requirements of arithmetic correctness.
        // if this is an unsigned type and the promotion policy is automatic.
        // the result will be signed.
        return 0 - *this;
    }
    /*   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 auto operator~() const { // complement
        return ~Stored(0u) ^ *this;
    }
};
 
} // safe_numerics
} // boost
 
/////////////////////////////////////////////////////////////////
// numeric limits for safe<int> etc.
 
#include <limits>
 
namespace std {
 
template<
    class T,
    T Min,
    T Max,
    class P,
    class E
>
class numeric_limits<boost::safe_numerics::safe_base<T, Min, Max, P, E> >
    : public std::numeric_limits<T>
{
    using SB = boost::safe_numerics::safe_base<T, Min, Max, P, E>;
public:
    constexpr static SB lowest() noexcept {
        return SB(Min, typename SB::skip_validation());
    }
    constexpr static SB min() noexcept {
        return SB(Min, typename SB::skip_validation());
    }
    constexpr static SB max() noexcept {
        return SB(Max, typename SB::skip_validation());
    }
};
 
} // std
 
#if BOOST_CLANG==1
#pragma GCC diagnostic pop
#endif
 
#endif // BOOST_NUMERIC_SAFE_BASE_HPP