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 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>
    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