OLD | NEW |
1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #ifndef BASE_NUMERICS_SAFE_MATH_IMPL_H_ | 5 #ifndef BASE_NUMERICS_SAFE_MATH_IMPL_H_ |
6 #define BASE_NUMERICS_SAFE_MATH_IMPL_H_ | 6 #define BASE_NUMERICS_SAFE_MATH_IMPL_H_ |
7 | 7 |
8 #include <stdint.h> | 8 #include <stdint.h> |
9 | 9 |
10 #include <cmath> | 10 #include <cmath> |
11 #include <cstdlib> | 11 #include <cstdlib> |
12 #include <limits> | 12 #include <limits> |
| 13 #include <type_traits> |
13 | 14 |
14 #include "base/numerics/safe_conversions.h" | 15 #include "base/numerics/safe_conversions.h" |
15 #include "base/template_util.h" | 16 #include "base/template_util.h" |
16 | 17 |
17 namespace base { | 18 namespace base { |
18 namespace internal { | 19 namespace internal { |
19 | 20 |
20 // Everything from here up to the floating point operations is portable C++, | 21 // Everything from here up to the floating point operations is portable C++, |
21 // but it may not be fast. This code could be split based on | 22 // but it may not be fast. This code could be split based on |
22 // platform/architecture and replaced with potentially faster implementations. | 23 // platform/architecture and replaced with potentially faster implementations. |
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
56 struct IntegerForSizeAndSign<8, false> { | 57 struct IntegerForSizeAndSign<8, false> { |
57 typedef uint64_t type; | 58 typedef uint64_t type; |
58 }; | 59 }; |
59 | 60 |
60 // WARNING: We have no IntegerForSizeAndSign<16, *>. If we ever add one to | 61 // WARNING: We have no IntegerForSizeAndSign<16, *>. If we ever add one to |
61 // support 128-bit math, then the ArithmeticPromotion template below will need | 62 // support 128-bit math, then the ArithmeticPromotion template below will need |
62 // to be updated (or more likely replaced with a decltype expression). | 63 // to be updated (or more likely replaced with a decltype expression). |
63 | 64 |
64 template <typename Integer> | 65 template <typename Integer> |
65 struct UnsignedIntegerForSize { | 66 struct UnsignedIntegerForSize { |
66 typedef typename enable_if< | 67 typedef typename std::enable_if< |
67 std::numeric_limits<Integer>::is_integer, | 68 std::numeric_limits<Integer>::is_integer, |
68 typename IntegerForSizeAndSign<sizeof(Integer), false>::type>::type type; | 69 typename IntegerForSizeAndSign<sizeof(Integer), false>::type>::type type; |
69 }; | 70 }; |
70 | 71 |
71 template <typename Integer> | 72 template <typename Integer> |
72 struct SignedIntegerForSize { | 73 struct SignedIntegerForSize { |
73 typedef typename enable_if< | 74 typedef typename std::enable_if< |
74 std::numeric_limits<Integer>::is_integer, | 75 std::numeric_limits<Integer>::is_integer, |
75 typename IntegerForSizeAndSign<sizeof(Integer), true>::type>::type type; | 76 typename IntegerForSizeAndSign<sizeof(Integer), true>::type>::type type; |
76 }; | 77 }; |
77 | 78 |
78 template <typename Integer> | 79 template <typename Integer> |
79 struct TwiceWiderInteger { | 80 struct TwiceWiderInteger { |
80 typedef typename enable_if< | 81 typedef typename std::enable_if< |
81 std::numeric_limits<Integer>::is_integer, | 82 std::numeric_limits<Integer>::is_integer, |
82 typename IntegerForSizeAndSign< | 83 typename IntegerForSizeAndSign< |
83 sizeof(Integer) * 2, | 84 sizeof(Integer) * 2, |
84 std::numeric_limits<Integer>::is_signed>::type>::type type; | 85 std::numeric_limits<Integer>::is_signed>::type>::type type; |
85 }; | 86 }; |
86 | 87 |
87 template <typename Integer> | 88 template <typename Integer> |
88 struct PositionOfSignBit { | 89 struct PositionOfSignBit { |
89 static const typename enable_if<std::numeric_limits<Integer>::is_integer, | 90 static const typename std::enable_if<std::numeric_limits<Integer>::is_integer, |
90 size_t>::type value = 8 * sizeof(Integer) - 1; | 91 size_t>::type value = |
| 92 8 * sizeof(Integer) - 1; |
91 }; | 93 }; |
92 | 94 |
93 // This is used for UnsignedAbs, where we need to support floating-point | 95 // This is used for UnsignedAbs, where we need to support floating-point |
94 // template instantiations even though we don't actually support the operations. | 96 // template instantiations even though we don't actually support the operations. |
95 // However, there is no corresponding implementation of e.g. CheckedUnsignedAbs, | 97 // However, there is no corresponding implementation of e.g. CheckedUnsignedAbs, |
96 // so the float versions will not compile. | 98 // so the float versions will not compile. |
97 template <typename Numeric, | 99 template <typename Numeric, |
98 bool IsInteger = std::numeric_limits<Numeric>::is_integer, | 100 bool IsInteger = std::numeric_limits<Numeric>::is_integer, |
99 bool IsFloat = std::numeric_limits<Numeric>::is_iec559> | 101 bool IsFloat = std::numeric_limits<Numeric>::is_iec559> |
100 struct UnsignedOrFloatForSize; | 102 struct UnsignedOrFloatForSize; |
(...skipping 21 matching lines...) Expand all Loading... |
122 template <typename T> | 124 template <typename T> |
123 T BinaryComplement(T x) { | 125 T BinaryComplement(T x) { |
124 return ~x; | 126 return ~x; |
125 } | 127 } |
126 | 128 |
127 // Here are the actual portable checked integer math implementations. | 129 // Here are the actual portable checked integer math implementations. |
128 // TODO(jschuh): Break this code out from the enable_if pattern and find a clean | 130 // TODO(jschuh): Break this code out from the enable_if pattern and find a clean |
129 // way to coalesce things into the CheckedNumericState specializations below. | 131 // way to coalesce things into the CheckedNumericState specializations below. |
130 | 132 |
131 template <typename T> | 133 template <typename T> |
132 typename enable_if<std::numeric_limits<T>::is_integer, T>::type | 134 typename std::enable_if<std::numeric_limits<T>::is_integer, T>::type |
133 CheckedAdd(T x, T y, RangeConstraint* validity) { | 135 CheckedAdd(T x, T y, RangeConstraint* validity) { |
134 // Since the value of x+y is undefined if we have a signed type, we compute | 136 // Since the value of x+y is undefined if we have a signed type, we compute |
135 // it using the unsigned type of the same size. | 137 // it using the unsigned type of the same size. |
136 typedef typename UnsignedIntegerForSize<T>::type UnsignedDst; | 138 typedef typename UnsignedIntegerForSize<T>::type UnsignedDst; |
137 UnsignedDst ux = static_cast<UnsignedDst>(x); | 139 UnsignedDst ux = static_cast<UnsignedDst>(x); |
138 UnsignedDst uy = static_cast<UnsignedDst>(y); | 140 UnsignedDst uy = static_cast<UnsignedDst>(y); |
139 UnsignedDst uresult = ux + uy; | 141 UnsignedDst uresult = ux + uy; |
140 // Addition is valid if the sign of (x + y) is equal to either that of x or | 142 // Addition is valid if the sign of (x + y) is equal to either that of x or |
141 // that of y. | 143 // that of y. |
142 if (std::numeric_limits<T>::is_signed) { | 144 if (std::numeric_limits<T>::is_signed) { |
143 if (HasSignBit(BinaryComplement((uresult ^ ux) & (uresult ^ uy)))) | 145 if (HasSignBit(BinaryComplement((uresult ^ ux) & (uresult ^ uy)))) |
144 *validity = RANGE_VALID; | 146 *validity = RANGE_VALID; |
145 else // Direction of wrap is inverse of result sign. | 147 else // Direction of wrap is inverse of result sign. |
146 *validity = HasSignBit(uresult) ? RANGE_OVERFLOW : RANGE_UNDERFLOW; | 148 *validity = HasSignBit(uresult) ? RANGE_OVERFLOW : RANGE_UNDERFLOW; |
147 | 149 |
148 } else { // Unsigned is either valid or overflow. | 150 } else { // Unsigned is either valid or overflow. |
149 *validity = BinaryComplement(x) >= y ? RANGE_VALID : RANGE_OVERFLOW; | 151 *validity = BinaryComplement(x) >= y ? RANGE_VALID : RANGE_OVERFLOW; |
150 } | 152 } |
151 return static_cast<T>(uresult); | 153 return static_cast<T>(uresult); |
152 } | 154 } |
153 | 155 |
154 template <typename T> | 156 template <typename T> |
155 typename enable_if<std::numeric_limits<T>::is_integer, T>::type | 157 typename std::enable_if<std::numeric_limits<T>::is_integer, T>::type |
156 CheckedSub(T x, T y, RangeConstraint* validity) { | 158 CheckedSub(T x, T y, RangeConstraint* validity) { |
157 // Since the value of x+y is undefined if we have a signed type, we compute | 159 // Since the value of x+y is undefined if we have a signed type, we compute |
158 // it using the unsigned type of the same size. | 160 // it using the unsigned type of the same size. |
159 typedef typename UnsignedIntegerForSize<T>::type UnsignedDst; | 161 typedef typename UnsignedIntegerForSize<T>::type UnsignedDst; |
160 UnsignedDst ux = static_cast<UnsignedDst>(x); | 162 UnsignedDst ux = static_cast<UnsignedDst>(x); |
161 UnsignedDst uy = static_cast<UnsignedDst>(y); | 163 UnsignedDst uy = static_cast<UnsignedDst>(y); |
162 UnsignedDst uresult = ux - uy; | 164 UnsignedDst uresult = ux - uy; |
163 // Subtraction is valid if either x and y have same sign, or (x-y) and x have | 165 // Subtraction is valid if either x and y have same sign, or (x-y) and x have |
164 // the same sign. | 166 // the same sign. |
165 if (std::numeric_limits<T>::is_signed) { | 167 if (std::numeric_limits<T>::is_signed) { |
166 if (HasSignBit(BinaryComplement((uresult ^ ux) & (ux ^ uy)))) | 168 if (HasSignBit(BinaryComplement((uresult ^ ux) & (ux ^ uy)))) |
167 *validity = RANGE_VALID; | 169 *validity = RANGE_VALID; |
168 else // Direction of wrap is inverse of result sign. | 170 else // Direction of wrap is inverse of result sign. |
169 *validity = HasSignBit(uresult) ? RANGE_OVERFLOW : RANGE_UNDERFLOW; | 171 *validity = HasSignBit(uresult) ? RANGE_OVERFLOW : RANGE_UNDERFLOW; |
170 | 172 |
171 } else { // Unsigned is either valid or underflow. | 173 } else { // Unsigned is either valid or underflow. |
172 *validity = x >= y ? RANGE_VALID : RANGE_UNDERFLOW; | 174 *validity = x >= y ? RANGE_VALID : RANGE_UNDERFLOW; |
173 } | 175 } |
174 return static_cast<T>(uresult); | 176 return static_cast<T>(uresult); |
175 } | 177 } |
176 | 178 |
177 // Integer multiplication is a bit complicated. In the fast case we just | 179 // Integer multiplication is a bit complicated. In the fast case we just |
178 // we just promote to a twice wider type, and range check the result. In the | 180 // we just promote to a twice wider type, and range check the result. In the |
179 // slow case we need to manually check that the result won't be truncated by | 181 // slow case we need to manually check that the result won't be truncated by |
180 // checking with division against the appropriate bound. | 182 // checking with division against the appropriate bound. |
181 template <typename T> | 183 template <typename T> |
182 typename enable_if< | 184 typename std::enable_if<std::numeric_limits<T>::is_integer && |
183 std::numeric_limits<T>::is_integer && sizeof(T) * 2 <= sizeof(uintmax_t), | 185 sizeof(T) * 2 <= sizeof(uintmax_t), |
184 T>::type | 186 T>::type |
185 CheckedMul(T x, T y, RangeConstraint* validity) { | 187 CheckedMul(T x, T y, RangeConstraint* validity) { |
186 typedef typename TwiceWiderInteger<T>::type IntermediateType; | 188 typedef typename TwiceWiderInteger<T>::type IntermediateType; |
187 IntermediateType tmp = | 189 IntermediateType tmp = |
188 static_cast<IntermediateType>(x) * static_cast<IntermediateType>(y); | 190 static_cast<IntermediateType>(x) * static_cast<IntermediateType>(y); |
189 *validity = DstRangeRelationToSrcRange<T>(tmp); | 191 *validity = DstRangeRelationToSrcRange<T>(tmp); |
190 return static_cast<T>(tmp); | 192 return static_cast<T>(tmp); |
191 } | 193 } |
192 | 194 |
193 template <typename T> | 195 template <typename T> |
194 typename enable_if<std::numeric_limits<T>::is_integer&& std::numeric_limits< | 196 typename std::enable_if<std::numeric_limits<T>::is_integer && |
195 T>::is_signed&&(sizeof(T) * 2 > sizeof(uintmax_t)), | 197 std::numeric_limits<T>::is_signed && |
196 T>::type | 198 (sizeof(T) * 2 > sizeof(uintmax_t)), |
| 199 T>::type |
197 CheckedMul(T x, T y, RangeConstraint* validity) { | 200 CheckedMul(T x, T y, RangeConstraint* validity) { |
198 // If either side is zero then the result will be zero. | 201 // If either side is zero then the result will be zero. |
199 if (!x || !y) { | 202 if (!x || !y) { |
200 return RANGE_VALID; | 203 return RANGE_VALID; |
201 | 204 |
202 } else if (x > 0) { | 205 } else if (x > 0) { |
203 if (y > 0) | 206 if (y > 0) |
204 *validity = | 207 *validity = |
205 x <= std::numeric_limits<T>::max() / y ? RANGE_VALID : RANGE_OVERFLOW; | 208 x <= std::numeric_limits<T>::max() / y ? RANGE_VALID : RANGE_OVERFLOW; |
206 else | 209 else |
207 *validity = y >= std::numeric_limits<T>::min() / x ? RANGE_VALID | 210 *validity = y >= std::numeric_limits<T>::min() / x ? RANGE_VALID |
208 : RANGE_UNDERFLOW; | 211 : RANGE_UNDERFLOW; |
209 | 212 |
210 } else { | 213 } else { |
211 if (y > 0) | 214 if (y > 0) |
212 *validity = x >= std::numeric_limits<T>::min() / y ? RANGE_VALID | 215 *validity = x >= std::numeric_limits<T>::min() / y ? RANGE_VALID |
213 : RANGE_UNDERFLOW; | 216 : RANGE_UNDERFLOW; |
214 else | 217 else |
215 *validity = | 218 *validity = |
216 y >= std::numeric_limits<T>::max() / x ? RANGE_VALID : RANGE_OVERFLOW; | 219 y >= std::numeric_limits<T>::max() / x ? RANGE_VALID : RANGE_OVERFLOW; |
217 } | 220 } |
218 | 221 |
219 return x * y; | 222 return x * y; |
220 } | 223 } |
221 | 224 |
222 template <typename T> | 225 template <typename T> |
223 typename enable_if<std::numeric_limits<T>::is_integer && | 226 typename std::enable_if<std::numeric_limits<T>::is_integer && |
224 !std::numeric_limits<T>::is_signed && | 227 !std::numeric_limits<T>::is_signed && |
225 (sizeof(T) * 2 > sizeof(uintmax_t)), | 228 (sizeof(T) * 2 > sizeof(uintmax_t)), |
226 T>::type | 229 T>::type |
227 CheckedMul(T x, T y, RangeConstraint* validity) { | 230 CheckedMul(T x, T y, RangeConstraint* validity) { |
228 *validity = (y == 0 || x <= std::numeric_limits<T>::max() / y) | 231 *validity = (y == 0 || x <= std::numeric_limits<T>::max() / y) |
229 ? RANGE_VALID | 232 ? RANGE_VALID |
230 : RANGE_OVERFLOW; | 233 : RANGE_OVERFLOW; |
231 return x * y; | 234 return x * y; |
232 } | 235 } |
233 | 236 |
234 // Division just requires a check for an invalid negation on signed min/-1. | 237 // Division just requires a check for an invalid negation on signed min/-1. |
235 template <typename T> | 238 template <typename T> |
236 T CheckedDiv( | 239 T CheckedDiv(T x, |
237 T x, | 240 T y, |
238 T y, | 241 RangeConstraint* validity, |
239 RangeConstraint* validity, | 242 typename std::enable_if<std::numeric_limits<T>::is_integer, |
240 typename enable_if<std::numeric_limits<T>::is_integer, int>::type = 0) { | 243 int>::type = 0) { |
241 if (std::numeric_limits<T>::is_signed && x == std::numeric_limits<T>::min() && | 244 if (std::numeric_limits<T>::is_signed && x == std::numeric_limits<T>::min() && |
242 y == static_cast<T>(-1)) { | 245 y == static_cast<T>(-1)) { |
243 *validity = RANGE_OVERFLOW; | 246 *validity = RANGE_OVERFLOW; |
244 return std::numeric_limits<T>::min(); | 247 return std::numeric_limits<T>::min(); |
245 } | 248 } |
246 | 249 |
247 *validity = RANGE_VALID; | 250 *validity = RANGE_VALID; |
248 return x / y; | 251 return x / y; |
249 } | 252 } |
250 | 253 |
251 template <typename T> | 254 template <typename T> |
252 typename enable_if< | 255 typename std::enable_if<std::numeric_limits<T>::is_integer && |
253 std::numeric_limits<T>::is_integer&& std::numeric_limits<T>::is_signed, | 256 std::numeric_limits<T>::is_signed, |
254 T>::type | 257 T>::type |
255 CheckedMod(T x, T y, RangeConstraint* validity) { | 258 CheckedMod(T x, T y, RangeConstraint* validity) { |
256 *validity = y > 0 ? RANGE_VALID : RANGE_INVALID; | 259 *validity = y > 0 ? RANGE_VALID : RANGE_INVALID; |
257 return x % y; | 260 return x % y; |
258 } | 261 } |
259 | 262 |
260 template <typename T> | 263 template <typename T> |
261 typename enable_if< | 264 typename std::enable_if<std::numeric_limits<T>::is_integer && |
262 std::numeric_limits<T>::is_integer && !std::numeric_limits<T>::is_signed, | 265 !std::numeric_limits<T>::is_signed, |
263 T>::type | 266 T>::type |
264 CheckedMod(T x, T y, RangeConstraint* validity) { | 267 CheckedMod(T x, T y, RangeConstraint* validity) { |
265 *validity = RANGE_VALID; | 268 *validity = RANGE_VALID; |
266 return x % y; | 269 return x % y; |
267 } | 270 } |
268 | 271 |
269 template <typename T> | 272 template <typename T> |
270 typename enable_if< | 273 typename std::enable_if<std::numeric_limits<T>::is_integer && |
271 std::numeric_limits<T>::is_integer&& std::numeric_limits<T>::is_signed, | 274 std::numeric_limits<T>::is_signed, |
272 T>::type | 275 T>::type |
273 CheckedNeg(T value, RangeConstraint* validity) { | 276 CheckedNeg(T value, RangeConstraint* validity) { |
274 *validity = | 277 *validity = |
275 value != std::numeric_limits<T>::min() ? RANGE_VALID : RANGE_OVERFLOW; | 278 value != std::numeric_limits<T>::min() ? RANGE_VALID : RANGE_OVERFLOW; |
276 // The negation of signed min is min, so catch that one. | 279 // The negation of signed min is min, so catch that one. |
277 return -value; | 280 return -value; |
278 } | 281 } |
279 | 282 |
280 template <typename T> | 283 template <typename T> |
281 typename enable_if< | 284 typename std::enable_if<std::numeric_limits<T>::is_integer && |
282 std::numeric_limits<T>::is_integer && !std::numeric_limits<T>::is_signed, | 285 !std::numeric_limits<T>::is_signed, |
283 T>::type | 286 T>::type |
284 CheckedNeg(T value, RangeConstraint* validity) { | 287 CheckedNeg(T value, RangeConstraint* validity) { |
285 // The only legal unsigned negation is zero. | 288 // The only legal unsigned negation is zero. |
286 *validity = value ? RANGE_UNDERFLOW : RANGE_VALID; | 289 *validity = value ? RANGE_UNDERFLOW : RANGE_VALID; |
287 return static_cast<T>( | 290 return static_cast<T>( |
288 -static_cast<typename SignedIntegerForSize<T>::type>(value)); | 291 -static_cast<typename SignedIntegerForSize<T>::type>(value)); |
289 } | 292 } |
290 | 293 |
291 template <typename T> | 294 template <typename T> |
292 typename enable_if< | 295 typename std::enable_if<std::numeric_limits<T>::is_integer && |
293 std::numeric_limits<T>::is_integer&& std::numeric_limits<T>::is_signed, | 296 std::numeric_limits<T>::is_signed, |
294 T>::type | 297 T>::type |
295 CheckedAbs(T value, RangeConstraint* validity) { | 298 CheckedAbs(T value, RangeConstraint* validity) { |
296 *validity = | 299 *validity = |
297 value != std::numeric_limits<T>::min() ? RANGE_VALID : RANGE_OVERFLOW; | 300 value != std::numeric_limits<T>::min() ? RANGE_VALID : RANGE_OVERFLOW; |
298 return static_cast<T>(std::abs(value)); | 301 return static_cast<T>(std::abs(value)); |
299 } | 302 } |
300 | 303 |
301 template <typename T> | 304 template <typename T> |
302 typename enable_if< | 305 typename std::enable_if<std::numeric_limits<T>::is_integer && |
303 std::numeric_limits<T>::is_integer && !std::numeric_limits<T>::is_signed, | 306 !std::numeric_limits<T>::is_signed, |
304 T>::type | 307 T>::type |
305 CheckedAbs(T value, RangeConstraint* validity) { | 308 CheckedAbs(T value, RangeConstraint* validity) { |
306 // T is unsigned, so |value| must already be positive. | 309 // T is unsigned, so |value| must already be positive. |
307 *validity = RANGE_VALID; | 310 *validity = RANGE_VALID; |
308 return value; | 311 return value; |
309 } | 312 } |
310 | 313 |
311 template <typename T> | 314 template <typename T> |
312 typename enable_if<std::numeric_limits<T>::is_integer && | 315 typename std::enable_if<std::numeric_limits<T>::is_integer && |
313 std::numeric_limits<T>::is_signed, | 316 std::numeric_limits<T>::is_signed, |
314 typename UnsignedIntegerForSize<T>::type>::type | 317 typename UnsignedIntegerForSize<T>::type>::type |
315 CheckedUnsignedAbs(T value) { | 318 CheckedUnsignedAbs(T value) { |
316 typedef typename UnsignedIntegerForSize<T>::type UnsignedT; | 319 typedef typename UnsignedIntegerForSize<T>::type UnsignedT; |
317 return value == std::numeric_limits<T>::min() | 320 return value == std::numeric_limits<T>::min() |
318 ? static_cast<UnsignedT>(std::numeric_limits<T>::max()) + 1 | 321 ? static_cast<UnsignedT>(std::numeric_limits<T>::max()) + 1 |
319 : static_cast<UnsignedT>(std::abs(value)); | 322 : static_cast<UnsignedT>(std::abs(value)); |
320 } | 323 } |
321 | 324 |
322 template <typename T> | 325 template <typename T> |
323 typename enable_if<std::numeric_limits<T>::is_integer && | 326 typename std::enable_if<std::numeric_limits<T>::is_integer && |
324 !std::numeric_limits<T>::is_signed, | 327 !std::numeric_limits<T>::is_signed, |
325 T>::type | 328 T>::type |
326 CheckedUnsignedAbs(T value) { | 329 CheckedUnsignedAbs(T value) { |
327 // T is unsigned, so |value| must already be positive. | 330 // T is unsigned, so |value| must already be positive. |
328 return value; | 331 return value; |
329 } | 332 } |
330 | 333 |
331 // These are the floating point stubs that the compiler needs to see. Only the | 334 // These are the floating point stubs that the compiler needs to see. Only the |
332 // negation operation is ever called. | 335 // negation operation is ever called. |
333 #define BASE_FLOAT_ARITHMETIC_STUBS(NAME) \ | 336 #define BASE_FLOAT_ARITHMETIC_STUBS(NAME) \ |
334 template <typename T> \ | 337 template <typename T> \ |
335 typename enable_if<std::numeric_limits<T>::is_iec559, T>::type \ | 338 typename std::enable_if<std::numeric_limits<T>::is_iec559, T>::type \ |
336 Checked##NAME(T, T, RangeConstraint*) { \ | 339 Checked##NAME(T, T, RangeConstraint*) { \ |
337 NOTREACHED(); \ | 340 NOTREACHED(); \ |
338 return 0; \ | 341 return 0; \ |
339 } | 342 } |
340 | 343 |
341 BASE_FLOAT_ARITHMETIC_STUBS(Add) | 344 BASE_FLOAT_ARITHMETIC_STUBS(Add) |
342 BASE_FLOAT_ARITHMETIC_STUBS(Sub) | 345 BASE_FLOAT_ARITHMETIC_STUBS(Sub) |
343 BASE_FLOAT_ARITHMETIC_STUBS(Mul) | 346 BASE_FLOAT_ARITHMETIC_STUBS(Mul) |
344 BASE_FLOAT_ARITHMETIC_STUBS(Div) | 347 BASE_FLOAT_ARITHMETIC_STUBS(Div) |
345 BASE_FLOAT_ARITHMETIC_STUBS(Mod) | 348 BASE_FLOAT_ARITHMETIC_STUBS(Mod) |
346 | 349 |
347 #undef BASE_FLOAT_ARITHMETIC_STUBS | 350 #undef BASE_FLOAT_ARITHMETIC_STUBS |
348 | 351 |
349 template <typename T> | 352 template <typename T> |
350 typename enable_if<std::numeric_limits<T>::is_iec559, T>::type CheckedNeg( | 353 typename std::enable_if<std::numeric_limits<T>::is_iec559, T>::type CheckedNeg( |
351 T value, | 354 T value, |
352 RangeConstraint*) { | 355 RangeConstraint*) { |
353 return -value; | 356 return -value; |
354 } | 357 } |
355 | 358 |
356 template <typename T> | 359 template <typename T> |
357 typename enable_if<std::numeric_limits<T>::is_iec559, T>::type CheckedAbs( | 360 typename std::enable_if<std::numeric_limits<T>::is_iec559, T>::type CheckedAbs( |
358 T value, | 361 T value, |
359 RangeConstraint*) { | 362 RangeConstraint*) { |
360 return std::abs(value); | 363 return std::abs(value); |
361 } | 364 } |
362 | 365 |
363 // Floats carry around their validity state with them, but integers do not. So, | 366 // Floats carry around their validity state with them, but integers do not. So, |
364 // we wrap the underlying value in a specialization in order to hide that detail | 367 // we wrap the underlying value in a specialization in order to hide that detail |
365 // and expose an interface via accessors. | 368 // and expose an interface via accessors. |
366 enum NumericRepresentation { | 369 enum NumericRepresentation { |
367 NUMERIC_INTEGER, | 370 NUMERIC_INTEGER, |
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
407 // Copy constructor. | 410 // Copy constructor. |
408 template <typename Src> | 411 template <typename Src> |
409 CheckedNumericState(const CheckedNumericState<Src>& rhs) | 412 CheckedNumericState(const CheckedNumericState<Src>& rhs) |
410 : value_(static_cast<T>(rhs.value())), | 413 : value_(static_cast<T>(rhs.value())), |
411 validity_(GetRangeConstraint( | 414 validity_(GetRangeConstraint( |
412 rhs.validity() | DstRangeRelationToSrcRange<T>(rhs.value()))) {} | 415 rhs.validity() | DstRangeRelationToSrcRange<T>(rhs.value()))) {} |
413 | 416 |
414 template <typename Src> | 417 template <typename Src> |
415 explicit CheckedNumericState( | 418 explicit CheckedNumericState( |
416 Src value, | 419 Src value, |
417 typename enable_if<std::numeric_limits<Src>::is_specialized, int>::type = | 420 typename std::enable_if<std::numeric_limits<Src>::is_specialized, |
418 0) | 421 int>::type = 0) |
419 : value_(static_cast<T>(value)), | 422 : value_(static_cast<T>(value)), |
420 validity_(DstRangeRelationToSrcRange<T>(value)) {} | 423 validity_(DstRangeRelationToSrcRange<T>(value)) {} |
421 | 424 |
422 RangeConstraint validity() const { return validity_; } | 425 RangeConstraint validity() const { return validity_; } |
423 T value() const { return value_; } | 426 T value() const { return value_; } |
424 }; | 427 }; |
425 | 428 |
426 // Floating points maintain their own validity, but need translation wrappers. | 429 // Floating points maintain their own validity, but need translation wrappers. |
427 template <typename T> | 430 template <typename T> |
428 class CheckedNumericState<T, NUMERIC_FLOATING> { | 431 class CheckedNumericState<T, NUMERIC_FLOATING> { |
429 private: | 432 private: |
430 T value_; | 433 T value_; |
431 | 434 |
432 public: | 435 public: |
433 template <typename Src, NumericRepresentation type> | 436 template <typename Src, NumericRepresentation type> |
434 friend class CheckedNumericState; | 437 friend class CheckedNumericState; |
435 | 438 |
436 CheckedNumericState() : value_(0.0) {} | 439 CheckedNumericState() : value_(0.0) {} |
437 | 440 |
438 template <typename Src> | 441 template <typename Src> |
439 CheckedNumericState( | 442 CheckedNumericState( |
440 Src value, | 443 Src value, |
441 RangeConstraint validity, | 444 RangeConstraint validity, |
442 typename enable_if<std::numeric_limits<Src>::is_integer, int>::type = 0) { | 445 typename std::enable_if<std::numeric_limits<Src>::is_integer, int>::type = |
| 446 0) { |
443 switch (DstRangeRelationToSrcRange<T>(value)) { | 447 switch (DstRangeRelationToSrcRange<T>(value)) { |
444 case RANGE_VALID: | 448 case RANGE_VALID: |
445 value_ = static_cast<T>(value); | 449 value_ = static_cast<T>(value); |
446 break; | 450 break; |
447 | 451 |
448 case RANGE_UNDERFLOW: | 452 case RANGE_UNDERFLOW: |
449 value_ = -std::numeric_limits<T>::infinity(); | 453 value_ = -std::numeric_limits<T>::infinity(); |
450 break; | 454 break; |
451 | 455 |
452 case RANGE_OVERFLOW: | 456 case RANGE_OVERFLOW: |
453 value_ = std::numeric_limits<T>::infinity(); | 457 value_ = std::numeric_limits<T>::infinity(); |
454 break; | 458 break; |
455 | 459 |
456 case RANGE_INVALID: | 460 case RANGE_INVALID: |
457 value_ = std::numeric_limits<T>::quiet_NaN(); | 461 value_ = std::numeric_limits<T>::quiet_NaN(); |
458 break; | 462 break; |
459 | 463 |
460 default: | 464 default: |
461 NOTREACHED(); | 465 NOTREACHED(); |
462 } | 466 } |
463 } | 467 } |
464 | 468 |
465 template <typename Src> | 469 template <typename Src> |
466 explicit CheckedNumericState( | 470 explicit CheckedNumericState( |
467 Src value, | 471 Src value, |
468 typename enable_if<std::numeric_limits<Src>::is_specialized, int>::type = | 472 typename std::enable_if<std::numeric_limits<Src>::is_specialized, |
469 0) | 473 int>::type = 0) |
470 : value_(static_cast<T>(value)) {} | 474 : value_(static_cast<T>(value)) {} |
471 | 475 |
472 // Copy constructor. | 476 // Copy constructor. |
473 template <typename Src> | 477 template <typename Src> |
474 CheckedNumericState(const CheckedNumericState<Src>& rhs) | 478 CheckedNumericState(const CheckedNumericState<Src>& rhs) |
475 : value_(static_cast<T>(rhs.value())) {} | 479 : value_(static_cast<T>(rhs.value())) {} |
476 | 480 |
477 RangeConstraint validity() const { | 481 RangeConstraint validity() const { |
478 return GetRangeConstraint(value_ <= std::numeric_limits<T>::max(), | 482 return GetRangeConstraint(value_ <= std::numeric_limits<T>::max(), |
479 value_ >= -std::numeric_limits<T>::max()); | 483 value_ >= -std::numeric_limits<T>::max()); |
(...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
531 sizeof(T) >= (2 * sizeof(Lhs)) && | 535 sizeof(T) >= (2 * sizeof(Lhs)) && |
532 StaticDstRangeRelationToSrcRange<T, Rhs>::value != | 536 StaticDstRangeRelationToSrcRange<T, Rhs>::value != |
533 NUMERIC_RANGE_CONTAINED && | 537 NUMERIC_RANGE_CONTAINED && |
534 sizeof(T) >= (2 * sizeof(Rhs)); | 538 sizeof(T) >= (2 * sizeof(Rhs)); |
535 }; | 539 }; |
536 | 540 |
537 } // namespace internal | 541 } // namespace internal |
538 } // namespace base | 542 } // namespace base |
539 | 543 |
540 #endif // BASE_NUMERICS_SAFE_MATH_IMPL_H_ | 544 #endif // BASE_NUMERICS_SAFE_MATH_IMPL_H_ |
OLD | NEW |