16d528ed9Sopenharmony_ci// Copyright 2017 The Chromium Authors. All rights reserved. 26d528ed9Sopenharmony_ci// Use of this source code is governed by a BSD-style license that can be 36d528ed9Sopenharmony_ci// found in the LICENSE file. 46d528ed9Sopenharmony_ci 56d528ed9Sopenharmony_ci#ifndef BASE_NUMERICS_CHECKED_MATH_H_ 66d528ed9Sopenharmony_ci#define BASE_NUMERICS_CHECKED_MATH_H_ 76d528ed9Sopenharmony_ci 86d528ed9Sopenharmony_ci#include <stddef.h> 96d528ed9Sopenharmony_ci 106d528ed9Sopenharmony_ci#include <limits> 116d528ed9Sopenharmony_ci#include <type_traits> 126d528ed9Sopenharmony_ci 136d528ed9Sopenharmony_ci#include "base/numerics/checked_math_impl.h" 146d528ed9Sopenharmony_ci 156d528ed9Sopenharmony_cinamespace base { 166d528ed9Sopenharmony_cinamespace internal { 176d528ed9Sopenharmony_ci 186d528ed9Sopenharmony_citemplate <typename T> 196d528ed9Sopenharmony_ciclass CheckedNumeric { 206d528ed9Sopenharmony_ci static_assert(std::is_arithmetic<T>::value, 216d528ed9Sopenharmony_ci "CheckedNumeric<T>: T must be a numeric type."); 226d528ed9Sopenharmony_ci 236d528ed9Sopenharmony_ci public: 246d528ed9Sopenharmony_ci using type = T; 256d528ed9Sopenharmony_ci 266d528ed9Sopenharmony_ci constexpr CheckedNumeric() = default; 276d528ed9Sopenharmony_ci 286d528ed9Sopenharmony_ci // Copy constructor. 296d528ed9Sopenharmony_ci template <typename Src> 306d528ed9Sopenharmony_ci constexpr CheckedNumeric(const CheckedNumeric<Src>& rhs) 316d528ed9Sopenharmony_ci : state_(rhs.state_.value(), rhs.IsValid()) {} 326d528ed9Sopenharmony_ci 336d528ed9Sopenharmony_ci template <typename Src> 346d528ed9Sopenharmony_ci friend class CheckedNumeric; 356d528ed9Sopenharmony_ci 366d528ed9Sopenharmony_ci // This is not an explicit constructor because we implicitly upgrade regular 376d528ed9Sopenharmony_ci // numerics to CheckedNumerics to make them easier to use. 386d528ed9Sopenharmony_ci template <typename Src> 396d528ed9Sopenharmony_ci constexpr CheckedNumeric(Src value) // NOLINT(runtime/explicit) 406d528ed9Sopenharmony_ci : state_(value) { 416d528ed9Sopenharmony_ci static_assert(std::is_arithmetic<Src>::value, "Argument must be numeric."); 426d528ed9Sopenharmony_ci } 436d528ed9Sopenharmony_ci 446d528ed9Sopenharmony_ci // This is not an explicit constructor because we want a seamless conversion 456d528ed9Sopenharmony_ci // from StrictNumeric types. 466d528ed9Sopenharmony_ci template <typename Src> 476d528ed9Sopenharmony_ci constexpr CheckedNumeric( 486d528ed9Sopenharmony_ci StrictNumeric<Src> value) // NOLINT(runtime/explicit) 496d528ed9Sopenharmony_ci : state_(static_cast<Src>(value)) {} 506d528ed9Sopenharmony_ci 516d528ed9Sopenharmony_ci // IsValid() - The public API to test if a CheckedNumeric is currently valid. 526d528ed9Sopenharmony_ci // A range checked destination type can be supplied using the Dst template 536d528ed9Sopenharmony_ci // parameter. 546d528ed9Sopenharmony_ci template <typename Dst = T> 556d528ed9Sopenharmony_ci constexpr bool IsValid() const { 566d528ed9Sopenharmony_ci return state_.is_valid() && 576d528ed9Sopenharmony_ci IsValueInRangeForNumericType<Dst>(state_.value()); 586d528ed9Sopenharmony_ci } 596d528ed9Sopenharmony_ci 606d528ed9Sopenharmony_ci // AssignIfValid(Dst) - Assigns the underlying value if it is currently valid 616d528ed9Sopenharmony_ci // and is within the range supported by the destination type. Returns true if 626d528ed9Sopenharmony_ci // successful and false otherwise. 636d528ed9Sopenharmony_ci template <typename Dst> 646d528ed9Sopenharmony_ci#if defined(__clang__) || defined(__GNUC__) 656d528ed9Sopenharmony_ci __attribute__((warn_unused_result)) 666d528ed9Sopenharmony_ci#elif defined(_MSC_VER) 676d528ed9Sopenharmony_ci _Check_return_ 686d528ed9Sopenharmony_ci#endif 696d528ed9Sopenharmony_ci constexpr bool 706d528ed9Sopenharmony_ci AssignIfValid(Dst* result) const { 716d528ed9Sopenharmony_ci return BASE_NUMERICS_LIKELY(IsValid<Dst>()) 726d528ed9Sopenharmony_ci ? ((*result = static_cast<Dst>(state_.value())), true) 736d528ed9Sopenharmony_ci : false; 746d528ed9Sopenharmony_ci } 756d528ed9Sopenharmony_ci 766d528ed9Sopenharmony_ci // ValueOrDie() - The primary accessor for the underlying value. If the 776d528ed9Sopenharmony_ci // current state is not valid it will CHECK and crash. 786d528ed9Sopenharmony_ci // A range checked destination type can be supplied using the Dst template 796d528ed9Sopenharmony_ci // parameter, which will trigger a CHECK if the value is not in bounds for 806d528ed9Sopenharmony_ci // the destination. 816d528ed9Sopenharmony_ci // The CHECK behavior can be overridden by supplying a handler as a 826d528ed9Sopenharmony_ci // template parameter, for test code, etc. However, the handler cannot access 836d528ed9Sopenharmony_ci // the underlying value, and it is not available through other means. 846d528ed9Sopenharmony_ci template <typename Dst = T, class CheckHandler = CheckOnFailure> 856d528ed9Sopenharmony_ci constexpr StrictNumeric<Dst> ValueOrDie() const { 866d528ed9Sopenharmony_ci return BASE_NUMERICS_LIKELY(IsValid<Dst>()) 876d528ed9Sopenharmony_ci ? static_cast<Dst>(state_.value()) 886d528ed9Sopenharmony_ci : CheckHandler::template HandleFailure<Dst>(); 896d528ed9Sopenharmony_ci } 906d528ed9Sopenharmony_ci 916d528ed9Sopenharmony_ci // ValueOrDefault(T default_value) - A convenience method that returns the 926d528ed9Sopenharmony_ci // current value if the state is valid, and the supplied default_value for 936d528ed9Sopenharmony_ci // any other state. 946d528ed9Sopenharmony_ci // A range checked destination type can be supplied using the Dst template 956d528ed9Sopenharmony_ci // parameter. WARNING: This function may fail to compile or CHECK at runtime 966d528ed9Sopenharmony_ci // if the supplied default_value is not within range of the destination type. 976d528ed9Sopenharmony_ci template <typename Dst = T, typename Src> 986d528ed9Sopenharmony_ci constexpr StrictNumeric<Dst> ValueOrDefault(const Src default_value) const { 996d528ed9Sopenharmony_ci return BASE_NUMERICS_LIKELY(IsValid<Dst>()) 1006d528ed9Sopenharmony_ci ? static_cast<Dst>(state_.value()) 1016d528ed9Sopenharmony_ci : checked_cast<Dst>(default_value); 1026d528ed9Sopenharmony_ci } 1036d528ed9Sopenharmony_ci 1046d528ed9Sopenharmony_ci // Returns a checked numeric of the specified type, cast from the current 1056d528ed9Sopenharmony_ci // CheckedNumeric. If the current state is invalid or the destination cannot 1066d528ed9Sopenharmony_ci // represent the result then the returned CheckedNumeric will be invalid. 1076d528ed9Sopenharmony_ci template <typename Dst> 1086d528ed9Sopenharmony_ci constexpr CheckedNumeric<typename UnderlyingType<Dst>::type> Cast() const { 1096d528ed9Sopenharmony_ci return *this; 1106d528ed9Sopenharmony_ci } 1116d528ed9Sopenharmony_ci 1126d528ed9Sopenharmony_ci // This friend method is available solely for providing more detailed logging 1136d528ed9Sopenharmony_ci // in the the tests. Do not implement it in production code, because the 1146d528ed9Sopenharmony_ci // underlying values may change at any time. 1156d528ed9Sopenharmony_ci template <typename U> 1166d528ed9Sopenharmony_ci friend U GetNumericValueForTest(const CheckedNumeric<U>& src); 1176d528ed9Sopenharmony_ci 1186d528ed9Sopenharmony_ci // Prototypes for the supported arithmetic operator overloads. 1196d528ed9Sopenharmony_ci template <typename Src> 1206d528ed9Sopenharmony_ci constexpr CheckedNumeric& operator+=(const Src rhs); 1216d528ed9Sopenharmony_ci template <typename Src> 1226d528ed9Sopenharmony_ci constexpr CheckedNumeric& operator-=(const Src rhs); 1236d528ed9Sopenharmony_ci template <typename Src> 1246d528ed9Sopenharmony_ci constexpr CheckedNumeric& operator*=(const Src rhs); 1256d528ed9Sopenharmony_ci template <typename Src> 1266d528ed9Sopenharmony_ci constexpr CheckedNumeric& operator/=(const Src rhs); 1276d528ed9Sopenharmony_ci template <typename Src> 1286d528ed9Sopenharmony_ci constexpr CheckedNumeric& operator%=(const Src rhs); 1296d528ed9Sopenharmony_ci template <typename Src> 1306d528ed9Sopenharmony_ci constexpr CheckedNumeric& operator<<=(const Src rhs); 1316d528ed9Sopenharmony_ci template <typename Src> 1326d528ed9Sopenharmony_ci constexpr CheckedNumeric& operator>>=(const Src rhs); 1336d528ed9Sopenharmony_ci template <typename Src> 1346d528ed9Sopenharmony_ci constexpr CheckedNumeric& operator&=(const Src rhs); 1356d528ed9Sopenharmony_ci template <typename Src> 1366d528ed9Sopenharmony_ci constexpr CheckedNumeric& operator|=(const Src rhs); 1376d528ed9Sopenharmony_ci template <typename Src> 1386d528ed9Sopenharmony_ci constexpr CheckedNumeric& operator^=(const Src rhs); 1396d528ed9Sopenharmony_ci 1406d528ed9Sopenharmony_ci constexpr CheckedNumeric operator-() const { 1416d528ed9Sopenharmony_ci // The negation of two's complement int min is int min, so we simply 1426d528ed9Sopenharmony_ci // check for that in the constexpr case. 1436d528ed9Sopenharmony_ci // We use an optimized code path for a known run-time variable. 1446d528ed9Sopenharmony_ci return MustTreatAsConstexpr(state_.value()) || !std::is_signed<T>::value || 1456d528ed9Sopenharmony_ci std::is_floating_point<T>::value 1466d528ed9Sopenharmony_ci ? CheckedNumeric<T>( 1476d528ed9Sopenharmony_ci NegateWrapper(state_.value()), 1486d528ed9Sopenharmony_ci IsValid() && (!std::is_signed<T>::value || 1496d528ed9Sopenharmony_ci std::is_floating_point<T>::value || 1506d528ed9Sopenharmony_ci NegateWrapper(state_.value()) != 1516d528ed9Sopenharmony_ci std::numeric_limits<T>::lowest())) 1526d528ed9Sopenharmony_ci : FastRuntimeNegate(); 1536d528ed9Sopenharmony_ci } 1546d528ed9Sopenharmony_ci 1556d528ed9Sopenharmony_ci constexpr CheckedNumeric operator~() const { 1566d528ed9Sopenharmony_ci return CheckedNumeric<decltype(InvertWrapper(T()))>( 1576d528ed9Sopenharmony_ci InvertWrapper(state_.value()), IsValid()); 1586d528ed9Sopenharmony_ci } 1596d528ed9Sopenharmony_ci 1606d528ed9Sopenharmony_ci constexpr CheckedNumeric Abs() const { 1616d528ed9Sopenharmony_ci return !IsValueNegative(state_.value()) ? *this : -*this; 1626d528ed9Sopenharmony_ci } 1636d528ed9Sopenharmony_ci 1646d528ed9Sopenharmony_ci template <typename U> 1656d528ed9Sopenharmony_ci constexpr CheckedNumeric<typename MathWrapper<CheckedMaxOp, T, U>::type> Max( 1666d528ed9Sopenharmony_ci const U rhs) const { 1676d528ed9Sopenharmony_ci using R = typename UnderlyingType<U>::type; 1686d528ed9Sopenharmony_ci using result_type = typename MathWrapper<CheckedMaxOp, T, U>::type; 1696d528ed9Sopenharmony_ci // TODO(jschuh): This can be converted to the MathOp version and remain 1706d528ed9Sopenharmony_ci // constexpr once we have C++14 support. 1716d528ed9Sopenharmony_ci return CheckedNumeric<result_type>( 1726d528ed9Sopenharmony_ci static_cast<result_type>( 1736d528ed9Sopenharmony_ci IsGreater<T, R>::Test(state_.value(), Wrapper<U>::value(rhs)) 1746d528ed9Sopenharmony_ci ? state_.value() 1756d528ed9Sopenharmony_ci : Wrapper<U>::value(rhs)), 1766d528ed9Sopenharmony_ci state_.is_valid() && Wrapper<U>::is_valid(rhs)); 1776d528ed9Sopenharmony_ci } 1786d528ed9Sopenharmony_ci 1796d528ed9Sopenharmony_ci template <typename U> 1806d528ed9Sopenharmony_ci constexpr CheckedNumeric<typename MathWrapper<CheckedMinOp, T, U>::type> Min( 1816d528ed9Sopenharmony_ci const U rhs) const { 1826d528ed9Sopenharmony_ci using R = typename UnderlyingType<U>::type; 1836d528ed9Sopenharmony_ci using result_type = typename MathWrapper<CheckedMinOp, T, U>::type; 1846d528ed9Sopenharmony_ci // TODO(jschuh): This can be converted to the MathOp version and remain 1856d528ed9Sopenharmony_ci // constexpr once we have C++14 support. 1866d528ed9Sopenharmony_ci return CheckedNumeric<result_type>( 1876d528ed9Sopenharmony_ci static_cast<result_type>( 1886d528ed9Sopenharmony_ci IsLess<T, R>::Test(state_.value(), Wrapper<U>::value(rhs)) 1896d528ed9Sopenharmony_ci ? state_.value() 1906d528ed9Sopenharmony_ci : Wrapper<U>::value(rhs)), 1916d528ed9Sopenharmony_ci state_.is_valid() && Wrapper<U>::is_valid(rhs)); 1926d528ed9Sopenharmony_ci } 1936d528ed9Sopenharmony_ci 1946d528ed9Sopenharmony_ci // This function is available only for integral types. It returns an unsigned 1956d528ed9Sopenharmony_ci // integer of the same width as the source type, containing the absolute value 1966d528ed9Sopenharmony_ci // of the source, and properly handling signed min. 1976d528ed9Sopenharmony_ci constexpr CheckedNumeric<typename UnsignedOrFloatForSize<T>::type> 1986d528ed9Sopenharmony_ci UnsignedAbs() const { 1996d528ed9Sopenharmony_ci return CheckedNumeric<typename UnsignedOrFloatForSize<T>::type>( 2006d528ed9Sopenharmony_ci SafeUnsignedAbs(state_.value()), state_.is_valid()); 2016d528ed9Sopenharmony_ci } 2026d528ed9Sopenharmony_ci 2036d528ed9Sopenharmony_ci constexpr CheckedNumeric& operator++() { 2046d528ed9Sopenharmony_ci *this += 1; 2056d528ed9Sopenharmony_ci return *this; 2066d528ed9Sopenharmony_ci } 2076d528ed9Sopenharmony_ci 2086d528ed9Sopenharmony_ci constexpr CheckedNumeric operator++(int) { 2096d528ed9Sopenharmony_ci CheckedNumeric value = *this; 2106d528ed9Sopenharmony_ci *this += 1; 2116d528ed9Sopenharmony_ci return value; 2126d528ed9Sopenharmony_ci } 2136d528ed9Sopenharmony_ci 2146d528ed9Sopenharmony_ci constexpr CheckedNumeric& operator--() { 2156d528ed9Sopenharmony_ci *this -= 1; 2166d528ed9Sopenharmony_ci return *this; 2176d528ed9Sopenharmony_ci } 2186d528ed9Sopenharmony_ci 2196d528ed9Sopenharmony_ci constexpr CheckedNumeric operator--(int) { 2206d528ed9Sopenharmony_ci CheckedNumeric value = *this; 2216d528ed9Sopenharmony_ci *this -= 1; 2226d528ed9Sopenharmony_ci return value; 2236d528ed9Sopenharmony_ci } 2246d528ed9Sopenharmony_ci 2256d528ed9Sopenharmony_ci // These perform the actual math operations on the CheckedNumerics. 2266d528ed9Sopenharmony_ci // Binary arithmetic operations. 2276d528ed9Sopenharmony_ci template <template <typename, typename, typename> class M, 2286d528ed9Sopenharmony_ci typename L, 2296d528ed9Sopenharmony_ci typename R> 2306d528ed9Sopenharmony_ci static constexpr CheckedNumeric MathOp(const L lhs, const R rhs) { 2316d528ed9Sopenharmony_ci using Math = typename MathWrapper<M, L, R>::math; 2326d528ed9Sopenharmony_ci T result = 0; 2336d528ed9Sopenharmony_ci bool is_valid = 2346d528ed9Sopenharmony_ci Wrapper<L>::is_valid(lhs) && Wrapper<R>::is_valid(rhs) && 2356d528ed9Sopenharmony_ci Math::Do(Wrapper<L>::value(lhs), Wrapper<R>::value(rhs), &result); 2366d528ed9Sopenharmony_ci return CheckedNumeric<T>(result, is_valid); 2376d528ed9Sopenharmony_ci } 2386d528ed9Sopenharmony_ci 2396d528ed9Sopenharmony_ci // Assignment arithmetic operations. 2406d528ed9Sopenharmony_ci template <template <typename, typename, typename> class M, typename R> 2416d528ed9Sopenharmony_ci constexpr CheckedNumeric& MathOp(const R rhs) { 2426d528ed9Sopenharmony_ci using Math = typename MathWrapper<M, T, R>::math; 2436d528ed9Sopenharmony_ci T result = 0; // Using T as the destination saves a range check. 2446d528ed9Sopenharmony_ci bool is_valid = state_.is_valid() && Wrapper<R>::is_valid(rhs) && 2456d528ed9Sopenharmony_ci Math::Do(state_.value(), Wrapper<R>::value(rhs), &result); 2466d528ed9Sopenharmony_ci *this = CheckedNumeric<T>(result, is_valid); 2476d528ed9Sopenharmony_ci return *this; 2486d528ed9Sopenharmony_ci } 2496d528ed9Sopenharmony_ci 2506d528ed9Sopenharmony_ci private: 2516d528ed9Sopenharmony_ci CheckedNumericState<T> state_; 2526d528ed9Sopenharmony_ci 2536d528ed9Sopenharmony_ci CheckedNumeric FastRuntimeNegate() const { 2546d528ed9Sopenharmony_ci T result; 2556d528ed9Sopenharmony_ci bool success = CheckedSubOp<T, T>::Do(T(0), state_.value(), &result); 2566d528ed9Sopenharmony_ci return CheckedNumeric<T>(result, IsValid() && success); 2576d528ed9Sopenharmony_ci } 2586d528ed9Sopenharmony_ci 2596d528ed9Sopenharmony_ci template <typename Src> 2606d528ed9Sopenharmony_ci constexpr CheckedNumeric(Src value, bool is_valid) 2616d528ed9Sopenharmony_ci : state_(value, is_valid) {} 2626d528ed9Sopenharmony_ci 2636d528ed9Sopenharmony_ci // These wrappers allow us to handle state the same way for both 2646d528ed9Sopenharmony_ci // CheckedNumeric and POD arithmetic types. 2656d528ed9Sopenharmony_ci template <typename Src> 2666d528ed9Sopenharmony_ci struct Wrapper { 2676d528ed9Sopenharmony_ci static constexpr bool is_valid(Src) { return true; } 2686d528ed9Sopenharmony_ci static constexpr Src value(Src value) { return value; } 2696d528ed9Sopenharmony_ci }; 2706d528ed9Sopenharmony_ci 2716d528ed9Sopenharmony_ci template <typename Src> 2726d528ed9Sopenharmony_ci struct Wrapper<CheckedNumeric<Src>> { 2736d528ed9Sopenharmony_ci static constexpr bool is_valid(const CheckedNumeric<Src> v) { 2746d528ed9Sopenharmony_ci return v.IsValid(); 2756d528ed9Sopenharmony_ci } 2766d528ed9Sopenharmony_ci static constexpr Src value(const CheckedNumeric<Src> v) { 2776d528ed9Sopenharmony_ci return v.state_.value(); 2786d528ed9Sopenharmony_ci } 2796d528ed9Sopenharmony_ci }; 2806d528ed9Sopenharmony_ci 2816d528ed9Sopenharmony_ci template <typename Src> 2826d528ed9Sopenharmony_ci struct Wrapper<StrictNumeric<Src>> { 2836d528ed9Sopenharmony_ci static constexpr bool is_valid(const StrictNumeric<Src>) { return true; } 2846d528ed9Sopenharmony_ci static constexpr Src value(const StrictNumeric<Src> v) { 2856d528ed9Sopenharmony_ci return static_cast<Src>(v); 2866d528ed9Sopenharmony_ci } 2876d528ed9Sopenharmony_ci }; 2886d528ed9Sopenharmony_ci}; 2896d528ed9Sopenharmony_ci 2906d528ed9Sopenharmony_ci// Convenience functions to avoid the ugly template disambiguator syntax. 2916d528ed9Sopenharmony_citemplate <typename Dst, typename Src> 2926d528ed9Sopenharmony_ciconstexpr bool IsValidForType(const CheckedNumeric<Src> value) { 2936d528ed9Sopenharmony_ci return value.template IsValid<Dst>(); 2946d528ed9Sopenharmony_ci} 2956d528ed9Sopenharmony_ci 2966d528ed9Sopenharmony_citemplate <typename Dst, typename Src> 2976d528ed9Sopenharmony_ciconstexpr StrictNumeric<Dst> ValueOrDieForType( 2986d528ed9Sopenharmony_ci const CheckedNumeric<Src> value) { 2996d528ed9Sopenharmony_ci return value.template ValueOrDie<Dst>(); 3006d528ed9Sopenharmony_ci} 3016d528ed9Sopenharmony_ci 3026d528ed9Sopenharmony_citemplate <typename Dst, typename Src, typename Default> 3036d528ed9Sopenharmony_ciconstexpr StrictNumeric<Dst> ValueOrDefaultForType( 3046d528ed9Sopenharmony_ci const CheckedNumeric<Src> value, 3056d528ed9Sopenharmony_ci const Default default_value) { 3066d528ed9Sopenharmony_ci return value.template ValueOrDefault<Dst>(default_value); 3076d528ed9Sopenharmony_ci} 3086d528ed9Sopenharmony_ci 3096d528ed9Sopenharmony_ci// Convience wrapper to return a new CheckedNumeric from the provided arithmetic 3106d528ed9Sopenharmony_ci// or CheckedNumericType. 3116d528ed9Sopenharmony_citemplate <typename T> 3126d528ed9Sopenharmony_ciconstexpr CheckedNumeric<typename UnderlyingType<T>::type> MakeCheckedNum( 3136d528ed9Sopenharmony_ci const T value) { 3146d528ed9Sopenharmony_ci return value; 3156d528ed9Sopenharmony_ci} 3166d528ed9Sopenharmony_ci 3176d528ed9Sopenharmony_ci// These implement the variadic wrapper for the math operations. 3186d528ed9Sopenharmony_citemplate <template <typename, typename, typename> class M, 3196d528ed9Sopenharmony_ci typename L, 3206d528ed9Sopenharmony_ci typename R> 3216d528ed9Sopenharmony_ciconstexpr CheckedNumeric<typename MathWrapper<M, L, R>::type> CheckMathOp( 3226d528ed9Sopenharmony_ci const L lhs, 3236d528ed9Sopenharmony_ci const R rhs) { 3246d528ed9Sopenharmony_ci using Math = typename MathWrapper<M, L, R>::math; 3256d528ed9Sopenharmony_ci return CheckedNumeric<typename Math::result_type>::template MathOp<M>(lhs, 3266d528ed9Sopenharmony_ci rhs); 3276d528ed9Sopenharmony_ci} 3286d528ed9Sopenharmony_ci 3296d528ed9Sopenharmony_ci// General purpose wrapper template for arithmetic operations. 3306d528ed9Sopenharmony_citemplate <template <typename, typename, typename> class M, 3316d528ed9Sopenharmony_ci typename L, 3326d528ed9Sopenharmony_ci typename R, 3336d528ed9Sopenharmony_ci typename... Args> 3346d528ed9Sopenharmony_ciconstexpr CheckedNumeric<typename ResultType<M, L, R, Args...>::type> 3356d528ed9Sopenharmony_ciCheckMathOp(const L lhs, const R rhs, const Args... args) { 3366d528ed9Sopenharmony_ci return CheckMathOp<M>(CheckMathOp<M>(lhs, rhs), args...); 3376d528ed9Sopenharmony_ci} 3386d528ed9Sopenharmony_ci 3396d528ed9Sopenharmony_ciBASE_NUMERIC_ARITHMETIC_OPERATORS(Checked, Check, Add, +, +=) 3406d528ed9Sopenharmony_ciBASE_NUMERIC_ARITHMETIC_OPERATORS(Checked, Check, Sub, -, -=) 3416d528ed9Sopenharmony_ciBASE_NUMERIC_ARITHMETIC_OPERATORS(Checked, Check, Mul, *, *=) 3426d528ed9Sopenharmony_ciBASE_NUMERIC_ARITHMETIC_OPERATORS(Checked, Check, Div, /, /=) 3436d528ed9Sopenharmony_ciBASE_NUMERIC_ARITHMETIC_OPERATORS(Checked, Check, Mod, %, %=) 3446d528ed9Sopenharmony_ciBASE_NUMERIC_ARITHMETIC_OPERATORS(Checked, Check, Lsh, <<, <<=) 3456d528ed9Sopenharmony_ciBASE_NUMERIC_ARITHMETIC_OPERATORS(Checked, Check, Rsh, >>, >>=) 3466d528ed9Sopenharmony_ciBASE_NUMERIC_ARITHMETIC_OPERATORS(Checked, Check, And, &, &=) 3476d528ed9Sopenharmony_ciBASE_NUMERIC_ARITHMETIC_OPERATORS(Checked, Check, Or, |, |=) 3486d528ed9Sopenharmony_ciBASE_NUMERIC_ARITHMETIC_OPERATORS(Checked, Check, Xor, ^, ^=) 3496d528ed9Sopenharmony_ciBASE_NUMERIC_ARITHMETIC_VARIADIC(Checked, Check, Max) 3506d528ed9Sopenharmony_ciBASE_NUMERIC_ARITHMETIC_VARIADIC(Checked, Check, Min) 3516d528ed9Sopenharmony_ci 3526d528ed9Sopenharmony_ci// These are some extra StrictNumeric operators to support simple pointer 3536d528ed9Sopenharmony_ci// arithmetic with our result types. Since wrapping on a pointer is always 3546d528ed9Sopenharmony_ci// bad, we trigger the CHECK condition here. 3556d528ed9Sopenharmony_citemplate <typename L, typename R> 3566d528ed9Sopenharmony_ciL* operator+(L* lhs, const StrictNumeric<R> rhs) { 3576d528ed9Sopenharmony_ci uintptr_t result = CheckAdd(reinterpret_cast<uintptr_t>(lhs), 3586d528ed9Sopenharmony_ci CheckMul(sizeof(L), static_cast<R>(rhs))) 3596d528ed9Sopenharmony_ci .template ValueOrDie<uintptr_t>(); 3606d528ed9Sopenharmony_ci return reinterpret_cast<L*>(result); 3616d528ed9Sopenharmony_ci} 3626d528ed9Sopenharmony_ci 3636d528ed9Sopenharmony_citemplate <typename L, typename R> 3646d528ed9Sopenharmony_ciL* operator-(L* lhs, const StrictNumeric<R> rhs) { 3656d528ed9Sopenharmony_ci uintptr_t result = CheckSub(reinterpret_cast<uintptr_t>(lhs), 3666d528ed9Sopenharmony_ci CheckMul(sizeof(L), static_cast<R>(rhs))) 3676d528ed9Sopenharmony_ci .template ValueOrDie<uintptr_t>(); 3686d528ed9Sopenharmony_ci return reinterpret_cast<L*>(result); 3696d528ed9Sopenharmony_ci} 3706d528ed9Sopenharmony_ci 3716d528ed9Sopenharmony_ci} // namespace internal 3726d528ed9Sopenharmony_ci 3736d528ed9Sopenharmony_ciusing internal::CheckAdd; 3746d528ed9Sopenharmony_ciusing internal::CheckAnd; 3756d528ed9Sopenharmony_ciusing internal::CheckDiv; 3766d528ed9Sopenharmony_ciusing internal::CheckedNumeric; 3776d528ed9Sopenharmony_ciusing internal::CheckLsh; 3786d528ed9Sopenharmony_ciusing internal::CheckMax; 3796d528ed9Sopenharmony_ciusing internal::CheckMin; 3806d528ed9Sopenharmony_ciusing internal::CheckMod; 3816d528ed9Sopenharmony_ciusing internal::CheckMul; 3826d528ed9Sopenharmony_ciusing internal::CheckOr; 3836d528ed9Sopenharmony_ciusing internal::CheckRsh; 3846d528ed9Sopenharmony_ciusing internal::CheckSub; 3856d528ed9Sopenharmony_ciusing internal::CheckXor; 3866d528ed9Sopenharmony_ciusing internal::IsValidForType; 3876d528ed9Sopenharmony_ciusing internal::MakeCheckedNum; 3886d528ed9Sopenharmony_ciusing internal::ValueOrDefaultForType; 3896d528ed9Sopenharmony_ciusing internal::ValueOrDieForType; 3906d528ed9Sopenharmony_ci 3916d528ed9Sopenharmony_ci} // namespace base 3926d528ed9Sopenharmony_ci 3936d528ed9Sopenharmony_ci#endif // BASE_NUMERICS_CHECKED_MATH_H_ 394