Add guf_dict_shrink_capacity

This commit is contained in:
jun 2025-03-28 18:28:27 +01:00
parent 3ff4cd7572
commit 9e0cd79ca0

View File

@ -165,6 +165,15 @@ GUF_DICT_KWRDS double GUF_CAT(GUF_DICT_NAME, _load_factor_without_tombstones)(co
GUF_DICT_KWRDS void GUF_CAT(GUF_DICT_NAME, _try_rehash_and_grow)(GUF_DICT_NAME *ht, guf_err *err);
GUF_DICT_KWRDS void GUF_CAT(GUF_DICT_NAME, _rehash_without_growth)(GUF_DICT_NAME *ht);
GUF_DICT_KWRDS void GUF_CAT(GUF_DICT_NAME, _try_shrink_to_fit)(GUF_DICT_NAME *ht, guf_err *err);
GUF_DICT_KWRDS void GUF_CAT(GUF_DICT_NAME, _shrink_to_fit)(GUF_DICT_NAME *ht);
GUF_DICT_KWRDS ptrdiff_t GUF_CAT(GUF_DICT_NAME, _max_capacity)(void);
GUF_DICT_KWRDS size_t GUF_CAT(GUF_DICT_NAME, _memory_usage)(const GUF_DICT_NAME *ht);
GUF_DICT_KWRDS bool GUF_CAT(GUF_DICT_NAME, _valid)(const GUF_DICT_NAME *ht);
GUF_DICT_KWRDS bool GUF_CAT(GUF_DICT_NAME, _debug_valid_size)(const GUF_DICT_NAME *ht);
/* Iterator functions */
GUF_DICT_KWRDS GUF_CAT(GUF_DICT_NAME, _iter) GUF_CAT(GUF_DICT_NAME, _begin)(const GUF_DICT_NAME* ht);
GUF_DICT_KWRDS GUF_CAT(GUF_DICT_NAME, _iter) GUF_CAT(GUF_DICT_NAME, _end)(const GUF_DICT_NAME* ht);
@ -185,12 +194,6 @@ GUF_DICT_KWRDS ptrdiff_t GUF_CAT(GUF_DICT_NAME, _iter_to_idx)(const GUF_DICT_NAM
GUF_DICT_KWRDS GUF_CAT(GUF_DICT_NAME, _iter) GUF_CAT(GUF_DICT_NAME, _find_val_if)(GUF_DICT_NAME *ht, GUF_CAT(GUF_DICT_NAME, _iter) begin, GUF_CAT(GUF_DICT_NAME, _iter) end, bool (*predicate)(const GUF_DICT_VAL_T *));
#endif
GUF_DICT_KWRDS ptrdiff_t GUF_CAT(GUF_DICT_NAME, _max_capacity)(void);
GUF_DICT_KWRDS size_t GUF_CAT(GUF_DICT_NAME, _memory_usage)(const GUF_DICT_NAME *ht);
GUF_DICT_KWRDS bool GUF_CAT(GUF_DICT_NAME, _valid)(const GUF_DICT_NAME *ht);
GUF_DICT_KWRDS bool GUF_CAT(GUF_DICT_NAME, _debug_valid_size)(const GUF_DICT_NAME *ht);
// #define GUF_DICT_IMPL /* DEBUGGGGGGGGG */
#if defined(GUF_DICT_IMPL) || defined(GUF_DICT_IMPL_STATIC)
@ -278,10 +281,11 @@ GUF_DICT_KWRDS GUF_DICT_NAME *GUF_CAT(GUF_DICT_NAME, _try_init_with_capacity)(GU
while ((kv_idx_cap <= MAX_IDX_CAP / 2) && ((kv_idx_cap << 1) <= desired_idx_cap)) {
kv_idx_cap <<= 1;
}
GUF_ASSERT_RELEASE(kv_idx_cap >= (size_t)ht->kv_elems.capacity && kv_idx_cap <= MAX_IDX_CAP);
GUF_ASSERT_RELEASE(guf_is_pow2_size_t(kv_idx_cap));
const size_t num_bytes = kv_idx_cap * sizeof(GUF_DICT_KV_META_T);
GUF_ASSERT_RELEASE(!guf_mul_is_overflow_size_t(kv_idx_cap, sizeof(GUF_DICT_KV_META_T)) && num_bytes <= PTRDIFF_MAX);
GUF_ASSERT_RELEASE(!guf_mul_is_overflow_size_t(kv_idx_cap, sizeof(GUF_DICT_KV_META_T)) && num_bytes <= GUF_ALLOC_MAX_BYTES(GUF_DICT_KV_META_T));
GUF_DICT_KV_META_T *kv_indices = ht->kv_elems.allocator->alloc(num_bytes, ht->kv_elems.allocator->ctx);
if (!kv_indices) {
@ -291,7 +295,7 @@ GUF_DICT_KWRDS GUF_DICT_NAME *GUF_CAT(GUF_DICT_NAME, _try_init_with_capacity)(GU
}
ht->kv_indices = kv_indices;
ht->kv_indices_cap = kv_idx_cap;
GUF_ASSERT(ht->kv_indices_cap > ht->kv_elems.capacity);
GUF_ASSERT(ht->kv_indices_cap >= ht->kv_elems.capacity);
for (ptrdiff_t i = 0; i < ht->kv_indices_cap; ++i) {
ht->kv_indices[i] = GUF_DICT_KV_META_IDX_NULL;
}
@ -437,7 +441,7 @@ GUF_DICT_KWRDS ptrdiff_t GUF_CAT(GUF_DICT_NAME, _size)(const GUF_DICT_NAME *ht)
return ht->kv_elems.size;
}
static inline size_t GUF_CAT(GUF_DICT_NAME, _probe_offset)(size_t probe_len)
static inline size_t GUF_CAT(GUF_DICT_NAME, _probe_offset_)(size_t probe_len)
{
GUF_ASSERT(probe_len > 0);
#ifdef GUF_DICT_PROBE_LINEAR
@ -451,7 +455,7 @@ 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, GUF_DICT_HASH_T key_hash, 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;
@ -490,7 +494,7 @@ static size_t GUF_CAT(GUF_DICT_NAME, _find_idx)(GUF_DICT_NAME *ht, const GUF_DIC
} 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.
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.
GUF_ASSERT((ptrdiff_t)probe_len <= (ht->kv_elems.size + ht->num_tombstones));
}
} while (idx != start_idx && probe_len < (size_t)ht->kv_indices_cap);
@ -522,7 +526,7 @@ static void GUF_CAT(GUF_DICT_NAME, _reinsert_elems_)(GUF_DICT_NAME *ht)
GUF_ASSERT(kv);
bool key_exists = false;
const GUF_DICT_HASH_T key_hash = GUF_DICT_KEY_HASH(&kv->key);
const size_t new_idx = GUF_CAT(GUF_DICT_NAME, _find_idx)(ht, &kv->key, key_hash, &key_exists);
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_MAX && new_idx < (size_t)ht->kv_indices_cap);
GUF_ASSERT((GUF_DICT_HASH_T_GET_HASHFRAG(key_hash) & (GUF_DICT_KV_META_T)kv_idx) == 0);
@ -636,7 +640,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_hash, &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;
@ -741,7 +745,7 @@ GUF_DICT_KWRDS void GUF_CAT(GUF_DICT_NAME, _insert_val_arg)(GUF_DICT_NAME *ht, G
}
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_hash, &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 {
@ -757,7 +761,6 @@ GUF_DICT_KWRDS void GUF_CAT(GUF_DICT_NAME, _insert_val_arg)(GUF_DICT_NAME *ht, G
{
return GUF_CAT(GUF_DICT_NAME, _at)(ht, &key);
}
#endif
GUF_DICT_KWRDS bool GUF_CAT(GUF_DICT_NAME, _contains)(GUF_DICT_NAME *ht, const GUF_DICT_KEY_T *key)
@ -768,7 +771,7 @@ GUF_DICT_KWRDS bool GUF_CAT(GUF_DICT_NAME, _contains)(GUF_DICT_NAME *ht, const G
}
bool key_exists = false;
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);
const size_t idx = GUF_CAT(GUF_DICT_NAME, _find_idx_)(ht, key, key_hash, &key_exists);
if (key_exists) {
GUF_ASSERT(idx != SIZE_MAX);
GUF_ASSERT(!GUF_DICT_META_IS_TOMBSTONE(ht->kv_indices[idx]));
@ -794,7 +797,7 @@ GUF_DICT_KWRDS bool GUF_CAT(GUF_DICT_NAME, _erase)(GUF_DICT_NAME *ht, const GUF_
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_hash, &key_exists);
const size_t idx = GUF_CAT(GUF_DICT_NAME, _find_idx_)(ht, key, key_hash, &key_exists);
if (!key_exists) {
return false;
}
@ -823,7 +826,7 @@ GUF_DICT_KWRDS bool GUF_CAT(GUF_DICT_NAME, _erase)(GUF_DICT_NAME *ht, const GUF_
// 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_hash, &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));
@ -863,6 +866,17 @@ GUF_DICT_KWRDS bool GUF_CAT(GUF_DICT_NAME, _erase_val_arg)(GUF_DICT_NAME *ht, G
}
GUF_DICT_KWRDS void GUF_CAT(GUF_DICT_NAME, _try_shrink_to_fit)(GUF_DICT_NAME *ht, guf_err *err)
{
GUF_ASSERT(GUF_CAT(GUF_DICT_NAME, _valid)(ht));
GUF_CAT(GUF_DICT_KV_DBUF, _try_shrink_to_fit)(&ht->kv_elems, err);
}
GUF_DICT_KWRDS void GUF_CAT(GUF_DICT_NAME, _shrink_to_fit)(GUF_DICT_NAME *ht)
{
GUF_CAT(GUF_DICT_NAME, _try_shrink_to_fit)(ht, NULL);
}
/* Iterator functions */
GUF_DICT_KWRDS GUF_CAT(GUF_DICT_NAME, _iter) GUF_CAT(GUF_DICT_NAME, _begin)(const GUF_DICT_NAME* ht)