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