diff options
-rw-r--r-- | include/llvm/ADT/Hashing.h | 10 | ||||
-rw-r--r-- | include/llvm/Support/type_traits.h | 18 | ||||
-rw-r--r-- | unittests/ADT/HashingTest.cpp | 12 |
3 files changed, 35 insertions, 5 deletions
diff --git a/include/llvm/ADT/Hashing.h b/include/llvm/ADT/Hashing.h index 06dd76a2ed..1b0e66947b 100644 --- a/include/llvm/ADT/Hashing.h +++ b/include/llvm/ADT/Hashing.h @@ -350,6 +350,16 @@ template <typename T> struct is_hashable_data : integral_constant<bool, ((is_integral<T>::value || is_pointer<T>::value) && 64 % sizeof(T) == 0)> {}; +// Special case std::pair to detect when both types are viable and when there +// is no alignment-derived padding in the pair. This is a bit of a lie because +// std::pair isn't truly POD, but it's close enough in all reasonable +// implementations for our use case of hashing the underlying data. +template <typename T, typename U> struct is_hashable_data<std::pair<T, U> > + : integral_constant<bool, (is_hashable_data<T>::value && + is_hashable_data<U>::value && + !is_alignment_padded<std::pair<T, U> >::value && + !is_pod_pair_padded<T, U>::value)> {}; + /// \brief Helper to get the hashable data representation for a type. /// This variant is enabled when the type itself can be used. template <typename T> diff --git a/include/llvm/Support/type_traits.h b/include/llvm/Support/type_traits.h index 03f85e9997..f488a29c7a 100644 --- a/include/llvm/Support/type_traits.h +++ b/include/llvm/Support/type_traits.h @@ -125,6 +125,24 @@ struct is_integral : is_integral_impl<T> {}; template <typename T> struct is_pointer : false_type {}; template <typename T> struct is_pointer<T*> : true_type {}; +/// \brief Metafunction to compute whether a type requires alignment padding. +/// When true, an object of this type will have padding bytes inside its +/// 'sizeof' bytes. +template <typename T> class is_alignment_padded { + struct pod_size_tester { T t; char c; }; +public: + enum { value = offsetof(pod_size_tester, c) != sizeof(T) }; +}; + +/// \brief Metafunction to determine whether an adjacent pair of two types will +/// require padding between them due to alignment. +template <typename T, typename U> class is_pod_pair_padded { + struct pod_pair { T t; U u; }; + struct pod_char_pair { T t; char c; }; +public: + enum { value = offsetof(pod_pair, u) != offsetof(pod_char_pair, c) }; +}; + // enable_if_c - Enable/disable a template based on a metafunction template<bool Cond, typename T = void> diff --git a/unittests/ADT/HashingTest.cpp b/unittests/ADT/HashingTest.cpp index a9458bb5a5..19a036cdf5 100644 --- a/unittests/ADT/HashingTest.cpp +++ b/unittests/ADT/HashingTest.cpp @@ -66,11 +66,13 @@ TEST(HashingTest, HashValueBasicTest) { EXPECT_NE(hash_combine(42, 43), hash_value(std::make_pair(42ull, 43ull))); EXPECT_NE(hash_combine(42, 43), hash_value(std::make_pair(42, 43ull))); EXPECT_NE(hash_combine(42, 43), hash_value(std::make_pair(42ull, 43))); - EXPECT_EQ(hash_combine(42, hash_combine(43, hash_combine(44, 45))), - hash_value( - std::make_pair(42, std::make_pair(43, std::make_pair(44, 45))))); - EXPECT_EQ(hash_combine(42, 43), hash_value(std::make_pair(42, 43))); - EXPECT_EQ(hash_combine(42, 43), hash_value(std::make_pair(42, 43))); + + // Note that pairs are implicitly flattened to a direct sequence of data and + // hashed efficiently as a consequence. + EXPECT_EQ(hash_combine(42, 43, 44), + hash_value(std::make_pair(42, std::make_pair(43, 44)))); + EXPECT_EQ(hash_value(std::make_pair(42, std::make_pair(43, 44))), + hash_value(std::make_pair(std::make_pair(42, 43), 44))); } template <typename T, size_t N> T *begin(T (&arr)[N]) { return arr; } |