xref: /aosp_15_r20/external/cronet/base/numerics/checked_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_CHECKED_MATH_IMPL_H_
6*6777b538SAndroid Build Coastguard Worker #define BASE_NUMERICS_CHECKED_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/safe_conversions.h"
19*6777b538SAndroid Build Coastguard Worker #include "base/numerics/safe_math_shared_impl.h"
20*6777b538SAndroid Build Coastguard Worker 
21*6777b538SAndroid Build Coastguard Worker namespace base {
22*6777b538SAndroid Build Coastguard Worker namespace internal {
23*6777b538SAndroid Build Coastguard Worker 
24*6777b538SAndroid Build Coastguard Worker template <typename T>
CheckedAddImpl(T x,T y,T * result)25*6777b538SAndroid Build Coastguard Worker constexpr bool CheckedAddImpl(T x, T y, T* result) {
26*6777b538SAndroid Build Coastguard Worker   static_assert(std::is_integral_v<T>, "Type must be integral");
27*6777b538SAndroid Build Coastguard Worker   // Since the value of x+y is undefined if we have a signed type, we compute
28*6777b538SAndroid Build Coastguard Worker   // it using the unsigned type of the same size.
29*6777b538SAndroid Build Coastguard Worker   using UnsignedDst = typename std::make_unsigned<T>::type;
30*6777b538SAndroid Build Coastguard Worker   using SignedDst = typename std::make_signed<T>::type;
31*6777b538SAndroid Build Coastguard Worker   const UnsignedDst ux = static_cast<UnsignedDst>(x);
32*6777b538SAndroid Build Coastguard Worker   const UnsignedDst uy = static_cast<UnsignedDst>(y);
33*6777b538SAndroid Build Coastguard Worker   const UnsignedDst uresult = static_cast<UnsignedDst>(ux + uy);
34*6777b538SAndroid Build Coastguard Worker   // Addition is valid if the sign of (x + y) is equal to either that of x or
35*6777b538SAndroid Build Coastguard Worker   // that of y.
36*6777b538SAndroid Build Coastguard Worker   if (std::is_signed_v<T>
37*6777b538SAndroid Build Coastguard Worker           ? static_cast<SignedDst>((uresult ^ ux) & (uresult ^ uy)) < 0
38*6777b538SAndroid Build Coastguard Worker           : uresult < uy) {  // Unsigned is either valid or underflow.
39*6777b538SAndroid Build Coastguard Worker     return false;
40*6777b538SAndroid Build Coastguard Worker   }
41*6777b538SAndroid Build Coastguard Worker   *result = static_cast<T>(uresult);
42*6777b538SAndroid Build Coastguard Worker   return true;
43*6777b538SAndroid Build Coastguard Worker }
44*6777b538SAndroid Build Coastguard Worker 
45*6777b538SAndroid Build Coastguard Worker template <typename T, typename U>
46*6777b538SAndroid Build Coastguard Worker struct CheckedAddOp {};
47*6777b538SAndroid Build Coastguard Worker 
48*6777b538SAndroid Build Coastguard Worker template <typename T, typename U>
49*6777b538SAndroid Build Coastguard Worker   requires(std::integral<T> && std::integral<U>)
50*6777b538SAndroid Build Coastguard Worker struct CheckedAddOp<T, U> {
51*6777b538SAndroid Build Coastguard Worker   using result_type = typename MaxExponentPromotion<T, U>::type;
52*6777b538SAndroid Build Coastguard Worker   template <typename V>
53*6777b538SAndroid Build Coastguard Worker   static constexpr bool Do(T x, U y, V* result) {
54*6777b538SAndroid Build Coastguard Worker     if constexpr (CheckedAddFastOp<T, U>::is_supported)
55*6777b538SAndroid Build Coastguard Worker       return CheckedAddFastOp<T, U>::Do(x, y, result);
56*6777b538SAndroid Build Coastguard Worker 
57*6777b538SAndroid Build Coastguard Worker     // Double the underlying type up to a full machine word.
58*6777b538SAndroid Build Coastguard Worker     using FastPromotion = typename FastIntegerArithmeticPromotion<T, U>::type;
59*6777b538SAndroid Build Coastguard Worker     using Promotion =
60*6777b538SAndroid Build Coastguard Worker         typename std::conditional<(IntegerBitsPlusSign<FastPromotion>::value >
61*6777b538SAndroid Build Coastguard Worker                                    IntegerBitsPlusSign<intptr_t>::value),
62*6777b538SAndroid Build Coastguard Worker                                   typename BigEnoughPromotion<T, U>::type,
63*6777b538SAndroid Build Coastguard Worker                                   FastPromotion>::type;
64*6777b538SAndroid Build Coastguard Worker     // Fail if either operand is out of range for the promoted type.
65*6777b538SAndroid Build Coastguard Worker     // TODO(jschuh): This could be made to work for a broader range of values.
66*6777b538SAndroid Build Coastguard Worker     if (BASE_NUMERICS_UNLIKELY(!IsValueInRangeForNumericType<Promotion>(x) ||
67*6777b538SAndroid Build Coastguard Worker                                !IsValueInRangeForNumericType<Promotion>(y))) {
68*6777b538SAndroid Build Coastguard Worker       return false;
69*6777b538SAndroid Build Coastguard Worker     }
70*6777b538SAndroid Build Coastguard Worker 
71*6777b538SAndroid Build Coastguard Worker     Promotion presult = {};
72*6777b538SAndroid Build Coastguard Worker     bool is_valid = true;
73*6777b538SAndroid Build Coastguard Worker     if (IsIntegerArithmeticSafe<Promotion, T, U>::value) {
74*6777b538SAndroid Build Coastguard Worker       presult = static_cast<Promotion>(x) + static_cast<Promotion>(y);
75*6777b538SAndroid Build Coastguard Worker     } else {
76*6777b538SAndroid Build Coastguard Worker       is_valid = CheckedAddImpl(static_cast<Promotion>(x),
77*6777b538SAndroid Build Coastguard Worker                                 static_cast<Promotion>(y), &presult);
78*6777b538SAndroid Build Coastguard Worker     }
79*6777b538SAndroid Build Coastguard Worker     if (!is_valid || !IsValueInRangeForNumericType<V>(presult))
80*6777b538SAndroid Build Coastguard Worker       return false;
81*6777b538SAndroid Build Coastguard Worker     *result = static_cast<V>(presult);
82*6777b538SAndroid Build Coastguard Worker     return true;
83*6777b538SAndroid Build Coastguard Worker   }
84*6777b538SAndroid Build Coastguard Worker };
85*6777b538SAndroid Build Coastguard Worker 
86*6777b538SAndroid Build Coastguard Worker template <typename T>
87*6777b538SAndroid Build Coastguard Worker constexpr bool CheckedSubImpl(T x, T y, T* result) {
88*6777b538SAndroid Build Coastguard Worker   static_assert(std::is_integral_v<T>, "Type must be integral");
89*6777b538SAndroid Build Coastguard Worker   // Since the value of x+y is undefined if we have a signed type, we compute
90*6777b538SAndroid Build Coastguard Worker   // it using the unsigned type of the same size.
91*6777b538SAndroid Build Coastguard Worker   using UnsignedDst = typename std::make_unsigned<T>::type;
92*6777b538SAndroid Build Coastguard Worker   using SignedDst = typename std::make_signed<T>::type;
93*6777b538SAndroid Build Coastguard Worker   const UnsignedDst ux = static_cast<UnsignedDst>(x);
94*6777b538SAndroid Build Coastguard Worker   const UnsignedDst uy = static_cast<UnsignedDst>(y);
95*6777b538SAndroid Build Coastguard Worker   const UnsignedDst uresult = static_cast<UnsignedDst>(ux - uy);
96*6777b538SAndroid Build Coastguard Worker   // Subtraction is valid if either x and y have same sign, or (x-y) and x have
97*6777b538SAndroid Build Coastguard Worker   // the same sign.
98*6777b538SAndroid Build Coastguard Worker   if (std::is_signed_v<T>
99*6777b538SAndroid Build Coastguard Worker           ? static_cast<SignedDst>((uresult ^ ux) & (ux ^ uy)) < 0
100*6777b538SAndroid Build Coastguard Worker           : x < y) {
101*6777b538SAndroid Build Coastguard Worker     return false;
102*6777b538SAndroid Build Coastguard Worker   }
103*6777b538SAndroid Build Coastguard Worker   *result = static_cast<T>(uresult);
104*6777b538SAndroid Build Coastguard Worker   return true;
105*6777b538SAndroid Build Coastguard Worker }
106*6777b538SAndroid Build Coastguard Worker 
107*6777b538SAndroid Build Coastguard Worker template <typename T, typename U>
108*6777b538SAndroid Build Coastguard Worker struct CheckedSubOp {};
109*6777b538SAndroid Build Coastguard Worker 
110*6777b538SAndroid Build Coastguard Worker template <typename T, typename U>
111*6777b538SAndroid Build Coastguard Worker   requires(std::integral<T> && std::integral<U>)
112*6777b538SAndroid Build Coastguard Worker struct CheckedSubOp<T, U> {
113*6777b538SAndroid Build Coastguard Worker   using result_type = typename MaxExponentPromotion<T, U>::type;
114*6777b538SAndroid Build Coastguard Worker   template <typename V>
115*6777b538SAndroid Build Coastguard Worker   static constexpr bool Do(T x, U y, V* result) {
116*6777b538SAndroid Build Coastguard Worker     if constexpr (CheckedSubFastOp<T, U>::is_supported)
117*6777b538SAndroid Build Coastguard Worker       return CheckedSubFastOp<T, U>::Do(x, y, result);
118*6777b538SAndroid Build Coastguard Worker 
119*6777b538SAndroid Build Coastguard Worker     // Double the underlying type up to a full machine word.
120*6777b538SAndroid Build Coastguard Worker     using FastPromotion = typename FastIntegerArithmeticPromotion<T, U>::type;
121*6777b538SAndroid Build Coastguard Worker     using Promotion =
122*6777b538SAndroid Build Coastguard Worker         typename std::conditional<(IntegerBitsPlusSign<FastPromotion>::value >
123*6777b538SAndroid Build Coastguard Worker                                    IntegerBitsPlusSign<intptr_t>::value),
124*6777b538SAndroid Build Coastguard Worker                                   typename BigEnoughPromotion<T, U>::type,
125*6777b538SAndroid Build Coastguard Worker                                   FastPromotion>::type;
126*6777b538SAndroid Build Coastguard Worker     // Fail if either operand is out of range for the promoted type.
127*6777b538SAndroid Build Coastguard Worker     // TODO(jschuh): This could be made to work for a broader range of values.
128*6777b538SAndroid Build Coastguard Worker     if (BASE_NUMERICS_UNLIKELY(!IsValueInRangeForNumericType<Promotion>(x) ||
129*6777b538SAndroid Build Coastguard Worker                                !IsValueInRangeForNumericType<Promotion>(y))) {
130*6777b538SAndroid Build Coastguard Worker       return false;
131*6777b538SAndroid Build Coastguard Worker     }
132*6777b538SAndroid Build Coastguard Worker 
133*6777b538SAndroid Build Coastguard Worker     Promotion presult = {};
134*6777b538SAndroid Build Coastguard Worker     bool is_valid = true;
135*6777b538SAndroid Build Coastguard Worker     if (IsIntegerArithmeticSafe<Promotion, T, U>::value) {
136*6777b538SAndroid Build Coastguard Worker       presult = static_cast<Promotion>(x) - static_cast<Promotion>(y);
137*6777b538SAndroid Build Coastguard Worker     } else {
138*6777b538SAndroid Build Coastguard Worker       is_valid = CheckedSubImpl(static_cast<Promotion>(x),
139*6777b538SAndroid Build Coastguard Worker                                 static_cast<Promotion>(y), &presult);
140*6777b538SAndroid Build Coastguard Worker     }
141*6777b538SAndroid Build Coastguard Worker     if (!is_valid || !IsValueInRangeForNumericType<V>(presult))
142*6777b538SAndroid Build Coastguard Worker       return false;
143*6777b538SAndroid Build Coastguard Worker     *result = static_cast<V>(presult);
144*6777b538SAndroid Build Coastguard Worker     return true;
145*6777b538SAndroid Build Coastguard Worker   }
146*6777b538SAndroid Build Coastguard Worker };
147*6777b538SAndroid Build Coastguard Worker 
148*6777b538SAndroid Build Coastguard Worker template <typename T>
149*6777b538SAndroid Build Coastguard Worker constexpr bool CheckedMulImpl(T x, T y, T* result) {
150*6777b538SAndroid Build Coastguard Worker   static_assert(std::is_integral_v<T>, "Type must be integral");
151*6777b538SAndroid Build Coastguard Worker   // Since the value of x*y is potentially undefined if we have a signed type,
152*6777b538SAndroid Build Coastguard Worker   // we compute it using the unsigned type of the same size.
153*6777b538SAndroid Build Coastguard Worker   using UnsignedDst = typename std::make_unsigned<T>::type;
154*6777b538SAndroid Build Coastguard Worker   using SignedDst = typename std::make_signed<T>::type;
155*6777b538SAndroid Build Coastguard Worker   const UnsignedDst ux = SafeUnsignedAbs(x);
156*6777b538SAndroid Build Coastguard Worker   const UnsignedDst uy = SafeUnsignedAbs(y);
157*6777b538SAndroid Build Coastguard Worker   const UnsignedDst uresult = static_cast<UnsignedDst>(ux * uy);
158*6777b538SAndroid Build Coastguard Worker   const bool is_negative =
159*6777b538SAndroid Build Coastguard Worker       std::is_signed_v<T> && static_cast<SignedDst>(x ^ y) < 0;
160*6777b538SAndroid Build Coastguard Worker   // We have a fast out for unsigned identity or zero on the second operand.
161*6777b538SAndroid Build Coastguard Worker   // After that it's an unsigned overflow check on the absolute value, with
162*6777b538SAndroid Build Coastguard Worker   // a +1 bound for a negative result.
163*6777b538SAndroid Build Coastguard Worker   if (uy > UnsignedDst(!std::is_signed_v<T> || is_negative) &&
164*6777b538SAndroid Build Coastguard Worker       ux > (std::numeric_limits<T>::max() + UnsignedDst(is_negative)) / uy) {
165*6777b538SAndroid Build Coastguard Worker     return false;
166*6777b538SAndroid Build Coastguard Worker   }
167*6777b538SAndroid Build Coastguard Worker   *result = static_cast<T>(is_negative ? 0 - uresult : uresult);
168*6777b538SAndroid Build Coastguard Worker   return true;
169*6777b538SAndroid Build Coastguard Worker }
170*6777b538SAndroid Build Coastguard Worker 
171*6777b538SAndroid Build Coastguard Worker template <typename T, typename U>
172*6777b538SAndroid Build Coastguard Worker struct CheckedMulOp {};
173*6777b538SAndroid Build Coastguard Worker 
174*6777b538SAndroid Build Coastguard Worker template <typename T, typename U>
175*6777b538SAndroid Build Coastguard Worker   requires(std::integral<T> && std::integral<U>)
176*6777b538SAndroid Build Coastguard Worker struct CheckedMulOp<T, U> {
177*6777b538SAndroid Build Coastguard Worker   using result_type = typename MaxExponentPromotion<T, U>::type;
178*6777b538SAndroid Build Coastguard Worker   template <typename V>
179*6777b538SAndroid Build Coastguard Worker   static constexpr bool Do(T x, U y, V* result) {
180*6777b538SAndroid Build Coastguard Worker     if constexpr (CheckedMulFastOp<T, U>::is_supported)
181*6777b538SAndroid Build Coastguard Worker       return CheckedMulFastOp<T, U>::Do(x, y, result);
182*6777b538SAndroid Build Coastguard Worker 
183*6777b538SAndroid Build Coastguard Worker     using Promotion = typename FastIntegerArithmeticPromotion<T, U>::type;
184*6777b538SAndroid Build Coastguard Worker     // Verify the destination type can hold the result (always true for 0).
185*6777b538SAndroid Build Coastguard Worker     if (BASE_NUMERICS_UNLIKELY((!IsValueInRangeForNumericType<Promotion>(x) ||
186*6777b538SAndroid Build Coastguard Worker                                 !IsValueInRangeForNumericType<Promotion>(y)) &&
187*6777b538SAndroid Build Coastguard Worker                                x && y)) {
188*6777b538SAndroid Build Coastguard Worker       return false;
189*6777b538SAndroid Build Coastguard Worker     }
190*6777b538SAndroid Build Coastguard Worker 
191*6777b538SAndroid Build Coastguard Worker     Promotion presult = {};
192*6777b538SAndroid Build Coastguard Worker     bool is_valid = true;
193*6777b538SAndroid Build Coastguard Worker     if (CheckedMulFastOp<Promotion, Promotion>::is_supported) {
194*6777b538SAndroid Build Coastguard Worker       // The fast op may be available with the promoted type.
195*6777b538SAndroid Build Coastguard Worker       // The casts here are safe because of the "value in range" conditional
196*6777b538SAndroid Build Coastguard Worker       // above.
197*6777b538SAndroid Build Coastguard Worker       is_valid = CheckedMulFastOp<Promotion, Promotion>::Do(
198*6777b538SAndroid Build Coastguard Worker           static_cast<Promotion>(x), static_cast<Promotion>(y), &presult);
199*6777b538SAndroid Build Coastguard Worker     } else if (IsIntegerArithmeticSafe<Promotion, T, U>::value) {
200*6777b538SAndroid Build Coastguard Worker       presult = static_cast<Promotion>(x) * static_cast<Promotion>(y);
201*6777b538SAndroid Build Coastguard Worker     } else {
202*6777b538SAndroid Build Coastguard Worker       is_valid = CheckedMulImpl(static_cast<Promotion>(x),
203*6777b538SAndroid Build Coastguard Worker                                 static_cast<Promotion>(y), &presult);
204*6777b538SAndroid Build Coastguard Worker     }
205*6777b538SAndroid Build Coastguard Worker     if (!is_valid || !IsValueInRangeForNumericType<V>(presult))
206*6777b538SAndroid Build Coastguard Worker       return false;
207*6777b538SAndroid Build Coastguard Worker     *result = static_cast<V>(presult);
208*6777b538SAndroid Build Coastguard Worker     return true;
209*6777b538SAndroid Build Coastguard Worker   }
210*6777b538SAndroid Build Coastguard Worker };
211*6777b538SAndroid Build Coastguard Worker 
212*6777b538SAndroid Build Coastguard Worker // Division just requires a check for a zero denominator or an invalid negation
213*6777b538SAndroid Build Coastguard Worker // on signed min/-1.
214*6777b538SAndroid Build Coastguard Worker template <typename T, typename U>
215*6777b538SAndroid Build Coastguard Worker struct CheckedDivOp {};
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 CheckedDivOp<T, U> {
220*6777b538SAndroid Build Coastguard Worker   using result_type = typename MaxExponentPromotion<T, U>::type;
221*6777b538SAndroid Build Coastguard Worker   template <typename V>
222*6777b538SAndroid Build Coastguard Worker   static constexpr bool Do(T x, U y, V* result) {
223*6777b538SAndroid Build Coastguard Worker     if (BASE_NUMERICS_UNLIKELY(!y))
224*6777b538SAndroid Build Coastguard Worker       return false;
225*6777b538SAndroid Build Coastguard Worker 
226*6777b538SAndroid Build Coastguard Worker     // The overflow check can be compiled away if we don't have the exact
227*6777b538SAndroid Build Coastguard Worker     // combination of types needed to trigger this case.
228*6777b538SAndroid Build Coastguard Worker     using Promotion = typename BigEnoughPromotion<T, U>::type;
229*6777b538SAndroid Build Coastguard Worker     if (BASE_NUMERICS_UNLIKELY(
230*6777b538SAndroid Build Coastguard Worker             (std::is_signed_v<T> && std::is_signed_v<U> &&
231*6777b538SAndroid Build Coastguard Worker              IsTypeInRangeForNumericType<T, Promotion>::value &&
232*6777b538SAndroid Build Coastguard Worker              static_cast<Promotion>(x) ==
233*6777b538SAndroid Build Coastguard Worker                  std::numeric_limits<Promotion>::lowest() &&
234*6777b538SAndroid Build Coastguard Worker              y == static_cast<U>(-1)))) {
235*6777b538SAndroid Build Coastguard Worker       return false;
236*6777b538SAndroid Build Coastguard Worker     }
237*6777b538SAndroid Build Coastguard Worker 
238*6777b538SAndroid Build Coastguard Worker     // This branch always compiles away if the above branch wasn't removed.
239*6777b538SAndroid Build Coastguard Worker     if (BASE_NUMERICS_UNLIKELY((!IsValueInRangeForNumericType<Promotion>(x) ||
240*6777b538SAndroid Build Coastguard Worker                                 !IsValueInRangeForNumericType<Promotion>(y)) &&
241*6777b538SAndroid Build Coastguard Worker                                x)) {
242*6777b538SAndroid Build Coastguard Worker       return false;
243*6777b538SAndroid Build Coastguard Worker     }
244*6777b538SAndroid Build Coastguard Worker 
245*6777b538SAndroid Build Coastguard Worker     const Promotion presult = Promotion(x) / Promotion(y);
246*6777b538SAndroid Build Coastguard Worker     if (!IsValueInRangeForNumericType<V>(presult))
247*6777b538SAndroid Build Coastguard Worker       return false;
248*6777b538SAndroid Build Coastguard Worker     *result = static_cast<V>(presult);
249*6777b538SAndroid Build Coastguard Worker     return true;
250*6777b538SAndroid Build Coastguard Worker   }
251*6777b538SAndroid Build Coastguard Worker };
252*6777b538SAndroid Build Coastguard Worker 
253*6777b538SAndroid Build Coastguard Worker template <typename T, typename U>
254*6777b538SAndroid Build Coastguard Worker struct CheckedModOp {};
255*6777b538SAndroid Build Coastguard Worker 
256*6777b538SAndroid Build Coastguard Worker template <typename T, typename U>
257*6777b538SAndroid Build Coastguard Worker   requires(std::integral<T> && std::integral<U>)
258*6777b538SAndroid Build Coastguard Worker struct CheckedModOp<T, U> {
259*6777b538SAndroid Build Coastguard Worker   using result_type = typename MaxExponentPromotion<T, U>::type;
260*6777b538SAndroid Build Coastguard Worker   template <typename V>
261*6777b538SAndroid Build Coastguard Worker   static constexpr bool Do(T x, U y, V* result) {
262*6777b538SAndroid Build Coastguard Worker     if (BASE_NUMERICS_UNLIKELY(!y))
263*6777b538SAndroid Build Coastguard Worker       return false;
264*6777b538SAndroid Build Coastguard Worker 
265*6777b538SAndroid Build Coastguard Worker     using Promotion = typename BigEnoughPromotion<T, U>::type;
266*6777b538SAndroid Build Coastguard Worker     if (BASE_NUMERICS_UNLIKELY(
267*6777b538SAndroid Build Coastguard Worker             (std::is_signed_v<T> && std::is_signed_v<U> &&
268*6777b538SAndroid Build Coastguard Worker              IsTypeInRangeForNumericType<T, Promotion>::value &&
269*6777b538SAndroid Build Coastguard Worker              static_cast<Promotion>(x) ==
270*6777b538SAndroid Build Coastguard Worker                  std::numeric_limits<Promotion>::lowest() &&
271*6777b538SAndroid Build Coastguard Worker              y == static_cast<U>(-1)))) {
272*6777b538SAndroid Build Coastguard Worker       *result = 0;
273*6777b538SAndroid Build Coastguard Worker       return true;
274*6777b538SAndroid Build Coastguard Worker     }
275*6777b538SAndroid Build Coastguard Worker 
276*6777b538SAndroid Build Coastguard Worker     const Promotion presult =
277*6777b538SAndroid Build Coastguard Worker         static_cast<Promotion>(x) % static_cast<Promotion>(y);
278*6777b538SAndroid Build Coastguard Worker     if (!IsValueInRangeForNumericType<V>(presult))
279*6777b538SAndroid Build Coastguard Worker       return false;
280*6777b538SAndroid Build Coastguard Worker     *result = static_cast<Promotion>(presult);
281*6777b538SAndroid Build Coastguard Worker     return true;
282*6777b538SAndroid Build Coastguard Worker   }
283*6777b538SAndroid Build Coastguard Worker };
284*6777b538SAndroid Build Coastguard Worker 
285*6777b538SAndroid Build Coastguard Worker template <typename T, typename U>
286*6777b538SAndroid Build Coastguard Worker struct CheckedLshOp {};
287*6777b538SAndroid Build Coastguard Worker 
288*6777b538SAndroid Build Coastguard Worker // Left shift. Shifts less than 0 or greater than or equal to the number
289*6777b538SAndroid Build Coastguard Worker // of bits in the promoted type are undefined. Shifts of negative values
290*6777b538SAndroid Build Coastguard Worker // are undefined. Otherwise it is defined when the result fits.
291*6777b538SAndroid Build Coastguard Worker template <typename T, typename U>
292*6777b538SAndroid Build Coastguard Worker   requires(std::integral<T> && std::integral<U>)
293*6777b538SAndroid Build Coastguard Worker struct CheckedLshOp<T, U> {
294*6777b538SAndroid Build Coastguard Worker   using result_type = T;
295*6777b538SAndroid Build Coastguard Worker   template <typename V>
296*6777b538SAndroid Build Coastguard Worker   static constexpr bool Do(T x, U shift, V* result) {
297*6777b538SAndroid Build Coastguard Worker     // Disallow negative numbers and verify the shift is in bounds.
298*6777b538SAndroid Build Coastguard Worker     if (BASE_NUMERICS_LIKELY(!IsValueNegative(x) &&
299*6777b538SAndroid Build Coastguard Worker                              as_unsigned(shift) <
300*6777b538SAndroid Build Coastguard Worker                                  as_unsigned(std::numeric_limits<T>::digits))) {
301*6777b538SAndroid Build Coastguard Worker       // Shift as unsigned to avoid undefined behavior.
302*6777b538SAndroid Build Coastguard Worker       *result = static_cast<V>(as_unsigned(x) << shift);
303*6777b538SAndroid Build Coastguard Worker       // If the shift can be reversed, we know it was valid.
304*6777b538SAndroid Build Coastguard Worker       return *result >> shift == x;
305*6777b538SAndroid Build Coastguard Worker     }
306*6777b538SAndroid Build Coastguard Worker 
307*6777b538SAndroid Build Coastguard Worker     // Handle the legal corner-case of a full-width signed shift of zero.
308*6777b538SAndroid Build Coastguard Worker     if (!std::is_signed_v<T> || x ||
309*6777b538SAndroid Build Coastguard Worker         as_unsigned(shift) != as_unsigned(std::numeric_limits<T>::digits)) {
310*6777b538SAndroid Build Coastguard Worker       return false;
311*6777b538SAndroid Build Coastguard Worker     }
312*6777b538SAndroid Build Coastguard Worker     *result = 0;
313*6777b538SAndroid Build Coastguard Worker     return true;
314*6777b538SAndroid Build Coastguard Worker   }
315*6777b538SAndroid Build Coastguard Worker };
316*6777b538SAndroid Build Coastguard Worker 
317*6777b538SAndroid Build Coastguard Worker template <typename T, typename U>
318*6777b538SAndroid Build Coastguard Worker struct CheckedRshOp {};
319*6777b538SAndroid Build Coastguard Worker 
320*6777b538SAndroid Build Coastguard Worker // Right shift. Shifts less than 0 or greater than or equal to the number
321*6777b538SAndroid Build Coastguard Worker // of bits in the promoted type are undefined. Otherwise, it is always defined,
322*6777b538SAndroid Build Coastguard Worker // but a right shift of a negative value is implementation-dependent.
323*6777b538SAndroid Build Coastguard Worker template <typename T, typename U>
324*6777b538SAndroid Build Coastguard Worker   requires(std::integral<T> && std::integral<U>)
325*6777b538SAndroid Build Coastguard Worker struct CheckedRshOp<T, U> {
326*6777b538SAndroid Build Coastguard Worker   using result_type = T;
327*6777b538SAndroid Build Coastguard Worker   template <typename V>
328*6777b538SAndroid Build Coastguard Worker   static constexpr bool Do(T x, U shift, V* result) {
329*6777b538SAndroid Build Coastguard Worker     // Use sign conversion to push negative values out of range.
330*6777b538SAndroid Build Coastguard Worker     if (BASE_NUMERICS_UNLIKELY(as_unsigned(shift) >=
331*6777b538SAndroid Build Coastguard Worker                                IntegerBitsPlusSign<T>::value)) {
332*6777b538SAndroid Build Coastguard Worker       return false;
333*6777b538SAndroid Build Coastguard Worker     }
334*6777b538SAndroid Build Coastguard Worker 
335*6777b538SAndroid Build Coastguard Worker     const T tmp = x >> shift;
336*6777b538SAndroid Build Coastguard Worker     if (!IsValueInRangeForNumericType<V>(tmp))
337*6777b538SAndroid Build Coastguard Worker       return false;
338*6777b538SAndroid Build Coastguard Worker     *result = static_cast<V>(tmp);
339*6777b538SAndroid Build Coastguard Worker     return true;
340*6777b538SAndroid Build Coastguard Worker   }
341*6777b538SAndroid Build Coastguard Worker };
342*6777b538SAndroid Build Coastguard Worker 
343*6777b538SAndroid Build Coastguard Worker template <typename T, typename U>
344*6777b538SAndroid Build Coastguard Worker struct CheckedAndOp {};
345*6777b538SAndroid Build Coastguard Worker 
346*6777b538SAndroid Build Coastguard Worker // For simplicity we support only unsigned integer results.
347*6777b538SAndroid Build Coastguard Worker template <typename T, typename U>
348*6777b538SAndroid Build Coastguard Worker   requires(std::integral<T> && std::integral<U>)
349*6777b538SAndroid Build Coastguard Worker struct CheckedAndOp<T, U> {
350*6777b538SAndroid Build Coastguard Worker   using result_type = typename std::make_unsigned<
351*6777b538SAndroid Build Coastguard Worker       typename MaxExponentPromotion<T, U>::type>::type;
352*6777b538SAndroid Build Coastguard Worker   template <typename V>
353*6777b538SAndroid Build Coastguard Worker   static constexpr bool Do(T x, U y, V* result) {
354*6777b538SAndroid Build Coastguard Worker     const result_type tmp =
355*6777b538SAndroid Build Coastguard Worker         static_cast<result_type>(x) & static_cast<result_type>(y);
356*6777b538SAndroid Build Coastguard Worker     if (!IsValueInRangeForNumericType<V>(tmp))
357*6777b538SAndroid Build Coastguard Worker       return false;
358*6777b538SAndroid Build Coastguard Worker     *result = static_cast<V>(tmp);
359*6777b538SAndroid Build Coastguard Worker     return true;
360*6777b538SAndroid Build Coastguard Worker   }
361*6777b538SAndroid Build Coastguard Worker };
362*6777b538SAndroid Build Coastguard Worker 
363*6777b538SAndroid Build Coastguard Worker template <typename T, typename U>
364*6777b538SAndroid Build Coastguard Worker struct CheckedOrOp {};
365*6777b538SAndroid Build Coastguard Worker 
366*6777b538SAndroid Build Coastguard Worker // For simplicity we support only unsigned integers.
367*6777b538SAndroid Build Coastguard Worker template <typename T, typename U>
368*6777b538SAndroid Build Coastguard Worker   requires(std::integral<T> && std::integral<U>)
369*6777b538SAndroid Build Coastguard Worker struct CheckedOrOp<T, U> {
370*6777b538SAndroid Build Coastguard Worker   using result_type = typename std::make_unsigned<
371*6777b538SAndroid Build Coastguard Worker       typename MaxExponentPromotion<T, U>::type>::type;
372*6777b538SAndroid Build Coastguard Worker   template <typename V>
373*6777b538SAndroid Build Coastguard Worker   static constexpr bool Do(T x, U y, V* result) {
374*6777b538SAndroid Build Coastguard Worker     const result_type tmp =
375*6777b538SAndroid Build Coastguard Worker         static_cast<result_type>(x) | static_cast<result_type>(y);
376*6777b538SAndroid Build Coastguard Worker     if (!IsValueInRangeForNumericType<V>(tmp))
377*6777b538SAndroid Build Coastguard Worker       return false;
378*6777b538SAndroid Build Coastguard Worker     *result = static_cast<V>(tmp);
379*6777b538SAndroid Build Coastguard Worker     return true;
380*6777b538SAndroid Build Coastguard Worker   }
381*6777b538SAndroid Build Coastguard Worker };
382*6777b538SAndroid Build Coastguard Worker 
383*6777b538SAndroid Build Coastguard Worker template <typename T, typename U>
384*6777b538SAndroid Build Coastguard Worker struct CheckedXorOp {};
385*6777b538SAndroid Build Coastguard Worker 
386*6777b538SAndroid Build Coastguard Worker // For simplicity we support only unsigned integers.
387*6777b538SAndroid Build Coastguard Worker template <typename T, typename U>
388*6777b538SAndroid Build Coastguard Worker   requires(std::integral<T> && std::integral<U>)
389*6777b538SAndroid Build Coastguard Worker struct CheckedXorOp<T, U> {
390*6777b538SAndroid Build Coastguard Worker   using result_type = typename std::make_unsigned<
391*6777b538SAndroid Build Coastguard Worker       typename MaxExponentPromotion<T, U>::type>::type;
392*6777b538SAndroid Build Coastguard Worker   template <typename V>
393*6777b538SAndroid Build Coastguard Worker   static constexpr bool Do(T x, U y, V* result) {
394*6777b538SAndroid Build Coastguard Worker     const result_type tmp =
395*6777b538SAndroid Build Coastguard Worker         static_cast<result_type>(x) ^ static_cast<result_type>(y);
396*6777b538SAndroid Build Coastguard Worker     if (!IsValueInRangeForNumericType<V>(tmp))
397*6777b538SAndroid Build Coastguard Worker       return false;
398*6777b538SAndroid Build Coastguard Worker     *result = static_cast<V>(tmp);
399*6777b538SAndroid Build Coastguard Worker     return true;
400*6777b538SAndroid Build Coastguard Worker   }
401*6777b538SAndroid Build Coastguard Worker };
402*6777b538SAndroid Build Coastguard Worker 
403*6777b538SAndroid Build Coastguard Worker // Max doesn't really need to be implemented this way because it can't fail,
404*6777b538SAndroid Build Coastguard Worker // but it makes the code much cleaner to use the MathOp wrappers.
405*6777b538SAndroid Build Coastguard Worker template <typename T, typename U>
406*6777b538SAndroid Build Coastguard Worker struct CheckedMaxOp {};
407*6777b538SAndroid Build Coastguard Worker 
408*6777b538SAndroid Build Coastguard Worker template <typename T, typename U>
409*6777b538SAndroid Build Coastguard Worker   requires(std::is_arithmetic_v<T> && std::is_arithmetic_v<U>)
410*6777b538SAndroid Build Coastguard Worker struct CheckedMaxOp<T, U> {
411*6777b538SAndroid Build Coastguard Worker   using result_type = typename MaxExponentPromotion<T, U>::type;
412*6777b538SAndroid Build Coastguard Worker   template <typename V>
413*6777b538SAndroid Build Coastguard Worker   static constexpr bool Do(T x, U y, V* result) {
414*6777b538SAndroid Build Coastguard Worker     const result_type tmp = IsGreater<T, U>::Test(x, y)
415*6777b538SAndroid Build Coastguard Worker                                 ? static_cast<result_type>(x)
416*6777b538SAndroid Build Coastguard Worker                                 : static_cast<result_type>(y);
417*6777b538SAndroid Build Coastguard Worker     if (!IsValueInRangeForNumericType<V>(tmp))
418*6777b538SAndroid Build Coastguard Worker       return false;
419*6777b538SAndroid Build Coastguard Worker     *result = static_cast<V>(tmp);
420*6777b538SAndroid Build Coastguard Worker     return true;
421*6777b538SAndroid Build Coastguard Worker   }
422*6777b538SAndroid Build Coastguard Worker };
423*6777b538SAndroid Build Coastguard Worker 
424*6777b538SAndroid Build Coastguard Worker // Min doesn't really need to be implemented this way because it can't fail,
425*6777b538SAndroid Build Coastguard Worker // but it makes the code much cleaner to use the MathOp wrappers.
426*6777b538SAndroid Build Coastguard Worker template <typename T, typename U>
427*6777b538SAndroid Build Coastguard Worker struct CheckedMinOp {};
428*6777b538SAndroid Build Coastguard Worker 
429*6777b538SAndroid Build Coastguard Worker template <typename T, typename U>
430*6777b538SAndroid Build Coastguard Worker   requires(std::is_arithmetic_v<T> && std::is_arithmetic_v<U>)
431*6777b538SAndroid Build Coastguard Worker struct CheckedMinOp<T, U> {
432*6777b538SAndroid Build Coastguard Worker   using result_type = typename LowestValuePromotion<T, U>::type;
433*6777b538SAndroid Build Coastguard Worker   template <typename V>
434*6777b538SAndroid Build Coastguard Worker   static constexpr bool Do(T x, U y, V* result) {
435*6777b538SAndroid Build Coastguard Worker     const result_type tmp = IsLess<T, U>::Test(x, y)
436*6777b538SAndroid Build Coastguard Worker                                 ? static_cast<result_type>(x)
437*6777b538SAndroid Build Coastguard Worker                                 : static_cast<result_type>(y);
438*6777b538SAndroid Build Coastguard Worker     if (!IsValueInRangeForNumericType<V>(tmp))
439*6777b538SAndroid Build Coastguard Worker       return false;
440*6777b538SAndroid Build Coastguard Worker     *result = static_cast<V>(tmp);
441*6777b538SAndroid Build Coastguard Worker     return true;
442*6777b538SAndroid Build Coastguard Worker   }
443*6777b538SAndroid Build Coastguard Worker };
444*6777b538SAndroid Build Coastguard Worker 
445*6777b538SAndroid Build Coastguard Worker // This is just boilerplate that wraps the standard floating point arithmetic.
446*6777b538SAndroid Build Coastguard Worker // A macro isn't the nicest solution, but it beats rewriting these repeatedly.
447*6777b538SAndroid Build Coastguard Worker #define BASE_FLOAT_ARITHMETIC_OPS(NAME, OP)                              \
448*6777b538SAndroid Build Coastguard Worker   template <typename T, typename U>                                      \
449*6777b538SAndroid Build Coastguard Worker     requires(std::is_floating_point_v<T> || std::is_floating_point_v<U>) \
450*6777b538SAndroid Build Coastguard Worker   struct Checked##NAME##Op<T, U> {                                       \
451*6777b538SAndroid Build Coastguard Worker     using result_type = typename MaxExponentPromotion<T, U>::type;       \
452*6777b538SAndroid Build Coastguard Worker     template <typename V>                                                \
453*6777b538SAndroid Build Coastguard Worker     static constexpr bool Do(T x, U y, V* result) {                      \
454*6777b538SAndroid Build Coastguard Worker       using Promotion = typename MaxExponentPromotion<T, U>::type;       \
455*6777b538SAndroid Build Coastguard Worker       const Promotion presult = x OP y;                                  \
456*6777b538SAndroid Build Coastguard Worker       if (!IsValueInRangeForNumericType<V>(presult))                     \
457*6777b538SAndroid Build Coastguard Worker         return false;                                                    \
458*6777b538SAndroid Build Coastguard Worker       *result = static_cast<V>(presult);                                 \
459*6777b538SAndroid Build Coastguard Worker       return true;                                                       \
460*6777b538SAndroid Build Coastguard Worker     }                                                                    \
461*6777b538SAndroid Build Coastguard Worker   };
462*6777b538SAndroid Build Coastguard Worker 
463*6777b538SAndroid Build Coastguard Worker BASE_FLOAT_ARITHMETIC_OPS(Add, +)
464*6777b538SAndroid Build Coastguard Worker BASE_FLOAT_ARITHMETIC_OPS(Sub, -)
465*6777b538SAndroid Build Coastguard Worker BASE_FLOAT_ARITHMETIC_OPS(Mul, *)
466*6777b538SAndroid Build Coastguard Worker BASE_FLOAT_ARITHMETIC_OPS(Div, /)
467*6777b538SAndroid Build Coastguard Worker 
468*6777b538SAndroid Build Coastguard Worker #undef BASE_FLOAT_ARITHMETIC_OPS
469*6777b538SAndroid Build Coastguard Worker 
470*6777b538SAndroid Build Coastguard Worker // Floats carry around their validity state with them, but integers do not. So,
471*6777b538SAndroid Build Coastguard Worker // we wrap the underlying value in a specialization in order to hide that detail
472*6777b538SAndroid Build Coastguard Worker // and expose an interface via accessors.
473*6777b538SAndroid Build Coastguard Worker enum NumericRepresentation {
474*6777b538SAndroid Build Coastguard Worker   NUMERIC_INTEGER,
475*6777b538SAndroid Build Coastguard Worker   NUMERIC_FLOATING,
476*6777b538SAndroid Build Coastguard Worker   NUMERIC_UNKNOWN
477*6777b538SAndroid Build Coastguard Worker };
478*6777b538SAndroid Build Coastguard Worker 
479*6777b538SAndroid Build Coastguard Worker template <typename NumericType>
480*6777b538SAndroid Build Coastguard Worker struct GetNumericRepresentation {
481*6777b538SAndroid Build Coastguard Worker   static const NumericRepresentation value =
482*6777b538SAndroid Build Coastguard Worker       std::is_integral_v<NumericType>
483*6777b538SAndroid Build Coastguard Worker           ? NUMERIC_INTEGER
484*6777b538SAndroid Build Coastguard Worker           : (std::is_floating_point_v<NumericType> ? NUMERIC_FLOATING
485*6777b538SAndroid Build Coastguard Worker                                                    : NUMERIC_UNKNOWN);
486*6777b538SAndroid Build Coastguard Worker };
487*6777b538SAndroid Build Coastguard Worker 
488*6777b538SAndroid Build Coastguard Worker template <typename T,
489*6777b538SAndroid Build Coastguard Worker           NumericRepresentation type = GetNumericRepresentation<T>::value>
490*6777b538SAndroid Build Coastguard Worker class CheckedNumericState {};
491*6777b538SAndroid Build Coastguard Worker 
492*6777b538SAndroid Build Coastguard Worker // Integrals require quite a bit of additional housekeeping to manage state.
493*6777b538SAndroid Build Coastguard Worker template <typename T>
494*6777b538SAndroid Build Coastguard Worker class CheckedNumericState<T, NUMERIC_INTEGER> {
495*6777b538SAndroid Build Coastguard Worker  public:
496*6777b538SAndroid Build Coastguard Worker   template <typename Src = int>
497*6777b538SAndroid Build Coastguard Worker   constexpr explicit CheckedNumericState(Src value = 0, bool is_valid = true)
498*6777b538SAndroid Build Coastguard Worker       : is_valid_(is_valid && IsValueInRangeForNumericType<T>(value)),
499*6777b538SAndroid Build Coastguard Worker         value_(WellDefinedConversionOrZero(value, is_valid_)) {
500*6777b538SAndroid Build Coastguard Worker     static_assert(std::is_arithmetic_v<Src>, "Argument must be numeric.");
501*6777b538SAndroid Build Coastguard Worker   }
502*6777b538SAndroid Build Coastguard Worker 
503*6777b538SAndroid Build Coastguard Worker   template <typename Src>
504*6777b538SAndroid Build Coastguard Worker   constexpr CheckedNumericState(const CheckedNumericState<Src>& rhs)
505*6777b538SAndroid Build Coastguard Worker       : CheckedNumericState(rhs.value(), rhs.is_valid()) {}
506*6777b538SAndroid Build Coastguard Worker 
507*6777b538SAndroid Build Coastguard Worker   constexpr bool is_valid() const { return is_valid_; }
508*6777b538SAndroid Build Coastguard Worker 
509*6777b538SAndroid Build Coastguard Worker   constexpr T value() const { return value_; }
510*6777b538SAndroid Build Coastguard Worker 
511*6777b538SAndroid Build Coastguard Worker  private:
512*6777b538SAndroid Build Coastguard Worker   // Ensures that a type conversion does not trigger undefined behavior.
513*6777b538SAndroid Build Coastguard Worker   template <typename Src>
514*6777b538SAndroid Build Coastguard Worker   static constexpr T WellDefinedConversionOrZero(Src value, bool is_valid) {
515*6777b538SAndroid Build Coastguard Worker     using SrcType = typename internal::UnderlyingType<Src>::type;
516*6777b538SAndroid Build Coastguard Worker     return (std::is_integral_v<SrcType> || is_valid) ? static_cast<T>(value)
517*6777b538SAndroid Build Coastguard Worker                                                      : 0;
518*6777b538SAndroid Build Coastguard Worker   }
519*6777b538SAndroid Build Coastguard Worker 
520*6777b538SAndroid Build Coastguard Worker   // is_valid_ precedes value_ because member initializers in the constructors
521*6777b538SAndroid Build Coastguard Worker   // are evaluated in field order, and is_valid_ must be read when initializing
522*6777b538SAndroid Build Coastguard Worker   // value_.
523*6777b538SAndroid Build Coastguard Worker   bool is_valid_;
524*6777b538SAndroid Build Coastguard Worker   T value_;
525*6777b538SAndroid Build Coastguard Worker };
526*6777b538SAndroid Build Coastguard Worker 
527*6777b538SAndroid Build Coastguard Worker // Floating points maintain their own validity, but need translation wrappers.
528*6777b538SAndroid Build Coastguard Worker template <typename T>
529*6777b538SAndroid Build Coastguard Worker class CheckedNumericState<T, NUMERIC_FLOATING> {
530*6777b538SAndroid Build Coastguard Worker  public:
531*6777b538SAndroid Build Coastguard Worker   template <typename Src = double>
532*6777b538SAndroid Build Coastguard Worker   constexpr explicit CheckedNumericState(Src value = 0.0, bool is_valid = true)
533*6777b538SAndroid Build Coastguard Worker       : value_(WellDefinedConversionOrNaN(
534*6777b538SAndroid Build Coastguard Worker             value,
535*6777b538SAndroid Build Coastguard Worker             is_valid && IsValueInRangeForNumericType<T>(value))) {}
536*6777b538SAndroid Build Coastguard Worker 
537*6777b538SAndroid Build Coastguard Worker   template <typename Src>
538*6777b538SAndroid Build Coastguard Worker   constexpr CheckedNumericState(const CheckedNumericState<Src>& rhs)
539*6777b538SAndroid Build Coastguard Worker       : CheckedNumericState(rhs.value(), rhs.is_valid()) {}
540*6777b538SAndroid Build Coastguard Worker 
541*6777b538SAndroid Build Coastguard Worker   constexpr bool is_valid() const {
542*6777b538SAndroid Build Coastguard Worker     // Written this way because std::isfinite is not reliably constexpr.
543*6777b538SAndroid Build Coastguard Worker     return IsConstantEvaluated()
544*6777b538SAndroid Build Coastguard Worker                ? value_ <= std::numeric_limits<T>::max() &&
545*6777b538SAndroid Build Coastguard Worker                      value_ >= std::numeric_limits<T>::lowest()
546*6777b538SAndroid Build Coastguard Worker                : std::isfinite(value_);
547*6777b538SAndroid Build Coastguard Worker   }
548*6777b538SAndroid Build Coastguard Worker 
549*6777b538SAndroid Build Coastguard Worker   constexpr T value() const { return value_; }
550*6777b538SAndroid Build Coastguard Worker 
551*6777b538SAndroid Build Coastguard Worker  private:
552*6777b538SAndroid Build Coastguard Worker   // Ensures that a type conversion does not trigger undefined behavior.
553*6777b538SAndroid Build Coastguard Worker   template <typename Src>
554*6777b538SAndroid Build Coastguard Worker   static constexpr T WellDefinedConversionOrNaN(Src value, bool is_valid) {
555*6777b538SAndroid Build Coastguard Worker     using SrcType = typename internal::UnderlyingType<Src>::type;
556*6777b538SAndroid Build Coastguard Worker     return (StaticDstRangeRelationToSrcRange<T, SrcType>::value ==
557*6777b538SAndroid Build Coastguard Worker                 NUMERIC_RANGE_CONTAINED ||
558*6777b538SAndroid Build Coastguard Worker             is_valid)
559*6777b538SAndroid Build Coastguard Worker                ? static_cast<T>(value)
560*6777b538SAndroid Build Coastguard Worker                : std::numeric_limits<T>::quiet_NaN();
561*6777b538SAndroid Build Coastguard Worker   }
562*6777b538SAndroid Build Coastguard Worker 
563*6777b538SAndroid Build Coastguard Worker   T value_;
564*6777b538SAndroid Build Coastguard Worker };
565*6777b538SAndroid Build Coastguard Worker 
566*6777b538SAndroid Build Coastguard Worker }  // namespace internal
567*6777b538SAndroid Build Coastguard Worker }  // namespace base
568*6777b538SAndroid Build Coastguard Worker 
569*6777b538SAndroid Build Coastguard Worker #endif  // BASE_NUMERICS_CHECKED_MATH_IMPL_H_
570