Bug 874764 - Add CheckedInt support for operator%. - r=bjacob,waldo
authorJeff Gilbert <jgilbert@mozilla.com>
Fri, 14 Jun 2013 15:19:30 -0700
changeset 135156 a74b3d43c3af2b8b09437a735e65c0e5bdbf7e4a
parent 135144 46dc449aa545282e11104a0ef8c014f196908122
child 135157 9e0bf0548e486cdfda2f9dd91e56edb733b1a0ba
push id24830
push userryanvm@gmail.com
push dateSun, 16 Jun 2013 01:34:51 +0000
treeherdermozilla-central@36da3cb92193 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbjacob, waldo
bugs874764
milestone24.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 874764 - Add CheckedInt support for operator%. - r=bjacob,waldo
mfbt/CheckedInt.h
mfbt/tests/TestCheckedInt.cpp
--- a/mfbt/CheckedInt.h
+++ b/mfbt/CheckedInt.h
@@ -445,16 +445,54 @@ template<typename T>
 inline bool
 IsDivValid(T x, T y)
 {
   // Keep in mind that in the signed case, min/-1 is invalid because abs(min)>max.
   return y != 0 &&
          !(IsSigned<T>::value && x == MinValue<T>::value && y == T(-1));
 }
 
+template<typename T, bool IsTSigned = IsSigned<T>::value>
+struct IsModValidImpl;
+
+template<typename T>
+inline bool
+IsModValid(T x, T y)
+{
+  return IsModValidImpl<T>::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<typename T>
+struct IsModValidImpl<T, false> {
+  static inline bool run(T x, T y) {
+    return y >= 1;
+  }
+};
+
+template<typename T>
+struct IsModValidImpl<T, true> {
+  static inline bool run(T x, T y) {
+    if (x < 0)
+      return false;
+
+    return y >= 1;
+  }
+};
+
 template<typename T, bool IsSigned = IsSigned<T>::value>
 struct NegateImpl;
 
 template<typename T>
 struct NegateImpl<T, false>
 {
     static CheckedInt<T> negate(const CheckedInt<T>& val)
     {
@@ -614,32 +652,41 @@ class CheckedInt
       return mIsValid;
     }
 
     template<typename U>
     friend CheckedInt<U> operator +(const CheckedInt<U>& lhs,
                                     const CheckedInt<U>& rhs);
     template<typename U>
     CheckedInt& operator +=(U rhs);
+
     template<typename U>
     friend CheckedInt<U> operator -(const CheckedInt<U>& lhs,
-                                    const CheckedInt<U> &rhs);
+                                    const CheckedInt<U>& rhs);
     template<typename U>
     CheckedInt& operator -=(U rhs);
+
     template<typename U>
     friend CheckedInt<U> operator *(const CheckedInt<U>& lhs,
-                                    const CheckedInt<U> &rhs);
+                                    const CheckedInt<U>& rhs);
     template<typename U>
     CheckedInt& operator *=(U rhs);
+
     template<typename U>
     friend CheckedInt<U> operator /(const CheckedInt<U>& lhs,
-                                    const CheckedInt<U> &rhs);
+                                    const CheckedInt<U>& rhs);
     template<typename U>
     CheckedInt& operator /=(U rhs);
 
+    template<typename U>
+    friend CheckedInt<U> operator %(const CheckedInt<U>& lhs,
+                                    const CheckedInt<U>& rhs);
+    template<typename U>
+    CheckedInt& operator %=(U rhs);
+
     CheckedInt operator -() const
     {
       return detail::NegateImpl<T>::negate(*this);
     }
 
     /**
      * @returns true if the left and right hand sides are valid
      * and have the same value.
@@ -721,16 +768,17 @@ inline CheckedInt<T> operator OP(const C
   return CheckedInt<T>(lhs.mValue OP rhs.mValue,                      \
                        lhs.mIsValid && rhs.mIsValid);                 \
 }
 
 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
 
 // Implement castToCheckedInt<T>(x), making sure that
 //  - it allows x to be either a CheckedInt<T> or any integer type
 //    that can be casted to T
 //  - if x is already a CheckedInt<T>, we just return a reference to it,
 //    instead of copying it (optimization)
@@ -781,16 +829,17 @@ inline CheckedInt<T> operator OP(U lhs, 
 {                                                                 \
   return castToCheckedInt<T>(lhs) OP rhs;                         \
 }
 
 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
 
 template<typename T, typename U>
 inline bool
 operator ==(const CheckedInt<T> &lhs, U rhs)
 {
   return lhs == castToCheckedInt<T>(rhs);
--- a/mfbt/tests/TestCheckedInt.cpp
+++ b/mfbt/tests/TestCheckedInt.cpp
@@ -185,16 +185,36 @@ void test()
 
   if (isTSigned) {
     VERIFY_IS_INVALID(min + min);
     VERIFY_IS_INVALID(minOverTwo + minOverTwo + minOverTwo);
     VERIFY_IS_INVALID(zero - min + min);
     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<T> 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<T> negOne = -one;
   const CheckedInt<T> negTwo = -two;
 
   if (isTSigned) {
     VERIFY_IS_VALID(-max);
     VERIFY_IS_INVALID(-min);
@@ -342,20 +362,25 @@ void test()
   VERIFY_IS_INVALID(someInvalid * zero);
   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 % 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 */
 
   VERIFY(one + T(2) == three);
   VERIFY(2 + one == three);
   {
     CheckedInt<T> x = one;
     x += 2;
@@ -377,16 +402,23 @@ void test()
   }
   VERIFY(four / 2 == two);
   VERIFY(4 / two == two);
   {
     CheckedInt<T> x = four;
     x /= 2;
     VERIFY(x == two);
   }
+  VERIFY(three % 2 == one);
+  VERIFY(3 % two == one);
+  {
+    CheckedInt<T> x = three;
+    x %= 2;
+    VERIFY(x == one);
+  }
 
   VERIFY(one == 1);
   VERIFY(1 == one);
   VERIFY_IS_FALSE(two == 1);
   VERIFY_IS_FALSE(1 == two);
   VERIFY_IS_FALSE(someInvalid == 1);
   VERIFY_IS_FALSE(1 == someInvalid);