• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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