mfbt/CheckedInt.h

Tue, 06 Jan 2015 21:39:09 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Tue, 06 Jan 2015 21:39:09 +0100
branch
TOR_BUG_9701
changeset 8
97036ab72558
permissions
-rw-r--r--

Conditionally force memory storage according to privacy.thirdparty.isolate;
This solves Tor bug #9701, complying with disk avoidance documented in
https://www.torproject.org/projects/torbrowser/design/#disk-avoidance.

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

mercurial