Pass key_hash to guf_dict_find_idx to avoid re-computation

This commit is contained in:
jun 2025-03-19 17:03:12 +01:00
parent b01e087c85
commit 1e534731bb

View File

@ -313,18 +313,18 @@ static inline size_t GUF_CAT(GUF_DICT_NAME, _probe_offset)(size_t probe_len)
#endif #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) { if (ht->kv_indices_cap <= 0) {
*key_exists = false; *key_exists = false;
return SIZE_T_MAX; 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) */ #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; const size_t start_idx = idx;
size_t first_tombstone_idx = SIZE_T_MAX; size_t first_tombstone_idx = SIZE_T_MAX;
size_t probe_len = 0; 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; first_tombstone_idx = idx;
} }
goto probe; 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); ht->max_probelen = GUF_MAX((ptrdiff_t)probe_len, ht->max_probelen);
*key_exists = true; *key_exists = true;
return idx; 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:
++probe_len; ++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. 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); const GUF_DICT_KV_NAME *kv = GUF_CAT(GUF_DICT_KV_DBUF, _at)(&ht->kv_elems, kv_idx);
GUF_ASSERT(kv); GUF_ASSERT(kv);
bool key_exists = false; 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(!key_exists);
GUF_ASSERT(new_idx < SIZE_T_MAX && new_idx < (size_t)ht->kv_indices_cap); 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); 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; 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. // 2.) Insert new key-value pair.
const GUF_DICT_HASH_T key_hash = GUF_DICT_KEY_HASH(key); const GUF_DICT_HASH_T key_hash = GUF_DICT_KEY_HASH(key);
bool key_exists = false; 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) { if (key_exists) {
guf_err_set_or_panic(err, GUF_ERR_ALREADY_EXISTS, GUF_ERR_MSG("in function dict_try_insert: Key already exists")); guf_err_set_or_panic(err, GUF_ERR_ALREADY_EXISTS, GUF_ERR_MSG("in function dict_try_insert: Key already exists"));
return; return;
@ -574,15 +574,16 @@ GUF_DICT_KWRDS void GUF_CAT(GUF_DICT_NAME, _insert_val_arg)(GUF_DICT_NAME *ht, G
if (!key) { if (!key) {
return NULL; return NULL;
} }
const GUF_DICT_HASH_T key_hash = GUF_DICT_KEY_HASH(key);
bool key_exists = false; 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) { if (!key_exists) {
return NULL; return NULL;
} else { } else {
GUF_ASSERT(idx != SIZE_T_MAX); GUF_ASSERT(idx != SIZE_T_MAX);
GUF_ASSERT((ptrdiff_t)idx < ht->kv_indices_cap); GUF_ASSERT((ptrdiff_t)idx < ht->kv_indices_cap);
const size_t kv_idx = GUF_DICT_META_GET_IDX(ht->kv_indices[idx]); 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; 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; return false;
} }
bool key_exists = 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) { if (key_exists) {
GUF_ASSERT(idx != SIZE_T_MAX); GUF_ASSERT(idx != SIZE_T_MAX);
GUF_ASSERT(!GUF_DICT_META_IS_TOMBSTONE(ht->kv_indices[idx])); 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; return false;
} }
const GUF_DICT_HASH_T key_hash = GUF_DICT_KEY_HASH(key);
bool key_exists = false; 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) { if (!key_exists) {
return false; 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)); // GUF_ASSERT(!GUF_DICT_KEY_T_EQ(key, &last_kv->key));
// 2.) Update kv_index. // 2.) Update kv_index.
const GUF_DICT_HASH_T last_key_hash = GUF_DICT_KEY_HASH(&last_kv->key);
bool last_key_exists = false; 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_idx != idx);
GUF_ASSERT(last_key_exists && (ptrdiff_t)last_idx < ht->kv_indices_cap); 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)); GUF_ASSERT(GUF_DICT_META_GET_IDX(ht->kv_indices[last_idx]) == (GUF_DICT_KV_META_T)(ht->kv_elems.size - 1));