diff --git a/include/llvm/ADT/Hashing.h b/include/llvm/ADT/Hashing.h index 06dd76a2ed7..1b0e66947b2 100644 --- a/include/llvm/ADT/Hashing.h +++ b/include/llvm/ADT/Hashing.h @@ -350,6 +350,16 @@ template struct is_hashable_data : integral_constant::value || is_pointer::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 struct is_hashable_data > + : integral_constant::value && + is_hashable_data::value && + !is_alignment_padded >::value && + !is_pod_pair_padded::value)> {}; + /// \brief Helper to get the hashable data representation for a type. /// This variant is enabled when the type itself can be used. template diff --git a/include/llvm/Support/type_traits.h b/include/llvm/Support/type_traits.h index 03f85e99971..f488a29c7af 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 {}; template struct is_pointer : false_type {}; template struct is_pointer : 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 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 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 diff --git a/unittests/ADT/HashingTest.cpp b/unittests/ADT/HashingTest.cpp index a9458bb5a5a..19a036cdf53 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 T *begin(T (&arr)[N]) { return arr; }