| OLD | NEW |
| (Empty) | |
| 1 // Copyright 2017 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. |
| 4 |
| 5 #ifndef BASE_NUMERICS_SAFE_MATH_SHARED_IMPL_H_ |
| 6 #define BASE_NUMERICS_SAFE_MATH_SHARED_IMPL_H_ |
| 7 |
| 8 #include <stddef.h> |
| 9 #include <stdint.h> |
| 10 |
| 11 #include <climits> |
| 12 #include <cmath> |
| 13 #include <cstdlib> |
| 14 #include <limits> |
| 15 #include <type_traits> |
| 16 |
| 17 #include "base/numerics/safe_conversions.h" |
| 18 |
| 19 namespace base { |
| 20 namespace internal { |
| 21 |
| 22 // This is used for UnsignedAbs, where we need to support floating-point |
| 23 // template instantiations even though we don't actually support the operations. |
| 24 // However, there is no corresponding implementation of e.g. SafeUnsignedAbs, |
| 25 // so the float versions will not compile. |
| 26 template <typename Numeric, |
| 27 bool IsInteger = std::is_integral<Numeric>::value, |
| 28 bool IsFloat = std::is_floating_point<Numeric>::value> |
| 29 struct UnsignedOrFloatForSize; |
| 30 |
| 31 template <typename Numeric> |
| 32 struct UnsignedOrFloatForSize<Numeric, true, false> { |
| 33 using type = typename std::make_unsigned<Numeric>::type; |
| 34 }; |
| 35 |
| 36 template <typename Numeric> |
| 37 struct UnsignedOrFloatForSize<Numeric, false, true> { |
| 38 using type = Numeric; |
| 39 }; |
| 40 |
| 41 // Wrap the unary operations to allow SFINAE when instantiating integrals versus |
| 42 // floating points. These don't perform any overflow checking. Rather, they |
| 43 // exhibit well-defined overflow semantics and rely on the caller to detect |
| 44 // if an overflow occured. |
| 45 |
| 46 template <typename T, |
| 47 typename std::enable_if<std::is_integral<T>::value>::type* = nullptr> |
| 48 constexpr T NegateWrapper(T value) { |
| 49 using UnsignedT = typename std::make_unsigned<T>::type; |
| 50 // This will compile to a NEG on Intel, and is normal negation on ARM. |
| 51 return static_cast<T>(UnsignedT(0) - static_cast<UnsignedT>(value)); |
| 52 } |
| 53 |
| 54 template < |
| 55 typename T, |
| 56 typename std::enable_if<std::is_floating_point<T>::value>::type* = nullptr> |
| 57 constexpr T NegateWrapper(T value) { |
| 58 return -value; |
| 59 } |
| 60 |
| 61 template <typename T, |
| 62 typename std::enable_if<std::is_integral<T>::value>::type* = nullptr> |
| 63 constexpr typename std::make_unsigned<T>::type InvertWrapper(T value) { |
| 64 return ~value; |
| 65 } |
| 66 |
| 67 template <typename T, |
| 68 typename std::enable_if<std::is_integral<T>::value>::type* = nullptr> |
| 69 constexpr T AbsWrapper(T value) { |
| 70 return static_cast<T>(SafeUnsignedAbs(value)); |
| 71 } |
| 72 |
| 73 template < |
| 74 typename T, |
| 75 typename std::enable_if<std::is_floating_point<T>::value>::type* = nullptr> |
| 76 constexpr T AbsWrapper(T value) { |
| 77 return value < 0 ? -value : value; |
| 78 } |
| 79 |
| 80 template <template <typename, typename, typename> class M, |
| 81 typename L, |
| 82 typename R> |
| 83 struct MathWrapper { |
| 84 using math = M<typename UnderlyingType<L>::type, |
| 85 typename UnderlyingType<R>::type, |
| 86 void>; |
| 87 using type = typename math::result_type; |
| 88 }; |
| 89 |
| 90 // These variadic templates work out the return types. |
| 91 // TODO(jschuh): Rip all this out once we have C++14 non-trailing auto support. |
| 92 template <template <typename, typename, typename> class M, |
| 93 typename L, |
| 94 typename R, |
| 95 typename... Args> |
| 96 struct ResultType; |
| 97 |
| 98 template <template <typename, typename, typename> class M, |
| 99 typename L, |
| 100 typename R> |
| 101 struct ResultType<M, L, R> { |
| 102 using type = typename MathWrapper<M, L, R>::type; |
| 103 }; |
| 104 |
| 105 template <template <typename, typename, typename> class M, |
| 106 typename L, |
| 107 typename R, |
| 108 typename... Args> |
| 109 struct ResultType { |
| 110 using type = |
| 111 typename ResultType<M, typename ResultType<M, L, R>::type, Args...>::type; |
| 112 }; |
| 113 |
| 114 // The following macros are just boilerplate for the standard arithmetic |
| 115 // operator overloads and variadic function templates. A macro isn't the nicest |
| 116 // solution, but it beats rewriting these over and over again. |
| 117 #define BASE_NUMERIC_ARITHMETIC_VARIADIC(CLASS, CL_ABBR, OP_NAME) \ |
| 118 template <typename L, typename R, typename... Args> \ |
| 119 CLASS##Numeric<typename ResultType<CLASS##OP_NAME##Op, L, R, Args...>::type> \ |
| 120 CL_ABBR##OP_NAME(const L lhs, const R rhs, const Args... args) { \ |
| 121 return ChkMathOp<CLASS##OP_NAME##Op, L, R, Args...>(lhs, rhs, args...); \ |
| 122 } |
| 123 |
| 124 #define BASE_NUMERIC_ARITHMETIC_OPERATORS(CLASS, CL_ABBR, OP_NAME, OP, CMP_OP) \ |
| 125 /* Binary arithmetic operator for all CheckedNumeric operations. */ \ |
| 126 template <typename L, typename R, \ |
| 127 typename std::enable_if<IsCheckedOp<L, R>::value>::type* = \ |
| 128 nullptr> \ |
| 129 CheckedNumeric<typename MathWrapper<CLASS##OP_NAME##Op, L, R>::type> \ |
| 130 operator OP(const L lhs, const R rhs) { \ |
| 131 return decltype(lhs OP rhs)::template MathOp<CLASS##OP_NAME##Op>(lhs, \ |
| 132 rhs); \ |
| 133 } \ |
| 134 /* Assignment arithmetic operator implementation from CheckedNumeric. */ \ |
| 135 template <typename L> \ |
| 136 template <typename R> \ |
| 137 CheckedNumeric<L>& CheckedNumeric<L>::operator CMP_OP(const R rhs) { \ |
| 138 return MathOp<CLASS##OP_NAME##Op>(rhs); \ |
| 139 } \ |
| 140 /* Variadic arithmetic functions that return CheckedNumeric. */ \ |
| 141 BASE_NUMERIC_ARITHMETIC_VARIADIC(CLASS, CL_ABBR, OP_NAME) |
| 142 |
| 143 } // namespace internal |
| 144 } // namespace base |
| 145 |
| 146 #endif // BASE_NUMERICS_SAFE_MATH_SHARED_IMPL_H_ |
| OLD | NEW |