• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 int>
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