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

Unified Diff: base/numerics/safe_math_impl.h

Issue 2502083002: Restructure ArithmeticPromotion to support alternate promotions (Closed)
Patch Set: nit 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 side-by-side diff with in-line comments
Download patch
« base/numerics/safe_math.h ('K') | « base/numerics/safe_math.h ('k') | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: base/numerics/safe_math_impl.h
diff --git a/base/numerics/safe_math_impl.h b/base/numerics/safe_math_impl.h
index 7b9e53ab94c012263e4af764a5d1c453b03b9e99..c8e4e20c2a84ee00b9f9fe996c7a1dc34ebcb823 100644
--- a/base/numerics/safe_math_impl.h
+++ b/base/numerics/safe_math_impl.h
@@ -127,26 +127,103 @@ constexpr T BinaryComplement(T x) {
return static_cast<T>(~x);
}
-// For integers less than 128-bit and floats 32-bit or larger, we have the type
-// with the larger maximum exponent take precedence.
-enum ArithmeticPromotionCategory { LEFT_PROMOTION, RIGHT_PROMOTION };
+enum ArithmeticPromotionCategory {
+ LEFT_PROMOTION, // Use the type of the left-hand argument.
Tom Sepez 2016/11/15 22:32:13 Do we ever do left/right promotion? Or is this fo
jschuh 2016/11/15 22:38:49 Just for the forthcoming shift.
+ RIGHT_PROMOTION, // Use the type of the right-hand argument.
+ MAX_EXPONENT_PROMOTION, // Use the type supporting the largest exponent.
+ BIG_ENOUGH_PROMOTION // Attempt to find a big enough type.
+};
+
+template <ArithmeticPromotionCategory Promotion,
+ typename Lhs,
+ typename Rhs = Lhs>
+struct ArithmeticPromotion;
template <typename Lhs,
- typename Rhs = Lhs,
+ typename Rhs,
ArithmeticPromotionCategory Promotion =
(MaxExponent<Lhs>::value > MaxExponent<Rhs>::value)
? LEFT_PROMOTION
: RIGHT_PROMOTION>
-struct ArithmeticPromotion;
+struct MaxExponentPromotion;
+
+template <typename Lhs, typename Rhs>
+struct MaxExponentPromotion<Lhs, Rhs, LEFT_PROMOTION> {
+ using type = Lhs;
+};
+
+template <typename Lhs, typename Rhs>
+struct MaxExponentPromotion<Lhs, Rhs, RIGHT_PROMOTION> {
+ using type = Rhs;
+};
+
+template <typename Lhs,
+ typename Rhs = Lhs,
+ bool is_intmax_type =
+ std::is_integral<
+ typename MaxExponentPromotion<Lhs, Rhs>::type>::value &&
+ sizeof(typename MaxExponentPromotion<Lhs, Rhs>::type) ==
+ sizeof(intmax_t),
+ bool is_max_exponent =
+ StaticDstRangeRelationToSrcRange<
+ typename MaxExponentPromotion<Lhs, Rhs>::type,
+ Lhs>::value ==
+ NUMERIC_RANGE_CONTAINED&& StaticDstRangeRelationToSrcRange<
+ typename MaxExponentPromotion<Lhs, Rhs>::type,
+ Rhs>::value == NUMERIC_RANGE_CONTAINED>
+struct BigEnoughPromotion;
+
+// The side with the max exponent is big enough.
+template <typename Lhs, typename Rhs, bool is_intmax_type>
+struct BigEnoughPromotion<Lhs, Rhs, is_intmax_type, true> {
+ using type = typename MaxExponentPromotion<Lhs, Rhs>::type;
+ static const bool is_contained = true;
+};
+
+// We can use a twice wider type to fit.
+template <typename Lhs, typename Rhs>
+struct BigEnoughPromotion<Lhs, Rhs, false, false> {
+ using type = typename IntegerForSizeAndSign<
+ sizeof(typename MaxExponentPromotion<Lhs, Rhs>::type) * 2,
+ std::is_signed<Lhs>::value || std::is_signed<Rhs>::value>::type;
+ static const bool is_contained = true;
+};
+
+// No type is large enough.
+template <typename Lhs, typename Rhs>
+struct BigEnoughPromotion<Lhs, Rhs, true, false> {
+ using type = typename MaxExponentPromotion<Lhs, Rhs>::type;
+ static const bool is_contained = false;
+};
+
+// These are the four supported promotion types.
+
+// Use the type of the left-hand argument.
+template <typename Lhs, typename Rhs>
+struct ArithmeticPromotion<LEFT_PROMOTION, Lhs, Rhs> {
+ using type = Lhs;
+ static const bool is_contained = true;
+};
+
+// Use the type of the right-hand argument.
+template <typename Lhs, typename Rhs>
+struct ArithmeticPromotion<RIGHT_PROMOTION, Lhs, Rhs> {
+ using type = Rhs;
+ static const bool is_contained = true;
+};
+// Use the type supporting the largest exponent.
template <typename Lhs, typename Rhs>
-struct ArithmeticPromotion<Lhs, Rhs, LEFT_PROMOTION> {
- typedef Lhs type;
+struct ArithmeticPromotion<MAX_EXPONENT_PROMOTION, Lhs, Rhs> {
+ using type = typename MaxExponentPromotion<Lhs, Rhs>::type;
+ static const bool is_contained = true;
};
+// Attempt to find a big enough type.
template <typename Lhs, typename Rhs>
-struct ArithmeticPromotion<Lhs, Rhs, RIGHT_PROMOTION> {
- typedef Rhs type;
+struct ArithmeticPromotion<BIG_ENOUGH_PROMOTION, Lhs, Rhs> {
+ using type = typename BigEnoughPromotion<Lhs, Rhs>::type;
+ static const bool is_contained = BigEnoughPromotion<Lhs, Rhs>::is_contained;
};
// Here are the actual portable checked integer math implementations.
@@ -178,7 +255,8 @@ typename std::enable_if<std::numeric_limits<T>::is_integer &&
std::numeric_limits<V>::is_integer,
bool>::type
CheckedAdd(T x, U y, V* result) {
- using Promotion = typename ArithmeticPromotion<T, U>::type;
+ using Promotion =
+ typename ArithmeticPromotion<BIG_ENOUGH_PROMOTION, T, U>::type;
// Fail if either operand is out of range for the promoted type.
// TODO(jschuh): This could be made to work for a broader range of values.
if (!IsValueInRangeForNumericType<Promotion>(x) ||
@@ -217,7 +295,8 @@ typename std::enable_if<std::numeric_limits<T>::is_integer &&
std::numeric_limits<V>::is_integer,
bool>::type
CheckedSub(T x, U y, V* result) {
- using Promotion = typename ArithmeticPromotion<T, U>::type;
+ using Promotion =
+ typename ArithmeticPromotion<BIG_ENOUGH_PROMOTION, T, U>::type;
// Fail if either operand is out of range for the promoted type.
// TODO(jschuh): This could be made to work for a broader range of values.
if (!IsValueInRangeForNumericType<Promotion>(x) ||
@@ -293,7 +372,8 @@ typename std::enable_if<std::numeric_limits<T>::is_integer &&
std::numeric_limits<V>::is_integer,
bool>::type
CheckedMul(T x, U y, V* result) {
- using Promotion = typename ArithmeticPromotion<T, U>::type;
+ using Promotion =
+ typename ArithmeticPromotion<BIG_ENOUGH_PROMOTION, T, U>::type;
// Fail if either operand is out of range for the promoted type.
// TODO(jschuh): This could be made to work for a broader range of values.
if (!IsValueInRangeForNumericType<Promotion>(x) ||
@@ -327,7 +407,8 @@ typename std::enable_if<std::numeric_limits<T>::is_integer &&
std::numeric_limits<V>::is_integer,
bool>::type
CheckedDiv(T x, U y, V* result) {
- using Promotion = typename ArithmeticPromotion<T, U>::type;
+ using Promotion =
+ typename ArithmeticPromotion<BIG_ENOUGH_PROMOTION, T, U>::type;
// Fail if either operand is out of range for the promoted type.
// TODO(jschuh): This could be made to work for a broader range of values.
if (!IsValueInRangeForNumericType<Promotion>(x) ||
@@ -372,7 +453,8 @@ typename std::enable_if<std::numeric_limits<T>::is_integer &&
std::numeric_limits<V>::is_integer,
bool>::type
CheckedMod(T x, U y, V* result) {
- using Promotion = typename ArithmeticPromotion<T, U>::type;
+ using Promotion =
+ typename ArithmeticPromotion<BIG_ENOUGH_PROMOTION, T, U>::type;
Promotion presult;
bool is_valid = CheckedModImpl(static_cast<Promotion>(x),
static_cast<Promotion>(y), &presult);
« base/numerics/safe_math.h ('K') | « base/numerics/safe_math.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698