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 50 namespace blink { 51 52 namespace 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 65 struct UnsupportedType {}; 66 67 template<typename IntegerType> 68 struct IsSupportedPass2 69 { 70 static const bool value = false; 71 }; 72 73 template<typename IntegerType> 74 struct IsSupported 75 { 76 static const bool value = IsSupportedPass2<IntegerType>::value; 77 }; 78 79 template<> 80 struct IsSupported<int8_t> 81 { static const bool value = true; }; 82 83 template<> 84 struct IsSupported<uint8_t> 85 { static const bool value = true; }; 86 87 template<> 88 struct IsSupported<int16_t> 89 { static const bool value = true; }; 90 91 template<> 92 struct IsSupported<uint16_t> 93 { static const bool value = true; }; 94 95 template<> 96 struct IsSupported<int32_t> 97 { static const bool value = true; }; 98 99 template<> 100 struct IsSupported<uint32_t> 101 { static const bool value = true; }; 102 103 template<> 104 struct IsSupported<int64_t> 105 { static const bool value = true; }; 106 107 template<> 108 struct IsSupported<uint64_t> 109 { static const bool value = true; }; 110 111 112 template<> 113 struct IsSupportedPass2<char> 114 { static const bool value = true; }; 115 116 template<> 117 struct IsSupportedPass2<unsigned char> 118 { static const bool value = true; }; 119 120 template<> 121 struct IsSupportedPass2<short> 122 { static const bool value = true; }; 123 124 template<> 125 struct IsSupportedPass2<unsigned short> 126 { static const bool value = true; }; 127 128 template<> 129 struct IsSupportedPass2<int> 130 { static const bool value = true; }; 131 132 template<> 133 struct IsSupportedPass2<unsigned> 134 { static const bool value = true; }; 135 136 template<> 137 struct IsSupportedPass2<long> 138 { static const bool value = true; }; 139 140 template<> 141 struct IsSupportedPass2<unsigned long> 142 { static const bool value = true; }; 143 144 145 /* 146 * Step 2: some integer-traits kind of stuff. 147 */ 148 149 template<size_t Size, bool Signedness> 150 struct StdintTypeForSizeAndSignedness 151 {}; 152 153 template<> 154 struct StdintTypeForSizeAndSignedness<1, true> 155 { typedef int8_t Type; }; 156 157 template<> 158 struct StdintTypeForSizeAndSignedness<1, false> 159 { typedef uint8_t Type; }; 160 161 template<> 162 struct StdintTypeForSizeAndSignedness<2, true> 163 { typedef int16_t Type; }; 164 165 template<> 166 struct StdintTypeForSizeAndSignedness<2, false> 167 { typedef uint16_t Type; }; 168 169 template<> 170 struct StdintTypeForSizeAndSignedness<4, true> 171 { typedef int32_t Type; }; 172 173 template<> 174 struct StdintTypeForSizeAndSignedness<4, false> 175 { typedef uint32_t Type; }; 176 177 template<> 178 struct StdintTypeForSizeAndSignedness<8, true> 179 { typedef int64_t Type; }; 180 181 template<> 182 struct StdintTypeForSizeAndSignedness<8, false> 183 { typedef uint64_t Type; }; 184 185 template<typename IntegerType> 186 struct UnsignedType 187 { 188 typedef typename StdintTypeForSizeAndSignedness<sizeof(IntegerType), 189 false>::Type Type; 190 }; 191 192 template<typename IntegerType> 193 struct IsSigned 194 { 195 static const bool value = IntegerType(-1) <= IntegerType(0); 196 }; 197 198 template<typename IntegerType, size_t Size = sizeof(IntegerType)> 199 struct TwiceBiggerType 200 { 201 typedef typename StdintTypeForSizeAndSignedness< 202 sizeof(IntegerType) * 2, 203 IsSigned<IntegerType>::value 204 >::Type Type; 205 }; 206 207 template<typename IntegerType> 208 struct TwiceBiggerType<IntegerType, 8> 209 { 210 typedef UnsupportedType Type; 211 }; 212 213 template<typename IntegerType> 214 struct PositionOfSignBit 215 { 216 static const size_t value = CHAR_BIT * sizeof(IntegerType) - 1; 217 }; 218 219 template<typename IntegerType> 220 struct 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 239 template<typename IntegerType> 240 struct 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 254 template<typename T> 255 inline bool 256 HasSignBit(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. 268 template<typename T> 269 inline T 270 BinaryComplement(T x) 271 { 272 return ~x; 273 } 274 275 template<typename T, 276 typename U, 277 bool IsTSigned = IsSigned<T>::value, 278 bool IsUSigned = IsSigned<U>::value> 279 struct DoesRangeContainRange 280 { 281 }; 282 283 template<typename T, typename U, bool Signedness> 284 struct DoesRangeContainRange<T, U, Signedness, Signedness> 285 { 286 static const bool value = sizeof(T) >= sizeof(U); 287 }; 288 289 template<typename T, typename U> 290 struct DoesRangeContainRange<T, U, true, false> 291 { 292 static const bool value = sizeof(T) > sizeof(U); 293 }; 294 295 template<typename T, typename U> 296 struct DoesRangeContainRange<T, U, false, true> 297 { 298 static const bool value = false; 299 }; 300 301 template<typename T, 302 typename U, 303 bool IsTSigned = IsSigned<T>::value, 304 bool IsUSigned = IsSigned<U>::value, 305 bool DoesTRangeContainURange = DoesRangeContainRange<T, U>::value> 306 struct IsInRangeImpl {}; 307 308 template<typename T, typename U, bool IsTSigned, bool IsUSigned> 309 struct IsInRangeImpl<T, U, IsTSigned, IsUSigned, true> 310 { 311 static bool run(U) 312 { 313 return true; 314 } 315 }; 316 317 template<typename T, typename U> 318 struct 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 326 template<typename T, typename U> 327 struct IsInRangeImpl<T, U, false, false, false> 328 { 329 static bool run(U x) 330 { 331 return x <= MaxValue<T>::value; 332 } 333 }; 334 335 template<typename T, typename U> 336 struct 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 344 template<typename T, typename U> 345 struct 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 355 template<typename T, typename U> 356 inline bool 357 IsInRange(U x) 358 { 359 return IsInRangeImpl<T, U>::run(x); 360 } 361 362 template<typename T> 363 inline bool 364 IsAddValid(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 380 template<typename T> 381 inline bool 382 IsSubValid(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 396 template<typename T, 397 bool IsSigned = IsSigned<T>::value, 398 bool TwiceBiggerTypeIsSupported = 399 IsSupported<typename TwiceBiggerType<T>::Type>::value> 400 struct IsMulValidImpl {}; 401 402 template<typename T, bool IsSigned> 403 struct 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 413 template<typename T> 414 struct 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 437 template<typename T> 438 struct 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 446 template<typename T> 447 inline bool 448 IsMulValid(T x, T y) 449 { 450 return IsMulValidImpl<T>::run(x, y); 451 } 452 453 template<typename T> 454 inline bool 455 IsDivValid(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. 463 template<typename T, bool IsSigned = IsSigned<T>::value> 464 struct OppositeIfSignedImpl 465 { 466 static T run(T x) { return -x; } 467 }; 468 template<typename T> 469 struct OppositeIfSignedImpl<T, false> 470 { 471 static T run(T x) { return x; } 472 }; 473 template<typename T> 474 inline T 475 OppositeIfSigned(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 */ 554 template<typename T> 555 class 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) \ 717 template<typename T> \ 718 inline 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 728 MOZ_CHECKEDINT_BASIC_BINARY_OPERATOR(Add, +) 729 MOZ_CHECKEDINT_BASIC_BINARY_OPERATOR(Sub, -) 730 MOZ_CHECKEDINT_BASIC_BINARY_OPERATOR(Mul, *) 731 MOZ_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 741 namespace detail { 742 743 template<typename T, typename U> 744 struct CastToCheckedIntImpl 745 { 746 typedef CheckedInt<T> ReturnType; 747 static CheckedInt<T> run(U u) { return u; } 748 }; 749 750 template<typename T> 751 struct 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 759 template<typename T, typename U> 760 inline typename detail::CastToCheckedIntImpl<T, U>::ReturnType 761 castToCheckedInt(U u) 762 { 763 return detail::CastToCheckedIntImpl<T, U>::run(u); 764 } 765 766 #define MOZ_CHECKEDINT_CONVENIENCE_BINARY_OPERATORS(OP, COMPOUND_OP) \ 767 template<typename T> \ 768 template<typename U> \ 769 CheckedInt<T>& CheckedInt<T>::operator COMPOUND_OP(U rhs) \ 770 { \ 771 *this = *this OP castToCheckedInt<T>(rhs); \ 772 return *this; \ 773 } \ 774 template<typename T, typename U> \ 775 inline CheckedInt<T> operator OP(const CheckedInt<T> &lhs, U rhs) \ 776 { \ 777 return lhs OP castToCheckedInt<T>(rhs); \ 778 } \ 779 template<typename T, typename U> \ 780 inline CheckedInt<T> operator OP(U lhs, const CheckedInt<T> &rhs) \ 781 { \ 782 return castToCheckedInt<T>(lhs) OP rhs; \ 783 } 784 785 MOZ_CHECKEDINT_CONVENIENCE_BINARY_OPERATORS(+, +=) 786 MOZ_CHECKEDINT_CONVENIENCE_BINARY_OPERATORS(*, *=) 787 MOZ_CHECKEDINT_CONVENIENCE_BINARY_OPERATORS(-, -=) 788 MOZ_CHECKEDINT_CONVENIENCE_BINARY_OPERATORS(/, /=) 789 790 #undef MOZ_CHECKEDINT_CONVENIENCE_BINARY_OPERATORS 791 792 template<typename T, typename U> 793 inline bool 794 operator ==(const CheckedInt<T> &lhs, U rhs) 795 { 796 return lhs == castToCheckedInt<T>(rhs); 797 } 798 799 template<typename T, typename U> 800 inline bool 801 operator ==(U lhs, const CheckedInt<T> &rhs) 802 { 803 return castToCheckedInt<T>(lhs) == rhs; 804 } 805 806 // Convenience typedefs. 807 typedef CheckedInt<int8_t> CheckedInt8; 808 typedef CheckedInt<uint8_t> CheckedUint8; 809 typedef CheckedInt<int16_t> CheckedInt16; 810 typedef CheckedInt<uint16_t> CheckedUint16; 811 typedef CheckedInt<int32_t> CheckedInt32; 812 typedef CheckedInt<uint32_t> CheckedUint32; 813 typedef CheckedInt<int64_t> CheckedInt64; 814 typedef CheckedInt<uint64_t> CheckedUint64; 815 816 } // namespace blink 817 818 #endif /* mozilla_CheckedInt_h_ */ 819