diff --git a/llvm/include/llvm/ADT/Hashing.h b/llvm/include/llvm/ADT/Hashing.h --- a/llvm/include/llvm/ADT/Hashing.h +++ b/llvm/include/llvm/ADT/Hashing.h @@ -52,6 +52,7 @@ #include #include #include +#include #include namespace llvm { @@ -116,6 +117,8 @@ template hash_code hash_value(const std::basic_string &arg); +/// Compute a hash_code for a tuple. +template hash_code hash_value(const std::tuple &arg); /// Override the execution seed with a fixed value. /// @@ -652,6 +655,45 @@ return hash_combine_range(arg.begin(), arg.end()); } +// Implementation details for the hash_value overload for std::tuple<...>(...). +namespace hashing { +namespace detail { + +// The indices of a tuple (0..n-1) are collected as the Indices template +// parameter of the TupleIndexSet template. +template struct TupleIndexSet {}; + +// Collecting the indices uses recursive template metaprogramming via the +// MakeTupleIndexSet struct. The I template parameter recursively +// counts up to N-1. The values are collected in the Indices template parameter +// and then returned in the second template specialization when I reaches N. +template +struct MakeTupleIndexSet { + typedef typename MakeTupleIndexSet::Type Type; +}; + +template +struct MakeTupleIndexSet { + typedef TupleIndexSet Type; +}; + +// The indices are then expanded in the hash_value_tuple_helper function into +// std::get<...>(...) calls. +template +hash_code hash_value_tuple_helper(const std::tuple &arg, + TupleIndexSet indices) { + return hash_combine(std::get(arg)...); +} + +} // namespace detail +} // namespace hashing + +template hash_code hash_value(const std::tuple &arg) { + typename ::llvm::hashing::detail::MakeTupleIndexSet<0, sizeof...(Ts)>::Type + indices; + return hash_value_tuple_helper(arg, indices); +} + } // namespace llvm #endif diff --git a/llvm/unittests/ADT/HashingTest.cpp b/llvm/unittests/ADT/HashingTest.cpp --- a/llvm/unittests/ADT/HashingTest.cpp +++ b/llvm/unittests/ADT/HashingTest.cpp @@ -101,6 +101,12 @@ hash_value(std::make_pair(obj1, std::make_pair(obj2, obj3)))); } +TEST(HashingTest, HashValueStdTuple) { + EXPECT_EQ(hash_combine(), hash_value(std::make_tuple())); + EXPECT_EQ(hash_combine(42), hash_value(std::make_tuple(42))); + EXPECT_EQ(hash_combine(42, 'c'), hash_value(std::make_tuple(42, 'c'))); +} + TEST(HashingTest, HashValueStdString) { std::string s = "Hello World!"; EXPECT_EQ(hash_combine_range(s.c_str(), s.c_str() + s.size()), hash_value(s));