1*6777b538SAndroid Build Coastguard Worker // Copyright 2017 The Chromium Authors 2*6777b538SAndroid Build Coastguard Worker // Use of this source code is governed by a BSD-style license that can be 3*6777b538SAndroid Build Coastguard Worker // found in the LICENSE file. 4*6777b538SAndroid Build Coastguard Worker 5*6777b538SAndroid Build Coastguard Worker #ifndef BASE_NUMERICS_CLAMPED_MATH_IMPL_H_ 6*6777b538SAndroid Build Coastguard Worker #define BASE_NUMERICS_CLAMPED_MATH_IMPL_H_ 7*6777b538SAndroid Build Coastguard Worker 8*6777b538SAndroid Build Coastguard Worker #include <stddef.h> 9*6777b538SAndroid Build Coastguard Worker #include <stdint.h> 10*6777b538SAndroid Build Coastguard Worker 11*6777b538SAndroid Build Coastguard Worker #include <climits> 12*6777b538SAndroid Build Coastguard Worker #include <cmath> 13*6777b538SAndroid Build Coastguard Worker #include <concepts> 14*6777b538SAndroid Build Coastguard Worker #include <cstdlib> 15*6777b538SAndroid Build Coastguard Worker #include <limits> 16*6777b538SAndroid Build Coastguard Worker #include <type_traits> 17*6777b538SAndroid Build Coastguard Worker 18*6777b538SAndroid Build Coastguard Worker #include "base/numerics/checked_math.h" 19*6777b538SAndroid Build Coastguard Worker #include "base/numerics/safe_conversions.h" 20*6777b538SAndroid Build Coastguard Worker #include "base/numerics/safe_math_shared_impl.h" 21*6777b538SAndroid Build Coastguard Worker 22*6777b538SAndroid Build Coastguard Worker namespace base { 23*6777b538SAndroid Build Coastguard Worker namespace internal { 24*6777b538SAndroid Build Coastguard Worker 25*6777b538SAndroid Build Coastguard Worker template <typename T> requires(std::signed_integral<T>)26*6777b538SAndroid Build Coastguard Worker requires(std::signed_integral<T>) 27*6777b538SAndroid Build Coastguard Worker constexpr T SaturatedNegWrapper(T value) { 28*6777b538SAndroid Build Coastguard Worker return IsConstantEvaluated() || !ClampedNegFastOp<T>::is_supported 29*6777b538SAndroid Build Coastguard Worker ? (NegateWrapper(value) != std::numeric_limits<T>::lowest() 30*6777b538SAndroid Build Coastguard Worker ? NegateWrapper(value) 31*6777b538SAndroid Build Coastguard Worker : std::numeric_limits<T>::max()) 32*6777b538SAndroid Build Coastguard Worker : ClampedNegFastOp<T>::Do(value); 33*6777b538SAndroid Build Coastguard Worker } 34*6777b538SAndroid Build Coastguard Worker 35*6777b538SAndroid Build Coastguard Worker template <typename T> requires(std::unsigned_integral<T>)36*6777b538SAndroid Build Coastguard Worker requires(std::unsigned_integral<T>) 37*6777b538SAndroid Build Coastguard Worker constexpr T SaturatedNegWrapper(T value) { 38*6777b538SAndroid Build Coastguard Worker return T(0); 39*6777b538SAndroid Build Coastguard Worker } 40*6777b538SAndroid Build Coastguard Worker 41*6777b538SAndroid Build Coastguard Worker template <typename T> requires(std::floating_point<T>)42*6777b538SAndroid Build Coastguard Worker requires(std::floating_point<T>) 43*6777b538SAndroid Build Coastguard Worker constexpr T SaturatedNegWrapper(T value) { 44*6777b538SAndroid Build Coastguard Worker return -value; 45*6777b538SAndroid Build Coastguard Worker } 46*6777b538SAndroid Build Coastguard Worker 47*6777b538SAndroid Build Coastguard Worker template <typename T> requires(std::integral<T>)48*6777b538SAndroid Build Coastguard Worker requires(std::integral<T>) 49*6777b538SAndroid Build Coastguard Worker constexpr T SaturatedAbsWrapper(T value) { 50*6777b538SAndroid Build Coastguard Worker // The calculation below is a static identity for unsigned types, but for 51*6777b538SAndroid Build Coastguard Worker // signed integer types it provides a non-branching, saturated absolute value. 52*6777b538SAndroid Build Coastguard Worker // This works because SafeUnsignedAbs() returns an unsigned type, which can 53*6777b538SAndroid Build Coastguard Worker // represent the absolute value of all negative numbers of an equal-width 54*6777b538SAndroid Build Coastguard Worker // integer type. The call to IsValueNegative() then detects overflow in the 55*6777b538SAndroid Build Coastguard Worker // special case of numeric_limits<T>::min(), by evaluating the bit pattern as 56*6777b538SAndroid Build Coastguard Worker // a signed integer value. If it is the overflow case, we end up subtracting 57*6777b538SAndroid Build Coastguard Worker // one from the unsigned result, thus saturating to numeric_limits<T>::max(). 58*6777b538SAndroid Build Coastguard Worker return static_cast<T>( 59*6777b538SAndroid Build Coastguard Worker SafeUnsignedAbs(value) - 60*6777b538SAndroid Build Coastguard Worker IsValueNegative<T>(static_cast<T>(SafeUnsignedAbs(value)))); 61*6777b538SAndroid Build Coastguard Worker } 62*6777b538SAndroid Build Coastguard Worker 63*6777b538SAndroid Build Coastguard Worker template <typename T> requires(std::floating_point<T>)64*6777b538SAndroid Build Coastguard Worker requires(std::floating_point<T>) 65*6777b538SAndroid Build Coastguard Worker constexpr T SaturatedAbsWrapper(T value) { 66*6777b538SAndroid Build Coastguard Worker return value < 0 ? -value : value; 67*6777b538SAndroid Build Coastguard Worker } 68*6777b538SAndroid Build Coastguard Worker 69*6777b538SAndroid Build Coastguard Worker template <typename T, typename U> 70*6777b538SAndroid Build Coastguard Worker struct ClampedAddOp {}; 71*6777b538SAndroid Build Coastguard Worker 72*6777b538SAndroid Build Coastguard Worker template <typename T, typename U> 73*6777b538SAndroid Build Coastguard Worker requires(std::integral<T> && std::integral<U>) 74*6777b538SAndroid Build Coastguard Worker struct ClampedAddOp<T, U> { 75*6777b538SAndroid Build Coastguard Worker using result_type = typename MaxExponentPromotion<T, U>::type; 76*6777b538SAndroid Build Coastguard Worker template <typename V = result_type> 77*6777b538SAndroid Build Coastguard Worker static constexpr V Do(T x, U y) { 78*6777b538SAndroid Build Coastguard Worker if (!IsConstantEvaluated() && ClampedAddFastOp<T, U>::is_supported) 79*6777b538SAndroid Build Coastguard Worker return ClampedAddFastOp<T, U>::template Do<V>(x, y); 80*6777b538SAndroid Build Coastguard Worker 81*6777b538SAndroid Build Coastguard Worker static_assert(std::is_same_v<V, result_type> || 82*6777b538SAndroid Build Coastguard Worker IsTypeInRangeForNumericType<U, V>::value, 83*6777b538SAndroid Build Coastguard Worker "The saturation result cannot be determined from the " 84*6777b538SAndroid Build Coastguard Worker "provided types."); 85*6777b538SAndroid Build Coastguard Worker const V saturated = CommonMaxOrMin<V>(IsValueNegative(y)); 86*6777b538SAndroid Build Coastguard Worker V result = {}; 87*6777b538SAndroid Build Coastguard Worker return BASE_NUMERICS_LIKELY((CheckedAddOp<T, U>::Do(x, y, &result))) 88*6777b538SAndroid Build Coastguard Worker ? result 89*6777b538SAndroid Build Coastguard Worker : saturated; 90*6777b538SAndroid Build Coastguard Worker } 91*6777b538SAndroid Build Coastguard Worker }; 92*6777b538SAndroid Build Coastguard Worker 93*6777b538SAndroid Build Coastguard Worker template <typename T, typename U> 94*6777b538SAndroid Build Coastguard Worker struct ClampedSubOp {}; 95*6777b538SAndroid Build Coastguard Worker 96*6777b538SAndroid Build Coastguard Worker template <typename T, typename U> 97*6777b538SAndroid Build Coastguard Worker requires(std::integral<T> && std::integral<U>) 98*6777b538SAndroid Build Coastguard Worker struct ClampedSubOp<T, U> { 99*6777b538SAndroid Build Coastguard Worker using result_type = typename MaxExponentPromotion<T, U>::type; 100*6777b538SAndroid Build Coastguard Worker template <typename V = result_type> 101*6777b538SAndroid Build Coastguard Worker static constexpr V Do(T x, U y) { 102*6777b538SAndroid Build Coastguard Worker if (!IsConstantEvaluated() && ClampedSubFastOp<T, U>::is_supported) 103*6777b538SAndroid Build Coastguard Worker return ClampedSubFastOp<T, U>::template Do<V>(x, y); 104*6777b538SAndroid Build Coastguard Worker 105*6777b538SAndroid Build Coastguard Worker static_assert(std::is_same_v<V, result_type> || 106*6777b538SAndroid Build Coastguard Worker IsTypeInRangeForNumericType<U, V>::value, 107*6777b538SAndroid Build Coastguard Worker "The saturation result cannot be determined from the " 108*6777b538SAndroid Build Coastguard Worker "provided types."); 109*6777b538SAndroid Build Coastguard Worker const V saturated = CommonMaxOrMin<V>(!IsValueNegative(y)); 110*6777b538SAndroid Build Coastguard Worker V result = {}; 111*6777b538SAndroid Build Coastguard Worker return BASE_NUMERICS_LIKELY((CheckedSubOp<T, U>::Do(x, y, &result))) 112*6777b538SAndroid Build Coastguard Worker ? result 113*6777b538SAndroid Build Coastguard Worker : saturated; 114*6777b538SAndroid Build Coastguard Worker } 115*6777b538SAndroid Build Coastguard Worker }; 116*6777b538SAndroid Build Coastguard Worker 117*6777b538SAndroid Build Coastguard Worker template <typename T, typename U> 118*6777b538SAndroid Build Coastguard Worker struct ClampedMulOp {}; 119*6777b538SAndroid Build Coastguard Worker 120*6777b538SAndroid Build Coastguard Worker template <typename T, typename U> 121*6777b538SAndroid Build Coastguard Worker requires(std::integral<T> && std::integral<U>) 122*6777b538SAndroid Build Coastguard Worker struct ClampedMulOp<T, U> { 123*6777b538SAndroid Build Coastguard Worker using result_type = typename MaxExponentPromotion<T, U>::type; 124*6777b538SAndroid Build Coastguard Worker template <typename V = result_type> 125*6777b538SAndroid Build Coastguard Worker static constexpr V Do(T x, U y) { 126*6777b538SAndroid Build Coastguard Worker if (!IsConstantEvaluated() && ClampedMulFastOp<T, U>::is_supported) 127*6777b538SAndroid Build Coastguard Worker return ClampedMulFastOp<T, U>::template Do<V>(x, y); 128*6777b538SAndroid Build Coastguard Worker 129*6777b538SAndroid Build Coastguard Worker V result = {}; 130*6777b538SAndroid Build Coastguard Worker const V saturated = 131*6777b538SAndroid Build Coastguard Worker CommonMaxOrMin<V>(IsValueNegative(x) ^ IsValueNegative(y)); 132*6777b538SAndroid Build Coastguard Worker return BASE_NUMERICS_LIKELY((CheckedMulOp<T, U>::Do(x, y, &result))) 133*6777b538SAndroid Build Coastguard Worker ? result 134*6777b538SAndroid Build Coastguard Worker : saturated; 135*6777b538SAndroid Build Coastguard Worker } 136*6777b538SAndroid Build Coastguard Worker }; 137*6777b538SAndroid Build Coastguard Worker 138*6777b538SAndroid Build Coastguard Worker template <typename T, typename U> 139*6777b538SAndroid Build Coastguard Worker struct ClampedDivOp {}; 140*6777b538SAndroid Build Coastguard Worker 141*6777b538SAndroid Build Coastguard Worker template <typename T, typename U> 142*6777b538SAndroid Build Coastguard Worker requires(std::integral<T> && std::integral<U>) 143*6777b538SAndroid Build Coastguard Worker struct ClampedDivOp<T, U> { 144*6777b538SAndroid Build Coastguard Worker using result_type = typename MaxExponentPromotion<T, U>::type; 145*6777b538SAndroid Build Coastguard Worker template <typename V = result_type> 146*6777b538SAndroid Build Coastguard Worker static constexpr V Do(T x, U y) { 147*6777b538SAndroid Build Coastguard Worker V result = {}; 148*6777b538SAndroid Build Coastguard Worker if (BASE_NUMERICS_LIKELY((CheckedDivOp<T, U>::Do(x, y, &result)))) 149*6777b538SAndroid Build Coastguard Worker return result; 150*6777b538SAndroid Build Coastguard Worker // Saturation goes to max, min, or NaN (if x is zero). 151*6777b538SAndroid Build Coastguard Worker return x ? CommonMaxOrMin<V>(IsValueNegative(x) ^ IsValueNegative(y)) 152*6777b538SAndroid Build Coastguard Worker : SaturationDefaultLimits<V>::NaN(); 153*6777b538SAndroid Build Coastguard Worker } 154*6777b538SAndroid Build Coastguard Worker }; 155*6777b538SAndroid Build Coastguard Worker 156*6777b538SAndroid Build Coastguard Worker template <typename T, typename U> 157*6777b538SAndroid Build Coastguard Worker struct ClampedModOp {}; 158*6777b538SAndroid Build Coastguard Worker 159*6777b538SAndroid Build Coastguard Worker template <typename T, typename U> 160*6777b538SAndroid Build Coastguard Worker requires(std::integral<T> && std::integral<U>) 161*6777b538SAndroid Build Coastguard Worker struct ClampedModOp<T, U> { 162*6777b538SAndroid Build Coastguard Worker using result_type = typename MaxExponentPromotion<T, U>::type; 163*6777b538SAndroid Build Coastguard Worker template <typename V = result_type> 164*6777b538SAndroid Build Coastguard Worker static constexpr V Do(T x, U y) { 165*6777b538SAndroid Build Coastguard Worker V result = {}; 166*6777b538SAndroid Build Coastguard Worker return BASE_NUMERICS_LIKELY((CheckedModOp<T, U>::Do(x, y, &result))) 167*6777b538SAndroid Build Coastguard Worker ? result 168*6777b538SAndroid Build Coastguard Worker : x; 169*6777b538SAndroid Build Coastguard Worker } 170*6777b538SAndroid Build Coastguard Worker }; 171*6777b538SAndroid Build Coastguard Worker 172*6777b538SAndroid Build Coastguard Worker template <typename T, typename U> 173*6777b538SAndroid Build Coastguard Worker struct ClampedLshOp {}; 174*6777b538SAndroid Build Coastguard Worker 175*6777b538SAndroid Build Coastguard Worker // Left shift. Non-zero values saturate in the direction of the sign. A zero 176*6777b538SAndroid Build Coastguard Worker // shifted by any value always results in zero. 177*6777b538SAndroid Build Coastguard Worker template <typename T, typename U> 178*6777b538SAndroid Build Coastguard Worker requires(std::integral<T> && std::integral<U>) 179*6777b538SAndroid Build Coastguard Worker struct ClampedLshOp<T, U> { 180*6777b538SAndroid Build Coastguard Worker using result_type = T; 181*6777b538SAndroid Build Coastguard Worker template <typename V = result_type> 182*6777b538SAndroid Build Coastguard Worker static constexpr V Do(T x, U shift) { 183*6777b538SAndroid Build Coastguard Worker static_assert(!std::is_signed_v<U>, "Shift value must be unsigned."); 184*6777b538SAndroid Build Coastguard Worker if (BASE_NUMERICS_LIKELY(shift < std::numeric_limits<T>::digits)) { 185*6777b538SAndroid Build Coastguard Worker // Shift as unsigned to avoid undefined behavior. 186*6777b538SAndroid Build Coastguard Worker V result = static_cast<V>(as_unsigned(x) << shift); 187*6777b538SAndroid Build Coastguard Worker // If the shift can be reversed, we know it was valid. 188*6777b538SAndroid Build Coastguard Worker if (BASE_NUMERICS_LIKELY(result >> shift == x)) 189*6777b538SAndroid Build Coastguard Worker return result; 190*6777b538SAndroid Build Coastguard Worker } 191*6777b538SAndroid Build Coastguard Worker return x ? CommonMaxOrMin<V>(IsValueNegative(x)) : 0; 192*6777b538SAndroid Build Coastguard Worker } 193*6777b538SAndroid Build Coastguard Worker }; 194*6777b538SAndroid Build Coastguard Worker 195*6777b538SAndroid Build Coastguard Worker template <typename T, typename U> 196*6777b538SAndroid Build Coastguard Worker struct ClampedRshOp {}; 197*6777b538SAndroid Build Coastguard Worker 198*6777b538SAndroid Build Coastguard Worker // Right shift. Negative values saturate to -1. Positive or 0 saturates to 0. 199*6777b538SAndroid Build Coastguard Worker template <typename T, typename U> 200*6777b538SAndroid Build Coastguard Worker requires(std::integral<T> && std::integral<U>) 201*6777b538SAndroid Build Coastguard Worker struct ClampedRshOp<T, U> { 202*6777b538SAndroid Build Coastguard Worker using result_type = T; 203*6777b538SAndroid Build Coastguard Worker template <typename V = result_type> 204*6777b538SAndroid Build Coastguard Worker static constexpr V Do(T x, U shift) { 205*6777b538SAndroid Build Coastguard Worker static_assert(!std::is_signed_v<U>, "Shift value must be unsigned."); 206*6777b538SAndroid Build Coastguard Worker // Signed right shift is odd, because it saturates to -1 or 0. 207*6777b538SAndroid Build Coastguard Worker const V saturated = as_unsigned(V(0)) - IsValueNegative(x); 208*6777b538SAndroid Build Coastguard Worker return BASE_NUMERICS_LIKELY(shift < IntegerBitsPlusSign<T>::value) 209*6777b538SAndroid Build Coastguard Worker ? saturated_cast<V>(x >> shift) 210*6777b538SAndroid Build Coastguard Worker : saturated; 211*6777b538SAndroid Build Coastguard Worker } 212*6777b538SAndroid Build Coastguard Worker }; 213*6777b538SAndroid Build Coastguard Worker 214*6777b538SAndroid Build Coastguard Worker template <typename T, typename U> 215*6777b538SAndroid Build Coastguard Worker struct ClampedAndOp {}; 216*6777b538SAndroid Build Coastguard Worker 217*6777b538SAndroid Build Coastguard Worker template <typename T, typename U> 218*6777b538SAndroid Build Coastguard Worker requires(std::integral<T> && std::integral<U>) 219*6777b538SAndroid Build Coastguard Worker struct ClampedAndOp<T, U> { 220*6777b538SAndroid Build Coastguard Worker using result_type = typename std::make_unsigned< 221*6777b538SAndroid Build Coastguard Worker typename MaxExponentPromotion<T, U>::type>::type; 222*6777b538SAndroid Build Coastguard Worker template <typename V> 223*6777b538SAndroid Build Coastguard Worker static constexpr V Do(T x, U y) { 224*6777b538SAndroid Build Coastguard Worker return static_cast<result_type>(x) & static_cast<result_type>(y); 225*6777b538SAndroid Build Coastguard Worker } 226*6777b538SAndroid Build Coastguard Worker }; 227*6777b538SAndroid Build Coastguard Worker 228*6777b538SAndroid Build Coastguard Worker template <typename T, typename U> 229*6777b538SAndroid Build Coastguard Worker struct ClampedOrOp {}; 230*6777b538SAndroid Build Coastguard Worker 231*6777b538SAndroid Build Coastguard Worker // For simplicity we promote to unsigned integers. 232*6777b538SAndroid Build Coastguard Worker template <typename T, typename U> 233*6777b538SAndroid Build Coastguard Worker requires(std::integral<T> && std::integral<U>) 234*6777b538SAndroid Build Coastguard Worker struct ClampedOrOp<T, U> { 235*6777b538SAndroid Build Coastguard Worker using result_type = typename std::make_unsigned< 236*6777b538SAndroid Build Coastguard Worker typename MaxExponentPromotion<T, U>::type>::type; 237*6777b538SAndroid Build Coastguard Worker template <typename V> 238*6777b538SAndroid Build Coastguard Worker static constexpr V Do(T x, U y) { 239*6777b538SAndroid Build Coastguard Worker return static_cast<result_type>(x) | static_cast<result_type>(y); 240*6777b538SAndroid Build Coastguard Worker } 241*6777b538SAndroid Build Coastguard Worker }; 242*6777b538SAndroid Build Coastguard Worker 243*6777b538SAndroid Build Coastguard Worker template <typename T, typename U> 244*6777b538SAndroid Build Coastguard Worker struct ClampedXorOp {}; 245*6777b538SAndroid Build Coastguard Worker 246*6777b538SAndroid Build Coastguard Worker // For simplicity we support only unsigned integers. 247*6777b538SAndroid Build Coastguard Worker template <typename T, typename U> 248*6777b538SAndroid Build Coastguard Worker requires(std::integral<T> && std::integral<U>) 249*6777b538SAndroid Build Coastguard Worker struct ClampedXorOp<T, U> { 250*6777b538SAndroid Build Coastguard Worker using result_type = typename std::make_unsigned< 251*6777b538SAndroid Build Coastguard Worker typename MaxExponentPromotion<T, U>::type>::type; 252*6777b538SAndroid Build Coastguard Worker template <typename V> 253*6777b538SAndroid Build Coastguard Worker static constexpr V Do(T x, U y) { 254*6777b538SAndroid Build Coastguard Worker return static_cast<result_type>(x) ^ static_cast<result_type>(y); 255*6777b538SAndroid Build Coastguard Worker } 256*6777b538SAndroid Build Coastguard Worker }; 257*6777b538SAndroid Build Coastguard Worker 258*6777b538SAndroid Build Coastguard Worker template <typename T, typename U> 259*6777b538SAndroid Build Coastguard Worker struct ClampedMaxOp {}; 260*6777b538SAndroid Build Coastguard Worker 261*6777b538SAndroid Build Coastguard Worker template <typename T, typename U> 262*6777b538SAndroid Build Coastguard Worker requires(std::is_arithmetic_v<T> && std::is_arithmetic_v<U>) 263*6777b538SAndroid Build Coastguard Worker struct ClampedMaxOp<T, U> { 264*6777b538SAndroid Build Coastguard Worker using result_type = typename MaxExponentPromotion<T, U>::type; 265*6777b538SAndroid Build Coastguard Worker template <typename V = result_type> 266*6777b538SAndroid Build Coastguard Worker static constexpr V Do(T x, U y) { 267*6777b538SAndroid Build Coastguard Worker return IsGreater<T, U>::Test(x, y) ? saturated_cast<V>(x) 268*6777b538SAndroid Build Coastguard Worker : saturated_cast<V>(y); 269*6777b538SAndroid Build Coastguard Worker } 270*6777b538SAndroid Build Coastguard Worker }; 271*6777b538SAndroid Build Coastguard Worker 272*6777b538SAndroid Build Coastguard Worker template <typename T, typename U> 273*6777b538SAndroid Build Coastguard Worker struct ClampedMinOp {}; 274*6777b538SAndroid Build Coastguard Worker 275*6777b538SAndroid Build Coastguard Worker template <typename T, typename U> 276*6777b538SAndroid Build Coastguard Worker requires(std::is_arithmetic_v<T> && std::is_arithmetic_v<U>) 277*6777b538SAndroid Build Coastguard Worker struct ClampedMinOp<T, U> { 278*6777b538SAndroid Build Coastguard Worker using result_type = typename LowestValuePromotion<T, U>::type; 279*6777b538SAndroid Build Coastguard Worker template <typename V = result_type> 280*6777b538SAndroid Build Coastguard Worker static constexpr V Do(T x, U y) { 281*6777b538SAndroid Build Coastguard Worker return IsLess<T, U>::Test(x, y) ? saturated_cast<V>(x) 282*6777b538SAndroid Build Coastguard Worker : saturated_cast<V>(y); 283*6777b538SAndroid Build Coastguard Worker } 284*6777b538SAndroid Build Coastguard Worker }; 285*6777b538SAndroid Build Coastguard Worker 286*6777b538SAndroid Build Coastguard Worker // This is just boilerplate that wraps the standard floating point arithmetic. 287*6777b538SAndroid Build Coastguard Worker // A macro isn't the nicest solution, but it beats rewriting these repeatedly. 288*6777b538SAndroid Build Coastguard Worker #define BASE_FLOAT_ARITHMETIC_OPS(NAME, OP) \ 289*6777b538SAndroid Build Coastguard Worker template <typename T, typename U> \ 290*6777b538SAndroid Build Coastguard Worker requires(std::floating_point<T> || std::floating_point<U>) \ 291*6777b538SAndroid Build Coastguard Worker struct Clamped##NAME##Op<T, U> { \ 292*6777b538SAndroid Build Coastguard Worker using result_type = typename MaxExponentPromotion<T, U>::type; \ 293*6777b538SAndroid Build Coastguard Worker template <typename V = result_type> \ 294*6777b538SAndroid Build Coastguard Worker static constexpr V Do(T x, U y) { \ 295*6777b538SAndroid Build Coastguard Worker return saturated_cast<V>(x OP y); \ 296*6777b538SAndroid Build Coastguard Worker } \ 297*6777b538SAndroid Build Coastguard Worker }; 298*6777b538SAndroid Build Coastguard Worker 299*6777b538SAndroid Build Coastguard Worker BASE_FLOAT_ARITHMETIC_OPS(Add, +) 300*6777b538SAndroid Build Coastguard Worker BASE_FLOAT_ARITHMETIC_OPS(Sub, -) 301*6777b538SAndroid Build Coastguard Worker BASE_FLOAT_ARITHMETIC_OPS(Mul, *) 302*6777b538SAndroid Build Coastguard Worker BASE_FLOAT_ARITHMETIC_OPS(Div, /) 303*6777b538SAndroid Build Coastguard Worker 304*6777b538SAndroid Build Coastguard Worker #undef BASE_FLOAT_ARITHMETIC_OPS 305*6777b538SAndroid Build Coastguard Worker 306*6777b538SAndroid Build Coastguard Worker } // namespace internal 307*6777b538SAndroid Build Coastguard Worker } // namespace base 308*6777b538SAndroid Build Coastguard Worker 309*6777b538SAndroid Build Coastguard Worker #endif // BASE_NUMERICS_CLAMPED_MATH_IMPL_H_ 310