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
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)
28 # define MOZ_HAS_BUILTIN_OP_OVERFLOW (0)
31 # define MOZ_HAS_BUILTIN_OP_OVERFLOW (0)
42 * Step 1: manually record supported types
44 * What's nontrivial here is that there are different families of integer
45 * types: basic integer types and stdint types. It is merrily undefined which
46 * types from one family may be just typedefs for a type from another family.
48 * For example, on GCC 4.6, aside from the basic integer types, the only other
49 * type that isn't just a typedef for some of them, is int8_t.
52 struct UnsupportedType
{};
54 template <typename IntegerType
>
55 struct IsSupportedPass2
{
56 static const bool value
= false;
59 template <typename IntegerType
>
61 static const bool value
= IsSupportedPass2
<IntegerType
>::value
;
65 struct IsSupported
<int8_t> {
66 static const bool value
= true;
70 struct IsSupported
<uint8_t> {
71 static const bool value
= true;
75 struct IsSupported
<int16_t> {
76 static const bool value
= true;
80 struct IsSupported
<uint16_t> {
81 static const bool value
= true;
85 struct IsSupported
<int32_t> {
86 static const bool value
= true;
90 struct IsSupported
<uint32_t> {
91 static const bool value
= true;
95 struct IsSupported
<int64_t> {
96 static const bool value
= true;
100 struct IsSupported
<uint64_t> {
101 static const bool value
= true;
105 struct IsSupportedPass2
<char> {
106 static const bool value
= true;
110 struct IsSupportedPass2
<signed char> {
111 static const bool value
= true;
115 struct IsSupportedPass2
<unsigned char> {
116 static const bool value
= true;
120 struct IsSupportedPass2
<short> {
121 static const bool value
= true;
125 struct IsSupportedPass2
<unsigned short> {
126 static const bool value
= true;
130 struct IsSupportedPass2
<int> {
131 static const bool value
= true;
135 struct IsSupportedPass2
<unsigned int> {
136 static const bool value
= true;
140 struct IsSupportedPass2
<long> {
141 static const bool value
= true;
145 struct IsSupportedPass2
<unsigned long> {
146 static const bool value
= true;
150 struct IsSupportedPass2
<long long> {
151 static const bool value
= true;
155 struct IsSupportedPass2
<unsigned long long> {
156 static const bool value
= true;
160 * Step 2: Implement the actual validity checks.
162 * Ideas taken from IntegerLib, code different.
165 template <typename IntegerType
, size_t Size
= sizeof(IntegerType
)>
166 struct TwiceBiggerType
{
167 typedef typename
detail::StdintTypeForSizeAndSignedness
<
168 sizeof(IntegerType
) * 2, IsSigned
<IntegerType
>::value
>::Type Type
;
171 template <typename IntegerType
>
172 struct TwiceBiggerType
<IntegerType
, 8> {
173 typedef UnsupportedType Type
;
176 template <typename T
>
177 inline bool HasSignBit(T aX
) {
178 // In C++, right bit shifts on negative values is undefined by the standard.
179 // Notice that signed-to-unsigned conversions are always well-defined in the
180 // standard, as the value congruent modulo 2**n as expected. By contrast,
181 // unsigned-to-signed is only well-defined if the value is representable.
182 return bool(typename MakeUnsigned
<T
>::Type(aX
) >>
183 PositionOfSignBit
<T
>::value
);
186 // Bitwise ops may return a larger type, so it's good to use this inline
187 // helper guaranteeing that the result is really of type T.
188 template <typename T
>
189 inline T
BinaryComplement(T aX
) {
193 template <typename T
, typename U
, bool IsTSigned
= IsSigned
<T
>::value
,
194 bool IsUSigned
= IsSigned
<U
>::value
>
195 struct DoesRangeContainRange
{};
197 template <typename T
, typename U
, bool Signedness
>
198 struct DoesRangeContainRange
<T
, U
, Signedness
, Signedness
> {
199 static const bool value
= sizeof(T
) >= sizeof(U
);
202 template <typename T
, typename U
>
203 struct DoesRangeContainRange
<T
, U
, true, false> {
204 static const bool value
= sizeof(T
) > sizeof(U
);
207 template <typename T
, typename U
>
208 struct DoesRangeContainRange
<T
, U
, false, true> {
209 static const bool value
= false;
212 template <typename T
, typename U
, 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> {
219 static bool constexpr run(U
) { return true; }
222 template <typename T
, typename U
>
223 struct IsInRangeImpl
<T
, U
, true, true, false> {
224 static bool constexpr run(U aX
) {
225 return aX
<= MaxValue
<T
>::value
&& aX
>= MinValue
<T
>::value
;
229 template <typename T
, typename U
>
230 struct IsInRangeImpl
<T
, U
, false, false, false> {
231 static bool constexpr run(U aX
) { return aX
<= MaxValue
<T
>::value
; }
234 template <typename T
, typename U
>
235 struct IsInRangeImpl
<T
, U
, true, false, false> {
236 static bool constexpr run(U aX
) {
237 return sizeof(T
) > sizeof(U
) || aX
<= U(MaxValue
<T
>::value
);
241 template <typename T
, typename U
>
242 struct IsInRangeImpl
<T
, U
, false, true, false> {
243 static bool constexpr run(U aX
) {
244 return sizeof(T
) >= sizeof(U
) ? aX
>= 0
245 : aX
>= 0 && aX
<= U(MaxValue
<T
>::value
);
249 template <typename T
, typename U
>
250 inline constexpr bool IsInRange(U aX
) {
251 return IsInRangeImpl
<T
, U
>::run(aX
);
254 template <typename T
>
255 inline bool IsAddValid(T aX
, T aY
) {
256 #if MOZ_HAS_BUILTIN_OP_OVERFLOW
258 return !__builtin_add_overflow(aX
, aY
, &dummy
);
260 // Addition is valid if the sign of aX+aY is equal to either that of aX or
261 // that of aY. Since the value of aX+aY is undefined if we have a signed
262 // type, we compute it using the unsigned type of the same size. Beware!
263 // These bitwise operations can return a larger integer type, if T was a
264 // small type like int8_t, so we explicitly cast to T.
266 typename MakeUnsigned
<T
>::Type ux
= aX
;
267 typename MakeUnsigned
<T
>::Type uy
= aY
;
268 typename MakeUnsigned
<T
>::Type result
= ux
+ uy
;
269 return IsSigned
<T
>::value
270 ? HasSignBit(BinaryComplement(T((result
^ aX
) & (result
^ aY
))))
271 : BinaryComplement(aX
) >= aY
;
275 template <typename T
>
276 inline bool IsSubValid(T aX
, T aY
) {
277 #if MOZ_HAS_BUILTIN_OP_OVERFLOW
279 return !__builtin_sub_overflow(aX
, aY
, &dummy
);
281 // Subtraction is valid if either aX and aY have same sign, or aX-aY and aX
282 // have same sign. Since the value of aX-aY is undefined if we have a signed
283 // type, we compute it using the unsigned type of the same size.
284 typename MakeUnsigned
<T
>::Type ux
= aX
;
285 typename MakeUnsigned
<T
>::Type uy
= aY
;
286 typename MakeUnsigned
<T
>::Type result
= ux
- uy
;
288 return IsSigned
<T
>::value
289 ? HasSignBit(BinaryComplement(T((result
^ aX
) & (aX
^ aY
))))
294 template <typename T
, bool IsTSigned
= IsSigned
<T
>::value
,
295 bool TwiceBiggerTypeIsSupported
=
296 IsSupported
<typename TwiceBiggerType
<T
>::Type
>::value
>
297 struct IsMulValidImpl
{};
299 template <typename T
, bool IsTSigned
>
300 struct IsMulValidImpl
<T
, IsTSigned
, true> {
301 static bool run(T aX
, T aY
) {
302 typedef typename TwiceBiggerType
<T
>::Type TwiceBiggerType
;
303 TwiceBiggerType product
= TwiceBiggerType(aX
) * TwiceBiggerType(aY
);
304 return IsInRange
<T
>(product
);
308 template <typename T
>
309 struct IsMulValidImpl
<T
, true, false> {
310 static bool run(T aX
, T aY
) {
311 const T max
= MaxValue
<T
>::value
;
312 const T min
= MinValue
<T
>::value
;
314 if (aX
== 0 || aY
== 0) {
318 return aY
> 0 ? aX
<= max
/ aY
: aY
>= min
/ aX
;
321 // If we reach this point, we know that aX < 0.
322 return aY
> 0 ? aX
>= min
/ aY
: aY
>= max
/ aX
;
326 template <typename T
>
327 struct IsMulValidImpl
<T
, false, false> {
328 static bool run(T aX
, T aY
) {
329 return aY
== 0 || aX
<= MaxValue
<T
>::value
/ aY
;
333 template <typename T
>
334 inline bool IsMulValid(T aX
, T aY
) {
335 #if MOZ_HAS_BUILTIN_OP_OVERFLOW
337 return !__builtin_mul_overflow(aX
, aY
, &dummy
);
339 return IsMulValidImpl
<T
>::run(aX
, aY
);
343 template <typename T
>
344 inline bool IsDivValid(T aX
, T aY
) {
345 // Keep in mind that in the signed case, min/-1 is invalid because
348 !(IsSigned
<T
>::value
&& aX
== MinValue
<T
>::value
&& aY
== T(-1));
351 template <typename T
, bool IsTSigned
= IsSigned
<T
>::value
>
352 struct IsModValidImpl
;
354 template <typename T
>
355 inline bool IsModValid(T aX
, T aY
) {
356 return IsModValidImpl
<T
>::run(aX
, aY
);
360 * Mod is pretty simple.
361 * For now, let's just use the ANSI C definition:
362 * If aX or aY are negative, the results are implementation defined.
363 * Consider these invalid.
364 * Undefined for aY=0.
365 * The result will never exceed either aX or aY.
367 * Checking that aX>=0 is a warning when T is unsigned.
370 template <typename T
>
371 struct IsModValidImpl
<T
, false> {
372 static inline bool run(T aX
, T aY
) { return aY
>= 1; }
375 template <typename T
>
376 struct IsModValidImpl
<T
, true> {
377 static inline bool run(T aX
, T aY
) {
385 template <typename T
, bool IsSigned
= IsSigned
<T
>::value
>
388 template <typename T
>
389 struct NegateImpl
<T
, false> {
390 static CheckedInt
<T
> negate(const CheckedInt
<T
>& aVal
) {
391 // Handle negation separately for signed/unsigned, for simpler code and to
392 // avoid an MSVC warning negating an unsigned value.
393 return CheckedInt
<T
>(0, aVal
.isValid() && aVal
.mValue
== 0);
397 template <typename T
>
398 struct NegateImpl
<T
, true> {
399 static CheckedInt
<T
> negate(const CheckedInt
<T
>& aVal
) {
400 // Watch out for the min-value, which (with twos-complement) can't be
401 // negated as -min-value is then (max-value + 1).
402 if (!aVal
.isValid() || aVal
.mValue
== MinValue
<T
>::value
) {
403 return CheckedInt
<T
>(aVal
.mValue
, false);
405 return CheckedInt
<T
>(-aVal
.mValue
, true);
409 } // namespace detail
412 * Step 3: Now define the CheckedInt class.
417 * @brief Integer wrapper class checking for integer overflow and other errors
418 * @param T the integer type to wrap. Can be any type among the following:
419 * - any basic integer type such as |int|
420 * - any stdint type such as |int8_t|
422 * This class implements guarded integer arithmetic. Do a computation, check
423 * that isValid() returns true, you then have a guarantee that no problem, such
424 * as integer overflow, happened during this computation, and you can call
425 * value() to get the plain integer value.
427 * The arithmetic operators in this class are guaranteed not to raise a signal
428 * (e.g. in case of a division by zero).
430 * For example, suppose that you want to implement a function that computes
431 * (aX+aY)/aZ, that doesn't crash if aZ==0, and that reports on error (divide by
432 * zero or integer overflow). You could code it as follows:
434 bool computeXPlusYOverZ(int aX, int aY, int aZ, int* aResult)
436 CheckedInt<int> checkedResult = (CheckedInt<int>(aX) + aY) / aZ;
437 if (checkedResult.isValid()) {
438 *aResult = checkedResult.value();
446 * Implicit conversion from plain integers to checked integers is allowed. The
447 * plain integer is checked to be in range before being casted to the
448 * destination type. This means that the following lines all compile, and the
449 * resulting CheckedInts are correctly detected as valid or invalid:
451 // 1 is of type int, is found to be in range for uint8_t, x is valid
452 CheckedInt<uint8_t> x(1);
453 // -1 is of type int, is found not to be in range for uint8_t, x is invalid
454 CheckedInt<uint8_t> x(-1);
455 // -1 is of type int, is found to be in range for int8_t, x is valid
456 CheckedInt<int8_t> x(-1);
457 // 1000 is of type int16_t, is found not to be in range for int8_t,
459 CheckedInt<int8_t> x(int16_t(1000));
460 // 3123456789 is of type uint32_t, is found not to be in range for int32_t,
462 CheckedInt<int32_t> x(uint32_t(3123456789));
464 * Implicit conversion from
465 * checked integers to plain integers is not allowed. As shown in the
466 * above example, to get the value of a checked integer as a normal integer,
469 * Arithmetic operations between checked and plain integers is allowed; the
470 * result type is the type of the checked integer.
472 * Checked integers of different types cannot be used in the same arithmetic
475 * There are convenience typedefs for all stdint types, of the following form
476 * (these are just 2 examples):
478 typedef CheckedInt<int32_t> CheckedInt32;
479 typedef CheckedInt<uint16_t> CheckedUint16;
482 template <typename T
>
488 template <typename U
>
489 CheckedInt(U aValue
, bool aIsValid
) : mValue(aValue
), mIsValid(aIsValid
) {
491 detail::IsSupported
<T
>::value
&& detail::IsSupported
<U
>::value
,
492 "This type is not supported by CheckedInt");
495 friend struct detail::NegateImpl
<T
>;
499 * Constructs a checked integer with given @a value. The checked integer is
500 * initialized as valid or invalid depending on whether the @a value
503 * This constructor is not explicit. Instead, the type of its argument is a
504 * separate template parameter, ensuring that no conversion is performed
505 * before this constructor is actually called. As explained in the above
506 * documentation for class CheckedInt, this constructor checks that its
509 template <typename U
>
510 MOZ_IMPLICIT MOZ_NO_ARITHMETIC_EXPR_IN_ARGUMENT
constexpr CheckedInt(U aValue
)
511 : mValue(T(aValue
)), mIsValid(detail::IsInRange
<T
>(aValue
)) {
513 detail::IsSupported
<T
>::value
&& detail::IsSupported
<U
>::value
,
514 "This type is not supported by CheckedInt");
517 template <typename U
>
518 friend class CheckedInt
;
520 template <typename U
>
521 CheckedInt
<U
> toChecked() const {
522 CheckedInt
<U
> ret(mValue
);
523 ret
.mIsValid
= ret
.mIsValid
&& mIsValid
;
527 /** Constructs a valid checked integer with initial value 0 */
528 constexpr CheckedInt() : mValue(0), mIsValid(true) {
529 static_assert(detail::IsSupported
<T
>::value
,
530 "This type is not supported by CheckedInt");
533 /** @returns the actual value */
535 MOZ_DIAGNOSTIC_ASSERT(
537 "Invalid checked integer (division by zero or integer overflow)");
542 * @returns true if the checked integer is valid, i.e. is not the result
543 * of an invalid operation or of an operation involving an invalid checked
546 bool isValid() const { return mIsValid
; }
548 template <typename U
>
549 friend CheckedInt
<U
> operator+(const CheckedInt
<U
>& aLhs
,
550 const CheckedInt
<U
>& aRhs
);
551 template <typename U
>
552 CheckedInt
& operator+=(U aRhs
);
553 CheckedInt
& operator+=(const CheckedInt
<T
>& aRhs
);
555 template <typename U
>
556 friend CheckedInt
<U
> operator-(const CheckedInt
<U
>& aLhs
,
557 const CheckedInt
<U
>& aRhs
);
558 template <typename U
>
559 CheckedInt
& operator-=(U aRhs
);
560 CheckedInt
& operator-=(const CheckedInt
<T
>& aRhs
);
562 template <typename U
>
563 friend CheckedInt
<U
> operator*(const CheckedInt
<U
>& aLhs
,
564 const CheckedInt
<U
>& aRhs
);
565 template <typename U
>
566 CheckedInt
& operator*=(U aRhs
);
567 CheckedInt
& operator*=(const CheckedInt
<T
>& aRhs
);
569 template <typename U
>
570 friend CheckedInt
<U
> operator/(const CheckedInt
<U
>& aLhs
,
571 const CheckedInt
<U
>& aRhs
);
572 template <typename U
>
573 CheckedInt
& operator/=(U aRhs
);
574 CheckedInt
& operator/=(const CheckedInt
<T
>& aRhs
);
576 template <typename U
>
577 friend CheckedInt
<U
> operator%(const CheckedInt
<U
>& aLhs
,
578 const CheckedInt
<U
>& aRhs
);
579 template <typename U
>
580 CheckedInt
& operator%=(U aRhs
);
581 CheckedInt
& operator%=(const CheckedInt
<T
>& aRhs
);
583 CheckedInt
operator-() const { return detail::NegateImpl
<T
>::negate(*this); }
586 * @returns true if the left and right hand sides are valid
587 * and have the same value.
589 * Note that these semantics are the reason why we don't offer
590 * a operator!=. Indeed, we'd want to have a!=b be equivalent to !(a==b)
591 * but that would mean that whenever a or b is invalid, a!=b
592 * is always true, which would be very confusing.
594 * For similar reasons, operators <, >, <=, >= would be very tricky to
595 * specify, so we just avoid offering them.
597 * Notice that these == semantics are made more reasonable by these facts:
598 * 1. a==b implies equality at the raw data level
599 * (the converse is false, as a==b is never true among invalids)
600 * 2. This is similar to the behavior of IEEE floats, where a==b
601 * means that a and b have the same value *and* neither is NaN.
603 bool operator==(const CheckedInt
& aOther
) const {
604 return mIsValid
&& aOther
.mIsValid
&& mValue
== aOther
.mValue
;
608 CheckedInt
& operator++() {
614 CheckedInt
operator++(int) {
615 CheckedInt tmp
= *this;
621 CheckedInt
& operator--() {
627 CheckedInt
operator--(int) {
628 CheckedInt tmp
= *this;
635 * The !=, <, <=, >, >= operators are disabled:
636 * see the comment on operator==.
638 template <typename U
>
639 bool operator!=(U aOther
) const = delete;
640 template <typename U
>
641 bool operator<(U aOther
) const = delete;
642 template <typename U
>
643 bool operator<=(U aOther
) const = delete;
644 template <typename U
>
645 bool operator>(U aOther
) const = delete;
646 template <typename U
>
647 bool operator>=(U aOther
) const = delete;
650 #define MOZ_CHECKEDINT_BASIC_BINARY_OPERATOR(NAME, OP) \
651 template <typename T> \
652 inline CheckedInt<T> operator OP(const CheckedInt<T>& aLhs, \
653 const CheckedInt<T>& aRhs) { \
654 if (!detail::Is##NAME##Valid(aLhs.mValue, aRhs.mValue)) { \
655 return CheckedInt<T>(0, false); \
657 return CheckedInt<T>(aLhs.mValue OP aRhs.mValue, \
658 aLhs.mIsValid && aRhs.mIsValid); \
661 #if MOZ_HAS_BUILTIN_OP_OVERFLOW
662 # define MOZ_CHECKEDINT_BASIC_BINARY_OPERATOR2(NAME, OP, FUN) \
663 template <typename T> \
664 inline CheckedInt<T> operator OP(const CheckedInt<T>& aLhs, \
665 const CheckedInt<T>& aRhs) { \
667 if (FUN(aLhs.mValue, aRhs.mValue, &result)) { \
668 return CheckedInt<T>(0, false); \
670 return CheckedInt<T>(result, aLhs.mIsValid && aRhs.mIsValid); \
672 MOZ_CHECKEDINT_BASIC_BINARY_OPERATOR2(Add
, +, __builtin_add_overflow
)
673 MOZ_CHECKEDINT_BASIC_BINARY_OPERATOR2(Sub
, -, __builtin_sub_overflow
)
674 MOZ_CHECKEDINT_BASIC_BINARY_OPERATOR2(Mul
, *, __builtin_mul_overflow
)
675 # undef MOZ_CHECKEDINT_BASIC_BINARY_OPERATOR2
677 MOZ_CHECKEDINT_BASIC_BINARY_OPERATOR(Add
, +)
678 MOZ_CHECKEDINT_BASIC_BINARY_OPERATOR(Sub
, -)
679 MOZ_CHECKEDINT_BASIC_BINARY_OPERATOR(Mul
, *)
682 MOZ_CHECKEDINT_BASIC_BINARY_OPERATOR(Div
, /)
683 MOZ_CHECKEDINT_BASIC_BINARY_OPERATOR(Mod
, %)
684 #undef MOZ_CHECKEDINT_BASIC_BINARY_OPERATOR
686 // Implement castToCheckedInt<T>(x), making sure that
687 // - it allows x to be either a CheckedInt<T> or any integer type
688 // that can be casted to T
689 // - if x is already a CheckedInt<T>, we just return a reference to it,
690 // instead of copying it (optimization)
694 template <typename T
, typename U
>
695 struct CastToCheckedIntImpl
{
696 typedef CheckedInt
<T
> ReturnType
;
697 static CheckedInt
<T
> run(U aU
) { return aU
; }
700 template <typename T
>
701 struct CastToCheckedIntImpl
<T
, CheckedInt
<T
> > {
702 typedef const CheckedInt
<T
>& ReturnType
;
703 static const CheckedInt
<T
>& run(const CheckedInt
<T
>& aU
) { return aU
; }
706 } // namespace detail
708 template <typename T
, typename U
>
709 inline typename
detail::CastToCheckedIntImpl
<T
, U
>::ReturnType
castToCheckedInt(
711 static_assert(detail::IsSupported
<T
>::value
&& detail::IsSupported
<U
>::value
,
712 "This type is not supported by CheckedInt");
713 return detail::CastToCheckedIntImpl
<T
, U
>::run(aU
);
716 #define MOZ_CHECKEDINT_CONVENIENCE_BINARY_OPERATORS(OP, COMPOUND_OP) \
717 template <typename T> \
718 template <typename U> \
719 CheckedInt<T>& CheckedInt<T>::operator COMPOUND_OP(U aRhs) { \
720 *this = *this OP castToCheckedInt<T>(aRhs); \
723 template <typename T> \
724 CheckedInt<T>& CheckedInt<T>::operator COMPOUND_OP( \
725 const CheckedInt<T>& aRhs) { \
726 *this = *this OP aRhs; \
729 template <typename T, typename U> \
730 inline CheckedInt<T> operator OP(const CheckedInt<T>& aLhs, U aRhs) { \
731 return aLhs OP castToCheckedInt<T>(aRhs); \
733 template <typename T, typename U> \
734 inline CheckedInt<T> operator OP(U aLhs, const CheckedInt<T>& aRhs) { \
735 return castToCheckedInt<T>(aLhs) OP aRhs; \
738 MOZ_CHECKEDINT_CONVENIENCE_BINARY_OPERATORS(+, +=)
739 MOZ_CHECKEDINT_CONVENIENCE_BINARY_OPERATORS(*, *=)
740 MOZ_CHECKEDINT_CONVENIENCE_BINARY_OPERATORS(-, -=)
741 MOZ_CHECKEDINT_CONVENIENCE_BINARY_OPERATORS(/, /=)
742 MOZ_CHECKEDINT_CONVENIENCE_BINARY_OPERATORS(%, %=)
744 #undef MOZ_CHECKEDINT_CONVENIENCE_BINARY_OPERATORS
746 template <typename T
, typename U
>
747 inline bool operator==(const CheckedInt
<T
>& aLhs
, U aRhs
) {
748 return aLhs
== castToCheckedInt
<T
>(aRhs
);
751 template <typename T
, typename U
>
752 inline bool operator==(U aLhs
, const CheckedInt
<T
>& aRhs
) {
753 return castToCheckedInt
<T
>(aLhs
) == aRhs
;
756 // Convenience typedefs.
757 typedef CheckedInt
<int8_t> CheckedInt8
;
758 typedef CheckedInt
<uint8_t> CheckedUint8
;
759 typedef CheckedInt
<int16_t> CheckedInt16
;
760 typedef CheckedInt
<uint16_t> CheckedUint16
;
761 typedef CheckedInt
<int32_t> CheckedInt32
;
762 typedef CheckedInt
<uint32_t> CheckedUint32
;
763 typedef CheckedInt
<int64_t> CheckedInt64
;
764 typedef CheckedInt
<uint64_t> CheckedUint64
;
766 } // namespace mozilla
768 #endif /* mozilla_CheckedInt_h */