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