Update third_party/base/numerics/safe_conversions code.
Use Chromium's version from r664400. Pick up lots of improvements. e.g.
https://crrev.com/486515
https://crrev.com/490852
https://crrev.com/618634
Also fix up header guards in third_party/base for consistency.
Change-Id: Ieab5a2bdffee29d57c5cb02495bc60a00e741664
Reviewed-on: https://pdfium-review.googlesource.com/c/pdfium/+/55192
Commit-Queue: Lei Zhang <thestig@chromium.org>
Reviewed-by: Tom Sepez <tsepez@chromium.org>
diff --git a/third_party/BUILD.gn b/third_party/BUILD.gn
index 3863ad2..5ef2987 100644
--- a/third_party/BUILD.gn
+++ b/third_party/BUILD.gn
@@ -625,6 +625,7 @@
"base/debug/alias.h",
"base/logging.h",
"base/numerics/safe_conversions.h",
+ "base/numerics/safe_conversions_arm_impl.h",
"base/numerics/safe_conversions_impl.h",
"base/numerics/safe_math.h",
"base/numerics/safe_math_impl.h",
diff --git a/third_party/base/debug/alias.h b/third_party/base/debug/alias.h
index 4fac666..8228a6f 100644
--- a/third_party/base/debug/alias.h
+++ b/third_party/base/debug/alias.h
@@ -2,8 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#ifndef PDFIUM_THIRD_PARTY_BASE_DEBUG_ALIAS_H_
-#define PDFIUM_THIRD_PARTY_BASE_DEBUG_ALIAS_H_
+#ifndef THIRD_PARTY_BASE_DEBUG_ALIAS_H_
+#define THIRD_PARTY_BASE_DEBUG_ALIAS_H_
namespace pdfium {
namespace base {
@@ -31,4 +31,4 @@
} // namespace base
} // namespace pdfium
-#endif // PDFIUM_THIRD_PARTY_BASE_DEBUG_ALIAS_H_
+#endif // THIRD_PARTY_BASE_DEBUG_ALIAS_H_
diff --git a/third_party/base/numerics/safe_conversions.h b/third_party/base/numerics/safe_conversions.h
index 6885b79..bb18562 100644
--- a/third_party/base/numerics/safe_conversions.h
+++ b/third_party/base/numerics/safe_conversions.h
@@ -2,8 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#ifndef PDFIUM_THIRD_PARTY_BASE_NUMERICS_SAFE_CONVERSIONS_H_
-#define PDFIUM_THIRD_PARTY_BASE_NUMERICS_SAFE_CONVERSIONS_H_
+#ifndef THIRD_PARTY_BASE_NUMERICS_SAFE_CONVERSIONS_H_
+#define THIRD_PARTY_BASE_NUMERICS_SAFE_CONVERSIONS_H_
#include <stddef.h>
@@ -13,89 +13,121 @@
#include "third_party/base/numerics/safe_conversions_impl.h"
+#if defined(__ARMEL__) || defined(__arch64__)
+#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
+
namespace pdfium {
namespace base {
+namespace internal {
-// The following are helper constexpr template functions and classes for safely
-// performing a range of conversions, assignments, and tests:
-//
-// checked_cast<> - Analogous to static_cast<> for numeric types, except
-// that it CHECKs that the specified numeric conversion will not overflow
-// or underflow. NaN source will always trigger a CHECK.
-// The default CHECK triggers a crash, but the handler can be overriden.
-// saturated_cast<> - Analogous to static_cast<> for numeric types, except
-// that it returns a saturated result when the specified numeric conversion
-// would otherwise overflow or underflow. An NaN source returns 0 by
-// default, but can be overridden to return a different result.
-// strict_cast<> - Analogous to static_cast<> for numeric types, except that
-// it will cause a compile failure if the destination type is not large
-// enough to contain any value in the source type. It performs no runtime
-// checking and thus introduces no runtime overhead.
-// IsValueInRangeForNumericType<>() - A convenience function that returns true
-// if the type supplied to the template parameter can represent the value
-// passed as an argument to the function.
-// IsValueNegative<>() - A convenience function that will accept any arithmetic
-// type as an argument and will return whether the value is less than zero.
-// Unsigned types always return false.
-// SafeUnsignedAbs() - Returns the absolute value of the supplied integer
-// parameter as an unsigned result (thus avoiding an overflow if the value
-// is the signed, two's complement minimum).
-// StrictNumeric<> - A wrapper type that performs assignments and copies via
-// the strict_cast<> template, and can perform valid arithmetic comparisons
-// across any range of arithmetic types. StrictNumeric is the return type
-// for values extracted from a CheckedNumeric class instance. The raw
-// arithmetic value is extracted via static_cast to the underlying type.
-// MakeStrictNum() - Creates a new StrictNumeric from the underlying type of
-// the supplied arithmetic or StrictNumeric type.
+#if !BASE_HAS_OPTIMIZED_SAFE_CONVERSIONS
+template <typename Dst, typename Src>
+struct SaturateFastAsmOp {
+ static const bool is_supported = false;
+ static constexpr Dst Do(Src) {
+ // Force a compile failure if instantiated.
+ return CheckOnFailure::template HandleFailure<Dst>();
+ }
+};
+#endif // BASE_HAS_OPTIMIZED_SAFE_CONVERSIONS
+#undef BASE_HAS_OPTIMIZED_SAFE_CONVERSIONS
+
+// The following special case a few specific integer conversions where we can
+// 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 Do(Src value) {
+ // Force a compile failure if instantiated.
+ return CheckOnFailure::template HandleFailure<bool>();
+ }
+};
+
+// Signed to signed range comparison.
+template <typename Dst, typename Src>
+struct IsValueInRangeFastOp<
+ Dst,
+ Src,
+ typename std::enable_if<
+ 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 Do(Src value) {
+ // Just downcast to the smaller type, sign extend it back to the original
+ // type, and then see if it matches the original value.
+ return value == static_cast<Dst>(value);
+ }
+};
+
+// Signed to unsigned range comparison.
+template <typename Dst, typename Src>
+struct IsValueInRangeFastOp<
+ Dst,
+ Src,
+ typename std::enable_if<
+ 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 Do(Src value) {
+ // We cast a signed as unsigned to overflow negative values to the top,
+ // then compare against whichever maximum is smaller, as our upper bound.
+ return as_unsigned(value) <= as_unsigned(CommonMax<Src, Dst>());
+ }
+};
// Convenience function that returns true if the supplied value is in range
// for the destination type.
template <typename Dst, typename Src>
constexpr bool IsValueInRangeForNumericType(Src value) {
- return internal::DstRangeRelationToSrcRange<Dst>(value).IsValid();
+ using SrcType = typename internal::UnderlyingType<Src>::type;
+ return internal::IsValueInRangeFastOp<Dst, SrcType>::is_supported
+ ? internal::IsValueInRangeFastOp<Dst, SrcType>::Do(
+ static_cast<SrcType>(value))
+ : internal::DstRangeRelationToSrcRange<Dst>(
+ static_cast<SrcType>(value))
+ .IsValid();
}
-// Forces a crash, like a CHECK(false). Used for numeric boundary errors.
-struct CheckOnFailure {
- template <typename T>
- static T HandleFailure() {
-#if defined(__GNUC__) || defined(__clang__)
- __builtin_trap();
-#else
- ((void)(*(volatile char*)0 = 0));
-#endif
- return T();
- }
-};
-
// checked_cast<> is analogous to static_cast<> for numeric types,
// except that it CHECKs that the specified numeric conversion will not
// overflow or underflow. NaN source will always trigger a CHECK.
-template <typename Dst, class CheckHandler = CheckOnFailure, typename Src>
+template <typename Dst,
+ class CheckHandler = internal::CheckOnFailure,
+ typename Src>
constexpr Dst checked_cast(Src value) {
// This throws a compile-time error on evaluating the constexpr if it can be
// determined at compile-time as failing, otherwise it will CHECK at runtime.
using SrcType = typename internal::UnderlyingType<Src>::type;
- return IsValueInRangeForNumericType<Dst, SrcType>(value)
+ return BASE_NUMERICS_LIKELY((IsValueInRangeForNumericType<Dst>(value)))
? static_cast<Dst>(static_cast<SrcType>(value))
: CheckHandler::template HandleFailure<Dst>();
}
// Default boundaries for integral/float: max/infinity, lowest/-infinity, 0/NaN.
+// You may provide your own limits (e.g. to saturated_cast) so long as you
+// implement all of the static constexpr member functions in the class below.
template <typename T>
-struct SaturationDefaultHandler {
+struct SaturationDefaultLimits : public std::numeric_limits<T> {
static constexpr T NaN() {
return std::numeric_limits<T>::has_quiet_NaN
? std::numeric_limits<T>::quiet_NaN()
: T();
}
- static constexpr T max() { return std::numeric_limits<T>::max(); }
+ using std::numeric_limits<T>::max;
static constexpr T Overflow() {
return std::numeric_limits<T>::has_infinity
? std::numeric_limits<T>::infinity()
: std::numeric_limits<T>::max();
}
- static constexpr T lowest() { return std::numeric_limits<T>::lowest(); }
+ using std::numeric_limits<T>::lowest;
static constexpr T Underflow() {
return std::numeric_limits<T>::has_infinity
? std::numeric_limits<T>::infinity() * -1
@@ -103,8 +135,6 @@
}
};
-namespace internal {
-
template <typename Dst, template <typename> class S, typename Src>
constexpr Dst saturated_cast_impl(Src value, RangeCheck constraint) {
// For some reason clang generates much better code when the branch is
@@ -118,19 +148,68 @@
: S<Dst>::NaN());
}
+// We can reduce the number of conditions and get slightly better performance
+// for normal signed and unsigned integer ranges. And in the specific case of
+// 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 Dst Do(Src value) {
+ // Force a compile failure if instantiated.
+ return CheckOnFailure::template HandleFailure<Dst>();
+ }
+};
+
+template <typename Dst, typename Src>
+struct SaturateFastOp<
+ Dst,
+ Src,
+ 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); }
+};
+
+template <typename Dst, typename Src>
+struct SaturateFastOp<
+ Dst,
+ Src,
+ 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) {
+ // 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>(
+ IsMaxInRangeForNumericType<Dst, Src>() ||
+ (!IsMinInRangeForNumericType<Dst, Src>() && IsValueNegative(value)));
+ return BASE_NUMERICS_LIKELY(IsValueInRangeForNumericType<Dst>(value))
+ ? static_cast<Dst>(value)
+ : saturated;
+ }
+};
+
// 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.
template <typename Dst,
- template <typename>
- class SaturationHandler = SaturationDefaultHandler,
+ template <typename> class SaturationHandler = SaturationDefaultLimits,
typename Src>
constexpr Dst saturated_cast(Src value) {
using SrcType = typename UnderlyingType<Src>::type;
- return saturated_cast_impl<Dst, SaturationHandler, SrcType>(
- value,
- DstRangeRelationToSrcRange<Dst, SaturationHandler, SrcType>(value));
+ return !IsCompileTimeConstant(value) &&
+ SaturateFastOp<Dst, SrcType>::is_supported &&
+ std::is_same<SaturationHandler<Dst>,
+ SaturationDefaultLimits<Dst>>::value
+ ? SaturateFastOp<Dst, SrcType>::Do(static_cast<SrcType>(value))
+ : saturated_cast_impl<Dst, SaturationHandler, SrcType>(
+ static_cast<SrcType>(value),
+ DstRangeRelationToSrcRange<Dst, SaturationHandler, SrcType>(
+ static_cast<SrcType>(value)));
}
// strict_cast<> is analogous to static_cast<> for numeric types, except that
@@ -237,30 +316,34 @@
return os;
}
-#define STRICT_COMPARISON_OP(NAME, OP) \
- template <typename L, typename R, \
- typename std::enable_if< \
- internal::IsStrictOp<L, R>::value>::type* = nullptr> \
- constexpr bool operator OP(const L lhs, const R rhs) { \
- return SafeCompare<NAME, typename UnderlyingType<L>::type, \
- typename UnderlyingType<R>::type>(lhs, rhs); \
+#define BASE_NUMERIC_COMPARISON_OPERATORS(CLASS, NAME, OP) \
+ template <typename L, typename R, \
+ typename std::enable_if< \
+ internal::Is##CLASS##Op<L, R>::value>::type* = nullptr> \
+ constexpr bool operator OP(const L lhs, const R rhs) { \
+ return SafeCompare<NAME, typename UnderlyingType<L>::type, \
+ typename UnderlyingType<R>::type>(lhs, rhs); \
}
-STRICT_COMPARISON_OP(IsLess, <)
-STRICT_COMPARISON_OP(IsLessOrEqual, <=)
-STRICT_COMPARISON_OP(IsGreater, >)
-STRICT_COMPARISON_OP(IsGreaterOrEqual, >=)
-STRICT_COMPARISON_OP(IsEqual, ==)
-STRICT_COMPARISON_OP(IsNotEqual, !=)
+BASE_NUMERIC_COMPARISON_OPERATORS(Strict, IsLess, <)
+BASE_NUMERIC_COMPARISON_OPERATORS(Strict, IsLessOrEqual, <=)
+BASE_NUMERIC_COMPARISON_OPERATORS(Strict, IsGreater, >)
+BASE_NUMERIC_COMPARISON_OPERATORS(Strict, IsGreaterOrEqual, >=)
+BASE_NUMERIC_COMPARISON_OPERATORS(Strict, IsEqual, ==)
+BASE_NUMERIC_COMPARISON_OPERATORS(Strict, IsNotEqual, !=)
-#undef STRICT_COMPARISON_OP
} // namespace internal
+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::IsValueNegative;
// Explicitly make a shorter size_t alias for convenience.
@@ -269,4 +352,4 @@
} // namespace base
} // namespace pdfium
-#endif // PDFIUM_THIRD_PARTY_BASE_NUMERICS_SAFE_CONVERSIONS_H_
+#endif // THIRD_PARTY_BASE_NUMERICS_SAFE_CONVERSIONS_H_
diff --git a/third_party/base/numerics/safe_conversions_arm_impl.h b/third_party/base/numerics/safe_conversions_arm_impl.h
new file mode 100644
index 0000000..f5e4c4e
--- /dev/null
+++ b/third_party/base/numerics/safe_conversions_arm_impl.h
@@ -0,0 +1,53 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_BASE_NUMERICS_SAFE_CONVERSIONS_ARM_IMPL_H_
+#define THIRD_PARTY_BASE_NUMERICS_SAFE_CONVERSIONS_ARM_IMPL_H_
+
+#include <cassert>
+#include <limits>
+#include <type_traits>
+
+#include "third_party/base/numerics/safe_conversions_impl.h"
+
+namespace pdfium {
+namespace base {
+namespace internal {
+
+// Fast saturation to a destination type.
+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 &&
+ IntegerBitsPlusSign<Src>::value <= IntegerBitsPlusSign<int32_t>::value &&
+ IntegerBitsPlusSign<Dst>::value <= IntegerBitsPlusSign<int32_t>::value &&
+ !IsTypeInRangeForNumericType<Dst, Src>::value;
+
+ __attribute__((always_inline)) static Dst Do(Src value) {
+ int32_t src = value;
+ typename std::conditional<std::is_signed<Dst>::value, int32_t,
+ uint32_t>::type result;
+ if (std::is_signed<Dst>::value) {
+ asm("ssat %[dst], %[shift], %[src]"
+ : [dst] "=r"(result)
+ : [src] "r"(src), [shift] "n"(IntegerBitsPlusSign<Dst>::value <= 32
+ ? IntegerBitsPlusSign<Dst>::value
+ : 32));
+ } else {
+ asm("usat %[dst], %[shift], %[src]"
+ : [dst] "=r"(result)
+ : [src] "r"(src), [shift] "n"(IntegerBitsPlusSign<Dst>::value < 32
+ ? IntegerBitsPlusSign<Dst>::value
+ : 31));
+ }
+ return static_cast<Dst>(result);
+ }
+};
+
+} // namespace internal
+} // namespace base
+} // namespace pdfium
+
+#endif // THIRD_PARTY_BASE_NUMERICS_SAFE_CONVERSIONS_ARM_IMPL_H_
diff --git a/third_party/base/numerics/safe_conversions_impl.h b/third_party/base/numerics/safe_conversions_impl.h
index 4077b28..bdad911 100644
--- a/third_party/base/numerics/safe_conversions_impl.h
+++ b/third_party/base/numerics/safe_conversions_impl.h
@@ -2,14 +2,22 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#ifndef PDFIUM_THIRD_PARTY_BASE_NUMERICS_SAFE_CONVERSIONS_IMPL_H_
-#define PDFIUM_THIRD_PARTY_BASE_NUMERICS_SAFE_CONVERSIONS_IMPL_H_
+#ifndef THIRD_PARTY_BASE_NUMERICS_SAFE_CONVERSIONS_IMPL_H_
+#define THIRD_PARTY_BASE_NUMERICS_SAFE_CONVERSIONS_IMPL_H_
#include <stdint.h>
#include <limits>
#include <type_traits>
+#if defined(__GNUC__) || defined(__clang__)
+#define BASE_NUMERICS_LIKELY(x) __builtin_expect(!!(x), 1)
+#define BASE_NUMERICS_UNLIKELY(x) __builtin_expect(!!(x), 0)
+#else
+#define BASE_NUMERICS_LIKELY(x) (x)
+#define BASE_NUMERICS_UNLIKELY(x) (x)
+#endif
+
namespace pdfium {
namespace base {
namespace internal {
@@ -77,6 +85,48 @@
: 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);
+}
+#else
+constexpr bool CanDetectCompileTimeConstant() {
+ return false;
+}
+template <typename T>
+constexpr bool IsCompileTimeConstant(const T) {
+ return 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
+// an error condition.
+struct CheckOnFailure {
+ template <typename T>
+ static T HandleFailure() {
+#if defined(_MSC_VER)
+ __debugbreak();
+#elif defined(__GNUC__) || defined(__clang__)
+ __builtin_trap();
+#else
+ ((void)(*(volatile char*)0 = 0));
+#endif
+ return T();
+ }
+};
+
enum IntegerRepresentation {
INTEGER_REPRESENTATION_UNSIGNED,
INTEGER_REPRESENTATION_SIGNED
@@ -143,7 +193,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_(false), is_overflow_(false) {}
+ constexpr RangeCheck() : is_underflow_(0), is_overflow_(0) {}
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_; }
@@ -338,6 +388,13 @@
}
};
+// Simple wrapper for statically checking if a type's range is contained.
+template <typename Dst, typename Src>
+struct IsTypeInRangeForNumericType {
+ static const bool value = StaticDstRangeRelationToSrcRange<Dst, Src>::value ==
+ NUMERIC_RANGE_CONTAINED;
+};
+
template <typename Dst,
template <typename> class Bounds = std::numeric_limits,
typename Src>
@@ -518,38 +575,16 @@
static const bool is_contained = false;
};
-// This hacks around libstdc++ 4.6 missing stuff in type_traits.
-#if defined(__GLIBCXX__)
-#define PRIV_GLIBCXX_4_7_0 20120322
-#define PRIV_GLIBCXX_4_5_4 20120702
-#define PRIV_GLIBCXX_4_6_4 20121127
-#if (__GLIBCXX__ < PRIV_GLIBCXX_4_7_0 || __GLIBCXX__ == PRIV_GLIBCXX_4_5_4 || \
- __GLIBCXX__ == PRIV_GLIBCXX_4_6_4)
-#define PRIV_USE_FALLBACKS_FOR_OLD_GLIBCXX
-#undef PRIV_GLIBCXX_4_7_0
-#undef PRIV_GLIBCXX_4_5_4
-#undef PRIV_GLIBCXX_4_6_4
-#endif
-#endif
-
// Extracts the underlying type from an enum.
template <typename T, bool is_enum = std::is_enum<T>::value>
struct ArithmeticOrUnderlyingEnum;
template <typename T>
struct ArithmeticOrUnderlyingEnum<T, true> {
-#if defined(PRIV_USE_FALLBACKS_FOR_OLD_GLIBCXX)
- using type = __underlying_type(T);
-#else
using type = typename std::underlying_type<T>::type;
-#endif
static const bool value = std::is_arithmetic<type>::value;
};
-#if defined(PRIV_USE_FALLBACKS_FOR_OLD_GLIBCXX)
-#undef PRIV_USE_FALLBACKS_FOR_OLD_GLIBCXX
-#endif
-
template <typename T>
struct ArithmeticOrUnderlyingEnum<T, false> {
using type = T;
@@ -561,6 +596,9 @@
class CheckedNumeric;
template <typename T>
+class ClampedNumeric;
+
+template <typename T>
class StrictNumeric;
// Used to treat CheckedNumeric and arithmetic underlying types the same.
@@ -569,6 +607,7 @@
using type = typename ArithmeticOrUnderlyingEnum<T>::type;
static const bool is_numeric = std::is_arithmetic<type>::value;
static const bool is_checked = false;
+ static const bool is_clamped = false;
static const bool is_strict = false;
};
@@ -577,6 +616,16 @@
using type = T;
static const bool is_numeric = true;
static const bool is_checked = true;
+ static const bool is_clamped = false;
+ static const bool is_strict = false;
+};
+
+template <typename T>
+struct UnderlyingType<ClampedNumeric<T>> {
+ using type = T;
+ static const bool is_numeric = true;
+ static const bool is_checked = false;
+ static const bool is_clamped = true;
static const bool is_strict = false;
};
@@ -585,6 +634,7 @@
using type = T;
static const bool is_numeric = true;
static const bool is_checked = false;
+ static const bool is_clamped = false;
static const bool is_strict = true;
};
@@ -596,12 +646,46 @@
};
template <typename L, typename R>
+struct IsClampedOp {
+ static const bool value =
+ UnderlyingType<L>::is_numeric && UnderlyingType<R>::is_numeric &&
+ (UnderlyingType<L>::is_clamped || UnderlyingType<R>::is_clamped) &&
+ !(UnderlyingType<L>::is_checked || UnderlyingType<R>::is_checked);
+};
+
+template <typename L, typename R>
struct IsStrictOp {
static const bool value =
UnderlyingType<L>::is_numeric && UnderlyingType<R>::is_numeric &&
- (UnderlyingType<L>::is_strict || UnderlyingType<R>::is_strict);
+ (UnderlyingType<L>::is_strict || UnderlyingType<R>::is_strict) &&
+ !(UnderlyingType<L>::is_checked || UnderlyingType<R>::is_checked) &&
+ !(UnderlyingType<L>::is_clamped || UnderlyingType<R>::is_clamped);
};
+// as_signed<> returns the supplied integral value (or integral castable
+// Numeric template) cast as a signed integral of equivalent precision.
+// I.e. it's mostly an alias for: static_cast<std::make_signed<T>::type>(t)
+template <typename Src>
+constexpr typename std::make_signed<
+ typename base::internal::UnderlyingType<Src>::type>::type
+as_signed(const Src value) {
+ static_assert(std::is_integral<decltype(as_signed(value))>::value,
+ "Argument must be a signed or unsigned integer type.");
+ return static_cast<decltype(as_signed(value))>(value);
+}
+
+// as_unsigned<> returns the supplied integral value (or integral castable
+// Numeric template) cast as an unsigned integral of equivalent precision.
+// I.e. it's mostly an alias for: static_cast<std::make_unsigned<T>::type>(t)
+template <typename Src>
+constexpr typename std::make_unsigned<
+ typename base::internal::UnderlyingType<Src>::type>::type
+as_unsigned(const Src value) {
+ static_assert(std::is_integral<decltype(as_unsigned(value))>::value,
+ "Argument must be a signed or unsigned integer type.");
+ return static_cast<decltype(as_unsigned(value))>(value);
+}
+
template <typename L, typename R>
constexpr bool IsLessImpl(const L lhs,
const R rhs,
@@ -727,8 +811,42 @@
: C<L, R>::Test(lhs, rhs);
}
+template <typename Dst, typename Src>
+constexpr bool IsMaxInRangeForNumericType() {
+ return IsGreaterOrEqual<Dst, Src>::Test(std::numeric_limits<Dst>::max(),
+ std::numeric_limits<Src>::max());
+}
+
+template <typename Dst, typename Src>
+constexpr bool IsMinInRangeForNumericType() {
+ return IsLessOrEqual<Dst, Src>::Test(std::numeric_limits<Dst>::lowest(),
+ std::numeric_limits<Src>::lowest());
+}
+
+template <typename Dst, typename Src>
+constexpr Dst CommonMax() {
+ return !IsMaxInRangeForNumericType<Dst, Src>()
+ ? Dst(std::numeric_limits<Dst>::max())
+ : Dst(std::numeric_limits<Src>::max());
+}
+
+template <typename Dst, typename Src>
+constexpr Dst CommonMin() {
+ return !IsMinInRangeForNumericType<Dst, Src>()
+ ? Dst(std::numeric_limits<Dst>::lowest())
+ : Dst(std::numeric_limits<Src>::lowest());
+}
+
+// This is a wrapper to generate return the max or min for a supplied type.
+// If the argument is false, the returned value is the maximum. If true the
+// returned value is the minimum.
+template <typename Dst, typename Src = Dst>
+constexpr Dst CommonMaxOrMin(bool is_min) {
+ return is_min ? CommonMin<Dst, Src>() : CommonMax<Dst, Src>();
+}
+
} // namespace internal
} // namespace base
} // namespace pdfium
-#endif // PDFIUM_THIRD_PARTY_BASE_NUMERICS_SAFE_CONVERSIONS_IMPL_H_
+#endif // THIRD_PARTY_BASE_NUMERICS_SAFE_CONVERSIONS_IMPL_H_
diff --git a/third_party/base/numerics/safe_math.h b/third_party/base/numerics/safe_math.h
index a118055..3007cd7 100644
--- a/third_party/base/numerics/safe_math.h
+++ b/third_party/base/numerics/safe_math.h
@@ -2,8 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#ifndef PDFIUM_THIRD_PARTY_BASE_NUMERICS_SAFE_MATH_H_
-#define PDFIUM_THIRD_PARTY_BASE_NUMERICS_SAFE_MATH_H_
+#ifndef THIRD_PARTY_BASE_NUMERICS_SAFE_MATH_H_
+#define THIRD_PARTY_BASE_NUMERICS_SAFE_MATH_H_
#include <stddef.h>
@@ -507,4 +507,4 @@
} // namespace base
} // namespace pdfium
-#endif // PDFIUM_THIRD_PARTY_BASE_NUMERICS_SAFE_MATH_H_
+#endif // THIRD_PARTY_BASE_NUMERICS_SAFE_MATH_H_
diff --git a/third_party/base/numerics/safe_math_impl.h b/third_party/base/numerics/safe_math_impl.h
index 61f18d2..d91dd2b 100644
--- a/third_party/base/numerics/safe_math_impl.h
+++ b/third_party/base/numerics/safe_math_impl.h
@@ -2,8 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#ifndef PDFIUM_THIRD_PARTY_BASE_NUMERICS_SAFE_MATH_IMPL_H_
-#define PDFIUM_THIRD_PARTY_BASE_NUMERICS_SAFE_MATH_IMPL_H_
+#ifndef THIRD_PARTY_BASE_NUMERICS_SAFE_MATH_IMPL_H_
+#define THIRD_PARTY_BASE_NUMERICS_SAFE_MATH_IMPL_H_
#include <stddef.h>
#include <stdint.h>
@@ -644,4 +644,4 @@
} // namespace base
} // namespace pdfium
-#endif // PDFIUM_THIRD_PARTY_BASE_NUMERICS_SAFE_MATH_IMPL_H_
+#endif // THIRD_PARTY_BASE_NUMERICS_SAFE_MATH_IMPL_H_