#include <stdint.h>
#include <string>
#include <utility>
+#include <tuple>
#include "folly/SpookyHashV1.h"
#include "folly/SpookyHashV2.h"
}
};
+// recursion
+template <size_t index, typename... Ts>
+struct TupleHasher {
+ size_t operator()(std::tuple<Ts...> const& key) const {
+ return hash::hash_combine(
+ TupleHasher<index - 1, Ts...>()(key),
+ std::get<index>(key));
+ }
+};
+
+// base
+template <typename... Ts>
+struct TupleHasher<0, Ts...> {
+ size_t operator()(std::tuple<Ts...> const& key) const {
+ // we could do std::hash here directly, but hash_combine hides all the
+ // ugly templating implicitly
+ return hash::hash_combine(std::get<0>(key));
+ }
+};
+
} // namespace folly
// Custom hash functions.
return folly::hash::hash_combine(x.first, x.second);
}
};
+
+ // Hash function for tuples. Requires default hash functions for all types.
+ template <typename... Ts>
+ struct hash<std::tuple<Ts...>> {
+ size_t operator()(std::tuple<Ts...> const& key) const {
+ folly::TupleHasher<
+ std::tuple_size<std::tuple<Ts...>>::value - 1, // start index
+ Ts...> hasher;
+
+ return hasher(key);
+ }
+ };
} // namespace std
#endif
TEST(Hash, hash_combine) {
EXPECT_NE(hash_combine(1, 2), hash_combine(2, 1));
}
+
+TEST(Hash, std_tuple) {
+ typedef std::tuple<int64_t, std::string, int32_t> tuple3;
+ tuple3 t(42, "foo", 1);
+
+ std::unordered_map<tuple3, std::string> m;
+ m[t] = "bar";
+ EXPECT_EQ("bar", m[t]);
+}