| 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 <stddef.h> | 8 #include <stddef.h> |
| 9 #include <stdint.h> | 9 #include <stdint.h> |
| 10 | 10 |
| (...skipping 244 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 255 // Addition is valid if the sign of (x + y) is equal to either that of x or | 255 // Addition is valid if the sign of (x + y) is equal to either that of x or |
| 256 // that of y. | 256 // that of y. |
| 257 return (std::numeric_limits<T>::is_signed) | 257 return (std::numeric_limits<T>::is_signed) |
| 258 ? HasSignBit(BinaryComplement( | 258 ? HasSignBit(BinaryComplement( |
| 259 static_cast<UnsignedDst>((uresult ^ ux) & (uresult ^ uy)))) | 259 static_cast<UnsignedDst>((uresult ^ ux) & (uresult ^ uy)))) |
| 260 : (BinaryComplement(x) >= | 260 : (BinaryComplement(x) >= |
| 261 y); // Unsigned is either valid or underflow. | 261 y); // Unsigned is either valid or underflow. |
| 262 } | 262 } |
| 263 | 263 |
| 264 template <typename T, typename U, class Enable = void> | 264 template <typename T, typename U, class Enable = void> |
| 265 struct CheckedAdd {}; | 265 struct CheckedAddOp {}; |
| 266 | 266 |
| 267 template <typename T, typename U> | 267 template <typename T, typename U> |
| 268 struct CheckedAdd< | 268 struct CheckedAddOp< |
| 269 T, | 269 T, |
| 270 U, | 270 U, |
| 271 typename std::enable_if<std::numeric_limits<T>::is_integer && | 271 typename std::enable_if<std::numeric_limits<T>::is_integer && |
| 272 std::numeric_limits<U>::is_integer>::type> { | 272 std::numeric_limits<U>::is_integer>::type> { |
| 273 using result_type = | 273 using result_type = |
| 274 typename ArithmeticPromotion<MAX_EXPONENT_PROMOTION, T, U>::type; | 274 typename ArithmeticPromotion<MAX_EXPONENT_PROMOTION, T, U>::type; |
| 275 template <typename V> | 275 template <typename V> |
| 276 static bool Op(T x, U y, V* result) { | 276 static bool Do(T x, U y, V* result) { |
| 277 #if USE_OVERFLOW_BUILTINS | 277 #if USE_OVERFLOW_BUILTINS |
| 278 return !__builtin_add_overflow(x, y, result); | 278 return !__builtin_add_overflow(x, y, result); |
| 279 #else | 279 #else |
| 280 using Promotion = | 280 using Promotion = |
| 281 typename ArithmeticPromotion<BIG_ENOUGH_PROMOTION, T, U>::type; | 281 typename ArithmeticPromotion<BIG_ENOUGH_PROMOTION, T, U>::type; |
| 282 Promotion presult; | 282 Promotion presult; |
| 283 // Fail if either operand is out of range for the promoted type. | 283 // Fail if either operand is out of range for the promoted type. |
| 284 // TODO(jschuh): This could be made to work for a broader range of values. | 284 // TODO(jschuh): This could be made to work for a broader range of values. |
| 285 bool is_valid = IsValueInRangeForNumericType<Promotion>(x) && | 285 bool is_valid = IsValueInRangeForNumericType<Promotion>(x) && |
| 286 IsValueInRangeForNumericType<Promotion>(y); | 286 IsValueInRangeForNumericType<Promotion>(y); |
| (...skipping 22 matching lines...) Expand all Loading... |
| 309 *result = static_cast<T>(uresult); | 309 *result = static_cast<T>(uresult); |
| 310 // Subtraction is valid if either x and y have same sign, or (x-y) and x have | 310 // Subtraction is valid if either x and y have same sign, or (x-y) and x have |
| 311 // the same sign. | 311 // the same sign. |
| 312 return (std::numeric_limits<T>::is_signed) | 312 return (std::numeric_limits<T>::is_signed) |
| 313 ? HasSignBit(BinaryComplement( | 313 ? HasSignBit(BinaryComplement( |
| 314 static_cast<UnsignedDst>((uresult ^ ux) & (ux ^ uy)))) | 314 static_cast<UnsignedDst>((uresult ^ ux) & (ux ^ uy)))) |
| 315 : (x >= y); | 315 : (x >= y); |
| 316 } | 316 } |
| 317 | 317 |
| 318 template <typename T, typename U, class Enable = void> | 318 template <typename T, typename U, class Enable = void> |
| 319 struct CheckedSub {}; | 319 struct CheckedSubOp {}; |
| 320 | 320 |
| 321 template <typename T, typename U> | 321 template <typename T, typename U> |
| 322 struct CheckedSub< | 322 struct CheckedSubOp< |
| 323 T, | 323 T, |
| 324 U, | 324 U, |
| 325 typename std::enable_if<std::numeric_limits<T>::is_integer && | 325 typename std::enable_if<std::numeric_limits<T>::is_integer && |
| 326 std::numeric_limits<U>::is_integer>::type> { | 326 std::numeric_limits<U>::is_integer>::type> { |
| 327 using result_type = | 327 using result_type = |
| 328 typename ArithmeticPromotion<MAX_EXPONENT_PROMOTION, T, U>::type; | 328 typename ArithmeticPromotion<MAX_EXPONENT_PROMOTION, T, U>::type; |
| 329 template <typename V> | 329 template <typename V> |
| 330 static bool Op(T x, U y, V* result) { | 330 static bool Do(T x, U y, V* result) { |
| 331 #if USE_OVERFLOW_BUILTINS | 331 #if USE_OVERFLOW_BUILTINS |
| 332 return !__builtin_sub_overflow(x, y, result); | 332 return !__builtin_sub_overflow(x, y, result); |
| 333 #else | 333 #else |
| 334 using Promotion = | 334 using Promotion = |
| 335 typename ArithmeticPromotion<BIG_ENOUGH_PROMOTION, T, U>::type; | 335 typename ArithmeticPromotion<BIG_ENOUGH_PROMOTION, T, U>::type; |
| 336 Promotion presult; | 336 Promotion presult; |
| 337 // Fail if either operand is out of range for the promoted type. | 337 // Fail if either operand is out of range for the promoted type. |
| 338 // TODO(jschuh): This could be made to work for a broader range of values. | 338 // TODO(jschuh): This could be made to work for a broader range of values. |
| 339 bool is_valid = IsValueInRangeForNumericType<Promotion>(x) && | 339 bool is_valid = IsValueInRangeForNumericType<Promotion>(x) && |
| 340 IsValueInRangeForNumericType<Promotion>(y); | 340 IsValueInRangeForNumericType<Promotion>(y); |
| (...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 400 typename std::enable_if<std::numeric_limits<T>::is_integer && | 400 typename std::enable_if<std::numeric_limits<T>::is_integer && |
| 401 !std::numeric_limits<T>::is_signed && | 401 !std::numeric_limits<T>::is_signed && |
| 402 (sizeof(T) * 2 > sizeof(uintmax_t)), | 402 (sizeof(T) * 2 > sizeof(uintmax_t)), |
| 403 bool>::type | 403 bool>::type |
| 404 CheckedMulImpl(T x, T y, T* result) { | 404 CheckedMulImpl(T x, T y, T* result) { |
| 405 *result = x * y; | 405 *result = x * y; |
| 406 return (y == 0 || x <= std::numeric_limits<T>::max() / y); | 406 return (y == 0 || x <= std::numeric_limits<T>::max() / y); |
| 407 } | 407 } |
| 408 | 408 |
| 409 template <typename T, typename U, class Enable = void> | 409 template <typename T, typename U, class Enable = void> |
| 410 struct CheckedMul {}; | 410 struct CheckedMulOp {}; |
| 411 | 411 |
| 412 template <typename T, typename U> | 412 template <typename T, typename U> |
| 413 struct CheckedMul< | 413 struct CheckedMulOp< |
| 414 T, | 414 T, |
| 415 U, | 415 U, |
| 416 typename std::enable_if<std::numeric_limits<T>::is_integer && | 416 typename std::enable_if<std::numeric_limits<T>::is_integer && |
| 417 std::numeric_limits<U>::is_integer>::type> { | 417 std::numeric_limits<U>::is_integer>::type> { |
| 418 using result_type = | 418 using result_type = |
| 419 typename ArithmeticPromotion<MAX_EXPONENT_PROMOTION, T, U>::type; | 419 typename ArithmeticPromotion<MAX_EXPONENT_PROMOTION, T, U>::type; |
| 420 template <typename V> | 420 template <typename V> |
| 421 static bool Op(T x, U y, V* result) { | 421 static bool Do(T x, U y, V* result) { |
| 422 #if USE_OVERFLOW_BUILTINS | 422 #if USE_OVERFLOW_BUILTINS |
| 423 #if defined(__clang__) | 423 #if defined(__clang__) |
| 424 // TODO(jschuh): Get the Clang runtime library issues sorted out so we can | 424 // TODO(jschuh): Get the Clang runtime library issues sorted out so we can |
| 425 // support full-width, mixed-sign multiply builtins. | 425 // support full-width, mixed-sign multiply builtins. |
| 426 // https://crbug.com/613003 | 426 // https://crbug.com/613003 |
| 427 static const bool kUseMaxInt = | 427 static const bool kUseMaxInt = |
| 428 sizeof(__typeof__(x * y)) < sizeof(intptr_t) || | 428 sizeof(__typeof__(x * y)) < sizeof(intptr_t) || |
| 429 (sizeof(__typeof__(x * y)) == sizeof(intptr_t) && | 429 (sizeof(__typeof__(x * y)) == sizeof(intptr_t) && |
| 430 std::is_signed<T>::value == std::is_signed<U>::value); | 430 std::is_signed<T>::value == std::is_signed<U>::value); |
| 431 #else | 431 #else |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 463 CheckedDivImpl(T x, T y, T* result) { | 463 CheckedDivImpl(T x, T y, T* result) { |
| 464 if (y && (!std::numeric_limits<T>::is_signed || | 464 if (y && (!std::numeric_limits<T>::is_signed || |
| 465 x != std::numeric_limits<T>::min() || y != static_cast<T>(-1))) { | 465 x != std::numeric_limits<T>::min() || y != static_cast<T>(-1))) { |
| 466 *result = x / y; | 466 *result = x / y; |
| 467 return true; | 467 return true; |
| 468 } | 468 } |
| 469 return false; | 469 return false; |
| 470 } | 470 } |
| 471 | 471 |
| 472 template <typename T, typename U, class Enable = void> | 472 template <typename T, typename U, class Enable = void> |
| 473 struct CheckedDiv {}; | 473 struct CheckedDivOp {}; |
| 474 | 474 |
| 475 template <typename T, typename U> | 475 template <typename T, typename U> |
| 476 struct CheckedDiv< | 476 struct CheckedDivOp< |
| 477 T, | 477 T, |
| 478 U, | 478 U, |
| 479 typename std::enable_if<std::numeric_limits<T>::is_integer && | 479 typename std::enable_if<std::numeric_limits<T>::is_integer && |
| 480 std::numeric_limits<U>::is_integer>::type> { | 480 std::numeric_limits<U>::is_integer>::type> { |
| 481 using result_type = | 481 using result_type = |
| 482 typename ArithmeticPromotion<MAX_EXPONENT_PROMOTION, T, U>::type; | 482 typename ArithmeticPromotion<MAX_EXPONENT_PROMOTION, T, U>::type; |
| 483 template <typename V> | 483 template <typename V> |
| 484 static bool Op(T x, U y, V* result) { | 484 static bool Do(T x, U y, V* result) { |
| 485 using Promotion = | 485 using Promotion = |
| 486 typename ArithmeticPromotion<BIG_ENOUGH_PROMOTION, T, U>::type; | 486 typename ArithmeticPromotion<BIG_ENOUGH_PROMOTION, T, U>::type; |
| 487 Promotion presult; | 487 Promotion presult; |
| 488 // Fail if either operand is out of range for the promoted type. | 488 // Fail if either operand is out of range for the promoted type. |
| 489 // TODO(jschuh): This could be made to work for a broader range of values. | 489 // TODO(jschuh): This could be made to work for a broader range of values. |
| 490 bool is_valid = IsValueInRangeForNumericType<Promotion>(x) && | 490 bool is_valid = IsValueInRangeForNumericType<Promotion>(x) && |
| 491 IsValueInRangeForNumericType<Promotion>(y); | 491 IsValueInRangeForNumericType<Promotion>(y); |
| 492 is_valid &= CheckedDivImpl(static_cast<Promotion>(x), | 492 is_valid &= CheckedDivImpl(static_cast<Promotion>(x), |
| 493 static_cast<Promotion>(y), &presult); | 493 static_cast<Promotion>(y), &presult); |
| 494 *result = static_cast<V>(presult); | 494 *result = static_cast<V>(presult); |
| (...skipping 19 matching lines...) Expand all Loading... |
| 514 bool>::type | 514 bool>::type |
| 515 CheckedModImpl(T x, T y, T* result) { | 515 CheckedModImpl(T x, T y, T* result) { |
| 516 if (y != 0) { | 516 if (y != 0) { |
| 517 *result = static_cast<T>(x % y); | 517 *result = static_cast<T>(x % y); |
| 518 return true; | 518 return true; |
| 519 } | 519 } |
| 520 return false; | 520 return false; |
| 521 } | 521 } |
| 522 | 522 |
| 523 template <typename T, typename U, class Enable = void> | 523 template <typename T, typename U, class Enable = void> |
| 524 struct CheckedMod {}; | 524 struct CheckedModOp {}; |
| 525 | 525 |
| 526 template <typename T, typename U> | 526 template <typename T, typename U> |
| 527 struct CheckedMod< | 527 struct CheckedModOp< |
| 528 T, | 528 T, |
| 529 U, | 529 U, |
| 530 typename std::enable_if<std::numeric_limits<T>::is_integer && | 530 typename std::enable_if<std::numeric_limits<T>::is_integer && |
| 531 std::numeric_limits<U>::is_integer>::type> { | 531 std::numeric_limits<U>::is_integer>::type> { |
| 532 using result_type = | 532 using result_type = |
| 533 typename ArithmeticPromotion<MAX_EXPONENT_PROMOTION, T, U>::type; | 533 typename ArithmeticPromotion<MAX_EXPONENT_PROMOTION, T, U>::type; |
| 534 template <typename V> | 534 template <typename V> |
| 535 static bool Op(T x, U y, V* result) { | 535 static bool Do(T x, U y, V* result) { |
| 536 using Promotion = | 536 using Promotion = |
| 537 typename ArithmeticPromotion<BIG_ENOUGH_PROMOTION, T, U>::type; | 537 typename ArithmeticPromotion<BIG_ENOUGH_PROMOTION, T, U>::type; |
| 538 Promotion presult; | 538 Promotion presult; |
| 539 bool is_valid = CheckedModImpl(static_cast<Promotion>(x), | 539 bool is_valid = CheckedModImpl(static_cast<Promotion>(x), |
| 540 static_cast<Promotion>(y), &presult); | 540 static_cast<Promotion>(y), &presult); |
| 541 *result = static_cast<V>(presult); | 541 *result = static_cast<V>(presult); |
| 542 return is_valid && IsValueInRangeForNumericType<V>(presult); | 542 return is_valid && IsValueInRangeForNumericType<V>(presult); |
| 543 } | 543 } |
| 544 }; | 544 }; |
| 545 | 545 |
| 546 template <typename T, typename U, class Enable = void> | 546 template <typename T, typename U, class Enable = void> |
| 547 struct CheckedLeftShift {}; | 547 struct CheckedLshOp {}; |
| 548 | 548 |
| 549 // Left shift. Shifts less than 0 or greater than or equal to the number | 549 // Left shift. Shifts less than 0 or greater than or equal to the number |
| 550 // of bits in the promoted type are undefined. Shifts of negative values | 550 // of bits in the promoted type are undefined. Shifts of negative values |
| 551 // are undefined. Otherwise it is defined when the result fits. | 551 // are undefined. Otherwise it is defined when the result fits. |
| 552 template <typename T, typename U> | 552 template <typename T, typename U> |
| 553 struct CheckedLeftShift< | 553 struct CheckedLshOp< |
| 554 T, | 554 T, |
| 555 U, | 555 U, |
| 556 typename std::enable_if<std::numeric_limits<T>::is_integer && | 556 typename std::enable_if<std::numeric_limits<T>::is_integer && |
| 557 std::numeric_limits<U>::is_integer>::type> { | 557 std::numeric_limits<U>::is_integer>::type> { |
| 558 using result_type = T; | 558 using result_type = T; |
| 559 template <typename V> | 559 template <typename V> |
| 560 static bool Op(T x, U shift, V* result) { | 560 static bool Do(T x, U shift, V* result) { |
| 561 using ShiftType = typename UnsignedIntegerForSize<T>::type; | 561 using ShiftType = typename UnsignedIntegerForSize<T>::type; |
| 562 static const ShiftType kBitWidth = CHAR_BIT * sizeof(T); | 562 static const ShiftType kBitWidth = CHAR_BIT * sizeof(T); |
| 563 const ShiftType real_shift = static_cast<ShiftType>(shift); | 563 const ShiftType real_shift = static_cast<ShiftType>(shift); |
| 564 // Signed shift is not legal on negative values. | 564 // Signed shift is not legal on negative values. |
| 565 if (!IsValueNegative(x) && real_shift < kBitWidth) { | 565 if (!IsValueNegative(x) && real_shift < kBitWidth) { |
| 566 // Just use a multiplication because it's easy. | 566 // Just use a multiplication because it's easy. |
| 567 // TODO(jschuh): This could probably be made more efficient. | 567 // TODO(jschuh): This could probably be made more efficient. |
| 568 if (!std::is_signed<T>::value || real_shift != kBitWidth - 1) | 568 if (!std::is_signed<T>::value || real_shift != kBitWidth - 1) |
| 569 return CheckedMul<T, T>::Op(x, static_cast<T>(1) << shift, result); | 569 return CheckedMulOp<T, T>::Do(x, static_cast<T>(1) << shift, result); |
| 570 return !x; // Special case zero for a full width signed shift. | 570 return !x; // Special case zero for a full width signed shift. |
| 571 } | 571 } |
| 572 return false; | 572 return false; |
| 573 } | 573 } |
| 574 }; | 574 }; |
| 575 | 575 |
| 576 template <typename T, typename U, class Enable = void> | 576 template <typename T, typename U, class Enable = void> |
| 577 struct CheckedRightShift {}; | 577 struct CheckedRshOp {}; |
| 578 | 578 |
| 579 // Right shift. Shifts less than 0 or greater than or equal to the number | 579 // Right shift. Shifts less than 0 or greater than or equal to the number |
| 580 // of bits in the promoted type are undefined. Otherwise, it is always defined, | 580 // of bits in the promoted type are undefined. Otherwise, it is always defined, |
| 581 // but a right shift of a negative value is implementation-dependent. | 581 // but a right shift of a negative value is implementation-dependent. |
| 582 template <typename T, typename U> | 582 template <typename T, typename U> |
| 583 struct CheckedRightShift< | 583 struct CheckedRshOp< |
| 584 T, | 584 T, |
| 585 U, | 585 U, |
| 586 typename std::enable_if<std::numeric_limits<T>::is_integer && | 586 typename std::enable_if<std::numeric_limits<T>::is_integer && |
| 587 std::numeric_limits<U>::is_integer>::type> { | 587 std::numeric_limits<U>::is_integer>::type> { |
| 588 using result_type = T; | 588 using result_type = T; |
| 589 template <typename V = result_type> | 589 template <typename V = result_type> |
| 590 static bool Op(T x, U shift, V* result) { | 590 static bool Do(T x, U shift, V* result) { |
| 591 // Use the type conversion push negative values out of range. | 591 // Use the type conversion push negative values out of range. |
| 592 using ShiftType = typename UnsignedIntegerForSize<T>::type; | 592 using ShiftType = typename UnsignedIntegerForSize<T>::type; |
| 593 if (static_cast<ShiftType>(shift) < (CHAR_BIT * sizeof(T))) { | 593 if (static_cast<ShiftType>(shift) < (CHAR_BIT * sizeof(T))) { |
| 594 T tmp = x >> shift; | 594 T tmp = x >> shift; |
| 595 *result = static_cast<V>(tmp); | 595 *result = static_cast<V>(tmp); |
| 596 return IsValueInRangeForNumericType<V>(tmp); | 596 return IsValueInRangeForNumericType<V>(tmp); |
| 597 } | 597 } |
| 598 return false; | 598 return false; |
| 599 } | 599 } |
| 600 }; | 600 }; |
| (...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 662 constexpr typename std::enable_if<std::numeric_limits<T>::is_integer && | 662 constexpr typename std::enable_if<std::numeric_limits<T>::is_integer && |
| 663 !std::numeric_limits<T>::is_signed, | 663 !std::numeric_limits<T>::is_signed, |
| 664 T>::type | 664 T>::type |
| 665 SafeUnsignedAbs(T value) { | 665 SafeUnsignedAbs(T value) { |
| 666 // T is unsigned, so |value| must already be positive. | 666 // T is unsigned, so |value| must already be positive. |
| 667 return static_cast<T>(value); | 667 return static_cast<T>(value); |
| 668 } | 668 } |
| 669 | 669 |
| 670 // This is just boilerplate that wraps the standard floating point arithmetic. | 670 // This is just boilerplate that wraps the standard floating point arithmetic. |
| 671 // A macro isn't the nicest solution, but it beats rewriting these repeatedly. | 671 // A macro isn't the nicest solution, but it beats rewriting these repeatedly. |
| 672 #define BASE_FLOAT_ARITHMETIC_OPS(NAME, OP) \ | 672 #define BASE_FLOAT_ARITHMETIC_OPS(NAME, OP) \ |
| 673 template <typename T, typename U> \ | 673 template <typename T, typename U> \ |
| 674 struct Checked##NAME<T, U, typename std::enable_if< \ | 674 struct Checked##NAME##Op< \ |
| 675 std::numeric_limits<T>::is_iec559 || \ | 675 T, U, \ |
| 676 std::numeric_limits<U>::is_iec559>::type> { \ | 676 typename std::enable_if<std::numeric_limits<T>::is_iec559 || \ |
| 677 using result_type = \ | 677 std::numeric_limits<U>::is_iec559>::type> { \ |
| 678 typename ArithmeticPromotion<MAX_EXPONENT_PROMOTION, T, U>::type; \ | 678 using result_type = \ |
| 679 template <typename V> \ | 679 typename ArithmeticPromotion<MAX_EXPONENT_PROMOTION, T, U>::type; \ |
| 680 static bool Op(T x, U y, V* result) { \ | 680 template <typename V> \ |
| 681 using Promotion = \ | 681 static bool Do(T x, U y, V* result) { \ |
| 682 typename ArithmeticPromotion<MAX_EXPONENT_PROMOTION, T, U>::type; \ | 682 using Promotion = \ |
| 683 Promotion presult = x OP y; \ | 683 typename ArithmeticPromotion<MAX_EXPONENT_PROMOTION, T, U>::type; \ |
| 684 *result = static_cast<V>(presult); \ | 684 Promotion presult = x OP y; \ |
| 685 return IsValueInRangeForNumericType<V>(presult); \ | 685 *result = static_cast<V>(presult); \ |
| 686 } \ | 686 return IsValueInRangeForNumericType<V>(presult); \ |
| 687 } \ |
| 687 }; | 688 }; |
| 688 | 689 |
| 689 BASE_FLOAT_ARITHMETIC_OPS(Add, +) | 690 BASE_FLOAT_ARITHMETIC_OPS(Add, +) |
| 690 BASE_FLOAT_ARITHMETIC_OPS(Sub, -) | 691 BASE_FLOAT_ARITHMETIC_OPS(Sub, -) |
| 691 BASE_FLOAT_ARITHMETIC_OPS(Mul, *) | 692 BASE_FLOAT_ARITHMETIC_OPS(Mul, *) |
| 692 BASE_FLOAT_ARITHMETIC_OPS(Div, /) | 693 BASE_FLOAT_ARITHMETIC_OPS(Div, /) |
| 693 | 694 |
| 694 #undef BASE_FLOAT_ARITHMETIC_OPS | 695 #undef BASE_FLOAT_ARITHMETIC_OPS |
| 695 | 696 |
| 696 template <typename T> | 697 template <typename T> |
| (...skipping 101 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 798 | 799 |
| 799 // Copy constructor. | 800 // Copy constructor. |
| 800 template <typename Src> | 801 template <typename Src> |
| 801 constexpr CheckedNumericState(const CheckedNumericState<Src>& rhs) | 802 constexpr CheckedNumericState(const CheckedNumericState<Src>& rhs) |
| 802 : value_(static_cast<T>(rhs.value())) {} | 803 : value_(static_cast<T>(rhs.value())) {} |
| 803 | 804 |
| 804 constexpr bool is_valid() const { return std::isfinite(value_); } | 805 constexpr bool is_valid() const { return std::isfinite(value_); } |
| 805 constexpr T value() const { return value_; } | 806 constexpr T value() const { return value_; } |
| 806 }; | 807 }; |
| 807 | 808 |
| 809 // The following are helper templates used in the CheckedNumeric class. |
| 810 template <typename T> |
| 811 class CheckedNumeric; |
| 812 |
| 813 // Used to treat CheckedNumeric and arithmetic underlying types the same. |
| 814 template <typename T> |
| 815 struct UnderlyingType { |
| 816 using type = T; |
| 817 static const bool is_numeric = std::is_arithmetic<T>::value; |
| 818 static const bool is_checked = false; |
| 819 }; |
| 820 |
| 821 template <typename T> |
| 822 struct UnderlyingType<CheckedNumeric<T>> { |
| 823 using type = T; |
| 824 static const bool is_numeric = true; |
| 825 static const bool is_checked = true; |
| 826 }; |
| 827 |
| 828 template <typename L, typename R> |
| 829 struct IsCheckedOp { |
| 830 static const bool value = |
| 831 UnderlyingType<L>::is_numeric && UnderlyingType<R>::is_numeric && |
| 832 (UnderlyingType<L>::is_checked || UnderlyingType<R>::is_checked); |
| 833 }; |
| 834 |
| 835 template <template <typename, typename, typename> class M, |
| 836 typename L, |
| 837 typename R> |
| 838 struct MathWrapper { |
| 839 using math = M<typename UnderlyingType<L>::type, |
| 840 typename UnderlyingType<R>::type, |
| 841 void>; |
| 842 using type = typename math::result_type; |
| 843 }; |
| 844 |
| 808 } // namespace internal | 845 } // namespace internal |
| 809 } // namespace base | 846 } // namespace base |
| 810 | 847 |
| 811 #endif // BASE_NUMERICS_SAFE_MATH_IMPL_H_ | 848 #endif // BASE_NUMERICS_SAFE_MATH_IMPL_H_ |
| OLD | NEW |