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