Bug 1297306 - part4:rename IsEnumFittingWithin with EnumTypeFitsWithin and move it to mfbt/EnumTypeTraits.h. draft
authorJeremy Chen <jeremychen@mozilla.com>
Wed, 07 Sep 2016 10:20:16 +0800
changeset 410887 5ea66f84a8d635679204c20ceba988ea1473bacf
parent 410886 e1a29a561af449a55c1e6efc4eed791b6e4e9e18
child 410888 8fbf6b36e1f4dc61baff0b7a52d6d15400a7940f
push id28778
push userjichen@mozilla.com
push dateWed, 07 Sep 2016 02:21:00 +0000
bugs1297306
milestone51.0a1
Bug 1297306 - part4:rename IsEnumFittingWithin with EnumTypeFitsWithin and move it to mfbt/EnumTypeTraits.h. With this change, we could share this EnumTypeTraits between files easily. MozReview-Commit-ID: 9Q2augati7l
layout/style/StyleAnimationValue.h
layout/style/nsCSSProps.h
layout/style/nsCSSValue.h
mfbt/EnumTypeTraits.h
mfbt/moz.build
mfbt/tests/TestEnumTypeTraits.cpp
mfbt/tests/moz.build
testing/cppunittest.ini
--- a/layout/style/StyleAnimationValue.h
+++ b/layout/style/StyleAnimationValue.h
@@ -444,17 +444,17 @@ public:
   void SetNormalValue();
   void SetAutoValue();
   void SetNoneValue();
   void SetIntValue(int32_t aInt, Unit aUnit);
   template<typename T,
            typename = typename std::enable_if<std::is_enum<T>::value>::type>
   void SetIntValue(T aInt, Unit aUnit)
   {
-    static_assert(mozilla::IsEnumFittingWithin<T, int32_t>::value,
+    static_assert(mozilla::EnumTypeFitsWithin<T, int32_t>::value,
                   "aValue must be an enum that fits within mValue.mInt");
     SetIntValue(static_cast<int32_t>(aInt), aUnit);
   }
   void SetCoordValue(nscoord aCoord);
   void SetPercentValue(float aPercent);
   void SetFloatValue(float aFloat);
   void SetColorValue(nscolor aColor);
   void SetCurrentColorValue();
--- a/layout/style/nsCSSProps.h
+++ b/layout/style/nsCSSProps.h
@@ -14,16 +14,17 @@
 #include <limits>
 #include <type_traits>
 #include "nsString.h"
 #include "nsCSSPropertyID.h"
 #include "nsStyleStructFwd.h"
 #include "nsCSSKeywords.h"
 #include "mozilla/CSSEnabledState.h"
 #include "mozilla/UseCounter.h"
+#include "mozilla/EnumTypeTraits.h"
 
 // Length of the "--" prefix on custom names (such as custom property names,
 // and, in the future, custom media query names).
 #define CSS_CUSTOM_NAME_PREFIX_LENGTH 2
 
 // Flags for ParseVariant method
 #define VARIANT_KEYWORD         0x000001  // K
 #define VARIANT_LENGTH          0x000002  // L
@@ -322,34 +323,16 @@ enum nsStyleAnimType {
 
   // discrete values
   eStyleAnimType_Discrete,
 
   // property not animatable
   eStyleAnimType_None
 };
 
-namespace mozilla {
-
-// Type trait that determines whether the integral or enum type Type can fit
-// within the integral type Storage without loss.
-template<typename T, typename Storage>
-struct IsEnumFittingWithin
-  : IntegralConstant<
-      bool,
-      std::is_integral<Storage>::value &&
-      std::numeric_limits<typename std::underlying_type<T>::type>::min() >=
-        std::numeric_limits<Storage>::min() &&
-      std::numeric_limits<typename std::underlying_type<T>::type>::max() <=
-        std::numeric_limits<Storage>::max()
-    >
-{};
-
-} // namespace mozilla
-
 class nsCSSProps {
 public:
   typedef mozilla::CSSEnabledState EnabledState;
 
   struct KTableEntry
   {
     // KTableEntry objects can be initialized either with an int16_t value
     // or a value of an enumeration type that can fit within an int16_t.
@@ -361,17 +344,17 @@ public:
     }
 
     template<typename T,
              typename = typename std::enable_if<std::is_enum<T>::value>::type>
     KTableEntry(nsCSSKeyword aKeyword, T aValue)
       : mKeyword(aKeyword)
       , mValue(static_cast<int16_t>(aValue))
     {
-      static_assert(mozilla::IsEnumFittingWithin<T, int16_t>::value,
+      static_assert(mozilla::EnumTypeFitsWithin<T, int16_t>::value,
                     "aValue must be an enum that fits within mValue");
     }
 
     nsCSSKeyword mKeyword;
     int16_t mValue;
   };
 
   static void AddRefTable(void);
@@ -447,29 +430,29 @@ public:
   // Return |eCSSKeyword_UNKNOWN| if not found.
   static nsCSSKeyword ValueToKeywordEnum(int32_t aValue,
                                          const KTableEntry aTable[]);
   template<typename T,
            typename = typename std::enable_if<std::is_enum<T>::value>::type>
   static nsCSSKeyword ValueToKeywordEnum(T aValue,
                                          const KTableEntry aTable[])
   {
-    static_assert(mozilla::IsEnumFittingWithin<T, int16_t>::value,
+    static_assert(mozilla::EnumTypeFitsWithin<T, int16_t>::value,
                   "aValue must be an enum that fits within KTableEntry::mValue");
     return ValueToKeywordEnum(static_cast<int16_t>(aValue), aTable);
   }
   // Ditto but as a string, return "" when not found.
   static const nsAFlatCString& ValueToKeyword(int32_t aValue,
                                               const KTableEntry aTable[]);
   template<typename T,
            typename = typename std::enable_if<std::is_enum<T>::value>::type>
   static const nsAFlatCString& ValueToKeyword(T aValue,
                                               const KTableEntry aTable[])
   {
-    static_assert(mozilla::IsEnumFittingWithin<T, int16_t>::value,
+    static_assert(mozilla::EnumTypeFitsWithin<T, int16_t>::value,
                   "aValue must be an enum that fits within KTableEntry::mValue");
     return ValueToKeyword(static_cast<int16_t>(aValue), aTable);
   }
 
   static const nsStyleStructID kSIDTable[eCSSProperty_COUNT_no_shorthands];
   static const KTableEntry* const kKeywordTableTable[eCSSProperty_COUNT_no_shorthands];
   static const nsStyleAnimType kAnimTypeTable[eCSSProperty_COUNT_no_shorthands];
   static const ptrdiff_t
--- a/layout/style/nsCSSValue.h
+++ b/layout/style/nsCSSValue.h
@@ -753,17 +753,17 @@ private:
   void DoReset();
 
 public:
   void SetIntValue(int32_t aValue, nsCSSUnit aUnit);
   template<typename T,
            typename = typename std::enable_if<std::is_enum<T>::value>::type>
   void SetIntValue(T aValue, nsCSSUnit aUnit)
   {
-    static_assert(mozilla::IsEnumFittingWithin<T, int32_t>::value,
+    static_assert(mozilla::EnumTypeFitsWithin<T, int32_t>::value,
                   "aValue must be an enum that fits within mValue.mInt");
     SetIntValue(static_cast<int32_t>(aValue), aUnit);
   }
   void SetPercentValue(float aValue);
   void SetFloatValue(float aValue, nsCSSUnit aUnit);
   void SetStringValue(const nsString& aValue, nsCSSUnit aUnit);
   void SetColorValue(nscolor aValue);
   void SetIntegerColorValue(nscolor aValue, nsCSSUnit aUnit);
new file mode 100644
--- /dev/null
+++ b/mfbt/EnumTypeTraits.h
@@ -0,0 +1,70 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * 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/. */
+
+/* Type traits for enums. */
+
+#ifndef mozilla_EnumTypeTraits_h
+#define mozilla_EnumTypeTraits_h
+
+#include <type_traits>
+
+namespace mozilla {
+
+namespace detail {
+
+template<size_t EnumSize, bool EnumSigned, size_t StorageSize, bool StorageSigned>
+struct EnumFitsWithinHelper;
+
+// Signed enum, signed storage.
+template<size_t EnumSize, size_t StorageSize>
+struct EnumFitsWithinHelper<EnumSize, true, StorageSize, true>
+  : public std::integral_constant<bool, (EnumSize <= StorageSize)>
+{};
+
+// Signed enum, unsigned storage.
+template<size_t EnumSize, size_t StorageSize>
+struct EnumFitsWithinHelper<EnumSize, true, StorageSize, false>
+  : public std::integral_constant<bool, false>
+{};
+
+// Unsigned enum, signed storage.
+template<size_t EnumSize, size_t StorageSize>
+struct EnumFitsWithinHelper<EnumSize, false, StorageSize, true>
+  : public std::integral_constant<bool, (EnumSize * 2 <= StorageSize)>
+{};
+
+// Unsigned enum, unsigned storage.
+template<size_t EnumSize, size_t StorageSize>
+struct EnumFitsWithinHelper<EnumSize, false, StorageSize, false>
+  : public std::integral_constant<bool, (EnumSize <= StorageSize)>
+{};
+
+} // namespace detail
+
+/*
+ * Type trait that determines whether the enum type T can fit within the
+ * integral type Storage without data loss. This trait should be used with
+ * caution with an enum type whose underlying type has not been explicitly
+ * specified: for such enums, the C++ implementation is free to choose a type
+ * no smaller than int whose range encompasses all possible values of the enum.
+ * So for an enum with only small non-negative values, the underlying type may
+ * be either int or unsigned int, depending on the whims of the implementation.
+ */
+template<typename T, typename Storage>
+struct EnumTypeFitsWithin
+  : public detail::EnumFitsWithinHelper<
+      sizeof(T),
+      std::is_signed<typename std::underlying_type<T>::type>::value,
+      sizeof(Storage),
+      std::is_signed<Storage>::value
+    >
+{
+  static_assert(std::is_enum<T>::value, "must provide an enum type");
+  static_assert(std::is_integral<Storage>::value, "must provide an integral type");
+};
+
+} // namespace mozilla
+
+#endif /* mozilla_EnumTypeTraits_h */
--- a/mfbt/moz.build
+++ b/mfbt/moz.build
@@ -34,16 +34,17 @@ EXPORTS.mozilla = [
     'DebugOnly.h',
     'decimal/Decimal.h',
     'double-conversion/double-conversion.h',
     'double-conversion/utils.h',
     'EndianUtils.h',
     'EnumeratedArray.h',
     'EnumeratedRange.h',
     'EnumSet.h',
+    'EnumTypeTraits.h',
     'FastBernoulliTrial.h',
     'FloatingPoint.h',
     'Function.h',
     'GuardObjects.h',
     'HashFunctions.h',
     'IndexSequence.h',
     'InitializerList.h',
     'IntegerPrintfMacros.h',
new file mode 100644
--- /dev/null
+++ b/mfbt/tests/TestEnumTypeTraits.cpp
@@ -0,0 +1,136 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * 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/IntegerTypeTraits.h"
+#include "mozilla/EnumTypeTraits.h"
+
+using namespace mozilla;
+
+/* Feature check for EnumTypeFitsWithin. */
+
+#define MAKE_FIXED_EMUM_FOR_TYPE(IntType)                               \
+  enum FixedEnumFor_##IntType : IntType {                               \
+    A_##IntType,                                                        \
+    B_##IntType,                                                        \
+    C_##IntType,                                                        \
+  };
+
+template<typename EnumType, typename IntType>
+static void
+TestShouldFit()
+{
+  static_assert(EnumTypeFitsWithin<EnumType, IntType>::value,
+                "Should fit within exact/promoted integral type");
+}
+
+template<typename EnumType, typename IntType>
+static void
+TestShouldNotFit()
+{
+  static_assert(!EnumTypeFitsWithin<EnumType, IntType>::value,
+                "Should not fit within");
+}
+
+int
+main()
+{
+  // check for int8_t
+  MAKE_FIXED_EMUM_FOR_TYPE(int8_t);
+  TestShouldFit<FixedEnumFor_int8_t, int8_t>();
+  TestShouldFit<FixedEnumFor_int8_t, int16_t>();
+  TestShouldFit<FixedEnumFor_int8_t, int32_t>();
+  TestShouldFit<FixedEnumFor_int8_t, int64_t>();
+
+  TestShouldNotFit<FixedEnumFor_int8_t, uint8_t>();
+  TestShouldNotFit<FixedEnumFor_int8_t, uint16_t>();
+  TestShouldNotFit<FixedEnumFor_int8_t, uint32_t>();
+  TestShouldNotFit<FixedEnumFor_int8_t, uint64_t>();
+
+  // check for uint8_t
+  MAKE_FIXED_EMUM_FOR_TYPE(uint8_t);
+  TestShouldFit<FixedEnumFor_uint8_t, uint8_t>();
+  TestShouldFit<FixedEnumFor_uint8_t, uint16_t>();
+  TestShouldFit<FixedEnumFor_uint8_t, uint32_t>();
+  TestShouldFit<FixedEnumFor_uint8_t, uint64_t>();
+
+  TestShouldNotFit<FixedEnumFor_uint8_t, int8_t>();
+  TestShouldFit<FixedEnumFor_uint8_t, int16_t>();
+  TestShouldFit<FixedEnumFor_uint8_t, int32_t>();
+  TestShouldFit<FixedEnumFor_uint8_t, int64_t>();
+
+  // check for int16_t
+  MAKE_FIXED_EMUM_FOR_TYPE(int16_t);
+  TestShouldNotFit<FixedEnumFor_int16_t, int8_t>();
+  TestShouldFit<FixedEnumFor_int16_t, int16_t>();
+  TestShouldFit<FixedEnumFor_int16_t, int32_t>();
+  TestShouldFit<FixedEnumFor_int16_t, int64_t>();
+
+  TestShouldNotFit<FixedEnumFor_int16_t, uint8_t>();
+  TestShouldNotFit<FixedEnumFor_int16_t, uint16_t>();
+  TestShouldNotFit<FixedEnumFor_int16_t, uint32_t>();
+  TestShouldNotFit<FixedEnumFor_int16_t, uint64_t>();
+
+  // check for uint16_t
+  MAKE_FIXED_EMUM_FOR_TYPE(uint16_t);
+  TestShouldNotFit<FixedEnumFor_uint16_t, uint8_t>();
+  TestShouldFit<FixedEnumFor_uint16_t, uint16_t>();
+  TestShouldFit<FixedEnumFor_uint16_t, uint32_t>();
+  TestShouldFit<FixedEnumFor_uint16_t, uint64_t>();
+
+  TestShouldNotFit<FixedEnumFor_uint16_t, int8_t>();
+  TestShouldNotFit<FixedEnumFor_uint16_t, int16_t>();
+  TestShouldFit<FixedEnumFor_uint16_t, int32_t>();
+  TestShouldFit<FixedEnumFor_uint16_t, int64_t>();
+
+  // check for int32_t
+  MAKE_FIXED_EMUM_FOR_TYPE(int32_t);
+  TestShouldNotFit<FixedEnumFor_int32_t, int8_t>();
+  TestShouldNotFit<FixedEnumFor_int32_t, int16_t>();
+  TestShouldFit<FixedEnumFor_int32_t, int32_t>();
+  TestShouldFit<FixedEnumFor_int32_t, int64_t>();
+
+  TestShouldNotFit<FixedEnumFor_int32_t, uint8_t>();
+  TestShouldNotFit<FixedEnumFor_int32_t, uint16_t>();
+  TestShouldNotFit<FixedEnumFor_int32_t, uint32_t>();
+  TestShouldNotFit<FixedEnumFor_int32_t, uint64_t>();
+
+  // check for uint32_t
+  MAKE_FIXED_EMUM_FOR_TYPE(uint32_t);
+  TestShouldNotFit<FixedEnumFor_uint32_t, uint8_t>();
+  TestShouldNotFit<FixedEnumFor_uint32_t, uint16_t>();
+  TestShouldFit<FixedEnumFor_uint32_t, uint32_t>();
+  TestShouldFit<FixedEnumFor_uint32_t, uint64_t>();
+
+  TestShouldNotFit<FixedEnumFor_uint32_t, int8_t>();
+  TestShouldNotFit<FixedEnumFor_uint32_t, int16_t>();
+  TestShouldNotFit<FixedEnumFor_uint32_t, int32_t>();
+  TestShouldFit<FixedEnumFor_uint32_t, int64_t>();
+
+  // check for int64_t
+  MAKE_FIXED_EMUM_FOR_TYPE(int64_t);
+  TestShouldNotFit<FixedEnumFor_int64_t, int8_t>();
+  TestShouldNotFit<FixedEnumFor_int64_t, int16_t>();
+  TestShouldNotFit<FixedEnumFor_int64_t, int32_t>();
+  TestShouldFit<FixedEnumFor_int64_t, int64_t>();
+
+  TestShouldNotFit<FixedEnumFor_int64_t, uint8_t>();
+  TestShouldNotFit<FixedEnumFor_int64_t, uint16_t>();
+  TestShouldNotFit<FixedEnumFor_int64_t, uint32_t>();
+  TestShouldNotFit<FixedEnumFor_int64_t, uint64_t>();
+
+  // check for uint64_t
+  MAKE_FIXED_EMUM_FOR_TYPE(uint64_t);
+  TestShouldNotFit<FixedEnumFor_uint64_t, uint8_t>();
+  TestShouldNotFit<FixedEnumFor_uint64_t, uint16_t>();
+  TestShouldNotFit<FixedEnumFor_uint64_t, uint32_t>();
+  TestShouldFit<FixedEnumFor_uint64_t, uint64_t>();
+
+  TestShouldNotFit<FixedEnumFor_uint64_t, int8_t>();
+  TestShouldNotFit<FixedEnumFor_uint64_t, int16_t>();
+  TestShouldNotFit<FixedEnumFor_uint64_t, int32_t>();
+  TestShouldNotFit<FixedEnumFor_uint64_t, int64_t>();
+
+  return 0;
+}
--- a/mfbt/tests/moz.build
+++ b/mfbt/tests/moz.build
@@ -12,16 +12,17 @@ CppUnitTests([
     'TestBufferList',
     'TestCasting',
     'TestCeilingFloor',
     'TestCheckedInt',
     'TestCountPopulation',
     'TestCountZeroes',
     'TestEndian',
     'TestEnumSet',
+    'TestEnumTypeTraits',
     'TestFastBernoulliTrial',
     'TestFloatingPoint',
     'TestFunction',
     'TestInitializerList',
     'TestIntegerPrintfMacros',
     'TestIntegerRange',
     'TestJSONWriter',
     'TestLinkedList',
--- a/testing/cppunittest.ini
+++ b/testing/cppunittest.ini
@@ -28,16 +28,17 @@ skip-if = os == 'b2g' || (os == 'android
 [TestCountZeroes]
 [TestDeadlockDetector]
 skip-if = os == 'b2g' || (os == 'android' && debug) # Bug 1054249
 [TestDeadlockDetectorScalability]
 [TestDllInterceptor]
 skip-if = os != 'win'
 [TestEndian]
 [TestEnumSet]
+[TestEnumTypeTraits]
 [TestFastBernoulliTrial]
 [TestFile]
 [TestFloatingPoint]
 [TestFunction]
 [TestGetURL]
 [TestHashtables]
 [TestID]
 [TestInitializerList]