1 #ifndef BOOST_NUMERIC_CPP_HPP
2 #define BOOST_NUMERIC_CPP_HPP
4 // Copyright (c) 2012 Robert Ramey
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)
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.
15 #include <type_traits> // integral constant, remove_cv, conditional
17 #include <boost/integer.hpp> // integer type selection
19 #include "safe_common.hpp"
20 #include "checked_result.hpp"
23 namespace safe_numerics {
25 // in C++ the following rules govern integer arithmetic
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
31 // Follow section 5 of the standard.
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;
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;
67 // section 4.5 integral promotions
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),
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
85 using integral_promotion = copy_sign<
86 higher_ranked_type<local_int_type, T>,
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,
99 template<class T, class U>
100 using select_unsigned = typename std::conditional<
101 std::numeric_limits<T>::is_signed,
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
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,
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,
134 // clause 4 - otherwise use unsigned version of the signed type
135 std::make_signed< select_signed<T, U>>
136 >::type >::type >::type
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>
145 template<typename T, typename U>
146 struct addition_result {
147 using type = result_type<T, U>;
149 template<typename T, typename U>
150 struct subtraction_result {
151 using type = result_type<T, U>;
153 template<typename T, typename U>
154 struct multiplication_result {
155 using type = result_type<T, U>;
157 template<typename T, typename U>
158 struct division_result {
159 using type = result_type<T, U>;
161 template<typename T, typename U>
162 struct modulus_result {
163 using type = result_type<T, U>;
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>;
172 template<typename T, typename U>
173 struct left_shift_result {
174 using type = result_type<T, U>;
176 template<typename T, typename U>
177 struct right_shift_result {
178 using type = result_type<T, U>;
180 template<typename T, typename U>
181 struct bitwise_and_result {
182 using type = result_type<T, U>;
184 template<typename T, typename U>
185 struct bitwise_or_result {
186 using type = result_type<T, U>;
188 template<typename T, typename U>
189 struct bitwise_xor_result {
190 using type = result_type<T, U>;
197 #endif // BOOST_NUMERIC_cpp_HPP