Backout 2ea2669b53c3, Bug 917642 - [Helix] Please update the helix blobs
[gecko.git] / mfbt / CheckedInt.h
blob050cef8ed8e4e7c74425fc5ad2f97e7c244704a3
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 // Enable relying of Mozilla's MFBT for possibly-available C++11 features
13 #define MOZ_CHECKEDINT_USE_MFBT
15 #include <stdint.h>
17 #ifdef MOZ_CHECKEDINT_USE_MFBT
18 # include "mozilla/Assertions.h"
19 #else
20 # include <cassert>
21 # define MOZ_ASSERT(cond, reason) assert((cond) && reason)
22 # define MOZ_DELETE
23 #endif
25 #include <climits>
26 #include <cstddef>
28 namespace mozilla {
30 template<typename T> class CheckedInt;
32 namespace detail {
35 * Step 1: manually record supported types
37 * What's nontrivial here is that there are different families of integer
38 * types: basic integer types and stdint types. It is merrily undefined which
39 * types from one family may be just typedefs for a type from another family.
41 * For example, on GCC 4.6, aside from the basic integer types, the only other
42 * type that isn't just a typedef for some of them, is int8_t.
45 struct UnsupportedType {};
47 template<typename IntegerType>
48 struct IsSupportedPass2
50 static const bool value = false;
53 template<typename IntegerType>
54 struct IsSupported
56 static const bool value = IsSupportedPass2<IntegerType>::value;
59 template<>
60 struct IsSupported<int8_t>
61 { static const bool value = true; };
63 template<>
64 struct IsSupported<uint8_t>
65 { static const bool value = true; };
67 template<>
68 struct IsSupported<int16_t>
69 { static const bool value = true; };
71 template<>
72 struct IsSupported<uint16_t>
73 { static const bool value = true; };
75 template<>
76 struct IsSupported<int32_t>
77 { static const bool value = true; };
79 template<>
80 struct IsSupported<uint32_t>
81 { static const bool value = true; };
83 template<>
84 struct IsSupported<int64_t>
85 { static const bool value = true; };
87 template<>
88 struct IsSupported<uint64_t>
89 { static const bool value = true; };
92 template<>
93 struct IsSupportedPass2<char>
94 { static const bool value = true; };
96 template<>
97 struct IsSupportedPass2<signed char>
98 { static const bool value = true; };
100 template<>
101 struct IsSupportedPass2<unsigned char>
102 { static const bool value = true; };
104 template<>
105 struct IsSupportedPass2<short>
106 { static const bool value = true; };
108 template<>
109 struct IsSupportedPass2<unsigned short>
110 { static const bool value = true; };
112 template<>
113 struct IsSupportedPass2<int>
114 { static const bool value = true; };
116 template<>
117 struct IsSupportedPass2<unsigned int>
118 { static const bool value = true; };
120 template<>
121 struct IsSupportedPass2<long>
122 { static const bool value = true; };
124 template<>
125 struct IsSupportedPass2<unsigned long>
126 { static const bool value = true; };
128 template<>
129 struct IsSupportedPass2<long long>
130 { static const bool value = true; };
132 template<>
133 struct IsSupportedPass2<unsigned long long>
134 { static const bool value = true; };
137 * Step 2: some integer-traits kind of stuff.
140 template<size_t Size, bool Signedness>
141 struct StdintTypeForSizeAndSignedness
144 template<>
145 struct StdintTypeForSizeAndSignedness<1, true>
146 { typedef int8_t Type; };
148 template<>
149 struct StdintTypeForSizeAndSignedness<1, false>
150 { typedef uint8_t Type; };
152 template<>
153 struct StdintTypeForSizeAndSignedness<2, true>
154 { typedef int16_t Type; };
156 template<>
157 struct StdintTypeForSizeAndSignedness<2, false>
158 { typedef uint16_t Type; };
160 template<>
161 struct StdintTypeForSizeAndSignedness<4, true>
162 { typedef int32_t Type; };
164 template<>
165 struct StdintTypeForSizeAndSignedness<4, false>
166 { typedef uint32_t Type; };
168 template<>
169 struct StdintTypeForSizeAndSignedness<8, true>
170 { typedef int64_t Type; };
172 template<>
173 struct StdintTypeForSizeAndSignedness<8, false>
174 { typedef uint64_t Type; };
176 template<typename IntegerType>
177 struct UnsignedType
179 typedef typename StdintTypeForSizeAndSignedness<sizeof(IntegerType),
180 false>::Type Type;
183 template<typename IntegerType>
184 struct IsSigned
186 static const bool value = IntegerType(-1) <= IntegerType(0);
189 template<typename IntegerType, size_t Size = sizeof(IntegerType)>
190 struct TwiceBiggerType
192 typedef typename StdintTypeForSizeAndSignedness<
193 sizeof(IntegerType) * 2,
194 IsSigned<IntegerType>::value
195 >::Type Type;
198 template<typename IntegerType>
199 struct TwiceBiggerType<IntegerType, 8>
201 typedef UnsupportedType Type;
204 template<typename IntegerType>
205 struct PositionOfSignBit
207 static const size_t value = CHAR_BIT * sizeof(IntegerType) - 1;
210 template<typename IntegerType>
211 struct MinValue
213 private:
214 typedef typename UnsignedType<IntegerType>::Type UnsignedIntegerType;
215 static const size_t PosOfSignBit = PositionOfSignBit<IntegerType>::value;
217 public:
218 // Bitwise ops may return a larger type, that's why we cast explicitly.
219 // In C++, left bit shifts on signed values is undefined by the standard
220 // unless the shifted value is representable.
221 // Notice that signed-to-unsigned conversions are always well-defined in
222 // the standard as the value congruent to 2**n, as expected. By contrast,
223 // unsigned-to-signed is only well-defined if the value is representable.
224 static const IntegerType value =
225 IsSigned<IntegerType>::value
226 ? IntegerType(UnsignedIntegerType(1) << PosOfSignBit)
227 : IntegerType(0);
230 template<typename IntegerType>
231 struct MaxValue
233 // Tricksy, but covered by the unit test.
234 // Relies heavily on the type of MinValue<IntegerType>::value
235 // being IntegerType.
236 static const IntegerType value = ~MinValue<IntegerType>::value;
240 * Step 3: Implement the actual validity checks.
242 * Ideas taken from IntegerLib, code different.
245 template<typename T>
246 inline bool
247 HasSignBit(T x)
249 // In C++, right bit shifts on negative values is undefined by the standard.
250 // Notice that signed-to-unsigned conversions are always well-defined in the
251 // standard, as the value congruent modulo 2**n as expected. By contrast,
252 // unsigned-to-signed is only well-defined if the value is representable.
253 return bool(typename UnsignedType<T>::Type(x)
254 >> PositionOfSignBit<T>::value);
257 // Bitwise ops may return a larger type, so it's good to use this inline
258 // helper guaranteeing that the result is really of type T.
259 template<typename T>
260 inline T
261 BinaryComplement(T x)
263 return ~x;
266 template<typename T,
267 typename U,
268 bool IsTSigned = IsSigned<T>::value,
269 bool IsUSigned = IsSigned<U>::value>
270 struct DoesRangeContainRange
274 template<typename T, typename U, bool Signedness>
275 struct DoesRangeContainRange<T, U, Signedness, Signedness>
277 static const bool value = sizeof(T) >= sizeof(U);
280 template<typename T, typename U>
281 struct DoesRangeContainRange<T, U, true, false>
283 static const bool value = sizeof(T) > sizeof(U);
286 template<typename T, typename U>
287 struct DoesRangeContainRange<T, U, false, true>
289 static const bool value = false;
292 template<typename T,
293 typename U,
294 bool IsTSigned = IsSigned<T>::value,
295 bool IsUSigned = IsSigned<U>::value,
296 bool DoesTRangeContainURange = DoesRangeContainRange<T, U>::value>
297 struct IsInRangeImpl {};
299 template<typename T, typename U, bool IsTSigned, bool IsUSigned>
300 struct IsInRangeImpl<T, U, IsTSigned, IsUSigned, true>
302 static bool run(U)
304 return true;
308 template<typename T, typename U>
309 struct IsInRangeImpl<T, U, true, true, false>
311 static bool run(U x)
313 return x <= MaxValue<T>::value && x >= MinValue<T>::value;
317 template<typename T, typename U>
318 struct IsInRangeImpl<T, U, false, false, false>
320 static bool run(U x)
322 return x <= MaxValue<T>::value;
326 template<typename T, typename U>
327 struct IsInRangeImpl<T, U, true, false, false>
329 static bool run(U x)
331 return sizeof(T) > sizeof(U) || x <= U(MaxValue<T>::value);
335 template<typename T, typename U>
336 struct IsInRangeImpl<T, U, false, true, false>
338 static bool run(U x)
340 return sizeof(T) >= sizeof(U)
341 ? x >= 0
342 : x >= 0 && x <= U(MaxValue<T>::value);
346 template<typename T, typename U>
347 inline bool
348 IsInRange(U x)
350 return IsInRangeImpl<T, U>::run(x);
353 template<typename T>
354 inline bool
355 IsAddValid(T x, T y)
357 // Addition is valid if the sign of x+y is equal to either that of x or that
358 // of y. Since the value of x+y is undefined if we have a signed type, we
359 // compute it using the unsigned type of the same size.
360 // Beware! These bitwise operations can return a larger integer type,
361 // if T was a small type like int8_t, so we explicitly cast to T.
363 typename UnsignedType<T>::Type ux = x;
364 typename UnsignedType<T>::Type uy = y;
365 typename UnsignedType<T>::Type result = ux + uy;
366 return IsSigned<T>::value
367 ? HasSignBit(BinaryComplement(T((result ^ x) & (result ^ y))))
368 : BinaryComplement(x) >= y;
371 template<typename T>
372 inline bool
373 IsSubValid(T x, T y)
375 // Subtraction is valid if either x and y have same sign, or x-y and x have
376 // same sign. Since the value of x-y is undefined if we have a signed type,
377 // we compute it using the unsigned type of the same size.
378 typename UnsignedType<T>::Type ux = x;
379 typename UnsignedType<T>::Type uy = y;
380 typename UnsignedType<T>::Type result = ux - uy;
382 return IsSigned<T>::value
383 ? HasSignBit(BinaryComplement(T((result ^ x) & (x ^ y))))
384 : x >= y;
387 template<typename T,
388 bool IsTSigned = IsSigned<T>::value,
389 bool TwiceBiggerTypeIsSupported =
390 IsSupported<typename TwiceBiggerType<T>::Type>::value>
391 struct IsMulValidImpl {};
393 template<typename T, bool IsTSigned>
394 struct IsMulValidImpl<T, IsTSigned, true>
396 static bool run(T x, T y)
398 typedef typename TwiceBiggerType<T>::Type TwiceBiggerType;
399 TwiceBiggerType product = TwiceBiggerType(x) * TwiceBiggerType(y);
400 return IsInRange<T>(product);
404 template<typename T>
405 struct IsMulValidImpl<T, true, false>
407 static bool run(T x, T y)
409 const T max = MaxValue<T>::value;
410 const T min = MinValue<T>::value;
412 if (x == 0 || y == 0)
413 return true;
415 if (x > 0) {
416 return y > 0
417 ? x <= max / y
418 : y >= min / x;
421 // If we reach this point, we know that x < 0.
422 return y > 0
423 ? x >= min / y
424 : y >= max / x;
428 template<typename T>
429 struct IsMulValidImpl<T, false, false>
431 static bool run(T x, T y)
433 return y == 0 || x <= MaxValue<T>::value / y;
437 template<typename T>
438 inline bool
439 IsMulValid(T x, T y)
441 return IsMulValidImpl<T>::run(x, y);
444 template<typename T>
445 inline bool
446 IsDivValid(T x, T y)
448 // Keep in mind that in the signed case, min/-1 is invalid because abs(min)>max.
449 return y != 0 &&
450 !(IsSigned<T>::value && x == MinValue<T>::value && y == T(-1));
453 template<typename T, bool IsTSigned = IsSigned<T>::value>
454 struct IsModValidImpl;
456 template<typename T>
457 inline bool
458 IsModValid(T x, T y)
460 return IsModValidImpl<T>::run(x, y);
464 * Mod is pretty simple.
465 * For now, let's just use the ANSI C definition:
466 * If x or y are negative, the results are implementation defined.
467 * Consider these invalid.
468 * Undefined for y=0.
469 * The result will never exceed either x or y.
471 * Checking that x>=0 is a warning when T is unsigned.
474 template<typename T>
475 struct IsModValidImpl<T, false> {
476 static inline bool run(T x, T y) {
477 return y >= 1;
481 template<typename T>
482 struct IsModValidImpl<T, true> {
483 static inline bool run(T x, T y) {
484 if (x < 0)
485 return false;
487 return y >= 1;
491 template<typename T, bool IsSigned = IsSigned<T>::value>
492 struct NegateImpl;
494 template<typename T>
495 struct NegateImpl<T, false>
497 static CheckedInt<T> negate(const CheckedInt<T>& val)
499 // Handle negation separately for signed/unsigned, for simpler code and to
500 // avoid an MSVC warning negating an unsigned value.
501 return CheckedInt<T>(0, val.isValid() && val.mValue == 0);
505 template<typename T>
506 struct NegateImpl<T, true>
508 static CheckedInt<T> negate(const CheckedInt<T>& val)
510 // Watch out for the min-value, which (with twos-complement) can't be
511 // negated as -min-value is then (max-value + 1).
512 if (!val.isValid() || val.mValue == MinValue<T>::value)
513 return CheckedInt<T>(val.mValue, false);
514 return CheckedInt<T>(-val.mValue, true);
518 } // namespace detail
522 * Step 4: Now define the CheckedInt class.
526 * @class CheckedInt
527 * @brief Integer wrapper class checking for integer overflow and other errors
528 * @param T the integer type to wrap. Can be any type among the following:
529 * - any basic integer type such as |int|
530 * - any stdint type such as |int8_t|
532 * This class implements guarded integer arithmetic. Do a computation, check
533 * that isValid() returns true, you then have a guarantee that no problem, such
534 * as integer overflow, happened during this computation, and you can call
535 * value() to get the plain integer value.
537 * The arithmetic operators in this class are guaranteed not to raise a signal
538 * (e.g. in case of a division by zero).
540 * For example, suppose that you want to implement a function that computes
541 * (x+y)/z, that doesn't crash if z==0, and that reports on error (divide by
542 * zero or integer overflow). You could code it as follows:
543 @code
544 bool computeXPlusYOverZ(int x, int y, int z, int *result)
546 CheckedInt<int> checkedResult = (CheckedInt<int>(x) + y) / z;
547 if (checkedResult.isValid()) {
548 *result = checkedResult.value();
549 return true;
550 } else {
551 return false;
554 @endcode
556 * Implicit conversion from plain integers to checked integers is allowed. The
557 * plain integer is checked to be in range before being casted to the
558 * destination type. This means that the following lines all compile, and the
559 * resulting CheckedInts are correctly detected as valid or invalid:
560 * @code
561 // 1 is of type int, is found to be in range for uint8_t, x is valid
562 CheckedInt<uint8_t> x(1);
563 // -1 is of type int, is found not to be in range for uint8_t, x is invalid
564 CheckedInt<uint8_t> x(-1);
565 // -1 is of type int, is found to be in range for int8_t, x is valid
566 CheckedInt<int8_t> x(-1);
567 // 1000 is of type int16_t, is found not to be in range for int8_t,
568 // x is invalid
569 CheckedInt<int8_t> x(int16_t(1000));
570 // 3123456789 is of type uint32_t, is found not to be in range for int32_t,
571 // x is invalid
572 CheckedInt<int32_t> x(uint32_t(3123456789));
573 * @endcode
574 * Implicit conversion from
575 * checked integers to plain integers is not allowed. As shown in the
576 * above example, to get the value of a checked integer as a normal integer,
577 * call value().
579 * Arithmetic operations between checked and plain integers is allowed; the
580 * result type is the type of the checked integer.
582 * Checked integers of different types cannot be used in the same arithmetic
583 * expression.
585 * There are convenience typedefs for all stdint types, of the following form
586 * (these are just 2 examples):
587 @code
588 typedef CheckedInt<int32_t> CheckedInt32;
589 typedef CheckedInt<uint16_t> CheckedUint16;
590 @endcode
592 template<typename T>
593 class CheckedInt
595 protected:
596 T mValue;
597 bool mIsValid;
599 template<typename U>
600 CheckedInt(U value, bool isValid) : mValue(value), mIsValid(isValid)
602 static_assert(detail::IsSupported<T>::value &&
603 detail::IsSupported<U>::value,
604 "This type is not supported by CheckedInt");
607 friend struct detail::NegateImpl<T>;
609 public:
611 * Constructs a checked integer with given @a value. The checked integer is
612 * initialized as valid or invalid depending on whether the @a value
613 * is in range.
615 * This constructor is not explicit. Instead, the type of its argument is a
616 * separate template parameter, ensuring that no conversion is performed
617 * before this constructor is actually called. As explained in the above
618 * documentation for class CheckedInt, this constructor checks that its
619 * argument is valid.
621 template<typename U>
622 CheckedInt(U value)
623 : mValue(T(value)),
624 mIsValid(detail::IsInRange<T>(value))
626 static_assert(detail::IsSupported<T>::value &&
627 detail::IsSupported<U>::value,
628 "This type is not supported by CheckedInt");
631 template<typename U>
632 friend class CheckedInt;
634 template<typename U>
635 CheckedInt<U> toChecked() const
637 CheckedInt<U> ret(mValue);
638 ret.mIsValid = ret.mIsValid && mIsValid;
639 return ret;
642 /** Constructs a valid checked integer with initial value 0 */
643 CheckedInt() : mValue(0), mIsValid(true)
645 static_assert(detail::IsSupported<T>::value,
646 "This type is not supported by CheckedInt");
649 /** @returns the actual value */
650 T value() const
652 MOZ_ASSERT(mIsValid, "Invalid checked integer (division by zero or integer overflow)");
653 return mValue;
657 * @returns true if the checked integer is valid, i.e. is not the result
658 * of an invalid operation or of an operation involving an invalid checked
659 * integer
661 bool isValid() const
663 return mIsValid;
666 template<typename U>
667 friend CheckedInt<U> operator +(const CheckedInt<U>& lhs,
668 const CheckedInt<U>& rhs);
669 template<typename U>
670 CheckedInt& operator +=(U rhs);
672 template<typename U>
673 friend CheckedInt<U> operator -(const CheckedInt<U>& lhs,
674 const CheckedInt<U>& rhs);
675 template<typename U>
676 CheckedInt& operator -=(U rhs);
678 template<typename U>
679 friend CheckedInt<U> operator *(const CheckedInt<U>& lhs,
680 const CheckedInt<U>& rhs);
681 template<typename U>
682 CheckedInt& operator *=(U rhs);
684 template<typename U>
685 friend CheckedInt<U> operator /(const CheckedInt<U>& lhs,
686 const CheckedInt<U>& rhs);
687 template<typename U>
688 CheckedInt& operator /=(U rhs);
690 template<typename U>
691 friend CheckedInt<U> operator %(const CheckedInt<U>& lhs,
692 const CheckedInt<U>& rhs);
693 template<typename U>
694 CheckedInt& operator %=(U rhs);
696 CheckedInt operator -() const
698 return detail::NegateImpl<T>::negate(*this);
702 * @returns true if the left and right hand sides are valid
703 * and have the same value.
705 * Note that these semantics are the reason why we don't offer
706 * a operator!=. Indeed, we'd want to have a!=b be equivalent to !(a==b)
707 * but that would mean that whenever a or b is invalid, a!=b
708 * is always true, which would be very confusing.
710 * For similar reasons, operators <, >, <=, >= would be very tricky to
711 * specify, so we just avoid offering them.
713 * Notice that these == semantics are made more reasonable by these facts:
714 * 1. a==b implies equality at the raw data level
715 * (the converse is false, as a==b is never true among invalids)
716 * 2. This is similar to the behavior of IEEE floats, where a==b
717 * means that a and b have the same value *and* neither is NaN.
719 bool operator ==(const CheckedInt& other) const
721 return mIsValid && other.mIsValid && mValue == other.mValue;
724 /** prefix ++ */
725 CheckedInt& operator++()
727 *this += 1;
728 return *this;
731 /** postfix ++ */
732 CheckedInt operator++(int)
734 CheckedInt tmp = *this;
735 *this += 1;
736 return tmp;
739 /** prefix -- */
740 CheckedInt& operator--()
742 *this -= 1;
743 return *this;
746 /** postfix -- */
747 CheckedInt operator--(int)
749 CheckedInt tmp = *this;
750 *this -= 1;
751 return tmp;
754 private:
756 * The !=, <, <=, >, >= operators are disabled:
757 * see the comment on operator==.
759 template<typename U>
760 bool operator !=(U other) const MOZ_DELETE;
761 template<typename U>
762 bool operator <(U other) const MOZ_DELETE;
763 template<typename U>
764 bool operator <=(U other) const MOZ_DELETE;
765 template<typename U>
766 bool operator >(U other) const MOZ_DELETE;
767 template<typename U>
768 bool operator >=(U other) const MOZ_DELETE;
771 #define MOZ_CHECKEDINT_BASIC_BINARY_OPERATOR(NAME, OP) \
772 template<typename T> \
773 inline CheckedInt<T> operator OP(const CheckedInt<T> &lhs, \
774 const CheckedInt<T> &rhs) \
776 if (!detail::Is##NAME##Valid(lhs.mValue, rhs.mValue)) \
777 return CheckedInt<T>(0, false); \
779 return CheckedInt<T>(lhs.mValue OP rhs.mValue, \
780 lhs.mIsValid && rhs.mIsValid); \
783 MOZ_CHECKEDINT_BASIC_BINARY_OPERATOR(Add, +)
784 MOZ_CHECKEDINT_BASIC_BINARY_OPERATOR(Sub, -)
785 MOZ_CHECKEDINT_BASIC_BINARY_OPERATOR(Mul, *)
786 MOZ_CHECKEDINT_BASIC_BINARY_OPERATOR(Div, /)
787 MOZ_CHECKEDINT_BASIC_BINARY_OPERATOR(Mod, %)
789 #undef MOZ_CHECKEDINT_BASIC_BINARY_OPERATOR
791 // Implement castToCheckedInt<T>(x), making sure that
792 // - it allows x to be either a CheckedInt<T> or any integer type
793 // that can be casted to T
794 // - if x is already a CheckedInt<T>, we just return a reference to it,
795 // instead of copying it (optimization)
797 namespace detail {
799 template<typename T, typename U>
800 struct CastToCheckedIntImpl
802 typedef CheckedInt<T> ReturnType;
803 static CheckedInt<T> run(U u) { return u; }
806 template<typename T>
807 struct CastToCheckedIntImpl<T, CheckedInt<T> >
809 typedef const CheckedInt<T>& ReturnType;
810 static const CheckedInt<T>& run(const CheckedInt<T>& u) { return u; }
813 } // namespace detail
815 template<typename T, typename U>
816 inline typename detail::CastToCheckedIntImpl<T, U>::ReturnType
817 castToCheckedInt(U u)
819 static_assert(detail::IsSupported<T>::value &&
820 detail::IsSupported<U>::value,
821 "This type is not supported by CheckedInt");
822 return detail::CastToCheckedIntImpl<T, U>::run(u);
825 #define MOZ_CHECKEDINT_CONVENIENCE_BINARY_OPERATORS(OP, COMPOUND_OP) \
826 template<typename T> \
827 template<typename U> \
828 CheckedInt<T>& CheckedInt<T>::operator COMPOUND_OP(U rhs) \
830 *this = *this OP castToCheckedInt<T>(rhs); \
831 return *this; \
833 template<typename T, typename U> \
834 inline CheckedInt<T> operator OP(const CheckedInt<T> &lhs, U rhs) \
836 return lhs OP castToCheckedInt<T>(rhs); \
838 template<typename T, typename U> \
839 inline CheckedInt<T> operator OP(U lhs, const CheckedInt<T> &rhs) \
841 return castToCheckedInt<T>(lhs) OP rhs; \
844 MOZ_CHECKEDINT_CONVENIENCE_BINARY_OPERATORS(+, +=)
845 MOZ_CHECKEDINT_CONVENIENCE_BINARY_OPERATORS(*, *=)
846 MOZ_CHECKEDINT_CONVENIENCE_BINARY_OPERATORS(-, -=)
847 MOZ_CHECKEDINT_CONVENIENCE_BINARY_OPERATORS(/, /=)
848 MOZ_CHECKEDINT_CONVENIENCE_BINARY_OPERATORS(%, %=)
850 #undef MOZ_CHECKEDINT_CONVENIENCE_BINARY_OPERATORS
852 template<typename T, typename U>
853 inline bool
854 operator ==(const CheckedInt<T> &lhs, U rhs)
856 return lhs == castToCheckedInt<T>(rhs);
859 template<typename T, typename U>
860 inline bool
861 operator ==(U lhs, const CheckedInt<T> &rhs)
863 return castToCheckedInt<T>(lhs) == rhs;
866 // Convenience typedefs.
867 typedef CheckedInt<int8_t> CheckedInt8;
868 typedef CheckedInt<uint8_t> CheckedUint8;
869 typedef CheckedInt<int16_t> CheckedInt16;
870 typedef CheckedInt<uint16_t> CheckedUint16;
871 typedef CheckedInt<int32_t> CheckedInt32;
872 typedef CheckedInt<uint32_t> CheckedUint32;
873 typedef CheckedInt<int64_t> CheckedInt64;
874 typedef CheckedInt<uint64_t> CheckedUint64;
876 } // namespace mozilla
878 #endif /* mozilla_CheckedInt_h */