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 SAFE_MATH_IMPL_H_ | 5 #ifndef SAFE_MATH_IMPL_H_ |
6 #define SAFE_MATH_IMPL_H_ | 6 #define SAFE_MATH_IMPL_H_ |
7 | 7 |
8 #include <stdint.h> | 8 #include <stdint.h> |
9 | 9 |
10 #include <cmath> | 10 #include <cmath> |
(...skipping 155 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
166 T>::type | 166 T>::type |
167 CheckedMul(T x, T y, RangeConstraint* validity) { | 167 CheckedMul(T x, T y, RangeConstraint* validity) { |
168 typedef typename TwiceWiderInteger<T>::type IntermediateType; | 168 typedef typename TwiceWiderInteger<T>::type IntermediateType; |
169 IntermediateType tmp = | 169 IntermediateType tmp = |
170 static_cast<IntermediateType>(x) * static_cast<IntermediateType>(y); | 170 static_cast<IntermediateType>(x) * static_cast<IntermediateType>(y); |
171 *validity = DstRangeRelationToSrcRange<T>(tmp); | 171 *validity = DstRangeRelationToSrcRange<T>(tmp); |
172 return static_cast<T>(tmp); | 172 return static_cast<T>(tmp); |
173 } | 173 } |
174 | 174 |
175 template <typename T> | 175 template <typename T> |
176 typename enable_if<std::numeric_limits<T>::is_integer&& std::numeric_limits< | 176 typename enable_if< |
177 T>::is_signed&&(sizeof(T) * 2 > sizeof(uintmax_t)), | 177 std::numeric_limits<T>::is_integer && |
178 T>::type | 178 std::numeric_limits<T>::is_signed&&(sizeof(T) * 2 > sizeof(uintmax_t)), |
| 179 T>::type |
179 CheckedMul(T x, T y, RangeConstraint* validity) { | 180 CheckedMul(T x, T y, RangeConstraint* validity) { |
180 // if either side is zero then the result will be zero. | 181 // if either side is zero then the result will be zero. |
181 if (!(x || y)) { | 182 if (!(x || y)) { |
182 return RANGE_VALID; | 183 return RANGE_VALID; |
183 | 184 |
184 } else if (x > 0) { | 185 } else if (x > 0) { |
185 if (y > 0) | 186 if (y > 0) |
186 *validity = | 187 *validity = |
187 x <= std::numeric_limits<T>::max() / y ? RANGE_VALID : RANGE_OVERFLOW; | 188 x <= std::numeric_limits<T>::max() / y ? RANGE_VALID : RANGE_OVERFLOW; |
188 else | 189 else |
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
225 *validity = RANGE_OVERFLOW; | 226 *validity = RANGE_OVERFLOW; |
226 return std::numeric_limits<T>::min(); | 227 return std::numeric_limits<T>::min(); |
227 } | 228 } |
228 | 229 |
229 *validity = RANGE_VALID; | 230 *validity = RANGE_VALID; |
230 return x / y; | 231 return x / y; |
231 } | 232 } |
232 | 233 |
233 template <typename T> | 234 template <typename T> |
234 typename enable_if< | 235 typename enable_if< |
235 std::numeric_limits<T>::is_integer&& std::numeric_limits<T>::is_signed, | 236 std::numeric_limits<T>::is_integer && std::numeric_limits<T>::is_signed, |
236 T>::type | 237 T>::type |
237 CheckedMod(T x, T y, RangeConstraint* validity) { | 238 CheckedMod(T x, T y, RangeConstraint* validity) { |
238 *validity = y > 0 ? RANGE_VALID : RANGE_INVALID; | 239 *validity = y > 0 ? RANGE_VALID : RANGE_INVALID; |
239 return x % y; | 240 return x % y; |
240 } | 241 } |
241 | 242 |
242 template <typename T> | 243 template <typename T> |
243 typename enable_if< | 244 typename enable_if< |
244 std::numeric_limits<T>::is_integer && !std::numeric_limits<T>::is_signed, | 245 std::numeric_limits<T>::is_integer && !std::numeric_limits<T>::is_signed, |
245 T>::type | 246 T>::type |
246 CheckedMod(T x, T y, RangeConstraint* validity) { | 247 CheckedMod(T x, T y, RangeConstraint* validity) { |
247 *validity = RANGE_VALID; | 248 *validity = RANGE_VALID; |
248 return x % y; | 249 return x % y; |
249 } | 250 } |
250 | 251 |
251 template <typename T> | 252 template <typename T> |
252 typename enable_if< | 253 typename enable_if< |
253 std::numeric_limits<T>::is_integer&& std::numeric_limits<T>::is_signed, | 254 std::numeric_limits<T>::is_integer && std::numeric_limits<T>::is_signed, |
254 T>::type | 255 T>::type |
255 CheckedNeg(T value, RangeConstraint* validity) { | 256 CheckedNeg(T value, RangeConstraint* validity) { |
256 *validity = | 257 *validity = |
257 value != std::numeric_limits<T>::min() ? RANGE_VALID : RANGE_OVERFLOW; | 258 value != std::numeric_limits<T>::min() ? RANGE_VALID : RANGE_OVERFLOW; |
258 // The negation of signed min is min, so catch that one. | 259 // The negation of signed min is min, so catch that one. |
259 return -value; | 260 return -value; |
260 } | 261 } |
261 | 262 |
262 template <typename T> | 263 template <typename T> |
263 typename enable_if< | 264 typename enable_if< |
264 std::numeric_limits<T>::is_integer && !std::numeric_limits<T>::is_signed, | 265 std::numeric_limits<T>::is_integer && !std::numeric_limits<T>::is_signed, |
265 T>::type | 266 T>::type |
266 CheckedNeg(T value, RangeConstraint* validity) { | 267 CheckedNeg(T value, RangeConstraint* validity) { |
267 // The only legal unsigned negation is zero. | 268 // The only legal unsigned negation is zero. |
268 *validity = value ? RANGE_UNDERFLOW : RANGE_VALID; | 269 *validity = value ? RANGE_UNDERFLOW : RANGE_VALID; |
269 return static_cast<T>( | 270 return static_cast<T>( |
270 -static_cast<typename SignedIntegerForSize<T>::type>(value)); | 271 -static_cast<typename SignedIntegerForSize<T>::type>(value)); |
271 } | 272 } |
272 | 273 |
273 template <typename T> | 274 template <typename T> |
274 typename enable_if< | 275 typename enable_if< |
275 std::numeric_limits<T>::is_integer&& std::numeric_limits<T>::is_signed, | 276 std::numeric_limits<T>::is_integer && std::numeric_limits<T>::is_signed, |
276 T>::type | 277 T>::type |
277 CheckedAbs(T value, RangeConstraint* validity) { | 278 CheckedAbs(T value, RangeConstraint* validity) { |
278 *validity = | 279 *validity = |
279 value != std::numeric_limits<T>::min() ? RANGE_VALID : RANGE_OVERFLOW; | 280 value != std::numeric_limits<T>::min() ? RANGE_VALID : RANGE_OVERFLOW; |
280 return std::abs(value); | 281 return std::abs(value); |
281 } | 282 } |
282 | 283 |
283 template <typename T> | 284 template <typename T> |
284 typename enable_if< | 285 typename enable_if< |
285 std::numeric_limits<T>::is_integer && !std::numeric_limits<T>::is_signed, | 286 std::numeric_limits<T>::is_integer && !std::numeric_limits<T>::is_signed, |
286 T>::type | 287 T>::type |
287 CheckedAbs(T value, RangeConstraint* validity) { | 288 CheckedAbs(T value, RangeConstraint* validity) { |
288 // Absolute value of a positive is just its identiy. | 289 // Absolute value of a positive is just its identiy. |
289 *validity = RANGE_VALID; | 290 *validity = RANGE_VALID; |
290 return value; | 291 return value; |
291 } | 292 } |
292 | 293 |
293 // These are the floating point stubs that the compiler needs to see. Only the | 294 // These are the floating point stubs that the compiler needs to see. Only the |
294 // negation operation is ever called. | 295 // negation operation is ever called. |
295 #define BASE_FLOAT_ARITHMETIC_STUBS(NAME) \ | 296 #define BASE_FLOAT_ARITHMETIC_STUBS(NAME) \ |
296 template <typename T> \ | 297 template <typename T> \ |
297 typename enable_if<std::numeric_limits<T>::is_iec559, T>::type \ | 298 typename enable_if<std::numeric_limits<T>::is_iec559, T>::type \ |
298 Checked##NAME(T, T, RangeConstraint*) { \ | 299 Checked##NAME(T, T, RangeConstraint*) { \ |
299 NOTREACHED(); \ | 300 NOTREACHED(); \ |
300 return 0; \ | 301 return 0; \ |
301 } | 302 } |
302 | 303 |
303 BASE_FLOAT_ARITHMETIC_STUBS(Add) | 304 BASE_FLOAT_ARITHMETIC_STUBS(Add) |
304 BASE_FLOAT_ARITHMETIC_STUBS(Sub) | 305 BASE_FLOAT_ARITHMETIC_STUBS(Sub) |
305 BASE_FLOAT_ARITHMETIC_STUBS(Mul) | 306 BASE_FLOAT_ARITHMETIC_STUBS(Mul) |
306 BASE_FLOAT_ARITHMETIC_STUBS(Div) | 307 BASE_FLOAT_ARITHMETIC_STUBS(Div) |
307 BASE_FLOAT_ARITHMETIC_STUBS(Mod) | 308 BASE_FLOAT_ARITHMETIC_STUBS(Mod) |
308 | 309 |
(...skipping 24 matching lines...) Expand all Loading... |
333 | 334 |
334 template <typename NumericType> | 335 template <typename NumericType> |
335 struct GetNumericRepresentation { | 336 struct GetNumericRepresentation { |
336 static const NumericRepresentation value = | 337 static const NumericRepresentation value = |
337 std::numeric_limits<NumericType>::is_integer | 338 std::numeric_limits<NumericType>::is_integer |
338 ? NUMERIC_INTEGER | 339 ? NUMERIC_INTEGER |
339 : (std::numeric_limits<NumericType>::is_iec559 ? NUMERIC_FLOATING | 340 : (std::numeric_limits<NumericType>::is_iec559 ? NUMERIC_FLOATING |
340 : NUMERIC_UNKNOWN); | 341 : NUMERIC_UNKNOWN); |
341 }; | 342 }; |
342 | 343 |
343 template <typename T, NumericRepresentation type = | 344 template <typename T, |
344 GetNumericRepresentation<T>::value> | 345 NumericRepresentation type = GetNumericRepresentation<T>::value> |
345 class CheckedNumericState {}; | 346 class CheckedNumericState {}; |
346 | 347 |
347 // Integrals require quite a bit of additional housekeeping to manage state. | 348 // Integrals require quite a bit of additional housekeeping to manage state. |
348 template <typename T> | 349 template <typename T> |
349 class CheckedNumericState<T, NUMERIC_INTEGER> { | 350 class CheckedNumericState<T, NUMERIC_INTEGER> { |
350 private: | 351 private: |
351 T value_; | 352 T value_; |
352 RangeConstraint validity_; | 353 RangeConstraint validity_; |
353 | 354 |
354 public: | 355 public: |
(...skipping 101 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
456 | 457 |
457 template <typename Lhs, | 458 template <typename Lhs, |
458 typename Rhs = Lhs, | 459 typename Rhs = Lhs, |
459 ArithmeticPromotionCategory Promotion = | 460 ArithmeticPromotionCategory Promotion = |
460 (MaxExponent<Lhs>::value > MaxExponent<Rhs>::value) | 461 (MaxExponent<Lhs>::value > MaxExponent<Rhs>::value) |
461 ? (MaxExponent<Lhs>::value > MaxExponent<int>::value | 462 ? (MaxExponent<Lhs>::value > MaxExponent<int>::value |
462 ? LEFT_PROMOTION | 463 ? LEFT_PROMOTION |
463 : DEFAULT_PROMOTION) | 464 : DEFAULT_PROMOTION) |
464 : (MaxExponent<Rhs>::value > MaxExponent<int>::value | 465 : (MaxExponent<Rhs>::value > MaxExponent<int>::value |
465 ? RIGHT_PROMOTION | 466 ? RIGHT_PROMOTION |
466 : DEFAULT_PROMOTION) > | 467 : DEFAULT_PROMOTION) > struct ArithmeticPromotion; |
467 struct ArithmeticPromotion; | |
468 | 468 |
469 template <typename Lhs, typename Rhs> | 469 template <typename Lhs, typename Rhs> |
470 struct ArithmeticPromotion<Lhs, Rhs, LEFT_PROMOTION> { | 470 struct ArithmeticPromotion<Lhs, Rhs, LEFT_PROMOTION> { |
471 typedef Lhs type; | 471 typedef Lhs type; |
472 }; | 472 }; |
473 | 473 |
474 template <typename Lhs, typename Rhs> | 474 template <typename Lhs, typename Rhs> |
475 struct ArithmeticPromotion<Lhs, Rhs, RIGHT_PROMOTION> { | 475 struct ArithmeticPromotion<Lhs, Rhs, RIGHT_PROMOTION> { |
476 typedef Rhs type; | 476 typedef Rhs type; |
477 }; | 477 }; |
(...skipping 15 matching lines...) Expand all Loading... |
493 sizeof(T) >= (2 * sizeof(Lhs)) && | 493 sizeof(T) >= (2 * sizeof(Lhs)) && |
494 StaticDstRangeRelationToSrcRange<T, Rhs>::value != | 494 StaticDstRangeRelationToSrcRange<T, Rhs>::value != |
495 NUMERIC_RANGE_CONTAINED && | 495 NUMERIC_RANGE_CONTAINED && |
496 sizeof(T) >= (2 * sizeof(Rhs)); | 496 sizeof(T) >= (2 * sizeof(Rhs)); |
497 }; | 497 }; |
498 | 498 |
499 } // namespace internal | 499 } // namespace internal |
500 } // namespace base | 500 } // namespace base |
501 | 501 |
502 #endif // SAFE_MATH_IMPL_H_ | 502 #endif // SAFE_MATH_IMPL_H_ |
OLD | NEW |