From c76e0ae685403f7979338ac1a70a17ba93093525 Mon Sep 17 00:00:00 2001 From: Felix Riedel Date: Tue, 22 Dec 2020 21:51:16 +0000 Subject: [PATCH] Use boost's way of combining hash values for arrays and kv pairs. `seed ^= hash_value(v) + 0x9e3779b9 + (seed << 6) + (seed >> 2);` from https://www.boost.org/doc/libs/1_35_0/doc/html/boost/hash_combine_id241013.html The current way of combining hashes peforms poorly on hash values of numbers. Changing the way hashes are combined canlead to a significant speed up: ``` time janet_new -e '(def tbl @{}) (loop [x :in (range 1000) y :in (range 1000)] (put tbl {0 x 1 y} true))' 3.77s user 0.08s system 99% cpu 3.843 total time janet_orig -e '(def tbl @{}) (loop [x :in (range 1000) y :in (range 1000)] (put tbl {0 x 1 y} true))' 48.98s user 0.15s system 99% cpu 49.136 total ``` --- src/core/util.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/src/core/util.c b/src/core/util.c index e2257759..275f5299 100644 --- a/src/core/util.c +++ b/src/core/util.c @@ -227,19 +227,21 @@ int32_t janet_string_calchash(const uint8_t *str, int32_t len) { /* Computes hash of an array of values */ int32_t janet_array_calchash(const Janet *array, int32_t len) { const Janet *end = array + len; - uint32_t hash = 5381; - while (array < end) - hash = (hash << 5) + hash + janet_hash(*array++); + uint32_t hash = 0; + while (array < end) { + uint32_t elem = janet_hash(*array++); + hash ^= elem + 0x9e3779b9 + (hash<<6) + (hash>>2); + } return (int32_t) hash; } /* Computes hash of an array of values */ int32_t janet_kv_calchash(const JanetKV *kvs, int32_t len) { const JanetKV *end = kvs + len; - uint32_t hash = 5381; + uint32_t hash = 0; while (kvs < end) { - hash = (hash << 5) + hash + janet_hash(kvs->key); - hash = (hash << 5) + hash + janet_hash(kvs->value); + hash ^= janet_hash(kvs->key) + 0x9e3779b9 + (hash<<6) + (hash>>2); + hash ^= janet_hash(kvs->value) + 0x9e3779b9 + (hash<<6) + (hash>>2); kvs++; } return (int32_t) hash;