1/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 2/* This Source Code Form is subject to the terms of the Mozilla Public 3 * License, v. 2.0. If a copy of the MPL was not distributed with this file, 4 * You can obtain one at http://mozilla.org/MPL/2.0/. */ 5 6/* Provides checked integers, detecting integer overflow and divide-by-0. */ 7 8// Necessary modifications are made to the original CheckedInt.h file when 9// incorporating it into WebKit: 10// 1) Comment out #define MOZ_CHECKEDINT_ENABLE_MOZ_ASSERTS 11// 2) Comment out #include "mozilla/StandardInteger.h" 12// 3) Define MOZ_DELETE 13// 4) Change namespace mozilla to namespace blink 14 15#ifndef mozilla_CheckedInt_h_ 16#define mozilla_CheckedInt_h_ 17 18/* 19 * Build options. Comment out these #defines to disable the corresponding 20 * optional feature. Disabling features may be useful for code using 21 * CheckedInt outside of Mozilla (e.g. WebKit) 22 */ 23 24// Enable usage of MOZ_STATIC_ASSERT to check for unsupported types. 25// If disabled, static asserts are replaced by regular assert(). 26// #define MOZ_CHECKEDINT_ENABLE_MOZ_ASSERTS 27 28/* 29 * End of build options 30 */ 31 32#ifdef MOZ_CHECKEDINT_ENABLE_MOZ_ASSERTS 33# include "mozilla/Assertions.h" 34#else 35# ifndef MOZ_STATIC_ASSERT 36# include <cassert> 37# define MOZ_STATIC_ASSERT(cond, reason) assert((cond) && reason) 38# define MOZ_ASSERT(cond, reason) assert((cond) && reason) 39# endif 40#endif 41 42// #include "mozilla/StandardInteger.h" 43 44#ifndef MOZ_DELETE 45#define MOZ_DELETE 46#endif 47 48#include <climits> 49 50namespace blink { 51 52namespace detail { 53 54/* 55 * Step 1: manually record supported types 56 * 57 * What's nontrivial here is that there are different families of integer 58 * types: basic integer types and stdint types. It is merrily undefined which 59 * types from one family may be just typedefs for a type from another family. 60 * 61 * For example, on GCC 4.6, aside from the basic integer types, the only other 62 * type that isn't just a typedef for some of them, is int8_t. 63 */ 64 65struct UnsupportedType {}; 66 67template<typename IntegerType> 68struct IsSupportedPass2 69{ 70 static const bool value = false; 71}; 72 73template<typename IntegerType> 74struct IsSupported 75{ 76 static const bool value = IsSupportedPass2<IntegerType>::value; 77}; 78 79template<> 80struct IsSupported<int8_t> 81{ static const bool value = true; }; 82 83template<> 84struct IsSupported<uint8_t> 85{ static const bool value = true; }; 86 87template<> 88struct IsSupported<int16_t> 89{ static const bool value = true; }; 90 91template<> 92struct IsSupported<uint16_t> 93{ static const bool value = true; }; 94 95template<> 96struct IsSupported<int32_t> 97{ static const bool value = true; }; 98 99template<> 100struct IsSupported<uint32_t> 101{ static const bool value = true; }; 102 103template<> 104struct IsSupported<int64_t> 105{ static const bool value = true; }; 106 107template<> 108struct IsSupported<uint64_t> 109{ static const bool value = true; }; 110 111 112template<> 113struct IsSupportedPass2<char> 114{ static const bool value = true; }; 115 116template<> 117struct IsSupportedPass2<unsigned char> 118{ static const bool value = true; }; 119 120template<> 121struct IsSupportedPass2<short> 122{ static const bool value = true; }; 123 124template<> 125struct IsSupportedPass2<unsigned short> 126{ static const bool value = true; }; 127 128template<> 129struct IsSupportedPass2<int> 130{ static const bool value = true; }; 131 132template<> 133struct IsSupportedPass2<unsigned> 134{ static const bool value = true; }; 135 136template<> 137struct IsSupportedPass2<long> 138{ static const bool value = true; }; 139 140template<> 141struct IsSupportedPass2<unsigned long> 142{ static const bool value = true; }; 143 144 145/* 146 * Step 2: some integer-traits kind of stuff. 147 */ 148 149template<size_t Size, bool Signedness> 150struct StdintTypeForSizeAndSignedness 151{}; 152 153template<> 154struct StdintTypeForSizeAndSignedness<1, true> 155{ typedef int8_t Type; }; 156 157template<> 158struct StdintTypeForSizeAndSignedness<1, false> 159{ typedef uint8_t Type; }; 160 161template<> 162struct StdintTypeForSizeAndSignedness<2, true> 163{ typedef int16_t Type; }; 164 165template<> 166struct StdintTypeForSizeAndSignedness<2, false> 167{ typedef uint16_t Type; }; 168 169template<> 170struct StdintTypeForSizeAndSignedness<4, true> 171{ typedef int32_t Type; }; 172 173template<> 174struct StdintTypeForSizeAndSignedness<4, false> 175{ typedef uint32_t Type; }; 176 177template<> 178struct StdintTypeForSizeAndSignedness<8, true> 179{ typedef int64_t Type; }; 180 181template<> 182struct StdintTypeForSizeAndSignedness<8, false> 183{ typedef uint64_t Type; }; 184 185template<typename IntegerType> 186struct UnsignedType 187{ 188 typedef typename StdintTypeForSizeAndSignedness<sizeof(IntegerType), 189 false>::Type Type; 190}; 191 192template<typename IntegerType> 193struct IsSigned 194{ 195 static const bool value = IntegerType(-1) <= IntegerType(0); 196}; 197 198template<typename IntegerType, size_t Size = sizeof(IntegerType)> 199struct TwiceBiggerType 200{ 201 typedef typename StdintTypeForSizeAndSignedness< 202 sizeof(IntegerType) * 2, 203 IsSigned<IntegerType>::value 204 >::Type Type; 205}; 206 207template<typename IntegerType> 208struct TwiceBiggerType<IntegerType, 8> 209{ 210 typedef UnsupportedType Type; 211}; 212 213template<typename IntegerType> 214struct PositionOfSignBit 215{ 216 static const size_t value = CHAR_BIT * sizeof(IntegerType) - 1; 217}; 218 219template<typename IntegerType> 220struct MinValue 221{ 222 private: 223 typedef typename UnsignedType<IntegerType>::Type UnsignedIntegerType; 224 static const size_t PosOfSignBit = PositionOfSignBit<IntegerType>::value; 225 226 public: 227 // Bitwise ops may return a larger type, that's why we cast explicitly. 228 // In C++, left bit shifts on signed values is undefined by the standard 229 // unless the shifted value is representable. 230 // Notice that signed-to-unsigned conversions are always well-defined in 231 // the standard as the value congruent to 2**n, as expected. By contrast, 232 // unsigned-to-signed is only well-defined if the value is representable. 233 static const IntegerType value = 234 IsSigned<IntegerType>::value 235 ? IntegerType(UnsignedIntegerType(1) << PosOfSignBit) 236 : IntegerType(0); 237}; 238 239template<typename IntegerType> 240struct MaxValue 241{ 242 // Tricksy, but covered by the unit test. 243 // Relies heavily on the type of MinValue<IntegerType>::value 244 // being IntegerType. 245 static const IntegerType value = ~MinValue<IntegerType>::value; 246}; 247 248/* 249 * Step 3: Implement the actual validity checks. 250 * 251 * Ideas taken from IntegerLib, code different. 252 */ 253 254template<typename T> 255inline bool 256HasSignBit(T x) 257{ 258 // In C++, right bit shifts on negative values is undefined by the standard. 259 // Notice that signed-to-unsigned conversions are always well-defined in the 260 // standard, as the value congruent modulo 2**n as expected. By contrast, 261 // unsigned-to-signed is only well-defined if the value is representable. 262 return bool(typename UnsignedType<T>::Type(x) 263 >> PositionOfSignBit<T>::value); 264} 265 266// Bitwise ops may return a larger type, so it's good to use this inline 267// helper guaranteeing that the result is really of type T. 268template<typename T> 269inline T 270BinaryComplement(T x) 271{ 272 return ~x; 273} 274 275template<typename T, 276 typename U, 277 bool IsTSigned = IsSigned<T>::value, 278 bool IsUSigned = IsSigned<U>::value> 279struct DoesRangeContainRange 280{ 281}; 282 283template<typename T, typename U, bool Signedness> 284struct DoesRangeContainRange<T, U, Signedness, Signedness> 285{ 286 static const bool value = sizeof(T) >= sizeof(U); 287}; 288 289template<typename T, typename U> 290struct DoesRangeContainRange<T, U, true, false> 291{ 292 static const bool value = sizeof(T) > sizeof(U); 293}; 294 295template<typename T, typename U> 296struct DoesRangeContainRange<T, U, false, true> 297{ 298 static const bool value = false; 299}; 300 301template<typename T, 302 typename U, 303 bool IsTSigned = IsSigned<T>::value, 304 bool IsUSigned = IsSigned<U>::value, 305 bool DoesTRangeContainURange = DoesRangeContainRange<T, U>::value> 306struct IsInRangeImpl {}; 307 308template<typename T, typename U, bool IsTSigned, bool IsUSigned> 309struct IsInRangeImpl<T, U, IsTSigned, IsUSigned, true> 310{ 311 static bool run(U) 312 { 313 return true; 314 } 315}; 316 317template<typename T, typename U> 318struct IsInRangeImpl<T, U, true, true, false> 319{ 320 static bool run(U x) 321 { 322 return x <= MaxValue<T>::value && x >= MinValue<T>::value; 323 } 324}; 325 326template<typename T, typename U> 327struct IsInRangeImpl<T, U, false, false, false> 328{ 329 static bool run(U x) 330 { 331 return x <= MaxValue<T>::value; 332 } 333}; 334 335template<typename T, typename U> 336struct IsInRangeImpl<T, U, true, false, false> 337{ 338 static bool run(U x) 339 { 340 return sizeof(T) > sizeof(U) || x <= U(MaxValue<T>::value); 341 } 342}; 343 344template<typename T, typename U> 345struct IsInRangeImpl<T, U, false, true, false> 346{ 347 static bool run(U x) 348 { 349 return sizeof(T) >= sizeof(U) 350 ? x >= 0 351 : x >= 0 && x <= U(MaxValue<T>::value); 352 } 353}; 354 355template<typename T, typename U> 356inline bool 357IsInRange(U x) 358{ 359 return IsInRangeImpl<T, U>::run(x); 360} 361 362template<typename T> 363inline bool 364IsAddValid(T x, T y) 365{ 366 // Addition is valid if the sign of x+y is equal to either that of x or that 367 // of y. Since the value of x+y is undefined if we have a signed type, we 368 // compute it using the unsigned type of the same size. 369 // Beware! These bitwise operations can return a larger integer type, 370 // if T was a small type like int8_t, so we explicitly cast to T. 371 372 typename UnsignedType<T>::Type ux = x; 373 typename UnsignedType<T>::Type uy = y; 374 typename UnsignedType<T>::Type result = ux + uy; 375 return IsSigned<T>::value 376 ? HasSignBit(BinaryComplement(T((result ^ x) & (result ^ y)))) 377 : BinaryComplement(x) >= y; 378} 379 380template<typename T> 381inline bool 382IsSubValid(T x, T y) 383{ 384 // Subtraction is valid if either x and y have same sign, or x-y and x have 385 // same sign. Since the value of x-y is undefined if we have a signed type, 386 // we compute it using the unsigned type of the same size. 387 typename UnsignedType<T>::Type ux = x; 388 typename UnsignedType<T>::Type uy = y; 389 typename UnsignedType<T>::Type result = ux - uy; 390 391 return IsSigned<T>::value 392 ? HasSignBit(BinaryComplement(T((result ^ x) & (x ^ y)))) 393 : x >= y; 394} 395 396template<typename T, 397 bool IsSigned = IsSigned<T>::value, 398 bool TwiceBiggerTypeIsSupported = 399 IsSupported<typename TwiceBiggerType<T>::Type>::value> 400struct IsMulValidImpl {}; 401 402template<typename T, bool IsSigned> 403struct IsMulValidImpl<T, IsSigned, true> 404{ 405 static bool run(T x, T y) 406 { 407 typedef typename TwiceBiggerType<T>::Type TwiceBiggerType; 408 TwiceBiggerType product = TwiceBiggerType(x) * TwiceBiggerType(y); 409 return IsInRange<T>(product); 410 } 411}; 412 413template<typename T> 414struct IsMulValidImpl<T, true, false> 415{ 416 static bool run(T x, T y) 417 { 418 const T max = MaxValue<T>::value; 419 const T min = MinValue<T>::value; 420 421 if (x == 0 || y == 0) 422 return true; 423 424 if (x > 0) { 425 return y > 0 426 ? x <= max / y 427 : y >= min / x; 428 } 429 430 // If we reach this point, we know that x < 0. 431 return y > 0 432 ? x >= min / y 433 : y >= max / x; 434 } 435}; 436 437template<typename T> 438struct IsMulValidImpl<T, false, false> 439{ 440 static bool run(T x, T y) 441 { 442 return y == 0 || x <= MaxValue<T>::value / y; 443 } 444}; 445 446template<typename T> 447inline bool 448IsMulValid(T x, T y) 449{ 450 return IsMulValidImpl<T>::run(x, y); 451} 452 453template<typename T> 454inline bool 455IsDivValid(T x, T y) 456{ 457 // Keep in mind that in the signed case, min/-1 is invalid because abs(min)>max. 458 return y != 0 && 459 !(IsSigned<T>::value && x == MinValue<T>::value && y == T(-1)); 460} 461 462// This is just to shut up msvc warnings about negating unsigned ints. 463template<typename T, bool IsSigned = IsSigned<T>::value> 464struct OppositeIfSignedImpl 465{ 466 static T run(T x) { return -x; } 467}; 468template<typename T> 469struct OppositeIfSignedImpl<T, false> 470{ 471 static T run(T x) { return x; } 472}; 473template<typename T> 474inline T 475OppositeIfSigned(T x) 476{ 477 return OppositeIfSignedImpl<T>::run(x); 478} 479 480} // namespace detail 481 482 483/* 484 * Step 4: Now define the CheckedInt class. 485 */ 486 487/** 488 * @class CheckedInt 489 * @brief Integer wrapper class checking for integer overflow and other errors 490 * @param T the integer type to wrap. Can be any type among the following: 491 * - any basic integer type such as |int| 492 * - any stdint type such as |int8_t| 493 * 494 * This class implements guarded integer arithmetic. Do a computation, check 495 * that isValid() returns true, you then have a guarantee that no problem, such 496 * as integer overflow, happened during this computation, and you can call 497 * value() to get the plain integer value. 498 * 499 * The arithmetic operators in this class are guaranteed not to raise a signal 500 * (e.g. in case of a division by zero). 501 * 502 * For example, suppose that you want to implement a function that computes 503 * (x+y)/z, that doesn't crash if z==0, and that reports on error (divide by 504 * zero or integer overflow). You could code it as follows: 505 @code 506 bool computeXPlusYOverZ(int x, int y, int z, int *result) 507 { 508 CheckedInt<int> checkedResult = (CheckedInt<int>(x) + y) / z; 509 if (checkedResult.isValid()) { 510 *result = checkedResult.value(); 511 return true; 512 } else { 513 return false; 514 } 515 } 516 @endcode 517 * 518 * Implicit conversion from plain integers to checked integers is allowed. The 519 * plain integer is checked to be in range before being casted to the 520 * destination type. This means that the following lines all compile, and the 521 * resulting CheckedInts are correctly detected as valid or invalid: 522 * @code 523 // 1 is of type int, is found to be in range for uint8_t, x is valid 524 CheckedInt<uint8_t> x(1); 525 // -1 is of type int, is found not to be in range for uint8_t, x is invalid 526 CheckedInt<uint8_t> x(-1); 527 // -1 is of type int, is found to be in range for int8_t, x is valid 528 CheckedInt<int8_t> x(-1); 529 // 1000 is of type int16_t, is found not to be in range for int8_t, 530 // x is invalid 531 CheckedInt<int8_t> x(int16_t(1000)); 532 // 3123456789 is of type uint32_t, is found not to be in range for int32_t, 533 // x is invalid 534 CheckedInt<int32_t> x(uint32_t(3123456789)); 535 * @endcode 536 * Implicit conversion from 537 * checked integers to plain integers is not allowed. As shown in the 538 * above example, to get the value of a checked integer as a normal integer, 539 * call value(). 540 * 541 * Arithmetic operations between checked and plain integers is allowed; the 542 * result type is the type of the checked integer. 543 * 544 * Checked integers of different types cannot be used in the same arithmetic 545 * expression. 546 * 547 * There are convenience typedefs for all stdint types, of the following form 548 * (these are just 2 examples): 549 @code 550 typedef CheckedInt<int32_t> CheckedInt32; 551 typedef CheckedInt<uint16_t> CheckedUint16; 552 @endcode 553 */ 554template<typename T> 555class CheckedInt 556{ 557 protected: 558 T mValue; 559 bool mIsValid; 560 561 template<typename U> 562 CheckedInt(U value, bool isValid) : mValue(value), mIsValid(isValid) 563 { 564 MOZ_STATIC_ASSERT(detail::IsSupported<T>::value, 565 "This type is not supported by CheckedInt"); 566 } 567 568 public: 569 /** 570 * Constructs a checked integer with given @a value. The checked integer is 571 * initialized as valid or invalid depending on whether the @a value 572 * is in range. 573 * 574 * This constructor is not explicit. Instead, the type of its argument is a 575 * separate template parameter, ensuring that no conversion is performed 576 * before this constructor is actually called. As explained in the above 577 * documentation for class CheckedInt, this constructor checks that its 578 * argument is valid. 579 */ 580 template<typename U> 581 CheckedInt(U value) 582 : mValue(T(value)), 583 mIsValid(detail::IsInRange<T>(value)) 584 { 585 MOZ_STATIC_ASSERT(detail::IsSupported<T>::value, 586 "This type is not supported by CheckedInt"); 587 } 588 589 /** Constructs a valid checked integer with initial value 0 */ 590 CheckedInt() : mValue(0), mIsValid(true) 591 { 592 MOZ_STATIC_ASSERT(detail::IsSupported<T>::value, 593 "This type is not supported by CheckedInt"); 594 } 595 596 /** @returns the actual value */ 597 T value() const 598 { 599 MOZ_ASSERT(mIsValid, "Invalid checked integer (division by zero or integer overflow)"); 600 return mValue; 601 } 602 603 /** 604 * @returns true if the checked integer is valid, i.e. is not the result 605 * of an invalid operation or of an operation involving an invalid checked 606 * integer 607 */ 608 bool isValid() const 609 { 610 return mIsValid; 611 } 612 613 template<typename U> 614 friend CheckedInt<U> operator +(const CheckedInt<U>& lhs, 615 const CheckedInt<U>& rhs); 616 template<typename U> 617 CheckedInt& operator +=(U rhs); 618 template<typename U> 619 friend CheckedInt<U> operator -(const CheckedInt<U>& lhs, 620 const CheckedInt<U> &rhs); 621 template<typename U> 622 CheckedInt& operator -=(U rhs); 623 template<typename U> 624 friend CheckedInt<U> operator *(const CheckedInt<U>& lhs, 625 const CheckedInt<U> &rhs); 626 template<typename U> 627 CheckedInt& operator *=(U rhs); 628 template<typename U> 629 friend CheckedInt<U> operator /(const CheckedInt<U>& lhs, 630 const CheckedInt<U> &rhs); 631 template<typename U> 632 CheckedInt& operator /=(U rhs); 633 634 CheckedInt operator -() const 635 { 636 // Circumvent msvc warning about - applied to unsigned int. 637 // if we're unsigned, the only valid case anyway is 0 638 // in which case - is a no-op. 639 T result = detail::OppositeIfSigned(mValue); 640 /* Help the compiler perform RVO (return value optimization). */ 641 return CheckedInt(result, 642 mIsValid && detail::IsSubValid(T(0), 643 mValue)); 644 } 645 646 /** 647 * @returns true if the left and right hand sides are valid 648 * and have the same value. 649 * 650 * Note that these semantics are the reason why we don't offer 651 * a operator!=. Indeed, we'd want to have a!=b be equivalent to !(a==b) 652 * but that would mean that whenever a or b is invalid, a!=b 653 * is always true, which would be very confusing. 654 * 655 * For similar reasons, operators <, >, <=, >= would be very tricky to 656 * specify, so we just avoid offering them. 657 * 658 * Notice that these == semantics are made more reasonable by these facts: 659 * 1. a==b implies equality at the raw data level 660 * (the converse is false, as a==b is never true among invalids) 661 * 2. This is similar to the behavior of IEEE floats, where a==b 662 * means that a and b have the same value *and* neither is NaN. 663 */ 664 bool operator ==(const CheckedInt& other) const 665 { 666 return mIsValid && other.mIsValid && mValue == other.mValue; 667 } 668 669 /** prefix ++ */ 670 CheckedInt& operator++() 671 { 672 *this += 1; 673 return *this; 674 } 675 676 /** postfix ++ */ 677 CheckedInt operator++(int) 678 { 679 CheckedInt tmp = *this; 680 *this += 1; 681 return tmp; 682 } 683 684 /** prefix -- */ 685 CheckedInt& operator--() 686 { 687 *this -= 1; 688 return *this; 689 } 690 691 /** postfix -- */ 692 CheckedInt operator--(int) 693 { 694 CheckedInt tmp = *this; 695 *this -= 1; 696 return tmp; 697 } 698 699 private: 700 /** 701 * The !=, <, <=, >, >= operators are disabled: 702 * see the comment on operator==. 703 */ 704 template<typename U> 705 bool operator !=(U other) const MOZ_DELETE; 706 template<typename U> 707 bool operator <(U other) const MOZ_DELETE; 708 template<typename U> 709 bool operator <=(U other) const MOZ_DELETE; 710 template<typename U> 711 bool operator >(U other) const MOZ_DELETE; 712 template<typename U> 713 bool operator >=(U other) const MOZ_DELETE; 714}; 715 716#define MOZ_CHECKEDINT_BASIC_BINARY_OPERATOR(NAME, OP) \ 717template<typename T> \ 718inline CheckedInt<T> operator OP(const CheckedInt<T> &lhs, \ 719 const CheckedInt<T> &rhs) \ 720{ \ 721 if (!detail::Is##NAME##Valid(lhs.mValue, rhs.mValue)) \ 722 return CheckedInt<T>(0, false); \ 723 \ 724 return CheckedInt<T>(lhs.mValue OP rhs.mValue, \ 725 lhs.mIsValid && rhs.mIsValid); \ 726} 727 728MOZ_CHECKEDINT_BASIC_BINARY_OPERATOR(Add, +) 729MOZ_CHECKEDINT_BASIC_BINARY_OPERATOR(Sub, -) 730MOZ_CHECKEDINT_BASIC_BINARY_OPERATOR(Mul, *) 731MOZ_CHECKEDINT_BASIC_BINARY_OPERATOR(Div, /) 732 733#undef MOZ_CHECKEDINT_BASIC_BINARY_OPERATOR 734 735// Implement castToCheckedInt<T>(x), making sure that 736// - it allows x to be either a CheckedInt<T> or any integer type 737// that can be casted to T 738// - if x is already a CheckedInt<T>, we just return a reference to it, 739// instead of copying it (optimization) 740 741namespace detail { 742 743template<typename T, typename U> 744struct CastToCheckedIntImpl 745{ 746 typedef CheckedInt<T> ReturnType; 747 static CheckedInt<T> run(U u) { return u; } 748}; 749 750template<typename T> 751struct CastToCheckedIntImpl<T, CheckedInt<T> > 752{ 753 typedef const CheckedInt<T>& ReturnType; 754 static const CheckedInt<T>& run(const CheckedInt<T>& u) { return u; } 755}; 756 757} // namespace detail 758 759template<typename T, typename U> 760inline typename detail::CastToCheckedIntImpl<T, U>::ReturnType 761castToCheckedInt(U u) 762{ 763 return detail::CastToCheckedIntImpl<T, U>::run(u); 764} 765 766#define MOZ_CHECKEDINT_CONVENIENCE_BINARY_OPERATORS(OP, COMPOUND_OP) \ 767template<typename T> \ 768template<typename U> \ 769CheckedInt<T>& CheckedInt<T>::operator COMPOUND_OP(U rhs) \ 770{ \ 771 *this = *this OP castToCheckedInt<T>(rhs); \ 772 return *this; \ 773} \ 774template<typename T, typename U> \ 775inline CheckedInt<T> operator OP(const CheckedInt<T> &lhs, U rhs) \ 776{ \ 777 return lhs OP castToCheckedInt<T>(rhs); \ 778} \ 779template<typename T, typename U> \ 780inline CheckedInt<T> operator OP(U lhs, const CheckedInt<T> &rhs) \ 781{ \ 782 return castToCheckedInt<T>(lhs) OP rhs; \ 783} 784 785MOZ_CHECKEDINT_CONVENIENCE_BINARY_OPERATORS(+, +=) 786MOZ_CHECKEDINT_CONVENIENCE_BINARY_OPERATORS(*, *=) 787MOZ_CHECKEDINT_CONVENIENCE_BINARY_OPERATORS(-, -=) 788MOZ_CHECKEDINT_CONVENIENCE_BINARY_OPERATORS(/, /=) 789 790#undef MOZ_CHECKEDINT_CONVENIENCE_BINARY_OPERATORS 791 792template<typename T, typename U> 793inline bool 794operator ==(const CheckedInt<T> &lhs, U rhs) 795{ 796 return lhs == castToCheckedInt<T>(rhs); 797} 798 799template<typename T, typename U> 800inline bool 801operator ==(U lhs, const CheckedInt<T> &rhs) 802{ 803 return castToCheckedInt<T>(lhs) == rhs; 804} 805 806// Convenience typedefs. 807typedef CheckedInt<int8_t> CheckedInt8; 808typedef CheckedInt<uint8_t> CheckedUint8; 809typedef CheckedInt<int16_t> CheckedInt16; 810typedef CheckedInt<uint16_t> CheckedUint16; 811typedef CheckedInt<int32_t> CheckedInt32; 812typedef CheckedInt<uint32_t> CheckedUint32; 813typedef CheckedInt<int64_t> CheckedInt64; 814typedef CheckedInt<uint64_t> CheckedUint64; 815 816} // namespace blink 817 818#endif /* mozilla_CheckedInt_h_ */ 819