cpp.hpp 6.6 KB

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