#include <utility>
#include <tuple>
+#include <folly/ApplyTuple.h>
#include <folly/SpookyHashV1.h>
#include <folly/SpookyHashV2.h>
} // namespace hash
-template<class Key>
+template<class Key, class Enable = void>
struct hasher;
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> {
}
};
+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 {
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);
}
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) {