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