Bug 1507750 - Compare the flexbox state for any changes before updating on reflows...
[gecko.git] / mfbt / CheckedInt.h
blobf78b1504e992de7aee67ce8d3073f4b641e5543e
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 /* Provides checked integers, detecting integer overflow and divide-by-0. */
9 #ifndef mozilla_CheckedInt_h
10 #define mozilla_CheckedInt_h
12 #include <stdint.h>
13 #include "mozilla/Assertions.h"
14 #include "mozilla/Attributes.h"
15 #include "mozilla/IntegerTypeTraits.h"
17 // Probe for builtin math overflow support. Disabled for 32-bit builds for now
18 // since "gcc -m32" claims to support these but its implementation is buggy.
19 // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=82274
20 #if defined(HAVE_64BIT_BUILD)
21 #if defined(__has_builtin)
22 #define MOZ_HAS_BUILTIN_OP_OVERFLOW (__has_builtin(__builtin_add_overflow))
23 #elif defined(__GNUC__)
24 // (clang also defines __GNUC__ but it supports __has_builtin since at least
25 // v3.1 (released in 2012) so it won't get here.)
26 #define MOZ_HAS_BUILTIN_OP_OVERFLOW (__GNUC__ >= 5)
27 #else
28 #define MOZ_HAS_BUILTIN_OP_OVERFLOW (0)
29 #endif
30 #else
31 #define MOZ_HAS_BUILTIN_OP_OVERFLOW (0)
32 #endif
34 namespace mozilla {
36 template<typename T> class CheckedInt;
38 namespace detail {
41 * Step 1: manually record supported types
43 * What's nontrivial here is that there are different families of integer
44 * types: basic integer types and stdint types. It is merrily undefined which
45 * types from one family may be just typedefs for a type from another family.
47 * For example, on GCC 4.6, aside from the basic integer types, the only other
48 * type that isn't just a typedef for some of them, is int8_t.
51 struct UnsupportedType {};
53 template<typename IntegerType>
54 struct IsSupportedPass2
56 static const bool value = false;
59 template<typename IntegerType>
60 struct IsSupported
62 static const bool value = IsSupportedPass2<IntegerType>::value;
65 template<>
66 struct IsSupported<int8_t>
67 { static const bool value = true; };
69 template<>
70 struct IsSupported<uint8_t>
71 { static const bool value = true; };
73 template<>
74 struct IsSupported<int16_t>
75 { static const bool value = true; };
77 template<>
78 struct IsSupported<uint16_t>
79 { static const bool value = true; };
81 template<>
82 struct IsSupported<int32_t>
83 { static const bool value = true; };
85 template<>
86 struct IsSupported<uint32_t>
87 { static const bool value = true; };
89 template<>
90 struct IsSupported<int64_t>
91 { static const bool value = true; };
93 template<>
94 struct IsSupported<uint64_t>
95 { static const bool value = true; };
98 template<>
99 struct IsSupportedPass2<char>
100 { static const bool value = true; };
102 template<>
103 struct IsSupportedPass2<signed char>
104 { static const bool value = true; };
106 template<>
107 struct IsSupportedPass2<unsigned char>
108 { static const bool value = true; };
110 template<>
111 struct IsSupportedPass2<short>
112 { static const bool value = true; };
114 template<>
115 struct IsSupportedPass2<unsigned short>
116 { static const bool value = true; };
118 template<>
119 struct IsSupportedPass2<int>
120 { static const bool value = true; };
122 template<>
123 struct IsSupportedPass2<unsigned int>
124 { static const bool value = true; };
126 template<>
127 struct IsSupportedPass2<long>
128 { static const bool value = true; };
130 template<>
131 struct IsSupportedPass2<unsigned long>
132 { static const bool value = true; };
134 template<>
135 struct IsSupportedPass2<long long>
136 { static const bool value = true; };
138 template<>
139 struct IsSupportedPass2<unsigned long long>
140 { static const bool value = true; };
143 * Step 2: Implement the actual validity checks.
145 * Ideas taken from IntegerLib, code different.
148 template<typename IntegerType, size_t Size = sizeof(IntegerType)>
149 struct TwiceBiggerType
151 typedef typename detail::StdintTypeForSizeAndSignedness<
152 sizeof(IntegerType) * 2,
153 IsSigned<IntegerType>::value
154 >::Type Type;
157 template<typename IntegerType>
158 struct TwiceBiggerType<IntegerType, 8>
160 typedef UnsupportedType Type;
163 template<typename T>
164 inline bool
165 HasSignBit(T aX)
167 // In C++, right bit shifts on negative values is undefined by the standard.
168 // Notice that signed-to-unsigned conversions are always well-defined in the
169 // standard, as the value congruent modulo 2**n as expected. By contrast,
170 // unsigned-to-signed is only well-defined if the value is representable.
171 return bool(typename MakeUnsigned<T>::Type(aX) >>
172 PositionOfSignBit<T>::value);
175 // Bitwise ops may return a larger type, so it's good to use this inline
176 // helper guaranteeing that the result is really of type T.
177 template<typename T>
178 inline T
179 BinaryComplement(T aX)
181 return ~aX;
184 template<typename T,
185 typename U,
186 bool IsTSigned = IsSigned<T>::value,
187 bool IsUSigned = IsSigned<U>::value>
188 struct DoesRangeContainRange
192 template<typename T, typename U, bool Signedness>
193 struct DoesRangeContainRange<T, U, Signedness, Signedness>
195 static const bool value = sizeof(T) >= sizeof(U);
198 template<typename T, typename U>
199 struct DoesRangeContainRange<T, U, true, false>
201 static const bool value = sizeof(T) > sizeof(U);
204 template<typename T, typename U>
205 struct DoesRangeContainRange<T, U, false, true>
207 static const bool value = false;
210 template<typename T,
211 typename U,
212 bool IsTSigned = IsSigned<T>::value,
213 bool IsUSigned = IsSigned<U>::value,
214 bool DoesTRangeContainURange = DoesRangeContainRange<T, U>::value>
215 struct IsInRangeImpl {};
217 template<typename T, typename U, bool IsTSigned, bool IsUSigned>
218 struct IsInRangeImpl<T, U, IsTSigned, IsUSigned, true>
220 static bool constexpr run(U)
222 return true;
226 template<typename T, typename U>
227 struct IsInRangeImpl<T, U, true, true, false>
229 static bool constexpr run(U aX)
231 return aX <= MaxValue<T>::value && aX >= MinValue<T>::value;
235 template<typename T, typename U>
236 struct IsInRangeImpl<T, U, false, false, false>
238 static bool constexpr run(U aX)
240 return aX <= MaxValue<T>::value;
244 template<typename T, typename U>
245 struct IsInRangeImpl<T, U, true, false, false>
247 static bool constexpr run(U aX)
249 return sizeof(T) > sizeof(U) || aX <= U(MaxValue<T>::value);
253 template<typename T, typename U>
254 struct IsInRangeImpl<T, U, false, true, false>
256 static bool constexpr run(U aX)
258 return sizeof(T) >= sizeof(U)
259 ? aX >= 0
260 : aX >= 0 && aX <= U(MaxValue<T>::value);
264 template<typename T, typename U>
265 inline constexpr bool
266 IsInRange(U aX)
268 return IsInRangeImpl<T, U>::run(aX);
271 template<typename T>
272 inline bool
273 IsAddValid(T aX, T aY)
275 #if MOZ_HAS_BUILTIN_OP_OVERFLOW
276 T dummy;
277 return !__builtin_add_overflow(aX, aY, &dummy);
278 #else
279 // Addition is valid if the sign of aX+aY is equal to either that of aX or
280 // that of aY. Since the value of aX+aY is undefined if we have a signed
281 // type, we compute it using the unsigned type of the same size. Beware!
282 // These bitwise operations can return a larger integer type, if T was a
283 // small type like int8_t, so we explicitly cast to T.
285 typename MakeUnsigned<T>::Type ux = aX;
286 typename MakeUnsigned<T>::Type uy = aY;
287 typename MakeUnsigned<T>::Type result = ux + uy;
288 return IsSigned<T>::value
289 ? HasSignBit(BinaryComplement(T((result ^ aX) & (result ^ aY))))
290 : BinaryComplement(aX) >= aY;
291 #endif
294 template<typename T>
295 inline bool
296 IsSubValid(T aX, T aY)
298 #if MOZ_HAS_BUILTIN_OP_OVERFLOW
299 T dummy;
300 return !__builtin_sub_overflow(aX, aY, &dummy);
301 #else
302 // Subtraction is valid if either aX and aY have same sign, or aX-aY and aX
303 // have same sign. Since the value of aX-aY is undefined if we have a signed
304 // type, we compute it using the unsigned type of the same size.
305 typename MakeUnsigned<T>::Type ux = aX;
306 typename MakeUnsigned<T>::Type uy = aY;
307 typename MakeUnsigned<T>::Type result = ux - uy;
309 return IsSigned<T>::value
310 ? HasSignBit(BinaryComplement(T((result ^ aX) & (aX ^ aY))))
311 : aX >= aY;
312 #endif
315 template<typename T,
316 bool IsTSigned = IsSigned<T>::value,
317 bool TwiceBiggerTypeIsSupported =
318 IsSupported<typename TwiceBiggerType<T>::Type>::value>
319 struct IsMulValidImpl {};
321 template<typename T, bool IsTSigned>
322 struct IsMulValidImpl<T, IsTSigned, true>
324 static bool run(T aX, T aY)
326 typedef typename TwiceBiggerType<T>::Type TwiceBiggerType;
327 TwiceBiggerType product = TwiceBiggerType(aX) * TwiceBiggerType(aY);
328 return IsInRange<T>(product);
332 template<typename T>
333 struct IsMulValidImpl<T, true, false>
335 static bool run(T aX, T aY)
337 const T max = MaxValue<T>::value;
338 const T min = MinValue<T>::value;
340 if (aX == 0 || aY == 0) {
341 return true;
343 if (aX > 0) {
344 return aY > 0
345 ? aX <= max / aY
346 : aY >= min / aX;
349 // If we reach this point, we know that aX < 0.
350 return aY > 0
351 ? aX >= min / aY
352 : aY >= max / aX;
356 template<typename T>
357 struct IsMulValidImpl<T, false, false>
359 static bool run(T aX, T aY)
361 return aY == 0 || aX <= MaxValue<T>::value / aY;
365 template<typename T>
366 inline bool
367 IsMulValid(T aX, T aY)
369 #if MOZ_HAS_BUILTIN_OP_OVERFLOW
370 T dummy;
371 return !__builtin_mul_overflow(aX, aY, &dummy);
372 #else
373 return IsMulValidImpl<T>::run(aX, aY);
374 #endif
377 template<typename T>
378 inline bool
379 IsDivValid(T aX, T aY)
381 // Keep in mind that in the signed case, min/-1 is invalid because
382 // abs(min)>max.
383 return aY != 0 &&
384 !(IsSigned<T>::value && aX == MinValue<T>::value && aY == T(-1));
387 template<typename T, bool IsTSigned = IsSigned<T>::value>
388 struct IsModValidImpl;
390 template<typename T>
391 inline bool
392 IsModValid(T aX, T aY)
394 return IsModValidImpl<T>::run(aX, aY);
398 * Mod is pretty simple.
399 * For now, let's just use the ANSI C definition:
400 * If aX or aY are negative, the results are implementation defined.
401 * Consider these invalid.
402 * Undefined for aY=0.
403 * The result will never exceed either aX or aY.
405 * Checking that aX>=0 is a warning when T is unsigned.
408 template<typename T>
409 struct IsModValidImpl<T, false>
411 static inline bool run(T aX, T aY)
413 return aY >= 1;
417 template<typename T>
418 struct IsModValidImpl<T, true>
420 static inline bool run(T aX, T aY)
422 if (aX < 0) {
423 return false;
425 return aY >= 1;
429 template<typename T, bool IsSigned = IsSigned<T>::value>
430 struct NegateImpl;
432 template<typename T>
433 struct NegateImpl<T, false>
435 static CheckedInt<T> negate(const CheckedInt<T>& aVal)
437 // Handle negation separately for signed/unsigned, for simpler code and to
438 // avoid an MSVC warning negating an unsigned value.
439 return CheckedInt<T>(0, aVal.isValid() && aVal.mValue == 0);
443 template<typename T>
444 struct NegateImpl<T, true>
446 static CheckedInt<T> negate(const CheckedInt<T>& aVal)
448 // Watch out for the min-value, which (with twos-complement) can't be
449 // negated as -min-value is then (max-value + 1).
450 if (!aVal.isValid() || aVal.mValue == MinValue<T>::value) {
451 return CheckedInt<T>(aVal.mValue, false);
453 return CheckedInt<T>(-aVal.mValue, true);
457 } // namespace detail
461 * Step 3: Now define the CheckedInt class.
465 * @class CheckedInt
466 * @brief Integer wrapper class checking for integer overflow and other errors
467 * @param T the integer type to wrap. Can be any type among the following:
468 * - any basic integer type such as |int|
469 * - any stdint type such as |int8_t|
471 * This class implements guarded integer arithmetic. Do a computation, check
472 * that isValid() returns true, you then have a guarantee that no problem, such
473 * as integer overflow, happened during this computation, and you can call
474 * value() to get the plain integer value.
476 * The arithmetic operators in this class are guaranteed not to raise a signal
477 * (e.g. in case of a division by zero).
479 * For example, suppose that you want to implement a function that computes
480 * (aX+aY)/aZ, that doesn't crash if aZ==0, and that reports on error (divide by
481 * zero or integer overflow). You could code it as follows:
482 @code
483 bool computeXPlusYOverZ(int aX, int aY, int aZ, int* aResult)
485 CheckedInt<int> checkedResult = (CheckedInt<int>(aX) + aY) / aZ;
486 if (checkedResult.isValid()) {
487 *aResult = checkedResult.value();
488 return true;
489 } else {
490 return false;
493 @endcode
495 * Implicit conversion from plain integers to checked integers is allowed. The
496 * plain integer is checked to be in range before being casted to the
497 * destination type. This means that the following lines all compile, and the
498 * resulting CheckedInts are correctly detected as valid or invalid:
499 * @code
500 // 1 is of type int, is found to be in range for uint8_t, x is valid
501 CheckedInt<uint8_t> x(1);
502 // -1 is of type int, is found not to be in range for uint8_t, x is invalid
503 CheckedInt<uint8_t> x(-1);
504 // -1 is of type int, is found to be in range for int8_t, x is valid
505 CheckedInt<int8_t> x(-1);
506 // 1000 is of type int16_t, is found not to be in range for int8_t,
507 // x is invalid
508 CheckedInt<int8_t> x(int16_t(1000));
509 // 3123456789 is of type uint32_t, is found not to be in range for int32_t,
510 // x is invalid
511 CheckedInt<int32_t> x(uint32_t(3123456789));
512 * @endcode
513 * Implicit conversion from
514 * checked integers to plain integers is not allowed. As shown in the
515 * above example, to get the value of a checked integer as a normal integer,
516 * call value().
518 * Arithmetic operations between checked and plain integers is allowed; the
519 * result type is the type of the checked integer.
521 * Checked integers of different types cannot be used in the same arithmetic
522 * expression.
524 * There are convenience typedefs for all stdint types, of the following form
525 * (these are just 2 examples):
526 @code
527 typedef CheckedInt<int32_t> CheckedInt32;
528 typedef CheckedInt<uint16_t> CheckedUint16;
529 @endcode
531 template<typename T>
532 class CheckedInt
534 protected:
535 T mValue;
536 bool mIsValid;
538 template<typename U>
539 CheckedInt(U aValue, bool aIsValid) : mValue(aValue), mIsValid(aIsValid)
541 static_assert(detail::IsSupported<T>::value &&
542 detail::IsSupported<U>::value,
543 "This type is not supported by CheckedInt");
546 friend struct detail::NegateImpl<T>;
548 public:
550 * Constructs a checked integer with given @a value. The checked integer is
551 * initialized as valid or invalid depending on whether the @a value
552 * is in range.
554 * This constructor is not explicit. Instead, the type of its argument is a
555 * separate template parameter, ensuring that no conversion is performed
556 * before this constructor is actually called. As explained in the above
557 * documentation for class CheckedInt, this constructor checks that its
558 * argument is valid.
560 template<typename U>
561 MOZ_IMPLICIT MOZ_NO_ARITHMETIC_EXPR_IN_ARGUMENT constexpr CheckedInt(U aValue)
562 : mValue(T(aValue)),
563 mIsValid(detail::IsInRange<T>(aValue))
565 static_assert(detail::IsSupported<T>::value &&
566 detail::IsSupported<U>::value,
567 "This type is not supported by CheckedInt");
570 template<typename U>
571 friend class CheckedInt;
573 template<typename U>
574 CheckedInt<U> toChecked() const
576 CheckedInt<U> ret(mValue);
577 ret.mIsValid = ret.mIsValid && mIsValid;
578 return ret;
581 /** Constructs a valid checked integer with initial value 0 */
582 constexpr CheckedInt() : mValue(0), mIsValid(true)
584 static_assert(detail::IsSupported<T>::value,
585 "This type is not supported by CheckedInt");
588 /** @returns the actual value */
589 T value() const
591 MOZ_ASSERT(mIsValid, "Invalid checked integer (division by zero or integer overflow)");
592 return mValue;
596 * @returns true if the checked integer is valid, i.e. is not the result
597 * of an invalid operation or of an operation involving an invalid checked
598 * integer
600 bool isValid() const
602 return mIsValid;
605 template<typename U>
606 friend CheckedInt<U> operator +(const CheckedInt<U>& aLhs,
607 const CheckedInt<U>& aRhs);
608 template<typename U>
609 CheckedInt& operator +=(U aRhs);
610 CheckedInt& operator +=(const CheckedInt<T>& aRhs);
612 template<typename U>
613 friend CheckedInt<U> operator -(const CheckedInt<U>& aLhs,
614 const CheckedInt<U>& aRhs);
615 template<typename U>
616 CheckedInt& operator -=(U aRhs);
617 CheckedInt& operator -=(const CheckedInt<T>& aRhs);
619 template<typename U>
620 friend CheckedInt<U> operator *(const CheckedInt<U>& aLhs,
621 const CheckedInt<U>& aRhs);
622 template<typename U>
623 CheckedInt& operator *=(U aRhs);
624 CheckedInt& operator *=(const CheckedInt<T>& aRhs);
626 template<typename U>
627 friend CheckedInt<U> operator /(const CheckedInt<U>& aLhs,
628 const CheckedInt<U>& aRhs);
629 template<typename U>
630 CheckedInt& operator /=(U aRhs);
631 CheckedInt& operator /=(const CheckedInt<T>& aRhs);
633 template<typename U>
634 friend CheckedInt<U> operator %(const CheckedInt<U>& aLhs,
635 const CheckedInt<U>& aRhs);
636 template<typename U>
637 CheckedInt& operator %=(U aRhs);
638 CheckedInt& operator %=(const CheckedInt<T>& aRhs);
640 CheckedInt operator -() const
642 return detail::NegateImpl<T>::negate(*this);
646 * @returns true if the left and right hand sides are valid
647 * and have the same value.
649 * Note that these semantics are the reason why we don't offer
650 * a operator!=. Indeed, we'd want to have a!=b be equivalent to !(a==b)
651 * but that would mean that whenever a or b is invalid, a!=b
652 * is always true, which would be very confusing.
654 * For similar reasons, operators <, >, <=, >= would be very tricky to
655 * specify, so we just avoid offering them.
657 * Notice that these == semantics are made more reasonable by these facts:
658 * 1. a==b implies equality at the raw data level
659 * (the converse is false, as a==b is never true among invalids)
660 * 2. This is similar to the behavior of IEEE floats, where a==b
661 * means that a and b have the same value *and* neither is NaN.
663 bool operator ==(const CheckedInt& aOther) const
665 return mIsValid && aOther.mIsValid && mValue == aOther.mValue;
668 /** prefix ++ */
669 CheckedInt& operator++()
671 *this += 1;
672 return *this;
675 /** postfix ++ */
676 CheckedInt operator++(int)
678 CheckedInt tmp = *this;
679 *this += 1;
680 return tmp;
683 /** prefix -- */
684 CheckedInt& operator--()
686 *this -= 1;
687 return *this;
690 /** postfix -- */
691 CheckedInt operator--(int)
693 CheckedInt tmp = *this;
694 *this -= 1;
695 return tmp;
698 private:
700 * The !=, <, <=, >, >= operators are disabled:
701 * see the comment on operator==.
703 template<typename U> bool operator !=(U aOther) const = delete;
704 template<typename U> bool operator < (U aOther) const = delete;
705 template<typename U> bool operator <=(U aOther) const = delete;
706 template<typename U> bool operator > (U aOther) const = delete;
707 template<typename U> bool operator >=(U aOther) const = delete;
710 #define MOZ_CHECKEDINT_BASIC_BINARY_OPERATOR(NAME, OP) \
711 template<typename T> \
712 inline CheckedInt<T> \
713 operator OP(const CheckedInt<T>& aLhs, const CheckedInt<T>& aRhs) \
715 if (!detail::Is##NAME##Valid(aLhs.mValue, aRhs.mValue)) { \
716 return CheckedInt<T>(0, false); \
718 return CheckedInt<T>(aLhs.mValue OP aRhs.mValue, \
719 aLhs.mIsValid && aRhs.mIsValid); \
722 #if MOZ_HAS_BUILTIN_OP_OVERFLOW
723 #define MOZ_CHECKEDINT_BASIC_BINARY_OPERATOR2(NAME, OP, FUN) \
724 template<typename T> \
725 inline CheckedInt<T> \
726 operator OP(const CheckedInt<T>& aLhs, const CheckedInt<T>& aRhs) \
728 T result; \
729 if (FUN(aLhs.mValue, aRhs.mValue, &result)) { \
730 return CheckedInt<T>(0, false); \
732 return CheckedInt<T>(result, aLhs.mIsValid && aRhs.mIsValid); \
734 MOZ_CHECKEDINT_BASIC_BINARY_OPERATOR2(Add, +, __builtin_add_overflow)
735 MOZ_CHECKEDINT_BASIC_BINARY_OPERATOR2(Sub, -, __builtin_sub_overflow)
736 MOZ_CHECKEDINT_BASIC_BINARY_OPERATOR2(Mul, *, __builtin_mul_overflow)
737 #undef MOZ_CHECKEDINT_BASIC_BINARY_OPERATOR2
738 #else
739 MOZ_CHECKEDINT_BASIC_BINARY_OPERATOR(Add, +)
740 MOZ_CHECKEDINT_BASIC_BINARY_OPERATOR(Sub, -)
741 MOZ_CHECKEDINT_BASIC_BINARY_OPERATOR(Mul, *)
742 #endif
744 MOZ_CHECKEDINT_BASIC_BINARY_OPERATOR(Div, /)
745 MOZ_CHECKEDINT_BASIC_BINARY_OPERATOR(Mod, %)
746 #undef MOZ_CHECKEDINT_BASIC_BINARY_OPERATOR
748 // Implement castToCheckedInt<T>(x), making sure that
749 // - it allows x to be either a CheckedInt<T> or any integer type
750 // that can be casted to T
751 // - if x is already a CheckedInt<T>, we just return a reference to it,
752 // instead of copying it (optimization)
754 namespace detail {
756 template<typename T, typename U>
757 struct CastToCheckedIntImpl
759 typedef CheckedInt<T> ReturnType;
760 static CheckedInt<T> run(U aU) { return aU; }
763 template<typename T>
764 struct CastToCheckedIntImpl<T, CheckedInt<T> >
766 typedef const CheckedInt<T>& ReturnType;
767 static const CheckedInt<T>& run(const CheckedInt<T>& aU) { return aU; }
770 } // namespace detail
772 template<typename T, typename U>
773 inline typename detail::CastToCheckedIntImpl<T, U>::ReturnType
774 castToCheckedInt(U aU)
776 static_assert(detail::IsSupported<T>::value &&
777 detail::IsSupported<U>::value,
778 "This type is not supported by CheckedInt");
779 return detail::CastToCheckedIntImpl<T, U>::run(aU);
782 #define MOZ_CHECKEDINT_CONVENIENCE_BINARY_OPERATORS(OP, COMPOUND_OP) \
783 template<typename T> \
784 template<typename U> \
785 CheckedInt<T>& CheckedInt<T>::operator COMPOUND_OP(U aRhs) \
787 *this = *this OP castToCheckedInt<T>(aRhs); \
788 return *this; \
790 template<typename T> \
791 CheckedInt<T>& CheckedInt<T>::operator COMPOUND_OP(const CheckedInt<T>& aRhs) \
793 *this = *this OP aRhs; \
794 return *this; \
796 template<typename T, typename U> \
797 inline CheckedInt<T> operator OP(const CheckedInt<T>& aLhs, U aRhs) \
799 return aLhs OP castToCheckedInt<T>(aRhs); \
801 template<typename T, typename U> \
802 inline CheckedInt<T> operator OP(U aLhs, const CheckedInt<T>& aRhs) \
804 return castToCheckedInt<T>(aLhs) OP aRhs; \
807 MOZ_CHECKEDINT_CONVENIENCE_BINARY_OPERATORS(+, +=)
808 MOZ_CHECKEDINT_CONVENIENCE_BINARY_OPERATORS(*, *=)
809 MOZ_CHECKEDINT_CONVENIENCE_BINARY_OPERATORS(-, -=)
810 MOZ_CHECKEDINT_CONVENIENCE_BINARY_OPERATORS(/, /=)
811 MOZ_CHECKEDINT_CONVENIENCE_BINARY_OPERATORS(%, %=)
813 #undef MOZ_CHECKEDINT_CONVENIENCE_BINARY_OPERATORS
815 template<typename T, typename U>
816 inline bool
817 operator ==(const CheckedInt<T>& aLhs, U aRhs)
819 return aLhs == castToCheckedInt<T>(aRhs);
822 template<typename T, typename U>
823 inline bool
824 operator ==(U aLhs, const CheckedInt<T>& aRhs)
826 return castToCheckedInt<T>(aLhs) == aRhs;
829 // Convenience typedefs.
830 typedef CheckedInt<int8_t> CheckedInt8;
831 typedef CheckedInt<uint8_t> CheckedUint8;
832 typedef CheckedInt<int16_t> CheckedInt16;
833 typedef CheckedInt<uint16_t> CheckedUint16;
834 typedef CheckedInt<int32_t> CheckedInt32;
835 typedef CheckedInt<uint32_t> CheckedUint32;
836 typedef CheckedInt<int64_t> CheckedInt64;
837 typedef CheckedInt<uint64_t> CheckedUint64;
839 } // namespace mozilla
841 #endif /* mozilla_CheckedInt_h */