]>
Commit | Line | Data |
---|---|---|
92f5a8d4 TL |
1 | #ifndef BOOST_NUMERIC_CPP_HPP |
2 | #define BOOST_NUMERIC_CPP_HPP | |
3 | ||
4 | // Copyright (c) 2012 Robert Ramey | |
5 | // | |
6 | // Distributed under the Boost Software License, Version 1.0. (See | |
7 | // accompanying file LICENSE_1_0.txt or copy at | |
8 | // http://www.boost.org/LICENSE_1_0.txt) | |
9 | ||
10 | // policy which creates results types equal to that of C++ promotions. | |
11 | // Using the policy will permit the program to build and run in release | |
12 | // mode which is identical to that in debug mode except for the fact | |
13 | // that errors aren't trapped. | |
14 | ||
15 | #include <type_traits> // integral constant, remove_cv, conditional | |
16 | #include <limits> | |
17 | #include <boost/integer.hpp> // integer type selection | |
18 | ||
19 | #include "safe_common.hpp" | |
20 | #include "checked_result.hpp" | |
21 | ||
22 | namespace boost { | |
23 | namespace safe_numerics { | |
24 | ||
25 | // in C++ the following rules govern integer arithmetic | |
26 | ||
27 | // This policy is use to emulate another compiler/machine architecture | |
28 | // For example, a Z80 has 8 bit char, 16 bit short, 16 bit int, 32 bit long. So one | |
29 | // would use cpp<8, 16, 16, 32, 32> to test programs destined to run on a Z80 | |
30 | ||
31 | // Follow section 5 of the standard. | |
32 | template< | |
33 | int CharBits, | |
34 | int ShortBits, | |
35 | int IntBits, | |
36 | int LongBits, | |
37 | int LongLongBits | |
38 | > | |
39 | struct cpp { | |
40 | public: | |
41 | using local_char_type = typename boost::int_t<CharBits>::exact; | |
42 | using local_short_type = typename boost::int_t<ShortBits>::exact; | |
43 | using local_int_type = typename boost::int_t<IntBits>::exact; | |
44 | using local_long_type = typename boost::int_t<LongBits>::exact; | |
45 | using local_long_long_type = typename boost::int_t<LongLongBits>::exact; | |
46 | ||
47 | template<class T> | |
48 | using rank = | |
49 | typename std::conditional< | |
50 | std::is_same<local_char_type, typename std::make_signed<T>::type>::value, | |
51 | std::integral_constant<int, 1>, | |
52 | typename std::conditional< | |
53 | std::is_same<local_short_type, typename std::make_signed<T>::type>::value, | |
54 | std::integral_constant<int, 2>, | |
55 | typename std::conditional< | |
56 | std::is_same<local_int_type, typename std::make_signed<T>::type>::value, | |
57 | std::integral_constant<int, 3>, | |
58 | typename std::conditional< | |
59 | std::is_same<local_long_type, typename std::make_signed<T>::type>::value, | |
60 | std::integral_constant<int, 4>, | |
61 | typename std::conditional< | |
62 | std::is_same<local_long_long_type, typename std::make_signed<T>::type>::value, | |
63 | std::integral_constant<int, 5>, | |
64 | std::integral_constant<int, 6> // catch all - never promote integral | |
65 | >::type >::type >::type >::type >::type; | |
66 | ||
67 | // section 4.5 integral promotions | |
68 | ||
69 | // convert smaller of two types to the size of the larger | |
70 | template<class T, class U> | |
71 | using higher_ranked_type = typename std::conditional< | |
72 | (rank<T>::value < rank<U>::value), | |
73 | U, | |
74 | T | |
75 | >::type; | |
76 | ||
77 | template<class T, class U> | |
78 | using copy_sign = typename std::conditional< | |
79 | std::is_signed<U>::value, | |
80 | typename std::make_signed<T>::type, | |
81 | typename std::make_unsigned<T>::type | |
82 | >::type; | |
83 | ||
84 | template<class T> | |
85 | using integral_promotion = copy_sign< | |
86 | higher_ranked_type<local_int_type, T>, | |
87 | T | |
88 | >; | |
89 | ||
90 | // note presumption that T & U don't have he same sign | |
91 | // if that's not true, these won't work | |
92 | template<class T, class U> | |
93 | using select_signed = typename std::conditional< | |
94 | std::numeric_limits<T>::is_signed, | |
95 | T, | |
96 | U | |
97 | >::type; | |
98 | ||
99 | template<class T, class U> | |
100 | using select_unsigned = typename std::conditional< | |
101 | std::numeric_limits<T>::is_signed, | |
102 | U, | |
103 | T | |
104 | >::type; | |
105 | ||
106 | // section 5 clause 11 - usual arithmetic conversions | |
107 | template<typename T, typename U> | |
108 | using usual_arithmetic_conversions = | |
109 | // clause 0 - if both operands have the same type | |
110 | typename std::conditional< | |
111 | std::is_same<T, U>::value, | |
112 | // no further conversion is needed | |
113 | T, | |
114 | // clause 1 - otherwise if both operands have the same sign | |
115 | typename std::conditional< | |
116 | std::numeric_limits<T>::is_signed | |
117 | == std::numeric_limits<U>::is_signed, | |
118 | // convert to the higher ranked type | |
119 | higher_ranked_type<T, U>, | |
120 | // clause 2 - otherwise if the rank of he unsigned type exceeds | |
121 | // the rank of the of the signed type | |
122 | typename std::conditional< | |
123 | rank<select_unsigned<T, U>>::value | |
124 | >= rank< select_signed<T, U>>::value, | |
125 | // use unsigned type | |
126 | select_unsigned<T, U>, | |
127 | // clause 3 - otherwise if the type of the signed integer type can | |
128 | // represent all the values of the unsigned type | |
129 | typename std::conditional< | |
130 | std::numeric_limits< select_signed<T, U>>::digits >= | |
131 | std::numeric_limits< select_unsigned<T, U>>::digits, | |
132 | // use signed type | |
133 | select_signed<T, U>, | |
134 | // clause 4 - otherwise use unsigned version of the signed type | |
135 | std::make_signed< select_signed<T, U>> | |
136 | >::type >::type >::type | |
137 | >; | |
138 | ||
139 | template<typename T, typename U> | |
140 | using result_type = typename usual_arithmetic_conversions< | |
141 | integral_promotion<typename base_type<T>::type>, | |
142 | integral_promotion<typename base_type<U>::type> | |
143 | >::type; | |
144 | public: | |
145 | template<typename T, typename U> | |
146 | struct addition_result { | |
147 | using type = result_type<T, U>; | |
148 | }; | |
149 | template<typename T, typename U> | |
150 | struct subtraction_result { | |
151 | using type = result_type<T, U>; | |
152 | }; | |
153 | template<typename T, typename U> | |
154 | struct multiplication_result { | |
155 | using type = result_type<T, U>; | |
156 | }; | |
157 | template<typename T, typename U> | |
158 | struct division_result { | |
159 | using type = result_type<T, U>; | |
160 | }; | |
161 | template<typename T, typename U> | |
162 | struct modulus_result { | |
163 | using type = result_type<T, U>; | |
164 | }; | |
165 | // note: comparison_result (<, >, ...) is special. | |
166 | // The return value is always a bool. The type returned here is | |
167 | // the intermediate type applied to make the values comparable. | |
168 | template<typename T, typename U> | |
169 | struct comparison_result { | |
170 | using type = result_type<T, U>; | |
171 | }; | |
172 | template<typename T, typename U> | |
173 | struct left_shift_result { | |
174 | using type = result_type<T, U>; | |
175 | }; | |
176 | template<typename T, typename U> | |
177 | struct right_shift_result { | |
178 | using type = result_type<T, U>; | |
179 | }; | |
180 | template<typename T, typename U> | |
181 | struct bitwise_and_result { | |
182 | using type = result_type<T, U>; | |
183 | }; | |
184 | template<typename T, typename U> | |
185 | struct bitwise_or_result { | |
186 | using type = result_type<T, U>; | |
187 | }; | |
188 | template<typename T, typename U> | |
189 | struct bitwise_xor_result { | |
190 | using type = result_type<T, U>; | |
191 | }; | |
192 | }; | |
193 | ||
194 | } // safe_numerics | |
195 | } // boost | |
196 | ||
197 | #endif // BOOST_NUMERIC_cpp_HPP |