Bug 881980 - Allow casting CheckedInts to other CheckedInt types. - r=bjacob,waldo
authorJeff Gilbert <jgilbert@mozilla.com>
Fri, 14 Jun 2013 15:19:40 -0700
changeset 135146 9e0bf0548e486cdfda2f9dd91e56edb733b1a0ba
parent 135145 a74b3d43c3af2b8b09437a735e65c0e5bdbf7e4a
child 135147 8bce22008b2535ecccf12e3194113a053f777c7e
push id29540
push userjgilbert@mozilla.com
push dateFri, 14 Jun 2013 22:23:02 +0000
treeherdermozilla-inbound@9e0bf0548e48 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbjacob, waldo
bugs881980
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 881980 - Allow casting CheckedInts to other CheckedInt types. - r=bjacob,waldo
mfbt/CheckedInt.h
mfbt/tests/TestCheckedInt.cpp
--- a/mfbt/CheckedInt.h
+++ b/mfbt/CheckedInt.h
@@ -561,17 +561,17 @@ struct NegateImpl<T, true>
    // 1 is of type int, is found to be in range for uint8_t, x is valid
    CheckedInt<uint8_t> x(1);
    // -1 is of type int, is found not to be in range for uint8_t, x is invalid
    CheckedInt<uint8_t> x(-1);
    // -1 is of type int, is found to be in range for int8_t, x is valid
    CheckedInt<int8_t> x(-1);
    // 1000 is of type int16_t, is found not to be in range for int8_t,
    // x is invalid
-   CheckedInt<int8_t> x(int16_t(1000)); 
+   CheckedInt<int8_t> x(int16_t(1000));
    // 3123456789 is of type uint32_t, is found not to be in range for int32_t,
    // x is invalid
    CheckedInt<int32_t> x(uint32_t(3123456789));
  * @endcode
  * Implicit conversion from
  * checked integers to plain integers is not allowed. As shown in the
  * above example, to get the value of a checked integer as a normal integer,
  * call value().
@@ -623,16 +623,27 @@ class CheckedInt
       : mValue(T(value)),
         mIsValid(detail::IsInRange<T>(value))
     {
       MOZ_STATIC_ASSERT(detail::IsSupported<T>::value &&
                         detail::IsSupported<U>::value,
                         "This type is not supported by CheckedInt");
     }
 
+    template<typename U>
+    friend class CheckedInt;
+
+    template<typename U>
+    CheckedInt<U> toChecked() const
+    {
+      CheckedInt<U> ret(mValue);
+      ret.mIsValid = ret.mIsValid && mIsValid;
+      return ret;
+    }
+
     /** Constructs a valid checked integer with initial value 0 */
     CheckedInt() : mValue(0), mIsValid(true)
     {
       MOZ_STATIC_ASSERT(detail::IsSupported<T>::value,
                         "This type is not supported by CheckedInt");
     }
 
     /** @returns the actual value */
--- a/mfbt/tests/TestCheckedInt.cpp
+++ b/mfbt/tests/TestCheckedInt.cpp
@@ -417,35 +417,60 @@ void test()
 
   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);
 
-  /* Check that construction of CheckedInt from an integer value of a mismatched type is checked */
+  // Check simple casting between different signedness and sizes.
+  {
+    CheckedInt<uint8_t> foo = CheckedInt<uint16_t>(2).toChecked<uint8_t>();
+    VERIFY_IS_VALID(foo);
+    VERIFY(foo == 2);
+  }
+  {
+    CheckedInt<uint8_t> foo = CheckedInt<uint16_t>(255).toChecked<uint8_t>();
+    VERIFY_IS_VALID(foo);
+    VERIFY(foo == 255);
+  }
+  {
+    CheckedInt<uint8_t> foo = CheckedInt<uint16_t>(256).toChecked<uint8_t>();
+    VERIFY_IS_INVALID(foo);
+  }
+  {
+    CheckedInt<uint8_t> foo = CheckedInt<int8_t>(-2).toChecked<uint8_t>();
+    VERIFY_IS_INVALID(foo);
+  }
 
-  #define VERIFY_CONSTRUCTION_FROM_INTEGER_TYPE(U) \
+  // Check that construction of CheckedInt from an integer value of a mismatched type is checked
+  // Also check casting between all types.
+
+  #define VERIFY_CONSTRUCTION_FROM_INTEGER_TYPE2(U,V,PostVExpr) \
   { \
     bool isUSigned = detail::IsSigned<U>::value; \
-    VERIFY_IS_VALID(CheckedInt<T>(U(0))); \
-    VERIFY_IS_VALID(CheckedInt<T>(U(1))); \
-    VERIFY_IS_VALID(CheckedInt<T>(U(100))); \
+    VERIFY_IS_VALID(CheckedInt<T>(V(  0)PostVExpr)); \
+    VERIFY_IS_VALID(CheckedInt<T>(V(  1)PostVExpr)); \
+    VERIFY_IS_VALID(CheckedInt<T>(V(100)PostVExpr)); \
     if (isUSigned) \
-      VERIFY_IS_VALID_IF(CheckedInt<T>(U(-1)), isTSigned); \
+      VERIFY_IS_VALID_IF(CheckedInt<T>(V(-1)PostVExpr), isTSigned); \
     if (sizeof(U) > sizeof(T)) \
-      VERIFY_IS_INVALID(CheckedInt<T>(U(detail::MaxValue<T>::value) + one.value())); \
+      VERIFY_IS_INVALID(CheckedInt<T>(V(detail::MaxValue<T>::value)PostVExpr + one.value())); \
     VERIFY_IS_VALID_IF(CheckedInt<T>(detail::MaxValue<U>::value), \
       (sizeof(T) > sizeof(U) || ((sizeof(T) == sizeof(U)) && (isUSigned || !isTSigned)))); \
     VERIFY_IS_VALID_IF(CheckedInt<T>(detail::MinValue<U>::value), \
-      isUSigned == false ? 1 : \
-      bool(isTSigned) == false ? 0 : \
-      sizeof(T) >= sizeof(U)); \
+      isUSigned == false ? 1 \
+                         : bool(isTSigned) == false ? 0 \
+                                                    : sizeof(T) >= sizeof(U)); \
   }
+  #define VERIFY_CONSTRUCTION_FROM_INTEGER_TYPE(U) \
+    VERIFY_CONSTRUCTION_FROM_INTEGER_TYPE2(U,U,+0) \
+    VERIFY_CONSTRUCTION_FROM_INTEGER_TYPE2(U,CheckedInt<U>,.toChecked<T>())
+
   VERIFY_CONSTRUCTION_FROM_INTEGER_TYPE(int8_t)
   VERIFY_CONSTRUCTION_FROM_INTEGER_TYPE(uint8_t)
   VERIFY_CONSTRUCTION_FROM_INTEGER_TYPE(int16_t)
   VERIFY_CONSTRUCTION_FROM_INTEGER_TYPE(uint16_t)
   VERIFY_CONSTRUCTION_FROM_INTEGER_TYPE(int32_t)
   VERIFY_CONSTRUCTION_FROM_INTEGER_TYPE(uint32_t)
   VERIFY_CONSTRUCTION_FROM_INTEGER_TYPE(int64_t)
   VERIFY_CONSTRUCTION_FROM_INTEGER_TYPE(uint64_t)