atom: use a better hash function
authorRan Benita <ran@unusedvar.com>
Sat, 9 Nov 2019 10:43:04 +0000 (12:43 +0200)
committerRan Benita <ran@unusedvar.com>
Sat, 9 Nov 2019 11:01:43 +0000 (13:01 +0200)
FNV-1a instead of the djb2-like one from before.

Keep the unrolling since it seems quite beneficial, even though it loses
one byte if the length is odd...

Signed-off-by: Ran Benita <ran@unusedvar.com>
src/atom.c

index cebc2e7..09f6e6a 100644 (file)
 #include "utils.h"
 #include "atom.h"
 
+/* FNV-1a (http://www.isthe.com/chongo/tech/comp/fnv/). */
+static inline uint32_t
+hash_buf(const char *string, size_t len)
+{
+    uint32_t hash = 2166136261u;
+    for (size_t i = 0; i < len / 2; i++) {
+        hash ^= (uint8_t) string[i];
+        hash *= 0x01000193;
+        hash ^= (uint8_t) string[len - 1 - i];
+        hash *= 0x01000193;
+    }
+    return hash;
+}
+
 struct atom_node {
     xkb_atom_t left, right;
     uint32_t fingerprint;
@@ -122,11 +136,7 @@ static bool
 find_atom_pointer(struct atom_table *table, const char *string, size_t len,
                   xkb_atom_t **atomp_out, uint32_t *fingerprint_out)
 {
-    uint32_t fingerprint = 0;
-    for (size_t i = 0; i < (len + 1) / 2; i++) {
-        fingerprint = fingerprint * 27 + string[i];
-        fingerprint = fingerprint * 27 + string[len - 1 - i];
-    }
+    uint32_t fingerprint = hash_buf(string, len);
 
     xkb_atom_t *atomp = &table->root;
     while (*atomp != XKB_ATOM_NONE) {