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