diff --git a/src/guf_dict.h b/src/guf_dict.h index d9fd676..e2ce95b 100755 --- a/src/guf_dict.h +++ b/src/guf_dict.h @@ -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; } @@ -334,12 +338,12 @@ GUF_DICT_KWRDS ptrdiff_t GUF_CAT(GUF_DICT_NAME, _max_capacity)(void) // Find next power of two (capacities must be powers of two). size_t pow2_cap = 1; const size_t MAX_SIZE_POW2 = SIZE_MAX & ~(SIZE_MAX >> 1); - while ((pow2_cap < MAX_SIZE_POW2) && ((pow2_cap << 1) <= max_cap_kv_indices) ) { + while ( (pow2_cap < MAX_SIZE_POW2) && ((pow2_cap << 1) <= max_cap_kv_indices) ) { pow2_cap <<= 1; } GUF_ASSERT(guf_is_pow2_size_t(pow2_cap) && pow2_cap <= max_cap_kv_indices && pow2_cap > 1); - return GUF_MIN(GUF_MIN(max_cap_kv_elems, pow2_cap), PTRDIFF_MAX); + return GUF_MIN(GUF_MIN(max_cap_kv_elems, pow2_cap), PTRDIFF_MAX); } GUF_DICT_KWRDS size_t GUF_CAT(GUF_DICT_NAME, _memory_usage)(const GUF_DICT_NAME *ht) @@ -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)