From: Subodh Iyengar Date: Sun, 23 Jul 2017 18:15:06 +0000 (-0700) Subject: Add fnv1-a hash to Hash X-Git-Tag: v2017.07.24.00~2 X-Git-Url: http://plrg.eecs.uci.edu/git/?a=commitdiff_plain;ds=sidebyside;h=b3698ed449d35f1c70a9671cf26c13d0e41e9f89;p=folly.git Add fnv1-a hash to Hash Summary: Add fnv1-a 64 bit hash to Hash.h. fnv1-a is supposed to be preferred over fnv1. Reviewed By: yfeldblum Differential Revision: D5453401 fbshipit-source-id: c13f12ef11eb6745c95f3901b14ceafce90ea0ea --- diff --git a/folly/Hash.h b/folly/Hash.h index 77ba5878..90492180 100644 --- a/folly/Hash.h +++ b/folly/Hash.h @@ -214,6 +214,7 @@ inline uint32_t jenkins_rev_unmix32(uint32_t key) { const uint32_t FNV_32_HASH_START = 2166136261UL; const uint64_t FNV_64_HASH_START = 14695981039346656037ULL; +const uint64_t FNVA_64_HASH_START = 14695981039346656037ULL; inline uint32_t fnv32(const char* buf, uint32_t hash = FNV_32_HASH_START) { // forcing signed char, since other platforms can use unsigned @@ -278,6 +279,24 @@ inline uint64_t fnv64(const std::string& str, return fnv64_buf(str.data(), str.size(), hash); } +inline uint64_t fnva64_buf(const void* buf, + size_t n, + uint64_t hash = FNVA_64_HASH_START) { + const uint8_t* char_buf = reinterpret_cast(buf); + + for (size_t i = 0; i < n; ++i) { + hash ^= char_buf[i]; + hash += (hash << 1) + (hash << 4) + (hash << 5) + (hash << 7) + + (hash << 8) + (hash << 40); + } + return hash; +} + +inline uint64_t fnva64(const std::string& str, + uint64_t hash = FNVA_64_HASH_START) { + return fnva64_buf(str.data(), str.size(), hash); +} + /* * Paul Hsieh: http://www.azillionmonkeys.com/qed/hash.html */ diff --git a/folly/test/HashTest.cpp b/folly/test/HashTest.cpp index 01cbf2e3..070cf78f 100644 --- a/folly/test/HashTest.cpp +++ b/folly/test/HashTest.cpp @@ -376,3 +376,45 @@ TEST(Hash, Strings) { EXPECT_EQ(h2(a3), h2(a3.str())); EXPECT_EQ(h2(a4), h2(a4.str())); } + +struct FNVTestParam { + std::string in; + uint64_t out; +}; + +class FNVTest : public ::testing::TestWithParam {}; + +TEST_P(FNVTest, Fnva64Buf) { + EXPECT_EQ(GetParam().out, + fnva64_buf(GetParam().in.data(), GetParam().in.size())); +} + +TEST_P(FNVTest, Fnva64) { + EXPECT_EQ(GetParam().out, fnva64(GetParam().in)); +} + +TEST_P(FNVTest, Fnva64Partial) { + size_t partialLen = GetParam().in.size() / 2; + auto data = GetParam().in.data(); + auto partial = fnva64_buf(data, partialLen); + EXPECT_EQ(GetParam().out, + fnva64_buf( + data + partialLen, GetParam().in.size() - partialLen, partial)); +} + +// Taken from http://www.isthe.com/chongo/src/fnv/test_fnv.c +INSTANTIATE_TEST_CASE_P( + FNVTesting, + FNVTest, + ::testing::Values( + (FNVTestParam){"foobar", // 11 + 0x85944171f73967e8}, + (FNVTestParam){"chongo was here!\n", // 39 + 0x46810940eff5f915}, + (FNVTestParam){"127.0.0.3", // 106, + 0xaabafc7104d91158}, + (FNVTestParam){ + "http://en.wikipedia.org/wiki/Fowler_Noll_Vo_hash", // 126 + 0xd9b957fb7fe794c5}, + (FNVTestParam){"http://norvig.com/21-days.html", // 136 + 0x07aaa640476e0b9a}));