diff options
-rw-r--r-- | include/llvm/ADT/Hashing.h | 20 | ||||
-rw-r--r-- | include/llvm/Support/type_traits.h | 32 | ||||
-rw-r--r-- | unittests/ADT/HashingTest.cpp | 6 |
3 files changed, 48 insertions, 10 deletions
diff --git a/include/llvm/ADT/Hashing.h b/include/llvm/ADT/Hashing.h index 5efaa72705..b2bd72e702 100644 --- a/include/llvm/ADT/Hashing.h +++ b/include/llvm/ADT/Hashing.h @@ -113,7 +113,7 @@ public: /// differing argument types even if they would implicit promote to a common /// type without changing the value. template <typename T> -typename enable_if<is_integral<T>, hash_code>::type hash_value(T value); +typename enable_if<is_integral_or_enum<T>, hash_code>::type hash_value(T value); /// \brief Compute a hash_code for a pointer's address. /// @@ -349,14 +349,15 @@ inline size_t get_execution_seed() { /// reading the underlying data. It is false if values of this type must /// first be passed to hash_value, and the resulting hash_codes combined. // -// FIXME: We want to replace is_integral and is_pointer here with a predicate -// which asserts that comparing the underlying storage of two values of the -// type for equality is equivalent to comparing the two values for equality. -// For all the platforms we care about, this holds for integers and pointers, -// but there are platforms where it doesn't and we would like to support -// user-defined types which happen to satisfy this property. +// FIXME: We want to replace is_integral_or_enum and is_pointer here with +// a predicate which asserts that comparing the underlying storage of two +// values of the type for equality is equivalent to comparing the two values +// for equality. For all the platforms we care about, this holds for integers +// and pointers, but there are platforms where it doesn't and we would like to +// support user-defined types which happen to satisfy this property. template <typename T> struct is_hashable_data - : integral_constant<bool, ((is_integral<T>::value || is_pointer<T>::value) && + : integral_constant<bool, ((is_integral_or_enum<T>::value || + is_pointer<T>::value) && 64 % sizeof(T) == 0)> {}; // Special case std::pair to detect when both types are viable and when there @@ -732,7 +733,8 @@ inline hash_code hash_integer_value(uint64_t value) { // Declared and documented above, but defined here so that any of the hashing // infrastructure is available. template <typename T> -typename enable_if<is_integral<T>, hash_code>::type hash_value(T value) { +typename enable_if<is_integral_or_enum<T>, hash_code>::type +hash_value(T value) { return ::llvm::hashing::detail::hash_integer_value(value); } diff --git a/include/llvm/Support/type_traits.h b/include/llvm/Support/type_traits.h index 85d90b17f1..a76344c098 100644 --- a/include/llvm/Support/type_traits.h +++ b/include/llvm/Support/type_traits.h @@ -121,12 +121,42 @@ template <> struct is_integral_impl<unsigned long long> : true_type {}; template <typename T> struct is_integral : is_integral_impl<T> {}; +/// \brief Metafunction that determines whether the given type is either an +/// integral type or an enumeration type. +/// +/// Note that this accepts potentially more integral types than we whitelist +/// above for is_integral, it should accept essentially anything the compiler +/// believes is an integral type. +template <typename T> class is_integral_or_enum { + + // Form a return type that can only be instantiated with an integral or enum + // types (or with nullptr_t in C++11). + template <typename U, U u = U()> struct check1_return_type { char c[2]; }; + template <typename U> static check1_return_type<U> checker1(U*); + static char checker1(...); + + // Form a return type that can only be instantiated with nullptr_t in C++11 + // mode. It's harmless in C++98 mode, but this allows us to filter nullptr_t + // when building in C++11 mode without having to detect that mode for each + // different compiler. + struct nonce {}; + template <typename U, nonce* u = U()> + struct check2_return_type { char c[2]; }; + template <typename U> static check2_return_type<U> checker2(U*); + static char checker2(...); + +public: + enum { + value = (sizeof(char) != sizeof(checker1((T*)0)) && + sizeof(char) == sizeof(checker2((T*)0))) + }; +}; + /// \brief Metafunction that determines whether the given type is a pointer /// type. template <typename T> struct is_pointer : false_type {}; template <typename T> struct is_pointer<T*> : true_type {}; - // enable_if_c - Enable/disable a template based on a metafunction template<bool Cond, typename T = void> struct enable_if_c { diff --git a/unittests/ADT/HashingTest.cpp b/unittests/ADT/HashingTest.cpp index f5d6aed5b9..b148f14451 100644 --- a/unittests/ADT/HashingTest.cpp +++ b/unittests/ADT/HashingTest.cpp @@ -51,6 +51,10 @@ using namespace llvm; namespace { +enum TestEnumeration { + TE_Foo = 42, + TE_Bar = 43 +}; TEST(HashingTest, HashValueBasicTest) { int x = 42, y = 43, c = 'x'; @@ -61,7 +65,9 @@ TEST(HashingTest, HashValueBasicTest) { const volatile int cvi = 71; uintptr_t addr = reinterpret_cast<uintptr_t>(&y); EXPECT_EQ(hash_value(42), hash_value(x)); + EXPECT_EQ(hash_value(42), hash_value(TE_Foo)); EXPECT_NE(hash_value(42), hash_value(y)); + EXPECT_NE(hash_value(42), hash_value(TE_Bar)); EXPECT_NE(hash_value(42), hash_value(p)); EXPECT_EQ(hash_value(71), hash_value(i)); EXPECT_EQ(hash_value(71), hash_value(ci)); |