xref: /aosp_15_r20/external/cronet/base/numerics/safe_conversions.h (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
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_H_
6*6777b538SAndroid Build Coastguard Worker #define BASE_NUMERICS_SAFE_CONVERSIONS_H_
7*6777b538SAndroid Build Coastguard Worker 
8*6777b538SAndroid Build Coastguard Worker #include <stddef.h>
9*6777b538SAndroid Build Coastguard Worker 
10*6777b538SAndroid Build Coastguard Worker #include <cmath>
11*6777b538SAndroid Build Coastguard Worker #include <concepts>
12*6777b538SAndroid Build Coastguard Worker #include <limits>
13*6777b538SAndroid Build Coastguard Worker #include <type_traits>
14*6777b538SAndroid Build Coastguard Worker 
15*6777b538SAndroid Build Coastguard Worker #include "base/numerics/safe_conversions_impl.h"
16*6777b538SAndroid Build Coastguard Worker 
17*6777b538SAndroid Build Coastguard Worker #if defined(__ARMEL__) && !defined(__native_client__)
18*6777b538SAndroid Build Coastguard Worker #include "base/numerics/safe_conversions_arm_impl.h"
19*6777b538SAndroid Build Coastguard Worker #define BASE_HAS_OPTIMIZED_SAFE_CONVERSIONS (1)
20*6777b538SAndroid Build Coastguard Worker #else
21*6777b538SAndroid Build Coastguard Worker #define BASE_HAS_OPTIMIZED_SAFE_CONVERSIONS (0)
22*6777b538SAndroid Build Coastguard Worker #endif
23*6777b538SAndroid Build Coastguard Worker 
24*6777b538SAndroid Build Coastguard Worker namespace base {
25*6777b538SAndroid Build Coastguard Worker namespace internal {
26*6777b538SAndroid Build Coastguard Worker 
27*6777b538SAndroid Build Coastguard Worker #if !BASE_HAS_OPTIMIZED_SAFE_CONVERSIONS
28*6777b538SAndroid Build Coastguard Worker template <typename Dst, typename Src>
29*6777b538SAndroid Build Coastguard Worker struct SaturateFastAsmOp {
30*6777b538SAndroid Build Coastguard Worker   static constexpr bool is_supported = false;
DoSaturateFastAsmOp31*6777b538SAndroid Build Coastguard Worker   static constexpr Dst Do(Src) {
32*6777b538SAndroid Build Coastguard Worker     // Force a compile failure if instantiated.
33*6777b538SAndroid Build Coastguard Worker     return CheckOnFailure::template HandleFailure<Dst>();
34*6777b538SAndroid Build Coastguard Worker   }
35*6777b538SAndroid Build Coastguard Worker };
36*6777b538SAndroid Build Coastguard Worker #endif  // BASE_HAS_OPTIMIZED_SAFE_CONVERSIONS
37*6777b538SAndroid Build Coastguard Worker #undef BASE_HAS_OPTIMIZED_SAFE_CONVERSIONS
38*6777b538SAndroid Build Coastguard Worker 
39*6777b538SAndroid Build Coastguard Worker // The following special case a few specific integer conversions where we can
40*6777b538SAndroid Build Coastguard Worker // eke out better performance than range checking.
41*6777b538SAndroid Build Coastguard Worker template <typename Dst, typename Src>
42*6777b538SAndroid Build Coastguard Worker struct IsValueInRangeFastOp {
43*6777b538SAndroid Build Coastguard Worker   static constexpr bool is_supported = false;
DoIsValueInRangeFastOp44*6777b538SAndroid Build Coastguard Worker   static constexpr bool Do(Src value) {
45*6777b538SAndroid Build Coastguard Worker     // Force a compile failure if instantiated.
46*6777b538SAndroid Build Coastguard Worker     return CheckOnFailure::template HandleFailure<bool>();
47*6777b538SAndroid Build Coastguard Worker   }
48*6777b538SAndroid Build Coastguard Worker };
49*6777b538SAndroid Build Coastguard Worker 
50*6777b538SAndroid Build Coastguard Worker // Signed to signed range comparison.
51*6777b538SAndroid Build Coastguard Worker template <typename Dst, typename Src>
52*6777b538SAndroid Build Coastguard Worker   requires(std::signed_integral<Dst> && std::signed_integral<Src> &&
53*6777b538SAndroid Build Coastguard Worker            !IsTypeInRangeForNumericType<Dst, Src>::value)
54*6777b538SAndroid Build Coastguard Worker struct IsValueInRangeFastOp<Dst, Src> {
55*6777b538SAndroid Build Coastguard Worker   static constexpr bool is_supported = true;
56*6777b538SAndroid Build Coastguard Worker 
57*6777b538SAndroid Build Coastguard Worker   static constexpr bool Do(Src value) {
58*6777b538SAndroid Build Coastguard Worker     // Just downcast to the smaller type, sign extend it back to the original
59*6777b538SAndroid Build Coastguard Worker     // type, and then see if it matches the original value.
60*6777b538SAndroid Build Coastguard Worker     return value == static_cast<Dst>(value);
61*6777b538SAndroid Build Coastguard Worker   }
62*6777b538SAndroid Build Coastguard Worker };
63*6777b538SAndroid Build Coastguard Worker 
64*6777b538SAndroid Build Coastguard Worker // Signed to unsigned range comparison.
65*6777b538SAndroid Build Coastguard Worker template <typename Dst, typename Src>
66*6777b538SAndroid Build Coastguard Worker   requires(std::unsigned_integral<Dst> && std::signed_integral<Src> &&
67*6777b538SAndroid Build Coastguard Worker            !IsTypeInRangeForNumericType<Dst, Src>::value)
68*6777b538SAndroid Build Coastguard Worker struct IsValueInRangeFastOp<Dst, Src> {
69*6777b538SAndroid Build Coastguard Worker   static constexpr bool is_supported = true;
70*6777b538SAndroid Build Coastguard Worker 
71*6777b538SAndroid Build Coastguard Worker   static constexpr bool Do(Src value) {
72*6777b538SAndroid Build Coastguard Worker     // We cast a signed as unsigned to overflow negative values to the top,
73*6777b538SAndroid Build Coastguard Worker     // then compare against whichever maximum is smaller, as our upper bound.
74*6777b538SAndroid Build Coastguard Worker     return as_unsigned(value) <= as_unsigned(CommonMax<Src, Dst>());
75*6777b538SAndroid Build Coastguard Worker   }
76*6777b538SAndroid Build Coastguard Worker };
77*6777b538SAndroid Build Coastguard Worker 
78*6777b538SAndroid Build Coastguard Worker // Convenience function that returns true if the supplied value is in range
79*6777b538SAndroid Build Coastguard Worker // for the destination type.
80*6777b538SAndroid Build Coastguard Worker template <typename Dst, typename Src>
81*6777b538SAndroid Build Coastguard Worker constexpr bool IsValueInRangeForNumericType(Src value) {
82*6777b538SAndroid Build Coastguard Worker   using SrcType = typename internal::UnderlyingType<Src>::type;
83*6777b538SAndroid Build Coastguard Worker   return internal::IsValueInRangeFastOp<Dst, SrcType>::is_supported
84*6777b538SAndroid Build Coastguard Worker              ? internal::IsValueInRangeFastOp<Dst, SrcType>::Do(
85*6777b538SAndroid Build Coastguard Worker                    static_cast<SrcType>(value))
86*6777b538SAndroid Build Coastguard Worker              : internal::DstRangeRelationToSrcRange<Dst>(
87*6777b538SAndroid Build Coastguard Worker                    static_cast<SrcType>(value))
88*6777b538SAndroid Build Coastguard Worker                    .IsValid();
89*6777b538SAndroid Build Coastguard Worker }
90*6777b538SAndroid Build Coastguard Worker 
91*6777b538SAndroid Build Coastguard Worker // checked_cast<> is analogous to static_cast<> for numeric types,
92*6777b538SAndroid Build Coastguard Worker // except that it CHECKs that the specified numeric conversion will not
93*6777b538SAndroid Build Coastguard Worker // overflow or underflow. NaN source will always trigger a CHECK.
94*6777b538SAndroid Build Coastguard Worker template <typename Dst,
95*6777b538SAndroid Build Coastguard Worker           class CheckHandler = internal::CheckOnFailure,
96*6777b538SAndroid Build Coastguard Worker           typename Src>
97*6777b538SAndroid Build Coastguard Worker constexpr Dst checked_cast(Src value) {
98*6777b538SAndroid Build Coastguard Worker   // This throws a compile-time error on evaluating the constexpr if it can be
99*6777b538SAndroid Build Coastguard Worker   // determined at compile-time as failing, otherwise it will CHECK at runtime.
100*6777b538SAndroid Build Coastguard Worker   using SrcType = typename internal::UnderlyingType<Src>::type;
101*6777b538SAndroid Build Coastguard Worker   return BASE_NUMERICS_LIKELY((IsValueInRangeForNumericType<Dst>(value)))
102*6777b538SAndroid Build Coastguard Worker              ? static_cast<Dst>(static_cast<SrcType>(value))
103*6777b538SAndroid Build Coastguard Worker              : CheckHandler::template HandleFailure<Dst>();
104*6777b538SAndroid Build Coastguard Worker }
105*6777b538SAndroid Build Coastguard Worker 
106*6777b538SAndroid Build Coastguard Worker // Default boundaries for integral/float: max/infinity, lowest/-infinity, 0/NaN.
107*6777b538SAndroid Build Coastguard Worker // You may provide your own limits (e.g. to saturated_cast) so long as you
108*6777b538SAndroid Build Coastguard Worker // implement all of the static constexpr member functions in the class below.
109*6777b538SAndroid Build Coastguard Worker template <typename T>
110*6777b538SAndroid Build Coastguard Worker struct SaturationDefaultLimits : public std::numeric_limits<T> {
111*6777b538SAndroid Build Coastguard Worker   static constexpr T NaN() {
112*6777b538SAndroid Build Coastguard Worker     if constexpr (std::numeric_limits<T>::has_quiet_NaN) {
113*6777b538SAndroid Build Coastguard Worker       return std::numeric_limits<T>::quiet_NaN();
114*6777b538SAndroid Build Coastguard Worker     } else {
115*6777b538SAndroid Build Coastguard Worker       return T();
116*6777b538SAndroid Build Coastguard Worker     }
117*6777b538SAndroid Build Coastguard Worker   }
118*6777b538SAndroid Build Coastguard Worker   using std::numeric_limits<T>::max;
119*6777b538SAndroid Build Coastguard Worker   static constexpr T Overflow() {
120*6777b538SAndroid Build Coastguard Worker     if constexpr (std::numeric_limits<T>::has_infinity) {
121*6777b538SAndroid Build Coastguard Worker       return std::numeric_limits<T>::infinity();
122*6777b538SAndroid Build Coastguard Worker     } else {
123*6777b538SAndroid Build Coastguard Worker       return std::numeric_limits<T>::max();
124*6777b538SAndroid Build Coastguard Worker     }
125*6777b538SAndroid Build Coastguard Worker   }
126*6777b538SAndroid Build Coastguard Worker   using std::numeric_limits<T>::lowest;
127*6777b538SAndroid Build Coastguard Worker   static constexpr T Underflow() {
128*6777b538SAndroid Build Coastguard Worker     if constexpr (std::numeric_limits<T>::has_infinity) {
129*6777b538SAndroid Build Coastguard Worker       return std::numeric_limits<T>::infinity() * -1;
130*6777b538SAndroid Build Coastguard Worker     } else {
131*6777b538SAndroid Build Coastguard Worker       return std::numeric_limits<T>::lowest();
132*6777b538SAndroid Build Coastguard Worker     }
133*6777b538SAndroid Build Coastguard Worker   }
134*6777b538SAndroid Build Coastguard Worker };
135*6777b538SAndroid Build Coastguard Worker 
136*6777b538SAndroid Build Coastguard Worker template <typename Dst, template <typename> class S, typename Src>
137*6777b538SAndroid Build Coastguard Worker constexpr Dst saturated_cast_impl(Src value, RangeCheck constraint) {
138*6777b538SAndroid Build Coastguard Worker   // For some reason clang generates much better code when the branch is
139*6777b538SAndroid Build Coastguard Worker   // structured exactly this way, rather than a sequence of checks.
140*6777b538SAndroid Build Coastguard Worker   return !constraint.IsOverflowFlagSet()
141*6777b538SAndroid Build Coastguard Worker              ? (!constraint.IsUnderflowFlagSet() ? static_cast<Dst>(value)
142*6777b538SAndroid Build Coastguard Worker                                                  : S<Dst>::Underflow())
143*6777b538SAndroid Build Coastguard Worker              // Skip this check for integral Src, which cannot be NaN.
144*6777b538SAndroid Build Coastguard Worker              : (std::is_integral_v<Src> || !constraint.IsUnderflowFlagSet()
145*6777b538SAndroid Build Coastguard Worker                     ? S<Dst>::Overflow()
146*6777b538SAndroid Build Coastguard Worker                     : S<Dst>::NaN());
147*6777b538SAndroid Build Coastguard Worker }
148*6777b538SAndroid Build Coastguard Worker 
149*6777b538SAndroid Build Coastguard Worker // We can reduce the number of conditions and get slightly better performance
150*6777b538SAndroid Build Coastguard Worker // for normal signed and unsigned integer ranges. And in the specific case of
151*6777b538SAndroid Build Coastguard Worker // Arm, we can use the optimized saturation instructions.
152*6777b538SAndroid Build Coastguard Worker template <typename Dst, typename Src>
153*6777b538SAndroid Build Coastguard Worker struct SaturateFastOp {
154*6777b538SAndroid Build Coastguard Worker   static constexpr bool is_supported = false;
155*6777b538SAndroid Build Coastguard Worker   static constexpr Dst Do(Src value) {
156*6777b538SAndroid Build Coastguard Worker     // Force a compile failure if instantiated.
157*6777b538SAndroid Build Coastguard Worker     return CheckOnFailure::template HandleFailure<Dst>();
158*6777b538SAndroid Build Coastguard Worker   }
159*6777b538SAndroid Build Coastguard Worker };
160*6777b538SAndroid Build Coastguard Worker 
161*6777b538SAndroid Build Coastguard Worker template <typename Dst, typename Src>
162*6777b538SAndroid Build Coastguard Worker   requires(std::integral<Src> && std::integral<Dst> &&
163*6777b538SAndroid Build Coastguard Worker            SaturateFastAsmOp<Dst, Src>::is_supported)
164*6777b538SAndroid Build Coastguard Worker struct SaturateFastOp<Dst, Src> {
165*6777b538SAndroid Build Coastguard Worker   static constexpr bool is_supported = true;
166*6777b538SAndroid Build Coastguard Worker   static constexpr Dst Do(Src value) {
167*6777b538SAndroid Build Coastguard Worker     return SaturateFastAsmOp<Dst, Src>::Do(value);
168*6777b538SAndroid Build Coastguard Worker   }
169*6777b538SAndroid Build Coastguard Worker };
170*6777b538SAndroid Build Coastguard Worker 
171*6777b538SAndroid Build Coastguard Worker template <typename Dst, typename Src>
172*6777b538SAndroid Build Coastguard Worker   requires(std::integral<Src> && std::integral<Dst> &&
173*6777b538SAndroid Build Coastguard Worker            !SaturateFastAsmOp<Dst, Src>::is_supported)
174*6777b538SAndroid Build Coastguard Worker struct SaturateFastOp<Dst, Src> {
175*6777b538SAndroid Build Coastguard Worker   static constexpr bool is_supported = true;
176*6777b538SAndroid Build Coastguard Worker   static constexpr Dst Do(Src value) {
177*6777b538SAndroid Build Coastguard Worker     // The exact order of the following is structured to hit the correct
178*6777b538SAndroid Build Coastguard Worker     // optimization heuristics across compilers. Do not change without
179*6777b538SAndroid Build Coastguard Worker     // checking the emitted code.
180*6777b538SAndroid Build Coastguard Worker     const Dst saturated = CommonMaxOrMin<Dst, Src>(
181*6777b538SAndroid Build Coastguard Worker         IsMaxInRangeForNumericType<Dst, Src>() ||
182*6777b538SAndroid Build Coastguard Worker         (!IsMinInRangeForNumericType<Dst, Src>() && IsValueNegative(value)));
183*6777b538SAndroid Build Coastguard Worker     return BASE_NUMERICS_LIKELY(IsValueInRangeForNumericType<Dst>(value))
184*6777b538SAndroid Build Coastguard Worker                ? static_cast<Dst>(value)
185*6777b538SAndroid Build Coastguard Worker                : saturated;
186*6777b538SAndroid Build Coastguard Worker   }
187*6777b538SAndroid Build Coastguard Worker };
188*6777b538SAndroid Build Coastguard Worker 
189*6777b538SAndroid Build Coastguard Worker // saturated_cast<> is analogous to static_cast<> for numeric types, except
190*6777b538SAndroid Build Coastguard Worker // that the specified numeric conversion will saturate by default rather than
191*6777b538SAndroid Build Coastguard Worker // overflow or underflow, and NaN assignment to an integral will return 0.
192*6777b538SAndroid Build Coastguard Worker // All boundary condition behaviors can be overridden with a custom handler.
193*6777b538SAndroid Build Coastguard Worker template <typename Dst,
194*6777b538SAndroid Build Coastguard Worker           template <typename> class SaturationHandler = SaturationDefaultLimits,
195*6777b538SAndroid Build Coastguard Worker           typename Src>
196*6777b538SAndroid Build Coastguard Worker constexpr Dst saturated_cast(Src value) {
197*6777b538SAndroid Build Coastguard Worker   using SrcType = typename UnderlyingType<Src>::type;
198*6777b538SAndroid Build Coastguard Worker   return !IsConstantEvaluated() && SaturateFastOp<Dst, SrcType>::is_supported &&
199*6777b538SAndroid Build Coastguard Worker                  std::is_same_v<SaturationHandler<Dst>,
200*6777b538SAndroid Build Coastguard Worker                                 SaturationDefaultLimits<Dst>>
201*6777b538SAndroid Build Coastguard Worker              ? SaturateFastOp<Dst, SrcType>::Do(static_cast<SrcType>(value))
202*6777b538SAndroid Build Coastguard Worker              : saturated_cast_impl<Dst, SaturationHandler, SrcType>(
203*6777b538SAndroid Build Coastguard Worker                    static_cast<SrcType>(value),
204*6777b538SAndroid Build Coastguard Worker                    DstRangeRelationToSrcRange<Dst, SaturationHandler, SrcType>(
205*6777b538SAndroid Build Coastguard Worker                        static_cast<SrcType>(value)));
206*6777b538SAndroid Build Coastguard Worker }
207*6777b538SAndroid Build Coastguard Worker 
208*6777b538SAndroid Build Coastguard Worker // strict_cast<> is analogous to static_cast<> for numeric types, except that
209*6777b538SAndroid Build Coastguard Worker // it will cause a compile failure if the destination type is not large enough
210*6777b538SAndroid Build Coastguard Worker // to contain any value in the source type. It performs no runtime checking.
211*6777b538SAndroid Build Coastguard Worker template <typename Dst, typename Src>
212*6777b538SAndroid Build Coastguard Worker constexpr Dst strict_cast(Src value) {
213*6777b538SAndroid Build Coastguard Worker   using SrcType = typename UnderlyingType<Src>::type;
214*6777b538SAndroid Build Coastguard Worker   static_assert(UnderlyingType<Src>::is_numeric, "Argument must be numeric.");
215*6777b538SAndroid Build Coastguard Worker   static_assert(std::is_arithmetic_v<Dst>, "Result must be numeric.");
216*6777b538SAndroid Build Coastguard Worker 
217*6777b538SAndroid Build Coastguard Worker   // If you got here from a compiler error, it's because you tried to assign
218*6777b538SAndroid Build Coastguard Worker   // from a source type to a destination type that has insufficient range.
219*6777b538SAndroid Build Coastguard Worker   // The solution may be to change the destination type you're assigning to,
220*6777b538SAndroid Build Coastguard Worker   // and use one large enough to represent the source.
221*6777b538SAndroid Build Coastguard Worker   // Alternatively, you may be better served with the checked_cast<> or
222*6777b538SAndroid Build Coastguard Worker   // saturated_cast<> template functions for your particular use case.
223*6777b538SAndroid Build Coastguard Worker   static_assert(StaticDstRangeRelationToSrcRange<Dst, SrcType>::value ==
224*6777b538SAndroid Build Coastguard Worker                     NUMERIC_RANGE_CONTAINED,
225*6777b538SAndroid Build Coastguard Worker                 "The source type is out of range for the destination type. "
226*6777b538SAndroid Build Coastguard Worker                 "Please see strict_cast<> comments for more information.");
227*6777b538SAndroid Build Coastguard Worker 
228*6777b538SAndroid Build Coastguard Worker   return static_cast<Dst>(static_cast<SrcType>(value));
229*6777b538SAndroid Build Coastguard Worker }
230*6777b538SAndroid Build Coastguard Worker 
231*6777b538SAndroid Build Coastguard Worker // Some wrappers to statically check that a type is in range.
232*6777b538SAndroid Build Coastguard Worker template <typename Dst, typename Src>
233*6777b538SAndroid Build Coastguard Worker struct IsNumericRangeContained {
234*6777b538SAndroid Build Coastguard Worker   static constexpr bool value = false;
235*6777b538SAndroid Build Coastguard Worker };
236*6777b538SAndroid Build Coastguard Worker 
237*6777b538SAndroid Build Coastguard Worker template <typename Dst, typename Src>
238*6777b538SAndroid Build Coastguard Worker   requires(ArithmeticOrUnderlyingEnum<Dst>::value &&
239*6777b538SAndroid Build Coastguard Worker            ArithmeticOrUnderlyingEnum<Src>::value)
240*6777b538SAndroid Build Coastguard Worker struct IsNumericRangeContained<Dst, Src> {
241*6777b538SAndroid Build Coastguard Worker   static constexpr bool value =
242*6777b538SAndroid Build Coastguard Worker       StaticDstRangeRelationToSrcRange<Dst, Src>::value ==
243*6777b538SAndroid Build Coastguard Worker       NUMERIC_RANGE_CONTAINED;
244*6777b538SAndroid Build Coastguard Worker };
245*6777b538SAndroid Build Coastguard Worker 
246*6777b538SAndroid Build Coastguard Worker // StrictNumeric implements compile time range checking between numeric types by
247*6777b538SAndroid Build Coastguard Worker // wrapping assignment operations in a strict_cast. This class is intended to be
248*6777b538SAndroid Build Coastguard Worker // used for function arguments and return types, to ensure the destination type
249*6777b538SAndroid Build Coastguard Worker // can always contain the source type. This is essentially the same as enforcing
250*6777b538SAndroid Build Coastguard Worker // -Wconversion in gcc and C4302 warnings on MSVC, but it can be applied
251*6777b538SAndroid Build Coastguard Worker // incrementally at API boundaries, making it easier to convert code so that it
252*6777b538SAndroid Build Coastguard Worker // compiles cleanly with truncation warnings enabled.
253*6777b538SAndroid Build Coastguard Worker // This template should introduce no runtime overhead, but it also provides no
254*6777b538SAndroid Build Coastguard Worker // runtime checking of any of the associated mathematical operations. Use
255*6777b538SAndroid Build Coastguard Worker // CheckedNumeric for runtime range checks of the actual value being assigned.
256*6777b538SAndroid Build Coastguard Worker template <typename T>
257*6777b538SAndroid Build Coastguard Worker class StrictNumeric {
258*6777b538SAndroid Build Coastguard Worker  public:
259*6777b538SAndroid Build Coastguard Worker   using type = T;
260*6777b538SAndroid Build Coastguard Worker 
261*6777b538SAndroid Build Coastguard Worker   constexpr StrictNumeric() : value_(0) {}
262*6777b538SAndroid Build Coastguard Worker 
263*6777b538SAndroid Build Coastguard Worker   // Copy constructor.
264*6777b538SAndroid Build Coastguard Worker   template <typename Src>
265*6777b538SAndroid Build Coastguard Worker   constexpr StrictNumeric(const StrictNumeric<Src>& rhs)
266*6777b538SAndroid Build Coastguard Worker       : value_(strict_cast<T>(rhs.value_)) {}
267*6777b538SAndroid Build Coastguard Worker 
268*6777b538SAndroid Build Coastguard Worker   // Strictly speaking, this is not necessary, but declaring this allows class
269*6777b538SAndroid Build Coastguard Worker   // template argument deduction to be used so that it is possible to simply
270*6777b538SAndroid Build Coastguard Worker   // write `StrictNumeric(777)` instead of `StrictNumeric<int>(777)`.
271*6777b538SAndroid Build Coastguard Worker   // NOLINTNEXTLINE(google-explicit-constructor)
272*6777b538SAndroid Build Coastguard Worker   constexpr StrictNumeric(T value) : value_(value) {}
273*6777b538SAndroid Build Coastguard Worker 
274*6777b538SAndroid Build Coastguard Worker   // This is not an explicit constructor because we implicitly upgrade regular
275*6777b538SAndroid Build Coastguard Worker   // numerics to StrictNumerics to make them easier to use.
276*6777b538SAndroid Build Coastguard Worker   template <typename Src>
277*6777b538SAndroid Build Coastguard Worker   // NOLINTNEXTLINE(google-explicit-constructor)
278*6777b538SAndroid Build Coastguard Worker   constexpr StrictNumeric(Src value) : value_(strict_cast<T>(value)) {}
279*6777b538SAndroid Build Coastguard Worker 
280*6777b538SAndroid Build Coastguard Worker   // If you got here from a compiler error, it's because you tried to assign
281*6777b538SAndroid Build Coastguard Worker   // from a source type to a destination type that has insufficient range.
282*6777b538SAndroid Build Coastguard Worker   // The solution may be to change the destination type you're assigning to,
283*6777b538SAndroid Build Coastguard Worker   // and use one large enough to represent the source.
284*6777b538SAndroid Build Coastguard Worker   // If you're assigning from a CheckedNumeric<> class, you may be able to use
285*6777b538SAndroid Build Coastguard Worker   // the AssignIfValid() member function, specify a narrower destination type to
286*6777b538SAndroid Build Coastguard Worker   // the member value functions (e.g. val.template ValueOrDie<Dst>()), use one
287*6777b538SAndroid Build Coastguard Worker   // of the value helper functions (e.g. ValueOrDieForType<Dst>(val)).
288*6777b538SAndroid Build Coastguard Worker   // If you've encountered an _ambiguous overload_ you can use a static_cast<>
289*6777b538SAndroid Build Coastguard Worker   // to explicitly cast the result to the destination type.
290*6777b538SAndroid Build Coastguard Worker   // If none of that works, you may be better served with the checked_cast<> or
291*6777b538SAndroid Build Coastguard Worker   // saturated_cast<> template functions for your particular use case.
292*6777b538SAndroid Build Coastguard Worker   template <typename Dst>
293*6777b538SAndroid Build Coastguard Worker     requires(IsNumericRangeContained<Dst, T>::value)
294*6777b538SAndroid Build Coastguard Worker   constexpr operator Dst() const {
295*6777b538SAndroid Build Coastguard Worker     return static_cast<typename ArithmeticOrUnderlyingEnum<Dst>::type>(value_);
296*6777b538SAndroid Build Coastguard Worker   }
297*6777b538SAndroid Build Coastguard Worker 
298*6777b538SAndroid Build Coastguard Worker  private:
299*6777b538SAndroid Build Coastguard Worker   const T value_;
300*6777b538SAndroid Build Coastguard Worker };
301*6777b538SAndroid Build Coastguard Worker 
302*6777b538SAndroid Build Coastguard Worker // Convenience wrapper returns a StrictNumeric from the provided arithmetic
303*6777b538SAndroid Build Coastguard Worker // type.
304*6777b538SAndroid Build Coastguard Worker template <typename T>
305*6777b538SAndroid Build Coastguard Worker constexpr StrictNumeric<typename UnderlyingType<T>::type> MakeStrictNum(
306*6777b538SAndroid Build Coastguard Worker     const T value) {
307*6777b538SAndroid Build Coastguard Worker   return value;
308*6777b538SAndroid Build Coastguard Worker }
309*6777b538SAndroid Build Coastguard Worker 
310*6777b538SAndroid Build Coastguard Worker #define BASE_NUMERIC_COMPARISON_OPERATORS(CLASS, NAME, OP)          \
311*6777b538SAndroid Build Coastguard Worker   template <typename L, typename R>                                 \
312*6777b538SAndroid Build Coastguard Worker     requires(internal::Is##CLASS##Op<L, R>::value)                  \
313*6777b538SAndroid Build Coastguard Worker   constexpr bool operator OP(const L lhs, const R rhs) {            \
314*6777b538SAndroid Build Coastguard Worker     return SafeCompare<NAME, typename UnderlyingType<L>::type,      \
315*6777b538SAndroid Build Coastguard Worker                        typename UnderlyingType<R>::type>(lhs, rhs); \
316*6777b538SAndroid Build Coastguard Worker   }
317*6777b538SAndroid Build Coastguard Worker 
318*6777b538SAndroid Build Coastguard Worker BASE_NUMERIC_COMPARISON_OPERATORS(Strict, IsLess, <)
319*6777b538SAndroid Build Coastguard Worker BASE_NUMERIC_COMPARISON_OPERATORS(Strict, IsLessOrEqual, <=)
320*6777b538SAndroid Build Coastguard Worker BASE_NUMERIC_COMPARISON_OPERATORS(Strict, IsGreater, >)
321*6777b538SAndroid Build Coastguard Worker BASE_NUMERIC_COMPARISON_OPERATORS(Strict, IsGreaterOrEqual, >=)
322*6777b538SAndroid Build Coastguard Worker BASE_NUMERIC_COMPARISON_OPERATORS(Strict, IsEqual, ==)
323*6777b538SAndroid Build Coastguard Worker BASE_NUMERIC_COMPARISON_OPERATORS(Strict, IsNotEqual, !=)
324*6777b538SAndroid Build Coastguard Worker 
325*6777b538SAndroid Build Coastguard Worker }  // namespace internal
326*6777b538SAndroid Build Coastguard Worker 
327*6777b538SAndroid Build Coastguard Worker using internal::as_signed;
328*6777b538SAndroid Build Coastguard Worker using internal::as_unsigned;
329*6777b538SAndroid Build Coastguard Worker using internal::checked_cast;
330*6777b538SAndroid Build Coastguard Worker using internal::IsTypeInRangeForNumericType;
331*6777b538SAndroid Build Coastguard Worker using internal::IsValueInRangeForNumericType;
332*6777b538SAndroid Build Coastguard Worker using internal::IsValueNegative;
333*6777b538SAndroid Build Coastguard Worker using internal::MakeStrictNum;
334*6777b538SAndroid Build Coastguard Worker using internal::SafeUnsignedAbs;
335*6777b538SAndroid Build Coastguard Worker using internal::saturated_cast;
336*6777b538SAndroid Build Coastguard Worker using internal::strict_cast;
337*6777b538SAndroid Build Coastguard Worker using internal::StrictNumeric;
338*6777b538SAndroid Build Coastguard Worker 
339*6777b538SAndroid Build Coastguard Worker // Explicitly make a shorter size_t alias for convenience.
340*6777b538SAndroid Build Coastguard Worker using SizeT = StrictNumeric<size_t>;
341*6777b538SAndroid Build Coastguard Worker 
342*6777b538SAndroid Build Coastguard Worker // floating -> integral conversions that saturate and thus can actually return
343*6777b538SAndroid Build Coastguard Worker // an integral type.
344*6777b538SAndroid Build Coastguard Worker //
345*6777b538SAndroid Build Coastguard Worker // Generally, what you want is saturated_cast<Dst>(std::nearbyint(x)), which
346*6777b538SAndroid Build Coastguard Worker // rounds correctly according to IEEE-754 (round to nearest, ties go to nearest
347*6777b538SAndroid Build Coastguard Worker // even number; this avoids bias). If your code is performance-critical
348*6777b538SAndroid Build Coastguard Worker // and you are sure that you will never overflow, you can use std::lrint()
349*6777b538SAndroid Build Coastguard Worker // or std::llrint(), which return a long or long long directly.
350*6777b538SAndroid Build Coastguard Worker //
351*6777b538SAndroid Build Coastguard Worker // Below are convenience functions around similar patterns, except that
352*6777b538SAndroid Build Coastguard Worker // they round in nonstandard directions and will generally be slower.
353*6777b538SAndroid Build Coastguard Worker 
354*6777b538SAndroid Build Coastguard Worker // Rounds towards negative infinity (i.e., down).
355*6777b538SAndroid Build Coastguard Worker template <typename Dst = int, typename Src>
356*6777b538SAndroid Build Coastguard Worker   requires(std::integral<Dst> && std::floating_point<Src>)
357*6777b538SAndroid Build Coastguard Worker Dst ClampFloor(Src value) {
358*6777b538SAndroid Build Coastguard Worker   return saturated_cast<Dst>(std::floor(value));
359*6777b538SAndroid Build Coastguard Worker }
360*6777b538SAndroid Build Coastguard Worker 
361*6777b538SAndroid Build Coastguard Worker // Rounds towards positive infinity (i.e., up).
362*6777b538SAndroid Build Coastguard Worker template <typename Dst = int, typename Src>
363*6777b538SAndroid Build Coastguard Worker   requires(std::integral<Dst> && std::floating_point<Src>)
364*6777b538SAndroid Build Coastguard Worker Dst ClampCeil(Src value) {
365*6777b538SAndroid Build Coastguard Worker   return saturated_cast<Dst>(std::ceil(value));
366*6777b538SAndroid Build Coastguard Worker }
367*6777b538SAndroid Build Coastguard Worker 
368*6777b538SAndroid Build Coastguard Worker // Rounds towards nearest integer, with ties away from zero.
369*6777b538SAndroid Build Coastguard Worker // This means that 0.5 will be rounded to 1 and 1.5 will be rounded to 2.
370*6777b538SAndroid Build Coastguard Worker // Similarly, -0.5 will be rounded to -1 and -1.5 will be rounded to -2.
371*6777b538SAndroid Build Coastguard Worker //
372*6777b538SAndroid Build Coastguard Worker // This is normally not what you want accuracy-wise (it introduces a small bias
373*6777b538SAndroid Build Coastguard Worker // away from zero), and it is not the fastest option, but it is frequently what
374*6777b538SAndroid Build Coastguard Worker // existing code expects. Compare with saturated_cast<Dst>(std::nearbyint(x))
375*6777b538SAndroid Build Coastguard Worker // or std::lrint(x), which would round 0.5 and -0.5 to 0 but 1.5 to 2 and
376*6777b538SAndroid Build Coastguard Worker // -1.5 to -2.
377*6777b538SAndroid Build Coastguard Worker template <typename Dst = int, typename Src>
378*6777b538SAndroid Build Coastguard Worker   requires(std::integral<Dst> && std::floating_point<Src>)
379*6777b538SAndroid Build Coastguard Worker Dst ClampRound(Src value) {
380*6777b538SAndroid Build Coastguard Worker   const Src rounded = std::round(value);
381*6777b538SAndroid Build Coastguard Worker   return saturated_cast<Dst>(rounded);
382*6777b538SAndroid Build Coastguard Worker }
383*6777b538SAndroid Build Coastguard Worker 
384*6777b538SAndroid Build Coastguard Worker }  // namespace base
385*6777b538SAndroid Build Coastguard Worker 
386*6777b538SAndroid Build Coastguard Worker #endif  // BASE_NUMERICS_SAFE_CONVERSIONS_H_
387