From: Ognjen Dragoljevic Date: Mon, 16 Oct 2017 14:24:15 +0000 (-0700) Subject: Fix hash overloads for integral types X-Git-Tag: v2017.10.23.00~42 X-Git-Url: http://demsky.eecs.uci.edu/git/?a=commitdiff_plain;h=4e2b0bb9a93dfd83b9dd74899463c2da5b33ab54;p=folly.git Fix hash overloads for integral types Summary: `folly/Hash.h:379:12: error: implicit instantiation of undefined template 'folly::hasher'` So, folly is unable to hash the very type it returns: `size_t`. Namely, folly has overloads for `uint32_t` and `uint64_t` which on my Mac map to `int` and `long long` respectively. `size_t` on the other hand maps to `long` which is neither. Rather than overloading library types (which are just typedefs), we should overload all the built-in types: `char`, `short`, `int`, `long`, `long long`, `signed` and `unsigned` variants (with special treatment of `char`). Reviewed By: yfeldblum, luciang Differential Revision: D6051600 fbshipit-source-id: d59569dab963cbe0329aa589ff321cfb22308193 --- diff --git a/folly/Hash.h b/folly/Hash.h index 211dc44e..6d277c16 100644 --- a/folly/Hash.h +++ b/folly/Hash.h @@ -370,6 +370,21 @@ inline uint32_t hsieh_hash32_str(const std::string& str) { } // namespace hash +namespace detail { +template +size_t integral_hash(I const& i) { + static_assert(sizeof(I) <= 8, "input type is too wide"); + if (sizeof(I) <= 4) { // the branch taken is known at compile time + auto const i32 = static_cast(i); // as impl accident, sign-extends + auto const u32 = static_cast(i32); + return static_cast(hash::jenkins_rev_mix32(u32)); + } else { + auto const u64 = static_cast(i); + return static_cast(hash::twang_mix64(u64)); + } +} +} // namespace detail + template struct hasher; @@ -393,59 +408,85 @@ struct hasher { } }; -template <> struct hasher { - size_t operator()(int32_t key) const { - return hash::jenkins_rev_mix32(uint32_t(key)); +template <> +struct hasher { + size_t operator()(unsigned long long key) const { + return detail::integral_hash(key); } }; -template <> struct hasher { - size_t operator()(uint32_t key) const { - return hash::jenkins_rev_mix32(key); +template <> +struct hasher { + size_t operator()(signed long long key) const { + return detail::integral_hash(key); } }; -template <> struct hasher { - size_t operator()(int16_t key) const { - return hasher()(key); // as impl accident, sign-extends +template <> +struct hasher { + size_t operator()(unsigned long key) const { + return detail::integral_hash(key); } }; -template <> struct hasher { - size_t operator()(uint16_t key) const { - return hasher()(key); +template <> +struct hasher { + size_t operator()(signed long key) const { + return detail::integral_hash(key); } }; -template <> struct hasher { - size_t operator()(int8_t key) const { - return hasher()(key); // as impl accident, sign-extends +template <> +struct hasher { + size_t operator()(unsigned int key) const { + return detail::integral_hash(key); } }; -template <> struct hasher { - size_t operator()(uint8_t key) const { - return hasher()(key); +template <> +struct hasher { + size_t operator()(signed int key) const { + return detail::integral_hash(key); } }; -template <> struct hasher { - using explicit_type = - std::conditional::value, int8_t, uint8_t>::type; - size_t operator()(char key) const { - return hasher()(key); // as impl accident, sign-extends +template <> +struct hasher { + size_t operator()(unsigned short key) const { + return detail::integral_hash(key); } }; -template <> struct hasher { - size_t operator()(int64_t key) const { - return static_cast(hash::twang_mix64(uint64_t(key))); +template <> +struct hasher { + size_t operator()(signed short key) const { + return detail::integral_hash(key); + } +}; + +template <> +struct hasher { + size_t operator()(unsigned char key) const { + return detail::integral_hash(key); } }; -template <> struct hasher { - size_t operator()(uint64_t key) const { - return static_cast(hash::twang_mix64(key)); +template <> +struct hasher { + size_t operator()(signed char key) const { + return detail::integral_hash(key); + } +}; + +// char is different type from both signed char and unsigned char. +template <> +struct hasher { + using explicit_type = std::conditional< + std::is_signed::value, + signed char, + unsigned char>::type; + size_t operator()(char key) const { + return detail::integral_hash(explicit_type(key)); } }; diff --git a/folly/test/HashTest.cpp b/folly/test/HashTest.cpp index dd03242b..759f9975 100644 --- a/folly/test/HashTest.cpp +++ b/folly/test/HashTest.cpp @@ -19,6 +19,7 @@ #include #include #include +#include #include using namespace folly::hash; @@ -185,6 +186,37 @@ TEST(Hash, hasher) { EXPECT_EQ(get_default(m, 4), 5); } +TEST(Hash, integral_types) { + // Basically just confirms that things compile ok. + std::unordered_set hashes; + folly::Hash hasher; + hashes.insert(hasher((char)1)); + hashes.insert(hasher((signed char)2)); + hashes.insert(hasher((unsigned char)3)); + hashes.insert(hasher((short)4)); + hashes.insert(hasher((signed short)5)); + hashes.insert(hasher((unsigned short)6)); + hashes.insert(hasher((int)7)); + hashes.insert(hasher((signed int)8)); + hashes.insert(hasher((unsigned int)9)); + hashes.insert(hasher((long)10)); + hashes.insert(hasher((signed long)11)); + hashes.insert(hasher((unsigned long)12)); + hashes.insert(hasher((long long)13)); + hashes.insert(hasher((signed long long)14)); + hashes.insert(hasher((unsigned long long)15)); + hashes.insert(hasher((int8_t)16)); + hashes.insert(hasher((uint8_t)17)); + hashes.insert(hasher((int16_t)18)); + hashes.insert(hasher((uint16_t)19)); + hashes.insert(hasher((int32_t)20)); + hashes.insert(hasher((uint32_t)21)); + hashes.insert(hasher((int64_t)22)); + hashes.insert(hasher((uint64_t)23)); + hashes.insert(hasher((size_t)24)); + EXPECT_EQ(24, hashes.size()); +} + // Not a full hasher since only handles one type class TestHasher { public: