Added function to explicitly shrink the set + added function to clear set.

This commit is contained in:
LoRd_MuldeR 2022-11-21 18:36:43 +01:00
parent a348e59e60
commit a683e0479b
2 changed files with 61 additions and 29 deletions

View File

@ -23,12 +23,13 @@ void hash_set_destroy(hash_set_t *instance);
errno_t hash_set_insert(hash_set_t *const instance, const uint64_t value); errno_t hash_set_insert(hash_set_t *const instance, const uint64_t value);
errno_t hash_set_remove(hash_set_t *const instance, const uint64_t value); errno_t hash_set_remove(hash_set_t *const instance, const uint64_t value);
errno_t hash_set_clear(hash_set_t *const instance);
errno_t hash_set_shrink(hash_set_t *const instance);
errno_t hash_set_contains(const hash_set_t *const instance, const uint64_t value); errno_t hash_set_contains(const hash_set_t *const instance, const uint64_t value);
errno_t hash_set_iterate(const hash_set_t *const instance, size_t *const offset, uint64_t *const value); errno_t hash_set_iterate(const hash_set_t *const instance, size_t *const offset, uint64_t *const value);
size_t hash_set_size(const hash_set_t *const instance);
size_t hash_set_size(hash_set_t *const instance); errno_t hash_set_info(const hash_set_t *const instance, size_t *const capacity, size_t *const valid, size_t *const deleted, size_t *const limit);
errno_t hash_set_info(hash_set_t *const instance, size_t *const capacity, size_t *const valid, size_t *const deleted, size_t *const limit);
#ifdef __cplusplus #ifdef __cplusplus
} }

View File

@ -38,6 +38,9 @@ struct _hash_set
struct _hash_set_data data; struct _hash_set_data data;
}; };
static const size_t MINIMUM_CAPACITY = 128U;
static const size_t DEFAULT_CAPACITY = 16384U;
/* ========================================================================= */ /* ========================================================================= */
/* PRIVATE FUNCTIONS */ /* PRIVATE FUNCTIONS */
/* ========================================================================= */ /* ========================================================================= */
@ -82,11 +85,11 @@ static FORCE_INLINE size_t safe_decr(const size_t value)
return (value > 0U) ? (value - 1U) : value; return (value > 0U) ? (value - 1U) : value;
} }
static FORCE_INLINE size_t next_pow2(const size_t minimum) static FORCE_INLINE size_t next_pow2(const size_t target)
{ {
size_t result = sizeof(uint64_t); size_t result = MINIMUM_CAPACITY;
while (result < minimum) while (result < target)
{ {
result = safe_mult2(result); result = safe_mult2(result);
} }
@ -286,7 +289,7 @@ hash_set_t *hash_set_create(const size_t initial_capacity, const double load_fac
return NULL; return NULL;
} }
if (!alloc_data(&instance->data, (initial_capacity > 0U) ? next_pow2(initial_capacity) : 1024U)) if (!alloc_data(&instance->data, (initial_capacity > 0U) ? next_pow2(initial_capacity) : DEFAULT_CAPACITY))
{ {
SAFE_FREE(instance); SAFE_FREE(instance);
return NULL; return NULL;
@ -323,7 +326,14 @@ errno_t hash_set_insert(hash_set_t *const instance, const uint64_t value)
return EEXIST; return EEXIST;
} }
while ((safe_add(instance->valid, instance->deleted) >= instance->limit) || (instance->valid >= instance->data.capacity)) if (!store_value(&instance->data, index, value))
{
instance->deleted = safe_decr(instance->deleted);
}
instance->valid = safe_incr(instance->valid);
while ((safe_add(instance->valid, instance->deleted) > instance->limit) || (instance->valid >= instance->data.capacity))
{ {
if (instance->data.capacity == SIZE_MAX) if (instance->data.capacity == SIZE_MAX)
{ {
@ -350,22 +360,9 @@ errno_t hash_set_insert(hash_set_t *const instance, const uint64_t value)
return error; return error;
} }
} }
else
{
if (find_slot(&instance->data, value, &index))
{
return EFAULT;
}
}
} }
} }
if (!store_value(&instance->data, index, value))
{
instance->deleted = safe_decr(instance->deleted);
}
instance->valid = safe_incr(instance->valid);
return 0; return 0;
} }
@ -397,18 +394,52 @@ errno_t hash_set_remove(hash_set_t *const instance, const uint64_t value)
instance->deleted = safe_incr(instance->deleted); instance->deleted = safe_incr(instance->deleted);
instance->valid = safe_decr(instance->valid); instance->valid = safe_decr(instance->valid);
if (instance->deleted > (instance->data.capacity >> 1)) if (instance->valid == 0U)
{ {
const errno_t error = rebuild_set(instance, next_pow2(round_sz(instance->valid / instance->load_factor))); hash_set_clear(instance); /*optimization*/
if (error && ((error != ENOMEM) || (instance->options & HASHSET_OPT_FAILFAST)))
{
return error;
}
} }
return 0; return 0;
} }
errno_t hash_set_clear(hash_set_t *const instance)
{
if ((!instance) || (!instance->data.values))
{
return EINVAL;
}
if ((instance->valid == 0U) && (instance->deleted == 0U))
{
return EAGAIN;
}
memset(instance->data.used, 0, sizeof(uint8_t) * div_ceil(instance->data.capacity, 8U));
memset(instance->data.deleted, 0, sizeof(uint8_t) * div_ceil(instance->data.capacity, 8U));
instance->valid = instance->deleted = 0U;
return 0;
}
errno_t hash_set_shrink(hash_set_t *const instance)
{
if ((!instance) || (!instance->data.values))
{
return EINVAL;
}
if (instance->data.capacity > MINIMUM_CAPACITY)
{
const size_t target_capacity = next_pow2(round_sz(safe_add(instance->valid, MINIMUM_CAPACITY) / instance->load_factor));
if (instance->data.capacity > target_capacity)
{
return rebuild_set(instance, target_capacity);
}
}
return EAGAIN;
}
errno_t hash_set_iterate(const hash_set_t *const instance, size_t *const offset, uint64_t *const value) errno_t hash_set_iterate(const hash_set_t *const instance, size_t *const offset, uint64_t *const value)
{ {
size_t index; size_t index;
@ -435,12 +466,12 @@ errno_t hash_set_iterate(const hash_set_t *const instance, size_t *const offset,
return ENOENT; return ENOENT;
} }
size_t hash_set_size(hash_set_t *const instance) size_t hash_set_size(const hash_set_t *const instance)
{ {
return instance ? instance->valid : 0U; return instance ? instance->valid : 0U;
} }
errno_t hash_set_info(hash_set_t *const instance, size_t *const capacity, size_t *const valid, size_t *const deleted, size_t *const limit) errno_t hash_set_info(const hash_set_t *const instance, size_t *const capacity, size_t *const valid, size_t *const deleted, size_t *const limit)
{ {
if ((!instance) || (!instance->data.values)) if ((!instance) || (!instance->data.values))
{ {