tuple hashing
authorHans Fugal <fugalh@fb.com>
Wed, 17 Jul 2013 01:34:51 +0000 (18:34 -0700)
committerSara Golemon <sgolemon@fb.com>
Thu, 18 Jul 2013 18:55:35 +0000 (11:55 -0700)
Summary:
Add hash support for std::tuple.
See also D490478 (where a first attempt was made) and D543586 (where that attempt was deemed broken and removed).

Test Plan: unit test

Reviewed By: chip@fb.com

FB internal diff: D888796

folly/Hash.h
folly/test/HashTest.cpp

index 132ad846edda98a359107bc8cadd3703d2074a32..cbd07b56ba126cd81efceb2ef1684f1944c87f12 100644 (file)
@@ -21,6 +21,7 @@
 #include <stdint.h>
 #include <string>
 #include <utility>
+#include <tuple>
 
 #include "folly/SpookyHashV1.h"
 #include "folly/SpookyHashV2.h"
@@ -348,6 +349,26 @@ template<> struct hasher<uint64_t> {
   }
 };
 
+// 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.
@@ -361,6 +382,18 @@ namespace std {
       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
index aef8f226e7b2fc4539bad1ee41e9ed1d68909ad0..6ed9a280a1d9ea0a3c58b651be730e94e9650966 100644 (file)
@@ -228,3 +228,12 @@ TEST(Hash, pair) {
 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]);
+}