From 1e534731bb0b5fcac5759929a1692530256546d4 Mon Sep 17 00:00:00 2001 From: jun <83899451+zeichensystem@users.noreply.github.com> Date: Wed, 19 Mar 2025 17:03:12 +0100 Subject: [PATCH] Pass key_hash to guf_dict_find_idx to avoid re-computation --- src/guf_dict.h | 32 ++++++++++++++++++-------------- 1 file changed, 18 insertions(+), 14 deletions(-) diff --git a/src/guf_dict.h b/src/guf_dict.h index f6c4eb7..42b2f78 100755 --- a/src/guf_dict.h +++ b/src/guf_dict.h @@ -313,18 +313,18 @@ static inline size_t GUF_CAT(GUF_DICT_NAME, _probe_offset)(size_t probe_len) #endif } -static size_t GUF_CAT(GUF_DICT_NAME, _find_idx)(GUF_DICT_NAME *ht, const GUF_DICT_KEY_T *key, bool *key_exists) +static size_t GUF_CAT(GUF_DICT_NAME, _find_idx)(GUF_DICT_NAME *ht, const GUF_DICT_KEY_T *key, GUF_DICT_HASH_T key_hash, bool *key_exists) { if (ht->kv_indices_cap <= 0) { *key_exists = false; return SIZE_T_MAX; } - const GUF_DICT_HASH_T hash = GUF_DICT_KEY_HASH(key); - const GUF_DICT_KV_META_T hash_frag = GUF_DICT_HASH_T_GET_HASHFRAG(hash); + + const GUF_DICT_KV_META_T key_hash_frag = GUF_DICT_HASH_T_GET_HASHFRAG(key_hash); #define GUF_MOD_CAP(A) ((size_t)(A) & (size_t)(ht->kv_indices_cap - 1)) /* A % ht->kv_indices_cap (kv_indices_cap must be a power of two > 0) */ - size_t idx = GUF_MOD_CAP(hash); + size_t idx = GUF_MOD_CAP(key_hash); const size_t start_idx = idx; size_t first_tombstone_idx = SIZE_T_MAX; size_t probe_len = 0; @@ -345,11 +345,11 @@ static size_t GUF_CAT(GUF_DICT_NAME, _find_idx)(GUF_DICT_NAME *ht, const GUF_DIC first_tombstone_idx = idx; } goto probe; - } else if (hash_frag == kv_hashfrag && GUF_DICT_KEY_T_EQ(key, &(GUF_CAT(GUF_DICT_KV_DBUF, _at)(&ht->kv_elems, kv_idx)->key))) { // 3.) Key already exists. + } else if (key_hash_frag == kv_hashfrag && GUF_DICT_KEY_T_EQ(key, &(GUF_CAT(GUF_DICT_KV_DBUF, _at)(&ht->kv_elems, kv_idx)->key))) { // 3.) Key already exists. ht->max_probelen = GUF_MAX((ptrdiff_t)probe_len, ht->max_probelen); *key_exists = true; return idx; - } else { // 4.) Have to probe due to hash-collision/tombstone. + } else { // 4.) Probe because kv_idx was a tombstone or because key != kv_elems[kv_idx] probe: ++probe_len; idx = GUF_MOD_CAP(start_idx + GUF_CAT(GUF_DICT_NAME, _probe_offset)(probe_len)); // NOTE: Add probe_offset to start_idx and not to idx. @@ -432,10 +432,10 @@ static void GUF_CAT(GUF_DICT_NAME, _try_grow_if_necessary)(GUF_DICT_NAME *ht, gu const GUF_DICT_KV_NAME *kv = GUF_CAT(GUF_DICT_KV_DBUF, _at)(&ht->kv_elems, kv_idx); GUF_ASSERT(kv); bool key_exists = false; - const size_t new_idx = GUF_CAT(GUF_DICT_NAME, _find_idx)(ht, &kv->key, &key_exists); + const GUF_DICT_HASH_T key_hash = GUF_DICT_KEY_HASH(&kv->key); // TODO: might be expensive... + const size_t new_idx = GUF_CAT(GUF_DICT_NAME, _find_idx)(ht, &kv->key, key_hash, &key_exists); GUF_ASSERT(!key_exists); GUF_ASSERT(new_idx < SIZE_T_MAX && new_idx < (size_t)ht->kv_indices_cap); - const GUF_DICT_HASH_T key_hash = GUF_DICT_KEY_HASH(&kv->key); // TODO: might be expensive... GUF_ASSERT((GUF_DICT_HASH_T_GET_HASHFRAG(key_hash) & (GUF_DICT_KV_META_T)kv_idx) == 0); ht->kv_indices[new_idx] = GUF_DICT_HASH_T_GET_HASHFRAG(key_hash) | (GUF_DICT_KV_META_T)kv_idx; } @@ -471,7 +471,7 @@ GUF_DICT_KWRDS void GUF_CAT(GUF_DICT_NAME, _try_insert)(GUF_DICT_NAME *ht, GUF_D // 2.) Insert new key-value pair. const GUF_DICT_HASH_T key_hash = GUF_DICT_KEY_HASH(key); bool key_exists = false; - size_t idx = GUF_CAT(GUF_DICT_NAME, _find_idx)(ht, key, &key_exists); + size_t idx = GUF_CAT(GUF_DICT_NAME, _find_idx)(ht, key, key_hash, &key_exists); if (key_exists) { guf_err_set_or_panic(err, GUF_ERR_ALREADY_EXISTS, GUF_ERR_MSG("in function dict_try_insert: Key already exists")); return; @@ -574,15 +574,16 @@ GUF_DICT_KWRDS void GUF_CAT(GUF_DICT_NAME, _insert_val_arg)(GUF_DICT_NAME *ht, G if (!key) { return NULL; } + const GUF_DICT_HASH_T key_hash = GUF_DICT_KEY_HASH(key); bool key_exists = false; - const size_t idx = GUF_CAT(GUF_DICT_NAME, _find_idx)(ht, key, &key_exists); + const size_t idx = GUF_CAT(GUF_DICT_NAME, _find_idx)(ht, key, key_hash, &key_exists); if (!key_exists) { return NULL; } else { GUF_ASSERT(idx != SIZE_T_MAX); GUF_ASSERT((ptrdiff_t)idx < ht->kv_indices_cap); const size_t kv_idx = GUF_DICT_META_GET_IDX(ht->kv_indices[idx]); - GUF_ASSERT((ptrdiff_t)kv_idx < ht->kv_elems.size); + GUF_ASSERT(kv_idx <= PTRDIFF_MAX && (ptrdiff_t)kv_idx < ht->kv_elems.size); return &GUF_CAT(GUF_DICT_KV_DBUF, _at)(&ht->kv_elems, kv_idx)->val; } } @@ -601,7 +602,8 @@ GUF_DICT_KWRDS bool GUF_CAT(GUF_DICT_NAME, _contains)(GUF_DICT_NAME *ht, const G return false; } bool key_exists = false; - const size_t idx = GUF_CAT(GUF_DICT_NAME, _find_idx)(ht, key, &key_exists); + const GUF_DICT_HASH_T key_hash = GUF_DICT_KEY_HASH(key); + const size_t idx = GUF_CAT(GUF_DICT_NAME, _find_idx)(ht, key, key_hash, &key_exists); if (key_exists) { GUF_ASSERT(idx != SIZE_T_MAX); GUF_ASSERT(!GUF_DICT_META_IS_TOMBSTONE(ht->kv_indices[idx])); @@ -625,8 +627,9 @@ GUF_DICT_KWRDS bool GUF_CAT(GUF_DICT_NAME, _erase)(GUF_DICT_NAME *ht, const GUF_ return false; } + const GUF_DICT_HASH_T key_hash = GUF_DICT_KEY_HASH(key); bool key_exists = false; - const size_t idx = GUF_CAT(GUF_DICT_NAME, _find_idx)(ht, key, &key_exists); + const size_t idx = GUF_CAT(GUF_DICT_NAME, _find_idx)(ht, key, key_hash, &key_exists); if (!key_exists) { return false; } @@ -653,8 +656,9 @@ GUF_DICT_KWRDS bool GUF_CAT(GUF_DICT_NAME, _erase)(GUF_DICT_NAME *ht, const GUF_ // GUF_ASSERT(!GUF_DICT_KEY_T_EQ(key, &last_kv->key)); // 2.) Update kv_index. + const GUF_DICT_HASH_T last_key_hash = GUF_DICT_KEY_HASH(&last_kv->key); bool last_key_exists = false; - const size_t last_idx = GUF_CAT(GUF_DICT_NAME, _find_idx)(ht, &last_kv->key, &last_key_exists); + const size_t last_idx = GUF_CAT(GUF_DICT_NAME, _find_idx)(ht, &last_kv->key, last_key_hash, &last_key_exists); GUF_ASSERT(last_idx != idx); GUF_ASSERT(last_key_exists && (ptrdiff_t)last_idx < ht->kv_indices_cap); GUF_ASSERT(GUF_DICT_META_GET_IDX(ht->kv_indices[last_idx]) == (GUF_DICT_KV_META_T)(ht->kv_elems.size - 1));