Commit 879db739 authored by Alexander Shaposhnikov's avatar Alexander Shaposhnikov Committed by facebook-github-bot-1

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
parent 408bb708
......@@ -23,6 +23,7 @@
#include <utility>
#include <tuple>
#include <folly/ApplyTuple.h>
#include <folly/SpookyHashV1.h>
#include <folly/SpookyHashV2.h>
......@@ -335,7 +336,7 @@ inline uint32_t hsieh_hash32_str(const std::string& str) {
} // namespace hash
template<class Key>
template<class Key, class Enable = void>
struct hasher;
struct Hash {
......@@ -343,6 +344,11 @@ struct Hash {
size_t operator()(const T& v) const {
return hasher<T>()(v);
}
template <class T, class... Ts>
size_t operator()(const T& t, const Ts&... ts) const {
return hash::hash_128_to_64((*this)(t), (*this)(ts...));
}
};
template<> struct hasher<int32_t> {
......@@ -369,6 +375,27 @@ template<> struct hasher<uint64_t> {
}
};
template <class T>
struct hasher<T, typename std::enable_if<std::is_enum<T>::value, void>::type> {
size_t operator()(T key) const {
return Hash()(static_cast<typename std::underlying_type<T>::type>(key));
}
};
template <class T1, class T2>
struct hasher<std::pair<T1, T2>> {
size_t operator()(const std::pair<T1, T2>& key) const {
return Hash()(key.first, key.second);
}
};
template <typename... Ts>
struct hasher<std::tuple<Ts...>> {
size_t operator() (const std::tuple<Ts...>& key) const {
return applyTuple(Hash(), key);
}
};
// recursion
template <size_t index, typename... Ts>
struct TupleHasher {
......
......@@ -1133,10 +1133,12 @@ inline size_t qfind_first_of(const Range<const unsigned char*>& haystack,
StringPiece(needles));
}
template<class Key>
template<class Key, class Enable>
struct hasher;
template <class T> struct hasher<folly::Range<T*>> {
template <class T>
struct hasher<folly::Range<T*>,
typename std::enable_if<std::is_pod<T>::value, void>::type> {
size_t operator()(folly::Range<T*> r) const {
return hash::SpookyHashV2::Hash64(r.begin(), r.size() * sizeof(T), 0);
}
......
......@@ -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<int32_t>(Enum32::Foo)), hash(Enum32::Foo));
EXPECT_EQ(hash(static_cast<int32_t>(Enum32::Bar)), hash(Enum32::Bar));
EXPECT_NE(hash(Enum32::Foo), hash(Enum32::Bar));
std::unordered_map<Enum32, std::string, folly::Hash> m32;
m32[Enum32::Foo] = "foo";
EXPECT_EQ("foo", m32[Enum32::Foo]);
enum class Enum64 : int64_t { Foo, Bar };
EXPECT_EQ(hash(static_cast<int64_t>(Enum64::Foo)), hash(Enum64::Foo));
EXPECT_EQ(hash(static_cast<int64_t>(Enum64::Bar)), hash(Enum64::Bar));
EXPECT_NE(hash(Enum64::Foo), hash(Enum64::Bar));
std::unordered_map<Enum64, std::string, folly::Hash> m64;
m64[Enum64::Foo] = "foo";
EXPECT_EQ("foo", m64[Enum64::Foo]);
}
TEST(Hash, pair_folly_hash) {
typedef std::pair<int64_t, int32_t> pair2;
pair2 p(42, 1);
std::unordered_map<pair2, std::string, folly::Hash> m;
m[p] = "bar";
EXPECT_EQ("bar", m[p]);
}
TEST(Hash, tuple_folly_hash) {
typedef std::tuple<int64_t, int32_t, int32_t> tuple3;
tuple3 t(42, 1, 1);
std::unordered_map<tuple3, std::string, folly::Hash> m;
m[t] = "bar";
EXPECT_EQ("bar", m[t]);
}
namespace {
template <class T>
size_t hash_vector(const std::vector<T>& v) {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment