From 16b4af3b138fa58614fc7452614802b71a0c2236 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Henrik=20Grubbstr=C3=B6m=20=28Grubba=29?=
 <grubba@grubba.org>
Date: Wed, 27 Aug 2014 21:06:41 +0200
Subject: [PATCH] Cyclic: Change to a power of two hash table.

The hash table used by BEGIN_CYCLIC() et al now has a size that
is a power of 2, so that we can avoid the modulo operation.

The hash function is also modified somewhat to improve its entropy.
---
 src/cyclic.c | 22 +++++++++++++++++++---
 1 file changed, 19 insertions(+), 3 deletions(-)

diff --git a/src/cyclic.c b/src/cyclic.c
index 6715437414..f09f86fb1b 100644
--- a/src/cyclic.c
+++ b/src/cyclic.c
@@ -7,7 +7,7 @@
 #include "global.h"
 #include "cyclic.h"
 
-#define CYCLIC_HASH_SIZE 4711
+#define CYCLIC_HASH_SIZE 0x1000
 
 static CYCLIC *cyclic_hash[CYCLIC_HASH_SIZE];
 
@@ -22,9 +22,25 @@ static size_t cyclic_hash_func(CYCLIC *c)
   h ^= PTR_TO_INT(c->b);
   h *= 33;
   h ^= PTR_TO_INT(c->th);
-  h *= 33;
 
-  return h % CYCLIC_HASH_SIZE;
+#if SIZEOF_CHAR_P > 4
+  h ^= h>>8;
+#endif
+  /* Fold h. This is to retain as many bits of h as possible.
+   *
+   * NB: The "magic" constant below has a 1 bit every 10 bits
+   *     starting at the least significant, and is == 1 when
+   *     shifted right 20 bits. Note also that 32 - 20 == 12
+   *     and 1<<12 == 0x1000 == CYCLIC_HASH_SIZE.
+   *
+   *     The multiplication has the effect of accumulating
+   *     the segments of 10 bits of h in the most significant
+   *     segment, which is then shifted down.
+   */
+  h *= 0x100401;
+  h >>= 20;
+
+  return h & (CYCLIC_HASH_SIZE-1);
 }
 
 static void low_unlink_cyclic(CYCLIC *c)
-- 
GitLab