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
50namespace blink {
51
52namespace 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
65struct UnsupportedType {};
66
67template<typename IntegerType>
68struct IsSupportedPass2
69{
70    static const bool value = false;
71};
72
73template<typename IntegerType>
74struct IsSupported
75{
76    static const bool value = IsSupportedPass2<IntegerType>::value;
77};
78
79template<>
80struct IsSupported<int8_t>
81{ static const bool value = true; };
82
83template<>
84struct IsSupported<uint8_t>
85{ static const bool value = true; };
86
87template<>
88struct IsSupported<int16_t>
89{ static const bool value = true; };
90
91template<>
92struct IsSupported<uint16_t>
93{ static const bool value = true; };
94
95template<>
96struct IsSupported<int32_t>
97{ static const bool value = true; };
98
99template<>
100struct IsSupported<uint32_t>
101{ static const bool value = true; };
102
103template<>
104struct IsSupported<int64_t>
105{ static const bool value = true; };
106
107template<>
108struct IsSupported<uint64_t>
109{ static const bool value = true; };
110
111
112template<>
113struct IsSupportedPass2<char>
114{ static const bool value = true; };
115
116template<>
117struct IsSupportedPass2<unsigned char>
118{ static const bool value = true; };
119
120template<>
121struct IsSupportedPass2<short>
122{ static const bool value = true; };
123
124template<>
125struct IsSupportedPass2<unsigned short>
126{ static const bool value = true; };
127
128template<>
129struct IsSupportedPass2<int>
130{ static const bool value = true; };
131
132template<>
133struct IsSupportedPass2<unsigned>
134{ static const bool value = true; };
135
136template<>
137struct IsSupportedPass2<long>
138{ static const bool value = true; };
139
140template<>
141struct IsSupportedPass2<unsigned long>
142{ static const bool value = true; };
143
144
145/*
146 * Step 2: some integer-traits kind of stuff.
147 */
148
149template<size_t Size, bool Signedness>
150struct StdintTypeForSizeAndSignedness
151{};
152
153template<>
154struct StdintTypeForSizeAndSignedness<1, true>
155{ typedef int8_t   Type; };
156
157template<>
158struct StdintTypeForSizeAndSignedness<1, false>
159{ typedef uint8_t  Type; };
160
161template<>
162struct StdintTypeForSizeAndSignedness<2, true>
163{ typedef int16_t  Type; };
164
165template<>
166struct StdintTypeForSizeAndSignedness<2, false>
167{ typedef uint16_t Type; };
168
169template<>
170struct StdintTypeForSizeAndSignedness<4, true>
171{ typedef int32_t  Type; };
172
173template<>
174struct StdintTypeForSizeAndSignedness<4, false>
175{ typedef uint32_t Type; };
176
177template<>
178struct StdintTypeForSizeAndSignedness<8, true>
179{ typedef int64_t  Type; };
180
181template<>
182struct StdintTypeForSizeAndSignedness<8, false>
183{ typedef uint64_t Type; };
184
185template<typename IntegerType>
186struct UnsignedType
187{
188    typedef typename StdintTypeForSizeAndSignedness<sizeof(IntegerType),
189                                                    false>::Type Type;
190};
191
192template<typename IntegerType>
193struct IsSigned
194{
195    static const bool value = IntegerType(-1) <= IntegerType(0);
196};
197
198template<typename IntegerType, size_t Size = sizeof(IntegerType)>
199struct TwiceBiggerType
200{
201    typedef typename StdintTypeForSizeAndSignedness<
202                       sizeof(IntegerType) * 2,
203                       IsSigned<IntegerType>::value
204                     >::Type Type;
205};
206
207template<typename IntegerType>
208struct TwiceBiggerType<IntegerType, 8>
209{
210    typedef UnsupportedType Type;
211};
212
213template<typename IntegerType>
214struct PositionOfSignBit
215{
216    static const size_t value = CHAR_BIT * sizeof(IntegerType) - 1;
217};
218
219template<typename IntegerType>
220struct 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
239template<typename IntegerType>
240struct 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
254template<typename T>
255inline bool
256HasSignBit(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.
268template<typename T>
269inline T
270BinaryComplement(T x)
271{
272  return ~x;
273}
274
275template<typename T,
276         typename U,
277         bool IsTSigned = IsSigned<T>::value,
278         bool IsUSigned = IsSigned<U>::value>
279struct DoesRangeContainRange
280{
281};
282
283template<typename T, typename U, bool Signedness>
284struct DoesRangeContainRange<T, U, Signedness, Signedness>
285{
286    static const bool value = sizeof(T) >= sizeof(U);
287};
288
289template<typename T, typename U>
290struct DoesRangeContainRange<T, U, true, false>
291{
292    static const bool value = sizeof(T) > sizeof(U);
293};
294
295template<typename T, typename U>
296struct DoesRangeContainRange<T, U, false, true>
297{
298    static const bool value = false;
299};
300
301template<typename T,
302         typename U,
303         bool IsTSigned = IsSigned<T>::value,
304         bool IsUSigned = IsSigned<U>::value,
305         bool DoesTRangeContainURange = DoesRangeContainRange<T, U>::value>
306struct IsInRangeImpl {};
307
308template<typename T, typename U, bool IsTSigned, bool IsUSigned>
309struct IsInRangeImpl<T, U, IsTSigned, IsUSigned, true>
310{
311    static bool run(U)
312    {
313       return true;
314    }
315};
316
317template<typename T, typename U>
318struct 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
326template<typename T, typename U>
327struct IsInRangeImpl<T, U, false, false, false>
328{
329    static bool run(U x)
330    {
331      return x <= MaxValue<T>::value;
332    }
333};
334
335template<typename T, typename U>
336struct 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
344template<typename T, typename U>
345struct 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
355template<typename T, typename U>
356inline bool
357IsInRange(U x)
358{
359  return IsInRangeImpl<T, U>::run(x);
360}
361
362template<typename T>
363inline bool
364IsAddValid(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
380template<typename T>
381inline bool
382IsSubValid(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
396template<typename T,
397         bool IsSigned = IsSigned<T>::value,
398         bool TwiceBiggerTypeIsSupported =
399           IsSupported<typename TwiceBiggerType<T>::Type>::value>
400struct IsMulValidImpl {};
401
402template<typename T, bool IsSigned>
403struct 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
413template<typename T>
414struct 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
437template<typename T>
438struct 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
446template<typename T>
447inline bool
448IsMulValid(T x, T y)
449{
450  return IsMulValidImpl<T>::run(x, y);
451}
452
453template<typename T>
454inline bool
455IsDivValid(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.
463template<typename T, bool IsSigned = IsSigned<T>::value>
464struct OppositeIfSignedImpl
465{
466    static T run(T x) { return -x; }
467};
468template<typename T>
469struct OppositeIfSignedImpl<T, false>
470{
471    static T run(T x) { return x; }
472};
473template<typename T>
474inline T
475OppositeIfSigned(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 */
554template<typename T>
555class 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)                \
717template<typename T>                                                  \
718inline 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
728MOZ_CHECKEDINT_BASIC_BINARY_OPERATOR(Add, +)
729MOZ_CHECKEDINT_BASIC_BINARY_OPERATOR(Sub, -)
730MOZ_CHECKEDINT_BASIC_BINARY_OPERATOR(Mul, *)
731MOZ_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
741namespace detail {
742
743template<typename T, typename U>
744struct CastToCheckedIntImpl
745{
746    typedef CheckedInt<T> ReturnType;
747    static CheckedInt<T> run(U u) { return u; }
748};
749
750template<typename T>
751struct 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
759template<typename T, typename U>
760inline typename detail::CastToCheckedIntImpl<T, U>::ReturnType
761castToCheckedInt(U u)
762{
763  return detail::CastToCheckedIntImpl<T, U>::run(u);
764}
765
766#define MOZ_CHECKEDINT_CONVENIENCE_BINARY_OPERATORS(OP, COMPOUND_OP)  \
767template<typename T>                                              \
768template<typename U>                                              \
769CheckedInt<T>& CheckedInt<T>::operator COMPOUND_OP(U rhs)         \
770{                                                                 \
771  *this = *this OP castToCheckedInt<T>(rhs);                      \
772  return *this;                                                   \
773}                                                                 \
774template<typename T, typename U>                                  \
775inline CheckedInt<T> operator OP(const CheckedInt<T> &lhs, U rhs) \
776{                                                                 \
777  return lhs OP castToCheckedInt<T>(rhs);                         \
778}                                                                 \
779template<typename T, typename U>                                  \
780inline CheckedInt<T> operator OP(U lhs, const CheckedInt<T> &rhs) \
781{                                                                 \
782  return castToCheckedInt<T>(lhs) OP rhs;                         \
783}
784
785MOZ_CHECKEDINT_CONVENIENCE_BINARY_OPERATORS(+, +=)
786MOZ_CHECKEDINT_CONVENIENCE_BINARY_OPERATORS(*, *=)
787MOZ_CHECKEDINT_CONVENIENCE_BINARY_OPERATORS(-, -=)
788MOZ_CHECKEDINT_CONVENIENCE_BINARY_OPERATORS(/, /=)
789
790#undef MOZ_CHECKEDINT_CONVENIENCE_BINARY_OPERATORS
791
792template<typename T, typename U>
793inline bool
794operator ==(const CheckedInt<T> &lhs, U rhs)
795{
796  return lhs == castToCheckedInt<T>(rhs);
797}
798
799template<typename T, typename U>
800inline bool
801operator ==(U  lhs, const CheckedInt<T> &rhs)
802{
803  return castToCheckedInt<T>(lhs) == rhs;
804}
805
806// Convenience typedefs.
807typedef CheckedInt<int8_t>   CheckedInt8;
808typedef CheckedInt<uint8_t>  CheckedUint8;
809typedef CheckedInt<int16_t>  CheckedInt16;
810typedef CheckedInt<uint16_t> CheckedUint16;
811typedef CheckedInt<int32_t>  CheckedInt32;
812typedef CheckedInt<uint32_t> CheckedUint32;
813typedef CheckedInt<int64_t>  CheckedInt64;
814typedef CheckedInt<uint64_t> CheckedUint64;
815
816} // namespace blink
817
818#endif /* mozilla_CheckedInt_h_ */
819