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

Unified Diff: base/numerics/safe_math_shared_impl.h

Issue 2931323002: Split out code to be shared between CheckedNumeric and ClampedNumeric (Closed)
Patch Set: iwyu Created 3 years, 6 months 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/checked_math_impl.h ('K') | « base/numerics/safe_math_impl.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_shared_impl.h
diff --git a/base/numerics/safe_math_shared_impl.h b/base/numerics/safe_math_shared_impl.h
new file mode 100644
index 0000000000000000000000000000000000000000..3e75bfecdea38aa0177fbf99ef34098a83f2ffd1
--- /dev/null
+++ b/base/numerics/safe_math_shared_impl.h
@@ -0,0 +1,146 @@
+// 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_SAFE_MATH_SHARED_IMPL_H_
+#define BASE_NUMERICS_SAFE_MATH_SHARED_IMPL_H_
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include <climits>
+#include <cmath>
+#include <cstdlib>
+#include <limits>
+#include <type_traits>
+
+#include "base/numerics/safe_conversions.h"
+
+namespace base {
+namespace internal {
+
+// This is used for UnsignedAbs, where we need to support floating-point
+// template instantiations even though we don't actually support the operations.
+// However, there is no corresponding implementation of e.g. SafeUnsignedAbs,
+// so the float versions will not compile.
+template <typename Numeric,
+ bool IsInteger = std::is_integral<Numeric>::value,
+ bool IsFloat = std::is_floating_point<Numeric>::value>
+struct UnsignedOrFloatForSize;
+
+template <typename Numeric>
+struct UnsignedOrFloatForSize<Numeric, true, false> {
+ using type = typename std::make_unsigned<Numeric>::type;
+};
+
+template <typename Numeric>
+struct UnsignedOrFloatForSize<Numeric, false, true> {
+ using type = Numeric;
+};
+
+// 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.
+
+template <typename T,
+ typename std::enable_if<std::is_integral<T>::value>::type* = nullptr>
+constexpr T NegateWrapper(T value) {
+ using UnsignedT = typename std::make_unsigned<T>::type;
+ // This will compile to a NEG on Intel, and is normal negation on ARM.
+ return static_cast<T>(UnsignedT(0) - static_cast<UnsignedT>(value));
+}
+
+template <
+ typename T,
+ typename std::enable_if<std::is_floating_point<T>::value>::type* = nullptr>
+constexpr T NegateWrapper(T value) {
+ return -value;
+}
+
+template <typename T,
+ typename std::enable_if<std::is_integral<T>::value>::type* = nullptr>
+constexpr typename std::make_unsigned<T>::type InvertWrapper(T value) {
+ return ~value;
+}
+
+template <typename T,
+ typename std::enable_if<std::is_integral<T>::value>::type* = nullptr>
+constexpr T AbsWrapper(T value) {
+ return static_cast<T>(SafeUnsignedAbs(value));
+}
+
+template <
+ typename T,
+ typename std::enable_if<std::is_floating_point<T>::value>::type* = nullptr>
+constexpr T AbsWrapper(T value) {
+ return value < 0 ? -value : value;
+}
+
+template <template <typename, typename, typename> class M,
+ typename L,
+ typename R>
+struct MathWrapper {
+ using math = M<typename UnderlyingType<L>::type,
+ typename UnderlyingType<R>::type,
+ void>;
+ 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> \
+ 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) { \
+ return ChkMathOp<CLASS##OP_NAME##Op, L, R, Args...>(lhs, rhs, args...); \
+ }
+
+#define BASE_NUMERIC_ARITHMETIC_OPERATORS(CLASS, CL_ABBR, OP_NAME, OP, CMP_OP) \
+ /* Binary arithmetic operator for all CheckedNumeric operations. */ \
+ template <typename L, typename R, \
+ typename std::enable_if<IsCheckedOp<L, R>::value>::type* = \
+ nullptr> \
+ CheckedNumeric<typename MathWrapper<CLASS##OP_NAME##Op, L, R>::type> \
+ operator OP(const L lhs, const R rhs) { \
+ return decltype(lhs OP rhs)::template MathOp<CLASS##OP_NAME##Op>(lhs, \
+ rhs); \
+ } \
+ /* Assignment arithmetic operator implementation from CheckedNumeric. */ \
+ template <typename L> \
+ template <typename R> \
+ CheckedNumeric<L>& CheckedNumeric<L>::operator CMP_OP(const R rhs) { \
+ return MathOp<CLASS##OP_NAME##Op>(rhs); \
+ } \
+ /* Variadic arithmetic functions that return CheckedNumeric. */ \
+ BASE_NUMERIC_ARITHMETIC_VARIADIC(CLASS, CL_ABBR, OP_NAME)
+
+} // namespace internal
+} // namespace base
+
+#endif // BASE_NUMERICS_SAFE_MATH_SHARED_IMPL_H_
« base/numerics/checked_math_impl.h ('K') | « base/numerics/safe_math_impl.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698