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_CHECKED_MATH_H_ 6#define BASE_NUMERICS_CHECKED_MATH_H_ 7 8#include <stddef.h> 9 10#include <limits> 11#include <type_traits> 12 13#include "base/numerics/checked_math_impl.h" 14 15namespace base { 16namespace internal { 17 18template <typename T> 19class CheckedNumeric { 20 static_assert(std::is_arithmetic<T>::value, 21 "CheckedNumeric<T>: T must be a numeric type."); 22 23 public: 24 using type = T; 25 26 constexpr CheckedNumeric() = default; 27 28 // Copy constructor. 29 template <typename Src> 30 constexpr CheckedNumeric(const CheckedNumeric<Src>& rhs) 31 : state_(rhs.state_.value(), rhs.IsValid()) {} 32 33 template <typename Src> 34 friend class CheckedNumeric; 35 36 // This is not an explicit constructor because we implicitly upgrade regular 37 // numerics to CheckedNumerics to make them easier to use. 38 template <typename Src> 39 constexpr CheckedNumeric(Src value) // NOLINT(runtime/explicit) 40 : state_(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 CheckedNumeric( 48 StrictNumeric<Src> value) // NOLINT(runtime/explicit) 49 : state_(static_cast<Src>(value)) {} 50 51 // IsValid() - The public API to test if a CheckedNumeric is currently valid. 52 // A range checked destination type can be supplied using the Dst template 53 // parameter. 54 template <typename Dst = T> 55 constexpr bool IsValid() const { 56 return state_.is_valid() && 57 IsValueInRangeForNumericType<Dst>(state_.value()); 58 } 59 60 // AssignIfValid(Dst) - Assigns the underlying value if it is currently valid 61 // and is within the range supported by the destination type. Returns true if 62 // successful and false otherwise. 63 template <typename Dst> 64#if defined(__clang__) || defined(__GNUC__) 65 __attribute__((warn_unused_result)) 66#elif defined(_MSC_VER) 67 _Check_return_ 68#endif 69 constexpr bool 70 AssignIfValid(Dst* result) const { 71 return BASE_NUMERICS_LIKELY(IsValid<Dst>()) 72 ? ((*result = static_cast<Dst>(state_.value())), true) 73 : false; 74 } 75 76 // ValueOrDie() - The primary accessor for the underlying value. If the 77 // current state is not valid it will CHECK and crash. 78 // A range checked destination type can be supplied using the Dst template 79 // parameter, which will trigger a CHECK if the value is not in bounds for 80 // the destination. 81 // The CHECK behavior can be overridden by supplying a handler as a 82 // template parameter, for test code, etc. However, the handler cannot access 83 // the underlying value, and it is not available through other means. 84 template <typename Dst = T, class CheckHandler = CheckOnFailure> 85 constexpr StrictNumeric<Dst> ValueOrDie() const { 86 return BASE_NUMERICS_LIKELY(IsValid<Dst>()) 87 ? static_cast<Dst>(state_.value()) 88 : CheckHandler::template HandleFailure<Dst>(); 89 } 90 91 // ValueOrDefault(T default_value) - A convenience method that returns the 92 // current value if the state is valid, and the supplied default_value for 93 // any other state. 94 // A range checked destination type can be supplied using the Dst template 95 // parameter. WARNING: This function may fail to compile or CHECK at runtime 96 // if the supplied default_value is not within range of the destination type. 97 template <typename Dst = T, typename Src> 98 constexpr StrictNumeric<Dst> ValueOrDefault(const Src default_value) const { 99 return BASE_NUMERICS_LIKELY(IsValid<Dst>()) 100 ? static_cast<Dst>(state_.value()) 101 : checked_cast<Dst>(default_value); 102 } 103 104 // Returns a checked numeric of the specified type, cast from the current 105 // CheckedNumeric. If the current state is invalid or the destination cannot 106 // represent the result then the returned CheckedNumeric will be invalid. 107 template <typename Dst> 108 constexpr CheckedNumeric<typename UnderlyingType<Dst>::type> Cast() const { 109 return *this; 110 } 111 112 // This friend method is available solely for providing more detailed logging 113 // in the the tests. Do not implement it in production code, because the 114 // underlying values may change at any time. 115 template <typename U> 116 friend U GetNumericValueForTest(const CheckedNumeric<U>& src); 117 118 // Prototypes for the supported arithmetic operator overloads. 119 template <typename Src> 120 constexpr CheckedNumeric& operator+=(const Src rhs); 121 template <typename Src> 122 constexpr CheckedNumeric& operator-=(const Src rhs); 123 template <typename Src> 124 constexpr CheckedNumeric& operator*=(const Src rhs); 125 template <typename Src> 126 constexpr CheckedNumeric& operator/=(const Src rhs); 127 template <typename Src> 128 constexpr CheckedNumeric& operator%=(const Src rhs); 129 template <typename Src> 130 constexpr CheckedNumeric& operator<<=(const Src rhs); 131 template <typename Src> 132 constexpr CheckedNumeric& operator>>=(const Src rhs); 133 template <typename Src> 134 constexpr CheckedNumeric& operator&=(const Src rhs); 135 template <typename Src> 136 constexpr CheckedNumeric& operator|=(const Src rhs); 137 template <typename Src> 138 constexpr CheckedNumeric& operator^=(const Src rhs); 139 140 constexpr CheckedNumeric operator-() const { 141 // The negation of two's complement int min is int min, so we simply 142 // check for that in the constexpr case. 143 // We use an optimized code path for a known run-time variable. 144 return MustTreatAsConstexpr(state_.value()) || !std::is_signed<T>::value || 145 std::is_floating_point<T>::value 146 ? CheckedNumeric<T>( 147 NegateWrapper(state_.value()), 148 IsValid() && (!std::is_signed<T>::value || 149 std::is_floating_point<T>::value || 150 NegateWrapper(state_.value()) != 151 std::numeric_limits<T>::lowest())) 152 : FastRuntimeNegate(); 153 } 154 155 constexpr CheckedNumeric operator~() const { 156 return CheckedNumeric<decltype(InvertWrapper(T()))>( 157 InvertWrapper(state_.value()), IsValid()); 158 } 159 160 constexpr CheckedNumeric Abs() const { 161 return !IsValueNegative(state_.value()) ? *this : -*this; 162 } 163 164 template <typename U> 165 constexpr CheckedNumeric<typename MathWrapper<CheckedMaxOp, T, U>::type> Max( 166 const U rhs) const { 167 using R = typename UnderlyingType<U>::type; 168 using result_type = typename MathWrapper<CheckedMaxOp, T, U>::type; 169 // TODO(jschuh): This can be converted to the MathOp version and remain 170 // constexpr once we have C++14 support. 171 return CheckedNumeric<result_type>( 172 static_cast<result_type>( 173 IsGreater<T, R>::Test(state_.value(), Wrapper<U>::value(rhs)) 174 ? state_.value() 175 : Wrapper<U>::value(rhs)), 176 state_.is_valid() && Wrapper<U>::is_valid(rhs)); 177 } 178 179 template <typename U> 180 constexpr CheckedNumeric<typename MathWrapper<CheckedMinOp, T, U>::type> Min( 181 const U rhs) const { 182 using R = typename UnderlyingType<U>::type; 183 using result_type = typename MathWrapper<CheckedMinOp, T, U>::type; 184 // TODO(jschuh): This can be converted to the MathOp version and remain 185 // constexpr once we have C++14 support. 186 return CheckedNumeric<result_type>( 187 static_cast<result_type>( 188 IsLess<T, R>::Test(state_.value(), Wrapper<U>::value(rhs)) 189 ? state_.value() 190 : Wrapper<U>::value(rhs)), 191 state_.is_valid() && Wrapper<U>::is_valid(rhs)); 192 } 193 194 // This function is available only for integral types. It returns an unsigned 195 // integer of the same width as the source type, containing the absolute value 196 // of the source, and properly handling signed min. 197 constexpr CheckedNumeric<typename UnsignedOrFloatForSize<T>::type> 198 UnsignedAbs() const { 199 return CheckedNumeric<typename UnsignedOrFloatForSize<T>::type>( 200 SafeUnsignedAbs(state_.value()), state_.is_valid()); 201 } 202 203 constexpr CheckedNumeric& operator++() { 204 *this += 1; 205 return *this; 206 } 207 208 constexpr CheckedNumeric operator++(int) { 209 CheckedNumeric value = *this; 210 *this += 1; 211 return value; 212 } 213 214 constexpr CheckedNumeric& operator--() { 215 *this -= 1; 216 return *this; 217 } 218 219 constexpr CheckedNumeric operator--(int) { 220 CheckedNumeric value = *this; 221 *this -= 1; 222 return value; 223 } 224 225 // These perform the actual math operations on the CheckedNumerics. 226 // Binary arithmetic operations. 227 template <template <typename, typename, typename> class M, 228 typename L, 229 typename R> 230 static constexpr CheckedNumeric MathOp(const L lhs, const R rhs) { 231 using Math = typename MathWrapper<M, L, R>::math; 232 T result = 0; 233 bool is_valid = 234 Wrapper<L>::is_valid(lhs) && Wrapper<R>::is_valid(rhs) && 235 Math::Do(Wrapper<L>::value(lhs), Wrapper<R>::value(rhs), &result); 236 return CheckedNumeric<T>(result, is_valid); 237 } 238 239 // Assignment arithmetic operations. 240 template <template <typename, typename, typename> class M, typename R> 241 constexpr CheckedNumeric& MathOp(const R rhs) { 242 using Math = typename MathWrapper<M, T, R>::math; 243 T result = 0; // Using T as the destination saves a range check. 244 bool is_valid = state_.is_valid() && Wrapper<R>::is_valid(rhs) && 245 Math::Do(state_.value(), Wrapper<R>::value(rhs), &result); 246 *this = CheckedNumeric<T>(result, is_valid); 247 return *this; 248 } 249 250 private: 251 CheckedNumericState<T> state_; 252 253 CheckedNumeric FastRuntimeNegate() const { 254 T result; 255 bool success = CheckedSubOp<T, T>::Do(T(0), state_.value(), &result); 256 return CheckedNumeric<T>(result, IsValid() && success); 257 } 258 259 template <typename Src> 260 constexpr CheckedNumeric(Src value, bool is_valid) 261 : state_(value, is_valid) {} 262 263 // These wrappers allow us to handle state the same way for both 264 // CheckedNumeric and POD arithmetic types. 265 template <typename Src> 266 struct Wrapper { 267 static constexpr bool is_valid(Src) { return true; } 268 static constexpr Src value(Src value) { return value; } 269 }; 270 271 template <typename Src> 272 struct Wrapper<CheckedNumeric<Src>> { 273 static constexpr bool is_valid(const CheckedNumeric<Src> v) { 274 return v.IsValid(); 275 } 276 static constexpr Src value(const CheckedNumeric<Src> v) { 277 return v.state_.value(); 278 } 279 }; 280 281 template <typename Src> 282 struct Wrapper<StrictNumeric<Src>> { 283 static constexpr bool is_valid(const StrictNumeric<Src>) { return true; } 284 static constexpr Src value(const StrictNumeric<Src> v) { 285 return static_cast<Src>(v); 286 } 287 }; 288}; 289 290// Convenience functions to avoid the ugly template disambiguator syntax. 291template <typename Dst, typename Src> 292constexpr bool IsValidForType(const CheckedNumeric<Src> value) { 293 return value.template IsValid<Dst>(); 294} 295 296template <typename Dst, typename Src> 297constexpr StrictNumeric<Dst> ValueOrDieForType( 298 const CheckedNumeric<Src> value) { 299 return value.template ValueOrDie<Dst>(); 300} 301 302template <typename Dst, typename Src, typename Default> 303constexpr StrictNumeric<Dst> ValueOrDefaultForType( 304 const CheckedNumeric<Src> value, 305 const Default default_value) { 306 return value.template ValueOrDefault<Dst>(default_value); 307} 308 309// Convience wrapper to return a new CheckedNumeric from the provided arithmetic 310// or CheckedNumericType. 311template <typename T> 312constexpr CheckedNumeric<typename UnderlyingType<T>::type> MakeCheckedNum( 313 const T value) { 314 return value; 315} 316 317// These implement the variadic wrapper for the math operations. 318template <template <typename, typename, typename> class M, 319 typename L, 320 typename R> 321constexpr CheckedNumeric<typename MathWrapper<M, L, R>::type> CheckMathOp( 322 const L lhs, 323 const R rhs) { 324 using Math = typename MathWrapper<M, L, R>::math; 325 return CheckedNumeric<typename Math::result_type>::template MathOp<M>(lhs, 326 rhs); 327} 328 329// General purpose wrapper template for arithmetic operations. 330template <template <typename, typename, typename> class M, 331 typename L, 332 typename R, 333 typename... Args> 334constexpr CheckedNumeric<typename ResultType<M, L, R, Args...>::type> 335CheckMathOp(const L lhs, const R rhs, const Args... args) { 336 return CheckMathOp<M>(CheckMathOp<M>(lhs, rhs), args...); 337} 338 339BASE_NUMERIC_ARITHMETIC_OPERATORS(Checked, Check, Add, +, +=) 340BASE_NUMERIC_ARITHMETIC_OPERATORS(Checked, Check, Sub, -, -=) 341BASE_NUMERIC_ARITHMETIC_OPERATORS(Checked, Check, Mul, *, *=) 342BASE_NUMERIC_ARITHMETIC_OPERATORS(Checked, Check, Div, /, /=) 343BASE_NUMERIC_ARITHMETIC_OPERATORS(Checked, Check, Mod, %, %=) 344BASE_NUMERIC_ARITHMETIC_OPERATORS(Checked, Check, Lsh, <<, <<=) 345BASE_NUMERIC_ARITHMETIC_OPERATORS(Checked, Check, Rsh, >>, >>=) 346BASE_NUMERIC_ARITHMETIC_OPERATORS(Checked, Check, And, &, &=) 347BASE_NUMERIC_ARITHMETIC_OPERATORS(Checked, Check, Or, |, |=) 348BASE_NUMERIC_ARITHMETIC_OPERATORS(Checked, Check, Xor, ^, ^=) 349BASE_NUMERIC_ARITHMETIC_VARIADIC(Checked, Check, Max) 350BASE_NUMERIC_ARITHMETIC_VARIADIC(Checked, Check, Min) 351 352// These are some extra StrictNumeric operators to support simple pointer 353// arithmetic with our result types. Since wrapping on a pointer is always 354// bad, we trigger the CHECK condition here. 355template <typename L, typename R> 356L* operator+(L* lhs, const StrictNumeric<R> rhs) { 357 uintptr_t result = CheckAdd(reinterpret_cast<uintptr_t>(lhs), 358 CheckMul(sizeof(L), static_cast<R>(rhs))) 359 .template ValueOrDie<uintptr_t>(); 360 return reinterpret_cast<L*>(result); 361} 362 363template <typename L, typename R> 364L* operator-(L* lhs, const StrictNumeric<R> rhs) { 365 uintptr_t result = CheckSub(reinterpret_cast<uintptr_t>(lhs), 366 CheckMul(sizeof(L), static_cast<R>(rhs))) 367 .template ValueOrDie<uintptr_t>(); 368 return reinterpret_cast<L*>(result); 369} 370 371} // namespace internal 372 373using internal::CheckAdd; 374using internal::CheckAnd; 375using internal::CheckDiv; 376using internal::CheckedNumeric; 377using internal::CheckLsh; 378using internal::CheckMax; 379using internal::CheckMin; 380using internal::CheckMod; 381using internal::CheckMul; 382using internal::CheckOr; 383using internal::CheckRsh; 384using internal::CheckSub; 385using internal::CheckXor; 386using internal::IsValidForType; 387using internal::MakeCheckedNum; 388using internal::ValueOrDefaultForType; 389using internal::ValueOrDieForType; 390 391} // namespace base 392 393#endif // BASE_NUMERICS_CHECKED_MATH_H_ 394