Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(140)

Side by Side Diff: base/numerics/safe_math_impl.h

Issue 2510973002: Add support for CheckedNumeric bitshift operators (Closed)
Patch Set: format Created 4 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « base/numerics/safe_math.h ('k') | base/numerics/safe_numerics_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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 109 matching lines...) Expand 10 before | Expand all | Expand 10 after
120 return !!(static_cast<typename UnsignedIntegerForSize<T>::type>(x) >> 120 return !!(static_cast<typename UnsignedIntegerForSize<T>::type>(x) >>
121 PositionOfSignBit<T>::value); 121 PositionOfSignBit<T>::value);
122 } 122 }
123 123
124 // This wrapper undoes the standard integer promotions. 124 // This wrapper undoes the standard integer promotions.
125 template <typename T> 125 template <typename T>
126 constexpr T BinaryComplement(T x) { 126 constexpr T BinaryComplement(T x) {
127 return static_cast<T>(~x); 127 return static_cast<T>(~x);
128 } 128 }
129 129
130 // Return if a numeric value is negative regardless of type.
131 template <typename T,
132 typename std::enable_if<std::is_arithmetic<T>::value &&
133 std::is_signed<T>::value>::type* = nullptr>
134 constexpr bool IsNegative(T x) {
135 return x < 0;
136 }
137
138 template <typename T,
139 typename std::enable_if<std::is_arithmetic<T>::value &&
140 !std::is_signed<T>::value>::type* = nullptr>
141 constexpr bool IsNegative(T x) {
142 return false;
143 }
144
130 enum ArithmeticPromotionCategory { 145 enum ArithmeticPromotionCategory {
131 LEFT_PROMOTION, // Use the type of the left-hand argument. 146 LEFT_PROMOTION, // Use the type of the left-hand argument.
132 RIGHT_PROMOTION, // Use the type of the right-hand argument. 147 RIGHT_PROMOTION, // Use the type of the right-hand argument.
133 MAX_EXPONENT_PROMOTION, // Use the type supporting the largest exponent. 148 MAX_EXPONENT_PROMOTION, // Use the type supporting the largest exponent.
134 BIG_ENOUGH_PROMOTION // Attempt to find a big enough type. 149 BIG_ENOUGH_PROMOTION // Attempt to find a big enough type.
135 }; 150 };
136 151
137 template <ArithmeticPromotionCategory Promotion, 152 template <ArithmeticPromotionCategory Promotion,
138 typename Lhs, 153 typename Lhs,
139 typename Rhs = Lhs> 154 typename Rhs = Lhs>
(...skipping 315 matching lines...) Expand 10 before | Expand all | Expand 10 after
455 CheckedMod(T x, U y, V* result) { 470 CheckedMod(T x, U y, V* result) {
456 using Promotion = 471 using Promotion =
457 typename ArithmeticPromotion<BIG_ENOUGH_PROMOTION, T, U>::type; 472 typename ArithmeticPromotion<BIG_ENOUGH_PROMOTION, T, U>::type;
458 Promotion presult; 473 Promotion presult;
459 bool is_valid = CheckedModImpl(static_cast<Promotion>(x), 474 bool is_valid = CheckedModImpl(static_cast<Promotion>(x),
460 static_cast<Promotion>(y), &presult); 475 static_cast<Promotion>(y), &presult);
461 *result = static_cast<V>(presult); 476 *result = static_cast<V>(presult);
462 return is_valid && IsValueInRangeForNumericType<V>(presult); 477 return is_valid && IsValueInRangeForNumericType<V>(presult);
463 } 478 }
464 479
480 // Left shift. Shifts less than 0 or greater than or equal to the number
481 // of bits in the promoted type are undefined. Shifts of negative values
482 // are undefined. Otherwise it is defined when the result fits.
483 template <typename T, typename U, typename V>
484 typename std::enable_if<std::numeric_limits<T>::is_integer &&
485 std::numeric_limits<U>::is_integer &&
486 std::numeric_limits<V>::is_integer,
487 bool>::type
488 CheckedLeftShift(T x, U shift, V* result) {
489 using ShiftType = typename UnsignedIntegerForSize<T>::type;
490 static const ShiftType kBitWidth = CHAR_BIT * sizeof(T);
491 const ShiftType real_shift = static_cast<ShiftType>(shift);
492 // Signed shift is not legal on negative values.
493 if (!IsNegative(x) && real_shift < kBitWidth) {
494 // Just use a multiplication because it's easy.
495 // TODO(jschuh): This could probably be made more efficient.
496 if (!std::is_signed<T>::value || real_shift != kBitWidth - 1)
497 return CheckedMul(x, static_cast<T>(1) << shift, result);
498 return !x; // Special case zero for a full width signed shift.
499 }
500 return false;
501 }
502
503 // Right shift. Shifts less than 0 or greater than or equal to the number
504 // of bits in the promoted type are undefined. Otherwise, it is always defined,
505 // but a right shift of a negative value is implementation-dependent.
506 template <typename T, typename U, typename V>
507 typename std::enable_if<std::numeric_limits<T>::is_integer &&
508 std::numeric_limits<U>::is_integer &&
509 std::numeric_limits<V>::is_integer,
510 bool>::type
511 CheckedRightShift(T x, U shift, V* result) {
512 // Use the type conversion push negative values out of range.
513 using ShiftType = typename UnsignedIntegerForSize<T>::type;
514 if (static_cast<ShiftType>(shift) < (CHAR_BIT * sizeof(T))) {
515 T tmp = x >> shift;
516 *result = static_cast<V>(tmp);
517 return IsValueInRangeForNumericType<unsigned>(tmp);
518 }
519 return false;
520 }
521
465 template <typename T> 522 template <typename T>
466 typename std::enable_if<std::numeric_limits<T>::is_integer && 523 typename std::enable_if<std::numeric_limits<T>::is_integer &&
467 std::numeric_limits<T>::is_signed, 524 std::numeric_limits<T>::is_signed,
468 bool>::type 525 bool>::type
469 CheckedNeg(T value, T* result) { 526 CheckedNeg(T value, T* result) {
470 // The negation of signed min is min, so catch that one. 527 // The negation of signed min is min, so catch that one.
471 if (value != std::numeric_limits<T>::min()) { 528 if (value != std::numeric_limits<T>::min()) {
472 *result = static_cast<T>(-value); 529 *result = static_cast<T>(-value);
473 return true; 530 return true;
474 } 531 }
(...skipping 200 matching lines...) Expand 10 before | Expand all | Expand 10 after
675 : value_(static_cast<T>(rhs.value())) {} 732 : value_(static_cast<T>(rhs.value())) {}
676 733
677 bool is_valid() const { return std::isfinite(value_); } 734 bool is_valid() const { return std::isfinite(value_); }
678 T value() const { return value_; } 735 T value() const { return value_; }
679 }; 736 };
680 737
681 } // namespace internal 738 } // namespace internal
682 } // namespace base 739 } // namespace base
683 740
684 #endif // BASE_NUMERICS_SAFE_MATH_IMPL_H_ 741 #endif // BASE_NUMERICS_SAFE_MATH_IMPL_H_
OLDNEW
« no previous file with comments | « base/numerics/safe_math.h ('k') | base/numerics/safe_numerics_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698