Bug 798179 - Implement mozilla::MakeSigned. r=froydnj
authorJeff Walden <jwalden@mit.edu>
Tue, 05 Mar 2013 15:44:02 -0800
changeset 134648 e4473d563e0f290a838efcd2a21c348774ec558b
parent 134647 57c346bd9ec3e19b545f17848fa3c4f6d28cef37
child 134649 094d54c0c9ea9db818d88beca4db95851bb1ecfa
push id29310
push userjwalden@mit.edu
push dateTue, 11 Jun 2013 15:38:40 +0000
treeherdermozilla-inbound@9404c1d1df0c [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersfroydnj
bugs798179
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 798179 - Implement mozilla::MakeSigned. r=froydnj
mfbt/TypeTraits.h
mfbt/tests/TestTypeTraits.cpp
--- a/mfbt/TypeTraits.h
+++ b/mfbt/TypeTraits.h
@@ -208,17 +208,18 @@ struct IsSignedHelper<T, true> : TrueTyp
 template<typename T>
 struct IsSignedHelper<T, false>
   : IntegralConstant<bool, IsArithmetic<T>::value && T(-1) < T(1)>
 {};
 
 } // namespace detail
 
 /**
- * IsSigned determines whether a type is a signed arithmetic type.
+ * IsSigned determines whether a type is a signed arithmetic type.  |char| is
+ * considered a signed type if it has the same representation as |signed char|.
  *
  * Don't use this if the type might be user-defined!  You might or might not get
  * a compile error, depending.
  *
  * mozilla::IsSigned<int>::value is true;
  * mozilla::IsSigned<const unsigned int>::value is false;
  * mozilla::IsSigned<unsigned char>::value is false;
  * mozilla::IsSigned<float>::value is true.
@@ -451,16 +452,102 @@ struct RemoveCV
 {
     typedef typename RemoveConst<typename RemoveVolatile<T>::Type>::Type Type;
 };
 
 /* 20.9.7.2 Reference modifications [meta.trans.ref] */
 
 /* 20.9.7.3 Sign modifications [meta.trans.sign] */
 
+template<bool B, typename T = void>
+struct EnableIf;
+
+template<bool Condition, typename A, typename B>
+struct Conditional;
+
+namespace detail {
+
+template<bool MakeConst, typename T>
+struct WithC : Conditional<MakeConst, const T, T>
+{};
+
+template<bool MakeVolatile, typename T>
+struct WithV : Conditional<MakeVolatile, volatile T, T>
+{};
+
+
+template<bool MakeConst, bool MakeVolatile, typename T>
+struct WithCV : WithC<MakeConst, typename WithV<MakeVolatile, T>::Type>
+{};
+
+template<typename T>
+struct CorrespondingSigned;
+
+template<>
+struct CorrespondingSigned<char> { typedef signed char Type; };
+template<>
+struct CorrespondingSigned<unsigned char> { typedef signed char Type; };
+template<>
+struct CorrespondingSigned<unsigned short> { typedef short Type; };
+template<>
+struct CorrespondingSigned<unsigned int> { typedef int Type; };
+template<>
+struct CorrespondingSigned<unsigned long> { typedef long Type; };
+template<>
+struct CorrespondingSigned<unsigned long long> { typedef long long Type; };
+
+template<typename T,
+         typename CVRemoved = typename RemoveCV<T>::Type,
+         bool IsSignedIntegerType = IsSigned<CVRemoved>::value &&
+                                    !IsSame<char, CVRemoved>::value>
+struct MakeSigned;
+
+template<typename T, typename CVRemoved>
+struct MakeSigned<T, CVRemoved, true>
+{
+    typedef T Type;
+};
+
+template<typename T, typename CVRemoved>
+struct MakeSigned<T, CVRemoved, false>
+  : WithCV<IsConst<T>::value, IsVolatile<T>::value,
+           typename CorrespondingSigned<CVRemoved>::Type>
+{};
+
+} // namespace detail
+
+/**
+ * MakeSigned produces the corresponding signed integer type for a given
+ * integral type T, with the const/volatile qualifiers of T.  T must be a
+ * possibly-const/volatile-qualified integral type that isn't bool.
+ *
+ * If T is already a signed integer type (not including char!), then T is
+ * produced.
+ *
+ * Otherwise, if T is an unsigned integer type, the signed variety of T, with
+ * T's const/volatile qualifiers, is produced.
+ *
+ * Otherwise, the integral type of the same size as T, with the lowest rank,
+ * with T's const/volatile qualifiers, is produced.  (This basically only acts
+ * to produce signed char when T = char.)
+ *
+ * mozilla::MakeSigned<unsigned long>::Type is signed long;
+ * mozilla::MakeSigned<volatile int>::Type is volatile int;
+ * mozilla::MakeSigned<const unsigned short>::Type is const signed short;
+ * mozilla::MakeSigned<const char>::Type is const signed char;
+ * mozilla::MakeSigned<bool> is an error;
+ * mozilla::MakeSigned<void*> is an error.
+ */
+template<typename T>
+struct MakeSigned
+  : EnableIf<IsIntegral<T>::value && !IsSame<bool, typename RemoveCV<T>::Type>::value,
+             typename detail::MakeSigned<T>
+            >::Type
+{};
+
 /* 20.9.7.4 Array modifications [meta.trans.arr] */
 
 /* 20.9.7.5 Pointer modifications [meta.trans.ptr] */
 
 /* 20.9.7.6 Other transformations [meta.trans.other] */
 
 /**
  * EnableIf is a struct containing a typedef of T if and only if B is true.
@@ -475,17 +562,17 @@ struct RemoveCV
  *   template<typename T>
  *   class PodVector // vector optimized to store POD (memcpy-able) types
  *   {
  *      EnableIf<IsPod<T>::value, T>::Type* vector;
  *      size_t length;
  *      ...
  *   };
  */
