Home | History | Annotate | Download | only in platform
      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