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