From 75ab2ff4732efa81f75b2776b4bf1e8b77f1e03d Mon Sep 17 00:00:00 2001 From: Jeff Gilbert Date: Fri, 14 Jun 2013 15:19:30 -0700 Subject: [PATCH] Bug 874764 - Add CheckedInt support for operator%. - r=bjacob,waldo --- mfbt/CheckedInt.h | 55 +++++++++++++++++++++++++++++++++-- mfbt/tests/TestCheckedInt.cpp | 32 ++++++++++++++++++++ 2 files changed, 84 insertions(+), 3 deletions(-) diff --git a/mfbt/CheckedInt.h b/mfbt/CheckedInt.h index 1dc80b032bb3..5b5b86d03f89 100644 --- a/mfbt/CheckedInt.h +++ b/mfbt/CheckedInt.h @@ -450,6 +450,44 @@ IsDivValid(T x, T y) !(IsSigned::value && x == MinValue::value && y == T(-1)); } +template::value> +struct IsModValidImpl; + +template +inline bool +IsModValid(T x, T y) +{ + return IsModValidImpl::run(x, y); +} + +/* + * Mod is pretty simple. + * For now, let's just use the ANSI C definition: + * If x or y are negative, the results are implementation defined. + * Consider these invalid. + * Undefined for y=0. + * The result will never exceed either x or y. + * + * Checking that x>=0 is a warning when T is unsigned. + */ + +template +struct IsModValidImpl { + static inline bool run(T x, T y) { + return y >= 1; + } +}; + +template +struct IsModValidImpl { + static inline bool run(T x, T y) { + if (x < 0) + return false; + + return y >= 1; + } +}; + template::value> struct NegateImpl; @@ -619,22 +657,31 @@ class CheckedInt const CheckedInt& rhs); template CheckedInt& operator +=(U rhs); + template friend CheckedInt operator -(const CheckedInt& lhs, - const CheckedInt &rhs); + const CheckedInt& rhs); template CheckedInt& operator -=(U rhs); + template friend CheckedInt operator *(const CheckedInt& lhs, - const CheckedInt &rhs); + const CheckedInt& rhs); template CheckedInt& operator *=(U rhs); + template friend CheckedInt operator /(const CheckedInt& lhs, - const CheckedInt &rhs); + const CheckedInt& rhs); template CheckedInt& operator /=(U rhs); + template + friend CheckedInt operator %(const CheckedInt& lhs, + const CheckedInt& rhs); + template + CheckedInt& operator %=(U rhs); + CheckedInt operator -() const { return detail::NegateImpl::negate(*this); @@ -726,6 +773,7 @@ MOZ_CHECKEDINT_BASIC_BINARY_OPERATOR(Add, +) MOZ_CHECKEDINT_BASIC_BINARY_OPERATOR(Sub, -) MOZ_CHECKEDINT_BASIC_BINARY_OPERATOR(Mul, *) MOZ_CHECKEDINT_BASIC_BINARY_OPERATOR(Div, /) +MOZ_CHECKEDINT_BASIC_BINARY_OPERATOR(Mod, %) #undef MOZ_CHECKEDINT_BASIC_BINARY_OPERATOR @@ -786,6 +834,7 @@ MOZ_CHECKEDINT_CONVENIENCE_BINARY_OPERATORS(+, +=) MOZ_CHECKEDINT_CONVENIENCE_BINARY_OPERATORS(*, *=) MOZ_CHECKEDINT_CONVENIENCE_BINARY_OPERATORS(-, -=) MOZ_CHECKEDINT_CONVENIENCE_BINARY_OPERATORS(/, /=) +MOZ_CHECKEDINT_CONVENIENCE_BINARY_OPERATORS(%, %=) #undef MOZ_CHECKEDINT_CONVENIENCE_BINARY_OPERATORS diff --git a/mfbt/tests/TestCheckedInt.cpp b/mfbt/tests/TestCheckedInt.cpp index f6e0c2830d2a..8e9aa42d8a50 100644 --- a/mfbt/tests/TestCheckedInt.cpp +++ b/mfbt/tests/TestCheckedInt.cpp @@ -190,6 +190,26 @@ void test() VERIFY_IS_INVALID(one - min + min); } + /* Modulo checks */ + VERIFY_IS_INVALID(zero % zero); + VERIFY_IS_INVALID(one % zero); + VERIFY_IS_VALID(zero % one); + VERIFY_IS_VALID(zero % max); + VERIFY_IS_VALID(one % max); + VERIFY_IS_VALID(max % one); + VERIFY_IS_VALID(max % max); + if (isTSigned) { + const CheckedInt minusOne = zero - one; + VERIFY_IS_INVALID(minusOne % minusOne); + VERIFY_IS_INVALID(zero % minusOne); + VERIFY_IS_INVALID(one % minusOne); + VERIFY_IS_INVALID(minusOne % one); + + VERIFY_IS_INVALID(min % min); + VERIFY_IS_INVALID(zero % min); + VERIFY_IS_INVALID(min % one); + } + /* Unary operator- checks */ const CheckedInt negOne = -one; @@ -347,10 +367,15 @@ void test() VERIFY_IS_INVALID(someInvalid / one); VERIFY_IS_INVALID(zero / someInvalid); VERIFY_IS_INVALID(one / someInvalid); + VERIFY_IS_INVALID(someInvalid % zero); + VERIFY_IS_INVALID(someInvalid % one); + VERIFY_IS_INVALID(zero % someInvalid); + VERIFY_IS_INVALID(one % someInvalid); VERIFY_IS_INVALID(someInvalid + someInvalid); VERIFY_IS_INVALID(someInvalid - someInvalid); VERIFY_IS_INVALID(someInvalid * someInvalid); VERIFY_IS_INVALID(someInvalid / someInvalid); + VERIFY_IS_INVALID(someInvalid % someInvalid); /* Check that mixing checked integers with plain integers in expressions is allowed */ @@ -382,6 +407,13 @@ void test() x /= 2; VERIFY(x == two); } + VERIFY(three % 2 == one); + VERIFY(3 % two == one); + { + CheckedInt x = three; + x %= 2; + VERIFY(x == one); + } VERIFY(one == 1); VERIFY(1 == one);