Index: base/numerics/clamped_math_impl.h |
diff --git a/base/numerics/clamped_math_impl.h b/base/numerics/clamped_math_impl.h |
new file mode 100644 |
index 0000000000000000000000000000000000000000..7f8035c21657b81f8bf8c38e7e729f031b13f5f6 |
--- /dev/null |
+++ b/base/numerics/clamped_math_impl.h |
@@ -0,0 +1,290 @@ |
+// 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 BASE_NUMERICS_CLAMPED_MATH_IMPL_H_ |
+#define BASE_NUMERICS_CLAMPED_MATH_IMPL_H_ |
+ |
+#include <stddef.h> |
+#include <stdint.h> |
+ |
+#include <climits> |
+#include <cmath> |
+#include <cstdlib> |
+#include <limits> |
+#include <type_traits> |
+ |
+#include "base/numerics/checked_math.h" |
+#include "base/numerics/safe_conversions.h" |
+#include "base/numerics/safe_math_shared_impl.h" |
+ |
+namespace base { |
+namespace internal { |
+ |
+// This provides a small optimization that generates more compact code when one |
+// of the components in an operation is a compile-time constant. |
+template <typename T> |
+constexpr bool IsCompileTimeConstant(const T v) { |
+#if defined(__clang__) || defined(__GNUC__) |
+ return __builtin_constant_p(v); |
+#else |
+ return false; |
+#endif |
+} |
+ |
+// 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 T> |
+constexpr T GetMaxOrMin(bool is_min) { |
+ // For both signed and unsigned math the bit pattern for minimum is really |
+ // just one plus the maximum. However, we have to cast to unsigned to ensure |
+ // we get well-defined overflow semantics. |
+ return as_unsigned(std::numeric_limits<T>::max()) + is_min; |
+} |
+ |
+template <typename T, typename U, class Enable = void> |
+struct ClampedAddOp {}; |
+ |
+template <typename T, typename U> |
+struct ClampedAddOp<T, |
+ U, |
+ typename std::enable_if<std::is_integral<T>::value && |
+ std::is_integral<U>::value>::type> { |
+ using result_type = typename MaxExponentPromotion<T, U>::type; |
+ template <typename V = result_type> |
+ static V Do(T x, U y) { |
+ V result; |
+ return CheckedAddOp<T, U>::Do(x, y, &result) |
+ ? result |
+ // Prefer a compile-time constant (if we have one). |
+ : GetMaxOrMin<V>(IsCompileTimeConstant(x) ? IsValueNegative(x) |
+ : IsValueNegative(y)); |
+ } |
+}; |
+ |
+template <typename T, typename U, class Enable = void> |
+struct ClampedSubOp {}; |
+ |
+template <typename T, typename U> |
+struct ClampedSubOp<T, |
+ U, |
+ typename std::enable_if<std::is_integral<T>::value && |
+ std::is_integral<U>::value>::type> { |
+ using result_type = typename MaxExponentPromotion<T, U>::type; |
+ template <typename V = result_type> |
+ static V Do(T x, U y) { |
+ V result; |
+ return CheckedSubOp<T, U>::Do(x, y, &result) |
+ ? result |
+ // Prefer a compile-time constant (if we have one). |
+ : GetMaxOrMin<V>(IsCompileTimeConstant(x) ? IsValueNegative(x) |
+ : !IsValueNegative(y)); |
+ } |
+}; |
+ |
+template <typename T, typename U, class Enable = void> |
+struct ClampedMulOp {}; |
+ |
+template <typename T, typename U> |
+struct ClampedMulOp<T, |
+ U, |
+ typename std::enable_if<std::is_integral<T>::value && |
+ std::is_integral<U>::value>::type> { |
+ using result_type = typename MaxExponentPromotion<T, U>::type; |
+ template <typename V = result_type> |
+ static V Do(T x, U y) { |
+ V result; |
+ return CheckedMulOp<T, U>::Do(x, y, &result) |
+ ? result |
+ : GetMaxOrMin<V>(IsValueNegative(x) ^ IsValueNegative(y)); |
+ } |
+}; |
+ |
+template <typename T, typename U, class Enable = void> |
+struct ClampedDivOp {}; |
+ |
+template <typename T, typename U> |
+struct ClampedDivOp<T, |
+ U, |
+ typename std::enable_if<std::is_integral<T>::value && |
+ std::is_integral<U>::value>::type> { |
+ using result_type = typename MaxExponentPromotion<T, U>::type; |
+ template <typename V = result_type> |
+ static V Do(T x, U y) { |
+ V result = SaturationDefaultLimits<V>::NaN(); |
+ return !x || CheckedDivOp<T, U>::Do(x, y, &result) |
+ ? result |
+ : GetMaxOrMin<V>(IsValueNegative(x) ^ IsValueNegative(y)); |
+ } |
+}; |
+ |
+template <typename T, typename U, class Enable = void> |
+struct ClampedModOp {}; |
+ |
+template <typename T, typename U> |
+struct ClampedModOp<T, |
+ U, |
+ typename std::enable_if<std::is_integral<T>::value && |
+ std::is_integral<U>::value>::type> { |
+ using result_type = typename MaxExponentPromotion<T, U>::type; |
+ template <typename V = result_type> |
+ static V Do(T x, U y) { |
+ V result; |
+ return CheckedModOp<T, U>::Do(x, y, &result) ? result : x; |
+ } |
+}; |
+ |
+template <typename T, typename U, class Enable = void> |
+struct ClampedLshOp {}; |
+ |
+// Left shift. Non-zero values saturate in the direction of the sign. A zero |
+// shifted by any value always results in zero. |
+// Note: This class template supports left shifting negative values. |
+template <typename T, typename U> |
+struct ClampedLshOp<T, |
+ U, |
+ typename std::enable_if<std::is_integral<T>::value && |
+ std::is_integral<U>::value>::type> { |
+ using result_type = T; |
+ template <typename V = result_type> |
+ static V Do(T x, U shift) { |
+ static_assert(!std::is_signed<U>::value, "Shift value must be unsigned."); |
+ V result = x; |
+ return (shift < std::numeric_limits<T>::digits && |
+ CheckedMulOp<T, T>::Do(x, T(1) << shift, &result)) |
+ ? result |
+ : (x ? GetMaxOrMin<V>(IsValueNegative(x)) : 0); |
+ } |
+}; |
+ |
+template <typename T, typename U, class Enable = void> |
+struct ClampedRshOp {}; |
+ |
+// Right shift. Negative values saturate to -1. Positive or 0 saturates to 0. |
+template <typename T, typename U> |
+struct ClampedRshOp<T, |
+ U, |
+ typename std::enable_if<std::is_integral<T>::value && |
+ std::is_integral<U>::value>::type> { |
+ using result_type = T; |
+ template <typename V = result_type> |
+ static V Do(T x, U shift) { |
+ static_assert(!std::is_signed<U>::value, "Shift value must be unsigned."); |
+ return shift < IntegerBitsPlusSign<T>::value |
+ ? saturated_cast<V>(x >> shift) |
+ // Signed right shift is odd, because it saturates to -1 or 0. |
+ : as_unsigned(V(0)) - IsValueNegative(x); |
+ } |
+}; |
+ |
+template <typename T, typename U, class Enable = void> |
+struct ClampedAndOp {}; |
+ |
+template <typename T, typename U> |
+struct ClampedAndOp<T, |
+ U, |
+ typename std::enable_if<std::is_integral<T>::value && |
+ std::is_integral<U>::value>::type> { |
+ using result_type = typename std::make_unsigned< |
+ typename MaxExponentPromotion<T, U>::type>::type; |
+ template <typename V> |
+ static constexpr V Do(T x, U y) { |
+ return static_cast<result_type>(x) & static_cast<result_type>(y); |
+ } |
+}; |
+ |
+template <typename T, typename U, class Enable = void> |
+struct ClampedOrOp {}; |
+ |
+// For simplicity we promote to unsigned integers. |
+template <typename T, typename U> |
+struct ClampedOrOp<T, |
+ U, |
+ typename std::enable_if<std::is_integral<T>::value && |
+ std::is_integral<U>::value>::type> { |
+ using result_type = typename std::make_unsigned< |
+ typename MaxExponentPromotion<T, U>::type>::type; |
+ template <typename V> |
+ static constexpr V Do(T x, U y) { |
+ return static_cast<result_type>(x) | static_cast<result_type>(y); |
+ } |
+}; |
+ |
+template <typename T, typename U, class Enable = void> |
+struct ClampedXorOp {}; |
+ |
+// For simplicity we support only unsigned integers. |
+template <typename T, typename U> |
+struct ClampedXorOp<T, |
+ U, |
+ typename std::enable_if<std::is_integral<T>::value && |
+ std::is_integral<U>::value>::type> { |
+ using result_type = typename std::make_unsigned< |
+ typename MaxExponentPromotion<T, U>::type>::type; |
+ template <typename V> |
+ static constexpr V Do(T x, U y) { |
+ return static_cast<result_type>(x) ^ static_cast<result_type>(y); |
+ } |
+}; |
+ |
+template <typename T, typename U, class Enable = void> |
+struct ClampedMaxOp {}; |
+ |
+template <typename T, typename U> |
+struct ClampedMaxOp< |
+ T, |
+ U, |
+ typename std::enable_if<std::is_arithmetic<T>::value && |
+ std::is_arithmetic<U>::value>::type> { |
+ using result_type = typename MaxExponentPromotion<T, U>::type; |
+ template <typename V = result_type> |
+ static constexpr V Do(T x, U y) { |
+ return IsGreater<T, U>::Test(x, y) ? saturated_cast<V>(x) |
+ : saturated_cast<V>(y); |
+ } |
+}; |
+ |
+template <typename T, typename U, class Enable = void> |
+struct ClampedMinOp {}; |
+ |
+template <typename T, typename U> |
+struct ClampedMinOp< |
+ T, |
+ U, |
+ typename std::enable_if<std::is_arithmetic<T>::value && |
+ std::is_arithmetic<U>::value>::type> { |
+ using result_type = typename LowestValuePromotion<T, U>::type; |
+ template <typename V = result_type> |
+ static constexpr V Do(T x, U y) { |
+ return IsLess<T, U>::Test(x, y) ? saturated_cast<V>(x) |
+ : saturated_cast<V>(y); |
+ } |
+}; |
+ |
+// This is just boilerplate that wraps the standard floating point arithmetic. |
+// A macro isn't the nicest solution, but it beats rewriting these repeatedly. |
+#define BASE_FLOAT_ARITHMETIC_OPS(NAME, OP) \ |
+ template <typename T, typename U> \ |
+ struct Clamped##NAME##Op< \ |
+ T, U, \ |
+ typename std::enable_if<std::is_floating_point<T>::value || \ |
+ std::is_floating_point<U>::value>::type> { \ |
+ using result_type = typename MaxExponentPromotion<T, U>::type; \ |
+ template <typename V = result_type> \ |
+ static constexpr V Do(T x, U y) { \ |
+ return saturated_cast<V>(x OP y); \ |
+ } \ |
+ }; |
+ |
+BASE_FLOAT_ARITHMETIC_OPS(Add, +) |
+BASE_FLOAT_ARITHMETIC_OPS(Sub, -) |
+BASE_FLOAT_ARITHMETIC_OPS(Mul, *) |
+BASE_FLOAT_ARITHMETIC_OPS(Div, /) |
+ |
+#undef BASE_FLOAT_ARITHMETIC_OPS |
+ |
+} // namespace internal |
+} // namespace base |
+ |
+#endif // BASE_NUMERICS_CLAMPED_MATH_IMPL_H_ |