1*6777b538SAndroid Build Coastguard Worker // Copyright 2014 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_SAFE_CONVERSIONS_IMPL_H_
6*6777b538SAndroid Build Coastguard Worker #define BASE_NUMERICS_SAFE_CONVERSIONS_IMPL_H_
7*6777b538SAndroid Build Coastguard Worker
8*6777b538SAndroid Build Coastguard Worker #include <stdint.h>
9*6777b538SAndroid Build Coastguard Worker
10*6777b538SAndroid Build Coastguard Worker #include <concepts>
11*6777b538SAndroid Build Coastguard Worker #include <limits>
12*6777b538SAndroid Build Coastguard Worker #include <type_traits>
13*6777b538SAndroid Build Coastguard Worker
14*6777b538SAndroid Build Coastguard Worker #if defined(__GNUC__) || defined(__clang__)
15*6777b538SAndroid Build Coastguard Worker #define BASE_NUMERICS_LIKELY(x) __builtin_expect(!!(x), 1)
16*6777b538SAndroid Build Coastguard Worker #define BASE_NUMERICS_UNLIKELY(x) __builtin_expect(!!(x), 0)
17*6777b538SAndroid Build Coastguard Worker #else
18*6777b538SAndroid Build Coastguard Worker #define BASE_NUMERICS_LIKELY(x) (x)
19*6777b538SAndroid Build Coastguard Worker #define BASE_NUMERICS_UNLIKELY(x) (x)
20*6777b538SAndroid Build Coastguard Worker #endif
21*6777b538SAndroid Build Coastguard Worker
22*6777b538SAndroid Build Coastguard Worker namespace base {
23*6777b538SAndroid Build Coastguard Worker namespace internal {
24*6777b538SAndroid Build Coastguard Worker
25*6777b538SAndroid Build Coastguard Worker // The std library doesn't provide a binary max_exponent for integers, however
26*6777b538SAndroid Build Coastguard Worker // we can compute an analog using std::numeric_limits<>::digits.
27*6777b538SAndroid Build Coastguard Worker template <typename NumericType>
28*6777b538SAndroid Build Coastguard Worker struct MaxExponent {
29*6777b538SAndroid Build Coastguard Worker static const int value = std::is_floating_point_v<NumericType>
30*6777b538SAndroid Build Coastguard Worker ? std::numeric_limits<NumericType>::max_exponent
31*6777b538SAndroid Build Coastguard Worker : std::numeric_limits<NumericType>::digits + 1;
32*6777b538SAndroid Build Coastguard Worker };
33*6777b538SAndroid Build Coastguard Worker
34*6777b538SAndroid Build Coastguard Worker // The number of bits (including the sign) in an integer. Eliminates sizeof
35*6777b538SAndroid Build Coastguard Worker // hacks.
36*6777b538SAndroid Build Coastguard Worker template <typename NumericType>
37*6777b538SAndroid Build Coastguard Worker struct IntegerBitsPlusSign {
38*6777b538SAndroid Build Coastguard Worker static const int value =
39*6777b538SAndroid Build Coastguard Worker std::numeric_limits<NumericType>::digits + std::is_signed_v<NumericType>;
40*6777b538SAndroid Build Coastguard Worker };
41*6777b538SAndroid Build Coastguard Worker
42*6777b538SAndroid Build Coastguard Worker // Helper templates for integer manipulations.
43*6777b538SAndroid Build Coastguard Worker
44*6777b538SAndroid Build Coastguard Worker template <typename Integer>
45*6777b538SAndroid Build Coastguard Worker struct PositionOfSignBit {
46*6777b538SAndroid Build Coastguard Worker static const size_t value = IntegerBitsPlusSign<Integer>::value - 1;
47*6777b538SAndroid Build Coastguard Worker };
48*6777b538SAndroid Build Coastguard Worker
49*6777b538SAndroid Build Coastguard Worker // Determines if a numeric value is negative without throwing compiler
50*6777b538SAndroid Build Coastguard Worker // warnings on: unsigned(value) < 0.
51*6777b538SAndroid Build Coastguard Worker template <typename T>
requires(std::is_arithmetic_v<T> && std::is_signed_v<T>)52*6777b538SAndroid Build Coastguard Worker requires(std::is_arithmetic_v<T> && std::is_signed_v<T>)
53*6777b538SAndroid Build Coastguard Worker constexpr bool IsValueNegative(T value) {
54*6777b538SAndroid Build Coastguard Worker return value < 0;
55*6777b538SAndroid Build Coastguard Worker }
56*6777b538SAndroid Build Coastguard Worker
57*6777b538SAndroid Build Coastguard Worker template <typename T>
requires(std::is_arithmetic_v<T> && std::is_unsigned_v<T>)58*6777b538SAndroid Build Coastguard Worker requires(std::is_arithmetic_v<T> && std::is_unsigned_v<T>)
59*6777b538SAndroid Build Coastguard Worker constexpr bool IsValueNegative(T) {
60*6777b538SAndroid Build Coastguard Worker return false;
61*6777b538SAndroid Build Coastguard Worker }
62*6777b538SAndroid Build Coastguard Worker
63*6777b538SAndroid Build Coastguard Worker // This performs a fast negation, returning a signed value. It works on unsigned
64*6777b538SAndroid Build Coastguard Worker // arguments, but probably doesn't do what you want for any unsigned value
65*6777b538SAndroid Build Coastguard Worker // larger than max / 2 + 1 (i.e. signed min cast to unsigned).
66*6777b538SAndroid Build Coastguard Worker template <typename T>
ConditionalNegate(T x,bool is_negative)67*6777b538SAndroid Build Coastguard Worker constexpr typename std::make_signed<T>::type ConditionalNegate(
68*6777b538SAndroid Build Coastguard Worker T x,
69*6777b538SAndroid Build Coastguard Worker bool is_negative) {
70*6777b538SAndroid Build Coastguard Worker static_assert(std::is_integral_v<T>, "Type must be integral");
71*6777b538SAndroid Build Coastguard Worker using SignedT = typename std::make_signed<T>::type;
72*6777b538SAndroid Build Coastguard Worker using UnsignedT = typename std::make_unsigned<T>::type;
73*6777b538SAndroid Build Coastguard Worker return static_cast<SignedT>((static_cast<UnsignedT>(x) ^
74*6777b538SAndroid Build Coastguard Worker static_cast<UnsignedT>(-SignedT(is_negative))) +
75*6777b538SAndroid Build Coastguard Worker is_negative);
76*6777b538SAndroid Build Coastguard Worker }
77*6777b538SAndroid Build Coastguard Worker
78*6777b538SAndroid Build Coastguard Worker // This performs a safe, absolute value via unsigned overflow.
79*6777b538SAndroid Build Coastguard Worker template <typename T>
SafeUnsignedAbs(T value)80*6777b538SAndroid Build Coastguard Worker constexpr typename std::make_unsigned<T>::type SafeUnsignedAbs(T value) {
81*6777b538SAndroid Build Coastguard Worker static_assert(std::is_integral_v<T>, "Type must be integral");
82*6777b538SAndroid Build Coastguard Worker using UnsignedT = typename std::make_unsigned<T>::type;
83*6777b538SAndroid Build Coastguard Worker return IsValueNegative(value)
84*6777b538SAndroid Build Coastguard Worker ? static_cast<UnsignedT>(0u - static_cast<UnsignedT>(value))
85*6777b538SAndroid Build Coastguard Worker : static_cast<UnsignedT>(value);
86*6777b538SAndroid Build Coastguard Worker }
87*6777b538SAndroid Build Coastguard Worker
88*6777b538SAndroid Build Coastguard Worker // TODO(jschuh): Switch to std::is_constant_evaluated() once C++20 is supported.
89*6777b538SAndroid Build Coastguard Worker // Alternately, the usage could be restructured for "consteval if" in C++23.
90*6777b538SAndroid Build Coastguard Worker #define IsConstantEvaluated() (__builtin_is_constant_evaluated())
91*6777b538SAndroid Build Coastguard Worker
92*6777b538SAndroid Build Coastguard Worker // TODO(jschuh): Debug builds don't reliably propagate constants, so we restrict
93*6777b538SAndroid Build Coastguard Worker // some accelerated runtime paths to release builds until this can be forced
94*6777b538SAndroid Build Coastguard Worker // with consteval support in C++20 or C++23.
95*6777b538SAndroid Build Coastguard Worker #if defined(NDEBUG)
96*6777b538SAndroid Build Coastguard Worker constexpr bool kEnableAsmCode = true;
97*6777b538SAndroid Build Coastguard Worker #else
98*6777b538SAndroid Build Coastguard Worker constexpr bool kEnableAsmCode = false;
99*6777b538SAndroid Build Coastguard Worker #endif
100*6777b538SAndroid Build Coastguard Worker
101*6777b538SAndroid Build Coastguard Worker // Forces a crash, like a CHECK(false). Used for numeric boundary errors.
102*6777b538SAndroid Build Coastguard Worker // Also used in a constexpr template to trigger a compilation failure on
103*6777b538SAndroid Build Coastguard Worker // an error condition.
104*6777b538SAndroid Build Coastguard Worker struct CheckOnFailure {
105*6777b538SAndroid Build Coastguard Worker template <typename T>
HandleFailureCheckOnFailure106*6777b538SAndroid Build Coastguard Worker static T HandleFailure() {
107*6777b538SAndroid Build Coastguard Worker #if defined(_MSC_VER)
108*6777b538SAndroid Build Coastguard Worker __debugbreak();
109*6777b538SAndroid Build Coastguard Worker #elif defined(__GNUC__) || defined(__clang__)
110*6777b538SAndroid Build Coastguard Worker __builtin_trap();
111*6777b538SAndroid Build Coastguard Worker #else
112*6777b538SAndroid Build Coastguard Worker ((void)(*(volatile char*)0 = 0));
113*6777b538SAndroid Build Coastguard Worker #endif
114*6777b538SAndroid Build Coastguard Worker return T();
115*6777b538SAndroid Build Coastguard Worker }
116*6777b538SAndroid Build Coastguard Worker };
117*6777b538SAndroid Build Coastguard Worker
118*6777b538SAndroid Build Coastguard Worker enum IntegerRepresentation {
119*6777b538SAndroid Build Coastguard Worker INTEGER_REPRESENTATION_UNSIGNED,
120*6777b538SAndroid Build Coastguard Worker INTEGER_REPRESENTATION_SIGNED
121*6777b538SAndroid Build Coastguard Worker };
122*6777b538SAndroid Build Coastguard Worker
123*6777b538SAndroid Build Coastguard Worker // A range for a given nunmeric Src type is contained for a given numeric Dst
124*6777b538SAndroid Build Coastguard Worker // type if both numeric_limits<Src>::max() <= numeric_limits<Dst>::max() and
125*6777b538SAndroid Build Coastguard Worker // numeric_limits<Src>::lowest() >= numeric_limits<Dst>::lowest() are true.
126*6777b538SAndroid Build Coastguard Worker // We implement this as template specializations rather than simple static
127*6777b538SAndroid Build Coastguard Worker // comparisons to ensure type correctness in our comparisons.
128*6777b538SAndroid Build Coastguard Worker enum NumericRangeRepresentation {
129*6777b538SAndroid Build Coastguard Worker NUMERIC_RANGE_NOT_CONTAINED,
130*6777b538SAndroid Build Coastguard Worker NUMERIC_RANGE_CONTAINED
131*6777b538SAndroid Build Coastguard Worker };
132*6777b538SAndroid Build Coastguard Worker
133*6777b538SAndroid Build Coastguard Worker // Helper templates to statically determine if our destination type can contain
134*6777b538SAndroid Build Coastguard Worker // maximum and minimum values represented by the source type.
135*6777b538SAndroid Build Coastguard Worker
136*6777b538SAndroid Build Coastguard Worker template <typename Dst,
137*6777b538SAndroid Build Coastguard Worker typename Src,
138*6777b538SAndroid Build Coastguard Worker IntegerRepresentation DstSign = std::is_signed_v<Dst>
139*6777b538SAndroid Build Coastguard Worker ? INTEGER_REPRESENTATION_SIGNED
140*6777b538SAndroid Build Coastguard Worker : INTEGER_REPRESENTATION_UNSIGNED,
141*6777b538SAndroid Build Coastguard Worker IntegerRepresentation SrcSign = std::is_signed_v<Src>
142*6777b538SAndroid Build Coastguard Worker ? INTEGER_REPRESENTATION_SIGNED
143*6777b538SAndroid Build Coastguard Worker : INTEGER_REPRESENTATION_UNSIGNED>
144*6777b538SAndroid Build Coastguard Worker struct StaticDstRangeRelationToSrcRange;
145*6777b538SAndroid Build Coastguard Worker
146*6777b538SAndroid Build Coastguard Worker // Same sign: Dst is guaranteed to contain Src only if its range is equal or
147*6777b538SAndroid Build Coastguard Worker // larger.
148*6777b538SAndroid Build Coastguard Worker template <typename Dst, typename Src, IntegerRepresentation Sign>
149*6777b538SAndroid Build Coastguard Worker struct StaticDstRangeRelationToSrcRange<Dst, Src, Sign, Sign> {
150*6777b538SAndroid Build Coastguard Worker static const NumericRangeRepresentation value =
151*6777b538SAndroid Build Coastguard Worker MaxExponent<Dst>::value >= MaxExponent<Src>::value
152*6777b538SAndroid Build Coastguard Worker ? NUMERIC_RANGE_CONTAINED
153*6777b538SAndroid Build Coastguard Worker : NUMERIC_RANGE_NOT_CONTAINED;
154*6777b538SAndroid Build Coastguard Worker };
155*6777b538SAndroid Build Coastguard Worker
156*6777b538SAndroid Build Coastguard Worker // Unsigned to signed: Dst is guaranteed to contain source only if its range is
157*6777b538SAndroid Build Coastguard Worker // larger.
158*6777b538SAndroid Build Coastguard Worker template <typename Dst, typename Src>
159*6777b538SAndroid Build Coastguard Worker struct StaticDstRangeRelationToSrcRange<Dst,
160*6777b538SAndroid Build Coastguard Worker Src,
161*6777b538SAndroid Build Coastguard Worker INTEGER_REPRESENTATION_SIGNED,
162*6777b538SAndroid Build Coastguard Worker INTEGER_REPRESENTATION_UNSIGNED> {
163*6777b538SAndroid Build Coastguard Worker static const NumericRangeRepresentation value =
164*6777b538SAndroid Build Coastguard Worker MaxExponent<Dst>::value > MaxExponent<Src>::value
165*6777b538SAndroid Build Coastguard Worker ? NUMERIC_RANGE_CONTAINED
166*6777b538SAndroid Build Coastguard Worker : NUMERIC_RANGE_NOT_CONTAINED;
167*6777b538SAndroid Build Coastguard Worker };
168*6777b538SAndroid Build Coastguard Worker
169*6777b538SAndroid Build Coastguard Worker // Signed to unsigned: Dst cannot be statically determined to contain Src.
170*6777b538SAndroid Build Coastguard Worker template <typename Dst, typename Src>
171*6777b538SAndroid Build Coastguard Worker struct StaticDstRangeRelationToSrcRange<Dst,
172*6777b538SAndroid Build Coastguard Worker Src,
173*6777b538SAndroid Build Coastguard Worker INTEGER_REPRESENTATION_UNSIGNED,
174*6777b538SAndroid Build Coastguard Worker INTEGER_REPRESENTATION_SIGNED> {
175*6777b538SAndroid Build Coastguard Worker static const NumericRangeRepresentation value = NUMERIC_RANGE_NOT_CONTAINED;
176*6777b538SAndroid Build Coastguard Worker };
177*6777b538SAndroid Build Coastguard Worker
178*6777b538SAndroid Build Coastguard Worker // This class wraps the range constraints as separate booleans so the compiler
179*6777b538SAndroid Build Coastguard Worker // can identify constants and eliminate unused code paths.
180*6777b538SAndroid Build Coastguard Worker class RangeCheck {
181*6777b538SAndroid Build Coastguard Worker public:
182*6777b538SAndroid Build Coastguard Worker constexpr RangeCheck(bool is_in_lower_bound, bool is_in_upper_bound)
183*6777b538SAndroid Build Coastguard Worker : is_underflow_(!is_in_lower_bound), is_overflow_(!is_in_upper_bound) {}
184*6777b538SAndroid Build Coastguard Worker constexpr RangeCheck() : is_underflow_(false), is_overflow_(false) {}
185*6777b538SAndroid Build Coastguard Worker constexpr bool IsValid() const { return !is_overflow_ && !is_underflow_; }
186*6777b538SAndroid Build Coastguard Worker constexpr bool IsInvalid() const { return is_overflow_ && is_underflow_; }
187*6777b538SAndroid Build Coastguard Worker constexpr bool IsOverflow() const { return is_overflow_ && !is_underflow_; }
188*6777b538SAndroid Build Coastguard Worker constexpr bool IsUnderflow() const { return !is_overflow_ && is_underflow_; }
189*6777b538SAndroid Build Coastguard Worker constexpr bool IsOverflowFlagSet() const { return is_overflow_; }
190*6777b538SAndroid Build Coastguard Worker constexpr bool IsUnderflowFlagSet() const { return is_underflow_; }
191*6777b538SAndroid Build Coastguard Worker constexpr bool operator==(const RangeCheck rhs) const {
192*6777b538SAndroid Build Coastguard Worker return is_underflow_ == rhs.is_underflow_ &&
193*6777b538SAndroid Build Coastguard Worker is_overflow_ == rhs.is_overflow_;
194*6777b538SAndroid Build Coastguard Worker }
195*6777b538SAndroid Build Coastguard Worker constexpr bool operator!=(const RangeCheck rhs) const {
196*6777b538SAndroid Build Coastguard Worker return !(*this == rhs);
197*6777b538SAndroid Build Coastguard Worker }
198*6777b538SAndroid Build Coastguard Worker
199*6777b538SAndroid Build Coastguard Worker private:
200*6777b538SAndroid Build Coastguard Worker // Do not change the order of these member variables. The integral conversion
201*6777b538SAndroid Build Coastguard Worker // optimization depends on this exact order.
202*6777b538SAndroid Build Coastguard Worker const bool is_underflow_;
203*6777b538SAndroid Build Coastguard Worker const bool is_overflow_;
204*6777b538SAndroid Build Coastguard Worker };
205*6777b538SAndroid Build Coastguard Worker
206*6777b538SAndroid Build Coastguard Worker // The following helper template addresses a corner case in range checks for
207*6777b538SAndroid Build Coastguard Worker // conversion from a floating-point type to an integral type of smaller range
208*6777b538SAndroid Build Coastguard Worker // but larger precision (e.g. float -> unsigned). The problem is as follows:
209*6777b538SAndroid Build Coastguard Worker // 1. Integral maximum is always one less than a power of two, so it must be
210*6777b538SAndroid Build Coastguard Worker // truncated to fit the mantissa of the floating point. The direction of
211*6777b538SAndroid Build Coastguard Worker // rounding is implementation defined, but by default it's always IEEE
212*6777b538SAndroid Build Coastguard Worker // floats, which round to nearest and thus result in a value of larger
213*6777b538SAndroid Build Coastguard Worker // magnitude than the integral value.
214*6777b538SAndroid Build Coastguard Worker // Example: float f = UINT_MAX; // f is 4294967296f but UINT_MAX
215*6777b538SAndroid Build Coastguard Worker // // is 4294967295u.
216*6777b538SAndroid Build Coastguard Worker // 2. If the floating point value is equal to the promoted integral maximum
217*6777b538SAndroid Build Coastguard Worker // value, a range check will erroneously pass.
218*6777b538SAndroid Build Coastguard Worker // Example: (4294967296f <= 4294967295u) // This is true due to a precision
219*6777b538SAndroid Build Coastguard Worker // // loss in rounding up to float.
220*6777b538SAndroid Build Coastguard Worker // 3. When the floating point value is then converted to an integral, the
221*6777b538SAndroid Build Coastguard Worker // resulting value is out of range for the target integral type and
222*6777b538SAndroid Build Coastguard Worker // thus is implementation defined.
223*6777b538SAndroid Build Coastguard Worker // Example: unsigned u = (float)INT_MAX; // u will typically overflow to 0.
224*6777b538SAndroid Build Coastguard Worker // To fix this bug we manually truncate the maximum value when the destination
225*6777b538SAndroid Build Coastguard Worker // type is an integral of larger precision than the source floating-point type,
226*6777b538SAndroid Build Coastguard Worker // such that the resulting maximum is represented exactly as a floating point.
227*6777b538SAndroid Build Coastguard Worker template <typename Dst, typename Src, template <typename> class Bounds>
228*6777b538SAndroid Build Coastguard Worker struct NarrowingRange {
229*6777b538SAndroid Build Coastguard Worker using SrcLimits = std::numeric_limits<Src>;
230*6777b538SAndroid Build Coastguard Worker using DstLimits = typename std::numeric_limits<Dst>;
231*6777b538SAndroid Build Coastguard Worker
232*6777b538SAndroid Build Coastguard Worker // Computes the mask required to make an accurate comparison between types.
233*6777b538SAndroid Build Coastguard Worker static const int kShift =
234*6777b538SAndroid Build Coastguard Worker (MaxExponent<Src>::value > MaxExponent<Dst>::value &&
235*6777b538SAndroid Build Coastguard Worker SrcLimits::digits < DstLimits::digits)
236*6777b538SAndroid Build Coastguard Worker ? (DstLimits::digits - SrcLimits::digits)
237*6777b538SAndroid Build Coastguard Worker : 0;
238*6777b538SAndroid Build Coastguard Worker
239*6777b538SAndroid Build Coastguard Worker template <typename T>
240*6777b538SAndroid Build Coastguard Worker requires(std::integral<T>)
241*6777b538SAndroid Build Coastguard Worker // Masks out the integer bits that are beyond the precision of the
242*6777b538SAndroid Build Coastguard Worker // intermediate type used for comparison.
243*6777b538SAndroid Build Coastguard Worker static constexpr T Adjust(T value) {
244*6777b538SAndroid Build Coastguard Worker static_assert(std::is_same_v<T, Dst>, "");
245*6777b538SAndroid Build Coastguard Worker static_assert(kShift < DstLimits::digits, "");
246*6777b538SAndroid Build Coastguard Worker using UnsignedDst = typename std::make_unsigned_t<T>;
247*6777b538SAndroid Build Coastguard Worker return static_cast<T>(ConditionalNegate(
248*6777b538SAndroid Build Coastguard Worker SafeUnsignedAbs(value) & ~((UnsignedDst{1} << kShift) - UnsignedDst{1}),
249*6777b538SAndroid Build Coastguard Worker IsValueNegative(value)));
250*6777b538SAndroid Build Coastguard Worker }
251*6777b538SAndroid Build Coastguard Worker
252*6777b538SAndroid Build Coastguard Worker template <typename T>
253*6777b538SAndroid Build Coastguard Worker requires(std::floating_point<T>)
254*6777b538SAndroid Build Coastguard Worker static constexpr T Adjust(T value) {
255*6777b538SAndroid Build Coastguard Worker static_assert(std::is_same_v<T, Dst>, "");
256*6777b538SAndroid Build Coastguard Worker static_assert(kShift == 0, "");
257*6777b538SAndroid Build Coastguard Worker return value;
258*6777b538SAndroid Build Coastguard Worker }
259*6777b538SAndroid Build Coastguard Worker
260*6777b538SAndroid Build Coastguard Worker static constexpr Dst max() { return Adjust(Bounds<Dst>::max()); }
261*6777b538SAndroid Build Coastguard Worker static constexpr Dst lowest() { return Adjust(Bounds<Dst>::lowest()); }
262*6777b538SAndroid Build Coastguard Worker };
263*6777b538SAndroid Build Coastguard Worker
264*6777b538SAndroid Build Coastguard Worker template <typename Dst,
265*6777b538SAndroid Build Coastguard Worker typename Src,
266*6777b538SAndroid Build Coastguard Worker template <typename>
267*6777b538SAndroid Build Coastguard Worker class Bounds,
268*6777b538SAndroid Build Coastguard Worker IntegerRepresentation DstSign = std::is_signed_v<Dst>
269*6777b538SAndroid Build Coastguard Worker ? INTEGER_REPRESENTATION_SIGNED
270*6777b538SAndroid Build Coastguard Worker : INTEGER_REPRESENTATION_UNSIGNED,
271*6777b538SAndroid Build Coastguard Worker IntegerRepresentation SrcSign = std::is_signed_v<Src>
272*6777b538SAndroid Build Coastguard Worker ? INTEGER_REPRESENTATION_SIGNED
273*6777b538SAndroid Build Coastguard Worker : INTEGER_REPRESENTATION_UNSIGNED,
274*6777b538SAndroid Build Coastguard Worker NumericRangeRepresentation DstRange =
275*6777b538SAndroid Build Coastguard Worker StaticDstRangeRelationToSrcRange<Dst, Src>::value>
276*6777b538SAndroid Build Coastguard Worker struct DstRangeRelationToSrcRangeImpl;
277*6777b538SAndroid Build Coastguard Worker
278*6777b538SAndroid Build Coastguard Worker // The following templates are for ranges that must be verified at runtime. We
279*6777b538SAndroid Build Coastguard Worker // split it into checks based on signedness to avoid confusing casts and
280*6777b538SAndroid Build Coastguard Worker // compiler warnings on signed an unsigned comparisons.
281*6777b538SAndroid Build Coastguard Worker
282*6777b538SAndroid Build Coastguard Worker // Same sign narrowing: The range is contained for normal limits.
283*6777b538SAndroid Build Coastguard Worker template <typename Dst,
284*6777b538SAndroid Build Coastguard Worker typename Src,
285*6777b538SAndroid Build Coastguard Worker template <typename>
286*6777b538SAndroid Build Coastguard Worker class Bounds,
287*6777b538SAndroid Build Coastguard Worker IntegerRepresentation DstSign,
288*6777b538SAndroid Build Coastguard Worker IntegerRepresentation SrcSign>
289*6777b538SAndroid Build Coastguard Worker struct DstRangeRelationToSrcRangeImpl<Dst,
290*6777b538SAndroid Build Coastguard Worker Src,
291*6777b538SAndroid Build Coastguard Worker Bounds,
292*6777b538SAndroid Build Coastguard Worker DstSign,
293*6777b538SAndroid Build Coastguard Worker SrcSign,
294*6777b538SAndroid Build Coastguard Worker NUMERIC_RANGE_CONTAINED> {
295*6777b538SAndroid Build Coastguard Worker static constexpr RangeCheck Check(Src value) {
296*6777b538SAndroid Build Coastguard Worker using SrcLimits = std::numeric_limits<Src>;
297*6777b538SAndroid Build Coastguard Worker using DstLimits = NarrowingRange<Dst, Src, Bounds>;
298*6777b538SAndroid Build Coastguard Worker return RangeCheck(
299*6777b538SAndroid Build Coastguard Worker static_cast<Dst>(SrcLimits::lowest()) >= DstLimits::lowest() ||
300*6777b538SAndroid Build Coastguard Worker static_cast<Dst>(value) >= DstLimits::lowest(),
301*6777b538SAndroid Build Coastguard Worker static_cast<Dst>(SrcLimits::max()) <= DstLimits::max() ||
302*6777b538SAndroid Build Coastguard Worker static_cast<Dst>(value) <= DstLimits::max());
303*6777b538SAndroid Build Coastguard Worker }
304*6777b538SAndroid Build Coastguard Worker };
305*6777b538SAndroid Build Coastguard Worker
306*6777b538SAndroid Build Coastguard Worker // Signed to signed narrowing: Both the upper and lower boundaries may be
307*6777b538SAndroid Build Coastguard Worker // exceeded for standard limits.
308*6777b538SAndroid Build Coastguard Worker template <typename Dst, typename Src, template <typename> class Bounds>
309*6777b538SAndroid Build Coastguard Worker struct DstRangeRelationToSrcRangeImpl<Dst,
310*6777b538SAndroid Build Coastguard Worker Src,
311*6777b538SAndroid Build Coastguard Worker Bounds,
312*6777b538SAndroid Build Coastguard Worker INTEGER_REPRESENTATION_SIGNED,
313*6777b538SAndroid Build Coastguard Worker INTEGER_REPRESENTATION_SIGNED,
314*6777b538SAndroid Build Coastguard Worker NUMERIC_RANGE_NOT_CONTAINED> {
315*6777b538SAndroid Build Coastguard Worker static constexpr RangeCheck Check(Src value) {
316*6777b538SAndroid Build Coastguard Worker using DstLimits = NarrowingRange<Dst, Src, Bounds>;
317*6777b538SAndroid Build Coastguard Worker return RangeCheck(value >= DstLimits::lowest(), value <= DstLimits::max());
318*6777b538SAndroid Build Coastguard Worker }
319*6777b538SAndroid Build Coastguard Worker };
320*6777b538SAndroid Build Coastguard Worker
321*6777b538SAndroid Build Coastguard Worker // Unsigned to unsigned narrowing: Only the upper bound can be exceeded for
322*6777b538SAndroid Build Coastguard Worker // standard limits.
323*6777b538SAndroid Build Coastguard Worker template <typename Dst, typename Src, template <typename> class Bounds>
324*6777b538SAndroid Build Coastguard Worker struct DstRangeRelationToSrcRangeImpl<Dst,
325*6777b538SAndroid Build Coastguard Worker Src,
326*6777b538SAndroid Build Coastguard Worker Bounds,
327*6777b538SAndroid Build Coastguard Worker INTEGER_REPRESENTATION_UNSIGNED,
328*6777b538SAndroid Build Coastguard Worker INTEGER_REPRESENTATION_UNSIGNED,
329*6777b538SAndroid Build Coastguard Worker NUMERIC_RANGE_NOT_CONTAINED> {
330*6777b538SAndroid Build Coastguard Worker static constexpr RangeCheck Check(Src value) {
331*6777b538SAndroid Build Coastguard Worker using DstLimits = NarrowingRange<Dst, Src, Bounds>;
332*6777b538SAndroid Build Coastguard Worker return RangeCheck(
333*6777b538SAndroid Build Coastguard Worker DstLimits::lowest() == Dst(0) || value >= DstLimits::lowest(),
334*6777b538SAndroid Build Coastguard Worker value <= DstLimits::max());
335*6777b538SAndroid Build Coastguard Worker }
336*6777b538SAndroid Build Coastguard Worker };
337*6777b538SAndroid Build Coastguard Worker
338*6777b538SAndroid Build Coastguard Worker // Unsigned to signed: Only the upper bound can be exceeded for standard limits.
339*6777b538SAndroid Build Coastguard Worker template <typename Dst, typename Src, template <typename> class Bounds>
340*6777b538SAndroid Build Coastguard Worker struct DstRangeRelationToSrcRangeImpl<Dst,
341*6777b538SAndroid Build Coastguard Worker Src,
342*6777b538SAndroid Build Coastguard Worker Bounds,
343*6777b538SAndroid Build Coastguard Worker INTEGER_REPRESENTATION_SIGNED,
344*6777b538SAndroid Build Coastguard Worker INTEGER_REPRESENTATION_UNSIGNED,
345*6777b538SAndroid Build Coastguard Worker NUMERIC_RANGE_NOT_CONTAINED> {
346*6777b538SAndroid Build Coastguard Worker static constexpr RangeCheck Check(Src value) {
347*6777b538SAndroid Build Coastguard Worker using DstLimits = NarrowingRange<Dst, Src, Bounds>;
348*6777b538SAndroid Build Coastguard Worker using Promotion = decltype(Src() + Dst());
349*6777b538SAndroid Build Coastguard Worker return RangeCheck(DstLimits::lowest() <= Dst(0) ||
350*6777b538SAndroid Build Coastguard Worker static_cast<Promotion>(value) >=
351*6777b538SAndroid Build Coastguard Worker static_cast<Promotion>(DstLimits::lowest()),
352*6777b538SAndroid Build Coastguard Worker static_cast<Promotion>(value) <=
353*6777b538SAndroid Build Coastguard Worker static_cast<Promotion>(DstLimits::max()));
354*6777b538SAndroid Build Coastguard Worker }
355*6777b538SAndroid Build Coastguard Worker };
356*6777b538SAndroid Build Coastguard Worker
357*6777b538SAndroid Build Coastguard Worker // Signed to unsigned: The upper boundary may be exceeded for a narrower Dst,
358*6777b538SAndroid Build Coastguard Worker // and any negative value exceeds the lower boundary for standard limits.
359*6777b538SAndroid Build Coastguard Worker template <typename Dst, typename Src, template <typename> class Bounds>
360*6777b538SAndroid Build Coastguard Worker struct DstRangeRelationToSrcRangeImpl<Dst,
361*6777b538SAndroid Build Coastguard Worker Src,
362*6777b538SAndroid Build Coastguard Worker Bounds,
363*6777b538SAndroid Build Coastguard Worker INTEGER_REPRESENTATION_UNSIGNED,
364*6777b538SAndroid Build Coastguard Worker INTEGER_REPRESENTATION_SIGNED,
365*6777b538SAndroid Build Coastguard Worker NUMERIC_RANGE_NOT_CONTAINED> {
366*6777b538SAndroid Build Coastguard Worker static constexpr RangeCheck Check(Src value) {
367*6777b538SAndroid Build Coastguard Worker using SrcLimits = std::numeric_limits<Src>;
368*6777b538SAndroid Build Coastguard Worker using DstLimits = NarrowingRange<Dst, Src, Bounds>;
369*6777b538SAndroid Build Coastguard Worker using Promotion = decltype(Src() + Dst());
370*6777b538SAndroid Build Coastguard Worker bool ge_zero = false;
371*6777b538SAndroid Build Coastguard Worker // Converting floating-point to integer will discard fractional part, so
372*6777b538SAndroid Build Coastguard Worker // values in (-1.0, -0.0) will truncate to 0 and fit in Dst.
373*6777b538SAndroid Build Coastguard Worker if (std::is_floating_point_v<Src>) {
374*6777b538SAndroid Build Coastguard Worker ge_zero = value > Src(-1);
375*6777b538SAndroid Build Coastguard Worker } else {
376*6777b538SAndroid Build Coastguard Worker ge_zero = value >= Src(0);
377*6777b538SAndroid Build Coastguard Worker }
378*6777b538SAndroid Build Coastguard Worker return RangeCheck(
379*6777b538SAndroid Build Coastguard Worker ge_zero && (DstLimits::lowest() == 0 ||
380*6777b538SAndroid Build Coastguard Worker static_cast<Dst>(value) >= DstLimits::lowest()),
381*6777b538SAndroid Build Coastguard Worker static_cast<Promotion>(SrcLimits::max()) <=
382*6777b538SAndroid Build Coastguard Worker static_cast<Promotion>(DstLimits::max()) ||
383*6777b538SAndroid Build Coastguard Worker static_cast<Promotion>(value) <=
384*6777b538SAndroid Build Coastguard Worker static_cast<Promotion>(DstLimits::max()));
385*6777b538SAndroid Build Coastguard Worker }
386*6777b538SAndroid Build Coastguard Worker };
387*6777b538SAndroid Build Coastguard Worker
388*6777b538SAndroid Build Coastguard Worker // Simple wrapper for statically checking if a type's range is contained.
389*6777b538SAndroid Build Coastguard Worker template <typename Dst, typename Src>
390*6777b538SAndroid Build Coastguard Worker struct IsTypeInRangeForNumericType {
391*6777b538SAndroid Build Coastguard Worker static const bool value = StaticDstRangeRelationToSrcRange<Dst, Src>::value ==
392*6777b538SAndroid Build Coastguard Worker NUMERIC_RANGE_CONTAINED;
393*6777b538SAndroid Build Coastguard Worker };
394*6777b538SAndroid Build Coastguard Worker
395*6777b538SAndroid Build Coastguard Worker template <typename Dst,
396*6777b538SAndroid Build Coastguard Worker template <typename> class Bounds = std::numeric_limits,
397*6777b538SAndroid Build Coastguard Worker typename Src>
398*6777b538SAndroid Build Coastguard Worker constexpr RangeCheck DstRangeRelationToSrcRange(Src value) {
399*6777b538SAndroid Build Coastguard Worker static_assert(std::is_arithmetic_v<Src>, "Argument must be numeric.");
400*6777b538SAndroid Build Coastguard Worker static_assert(std::is_arithmetic_v<Dst>, "Result must be numeric.");
401*6777b538SAndroid Build Coastguard Worker static_assert(Bounds<Dst>::lowest() < Bounds<Dst>::max(), "");
402*6777b538SAndroid Build Coastguard Worker return DstRangeRelationToSrcRangeImpl<Dst, Src, Bounds>::Check(value);
403*6777b538SAndroid Build Coastguard Worker }
404*6777b538SAndroid Build Coastguard Worker
405*6777b538SAndroid Build Coastguard Worker // Integer promotion templates used by the portable checked integer arithmetic.
406*6777b538SAndroid Build Coastguard Worker template <size_t Size, bool IsSigned>
407*6777b538SAndroid Build Coastguard Worker struct IntegerForDigitsAndSign;
408*6777b538SAndroid Build Coastguard Worker
409*6777b538SAndroid Build Coastguard Worker #define INTEGER_FOR_DIGITS_AND_SIGN(I) \
410*6777b538SAndroid Build Coastguard Worker template <> \
411*6777b538SAndroid Build Coastguard Worker struct IntegerForDigitsAndSign<IntegerBitsPlusSign<I>::value, \
412*6777b538SAndroid Build Coastguard Worker std::is_signed_v<I>> { \
413*6777b538SAndroid Build Coastguard Worker using type = I; \
414*6777b538SAndroid Build Coastguard Worker }
415*6777b538SAndroid Build Coastguard Worker
416*6777b538SAndroid Build Coastguard Worker INTEGER_FOR_DIGITS_AND_SIGN(int8_t);
417*6777b538SAndroid Build Coastguard Worker INTEGER_FOR_DIGITS_AND_SIGN(uint8_t);
418*6777b538SAndroid Build Coastguard Worker INTEGER_FOR_DIGITS_AND_SIGN(int16_t);
419*6777b538SAndroid Build Coastguard Worker INTEGER_FOR_DIGITS_AND_SIGN(uint16_t);
420*6777b538SAndroid Build Coastguard Worker INTEGER_FOR_DIGITS_AND_SIGN(int32_t);
421*6777b538SAndroid Build Coastguard Worker INTEGER_FOR_DIGITS_AND_SIGN(uint32_t);
422*6777b538SAndroid Build Coastguard Worker INTEGER_FOR_DIGITS_AND_SIGN(int64_t);
423*6777b538SAndroid Build Coastguard Worker INTEGER_FOR_DIGITS_AND_SIGN(uint64_t);
424*6777b538SAndroid Build Coastguard Worker #undef INTEGER_FOR_DIGITS_AND_SIGN
425*6777b538SAndroid Build Coastguard Worker
426*6777b538SAndroid Build Coastguard Worker // WARNING: We have no IntegerForSizeAndSign<16, *>. If we ever add one to
427*6777b538SAndroid Build Coastguard Worker // support 128-bit math, then the ArithmeticPromotion template below will need
428*6777b538SAndroid Build Coastguard Worker // to be updated (or more likely replaced with a decltype expression).
429*6777b538SAndroid Build Coastguard Worker static_assert(IntegerBitsPlusSign<intmax_t>::value == 64,
430*6777b538SAndroid Build Coastguard Worker "Max integer size not supported for this toolchain.");
431*6777b538SAndroid Build Coastguard Worker
432*6777b538SAndroid Build Coastguard Worker template <typename Integer, bool IsSigned = std::is_signed_v<Integer>>
433*6777b538SAndroid Build Coastguard Worker struct TwiceWiderInteger {
434*6777b538SAndroid Build Coastguard Worker using type =
435*6777b538SAndroid Build Coastguard Worker typename IntegerForDigitsAndSign<IntegerBitsPlusSign<Integer>::value * 2,
436*6777b538SAndroid Build Coastguard Worker IsSigned>::type;
437*6777b538SAndroid Build Coastguard Worker };
438*6777b538SAndroid Build Coastguard Worker
439*6777b538SAndroid Build Coastguard Worker enum ArithmeticPromotionCategory {
440*6777b538SAndroid Build Coastguard Worker LEFT_PROMOTION, // Use the type of the left-hand argument.
441*6777b538SAndroid Build Coastguard Worker RIGHT_PROMOTION // Use the type of the right-hand argument.
442*6777b538SAndroid Build Coastguard Worker };
443*6777b538SAndroid Build Coastguard Worker
444*6777b538SAndroid Build Coastguard Worker // Determines the type that can represent the largest positive value.
445*6777b538SAndroid Build Coastguard Worker template <typename Lhs,
446*6777b538SAndroid Build Coastguard Worker typename Rhs,
447*6777b538SAndroid Build Coastguard Worker ArithmeticPromotionCategory Promotion =
448*6777b538SAndroid Build Coastguard Worker (MaxExponent<Lhs>::value > MaxExponent<Rhs>::value)
449*6777b538SAndroid Build Coastguard Worker ? LEFT_PROMOTION
450*6777b538SAndroid Build Coastguard Worker : RIGHT_PROMOTION>
451*6777b538SAndroid Build Coastguard Worker struct MaxExponentPromotion;
452*6777b538SAndroid Build Coastguard Worker
453*6777b538SAndroid Build Coastguard Worker template <typename Lhs, typename Rhs>
454*6777b538SAndroid Build Coastguard Worker struct MaxExponentPromotion<Lhs, Rhs, LEFT_PROMOTION> {
455*6777b538SAndroid Build Coastguard Worker using type = Lhs;
456*6777b538SAndroid Build Coastguard Worker };
457*6777b538SAndroid Build Coastguard Worker
458*6777b538SAndroid Build Coastguard Worker template <typename Lhs, typename Rhs>
459*6777b538SAndroid Build Coastguard Worker struct MaxExponentPromotion<Lhs, Rhs, RIGHT_PROMOTION> {
460*6777b538SAndroid Build Coastguard Worker using type = Rhs;
461*6777b538SAndroid Build Coastguard Worker };
462*6777b538SAndroid Build Coastguard Worker
463*6777b538SAndroid Build Coastguard Worker // Determines the type that can represent the lowest arithmetic value.
464*6777b538SAndroid Build Coastguard Worker template <typename Lhs,
465*6777b538SAndroid Build Coastguard Worker typename Rhs,
466*6777b538SAndroid Build Coastguard Worker ArithmeticPromotionCategory Promotion =
467*6777b538SAndroid Build Coastguard Worker std::is_signed_v<Lhs>
468*6777b538SAndroid Build Coastguard Worker ? (std::is_signed_v<Rhs>
469*6777b538SAndroid Build Coastguard Worker ? (MaxExponent<Lhs>::value > MaxExponent<Rhs>::value
470*6777b538SAndroid Build Coastguard Worker ? LEFT_PROMOTION
471*6777b538SAndroid Build Coastguard Worker : RIGHT_PROMOTION)
472*6777b538SAndroid Build Coastguard Worker : LEFT_PROMOTION)
473*6777b538SAndroid Build Coastguard Worker : (std::is_signed_v<Rhs>
474*6777b538SAndroid Build Coastguard Worker ? RIGHT_PROMOTION
475*6777b538SAndroid Build Coastguard Worker : (MaxExponent<Lhs>::value < MaxExponent<Rhs>::value
476*6777b538SAndroid Build Coastguard Worker ? LEFT_PROMOTION
477*6777b538SAndroid Build Coastguard Worker : RIGHT_PROMOTION))>
478*6777b538SAndroid Build Coastguard Worker struct LowestValuePromotion;
479*6777b538SAndroid Build Coastguard Worker
480*6777b538SAndroid Build Coastguard Worker template <typename Lhs, typename Rhs>
481*6777b538SAndroid Build Coastguard Worker struct LowestValuePromotion<Lhs, Rhs, LEFT_PROMOTION> {
482*6777b538SAndroid Build Coastguard Worker using type = Lhs;
483*6777b538SAndroid Build Coastguard Worker };
484*6777b538SAndroid Build Coastguard Worker
485*6777b538SAndroid Build Coastguard Worker template <typename Lhs, typename Rhs>
486*6777b538SAndroid Build Coastguard Worker struct LowestValuePromotion<Lhs, Rhs, RIGHT_PROMOTION> {
487*6777b538SAndroid Build Coastguard Worker using type = Rhs;
488*6777b538SAndroid Build Coastguard Worker };
489*6777b538SAndroid Build Coastguard Worker
490*6777b538SAndroid Build Coastguard Worker // Determines the type that is best able to represent an arithmetic result.
491*6777b538SAndroid Build Coastguard Worker template <
492*6777b538SAndroid Build Coastguard Worker typename Lhs,
493*6777b538SAndroid Build Coastguard Worker typename Rhs = Lhs,
494*6777b538SAndroid Build Coastguard Worker bool is_intmax_type =
495*6777b538SAndroid Build Coastguard Worker std::is_integral_v<typename MaxExponentPromotion<Lhs, Rhs>::type> &&
496*6777b538SAndroid Build Coastguard Worker IntegerBitsPlusSign<typename MaxExponentPromotion<Lhs, Rhs>::type>::
497*6777b538SAndroid Build Coastguard Worker value == IntegerBitsPlusSign<intmax_t>::value,
498*6777b538SAndroid Build Coastguard Worker bool is_max_exponent = StaticDstRangeRelationToSrcRange<
499*6777b538SAndroid Build Coastguard Worker typename MaxExponentPromotion<Lhs, Rhs>::type,
500*6777b538SAndroid Build Coastguard Worker Lhs>::value == NUMERIC_RANGE_CONTAINED &&
501*6777b538SAndroid Build Coastguard Worker StaticDstRangeRelationToSrcRange<
502*6777b538SAndroid Build Coastguard Worker typename MaxExponentPromotion<Lhs, Rhs>::type,
503*6777b538SAndroid Build Coastguard Worker Rhs>::value == NUMERIC_RANGE_CONTAINED>
504*6777b538SAndroid Build Coastguard Worker struct BigEnoughPromotion;
505*6777b538SAndroid Build Coastguard Worker
506*6777b538SAndroid Build Coastguard Worker // The side with the max exponent is big enough.
507*6777b538SAndroid Build Coastguard Worker template <typename Lhs, typename Rhs, bool is_intmax_type>
508*6777b538SAndroid Build Coastguard Worker struct BigEnoughPromotion<Lhs, Rhs, is_intmax_type, true> {
509*6777b538SAndroid Build Coastguard Worker using type = typename MaxExponentPromotion<Lhs, Rhs>::type;
510*6777b538SAndroid Build Coastguard Worker static const bool is_contained = true;
511*6777b538SAndroid Build Coastguard Worker };
512*6777b538SAndroid Build Coastguard Worker
513*6777b538SAndroid Build Coastguard Worker // We can use a twice wider type to fit.
514*6777b538SAndroid Build Coastguard Worker template <typename Lhs, typename Rhs>
515*6777b538SAndroid Build Coastguard Worker struct BigEnoughPromotion<Lhs, Rhs, false, false> {
516*6777b538SAndroid Build Coastguard Worker using type =
517*6777b538SAndroid Build Coastguard Worker typename TwiceWiderInteger<typename MaxExponentPromotion<Lhs, Rhs>::type,
518*6777b538SAndroid Build Coastguard Worker std::is_signed_v<Lhs> ||
519*6777b538SAndroid Build Coastguard Worker std::is_signed_v<Rhs>>::type;
520*6777b538SAndroid Build Coastguard Worker static const bool is_contained = true;
521*6777b538SAndroid Build Coastguard Worker };
522*6777b538SAndroid Build Coastguard Worker
523*6777b538SAndroid Build Coastguard Worker // No type is large enough.
524*6777b538SAndroid Build Coastguard Worker template <typename Lhs, typename Rhs>
525*6777b538SAndroid Build Coastguard Worker struct BigEnoughPromotion<Lhs, Rhs, true, false> {
526*6777b538SAndroid Build Coastguard Worker using type = typename MaxExponentPromotion<Lhs, Rhs>::type;
527*6777b538SAndroid Build Coastguard Worker static const bool is_contained = false;
528*6777b538SAndroid Build Coastguard Worker };
529*6777b538SAndroid Build Coastguard Worker
530*6777b538SAndroid Build Coastguard Worker // We can statically check if operations on the provided types can wrap, so we
531*6777b538SAndroid Build Coastguard Worker // can skip the checked operations if they're not needed. So, for an integer we
532*6777b538SAndroid Build Coastguard Worker // care if the destination type preserves the sign and is twice the width of
533*6777b538SAndroid Build Coastguard Worker // the source.
534*6777b538SAndroid Build Coastguard Worker template <typename T, typename Lhs, typename Rhs = Lhs>
535*6777b538SAndroid Build Coastguard Worker struct IsIntegerArithmeticSafe {
536*6777b538SAndroid Build Coastguard Worker static const bool value =
537*6777b538SAndroid Build Coastguard Worker !std::is_floating_point_v<T> && !std::is_floating_point_v<Lhs> &&
538*6777b538SAndroid Build Coastguard Worker !std::is_floating_point_v<Rhs> &&
539*6777b538SAndroid Build Coastguard Worker std::is_signed_v<T> >= std::is_signed_v<Lhs> &&
540*6777b538SAndroid Build Coastguard Worker IntegerBitsPlusSign<T>::value >= (2 * IntegerBitsPlusSign<Lhs>::value) &&
541*6777b538SAndroid Build Coastguard Worker std::is_signed_v<T> >= std::is_signed_v<Rhs> &&
542*6777b538SAndroid Build Coastguard Worker IntegerBitsPlusSign<T>::value >= (2 * IntegerBitsPlusSign<Rhs>::value);
543*6777b538SAndroid Build Coastguard Worker };
544*6777b538SAndroid Build Coastguard Worker
545*6777b538SAndroid Build Coastguard Worker // Promotes to a type that can represent any possible result of a binary
546*6777b538SAndroid Build Coastguard Worker // arithmetic operation with the source types.
547*6777b538SAndroid Build Coastguard Worker template <typename Lhs, typename Rhs>
548*6777b538SAndroid Build Coastguard Worker struct FastIntegerArithmeticPromotion {
549*6777b538SAndroid Build Coastguard Worker using type = typename BigEnoughPromotion<Lhs, Rhs>::type;
550*6777b538SAndroid Build Coastguard Worker static const bool is_contained = false;
551*6777b538SAndroid Build Coastguard Worker };
552*6777b538SAndroid Build Coastguard Worker
553*6777b538SAndroid Build Coastguard Worker template <typename Lhs, typename Rhs>
554*6777b538SAndroid Build Coastguard Worker requires(IsIntegerArithmeticSafe<
555*6777b538SAndroid Build Coastguard Worker std::conditional_t<std::is_signed_v<Lhs> || std::is_signed_v<Rhs>,
556*6777b538SAndroid Build Coastguard Worker intmax_t,
557*6777b538SAndroid Build Coastguard Worker uintmax_t>,
558*6777b538SAndroid Build Coastguard Worker typename MaxExponentPromotion<Lhs, Rhs>::type>::value)
559*6777b538SAndroid Build Coastguard Worker struct FastIntegerArithmeticPromotion<Lhs, Rhs> {
560*6777b538SAndroid Build Coastguard Worker using type =
561*6777b538SAndroid Build Coastguard Worker typename TwiceWiderInteger<typename MaxExponentPromotion<Lhs, Rhs>::type,
562*6777b538SAndroid Build Coastguard Worker std::is_signed_v<Lhs> ||
563*6777b538SAndroid Build Coastguard Worker std::is_signed_v<Rhs>>::type;
564*6777b538SAndroid Build Coastguard Worker static_assert(IsIntegerArithmeticSafe<type, Lhs, Rhs>::value, "");
565*6777b538SAndroid Build Coastguard Worker static const bool is_contained = true;
566*6777b538SAndroid Build Coastguard Worker };
567*6777b538SAndroid Build Coastguard Worker
568*6777b538SAndroid Build Coastguard Worker // Extracts the underlying type from an enum.
569*6777b538SAndroid Build Coastguard Worker template <typename T>
570*6777b538SAndroid Build Coastguard Worker struct ArithmeticOrUnderlyingEnum {
571*6777b538SAndroid Build Coastguard Worker using type = T;
572*6777b538SAndroid Build Coastguard Worker static const bool value = std::is_arithmetic_v<type>;
573*6777b538SAndroid Build Coastguard Worker };
574*6777b538SAndroid Build Coastguard Worker
575*6777b538SAndroid Build Coastguard Worker template <typename T>
576*6777b538SAndroid Build Coastguard Worker requires(std::is_enum_v<T>)
577*6777b538SAndroid Build Coastguard Worker struct ArithmeticOrUnderlyingEnum<T> {
578*6777b538SAndroid Build Coastguard Worker using type = typename std::underlying_type<T>::type;
579*6777b538SAndroid Build Coastguard Worker static const bool value = std::is_arithmetic_v<type>;
580*6777b538SAndroid Build Coastguard Worker };
581*6777b538SAndroid Build Coastguard Worker
582*6777b538SAndroid Build Coastguard Worker // The following are helper templates used in the CheckedNumeric class.
583*6777b538SAndroid Build Coastguard Worker template <typename T>
584*6777b538SAndroid Build Coastguard Worker class CheckedNumeric;
585*6777b538SAndroid Build Coastguard Worker
586*6777b538SAndroid Build Coastguard Worker template <typename T>
587*6777b538SAndroid Build Coastguard Worker class ClampedNumeric;
588*6777b538SAndroid Build Coastguard Worker
589*6777b538SAndroid Build Coastguard Worker template <typename T>
590*6777b538SAndroid Build Coastguard Worker class StrictNumeric;
591*6777b538SAndroid Build Coastguard Worker
592*6777b538SAndroid Build Coastguard Worker // Used to treat CheckedNumeric and arithmetic underlying types the same.
593*6777b538SAndroid Build Coastguard Worker template <typename T>
594*6777b538SAndroid Build Coastguard Worker struct UnderlyingType {
595*6777b538SAndroid Build Coastguard Worker using type = typename ArithmeticOrUnderlyingEnum<T>::type;
596*6777b538SAndroid Build Coastguard Worker static const bool is_numeric = std::is_arithmetic_v<type>;
597*6777b538SAndroid Build Coastguard Worker static const bool is_checked = false;
598*6777b538SAndroid Build Coastguard Worker static const bool is_clamped = false;
599*6777b538SAndroid Build Coastguard Worker static const bool is_strict = false;
600*6777b538SAndroid Build Coastguard Worker };
601*6777b538SAndroid Build Coastguard Worker
602*6777b538SAndroid Build Coastguard Worker template <typename T>
603*6777b538SAndroid Build Coastguard Worker struct UnderlyingType<CheckedNumeric<T>> {
604*6777b538SAndroid Build Coastguard Worker using type = T;
605*6777b538SAndroid Build Coastguard Worker static const bool is_numeric = true;
606*6777b538SAndroid Build Coastguard Worker static const bool is_checked = true;
607*6777b538SAndroid Build Coastguard Worker static const bool is_clamped = false;
608*6777b538SAndroid Build Coastguard Worker static const bool is_strict = false;
609*6777b538SAndroid Build Coastguard Worker };
610*6777b538SAndroid Build Coastguard Worker
611*6777b538SAndroid Build Coastguard Worker template <typename T>
612*6777b538SAndroid Build Coastguard Worker struct UnderlyingType<ClampedNumeric<T>> {
613*6777b538SAndroid Build Coastguard Worker using type = T;
614*6777b538SAndroid Build Coastguard Worker static const bool is_numeric = true;
615*6777b538SAndroid Build Coastguard Worker static const bool is_checked = false;
616*6777b538SAndroid Build Coastguard Worker static const bool is_clamped = true;
617*6777b538SAndroid Build Coastguard Worker static const bool is_strict = false;
618*6777b538SAndroid Build Coastguard Worker };
619*6777b538SAndroid Build Coastguard Worker
620*6777b538SAndroid Build Coastguard Worker template <typename T>
621*6777b538SAndroid Build Coastguard Worker struct UnderlyingType<StrictNumeric<T>> {
622*6777b538SAndroid Build Coastguard Worker using type = T;
623*6777b538SAndroid Build Coastguard Worker static const bool is_numeric = true;
624*6777b538SAndroid Build Coastguard Worker static const bool is_checked = false;
625*6777b538SAndroid Build Coastguard Worker static const bool is_clamped = false;
626*6777b538SAndroid Build Coastguard Worker static const bool is_strict = true;
627*6777b538SAndroid Build Coastguard Worker };
628*6777b538SAndroid Build Coastguard Worker
629*6777b538SAndroid Build Coastguard Worker template <typename L, typename R>
630*6777b538SAndroid Build Coastguard Worker struct IsCheckedOp {
631*6777b538SAndroid Build Coastguard Worker static const bool value =
632*6777b538SAndroid Build Coastguard Worker UnderlyingType<L>::is_numeric && UnderlyingType<R>::is_numeric &&
633*6777b538SAndroid Build Coastguard Worker (UnderlyingType<L>::is_checked || UnderlyingType<R>::is_checked);
634*6777b538SAndroid Build Coastguard Worker };
635*6777b538SAndroid Build Coastguard Worker
636*6777b538SAndroid Build Coastguard Worker template <typename L, typename R>
637*6777b538SAndroid Build Coastguard Worker struct IsClampedOp {
638*6777b538SAndroid Build Coastguard Worker static const bool value =
639*6777b538SAndroid Build Coastguard Worker UnderlyingType<L>::is_numeric && UnderlyingType<R>::is_numeric &&
640*6777b538SAndroid Build Coastguard Worker (UnderlyingType<L>::is_clamped || UnderlyingType<R>::is_clamped) &&
641*6777b538SAndroid Build Coastguard Worker !(UnderlyingType<L>::is_checked || UnderlyingType<R>::is_checked);
642*6777b538SAndroid Build Coastguard Worker };
643*6777b538SAndroid Build Coastguard Worker
644*6777b538SAndroid Build Coastguard Worker template <typename L, typename R>
645*6777b538SAndroid Build Coastguard Worker struct IsStrictOp {
646*6777b538SAndroid Build Coastguard Worker static const bool value =
647*6777b538SAndroid Build Coastguard Worker UnderlyingType<L>::is_numeric && UnderlyingType<R>::is_numeric &&
648*6777b538SAndroid Build Coastguard Worker (UnderlyingType<L>::is_strict || UnderlyingType<R>::is_strict) &&
649*6777b538SAndroid Build Coastguard Worker !(UnderlyingType<L>::is_checked || UnderlyingType<R>::is_checked) &&
650*6777b538SAndroid Build Coastguard Worker !(UnderlyingType<L>::is_clamped || UnderlyingType<R>::is_clamped);
651*6777b538SAndroid Build Coastguard Worker };
652*6777b538SAndroid Build Coastguard Worker
653*6777b538SAndroid Build Coastguard Worker // as_signed<> returns the supplied integral value (or integral castable
654*6777b538SAndroid Build Coastguard Worker // Numeric template) cast as a signed integral of equivalent precision.
655*6777b538SAndroid Build Coastguard Worker // I.e. it's mostly an alias for: static_cast<std::make_signed<T>::type>(t)
656*6777b538SAndroid Build Coastguard Worker template <typename Src>
657*6777b538SAndroid Build Coastguard Worker constexpr typename std::make_signed<
658*6777b538SAndroid Build Coastguard Worker typename base::internal::UnderlyingType<Src>::type>::type
659*6777b538SAndroid Build Coastguard Worker as_signed(const Src value) {
660*6777b538SAndroid Build Coastguard Worker static_assert(std::is_integral_v<decltype(as_signed(value))>,
661*6777b538SAndroid Build Coastguard Worker "Argument must be a signed or unsigned integer type.");
662*6777b538SAndroid Build Coastguard Worker return static_cast<decltype(as_signed(value))>(value);
663*6777b538SAndroid Build Coastguard Worker }
664*6777b538SAndroid Build Coastguard Worker
665*6777b538SAndroid Build Coastguard Worker // as_unsigned<> returns the supplied integral value (or integral castable
666*6777b538SAndroid Build Coastguard Worker // Numeric template) cast as an unsigned integral of equivalent precision.
667*6777b538SAndroid Build Coastguard Worker // I.e. it's mostly an alias for: static_cast<std::make_unsigned<T>::type>(t)
668*6777b538SAndroid Build Coastguard Worker template <typename Src>
669*6777b538SAndroid Build Coastguard Worker constexpr typename std::make_unsigned<
670*6777b538SAndroid Build Coastguard Worker typename base::internal::UnderlyingType<Src>::type>::type
671*6777b538SAndroid Build Coastguard Worker as_unsigned(const Src value) {
672*6777b538SAndroid Build Coastguard Worker static_assert(std::is_integral_v<decltype(as_unsigned(value))>,
673*6777b538SAndroid Build Coastguard Worker "Argument must be a signed or unsigned integer type.");
674*6777b538SAndroid Build Coastguard Worker return static_cast<decltype(as_unsigned(value))>(value);
675*6777b538SAndroid Build Coastguard Worker }
676*6777b538SAndroid Build Coastguard Worker
677*6777b538SAndroid Build Coastguard Worker template <typename L, typename R>
678*6777b538SAndroid Build Coastguard Worker constexpr bool IsLessImpl(const L lhs,
679*6777b538SAndroid Build Coastguard Worker const R rhs,
680*6777b538SAndroid Build Coastguard Worker const RangeCheck l_range,
681*6777b538SAndroid Build Coastguard Worker const RangeCheck r_range) {
682*6777b538SAndroid Build Coastguard Worker return l_range.IsUnderflow() || r_range.IsOverflow() ||
683*6777b538SAndroid Build Coastguard Worker (l_range == r_range && static_cast<decltype(lhs + rhs)>(lhs) <
684*6777b538SAndroid Build Coastguard Worker static_cast<decltype(lhs + rhs)>(rhs));
685*6777b538SAndroid Build Coastguard Worker }
686*6777b538SAndroid Build Coastguard Worker
687*6777b538SAndroid Build Coastguard Worker template <typename L, typename R>
688*6777b538SAndroid Build Coastguard Worker struct IsLess {
689*6777b538SAndroid Build Coastguard Worker static_assert(std::is_arithmetic_v<L> && std::is_arithmetic_v<R>,
690*6777b538SAndroid Build Coastguard Worker "Types must be numeric.");
691*6777b538SAndroid Build Coastguard Worker static constexpr bool Test(const L lhs, const R rhs) {
692*6777b538SAndroid Build Coastguard Worker return IsLessImpl(lhs, rhs, DstRangeRelationToSrcRange<R>(lhs),
693*6777b538SAndroid Build Coastguard Worker DstRangeRelationToSrcRange<L>(rhs));
694*6777b538SAndroid Build Coastguard Worker }
695*6777b538SAndroid Build Coastguard Worker };
696*6777b538SAndroid Build Coastguard Worker
697*6777b538SAndroid Build Coastguard Worker template <typename L, typename R>
698*6777b538SAndroid Build Coastguard Worker constexpr bool IsLessOrEqualImpl(const L lhs,
699*6777b538SAndroid Build Coastguard Worker const R rhs,
700*6777b538SAndroid Build Coastguard Worker const RangeCheck l_range,
701*6777b538SAndroid Build Coastguard Worker const RangeCheck r_range) {
702*6777b538SAndroid Build Coastguard Worker return l_range.IsUnderflow() || r_range.IsOverflow() ||
703*6777b538SAndroid Build Coastguard Worker (l_range == r_range && static_cast<decltype(lhs + rhs)>(lhs) <=
704*6777b538SAndroid Build Coastguard Worker static_cast<decltype(lhs + rhs)>(rhs));
705*6777b538SAndroid Build Coastguard Worker }
706*6777b538SAndroid Build Coastguard Worker
707*6777b538SAndroid Build Coastguard Worker template <typename L, typename R>
708*6777b538SAndroid Build Coastguard Worker struct IsLessOrEqual {
709*6777b538SAndroid Build Coastguard Worker static_assert(std::is_arithmetic_v<L> && std::is_arithmetic_v<R>,
710*6777b538SAndroid Build Coastguard Worker "Types must be numeric.");
711*6777b538SAndroid Build Coastguard Worker static constexpr bool Test(const L lhs, const R rhs) {
712*6777b538SAndroid Build Coastguard Worker return IsLessOrEqualImpl(lhs, rhs, DstRangeRelationToSrcRange<R>(lhs),
713*6777b538SAndroid Build Coastguard Worker DstRangeRelationToSrcRange<L>(rhs));
714*6777b538SAndroid Build Coastguard Worker }
715*6777b538SAndroid Build Coastguard Worker };
716*6777b538SAndroid Build Coastguard Worker
717*6777b538SAndroid Build Coastguard Worker template <typename L, typename R>
718*6777b538SAndroid Build Coastguard Worker constexpr bool IsGreaterImpl(const L lhs,
719*6777b538SAndroid Build Coastguard Worker const R rhs,
720*6777b538SAndroid Build Coastguard Worker const RangeCheck l_range,
721*6777b538SAndroid Build Coastguard Worker const RangeCheck r_range) {
722*6777b538SAndroid Build Coastguard Worker return l_range.IsOverflow() || r_range.IsUnderflow() ||
723*6777b538SAndroid Build Coastguard Worker (l_range == r_range && static_cast<decltype(lhs + rhs)>(lhs) >
724*6777b538SAndroid Build Coastguard Worker static_cast<decltype(lhs + rhs)>(rhs));
725*6777b538SAndroid Build Coastguard Worker }
726*6777b538SAndroid Build Coastguard Worker
727*6777b538SAndroid Build Coastguard Worker template <typename L, typename R>
728*6777b538SAndroid Build Coastguard Worker struct IsGreater {
729*6777b538SAndroid Build Coastguard Worker static_assert(std::is_arithmetic_v<L> && std::is_arithmetic_v<R>,
730*6777b538SAndroid Build Coastguard Worker "Types must be numeric.");
731*6777b538SAndroid Build Coastguard Worker static constexpr bool Test(const L lhs, const R rhs) {
732*6777b538SAndroid Build Coastguard Worker return IsGreaterImpl(lhs, rhs, DstRangeRelationToSrcRange<R>(lhs),
733*6777b538SAndroid Build Coastguard Worker DstRangeRelationToSrcRange<L>(rhs));
734*6777b538SAndroid Build Coastguard Worker }
735*6777b538SAndroid Build Coastguard Worker };
736*6777b538SAndroid Build Coastguard Worker
737*6777b538SAndroid Build Coastguard Worker template <typename L, typename R>
738*6777b538SAndroid Build Coastguard Worker constexpr bool IsGreaterOrEqualImpl(const L lhs,
739*6777b538SAndroid Build Coastguard Worker const R rhs,
740*6777b538SAndroid Build Coastguard Worker const RangeCheck l_range,
741*6777b538SAndroid Build Coastguard Worker const RangeCheck r_range) {
742*6777b538SAndroid Build Coastguard Worker return l_range.IsOverflow() || r_range.IsUnderflow() ||
743*6777b538SAndroid Build Coastguard Worker (l_range == r_range && static_cast<decltype(lhs + rhs)>(lhs) >=
744*6777b538SAndroid Build Coastguard Worker static_cast<decltype(lhs + rhs)>(rhs));
745*6777b538SAndroid Build Coastguard Worker }
746*6777b538SAndroid Build Coastguard Worker
747*6777b538SAndroid Build Coastguard Worker template <typename L, typename R>
748*6777b538SAndroid Build Coastguard Worker struct IsGreaterOrEqual {
749*6777b538SAndroid Build Coastguard Worker static_assert(std::is_arithmetic_v<L> && std::is_arithmetic_v<R>,
750*6777b538SAndroid Build Coastguard Worker "Types must be numeric.");
751*6777b538SAndroid Build Coastguard Worker static constexpr bool Test(const L lhs, const R rhs) {
752*6777b538SAndroid Build Coastguard Worker return IsGreaterOrEqualImpl(lhs, rhs, DstRangeRelationToSrcRange<R>(lhs),
753*6777b538SAndroid Build Coastguard Worker DstRangeRelationToSrcRange<L>(rhs));
754*6777b538SAndroid Build Coastguard Worker }
755*6777b538SAndroid Build Coastguard Worker };
756*6777b538SAndroid Build Coastguard Worker
757*6777b538SAndroid Build Coastguard Worker template <typename L, typename R>
758*6777b538SAndroid Build Coastguard Worker struct IsEqual {
759*6777b538SAndroid Build Coastguard Worker static_assert(std::is_arithmetic_v<L> && std::is_arithmetic_v<R>,
760*6777b538SAndroid Build Coastguard Worker "Types must be numeric.");
761*6777b538SAndroid Build Coastguard Worker static constexpr bool Test(const L lhs, const R rhs) {
762*6777b538SAndroid Build Coastguard Worker return DstRangeRelationToSrcRange<R>(lhs) ==
763*6777b538SAndroid Build Coastguard Worker DstRangeRelationToSrcRange<L>(rhs) &&
764*6777b538SAndroid Build Coastguard Worker static_cast<decltype(lhs + rhs)>(lhs) ==
765*6777b538SAndroid Build Coastguard Worker static_cast<decltype(lhs + rhs)>(rhs);
766*6777b538SAndroid Build Coastguard Worker }
767*6777b538SAndroid Build Coastguard Worker };
768*6777b538SAndroid Build Coastguard Worker
769*6777b538SAndroid Build Coastguard Worker template <typename L, typename R>
770*6777b538SAndroid Build Coastguard Worker struct IsNotEqual {
771*6777b538SAndroid Build Coastguard Worker static_assert(std::is_arithmetic_v<L> && std::is_arithmetic_v<R>,
772*6777b538SAndroid Build Coastguard Worker "Types must be numeric.");
773*6777b538SAndroid Build Coastguard Worker static constexpr bool Test(const L lhs, const R rhs) {
774*6777b538SAndroid Build Coastguard Worker return DstRangeRelationToSrcRange<R>(lhs) !=
775*6777b538SAndroid Build Coastguard Worker DstRangeRelationToSrcRange<L>(rhs) ||
776*6777b538SAndroid Build Coastguard Worker static_cast<decltype(lhs + rhs)>(lhs) !=
777*6777b538SAndroid Build Coastguard Worker static_cast<decltype(lhs + rhs)>(rhs);
778*6777b538SAndroid Build Coastguard Worker }
779*6777b538SAndroid Build Coastguard Worker };
780*6777b538SAndroid Build Coastguard Worker
781*6777b538SAndroid Build Coastguard Worker // These perform the actual math operations on the CheckedNumerics.
782*6777b538SAndroid Build Coastguard Worker // Binary arithmetic operations.
783*6777b538SAndroid Build Coastguard Worker template <template <typename, typename> class C, typename L, typename R>
784*6777b538SAndroid Build Coastguard Worker constexpr bool SafeCompare(const L lhs, const R rhs) {
785*6777b538SAndroid Build Coastguard Worker static_assert(std::is_arithmetic_v<L> && std::is_arithmetic_v<R>,
786*6777b538SAndroid Build Coastguard Worker "Types must be numeric.");
787*6777b538SAndroid Build Coastguard Worker using Promotion = BigEnoughPromotion<L, R>;
788*6777b538SAndroid Build Coastguard Worker using BigType = typename Promotion::type;
789*6777b538SAndroid Build Coastguard Worker return Promotion::is_contained
790*6777b538SAndroid Build Coastguard Worker // Force to a larger type for speed if both are contained.
791*6777b538SAndroid Build Coastguard Worker ? C<BigType, BigType>::Test(
792*6777b538SAndroid Build Coastguard Worker static_cast<BigType>(static_cast<L>(lhs)),
793*6777b538SAndroid Build Coastguard Worker static_cast<BigType>(static_cast<R>(rhs)))
794*6777b538SAndroid Build Coastguard Worker // Let the template functions figure it out for mixed types.
795*6777b538SAndroid Build Coastguard Worker : C<L, R>::Test(lhs, rhs);
796*6777b538SAndroid Build Coastguard Worker }
797*6777b538SAndroid Build Coastguard Worker
798*6777b538SAndroid Build Coastguard Worker template <typename Dst, typename Src>
799*6777b538SAndroid Build Coastguard Worker constexpr bool IsMaxInRangeForNumericType() {
800*6777b538SAndroid Build Coastguard Worker return IsGreaterOrEqual<Dst, Src>::Test(std::numeric_limits<Dst>::max(),
801*6777b538SAndroid Build Coastguard Worker std::numeric_limits<Src>::max());
802*6777b538SAndroid Build Coastguard Worker }
803*6777b538SAndroid Build Coastguard Worker
804*6777b538SAndroid Build Coastguard Worker template <typename Dst, typename Src>
805*6777b538SAndroid Build Coastguard Worker constexpr bool IsMinInRangeForNumericType() {
806*6777b538SAndroid Build Coastguard Worker return IsLessOrEqual<Dst, Src>::Test(std::numeric_limits<Dst>::lowest(),
807*6777b538SAndroid Build Coastguard Worker std::numeric_limits<Src>::lowest());
808*6777b538SAndroid Build Coastguard Worker }
809*6777b538SAndroid Build Coastguard Worker
810*6777b538SAndroid Build Coastguard Worker template <typename Dst, typename Src>
811*6777b538SAndroid Build Coastguard Worker constexpr Dst CommonMax() {
812*6777b538SAndroid Build Coastguard Worker return !IsMaxInRangeForNumericType<Dst, Src>()
813*6777b538SAndroid Build Coastguard Worker ? Dst(std::numeric_limits<Dst>::max())
814*6777b538SAndroid Build Coastguard Worker : Dst(std::numeric_limits<Src>::max());
815*6777b538SAndroid Build Coastguard Worker }
816*6777b538SAndroid Build Coastguard Worker
817*6777b538SAndroid Build Coastguard Worker template <typename Dst, typename Src>
818*6777b538SAndroid Build Coastguard Worker constexpr Dst CommonMin() {
819*6777b538SAndroid Build Coastguard Worker return !IsMinInRangeForNumericType<Dst, Src>()
820*6777b538SAndroid Build Coastguard Worker ? Dst(std::numeric_limits<Dst>::lowest())
821*6777b538SAndroid Build Coastguard Worker : Dst(std::numeric_limits<Src>::lowest());
822*6777b538SAndroid Build Coastguard Worker }
823*6777b538SAndroid Build Coastguard Worker
824*6777b538SAndroid Build Coastguard Worker // This is a wrapper to generate return the max or min for a supplied type.
825*6777b538SAndroid Build Coastguard Worker // If the argument is false, the returned value is the maximum. If true the
826*6777b538SAndroid Build Coastguard Worker // returned value is the minimum.
827*6777b538SAndroid Build Coastguard Worker template <typename Dst, typename Src = Dst>
828*6777b538SAndroid Build Coastguard Worker constexpr Dst CommonMaxOrMin(bool is_min) {
829*6777b538SAndroid Build Coastguard Worker return is_min ? CommonMin<Dst, Src>() : CommonMax<Dst, Src>();
830*6777b538SAndroid Build Coastguard Worker }
831*6777b538SAndroid Build Coastguard Worker
832*6777b538SAndroid Build Coastguard Worker } // namespace internal
833*6777b538SAndroid Build Coastguard Worker } // namespace base
834*6777b538SAndroid Build Coastguard Worker
835*6777b538SAndroid Build Coastguard Worker #endif // BASE_NUMERICS_SAFE_CONVERSIONS_IMPL_H_
836