xref: /aosp_15_r20/external/cronet/base/numerics/clamped_math_impl.h (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
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