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