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 198