Don't use identity as hash function for integers.
authorbmeurer@chromium.org <bmeurer@chromium.org>
Mon, 6 Oct 2014 15:23:59 +0000 (15:23 +0000)
committerbmeurer@chromium.org <bmeurer@chromium.org>
Mon, 6 Oct 2014 15:23:59 +0000 (15:23 +0000)
Also slightly improve hashing of floats/doubles.

TEST=unittests
R=jarin@chromium.org

Review URL: https://codereview.chromium.org/632713002

git-svn-id: https://v8.googlecode.com/svn/branches/bleeding_edge@24420 ce2b1a6d-e550-0410-aec6-3dcde31c8c00

src/base/functional.cc
src/base/functional.h
test/unittests/base/functional-unittest.cc

index c4a61adda2452f9203b2b88cf986a58f7f1fea36..4c0f3c8b2af3bf3f16a0286402d895dd9d8c20f9 100644 (file)
@@ -64,6 +64,19 @@ size_t hash_combine(size_t seed, size_t value) {
 }
 
 
+// Thomas Wang, Integer Hash Functions.
+// http://www.concentric.net/~Ttwang/tech/inthash.htm
+size_t hash_value(unsigned int v) {
+  v = ~v + (v << 15);  // v = (v << 15) - v - 1;
+  v = v ^ (v >> 12);
+  v = v + (v << 2);
+  v = v ^ (v >> 4);
+  v = v * 2057;  // v = (v + (v << 3)) + (v << 11);
+  v = v ^ (v >> 16);
+  return v;
+}
+
+
 size_t hash_value(unsigned long v) {  // NOLINT(runtime/int)
   return hash_value_unsigned(v);
 }
@@ -76,13 +89,13 @@ size_t hash_value(unsigned long long v) {  // NOLINT(runtime/int)
 
 size_t hash_value(float v) {
   // 0 and -0 both hash to zero.
-  return v != 0.0f ? hash_value(bit_cast<uint32_t>(v)) : 0;
+  return v != 0.0f ? hash_value_unsigned(bit_cast<uint32_t>(v)) : 0;
 }
 
 
 size_t hash_value(double v) {
   // 0 and -0 both hash to zero.
-  return v != 0.0 ? hash_value(bit_cast<uint64_t>(v)) : 0;
+  return v != 0.0 ? hash_value_unsigned(bit_cast<uint64_t>(v)) : 0;
 }
 
 }  // namespace base
index 60f93ddad5dfbac1059c32d1f58cbac0402258ef..d815c7214226cfd2e45c002144dac486d39ab59f 100644 (file)
@@ -76,11 +76,11 @@ inline size_t hash_combine(T const& v, Ts const&... vs) {
 V8_BASE_HASH_VALUE_TRIVIAL(bool)
 V8_BASE_HASH_VALUE_TRIVIAL(unsigned char)
 V8_BASE_HASH_VALUE_TRIVIAL(unsigned short)  // NOLINT(runtime/int)
-V8_BASE_HASH_VALUE_TRIVIAL(unsigned int)
 #undef V8_BASE_HASH_VALUE_TRIVIAL
 
-size_t hash_value(unsigned long v);       // NOLINT(runtime/int)
-size_t hash_value(unsigned long long v);  // NOLINT(runtime/int)
+size_t hash_value(unsigned int);
+size_t hash_value(unsigned long);       // NOLINT(runtime/int)
+size_t hash_value(unsigned long long);  // NOLINT(runtime/int)
 
 #define V8_BASE_HASH_VALUE_SIGNED(type)            \
   inline size_t hash_value(signed type v) {        \
index e6f260f2b8da68d2f9cb10b71f958641f9c4628c..4015485a88d1d0dfb38ca50a424f09c0b4af69a7 100644 (file)
@@ -83,7 +83,7 @@ TYPED_TEST(FunctionalTest, HashIsStateless) {
 
 TYPED_TEST(FunctionalTest, HashIsOkish) {
   const size_t kValues = 128;
-  const size_t kMinHashes = kValues / (sizeof(uint64_t) / sizeof(size_t));
+  const size_t kMinHashes = kValues / 4;
   std::set<TypeParam> vs;
   while (vs.size() != kValues) {
     TypeParam v;