]>
Commit | Line | Data |
---|---|---|
92f5a8d4 TL |
1 | #ifndef BOOST_NUMERIC_SAFE_INTEGER_LITERAL_HPP |
2 | #define BOOST_NUMERIC_SAFE_INTEGER_LITERAL_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 | #include <cstdint> // for intmax_t/uintmax_t | |
11 | #include <iosfwd> | |
12 | #include <type_traits> // conditional, enable_if | |
13 | #include <boost/mp11/utility.hpp> | |
14 | ||
15 | #include "utility.hpp" | |
16 | #include "safe_integer.hpp" | |
17 | #include "checked_integer.hpp" | |
18 | ||
19 | namespace boost { | |
20 | namespace safe_numerics { | |
21 | ||
22 | template<typename T, T N, class P, class E> | |
23 | class safe_literal_impl; | |
24 | ||
25 | template<typename T, T N, class P, class E> | |
26 | struct is_safe<safe_literal_impl<T, N, P, E> > : public std::true_type | |
27 | {}; | |
28 | ||
29 | template<typename T, T N, class P, class E> | |
30 | struct get_promotion_policy<safe_literal_impl<T, N, P, E> > { | |
31 | using type = P; | |
32 | }; | |
33 | ||
34 | template<typename T, T N, class P, class E> | |
35 | struct get_exception_policy<safe_literal_impl<T, N, P, E> > { | |
36 | using type = E; | |
37 | }; | |
38 | template<typename T, T N, class P, class E> | |
39 | struct base_type<safe_literal_impl<T, N, P, E> > { | |
40 | using type = T; | |
41 | }; | |
42 | ||
43 | template<typename T, T N, class P, class E> | |
44 | constexpr T base_value( | |
45 | const safe_literal_impl<T, N, P, E> & | |
46 | ) { | |
47 | return N; | |
48 | } | |
49 | ||
50 | template<typename CharT, typename Traits, typename T, T N, class P, class E> | |
51 | inline std::basic_ostream<CharT, Traits> & operator<<( | |
52 | std::basic_ostream<CharT, Traits> & os, | |
53 | const safe_literal_impl<T, N, P, E> & | |
54 | ){ | |
55 | return os << ( | |
56 | (std::is_same<T, signed char>::value | |
57 | || std::is_same<T, unsigned char>::value | |
58 | ) ? | |
59 | static_cast<int>(N) | |
60 | : | |
61 | N | |
62 | ); | |
63 | } | |
64 | ||
65 | template<typename T, T N, class P, class E> | |
66 | class safe_literal_impl { | |
67 | ||
68 | template< | |
69 | class CharT, | |
70 | class Traits | |
71 | > | |
72 | friend std::basic_ostream<CharT, Traits> & operator<<( | |
73 | std::basic_ostream<CharT, Traits> & os, | |
74 | const safe_literal_impl & | |
75 | ){ | |
76 | return os << ( | |
77 | (::std::is_same<T, signed char>::value | |
78 | || ::std::is_same<T, unsigned char>::value | |
79 | || ::std::is_same<T, wchar_t>::value | |
80 | ) ? | |
81 | static_cast<int>(N) | |
82 | : | |
83 | N | |
84 | ); | |
85 | }; | |
86 | ||
87 | public: | |
88 | ||
89 | //////////////////////////////////////////////////////////// | |
90 | // constructors | |
91 | // default constructor | |
92 | constexpr safe_literal_impl(){} | |
93 | ||
94 | ///////////////////////////////////////////////////////////////// | |
95 | // casting operators for intrinsic integers | |
96 | // convert to any type which is not safe. safe types need to be | |
97 | // excluded to prevent ambiguous function selection which | |
98 | // would otherwise occur | |
99 | template< | |
100 | class R, | |
101 | typename std::enable_if< | |
102 | ! boost::safe_numerics::is_safe<R>::value, | |
103 | int | |
104 | >::type = 0 | |
105 | > | |
106 | constexpr operator R () const { | |
f67539c2 TL |
107 | // if static values don't overlap, the program can never function |
108 | #if 1 | |
109 | constexpr const interval<R> r_interval; | |
110 | static_assert( | |
111 | ! r_interval.excludes(N), | |
112 | "safe type cannot be constructed with this type" | |
113 | ); | |
114 | #endif | |
115 | ||
116 | return validate_detail< | |
117 | R, | |
118 | std::numeric_limits<R>::min(), | |
119 | std::numeric_limits<R>::max(), | |
120 | E | |
121 | >::return_value(*this); | |
92f5a8d4 TL |
122 | } |
123 | ||
124 | // non mutating unary operators | |
125 | constexpr safe_literal_impl<T, N, P, E> operator+() const { // unary plus | |
126 | return safe_literal_impl<T, N, P, E>(); | |
127 | } | |
128 | // after much consideration, I've permitted the resulting value of a unary | |
129 | // - to change the type in accordance with the promotion policy. | |
130 | // The C++ standard does invoke integral promotions so it's changing the type as well. | |
131 | ||
132 | /* section 5.3.1 &8 of the C++ standard | |
133 | The operand of the unary - operator shall have arithmetic or unscoped | |
134 | enumeration type and the result is the negation of its operand. Integral | |
135 | promotion is performed on integral or enumeration operands. The negative | |
136 | of an unsigned quantity is computed by subtracting its value from 2n, | |
137 | where n is the number of bits in the promoted operand. The type of the | |
138 | result is the type of the promoted operand. | |
139 | */ | |
140 | template< | |
141 | typename Tx, Tx Nx, typename = std::enable_if_t<! checked::minus(Nx).exception()> | |
142 | > | |
143 | constexpr auto minus_helper() const { | |
144 | return safe_literal_impl<Tx, -N, P, E>(); | |
145 | } | |
146 | ||
147 | constexpr auto operator-() const { // unary minus | |
148 | return minus_helper<T, N>(); | |
149 | } | |
150 | ||
151 | /* section 5.3.1 &10 of the C++ standard | |
152 | The operand of ~ shall have integral or unscoped enumeration type; | |
153 | the result is the ones’ complement of its operand. Integral promotions | |
154 | are performed. The type of the result is the type of the promoted operand. | |
155 | constexpr safe_literal_impl<T, checked::bitwise_not(N), P, E> operator~() const { // invert bits | |
156 | return safe_literal_impl<T, checked::bitwise_not(N), P, E>(); | |
157 | } | |
158 | */ | |
159 | template< | |
160 | typename Tx, Tx Nx, typename = std::enable_if_t<! checked::bitwise_not(Nx).exception()> | |
161 | > | |
162 | constexpr auto not_helper() const { | |
163 | return safe_literal_impl<Tx, ~N, P, E>(); | |
164 | } | |
165 | ||
166 | constexpr auto operator~() const { // unary minus | |
167 | return not_helper<T, N>(); | |
168 | } | |
169 | }; | |
170 | ||
171 | template< | |
172 | std::intmax_t N, | |
173 | class P = void, | |
174 | class E = void | |
175 | > | |
176 | using safe_signed_literal = safe_literal_impl< | |
177 | typename utility::signed_stored_type<N, N>, | |
178 | N, | |
179 | P, | |
180 | E | |
181 | >; | |
182 | ||
183 | template< | |
184 | std::uintmax_t N, | |
185 | class P = void, | |
186 | class E = void | |
187 | > | |
188 | using safe_unsigned_literal = safe_literal_impl< | |
189 | typename utility::unsigned_stored_type<N, N>, | |
190 | N, | |
191 | P, | |
192 | E | |
193 | >; | |
194 | ||
195 | template< | |
196 | class T, | |
197 | T N, | |
198 | class P = void, | |
199 | class E = void, | |
200 | typename std::enable_if< | |
201 | std::is_signed<T>::value, | |
202 | int | |
203 | >::type = 0 | |
204 | > | |
205 | constexpr auto make_safe_literal_impl() { | |
206 | return boost::safe_numerics::safe_signed_literal<N, P, E>(); | |
207 | } | |
208 | ||
209 | template< | |
210 | class T, | |
211 | T N, | |
212 | class P = void, | |
213 | class E = void, | |
214 | typename std::enable_if< | |
215 | ! std::is_signed<T>::value, | |
216 | int | |
217 | >::type = 0 | |
218 | > | |
219 | constexpr auto make_safe_literal_impl() { | |
220 | return boost::safe_numerics::safe_unsigned_literal<N, P, E>(); | |
221 | } | |
222 | ||
223 | } // safe_numerics | |
224 | } // boost | |
225 | ||
226 | #define make_safe_literal(n, P, E) \ | |
227 | boost::safe_numerics::make_safe_literal_impl<decltype(n), n, P, E>() | |
228 | ||
229 | ///////////////////////////////////////////////////////////////// | |
230 | // numeric limits for safe_literal etc. | |
231 | ||
232 | #include <limits> | |
233 | ||
234 | namespace std { | |
235 | ||
236 | template< | |
237 | typename T, | |
238 | T N, | |
239 | class P, | |
240 | class E | |
241 | > | |
242 | class numeric_limits<boost::safe_numerics::safe_literal_impl<T, N, P, E> > | |
243 | : public std::numeric_limits<T> | |
244 | { | |
245 | using SL = boost::safe_numerics::safe_literal_impl<T, N, P, E>; | |
246 | public: | |
247 | constexpr static SL lowest() noexcept { | |
248 | return SL(); | |
249 | } | |
250 | constexpr static SL min() noexcept { | |
251 | return SL(); | |
252 | } | |
253 | constexpr static SL max() noexcept { | |
254 | return SL(); | |
255 | } | |
256 | }; | |
257 | ||
258 | } // std | |
259 | ||
260 | #endif // BOOST_NUMERIC_SAFE_INTEGER_LITERAL_HPP |