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_CLAMPED_MATH_H_ |
| 6 #define BASE_NUMERICS_CLAMPED_MATH_H_ |
| 7 |
| 8 #include <stddef.h> |
| 9 |
| 10 #include <limits> |
| 11 #include <type_traits> |
| 12 |
| 13 #include "base/numerics/clamped_math_impl.h" |
| 14 |
| 15 namespace base { |
| 16 namespace internal { |
| 17 |
| 18 template <typename T> |
| 19 class ClampedNumeric { |
| 20 static_assert(std::is_arithmetic<T>::value, |
| 21 "ClampedNumeric<T>: T must be a numeric type."); |
| 22 |
| 23 public: |
| 24 using type = T; |
| 25 |
| 26 constexpr ClampedNumeric() : value_(0) {} |
| 27 |
| 28 // Copy constructor. |
| 29 template <typename Src> |
| 30 constexpr ClampedNumeric(const ClampedNumeric<Src>& rhs) |
| 31 : value_(saturated_cast<T>(rhs.value_)) {} |
| 32 |
| 33 template <typename Src> |
| 34 friend class ClampedNumeric; |
| 35 |
| 36 // This is not an explicit constructor because we implicitly upgrade regular |
| 37 // numerics to ClampedNumerics to make them easier to use. |
| 38 template <typename Src> |
| 39 constexpr ClampedNumeric(Src value) // NOLINT(runtime/explicit) |
| 40 : value_(saturated_cast<T>(value)) { |
| 41 static_assert(std::is_arithmetic<Src>::value, "Argument must be numeric."); |
| 42 } |
| 43 |
| 44 // This is not an explicit constructor because we want a seamless conversion |
| 45 // from StrictNumeric types. |
| 46 template <typename Src> |
| 47 constexpr ClampedNumeric( |
| 48 StrictNumeric<Src> value) // NOLINT(runtime/explicit) |
| 49 : value_(saturated_cast<T>(static_cast<Src>(value))) {} |
| 50 |
| 51 // Returns a ClampedNumeric of the specified type, cast from the current |
| 52 // ClampedNumeric, and saturated to the destination type. |
| 53 template <typename Dst> |
| 54 constexpr ClampedNumeric<typename UnderlyingType<Dst>::type> Cast() const { |
| 55 return *this; |
| 56 } |
| 57 |
| 58 // Prototypes for the supported arithmetic operator overloads. |
| 59 template <typename Src> |
| 60 ClampedNumeric& operator+=(const Src rhs); |
| 61 template <typename Src> |
| 62 ClampedNumeric& operator-=(const Src rhs); |
| 63 template <typename Src> |
| 64 ClampedNumeric& operator*=(const Src rhs); |
| 65 template <typename Src> |
| 66 ClampedNumeric& operator/=(const Src rhs); |
| 67 template <typename Src> |
| 68 ClampedNumeric& operator%=(const Src rhs); |
| 69 template <typename Src> |
| 70 ClampedNumeric& operator<<=(const Src rhs); |
| 71 template <typename Src> |
| 72 ClampedNumeric& operator>>=(const Src rhs); |
| 73 template <typename Src> |
| 74 ClampedNumeric& operator&=(const Src rhs); |
| 75 template <typename Src> |
| 76 ClampedNumeric& operator|=(const Src rhs); |
| 77 template <typename Src> |
| 78 ClampedNumeric& operator^=(const Src rhs); |
| 79 |
| 80 constexpr ClampedNumeric operator-() const { |
| 81 return ClampedNumeric<T>( |
| 82 // The negation of two's complement int min is int min, so that's the |
| 83 // only overflow case we have to check for. |
| 84 std::is_signed<T>::value |
| 85 ? ((std::is_floating_point<T>::value || |
| 86 NegateWrapper(value_) != std::numeric_limits<T>::lowest()) |
| 87 ? NegateWrapper(value_) |
| 88 : std::numeric_limits<T>::max()) |
| 89 : T(0)); // Clamped unsigned negation is always zero. |
| 90 } |
| 91 |
| 92 constexpr ClampedNumeric operator~() const { |
| 93 return ClampedNumeric<decltype(InvertWrapper(T()))>(InvertWrapper(value_)); |
| 94 } |
| 95 |
| 96 constexpr ClampedNumeric Abs() const { |
| 97 return ClampedNumeric<T>( |
| 98 // The negation of two's complement int min is int min, so that's the |
| 99 // only overflow case we have to check for. |
| 100 (!std::is_signed<T>::value || std::is_floating_point<T>::value || |
| 101 AbsWrapper(value_) != std::numeric_limits<T>::lowest()) |
| 102 ? AbsWrapper(value_) |
| 103 : std::numeric_limits<T>::max()); |
| 104 } |
| 105 |
| 106 template <typename U> |
| 107 constexpr ClampedNumeric<typename MathWrapper<ClampedMaxOp, T, U>::type> Max( |
| 108 const U rhs) const { |
| 109 using result_type = typename MathWrapper<ClampedMaxOp, T, U>::type; |
| 110 return ClampedNumeric<result_type>( |
| 111 ClampedMaxOp<T, U>(value_, Wrapper<U>::value(rhs))); |
| 112 } |
| 113 |
| 114 template <typename U> |
| 115 constexpr ClampedNumeric<typename MathWrapper<ClampedMinOp, T, U>::type> Min( |
| 116 const U rhs) const { |
| 117 using result_type = typename MathWrapper<ClampedMinOp, T, U>::type; |
| 118 return ClampedNumeric<result_type>( |
| 119 ClampedMinOp<T, U>(value_, Wrapper<U>::value(rhs))); |
| 120 } |
| 121 |
| 122 // This function is available only for integral types. It returns an unsigned |
| 123 // integer of the same width as the source type, containing the absolute value |
| 124 // of the source, and properly handling signed min. |
| 125 constexpr ClampedNumeric<typename UnsignedOrFloatForSize<T>::type> |
| 126 UnsignedAbs() const { |
| 127 return ClampedNumeric<typename UnsignedOrFloatForSize<T>::type>( |
| 128 SafeUnsignedAbs(value_)); |
| 129 } |
| 130 |
| 131 ClampedNumeric& operator++() { |
| 132 *this += 1; |
| 133 return *this; |
| 134 } |
| 135 |
| 136 ClampedNumeric operator++(int) { |
| 137 ClampedNumeric value = *this; |
| 138 *this += 1; |
| 139 return value; |
| 140 } |
| 141 |
| 142 ClampedNumeric& operator--() { |
| 143 *this -= 1; |
| 144 return *this; |
| 145 } |
| 146 |
| 147 ClampedNumeric operator--(int) { |
| 148 ClampedNumeric value = *this; |
| 149 *this -= 1; |
| 150 return value; |
| 151 } |
| 152 |
| 153 // These perform the actual math operations on the ClampedNumerics. |
| 154 // Binary arithmetic operations. |
| 155 template <template <typename, typename, typename> class M, |
| 156 typename L, |
| 157 typename R> |
| 158 static ClampedNumeric MathOp(const L lhs, const R rhs) { |
| 159 using Math = typename MathWrapper<M, L, R>::math; |
| 160 return ClampedNumeric<T>( |
| 161 Math::template Do<T>(Wrapper<L>::value(lhs), Wrapper<R>::value(rhs))); |
| 162 } |
| 163 |
| 164 // Assignment arithmetic operations. |
| 165 template <template <typename, typename, typename> class M, typename R> |
| 166 ClampedNumeric& MathOp(const R rhs) { |
| 167 using Math = typename MathWrapper<M, T, R>::math; |
| 168 *this = |
| 169 ClampedNumeric<T>(Math::template Do<T>(value_, Wrapper<R>::value(rhs))); |
| 170 return *this; |
| 171 } |
| 172 |
| 173 template <typename Dst> |
| 174 constexpr operator Dst() const { |
| 175 return saturated_cast<typename ArithmeticOrUnderlyingEnum<Dst>::type>( |
| 176 value_); |
| 177 } |
| 178 |
| 179 private: |
| 180 T value_; |
| 181 |
| 182 // These wrappers allow us to handle state the same way for both |
| 183 // ClampedNumeric and POD arithmetic types. |
| 184 template <typename Src> |
| 185 struct Wrapper { |
| 186 static constexpr Src value(Src value) { |
| 187 return static_cast<typename UnderlyingType<Src>::type>(value); |
| 188 } |
| 189 }; |
| 190 }; |
| 191 |
| 192 // Convience wrapper to return a new ClampedNumeric from the provided arithmetic |
| 193 // or ClampedNumericType. |
| 194 template <typename T> |
| 195 constexpr ClampedNumeric<typename UnderlyingType<T>::type> MakeClampedNum( |
| 196 const T value) { |
| 197 return value; |
| 198 } |
| 199 |
| 200 // Overload the ostream output operator to make logging work nicely. |
| 201 template <typename T> |
| 202 std::ostream& operator<<(std::ostream& os, const ClampedNumeric<T>& value) { |
| 203 os << static_cast<T>(value); |
| 204 return os; |
| 205 } |
| 206 |
| 207 // These implement the variadic wrapper for the math operations. |
| 208 template <template <typename, typename, typename> class M, |
| 209 typename L, |
| 210 typename R> |
| 211 ClampedNumeric<typename MathWrapper<M, L, R>::type> ClampMathOp(const L lhs, |
| 212 const R rhs) { |
| 213 using Math = typename MathWrapper<M, L, R>::math; |
| 214 return ClampedNumeric<typename Math::result_type>::template MathOp<M>(lhs, |
| 215 rhs); |
| 216 } |
| 217 |
| 218 // General purpose wrapper template for arithmetic operations. |
| 219 template <template <typename, typename, typename> class M, |
| 220 typename L, |
| 221 typename R, |
| 222 typename... Args> |
| 223 ClampedNumeric<typename ResultType<M, L, R, Args...>::type> |
| 224 ClampMathOp(const L lhs, const R rhs, const Args... args) { |
| 225 return ClampMathOp<M>(ClampMathOp<M>(lhs, rhs), args...); |
| 226 } |
| 227 |
| 228 BASE_NUMERIC_ARITHMETIC_OPERATORS(Clamped, Clamp, Add, +, +=) |
| 229 BASE_NUMERIC_ARITHMETIC_OPERATORS(Clamped, Clamp, Sub, -, -=) |
| 230 BASE_NUMERIC_ARITHMETIC_OPERATORS(Clamped, Clamp, Mul, *, *=) |
| 231 BASE_NUMERIC_ARITHMETIC_OPERATORS(Clamped, Clamp, Div, /, /=) |
| 232 BASE_NUMERIC_ARITHMETIC_OPERATORS(Clamped, Clamp, Mod, %, %=) |
| 233 BASE_NUMERIC_ARITHMETIC_OPERATORS(Clamped, Clamp, Lsh, <<, <<=) |
| 234 BASE_NUMERIC_ARITHMETIC_OPERATORS(Clamped, Clamp, Rsh, >>, >>=) |
| 235 BASE_NUMERIC_ARITHMETIC_OPERATORS(Clamped, Clamp, And, &, &=) |
| 236 BASE_NUMERIC_ARITHMETIC_OPERATORS(Clamped, Clamp, Or, |, |=) |
| 237 BASE_NUMERIC_ARITHMETIC_OPERATORS(Clamped, Clamp, Xor, ^, ^=) |
| 238 BASE_NUMERIC_ARITHMETIC_VARIADIC(Clamped, Clamp, Max) |
| 239 BASE_NUMERIC_ARITHMETIC_VARIADIC(Clamped, Clamp, Min) |
| 240 BASE_NUMERIC_COMPARISON_OPERATORS(Clamped, IsLess, <); |
| 241 BASE_NUMERIC_COMPARISON_OPERATORS(Clamped, IsLessOrEqual, <=); |
| 242 BASE_NUMERIC_COMPARISON_OPERATORS(Clamped, IsGreater, >); |
| 243 BASE_NUMERIC_COMPARISON_OPERATORS(Clamped, IsGreaterOrEqual, >=); |
| 244 BASE_NUMERIC_COMPARISON_OPERATORS(Clamped, IsEqual, ==); |
| 245 BASE_NUMERIC_COMPARISON_OPERATORS(Clamped, IsNotEqual, !=); |
| 246 |
| 247 } // namespace internal |
| 248 |
| 249 using internal::ClampedNumeric; |
| 250 using internal::MakeClampedNum; |
| 251 using internal::ClampMax; |
| 252 using internal::ClampMin; |
| 253 using internal::ClampAdd; |
| 254 using internal::ClampSub; |
| 255 using internal::ClampMul; |
| 256 using internal::ClampDiv; |
| 257 using internal::ClampMod; |
| 258 using internal::ClampLsh; |
| 259 using internal::ClampRsh; |
| 260 using internal::ClampAnd; |
| 261 using internal::ClampOr; |
| 262 using internal::ClampXor; |
| 263 |
| 264 } // namespace base |
| 265 |
| 266 #endif // BASE_NUMERICS_CLAMPED_MATH_H_ |
OLD | NEW |