diff --git a/hashset/src/main.c b/hashset/src/main.c index 0ce5bcc..295ed46 100644 --- a/hashset/src/main.c +++ b/hashset/src/main.c @@ -47,7 +47,15 @@ int main() const clock_t now = clock(); if ((now < last_update) || (now >= last_update + CLOCKS_PER_SEC)) { - printf("%zu\n", hash_set_size(hash_set)); + size_t capacity, valid, deleted, limit; + if (!hash_set_info(hash_set, &capacity, &valid, &deleted, &limit)) + { + printf("%010zu, %010zu, %010zu, %010zu\n", capacity, valid, deleted, limit); + } + else + { + printf("%zu\n", hash_set_size(hash_set)); + } last_update = now; } } diff --git a/libhashset/include/hash_set.h b/libhashset/include/hash_set.h index a391462..df92e68 100644 --- a/libhashset/include/hash_set.h +++ b/libhashset/include/hash_set.h @@ -14,7 +14,6 @@ extern "C" { #endif #define HASHSET_OPT_FAILFAST UINT16_C(0x1) -#define HASHSET_ITERATOR_INIT ((size_t)0U) struct _hash_set; typedef struct _hash_set hash_set_t; @@ -29,6 +28,7 @@ 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); size_t hash_set_size(hash_set_t *const instance); +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 } diff --git a/libhashset/src/hash_set.c b/libhashset/src/hash_set.c index 0722eb0..c9d71d1 100644 --- a/libhashset/src/hash_set.c +++ b/libhashset/src/hash_set.c @@ -34,7 +34,7 @@ struct _hash_set { double load_factor; uint16_t options; - size_t count, deleted, limit; + size_t valid, deleted, limit; struct _hash_set_data data; }; @@ -52,21 +52,36 @@ struct _hash_set /* Math */ /* ------------------------------------------------- */ -static FORCE_INLINE size_t round_sz(double d) -{ - return (d >= 0.0) ? ((d > ((double)SIZE_MAX)) ? SIZE_MAX : ((size_t)(d + 0.5))) : 0U; -} - static FORCE_INLINE size_t div_ceil(const size_t value, const size_t divisor) { return (value / divisor) + ((value % divisor != 0U) ? 1U : 0U); } +static FORCE_INLINE size_t round_sz(double d) +{ + return (d >= 0.0) ? ((d + 0.5 >= ((double)SIZE_MAX)) ? SIZE_MAX : ((size_t)(d + 0.5))) : 0U; +} + static FORCE_INLINE size_t safe_mult2(const size_t value) { return (value < (SIZE_MAX >> 1)) ? (value << 1) : SIZE_MAX; } +static FORCE_INLINE size_t safe_add(const size_t a, const size_t b) +{ + return ((SIZE_MAX - a) > b) ? (a + b) : SIZE_MAX; +} + +static FORCE_INLINE size_t safe_incr(const size_t value) +{ + return (value < SIZE_MAX) ? (value + 1U) : SIZE_MAX; +} + +static FORCE_INLINE size_t safe_decr(const size_t value) +{ + return (value > 0U) ? (value - 1U) : 0U; +} + static FORCE_INLINE size_t next_pow2(const size_t minimum) { size_t result = sizeof(uint64_t); @@ -308,11 +323,11 @@ errno_t hash_set_insert(hash_set_t *const instance, const uint64_t value) return EEXIST; } - while ((instance->count >= instance->limit) || (instance->count >= instance->data.capacity)) + while ((safe_add(instance->valid, instance->deleted) >= instance->limit) || (instance->valid >= instance->data.capacity)) { if (instance->data.capacity == SIZE_MAX) { - if ((instance->options & HASHSET_OPT_FAILFAST) || (instance->count >= instance->data.capacity)) + if ((instance->options & HASHSET_OPT_FAILFAST) || (instance->valid >= instance->data.capacity)) { return ENOMEM; /*malloc has failed!*/ } @@ -324,7 +339,7 @@ errno_t hash_set_insert(hash_set_t *const instance, const uint64_t value) { if (error == ENOMEM) { - if ((instance->options & HASHSET_OPT_FAILFAST) || (instance->count >= instance->data.capacity)) + if ((instance->options & HASHSET_OPT_FAILFAST) || (instance->valid >= instance->data.capacity)) { return ENOMEM; /*malloc has failed!*/ } @@ -347,10 +362,10 @@ errno_t hash_set_insert(hash_set_t *const instance, const uint64_t value) if (!store_value(&instance->data, index, value)) { - --instance->deleted; + instance->deleted = safe_decr(instance->deleted); } - ++instance->count; + instance->valid = safe_incr(instance->valid); return 0; } @@ -379,11 +394,12 @@ errno_t hash_set_remove(hash_set_t *const instance, const uint64_t value) } set_flag(instance->data.deleted, index); - --instance->count; + instance->deleted = safe_incr(instance->deleted); + instance->valid = safe_decr(instance->valid); - if (++instance->deleted > (instance->data.capacity >> 1)) + if (instance->deleted > (instance->data.capacity >> 1)) { - const errno_t error = rebuild_set(instance, next_pow2(round_sz(instance->count / instance->load_factor))); + const errno_t error = rebuild_set(instance, next_pow2(round_sz(instance->valid / instance->load_factor))); if (error && ((error != ENOMEM) || (instance->options & HASHSET_OPT_FAILFAST))) { return error; @@ -421,5 +437,32 @@ errno_t hash_set_iterate(const hash_set_t *const instance, size_t *const offset, size_t hash_set_size(hash_set_t *const instance) { - return instance ? instance->count : 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) +{ + if ((!instance) || (!instance->data.values)) + { + return EINVAL; + } + + if (capacity) + { + *capacity = instance->data.capacity; + } + if (valid) + { + *valid = instance->valid; + } + if (deleted) + { + *deleted = instance->deleted; + } + if (limit) + { + *limit = instance->limit; + } + + return 0; }