From 879db739d6bb0cd6a7035d4606c34c877077c88e Mon Sep 17 00:00:00 2001 From: Alexander Shaposhnikov Date: Tue, 28 Jul 2015 20:35:46 -0700 Subject: [PATCH] Add hasher specializations for enums, pairs and tuples Summary: This diff adds partial specializations of folly::hasher for enum types, std::pair and std::tuple. We also restrict the specialization for folly::Range to POD value types. Reviewed By: @ot, @ddrcoder Differential Revision: D2285554 --- folly/Hash.h | 29 ++++++++++++++++++++++++++++- folly/Range.h | 6 ++++-- folly/test/HashTest.cpp | 40 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 72 insertions(+), 3 deletions(-) diff --git a/folly/Hash.h b/folly/Hash.h index 566bad05..f40f4ec2 100644 --- a/folly/Hash.h +++ b/folly/Hash.h @@ -23,6 +23,7 @@ #include #include +#include #include #include @@ -335,7 +336,7 @@ inline uint32_t hsieh_hash32_str(const std::string& str) { } // namespace hash -template +template struct hasher; struct Hash { @@ -343,6 +344,11 @@ struct Hash { size_t operator()(const T& v) const { return hasher()(v); } + + template + size_t operator()(const T& t, const Ts&... ts) const { + return hash::hash_128_to_64((*this)(t), (*this)(ts...)); + } }; template<> struct hasher { @@ -369,6 +375,27 @@ template<> struct hasher { } }; +template +struct hasher::value, void>::type> { + size_t operator()(T key) const { + return Hash()(static_cast::type>(key)); + } +}; + +template +struct hasher> { + size_t operator()(const std::pair& key) const { + return Hash()(key.first, key.second); + } +}; + +template +struct hasher> { + size_t operator() (const std::tuple& key) const { + return applyTuple(Hash(), key); + } +}; + // recursion template struct TupleHasher { diff --git a/folly/Range.h b/folly/Range.h index c34d5cfe..1088f466 100644 --- a/folly/Range.h +++ b/folly/Range.h @@ -1133,10 +1133,12 @@ inline size_t qfind_first_of(const Range& haystack, StringPiece(needles)); } -template +template struct hasher; -template struct hasher> { +template +struct hasher, + typename std::enable_if::value, void>::type> { size_t operator()(folly::Range r) const { return hash::SpookyHashV2::Hash64(r.begin(), r.size() * sizeof(T), 0); } diff --git a/folly/test/HashTest.cpp b/folly/test/HashTest.cpp index 435352b7..bbae4f6f 100644 --- a/folly/test/HashTest.cpp +++ b/folly/test/HashTest.cpp @@ -238,6 +238,46 @@ TEST(Hash, std_tuple) { EXPECT_EQ("bar", m[t]); } +TEST(Hash, enum_type) { + const auto hash = folly::Hash(); + + enum class Enum32 : int32_t { Foo, Bar }; + EXPECT_EQ(hash(static_cast(Enum32::Foo)), hash(Enum32::Foo)); + EXPECT_EQ(hash(static_cast(Enum32::Bar)), hash(Enum32::Bar)); + EXPECT_NE(hash(Enum32::Foo), hash(Enum32::Bar)); + + std::unordered_map m32; + m32[Enum32::Foo] = "foo"; + EXPECT_EQ("foo", m32[Enum32::Foo]); + + enum class Enum64 : int64_t { Foo, Bar }; + EXPECT_EQ(hash(static_cast(Enum64::Foo)), hash(Enum64::Foo)); + EXPECT_EQ(hash(static_cast(Enum64::Bar)), hash(Enum64::Bar)); + EXPECT_NE(hash(Enum64::Foo), hash(Enum64::Bar)); + + std::unordered_map m64; + m64[Enum64::Foo] = "foo"; + EXPECT_EQ("foo", m64[Enum64::Foo]); +} + +TEST(Hash, pair_folly_hash) { + typedef std::pair pair2; + pair2 p(42, 1); + + std::unordered_map m; + m[p] = "bar"; + EXPECT_EQ("bar", m[p]); +} + +TEST(Hash, tuple_folly_hash) { + typedef std::tuple tuple3; + tuple3 t(42, 1, 1); + + std::unordered_map m; + m[t] = "bar"; + EXPECT_EQ("bar", m[t]); +} + namespace { template size_t hash_vector(const std::vector& v) { -- 2.34.1