Update third_party/base/numerics.
Sync with Chromium's copy at https://crrev.com/992474 to pick up changes
like https://crrev.com/957561 and https://crrev.com/958889.
Change-Id: Id8be1ca177c5cc369b6eaabae6b32e51b7bc23bc
Reviewed-on: https://pdfium-review.googlesource.com/c/pdfium/+/93380
Commit-Queue: Lei Zhang <thestig@chromium.org>
Reviewed-by: Tom Sepez <tsepez@chromium.org>
diff --git a/third_party/base/numerics/checked_math.h b/third_party/base/numerics/checked_math.h
index 2da3677..eb0d9a5 100644
--- a/third_party/base/numerics/checked_math.h
+++ b/third_party/base/numerics/checked_math.h
@@ -22,6 +22,9 @@
"CheckedNumeric<T>: T must be a numeric type.");
public:
+ template <typename Src>
+ friend class CheckedNumeric;
+
using type = T;
constexpr CheckedNumeric() = default;
@@ -31,15 +34,12 @@
constexpr CheckedNumeric(const CheckedNumeric<Src>& rhs)
: state_(rhs.state_.value(), rhs.IsValid()) {}
- template <typename Src>
- friend class CheckedNumeric;
-
// This is not an explicit constructor because we implicitly upgrade regular
// numerics to CheckedNumerics to make them easier to use.
template <typename Src>
constexpr CheckedNumeric(Src value) // NOLINT(runtime/explicit)
: state_(value) {
- static_assert(std::is_arithmetic<Src>::value, "Argument must be numeric.");
+ static_assert(UnderlyingType<Src>::is_numeric, "Argument must be numeric.");
}
// This is not an explicit constructor because we want a seamless conversion
@@ -111,7 +111,7 @@
}
// This friend method is available solely for providing more detailed logging
- // in the the tests. Do not implement it in production code, because the
+ // in the tests. Do not implement it in production code, because the
// underlying values may change at any time.
template <typename U>
friend U GetNumericValueForTest(const CheckedNumeric<U>& src);
@@ -139,18 +139,17 @@
constexpr CheckedNumeric& operator^=(const Src rhs);
constexpr CheckedNumeric operator-() const {
- // The negation of two's complement int min is int min, so we simply
- // check for that in the constexpr case.
- // We use an optimized code path for a known run-time variable.
- return MustTreatAsConstexpr(state_.value()) || !std::is_signed<T>::value ||
- std::is_floating_point<T>::value
- ? CheckedNumeric<T>(
- NegateWrapper(state_.value()),
- IsValid() && (!std::is_signed<T>::value ||
- std::is_floating_point<T>::value ||
- NegateWrapper(state_.value()) !=
- std::numeric_limits<T>::lowest()))
- : FastRuntimeNegate();
+ // Use an optimized code path for a known run-time variable.
+ if (!IsConstantEvaluated() && std::is_signed<T>::value &&
+ std::is_floating_point<T>::value) {
+ return FastRuntimeNegate();
+ }
+ // The negation of two's complement int min is int min.
+ const bool is_valid =
+ IsValid() &&
+ (!std::is_signed<T>::value || std::is_floating_point<T>::value ||
+ NegateWrapper(state_.value()) != std::numeric_limits<T>::lowest());
+ return CheckedNumeric<T>(NegateWrapper(state_.value()), is_valid);
}
constexpr CheckedNumeric operator~() const {
@@ -165,31 +164,13 @@
template <typename U>
constexpr CheckedNumeric<typename MathWrapper<CheckedMaxOp, T, U>::type> Max(
const U rhs) const {
- using R = typename UnderlyingType<U>::type;
- using result_type = typename MathWrapper<CheckedMaxOp, T, U>::type;
- // TODO(jschuh): This can be converted to the MathOp version and remain
- // constexpr once we have C++14 support.
- return CheckedNumeric<result_type>(
- static_cast<result_type>(
- IsGreater<T, R>::Test(state_.value(), Wrapper<U>::value(rhs))
- ? state_.value()
- : Wrapper<U>::value(rhs)),
- state_.is_valid() && Wrapper<U>::is_valid(rhs));
+ return CheckMax(*this, rhs);
}
template <typename U>
constexpr CheckedNumeric<typename MathWrapper<CheckedMinOp, T, U>::type> Min(
const U rhs) const {
- using R = typename UnderlyingType<U>::type;
- using result_type = typename MathWrapper<CheckedMinOp, T, U>::type;
- // TODO(jschuh): This can be converted to the MathOp version and remain
- // constexpr once we have C++14 support.
- return CheckedNumeric<result_type>(
- static_cast<result_type>(
- IsLess<T, R>::Test(state_.value(), Wrapper<U>::value(rhs))
- ? state_.value()
- : Wrapper<U>::value(rhs)),
- state_.is_valid() && Wrapper<U>::is_valid(rhs));
+ return CheckMin(*this, rhs);
}
// This function is available only for integral types. It returns an unsigned
@@ -218,7 +199,8 @@
}
constexpr CheckedNumeric operator--(int) {
- CheckedNumeric value = *this;
+ // TODO(pkasting): Consider std::exchange() once it's constexpr in C++20.
+ const CheckedNumeric value = *this;
*this -= 1;
return value;
}
@@ -231,7 +213,7 @@
static constexpr CheckedNumeric MathOp(const L lhs, const R rhs) {
using Math = typename MathWrapper<M, L, R>::math;
T result = 0;
- bool is_valid =
+ const bool is_valid =
Wrapper<L>::is_valid(lhs) && Wrapper<R>::is_valid(rhs) &&
Math::Do(Wrapper<L>::value(lhs), Wrapper<R>::value(rhs), &result);
return CheckedNumeric<T>(result, is_valid);
@@ -242,8 +224,9 @@
constexpr CheckedNumeric& MathOp(const R rhs) {
using Math = typename MathWrapper<M, T, R>::math;
T result = 0; // Using T as the destination saves a range check.
- bool is_valid = state_.is_valid() && Wrapper<R>::is_valid(rhs) &&
- Math::Do(state_.value(), Wrapper<R>::value(rhs), &result);
+ const bool is_valid =
+ state_.is_valid() && Wrapper<R>::is_valid(rhs) &&
+ Math::Do(state_.value(), Wrapper<R>::value(rhs), &result);
*this = CheckedNumeric<T>(result, is_valid);
return *this;
}
@@ -253,7 +236,7 @@
CheckedNumeric FastRuntimeNegate() const {
T result;
- bool success = CheckedSubOp<T, T>::Do(T(0), state_.value(), &result);
+ const bool success = CheckedSubOp<T, T>::Do(T(0), state_.value(), &result);
return CheckedNumeric<T>(result, IsValid() && success);
}
@@ -307,8 +290,8 @@
return value.template ValueOrDefault<Dst>(default_value);
}
-// Convience wrapper to return a new CheckedNumeric from the provided arithmetic
-// or CheckedNumericType.
+// Convenience wrapper to return a new CheckedNumeric from the provided
+// arithmetic or CheckedNumericType.
template <typename T>
constexpr CheckedNumeric<typename UnderlyingType<T>::type> MakeCheckedNum(
const T value) {
@@ -332,8 +315,7 @@
typename L,
typename R,
typename... Args>
-constexpr CheckedNumeric<typename ResultType<M, L, R, Args...>::type>
-CheckMathOp(const L lhs, const R rhs, const Args... args) {
+constexpr auto CheckMathOp(const L lhs, const R rhs, const Args... args) {
return CheckMathOp<M>(CheckMathOp<M>(lhs, rhs), args...);
}
@@ -355,39 +337,39 @@
// bad, we trigger the CHECK condition here.
template <typename L, typename R>
L* operator+(L* lhs, const StrictNumeric<R> rhs) {
- uintptr_t result = CheckAdd(reinterpret_cast<uintptr_t>(lhs),
- CheckMul(sizeof(L), static_cast<R>(rhs)))
- .template ValueOrDie<uintptr_t>();
+ const uintptr_t result = CheckAdd(reinterpret_cast<uintptr_t>(lhs),
+ CheckMul(sizeof(L), static_cast<R>(rhs)))
+ .template ValueOrDie<uintptr_t>();
return reinterpret_cast<L*>(result);
}
template <typename L, typename R>
L* operator-(L* lhs, const StrictNumeric<R> rhs) {
- uintptr_t result = CheckSub(reinterpret_cast<uintptr_t>(lhs),
- CheckMul(sizeof(L), static_cast<R>(rhs)))
- .template ValueOrDie<uintptr_t>();
+ const uintptr_t result = CheckSub(reinterpret_cast<uintptr_t>(lhs),
+ CheckMul(sizeof(L), static_cast<R>(rhs)))
+ .template ValueOrDie<uintptr_t>();
return reinterpret_cast<L*>(result);
}
} // namespace internal
+using internal::CheckAdd;
+using internal::CheckAnd;
+using internal::CheckDiv;
using internal::CheckedNumeric;
-using internal::IsValidForType;
-using internal::ValueOrDieForType;
-using internal::ValueOrDefaultForType;
-using internal::MakeCheckedNum;
+using internal::CheckLsh;
using internal::CheckMax;
using internal::CheckMin;
-using internal::CheckAdd;
-using internal::CheckSub;
-using internal::CheckMul;
-using internal::CheckDiv;
using internal::CheckMod;
-using internal::CheckLsh;
-using internal::CheckRsh;
-using internal::CheckAnd;
+using internal::CheckMul;
using internal::CheckOr;
+using internal::CheckRsh;
+using internal::CheckSub;
using internal::CheckXor;
+using internal::IsValidForType;
+using internal::MakeCheckedNum;
+using internal::ValueOrDefaultForType;
+using internal::ValueOrDieForType;
} // namespace base
} // namespace pdfium
diff --git a/third_party/base/numerics/checked_math_impl.h b/third_party/base/numerics/checked_math_impl.h
index 3227817..e61053d 100644
--- a/third_party/base/numerics/checked_math_impl.h
+++ b/third_party/base/numerics/checked_math_impl.h
@@ -28,15 +28,17 @@
// it using the unsigned type of the same size.
using UnsignedDst = typename std::make_unsigned<T>::type;
using SignedDst = typename std::make_signed<T>::type;
- UnsignedDst ux = static_cast<UnsignedDst>(x);
- UnsignedDst uy = static_cast<UnsignedDst>(y);
- UnsignedDst uresult = static_cast<UnsignedDst>(ux + uy);
- *result = static_cast<T>(uresult);
+ const UnsignedDst ux = static_cast<UnsignedDst>(x);
+ const UnsignedDst uy = static_cast<UnsignedDst>(y);
+ const UnsignedDst uresult = static_cast<UnsignedDst>(ux + uy);
// Addition is valid if the sign of (x + y) is equal to either that of x or
// that of y.
- return (std::is_signed<T>::value)
- ? static_cast<SignedDst>((uresult ^ ux) & (uresult ^ uy)) >= 0
- : uresult >= uy; // Unsigned is either valid or underflow.
+ if (std::is_signed<T>::value
+ ? static_cast<SignedDst>((uresult ^ ux) & (uresult ^ uy)) < 0
+ : uresult < uy) // Unsigned is either valid or underflow.
+ return false;
+ *result = static_cast<T>(uresult);
+ return true;
}
template <typename T, typename U, class Enable = void>
@@ -50,8 +52,7 @@
using result_type = typename MaxExponentPromotion<T, U>::type;
template <typename V>
static constexpr bool Do(T x, U y, V* result) {
- // TODO(jschuh) Make this "constexpr if" once we're C++17.
- if (CheckedAddFastOp<T, U>::is_supported)
+ if constexpr (CheckedAddFastOp<T, U>::is_supported)
return CheckedAddFastOp<T, U>::Do(x, y, result);
// Double the underlying type up to a full machine word.
@@ -76,8 +77,10 @@
is_valid = CheckedAddImpl(static_cast<Promotion>(x),
static_cast<Promotion>(y), &presult);
}
+ if (!is_valid || !IsValueInRangeForNumericType<V>(presult))
+ return false;
*result = static_cast<V>(presult);
- return is_valid && IsValueInRangeForNumericType<V>(presult);
+ return true;
}
};
@@ -88,15 +91,17 @@
// it using the unsigned type of the same size.
using UnsignedDst = typename std::make_unsigned<T>::type;
using SignedDst = typename std::make_signed<T>::type;
- UnsignedDst ux = static_cast<UnsignedDst>(x);
- UnsignedDst uy = static_cast<UnsignedDst>(y);
- UnsignedDst uresult = static_cast<UnsignedDst>(ux - uy);
- *result = static_cast<T>(uresult);
+ const UnsignedDst ux = static_cast<UnsignedDst>(x);
+ const UnsignedDst uy = static_cast<UnsignedDst>(y);
+ const UnsignedDst uresult = static_cast<UnsignedDst>(ux - uy);
// Subtraction is valid if either x and y have same sign, or (x-y) and x have
// the same sign.
- return (std::is_signed<T>::value)
- ? static_cast<SignedDst>((uresult ^ ux) & (ux ^ uy)) >= 0
- : x >= y;
+ if (std::is_signed<T>::value
+ ? static_cast<SignedDst>((uresult ^ ux) & (ux ^ uy)) < 0
+ : x < y)
+ return false;
+ *result = static_cast<T>(uresult);
+ return true;
}
template <typename T, typename U, class Enable = void>
@@ -110,8 +115,7 @@
using result_type = typename MaxExponentPromotion<T, U>::type;
template <typename V>
static constexpr bool Do(T x, U y, V* result) {
- // TODO(jschuh) Make this "constexpr if" once we're C++17.
- if (CheckedSubFastOp<T, U>::is_supported)
+ if constexpr (CheckedSubFastOp<T, U>::is_supported)
return CheckedSubFastOp<T, U>::Do(x, y, result);
// Double the underlying type up to a full machine word.
@@ -136,8 +140,10 @@
is_valid = CheckedSubImpl(static_cast<Promotion>(x),
static_cast<Promotion>(y), &presult);
}
+ if (!is_valid || !IsValueInRangeForNumericType<V>(presult))
+ return false;
*result = static_cast<V>(presult);
- return is_valid && IsValueInRangeForNumericType<V>(presult);
+ return true;
}
};
@@ -150,15 +156,17 @@
using SignedDst = typename std::make_signed<T>::type;
const UnsignedDst ux = SafeUnsignedAbs(x);
const UnsignedDst uy = SafeUnsignedAbs(y);
- UnsignedDst uresult = static_cast<UnsignedDst>(ux * uy);
+ const UnsignedDst uresult = static_cast<UnsignedDst>(ux * uy);
const bool is_negative =
std::is_signed<T>::value && static_cast<SignedDst>(x ^ y) < 0;
- *result = is_negative ? 0 - uresult : uresult;
// We have a fast out for unsigned identity or zero on the second operand.
// After that it's an unsigned overflow check on the absolute value, with
// a +1 bound for a negative result.
- return uy <= UnsignedDst(!std::is_signed<T>::value || is_negative) ||
- ux <= (std::numeric_limits<T>::max() + UnsignedDst(is_negative)) / uy;
+ if (uy > UnsignedDst(!std::is_signed<T>::value || is_negative) &&
+ ux > (std::numeric_limits<T>::max() + UnsignedDst(is_negative)) / uy)
+ return false;
+ *result = is_negative ? 0 - uresult : uresult;
+ return true;
}
template <typename T, typename U, class Enable = void>
@@ -172,8 +180,7 @@
using result_type = typename MaxExponentPromotion<T, U>::type;
template <typename V>
static constexpr bool Do(T x, U y, V* result) {
- // TODO(jschuh) Make this "constexpr if" once we're C++17.
- if (CheckedMulFastOp<T, U>::is_supported)
+ if constexpr (CheckedMulFastOp<T, U>::is_supported)
return CheckedMulFastOp<T, U>::Do(x, y, result);
using Promotion = typename FastIntegerArithmeticPromotion<T, U>::type;
@@ -195,8 +202,10 @@
is_valid = CheckedMulImpl(static_cast<Promotion>(x),
static_cast<Promotion>(y), &presult);
}
+ if (!is_valid || !IsValueInRangeForNumericType<V>(presult))
+ return false;
*result = static_cast<V>(presult);
- return is_valid && IsValueInRangeForNumericType<V>(presult);
+ return true;
}
};
@@ -235,9 +244,11 @@
return false;
}
- Promotion presult = Promotion(x) / Promotion(y);
+ const Promotion presult = Promotion(x) / Promotion(y);
+ if (!IsValueInRangeForNumericType<V>(presult))
+ return false;
*result = static_cast<V>(presult);
- return IsValueInRangeForNumericType<V>(presult);
+ return true;
}
};
@@ -266,9 +277,12 @@
return true;
}
- Promotion presult = static_cast<Promotion>(x) % static_cast<Promotion>(y);
+ const Promotion presult =
+ static_cast<Promotion>(x) % static_cast<Promotion>(y);
+ if (!IsValueInRangeForNumericType<V>(presult))
+ return false;
*result = static_cast<Promotion>(presult);
- return IsValueInRangeForNumericType<V>(presult);
+ return true;
}
};
@@ -297,8 +311,11 @@
}
// Handle the legal corner-case of a full-width signed shift of zero.
- return std::is_signed<T>::value && !x &&
- as_unsigned(shift) == as_unsigned(std::numeric_limits<T>::digits);
+ if (!std::is_signed<T>::value || x ||
+ as_unsigned(shift) != as_unsigned(std::numeric_limits<T>::digits))
+ return false;
+ *result = 0;
+ return true;
}
};
@@ -315,15 +332,18 @@
std::is_integral<U>::value>::type> {
using result_type = T;
template <typename V>
- static bool Do(T x, U shift, V* result) {
- // Use the type conversion push negative values out of range.
- if (BASE_NUMERICS_LIKELY(as_unsigned(shift) <
- IntegerBitsPlusSign<T>::value)) {
- T tmp = x >> shift;
- *result = static_cast<V>(tmp);
- return IsValueInRangeForNumericType<V>(tmp);
+ static constexpr bool Do(T x, U shift, V* result) {
+ // Use sign conversion to push negative values out of range.
+ if (BASE_NUMERICS_UNLIKELY(as_unsigned(shift) >=
+ IntegerBitsPlusSign<T>::value)) {
+ return false;
}
- return false;
+
+ const T tmp = x >> shift;
+ if (!IsValueInRangeForNumericType<V>(tmp))
+ return false;
+ *result = static_cast<V>(tmp);
+ return true;
}
};
@@ -340,9 +360,12 @@
typename MaxExponentPromotion<T, U>::type>::type;
template <typename V>
static constexpr bool Do(T x, U y, V* result) {
- result_type tmp = static_cast<result_type>(x) & static_cast<result_type>(y);
+ const result_type tmp =
+ static_cast<result_type>(x) & static_cast<result_type>(y);
+ if (!IsValueInRangeForNumericType<V>(tmp))
+ return false;
*result = static_cast<V>(tmp);
- return IsValueInRangeForNumericType<V>(tmp);
+ return true;
}
};
@@ -359,9 +382,12 @@
typename MaxExponentPromotion<T, U>::type>::type;
template <typename V>
static constexpr bool Do(T x, U y, V* result) {
- result_type tmp = static_cast<result_type>(x) | static_cast<result_type>(y);
+ const result_type tmp =
+ static_cast<result_type>(x) | static_cast<result_type>(y);
+ if (!IsValueInRangeForNumericType<V>(tmp))
+ return false;
*result = static_cast<V>(tmp);
- return IsValueInRangeForNumericType<V>(tmp);
+ return true;
}
};
@@ -378,9 +404,12 @@
typename MaxExponentPromotion<T, U>::type>::type;
template <typename V>
static constexpr bool Do(T x, U y, V* result) {
- result_type tmp = static_cast<result_type>(x) ^ static_cast<result_type>(y);
+ const result_type tmp =
+ static_cast<result_type>(x) ^ static_cast<result_type>(y);
+ if (!IsValueInRangeForNumericType<V>(tmp))
+ return false;
*result = static_cast<V>(tmp);
- return IsValueInRangeForNumericType<V>(tmp);
+ return true;
}
};
@@ -398,10 +427,13 @@
using result_type = typename MaxExponentPromotion<T, U>::type;
template <typename V>
static constexpr bool Do(T x, U y, V* result) {
- result_type tmp = IsGreater<T, U>::Test(x, y) ? static_cast<result_type>(x)
- : static_cast<result_type>(y);
+ const result_type tmp = IsGreater<T, U>::Test(x, y)
+ ? static_cast<result_type>(x)
+ : static_cast<result_type>(y);
+ if (!IsValueInRangeForNumericType<V>(tmp))
+ return false;
*result = static_cast<V>(tmp);
- return IsValueInRangeForNumericType<V>(tmp);
+ return true;
}
};
@@ -419,10 +451,13 @@
using result_type = typename LowestValuePromotion<T, U>::type;
template <typename V>
static constexpr bool Do(T x, U y, V* result) {
- result_type tmp = IsLess<T, U>::Test(x, y) ? static_cast<result_type>(x)
- : static_cast<result_type>(y);
+ const result_type tmp = IsLess<T, U>::Test(x, y)
+ ? static_cast<result_type>(x)
+ : static_cast<result_type>(y);
+ if (!IsValueInRangeForNumericType<V>(tmp))
+ return false;
*result = static_cast<V>(tmp);
- return IsValueInRangeForNumericType<V>(tmp);
+ return true;
}
};
@@ -438,9 +473,11 @@
template <typename V> \
static constexpr bool Do(T x, U y, V* result) { \
using Promotion = typename MaxExponentPromotion<T, U>::type; \
- Promotion presult = x OP y; \
+ const Promotion presult = x OP y; \
+ if (!IsValueInRangeForNumericType<V>(presult)) \
+ return false; \
*result = static_cast<V>(presult); \
- return IsValueInRangeForNumericType<V>(presult); \
+ return true; \
} \
};
@@ -476,61 +513,67 @@
// Integrals require quite a bit of additional housekeeping to manage state.
template <typename T>
class CheckedNumericState<T, NUMERIC_INTEGER> {
- private:
- // is_valid_ precedes value_ because member intializers in the constructors
- // are evaluated in field order, and is_valid_ must be read when initializing
- // value_.
- bool is_valid_;
- T value_;
-
- // Ensures that a type conversion does not trigger undefined behavior.
- template <typename Src>
- static constexpr T WellDefinedConversionOrZero(const Src value,
- const bool is_valid) {
- using SrcType = typename internal::UnderlyingType<Src>::type;
- return (std::is_integral<SrcType>::value || is_valid)
- ? static_cast<T>(value)
- : static_cast<T>(0);
- }
-
public:
- template <typename Src, NumericRepresentation type>
- friend class CheckedNumericState;
-
- constexpr CheckedNumericState() : is_valid_(true), value_(0) {}
-
- template <typename Src>
- constexpr CheckedNumericState(Src value, bool is_valid)
+ template <typename Src = int>
+ constexpr explicit CheckedNumericState(Src value = 0, bool is_valid = true)
: is_valid_(is_valid && IsValueInRangeForNumericType<T>(value)),
value_(WellDefinedConversionOrZero(value, is_valid_)) {
static_assert(std::is_arithmetic<Src>::value, "Argument must be numeric.");
}
- // Copy constructor.
template <typename Src>
constexpr CheckedNumericState(const CheckedNumericState<Src>& rhs)
- : is_valid_(rhs.IsValid()),
- value_(WellDefinedConversionOrZero(rhs.value(), is_valid_)) {}
-
- template <typename Src>
- constexpr explicit CheckedNumericState(Src value)
- : is_valid_(IsValueInRangeForNumericType<T>(value)),
- value_(WellDefinedConversionOrZero(value, is_valid_)) {}
+ : CheckedNumericState(rhs.value(), rhs.is_valid()) {}
constexpr bool is_valid() const { return is_valid_; }
+
constexpr T value() const { return value_; }
+
+ private:
+ // Ensures that a type conversion does not trigger undefined behavior.
+ template <typename Src>
+ static constexpr T WellDefinedConversionOrZero(Src value, bool is_valid) {
+ using SrcType = typename internal::UnderlyingType<Src>::type;
+ return (std::is_integral<SrcType>::value || is_valid)
+ ? static_cast<T>(value)
+ : 0;
+ }
+
+ // is_valid_ precedes value_ because member initializers in the constructors
+ // are evaluated in field order, and is_valid_ must be read when initializing
+ // value_.
+ bool is_valid_;
+ T value_;
};
// Floating points maintain their own validity, but need translation wrappers.
template <typename T>
class CheckedNumericState<T, NUMERIC_FLOATING> {
- private:
- T value_;
+ public:
+ template <typename Src = double>
+ constexpr explicit CheckedNumericState(Src value = 0.0, bool is_valid = true)
+ : value_(WellDefinedConversionOrNaN(
+ value,
+ is_valid && IsValueInRangeForNumericType<T>(value))) {}
+ template <typename Src>
+ constexpr CheckedNumericState(const CheckedNumericState<Src>& rhs)
+ : CheckedNumericState(rhs.value(), rhs.is_valid()) {}
+
+ constexpr bool is_valid() const {
+ // Written this way because std::isfinite is not reliably constexpr.
+ return IsConstantEvaluated()
+ ? value_ <= std::numeric_limits<T>::max() &&
+ value_ >= std::numeric_limits<T>::lowest()
+ : std::isfinite(value_);
+ }
+
+ constexpr T value() const { return value_; }
+
+ private:
// Ensures that a type conversion does not trigger undefined behavior.
template <typename Src>
- static constexpr T WellDefinedConversionOrNaN(const Src value,
- const bool is_valid) {
+ static constexpr T WellDefinedConversionOrNaN(Src value, bool is_valid) {
using SrcType = typename internal::UnderlyingType<Src>::type;
return (StaticDstRangeRelationToSrcRange<T, SrcType>::value ==
NUMERIC_RANGE_CONTAINED ||
@@ -539,37 +582,7 @@
: std::numeric_limits<T>::quiet_NaN();
}
- public:
- template <typename Src, NumericRepresentation type>
- friend class CheckedNumericState;
-
- constexpr CheckedNumericState() : value_(0.0) {}
-
- template <typename Src>
- constexpr CheckedNumericState(Src value, bool is_valid)
- : value_(WellDefinedConversionOrNaN(value, is_valid)) {}
-
- template <typename Src>
- constexpr explicit CheckedNumericState(Src value)
- : value_(WellDefinedConversionOrNaN(
- value,
- IsValueInRangeForNumericType<T>(value))) {}
-
- // Copy constructor.
- template <typename Src>
- constexpr CheckedNumericState(const CheckedNumericState<Src>& rhs)
- : value_(WellDefinedConversionOrNaN(
- rhs.value(),
- rhs.is_valid() && IsValueInRangeForNumericType<T>(rhs.value()))) {}
-
- constexpr bool is_valid() const {
- // Written this way because std::isfinite is not reliably constexpr.
- return MustTreatAsConstexpr(value_)
- ? value_ <= std::numeric_limits<T>::max() &&
- value_ >= std::numeric_limits<T>::lowest()
- : std::isfinite(value_);
- }
- constexpr T value() const { return value_; }
+ T value_;
};
} // namespace internal
diff --git a/third_party/base/numerics/clamped_math.h b/third_party/base/numerics/clamped_math.h
index c2f25c5..ffa48f0 100644
--- a/third_party/base/numerics/clamped_math.h
+++ b/third_party/base/numerics/clamped_math.h
@@ -39,7 +39,7 @@
template <typename Src>
constexpr ClampedNumeric(Src value) // NOLINT(runtime/explicit)
: value_(saturated_cast<T>(value)) {
- static_assert(std::is_arithmetic<Src>::value, "Argument must be numeric.");
+ static_assert(UnderlyingType<Src>::is_numeric, "Argument must be numeric.");
}
// This is not an explicit constructor because we want a seamless conversion
@@ -179,14 +179,14 @@
// ClampedNumeric and POD arithmetic types.
template <typename Src>
struct Wrapper {
- static constexpr Src value(Src value) {
- return static_cast<typename UnderlyingType<Src>::type>(value);
+ static constexpr typename UnderlyingType<Src>::type value(Src value) {
+ return value;
}
};
};
-// Convience wrapper to return a new ClampedNumeric from the provided arithmetic
-// or ClampedNumericType.
+// Convenience wrapper to return a new ClampedNumeric from the provided
+// arithmetic or ClampedNumericType.
template <typename T>
constexpr ClampedNumeric<typename UnderlyingType<T>::type> MakeClampedNum(
const T value) {
@@ -210,8 +210,7 @@
typename L,
typename R,
typename... Args>
-constexpr ClampedNumeric<typename ResultType<M, L, R, Args...>::type>
-ClampMathOp(const L lhs, const R rhs, const Args... args) {
+constexpr auto ClampMathOp(const L lhs, const R rhs, const Args... args) {
return ClampMathOp<M>(ClampMathOp<M>(lhs, rhs), args...);
}
@@ -236,20 +235,20 @@
} // namespace internal
+using internal::ClampAdd;
+using internal::ClampAnd;
+using internal::ClampDiv;
using internal::ClampedNumeric;
-using internal::MakeClampedNum;
+using internal::ClampLsh;
using internal::ClampMax;
using internal::ClampMin;
-using internal::ClampAdd;
-using internal::ClampSub;
-using internal::ClampMul;
-using internal::ClampDiv;
using internal::ClampMod;
-using internal::ClampLsh;
-using internal::ClampRsh;
-using internal::ClampAnd;
+using internal::ClampMul;
using internal::ClampOr;
+using internal::ClampRsh;
+using internal::ClampSub;
using internal::ClampXor;
+using internal::MakeClampedNum;
} // namespace base
} // namespace pdfium
diff --git a/third_party/base/numerics/clamped_math_impl.h b/third_party/base/numerics/clamped_math_impl.h
index 9922051..10b097f 100644
--- a/third_party/base/numerics/clamped_math_impl.h
+++ b/third_party/base/numerics/clamped_math_impl.h
@@ -26,7 +26,7 @@
typename std::enable_if<std::is_integral<T>::value &&
std::is_signed<T>::value>::type* = nullptr>
constexpr T SaturatedNegWrapper(T value) {
- return MustTreatAsConstexpr(value) || !ClampedNegFastOp<T>::is_supported
+ return IsConstantEvaluated() || !ClampedNegFastOp<T>::is_supported
? (NegateWrapper(value) != std::numeric_limits<T>::lowest()
? NegateWrapper(value)
: std::numeric_limits<T>::max())
@@ -80,7 +80,7 @@
using result_type = typename MaxExponentPromotion<T, U>::type;
template <typename V = result_type>
static constexpr V Do(T x, U y) {
- if (ClampedAddFastOp<T, U>::is_supported)
+ if (!IsConstantEvaluated() && ClampedAddFastOp<T, U>::is_supported)
return ClampedAddFastOp<T, U>::template Do<V>(x, y);
static_assert(std::is_same<V, result_type>::value ||
@@ -106,8 +106,7 @@
using result_type = typename MaxExponentPromotion<T, U>::type;
template <typename V = result_type>
static constexpr V Do(T x, U y) {
- // TODO(jschuh) Make this "constexpr if" once we're C++17.
- if (ClampedSubFastOp<T, U>::is_supported)
+ if (!IsConstantEvaluated() && ClampedSubFastOp<T, U>::is_supported)
return ClampedSubFastOp<T, U>::template Do<V>(x, y);
static_assert(std::is_same<V, result_type>::value ||
@@ -133,8 +132,7 @@
using result_type = typename MaxExponentPromotion<T, U>::type;
template <typename V = result_type>
static constexpr V Do(T x, U y) {
- // TODO(jschuh) Make this "constexpr if" once we're C++17.
- if (ClampedMulFastOp<T, U>::is_supported)
+ if (!IsConstantEvaluated() && ClampedMulFastOp<T, U>::is_supported)
return ClampedMulFastOp<T, U>::template Do<V>(x, y);
V result = {};
diff --git a/third_party/base/numerics/safe_conversions.h b/third_party/base/numerics/safe_conversions.h
index 244f16c..bcc7ba8 100644
--- a/third_party/base/numerics/safe_conversions.h
+++ b/third_party/base/numerics/safe_conversions.h
@@ -7,18 +7,23 @@
#include <stddef.h>
+#include <cmath>
#include <limits>
#include <type_traits>
#include "third_party/base/numerics/safe_conversions_impl.h"
-#if !defined(__native_client__) && (defined(__ARMEL__) || defined(__arch64__))
+#if defined(__ARMEL__) && !defined(__native_client__)
#include "third_party/base/numerics/safe_conversions_arm_impl.h"
#define BASE_HAS_OPTIMIZED_SAFE_CONVERSIONS (1)
#else
#define BASE_HAS_OPTIMIZED_SAFE_CONVERSIONS (0)
#endif
+#if !BASE_NUMERICS_DISABLE_OSTREAM_OPERATORS
+#include <ostream>
+#endif
+
namespace pdfium {
namespace base {
namespace internal {
@@ -26,7 +31,7 @@
#if !BASE_HAS_OPTIMIZED_SAFE_CONVERSIONS
template <typename Dst, typename Src>
struct SaturateFastAsmOp {
- static const bool is_supported = false;
+ static constexpr bool is_supported = false;
static constexpr Dst Do(Src) {
// Force a compile failure if instantiated.
return CheckOnFailure::template HandleFailure<Dst>();
@@ -39,7 +44,7 @@
// eke out better performance than range checking.
template <typename Dst, typename Src, typename Enable = void>
struct IsValueInRangeFastOp {
- static const bool is_supported = false;
+ static constexpr bool is_supported = false;
static constexpr bool Do(Src value) {
// Force a compile failure if instantiated.
return CheckOnFailure::template HandleFailure<bool>();
@@ -55,7 +60,7 @@
std::is_integral<Dst>::value && std::is_integral<Src>::value &&
std::is_signed<Dst>::value && std::is_signed<Src>::value &&
!IsTypeInRangeForNumericType<Dst, Src>::value>::type> {
- static const bool is_supported = true;
+ static constexpr bool is_supported = true;
static constexpr bool Do(Src value) {
// Just downcast to the smaller type, sign extend it back to the original
@@ -73,7 +78,7 @@
std::is_integral<Dst>::value && std::is_integral<Src>::value &&
!std::is_signed<Dst>::value && std::is_signed<Src>::value &&
!IsTypeInRangeForNumericType<Dst, Src>::value>::type> {
- static const bool is_supported = true;
+ static constexpr bool is_supported = true;
static constexpr bool Do(Src value) {
// We cast a signed as unsigned to overflow negative values to the top,
@@ -152,7 +157,7 @@
// Arm, we can use the optimized saturation instructions.
template <typename Dst, typename Src, typename Enable = void>
struct SaturateFastOp {
- static const bool is_supported = false;
+ static constexpr bool is_supported = false;
static constexpr Dst Do(Src value) {
// Force a compile failure if instantiated.
return CheckOnFailure::template HandleFailure<Dst>();
@@ -166,8 +171,10 @@
typename std::enable_if<std::is_integral<Src>::value &&
std::is_integral<Dst>::value &&
SaturateFastAsmOp<Dst, Src>::is_supported>::type> {
- static const bool is_supported = true;
- static Dst Do(Src value) { return SaturateFastAsmOp<Dst, Src>::Do(value); }
+ static constexpr bool is_supported = true;
+ static constexpr Dst Do(Src value) {
+ return SaturateFastAsmOp<Dst, Src>::Do(value);
+ }
};
template <typename Dst, typename Src>
@@ -177,12 +184,12 @@
typename std::enable_if<std::is_integral<Src>::value &&
std::is_integral<Dst>::value &&
!SaturateFastAsmOp<Dst, Src>::is_supported>::type> {
- static const bool is_supported = true;
- static Dst Do(Src value) {
+ static constexpr bool is_supported = true;
+ static constexpr Dst Do(Src value) {
// The exact order of the following is structured to hit the correct
// optimization heuristics across compilers. Do not change without
// checking the emitted code.
- Dst saturated = CommonMaxOrMin<Dst, Src>(
+ const Dst saturated = CommonMaxOrMin<Dst, Src>(
IsMaxInRangeForNumericType<Dst, Src>() ||
(!IsMinInRangeForNumericType<Dst, Src>() && IsValueNegative(value)));
return BASE_NUMERICS_LIKELY(IsValueInRangeForNumericType<Dst>(value))
@@ -194,14 +201,13 @@
// saturated_cast<> is analogous to static_cast<> for numeric types, except
// that the specified numeric conversion will saturate by default rather than
// overflow or underflow, and NaN assignment to an integral will return 0.
-// All boundary condition behaviors can be overriden with a custom handler.
+// All boundary condition behaviors can be overridden with a custom handler.
template <typename Dst,
template <typename> class SaturationHandler = SaturationDefaultLimits,
typename Src>
constexpr Dst saturated_cast(Src value) {
using SrcType = typename UnderlyingType<Src>::type;
- return !IsCompileTimeConstant(value) &&
- SaturateFastOp<Dst, SrcType>::is_supported &&
+ return !IsConstantEvaluated() && SaturateFastOp<Dst, SrcType>::is_supported &&
std::is_same<SaturationHandler<Dst>,
SaturationDefaultLimits<Dst>>::value
? SaturateFastOp<Dst, SrcType>::Do(static_cast<SrcType>(value))
@@ -237,7 +243,7 @@
// Some wrappers to statically check that a type is in range.
template <typename Dst, typename Src, class Enable = void>
struct IsNumericRangeContained {
- static const bool value = false;
+ static constexpr bool value = false;
};
template <typename Dst, typename Src>
@@ -246,8 +252,9 @@
Src,
typename std::enable_if<ArithmeticOrUnderlyingEnum<Dst>::value &&
ArithmeticOrUnderlyingEnum<Src>::value>::type> {
- static const bool value = StaticDstRangeRelationToSrcRange<Dst, Src>::value ==
- NUMERIC_RANGE_CONTAINED;
+ static constexpr bool value =
+ StaticDstRangeRelationToSrcRange<Dst, Src>::value ==
+ NUMERIC_RANGE_CONTAINED;
};
// StrictNumeric implements compile time range checking between numeric types by
@@ -301,7 +308,8 @@
const T value_;
};
-// Convience wrapper returns a StrictNumeric from the provided arithmetic type.
+// Convenience wrapper returns a StrictNumeric from the provided arithmetic
+// type.
template <typename T>
constexpr StrictNumeric<typename UnderlyingType<T>::type> MakeStrictNum(
const T value) {
@@ -329,18 +337,45 @@
using internal::as_signed;
using internal::as_unsigned;
using internal::checked_cast;
-using internal::strict_cast;
-using internal::saturated_cast;
-using internal::SafeUnsignedAbs;
-using internal::StrictNumeric;
-using internal::MakeStrictNum;
-using internal::IsValueInRangeForNumericType;
using internal::IsTypeInRangeForNumericType;
+using internal::IsValueInRangeForNumericType;
using internal::IsValueNegative;
+using internal::MakeStrictNum;
+using internal::SafeUnsignedAbs;
+using internal::saturated_cast;
+using internal::strict_cast;
+using internal::StrictNumeric;
// Explicitly make a shorter size_t alias for convenience.
using SizeT = StrictNumeric<size_t>;
+// floating -> integral conversions that saturate and thus can actually return
+// an integral type. In most cases, these should be preferred over the std::
+// versions.
+template <typename Dst = int,
+ typename Src,
+ typename = std::enable_if_t<std::is_integral<Dst>::value &&
+ std::is_floating_point<Src>::value>>
+Dst ClampFloor(Src value) {
+ return saturated_cast<Dst>(std::floor(value));
+}
+template <typename Dst = int,
+ typename Src,
+ typename = std::enable_if_t<std::is_integral<Dst>::value &&
+ std::is_floating_point<Src>::value>>
+Dst ClampCeil(Src value) {
+ return saturated_cast<Dst>(std::ceil(value));
+}
+template <typename Dst = int,
+ typename Src,
+ typename = std::enable_if_t<std::is_integral<Dst>::value &&
+ std::is_floating_point<Src>::value>>
+Dst ClampRound(Src value) {
+ const Src rounded =
+ (value >= 0.0f) ? std::floor(value + 0.5f) : std::ceil(value - 0.5f);
+ return saturated_cast<Dst>(rounded);
+}
+
} // namespace base
} // namespace pdfium
diff --git a/third_party/base/numerics/safe_conversions_arm_impl.h b/third_party/base/numerics/safe_conversions_arm_impl.h
index f5e4c4e..426118a 100644
--- a/third_party/base/numerics/safe_conversions_arm_impl.h
+++ b/third_party/base/numerics/safe_conversions_arm_impl.h
@@ -19,8 +19,8 @@
template <typename Dst, typename Src>
struct SaturateFastAsmOp {
static constexpr bool is_supported =
- std::is_signed<Src>::value && std::is_integral<Dst>::value &&
- std::is_integral<Src>::value &&
+ kEnableAsmCode && std::is_signed<Src>::value &&
+ std::is_integral<Dst>::value && std::is_integral<Src>::value &&
IntegerBitsPlusSign<Src>::value <= IntegerBitsPlusSign<int32_t>::value &&
IntegerBitsPlusSign<Dst>::value <= IntegerBitsPlusSign<int32_t>::value &&
!IsTypeInRangeForNumericType<Dst, Src>::value;
diff --git a/third_party/base/numerics/safe_conversions_impl.h b/third_party/base/numerics/safe_conversions_impl.h
index 116190d..4d8a7b7 100644
--- a/third_party/base/numerics/safe_conversions_impl.h
+++ b/third_party/base/numerics/safe_conversions_impl.h
@@ -86,30 +86,18 @@
: static_cast<UnsignedT>(value);
}
-// This allows us to switch paths on known compile-time constants.
-#if defined(__clang__) || defined(__GNUC__)
-constexpr bool CanDetectCompileTimeConstant() {
- return true;
-}
-template <typename T>
-constexpr bool IsCompileTimeConstant(const T v) {
- return __builtin_constant_p(v);
-}
+// TODO(jschuh): Switch to std::is_constant_evaluated() once C++20 is supported.
+// Alternately, the usage could be restructured for "consteval if" in C++23.
+#define IsConstantEvaluated() (__builtin_is_constant_evaluated())
+
+// TODO(jschuh): Debug builds don't reliably propagate constants, so we restrict
+// some accelerated runtime paths to release builds until this can be forced
+// with consteval support in C++20 or C++23.
+#if defined(NDEBUG)
+constexpr bool kEnableAsmCode = true;
#else
-constexpr bool CanDetectCompileTimeConstant() {
- return false;
-}
-template <typename T>
-constexpr bool IsCompileTimeConstant(const T) {
- return false;
-}
+constexpr bool kEnableAsmCode = false;
#endif
-template <typename T>
-constexpr bool MustTreatAsConstexpr(const T v) {
- // Either we can't detect a compile-time constant, and must always use the
- // constexpr path, or we know we have a compile-time constant.
- return !CanDetectCompileTimeConstant() || IsCompileTimeConstant(v);
-}
// Forces a crash, like a CHECK(false). Used for numeric boundary errors.
// Also used in a constexpr template to trigger a compilation failure on
@@ -194,7 +182,7 @@
public:
constexpr RangeCheck(bool is_in_lower_bound, bool is_in_upper_bound)
: is_underflow_(!is_in_lower_bound), is_overflow_(!is_in_upper_bound) {}
- constexpr RangeCheck() : is_underflow_(0), is_overflow_(0) {}
+ constexpr RangeCheck() : is_underflow_(false), is_overflow_(false) {}
constexpr bool IsValid() const { return !is_overflow_ && !is_underflow_; }
constexpr bool IsInvalid() const { return is_overflow_ && is_underflow_; }
constexpr bool IsOverflow() const { return is_overflow_ && !is_underflow_; }
@@ -277,7 +265,8 @@
template <typename Dst,
typename Src,
- template <typename> class Bounds,
+ template <typename>
+ class Bounds,
IntegerRepresentation DstSign = std::is_signed<Dst>::value
? INTEGER_REPRESENTATION_SIGNED
: INTEGER_REPRESENTATION_UNSIGNED,
@@ -295,7 +284,8 @@
// Same sign narrowing: The range is contained for normal limits.
template <typename Dst,
typename Src,
- template <typename> class Bounds,
+ template <typename>
+ class Bounds,
IntegerRepresentation DstSign,
IntegerRepresentation SrcSign>
struct DstRangeRelationToSrcRangeImpl<Dst,
@@ -379,9 +369,17 @@
using SrcLimits = std::numeric_limits<Src>;
using DstLimits = NarrowingRange<Dst, Src, Bounds>;
using Promotion = decltype(Src() + Dst());
+ bool ge_zero = false;
+ // Converting floating-point to integer will discard fractional part, so
+ // values in (-1.0, -0.0) will truncate to 0 and fit in Dst.
+ if (std::is_floating_point<Src>::value) {
+ ge_zero = value > Src(-1);
+ } else {
+ ge_zero = value >= Src(0);
+ }
return RangeCheck(
- value >= Src(0) && (DstLimits::lowest() == 0 ||
- static_cast<Dst>(value) >= DstLimits::lowest()),
+ ge_zero && (DstLimits::lowest() == 0 ||
+ static_cast<Dst>(value) >= DstLimits::lowest()),
static_cast<Promotion>(SrcLimits::max()) <=
static_cast<Promotion>(DstLimits::max()) ||
static_cast<Promotion>(value) <=
@@ -693,9 +691,8 @@
const RangeCheck l_range,
const RangeCheck r_range) {
return l_range.IsUnderflow() || r_range.IsOverflow() ||
- (l_range == r_range &&
- static_cast<decltype(lhs + rhs)>(lhs) <
- static_cast<decltype(lhs + rhs)>(rhs));
+ (l_range == r_range && static_cast<decltype(lhs + rhs)>(lhs) <
+ static_cast<decltype(lhs + rhs)>(rhs));
}
template <typename L, typename R>
@@ -714,9 +711,8 @@
const RangeCheck l_range,
const RangeCheck r_range) {
return l_range.IsUnderflow() || r_range.IsOverflow() ||
- (l_range == r_range &&
- static_cast<decltype(lhs + rhs)>(lhs) <=
- static_cast<decltype(lhs + rhs)>(rhs));
+ (l_range == r_range && static_cast<decltype(lhs + rhs)>(lhs) <=
+ static_cast<decltype(lhs + rhs)>(rhs));
}
template <typename L, typename R>
@@ -735,9 +731,8 @@
const RangeCheck l_range,
const RangeCheck r_range) {
return l_range.IsOverflow() || r_range.IsUnderflow() ||
- (l_range == r_range &&
- static_cast<decltype(lhs + rhs)>(lhs) >
- static_cast<decltype(lhs + rhs)>(rhs));
+ (l_range == r_range && static_cast<decltype(lhs + rhs)>(lhs) >
+ static_cast<decltype(lhs + rhs)>(rhs));
}
template <typename L, typename R>
@@ -756,9 +751,8 @@
const RangeCheck l_range,
const RangeCheck r_range) {
return l_range.IsOverflow() || r_range.IsUnderflow() ||
- (l_range == r_range &&
- static_cast<decltype(lhs + rhs)>(lhs) >=
- static_cast<decltype(lhs + rhs)>(rhs));
+ (l_range == r_range && static_cast<decltype(lhs + rhs)>(lhs) >=
+ static_cast<decltype(lhs + rhs)>(rhs));
}
template <typename L, typename R>
diff --git a/third_party/base/numerics/safe_math_arm_impl.h b/third_party/base/numerics/safe_math_arm_impl.h
index 3291e74..cea9632 100644
--- a/third_party/base/numerics/safe_math_arm_impl.h
+++ b/third_party/base/numerics/safe_math_arm_impl.h
@@ -6,7 +6,6 @@
#define THIRD_PARTY_BASE_NUMERICS_SAFE_MATH_ARM_IMPL_H_
#include <cassert>
-#include <limits>
#include <type_traits>
#include "third_party/base/numerics/safe_conversions.h"
@@ -18,9 +17,10 @@
template <typename T, typename U>
struct CheckedMulFastAsmOp {
static const bool is_supported =
- FastIntegerArithmeticPromotion<T, U>::is_contained;
+ kEnableAsmCode && FastIntegerArithmeticPromotion<T, U>::is_contained;
- // The following is much more efficient than the Clang and GCC builtins for
+ // The following is not an assembler routine and is thus constexpr safe, it
+ // just emits much more efficient code than the Clang and GCC builtins for
// performing overflow-checked multiplication when a twice wider type is
// available. The below compiles down to 2-3 instructions, depending on the
// width of the types in use.
@@ -32,20 +32,22 @@
// asr r2, r1, #16
// cmp r2, r1, asr #15
template <typename V>
- __attribute__((always_inline)) static bool Do(T x, U y, V* result) {
+ static constexpr bool Do(T x, U y, V* result) {
using Promotion = typename FastIntegerArithmeticPromotion<T, U>::type;
Promotion presult;
presult = static_cast<Promotion>(x) * static_cast<Promotion>(y);
+ if (!IsValueInRangeForNumericType<V>(presult))
+ return false;
*result = static_cast<V>(presult);
- return IsValueInRangeForNumericType<V>(presult);
+ return true;
}
};
template <typename T, typename U>
struct ClampedAddFastAsmOp {
static const bool is_supported =
- BigEnoughPromotion<T, U>::is_contained &&
+ kEnableAsmCode && BigEnoughPromotion<T, U>::is_contained &&
IsTypeInRangeForNumericType<
int32_t,
typename BigEnoughPromotion<T, U>::type>::value;
@@ -71,7 +73,7 @@
template <typename T, typename U>
struct ClampedSubFastAsmOp {
static const bool is_supported =
- BigEnoughPromotion<T, U>::is_contained &&
+ kEnableAsmCode && BigEnoughPromotion<T, U>::is_contained &&
IsTypeInRangeForNumericType<
int32_t,
typename BigEnoughPromotion<T, U>::type>::value;
@@ -96,7 +98,8 @@
template <typename T, typename U>
struct ClampedMulFastAsmOp {
- static const bool is_supported = CheckedMulFastAsmOp<T, U>::is_supported;
+ static const bool is_supported =
+ kEnableAsmCode && CheckedMulFastAsmOp<T, U>::is_supported;
template <typename V>
__attribute__((always_inline)) static V Do(T x, U y) {
@@ -105,9 +108,9 @@
if (!IsIntegerArithmeticSafe<int32_t, T, U>::value &&
!IsIntegerArithmeticSafe<uint32_t, T, U>::value) {
V result;
- if (CheckedMulFastAsmOp<T, U>::Do(x, y, &result))
- return result;
- return CommonMaxOrMin<V>(IsValueNegative(x) ^ IsValueNegative(y));
+ return CheckedMulFastAsmOp<T, U>::Do(x, y, &result)
+ ? result
+ : CommonMaxOrMin<V>(IsValueNegative(x) ^ IsValueNegative(y));
}
assert((FastIntegerArithmeticPromotion<T, U>::is_contained));
diff --git a/third_party/base/numerics/safe_math_shared_impl.h b/third_party/base/numerics/safe_math_shared_impl.h
index 8c06882..871906d 100644
--- a/third_party/base/numerics/safe_math_shared_impl.h
+++ b/third_party/base/numerics/safe_math_shared_impl.h
@@ -15,17 +15,18 @@
#include <limits>
#include <type_traits>
+#include "build/build_config.h"
#include "third_party/base/numerics/safe_conversions.h"
-#ifdef __asmjs__
+#if BUILDFLAG(IS_ASMJS)
// Optimized safe math instructions are incompatible with asmjs.
#define BASE_HAS_OPTIMIZED_SAFE_MATH (0)
// Where available use builtin math overflow support on Clang and GCC.
-#elif !defined(__native_client__) && \
- ((defined(__clang__) && \
- ((__clang_major__ > 3) || \
- (__clang_major__ == 3 && __clang_minor__ >= 4))) || \
- (defined(__GNUC__) && __GNUC__ >= 5))
+#elif !defined(__native_client__) && \
+ ((defined(__clang__) && \
+ ((__clang_major__ > 3) || \
+ (__clang_major__ == 3 && __clang_minor__ >= 4))) || \
+ (defined(__GNUC__) && __GNUC__ >= 5))
#include "third_party/base/numerics/safe_math_clang_gcc_impl.h"
#define BASE_HAS_OPTIMIZED_SAFE_MATH (1)
#else
@@ -132,7 +133,7 @@
// Wrap the unary operations to allow SFINAE when instantiating integrals versus
// floating points. These don't perform any overflow checking. Rather, they
// exhibit well-defined overflow semantics and rely on the caller to detect
-// if an overflow occured.
+// if an overflow occurred.
template <typename T,
typename std::enable_if<std::is_integral<T>::value>::type* = nullptr>
@@ -178,38 +179,13 @@
using type = typename math::result_type;
};
-// These variadic templates work out the return types.
-// TODO(jschuh): Rip all this out once we have C++14 non-trailing auto support.
-template <template <typename, typename, typename> class M,
- typename L,
- typename R,
- typename... Args>
-struct ResultType;
-
-template <template <typename, typename, typename> class M,
- typename L,
- typename R>
-struct ResultType<M, L, R> {
- using type = typename MathWrapper<M, L, R>::type;
-};
-
-template <template <typename, typename, typename> class M,
- typename L,
- typename R,
- typename... Args>
-struct ResultType {
- using type =
- typename ResultType<M, typename ResultType<M, L, R>::type, Args...>::type;
-};
-
// The following macros are just boilerplate for the standard arithmetic
// operator overloads and variadic function templates. A macro isn't the nicest
// solution, but it beats rewriting these over and over again.
#define BASE_NUMERIC_ARITHMETIC_VARIADIC(CLASS, CL_ABBR, OP_NAME) \
template <typename L, typename R, typename... Args> \
- constexpr CLASS##Numeric< \
- typename ResultType<CLASS##OP_NAME##Op, L, R, Args...>::type> \
- CL_ABBR##OP_NAME(const L lhs, const R rhs, const Args... args) { \
+ constexpr auto CL_ABBR##OP_NAME(const L lhs, const R rhs, \
+ const Args... args) { \
return CL_ABBR##MathOp<CLASS##OP_NAME##Op, L, R, Args...>(lhs, rhs, \
args...); \
}