-template<bool B, typename T = void>
+template<bool B, typename T>
 struct EnableIf
 {};
 
 template<typename T>
 struct EnableIf<true, T>
 {
     typedef T Type;
 };
--- a/mfbt/tests/TestTypeTraits.cpp
+++ b/mfbt/tests/TestTypeTraits.cpp
@@ -3,18 +3,20 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "mozilla/Assertions.h"
 #include "mozilla/TypeTraits.h"
 
 using mozilla::IsBaseOf;
 using mozilla::IsConvertible;
+using mozilla::IsSame;
 using mozilla::IsSigned;
 using mozilla::IsUnsigned;
+using mozilla::MakeSigned;
 
 MOZ_STATIC_ASSERT(!IsSigned<bool>::value, "bool shouldn't be signed");
 MOZ_STATIC_ASSERT(IsUnsigned<bool>::value, "bool should be unsigned");
 
 MOZ_STATIC_ASSERT(!IsSigned<const bool>::value, "const bool shouldn't be signed");
 MOZ_STATIC_ASSERT(IsUnsigned<const bool>::value, "const bool should be unsigned");
 
 MOZ_STATIC_ASSERT(!IsSigned<volatile bool>::value, "volatile bool shouldn't be signed");
@@ -145,15 +147,40 @@ TestIsConvertible()
   // These cases seem to require C++11 support to properly implement them, so
   // for now just disable them.
   //MOZ_ASSERT((!IsConvertible<C*, A*>::value),
   //           "C* shouldn't convert to A* (private inheritance)");
   //MOZ_ASSERT((!IsConvertible<C, A>::value),
   //           "C doesn't convert to A (private inheritance)");
 }
 
+MOZ_STATIC_ASSERT((IsSame<MakeSigned<const unsigned char>::Type, const signed char>::value),
+                  "const unsigned char won't signify correctly");
+MOZ_STATIC_ASSERT((IsSame<MakeSigned<volatile unsigned short>::Type, volatile signed short>::value),
+                  "volatile unsigned short won't signify correctly");
+MOZ_STATIC_ASSERT((IsSame<MakeSigned<const volatile unsigned int>::Type, const volatile signed int>::value),
+                  "const volatile unsigned int won't signify correctly");
+MOZ_STATIC_ASSERT((IsSame<MakeSigned<unsigned long>::Type, signed long>::value),
+                  "unsigned long won't signify correctly");
+MOZ_STATIC_ASSERT((IsSame<MakeSigned<const signed char>::Type, const signed char>::value),
+                  "const signed char won't signify correctly");
+
+MOZ_STATIC_ASSERT((IsSame<MakeSigned<volatile signed short>::Type, volatile signed short>::value),
+                  "volatile signed short won't signify correctly");
+MOZ_STATIC_ASSERT((IsSame<MakeSigned<const volatile signed int>::Type, const volatile signed int>::value),
+                  "const volatile signed int won't signify correctly");
+MOZ_STATIC_ASSERT((IsSame<MakeSigned<signed long>::Type, signed long>::value),
+                  "signed long won't signify correctly");
+
+MOZ_STATIC_ASSERT((IsSame<MakeSigned<char>::Type, signed char>::value),
+                  "char won't signify correctly");
+MOZ_STATIC_ASSERT((IsSame<MakeSigned<volatile char>::Type, volatile signed char>::value),
+                  "volatile char won't signify correctly");
+MOZ_STATIC_ASSERT((IsSame<MakeSigned<const char>::Type, const signed char>::value),
+                  "const char won't signify correctly");
+
 int
 main()
 {
   CPlusPlus11IsBaseOf::StandardIsBaseOfTests();
   TestIsBaseOf();
   TestIsConvertible();
 }