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
#ifndef BOOST_NUMERIC_CPP_HPP
#define BOOST_NUMERIC_CPP_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)
 
// policy which creates results types equal to that of C++ promotions.
// Using the policy will permit the program to build and run in release
// mode which is identical to that in debug mode except for the fact
// that errors aren't trapped. 
 
#include <type_traits> // integral constant, remove_cv, conditional
#include <limits>
#include <boost/integer.hpp> // integer type selection
 
#include "safe_common.hpp"
#include "checked_result.hpp"
 
namespace boost {
namespace safe_numerics {
 
// in C++ the following rules govern integer arithmetic
 
// This policy is use to emulate another compiler/machine architecture
// For example, a Z80 has 8 bit char, 16 bit short, 16 bit int, 32 bit long.  So one
// would use cpp<8, 16, 16, 32, 32> to test programs destined to run on a Z80
 
// Follow section 5 of the standard.
template<
    int CharBits,
    int ShortBits,
    int IntBits,
    int LongBits,
    int LongLongBits
>
struct cpp {
public:
    using local_char_type = typename boost::int_t<CharBits>::exact;
    using local_short_type = typename boost::int_t<ShortBits>::exact;
    using local_int_type = typename boost::int_t<IntBits>::exact;
    using local_long_type = typename boost::int_t<LongBits>::exact;
    using local_long_long_type = typename boost::int_t<LongLongBits>::exact;
 
    template<class T>
    using rank =
        typename std::conditional<
            std::is_same<local_char_type, typename std::make_signed<T>::type>::value,
            std::integral_constant<int, 1>,
        typename std::conditional<
            std::is_same<local_short_type, typename std::make_signed<T>::type>::value,
            std::integral_constant<int, 2>,
        typename std::conditional<
            std::is_same<local_int_type, typename std::make_signed<T>::type>::value,
            std::integral_constant<int, 3>,
        typename std::conditional<
            std::is_same<local_long_type, typename std::make_signed<T>::type>::value,
            std::integral_constant<int, 4>,
        typename std::conditional<
            std::is_same<local_long_long_type, typename std::make_signed<T>::type>::value,
            std::integral_constant<int, 5>,
            std::integral_constant<int, 6> // catch all - never promote integral
        >::type >::type >::type >::type >::type;
 
    // section 4.5 integral promotions
 
   // convert smaller of two types to the size of the larger
    template<class T, class U>
    using higher_ranked_type = typename std::conditional<
        (rank<T>::value < rank<U>::value),
        U,
        T
    >::type;
 
    template<class T, class U>
    using copy_sign = typename std::conditional<
        std::is_signed<U>::value,
        typename std::make_signed<T>::type,
        typename std::make_unsigned<T>::type
    >::type;
 
    template<class T>
    using integral_promotion = copy_sign<
        higher_ranked_type<local_int_type, T>,
        T
    >;
 
    // note presumption that T & U don't have he same sign
    // if that's not true, these won't work
    template<class T, class U>
    using select_signed = typename std::conditional<
        std::numeric_limits<T>::is_signed,
        T,
        U
    >::type;
 
    template<class T, class U>
    using select_unsigned = typename std::conditional<
        std::numeric_limits<T>::is_signed,
        U,
        T
    >::type;
 
    // section 5 clause 11 - usual arithmetic conversions
    template<typename T, typename U>
    using usual_arithmetic_conversions =
        // clause 0 - if both operands have the same type
        typename std::conditional<
            std::is_same<T, U>::value,
            // no further conversion is needed
            T,
        // clause 1 - otherwise if both operands have the same sign
        typename std::conditional<
            std::numeric_limits<T>::is_signed
            == std::numeric_limits<U>::is_signed,
            // convert to the higher ranked type
            higher_ranked_type<T, U>,
        // clause 2 - otherwise if the rank of he unsigned type exceeds
        // the rank of the of the signed type
        typename std::conditional<
            rank<select_unsigned<T, U>>::value
            >= rank< select_signed<T, U>>::value,
            // use unsigned type
            select_unsigned<T, U>,
        // clause 3 - otherwise if the type of the signed integer type can
        // represent all the values of the unsigned type
        typename std::conditional<
            std::numeric_limits< select_signed<T, U>>::digits >=
            std::numeric_limits< select_unsigned<T, U>>::digits,
            // use signed type
            select_signed<T, U>,
        // clause 4 - otherwise use unsigned version of the signed type
            std::make_signed< select_signed<T, U>>
        >::type >::type >::type
    >;
 
    template<typename T, typename U>
    using result_type = typename usual_arithmetic_conversions<
        integral_promotion<typename base_type<T>::type>,
        integral_promotion<typename base_type<U>::type>
    >::type;
public:
    template<typename T, typename U>
    struct addition_result {
       using type = result_type<T, U>;
    };
    template<typename T, typename U>
    struct subtraction_result {
       using type = result_type<T, U>;
    };
    template<typename T, typename U>
    struct multiplication_result {
       using type = result_type<T, U>;
    };
    template<typename T, typename U>
    struct division_result {
       using type = result_type<T, U>;
    };
    template<typename T, typename U>
    struct modulus_result {
       using type = result_type<T, U>;
    };
    // note: comparison_result (<, >, ...) is special.
    // The return value is always a bool.  The type returned here is
    // the intermediate type applied to make the values comparable.
    template<typename T, typename U>
    struct comparison_result {
        using type = result_type<T, U>;
    };
    template<typename T, typename U>
    struct left_shift_result {
       using type = result_type<T, U>;
    };
    template<typename T, typename U>
    struct right_shift_result {
       using type = result_type<T, U>;
    };
    template<typename T, typename U>
    struct bitwise_and_result {
       using type = result_type<T, U>;
    };
    template<typename T, typename U>
    struct bitwise_or_result {
       using type = result_type<T, U>;
    };
    template<typename T, typename U>
    struct bitwise_xor_result {
       using type = result_type<T, U>;
    };
};
 
} // safe_numerics
} // boost
 
#endif // BOOST_NUMERIC_cpp_HPP