clamped_math.h (9130B)
1 // Copyright 2017 The Chromium Authors 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_v<T>, 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 // Strictly speaking, this is not necessary, but declaring this allows class 37 // template argument deduction to be used so that it is possible to simply 38 // write `ClampedNumeric(777)` instead of `ClampedNumeric<int>(777)`. 39 // NOLINTNEXTLINE(google-explicit-constructor) 40 constexpr ClampedNumeric(T value) : value_(value) {} 41 42 // This is not an explicit constructor because we implicitly upgrade regular 43 // numerics to ClampedNumerics to make them easier to use. 44 template <typename Src> 45 // NOLINTNEXTLINE(google-explicit-constructor) 46 constexpr ClampedNumeric(Src value) : value_(saturated_cast<T>(value)) { 47 static_assert(UnderlyingType<Src>::is_numeric, "Argument must be numeric."); 48 } 49 50 // This is not an explicit constructor because we want a seamless conversion 51 // from StrictNumeric types. 52 template <typename Src> 53 // NOLINTNEXTLINE(google-explicit-constructor) 54 constexpr ClampedNumeric(StrictNumeric<Src> value) 55 : value_(saturated_cast<T>(static_cast<Src>(value))) {} 56 57 // Returns a ClampedNumeric of the specified type, cast from the current 58 // ClampedNumeric, and saturated to the destination type. 59 template <typename Dst> 60 constexpr ClampedNumeric<typename UnderlyingType<Dst>::type> Cast() const { 61 return *this; 62 } 63 64 // Prototypes for the supported arithmetic operator overloads. 65 template <typename Src> 66 constexpr ClampedNumeric& operator+=(const Src rhs); 67 template <typename Src> 68 constexpr ClampedNumeric& operator-=(const Src rhs); 69 template <typename Src> 70 constexpr ClampedNumeric& operator*=(const Src rhs); 71 template <typename Src> 72 constexpr ClampedNumeric& operator/=(const Src rhs); 73 template <typename Src> 74 constexpr ClampedNumeric& operator%=(const Src rhs); 75 template <typename Src> 76 constexpr ClampedNumeric& operator<<=(const Src rhs); 77 template <typename Src> 78 constexpr ClampedNumeric& operator>>=(const Src rhs); 79 template <typename Src> 80 constexpr ClampedNumeric& operator&=(const Src rhs); 81 template <typename Src> 82 constexpr ClampedNumeric& operator|=(const Src rhs); 83 template <typename Src> 84 constexpr ClampedNumeric& operator^=(const Src rhs); 85 86 constexpr ClampedNumeric operator-() const { 87 // The negation of two's complement int min is int min, so that's the 88 // only overflow case where we will saturate. 89 return ClampedNumeric<T>(SaturatedNegWrapper(value_)); 90 } 91 92 constexpr ClampedNumeric operator~() const { 93 return ClampedNumeric<decltype(InvertWrapper(T()))>(InvertWrapper(value_)); 94 } 95 96 constexpr ClampedNumeric Abs() const { 97 // The negation of two's complement int min is int min, so that's the 98 // only overflow case where we will saturate. 99 return ClampedNumeric<T>(SaturatedAbsWrapper(value_)); 100 } 101 102 template <typename U> 103 constexpr ClampedNumeric<typename MathWrapper<ClampedMaxOp, T, U>::type> Max( 104 const U rhs) const { 105 using result_type = typename MathWrapper<ClampedMaxOp, T, U>::type; 106 return ClampedNumeric<result_type>( 107 ClampedMaxOp<T, U>::Do(value_, Wrapper<U>::value(rhs))); 108 } 109 110 template <typename U> 111 constexpr ClampedNumeric<typename MathWrapper<ClampedMinOp, T, U>::type> Min( 112 const U rhs) const { 113 using result_type = typename MathWrapper<ClampedMinOp, T, U>::type; 114 return ClampedNumeric<result_type>( 115 ClampedMinOp<T, U>::Do(value_, Wrapper<U>::value(rhs))); 116 } 117 118 // This function is available only for integral types. It returns an unsigned 119 // integer of the same width as the source type, containing the absolute value 120 // of the source, and properly handling signed min. 121 constexpr ClampedNumeric<typename UnsignedOrFloatForSize<T>::type> 122 UnsignedAbs() const { 123 return ClampedNumeric<typename UnsignedOrFloatForSize<T>::type>( 124 SafeUnsignedAbs(value_)); 125 } 126 127 constexpr ClampedNumeric& operator++() { 128 *this += 1; 129 return *this; 130 } 131 132 constexpr ClampedNumeric operator++(int) { 133 ClampedNumeric value = *this; 134 *this += 1; 135 return value; 136 } 137 138 constexpr ClampedNumeric& operator--() { 139 *this -= 1; 140 return *this; 141 } 142 143 constexpr ClampedNumeric operator--(int) { 144 ClampedNumeric value = *this; 145 *this -= 1; 146 return value; 147 } 148 149 // These perform the actual math operations on the ClampedNumerics. 150 // Binary arithmetic operations. 151 template <template <typename, typename, typename> class M, 152 typename L, 153 typename R> 154 static constexpr ClampedNumeric MathOp(const L lhs, const R rhs) { 155 using Math = typename MathWrapper<M, L, R>::math; 156 return ClampedNumeric<T>( 157 Math::template Do<T>(Wrapper<L>::value(lhs), Wrapper<R>::value(rhs))); 158 } 159 160 // Assignment arithmetic operations. 161 template <template <typename, typename, typename> class M, typename R> 162 constexpr ClampedNumeric& MathOp(const R rhs) { 163 using Math = typename MathWrapper<M, T, R>::math; 164 *this = 165 ClampedNumeric<T>(Math::template Do<T>(value_, Wrapper<R>::value(rhs))); 166 return *this; 167 } 168 169 template <typename Dst> 170 constexpr operator Dst() const { 171 return saturated_cast<typename ArithmeticOrUnderlyingEnum<Dst>::type>( 172 value_); 173 } 174 175 // This method extracts the raw integer value without saturating it to the 176 // destination type as the conversion operator does. This is useful when 177 // e.g. assigning to an auto type or passing as a deduced template parameter. 178 constexpr T RawValue() const { return value_; } 179 180 private: 181 T value_; 182 183 // These wrappers allow us to handle state the same way for both 184 // ClampedNumeric and POD arithmetic types. 185 template <typename Src> 186 struct Wrapper { 187 static constexpr typename UnderlyingType<Src>::type value(Src value) { 188 return value; 189 } 190 }; 191 }; 192 193 // Convenience wrapper to return a new ClampedNumeric from the provided 194 // arithmetic or ClampedNumericType. 195 template <typename T> 196 constexpr ClampedNumeric<typename UnderlyingType<T>::type> MakeClampedNum( 197 const T value) { 198 return value; 199 } 200 201 // These implement the variadic wrapper for the math operations. 202 template <template <typename, typename, typename> class M, 203 typename L, 204 typename R> 205 constexpr ClampedNumeric<typename MathWrapper<M, L, R>::type> ClampMathOp( 206 const L lhs, 207 const R rhs) { 208 using Math = typename MathWrapper<M, L, R>::math; 209 return ClampedNumeric<typename Math::result_type>::template MathOp<M>(lhs, 210 rhs); 211 } 212 213 // General purpose wrapper template for arithmetic operations. 214 template <template <typename, typename, typename> class M, 215 typename L, 216 typename R, 217 typename... Args> 218 constexpr auto ClampMathOp(const L lhs, const R rhs, const Args... args) { 219 return ClampMathOp<M>(ClampMathOp<M>(lhs, rhs), args...); 220 } 221 222 BASE_NUMERIC_ARITHMETIC_OPERATORS(Clamped, Clamp, Add, +, +=) 223 BASE_NUMERIC_ARITHMETIC_OPERATORS(Clamped, Clamp, Sub, -, -=) 224 BASE_NUMERIC_ARITHMETIC_OPERATORS(Clamped, Clamp, Mul, *, *=) 225 BASE_NUMERIC_ARITHMETIC_OPERATORS(Clamped, Clamp, Div, /, /=) 226 BASE_NUMERIC_ARITHMETIC_OPERATORS(Clamped, Clamp, Mod, %, %=) 227 BASE_NUMERIC_ARITHMETIC_OPERATORS(Clamped, Clamp, Lsh, <<, <<=) 228 BASE_NUMERIC_ARITHMETIC_OPERATORS(Clamped, Clamp, Rsh, >>, >>=) 229 BASE_NUMERIC_ARITHMETIC_OPERATORS(Clamped, Clamp, And, &, &=) 230 BASE_NUMERIC_ARITHMETIC_OPERATORS(Clamped, Clamp, Or, |, |=) 231 BASE_NUMERIC_ARITHMETIC_OPERATORS(Clamped, Clamp, Xor, ^, ^=) 232 BASE_NUMERIC_ARITHMETIC_VARIADIC(Clamped, Clamp, Max) 233 BASE_NUMERIC_ARITHMETIC_VARIADIC(Clamped, Clamp, Min) 234 BASE_NUMERIC_COMPARISON_OPERATORS(Clamped, IsLess, <) 235 BASE_NUMERIC_COMPARISON_OPERATORS(Clamped, IsLessOrEqual, <=) 236 BASE_NUMERIC_COMPARISON_OPERATORS(Clamped, IsGreater, >) 237 BASE_NUMERIC_COMPARISON_OPERATORS(Clamped, IsGreaterOrEqual, >=) 238 BASE_NUMERIC_COMPARISON_OPERATORS(Clamped, IsEqual, ==) 239 BASE_NUMERIC_COMPARISON_OPERATORS(Clamped, IsNotEqual, !=) 240 241 } // namespace internal 242 243 using internal::ClampAdd; 244 using internal::ClampAnd; 245 using internal::ClampDiv; 246 using internal::ClampedNumeric; 247 using internal::ClampLsh; 248 using internal::ClampMax; 249 using internal::ClampMin; 250 using internal::ClampMod; 251 using internal::ClampMul; 252 using internal::ClampOr; 253 using internal::ClampRsh; 254 using internal::ClampSub; 255 using internal::ClampXor; 256 using internal::MakeClampedNum; 257 258 } // namespace base 259 260 #endif // BASE_NUMERICS_CLAMPED_MATH_H_