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