From aa8d45936cafe89075521bd412f325a53f401622 Mon Sep 17 00:00:00 2001 From: LoRd_MuldeR Date: Tue, 29 Nov 2022 21:22:23 +0100 Subject: [PATCH] Map support has been implemented. --- example/src/main.c | 3 +- libhashset/include/hash_map.h | 79 +++ libhashset/include/hash_set.h | 26 +- libhashset/libhashset.vcxproj | 6 +- libhashset/libhashset.vcxproj.filters | 14 +- libhashset/src/common.h | 2 +- libhashset/src/generic_hash_map.h | 452 ++++++++++++++++++ .../src/{generic.h => generic_hash_set.h} | 81 ++-- libhashset/src/hash_map_32.c | 12 + libhashset/src/hash_map_64.c | 12 + libhashset/src/hash_set_32.c | 5 +- libhashset/src/hash_set_64.c | 4 +- libhashset/src/version.c | 6 +- test/src/tests.c | 3 +- 14 files changed, 637 insertions(+), 68 deletions(-) create mode 100644 libhashset/include/hash_map.h create mode 100644 libhashset/src/generic_hash_map.h rename libhashset/src/{generic.h => generic_hash_set.h} (80%) create mode 100644 libhashset/src/hash_map_32.c create mode 100644 libhashset/src/hash_map_64.c diff --git a/example/src/main.c b/example/src/main.c index b9b4f85..e0f6802 100644 --- a/example/src/main.c +++ b/example/src/main.c @@ -16,8 +16,7 @@ int main(void) { hash_set64_t *hash_set; uint64_t value; - uintptr_t cursor = 0U; - size_t offset = 0U; + size_t cursor = 0U, offset = 0U; /* print logo */ printf("LibHashSet Example v%" PRIu16 ".%" PRIu16 ".%" PRIu16 " [%s]\n\n", diff --git a/libhashset/include/hash_map.h b/libhashset/include/hash_map.h new file mode 100644 index 0000000..cbdf3cd --- /dev/null +++ b/libhashset/include/hash_map.h @@ -0,0 +1,79 @@ +/******************************************************************************/ +/* HashSet for C99, by LoRd_MuldeR */ +/* This work has been released under the CC0 1.0 Universal license! */ +/******************************************************************************/ + +#ifndef _LIBHASHSET_MAP_INCLUDED +#define _LIBHASHSET_MAP_INCLUDED + +#include +#include + +#if defined(_WIN32) && defined(HASHSET_DLL) +# ifdef _HASHSET_EXPORTS +# define HASHSET_API extern __declspec(dllexport) +# else +# define HASHSET_API extern __declspec(dllimport) +# endif +#else +# define HASHSET_API extern +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +#if !defined(_MSC_VER) && !defined(__MINGW32__) && !defined(_ERRNO_T_DEFINED) +typedef int errno_t; +#endif + +HASHSET_API const uint16_t HASHSET_VERSION_MAJOR; +HASHSET_API const uint16_t HASHSET_VERSION_MINOR; +HASHSET_API const uint16_t HASHSET_VERSION_PATCH; + +HASHSET_API const char *const HASHSET_BUILD_DATE; +HASHSET_API const char *const HASHSET_BUILD_TIME; + +struct _hash_map32; +struct _hash_map64; + +typedef struct _hash_map32 hash_map32_t; +typedef struct _hash_map64 hash_map64_t; + +HASHSET_API hash_map32_t *hash_map_create32(const size_t initial_capacity, const double load_factor); +HASHSET_API hash_map64_t *hash_map_create64(const size_t initial_capacity, const double load_factor); + +HASHSET_API void hash_map_destroy32(hash_map32_t *const instance); +HASHSET_API void hash_map_destroy64(hash_map64_t *const instance); + +HASHSET_API errno_t hash_map_insert32(hash_map32_t *const instance, const uint32_t key, const uintptr_t value); +HASHSET_API errno_t hash_map_insert64(hash_map64_t *const instance, const uint64_t key, const uintptr_t value); + +HASHSET_API errno_t hash_map_remove32(hash_map32_t *const instance, const uint32_t key); +HASHSET_API errno_t hash_map_remove64(hash_map64_t *const instance, const uint64_t key); + +HASHSET_API errno_t hash_map_clear32(hash_map32_t *const instance); +HASHSET_API errno_t hash_map_clear64(hash_map64_t *const instance); + +HASHSET_API errno_t hash_map_contains32(const hash_map32_t *const instance, const uint32_t key); +HASHSET_API errno_t hash_map_contains64(const hash_map64_t *const instance, const uint64_t key); + +HASHSET_API errno_t hash_map_get32(const hash_map32_t *const instance, const uint32_t key, uintptr_t *const value); +HASHSET_API errno_t hash_map_get64(const hash_map64_t *const instance, const uint64_t key, uintptr_t *const value); + +HASHSET_API errno_t hash_map_iterate32(const hash_map32_t *const instance, size_t *const cursor, uint32_t *const key, uintptr_t *const value); +HASHSET_API errno_t hash_map_iterate64(const hash_map64_t *const instance, size_t *const cursor, uint64_t *const key, uintptr_t *const value); + +HASHSET_API size_t hash_map_size32(const hash_map32_t *const instance); +HASHSET_API size_t hash_map_size64(const hash_map64_t *const instance); + +HASHSET_API errno_t hash_map_info32(const hash_map32_t *const instance, size_t *const capacity, size_t *const valid, size_t *const deleted, size_t *const limit); +HASHSET_API errno_t hash_map_info64(const hash_map64_t *const instance, size_t *const capacity, size_t *const valid, size_t *const deleted, size_t *const limit); + +HASHSET_API errno_t hash_map_dump32(const hash_map32_t *const instance, int (*const callback)(const size_t index, const char status, const uint32_t key, const uintptr_t value)); +HASHSET_API errno_t hash_map_dump64(const hash_map64_t *const instance, int (*const callback)(const size_t index, const char status, const uint64_t key, const uintptr_t value)); + +#ifdef __cplusplus +} +#endif +#endif /*_LIBHASHSET_MAP_INCLUDED*/ diff --git a/libhashset/include/hash_set.h b/libhashset/include/hash_set.h index 254e79d..d82a0ca 100644 --- a/libhashset/include/hash_set.h +++ b/libhashset/include/hash_set.h @@ -3,8 +3,8 @@ /* This work has been released under the CC0 1.0 Universal license! */ /******************************************************************************/ -#ifndef _LIBHASHSET_INCLUDED -#define _LIBHASHSET_INCLUDED +#ifndef _LIBHASHSET_SET_INCLUDED +#define _LIBHASHSET_SET_INCLUDED #include #include @@ -46,20 +46,20 @@ HASHSET_API hash_set64_t *hash_set_create64(const size_t initial_capacity, const HASHSET_API void hash_set_destroy32(hash_set32_t *const instance); HASHSET_API void hash_set_destroy64(hash_set64_t *const instance); -HASHSET_API errno_t hash_set_insert32(hash_set32_t *const instance, const uint32_t value); -HASHSET_API errno_t hash_set_insert64(hash_set64_t *const instance, const uint64_t value); +HASHSET_API errno_t hash_set_insert32(hash_set32_t *const instance, const uint32_t item); +HASHSET_API errno_t hash_set_insert64(hash_set64_t *const instance, const uint64_t item); -HASHSET_API errno_t hash_set_remove32(hash_set32_t *const instance, const uint32_t value); -HASHSET_API errno_t hash_set_remove64(hash_set64_t *const instance, const uint64_t value); +HASHSET_API errno_t hash_set_remove32(hash_set32_t *const instance, const uint32_t item); +HASHSET_API errno_t hash_set_remove64(hash_set64_t *const instance, const uint64_t item); HASHSET_API errno_t hash_set_clear32(hash_set32_t *const instance); HASHSET_API errno_t hash_set_clear64(hash_set64_t *const instance); -HASHSET_API errno_t hash_set_contains32(const hash_set32_t *const instance, const uint32_t value); -HASHSET_API errno_t hash_set_contains64(const hash_set64_t *const instance, const uint64_t value); +HASHSET_API errno_t hash_set_contains32(const hash_set32_t *const instance, const uint32_t item); +HASHSET_API errno_t hash_set_contains64(const hash_set64_t *const instance, const uint64_t item); -HASHSET_API errno_t hash_set_iterate32(const hash_set32_t *const instance, uintptr_t *const cursor, uint32_t *const value); -HASHSET_API errno_t hash_set_iterate64(const hash_set64_t *const instance, uintptr_t *const cursor, uint64_t *const value); +HASHSET_API errno_t hash_set_iterate32(const hash_set32_t *const instance, size_t *const cursor, uint32_t *const item); +HASHSET_API errno_t hash_set_iterate64(const hash_set64_t *const instance, size_t *const cursor, uint64_t *const item); HASHSET_API size_t hash_set_size32(const hash_set32_t *const instance); HASHSET_API size_t hash_set_size64(const hash_set64_t *const instance); @@ -67,10 +67,10 @@ HASHSET_API size_t hash_set_size64(const hash_set64_t *const instance); HASHSET_API errno_t hash_set_info32(const hash_set32_t *const instance, size_t *const capacity, size_t *const valid, size_t *const deleted, size_t *const limit); HASHSET_API errno_t hash_set_info64(const hash_set64_t *const instance, size_t *const capacity, size_t *const valid, size_t *const deleted, size_t *const limit); -HASHSET_API errno_t hash_set_dump32(const hash_set32_t *const instance, int (*const callback)(const size_t index, const char status, const uint32_t value)); -HASHSET_API errno_t hash_set_dump64(const hash_set64_t *const instance, int (*const callback)(const size_t index, const char status, const uint64_t value)); +HASHSET_API errno_t hash_set_dump32(const hash_set32_t *const instance, int (*const callback)(const size_t index, const char status, const uint32_t item)); +HASHSET_API errno_t hash_set_dump64(const hash_set64_t *const instance, int (*const callback)(const size_t index, const char status, const uint64_t item)); #ifdef __cplusplus } #endif -#endif /* _LIBHASHSET_INCLUDED */ +#endif /*_LIBHASHSET_SET_INCLUDED*/ diff --git a/libhashset/libhashset.vcxproj b/libhashset/libhashset.vcxproj index 2b152e8..19c256b 100644 --- a/libhashset/libhashset.vcxproj +++ b/libhashset/libhashset.vcxproj @@ -39,11 +39,15 @@ + - + + + + diff --git a/libhashset/libhashset.vcxproj.filters b/libhashset/libhashset.vcxproj.filters index a2aba0c..79a7fa2 100644 --- a/libhashset/libhashset.vcxproj.filters +++ b/libhashset/libhashset.vcxproj.filters @@ -21,7 +21,13 @@ Header Files - + + Header Files + + + Header Files + + Header Files @@ -35,5 +41,11 @@ Source Files + + Source Files + + + Source Files + \ No newline at end of file diff --git a/libhashset/src/common.h b/libhashset/src/common.h index 3dc3e0c..5764eba 100644 --- a/libhashset/src/common.h +++ b/libhashset/src/common.h @@ -101,7 +101,7 @@ static FORCE_INLINE size_t next_pow2(const size_t target) /* Hash function */ /* ------------------------------------------------- */ -static FORCE_INLINE void hash_update(uint64_t* const hash, uint64_t value) +static FORCE_INLINE void hash_update(uint64_t *const hash, uint64_t value) { do { diff --git a/libhashset/src/generic_hash_map.h b/libhashset/src/generic_hash_map.h new file mode 100644 index 0000000..e96f1fb --- /dev/null +++ b/libhashset/src/generic_hash_map.h @@ -0,0 +1,452 @@ +/******************************************************************************/ +/* HashSet for C99, by LoRd_MuldeR */ +/* This work has been released under the CC0 1.0 Universal license! */ +/******************************************************************************/ + +#ifndef _LIBHASHSET_GENERIC_MAP_INCLUDED +#define _LIBHASHSET_GENERIC_MAP_INCLUDED + +#include "common.h" + +#ifndef NAME_SUFFIX +#error NAME_SUFFIX must be defined! +#endif + +#define _CONCAT(X,Y) X##Y +#define CONCAT(X,Y) _CONCAT(X,Y) + +#define DECLARE(X) CONCAT(X,NAME_SUFFIX) + +/* ------------------------------------------------- */ +/* Data types */ +/* ------------------------------------------------- */ + +typedef struct DECLARE(_hash_map_data) +{ + key_t *keys; + uintptr_t *values; + uint8_t *used, *deleted; + size_t capacity; +} +hash_data_t; + +struct DECLARE(_hash_map) +{ + double load_factor; + size_t valid, deleted, limit; + hash_data_t data; +}; + +/* ------------------------------------------------- */ +/* Allocation */ +/* ------------------------------------------------- */ + +static INLINE bool_t alloc_data(hash_data_t *const data, const size_t capacity) +{ + zero_memory(data, 1U, sizeof(hash_data_t)); + + data->keys = (key_t*) calloc(capacity, sizeof(key_t)); + if (!data->values) + { + return FALSE; + } + + data->values = (uintptr_t*) calloc(capacity, sizeof(uintptr_t)); + if (!data->values) + { + return FALSE; + } + + data->used = (uint8_t*) calloc(div_ceil(capacity, 8U), sizeof(uint8_t)); + if (!data->used) + { + SAFE_FREE(data->values); + return FALSE; + } + + data->deleted = (uint8_t*) calloc(div_ceil(capacity, 8U), sizeof(uint8_t)); + if (!data->deleted) + { + SAFE_FREE(data->used); + SAFE_FREE(data->values); + return FALSE; + } + + data->capacity = capacity; + return TRUE; +} + +static INLINE void free_data(hash_data_t *const data) +{ + if (data) + { + SAFE_FREE(data->keys); + SAFE_FREE(data->values); + SAFE_FREE(data->used); + SAFE_FREE(data->deleted); + data->capacity = 0U; + } +} + +/* ------------------------------------------------- */ +/* Set functions */ +/* ------------------------------------------------- */ + +#define INDEX(X) ((size_t)((X) % data->capacity)) + +static INLINE bool_t find_slot(const hash_data_t *const data, const key_t key, size_t *const index_out, bool_t *const reused_out) +{ + uint64_t loop = 0U; + bool_t is_saved = FALSE; + size_t index; + + for (index = INDEX(hash_compute(loop, key)); get_flag(data->used, index); index = INDEX(hash_compute(++loop, key))) + { + if (get_flag(data->deleted, index)) + { + if (!is_saved) + { + SAFE_SET(index_out, index); + SAFE_SET(reused_out, TRUE); + is_saved = TRUE; + } + } + else + { + if (data->keys[index] == key) + { + SAFE_SET(index_out, index); + SAFE_SET(reused_out, FALSE); + return TRUE; + } + } + } + + if (!is_saved) + { + SAFE_SET(index_out, index); + SAFE_SET(reused_out, FALSE); + } + + return FALSE; +} + +static INLINE void put_value(hash_data_t *const data, const size_t index, const key_t key, const uintptr_t value, const bool_t reusing) +{ + data->keys[index] = key; + data->values[index] = value; + + if (reusing) + { + assert(get_flag(data->used, index)); + clear_flag(data->deleted, index); + } + else + { + assert(!get_flag(data->deleted, index)); + set_flag(data->used, index); + } +} + +static INLINE size_t compute_limit(const size_t capacity, const double load_factor) +{ + size_t limit = round_sz(capacity * load_factor); + + while (capacity && (limit >= capacity)) + { + limit = safe_decr(limit); + } + + return limit; +} + +static INLINE errno_t rebuild_map(hash_map_t *const instance, const size_t new_capacity) +{ + size_t k, index; + hash_data_t temp; + + if (new_capacity < instance->valid) + { + return EINVAL; + } + + if (!alloc_data(&temp, new_capacity)) + { + return ENOMEM; + } + + for (k = 0U; k < instance->data.capacity; ++k) + { + if (IS_VALID(instance->data, k)) + { + const key_t key = instance->data.keys[k]; + const uintptr_t value = instance->data.values[k]; + if (find_slot(&temp, key, &index, NULL)) + { + free_data(&temp); + return EFAULT; /*this should never happen!*/ + } + put_value(&temp, index, key, value, FALSE); + } + } + + free_data(&instance->data); + instance->data = temp; + instance->limit = compute_limit(instance->data.capacity, instance->load_factor); + instance->deleted = 0U; + + return 0; +} + +/* ========================================================================= */ +/* PUBLIC FUNCTIONS */ +/* ========================================================================= */ + +hash_map_t *DECLARE(hash_map_create)(const size_t initial_capacity, const double load_factor) +{ + hash_map_t* instance = (hash_map_t*) calloc(1U, sizeof(hash_map_t)); + if (!instance) + { + return NULL; + } + + if (!alloc_data(&instance->data, (initial_capacity > 0U) ? next_pow2(initial_capacity) : DEFAULT_CAPACITY)) + { + SAFE_FREE(instance); + return NULL; + } + + instance->load_factor = (load_factor > DBL_EPSILON) ? BOUND(0.125, load_factor, 1.0) : DEFAULT_LOADFCTR; + instance->limit = compute_limit(instance->data.capacity, instance->load_factor); + + return instance; +} + +void DECLARE(hash_map_destroy)(hash_map_t *instance) +{ + if (instance) + { + free_data(&instance->data); + zero_memory(instance, 1U, sizeof(hash_map_t)); + SAFE_FREE(instance); + } +} + +errno_t DECLARE(hash_map_insert)(hash_map_t *const instance, const key_t key, const uintptr_t value) +{ + size_t index; + bool_t slot_reused; + + if ((!instance) || (!instance->data.keys)) + { + return EINVAL; + } + + if (find_slot(&instance->data, key, &index, &slot_reused)) + { + instance->data.values[index] = index; + return EEXIST; + } + + if ((!slot_reused) && (safe_add(instance->valid, instance->deleted) >= instance->limit)) + { + const errno_t error = rebuild_map(instance, safe_times2(instance->data.capacity)); + if (error) + { + return error; + } + if (find_slot(&instance->data, key, &index, &slot_reused)) + { + return EFAULT; + } + } + + put_value(&instance->data, index, key, value, slot_reused); + + instance->valid = safe_incr(instance->valid); + if (slot_reused) + { + instance->deleted = safe_decr(instance->deleted); + } + + return 0; +} + +errno_t DECLARE(hash_map_contains)(const hash_map_t *const instance, const key_t key) +{ + if ((!instance) || (!instance->data.keys)) + { + return EINVAL; + } + + return (instance->valid && find_slot(&instance->data, key, NULL, NULL)) ? 0 : ENOENT; +} + +errno_t DECLARE(hash_map_get)(const hash_map_t *const instance, const key_t key, uintptr_t *const value) +{ + size_t index; + + if ((!instance) || (!instance->data.keys)) + { + return EINVAL; + } + + if (!find_slot(&instance->data, key, &index, NULL)) + { + return ENOENT; + } + + *value = instance->data.values[index]; + return 0; +} + +errno_t DECLARE(hash_map_remove)(hash_map_t *const instance, const key_t key) +{ + size_t index; + + if ((!instance) || (!instance->data.keys)) + { + return EINVAL; + } + + if ((!instance->valid) || (!find_slot(&instance->data, key, &index, NULL))) + { + return ENOENT; + } + + set_flag(instance->data.deleted, index); + instance->deleted = safe_incr(instance->deleted); + instance->valid = safe_decr(instance->valid); + + if (!instance->valid) + { + return DECLARE(hash_map_clear)(instance); + } + + if (instance->deleted > (instance->limit / 2U)) + { + const size_t min_capacity = next_pow2(round_sz(safe_incr(instance->valid) / instance->load_factor)); + const errno_t error = rebuild_map(instance, (instance->data.capacity > min_capacity) ? min_capacity : instance->data.capacity); + if (error && (error != ENOMEM)) + { + return error; + } + } + + return 0; +} + +errno_t DECLARE(hash_map_clear)(hash_map_t *const instance) +{ + if ((!instance) || (!instance->data.values)) + { + return EINVAL; + } + + if (instance->valid || instance->deleted) + { + const size_t count = div_ceil(instance->data.capacity, 8U); + instance->valid = instance->deleted = 0U; + zero_memory(instance->data.used, count, sizeof(uint8_t)); + zero_memory(instance->data.deleted, count, sizeof(uint8_t)); + } + else + { + return EAGAIN; + } + + if (instance->data.capacity > MINIMUM_CAPACITY) + { + const errno_t error = rebuild_map(instance, MINIMUM_CAPACITY); + if (error && (error != ENOMEM)) + { + return error; + } + } + + return 0; +} + +errno_t DECLARE(hash_map_iterate)(const hash_map_t *const instance, size_t *const cursor, key_t *const key, uintptr_t *const value) +{ + size_t index; + + if ((!instance) || (!cursor) || (*cursor >= SIZE_MAX) || (!instance->data.values)) + { + return EINVAL; + } + + for (index = *cursor; index < instance->data.capacity; ++index) + { + if (IS_VALID(instance->data, index)) + { + if (key) + { + *key = instance->data.keys[index]; + } + if (value) + { + *value = instance->data.values[index]; + } + *cursor = index + 1U; + return 0; + } + } + + *cursor = SIZE_MAX; + return ENOENT; +} + +size_t DECLARE(hash_map_size)(const hash_map_t *const instance) +{ + return instance ? instance->valid : 0U; +} + +errno_t DECLARE(hash_map_info)(const hash_map_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; +} + +HASHSET_API errno_t DECLARE(hash_map_dump)(const hash_map_t *const instance, int (*const callback)(const size_t index, const char status, const key_t key, const uintptr_t value)) +{ + size_t index; + + if ((!instance) || (!instance->data.values)) + { + return EINVAL; + } + + for (index = 0U; index < instance->data.capacity; ++index) + { + if (!callback(index, get_flag(instance->data.used, index) ? (get_flag(instance->data.deleted, index) ? 'd' : 'v') : 'u', instance->data.keys[index], instance->data.values[index])) + { + return ECANCELED; + } + } + + return 0; +} + +#endif /*_LIBHASHSET_GENERIC_MAP_INCLUDED*/ diff --git a/libhashset/src/generic.h b/libhashset/src/generic_hash_set.h similarity index 80% rename from libhashset/src/generic.h rename to libhashset/src/generic_hash_set.h index 245f118..aedf05f 100644 --- a/libhashset/src/generic.h +++ b/libhashset/src/generic_hash_set.h @@ -3,8 +3,8 @@ /* This work has been released under the CC0 1.0 Universal license! */ /******************************************************************************/ -#ifndef _LIBHASHSET_GENERIC_INCLUDED -#define _LIBHASHSET_GENERIC_INCLUDED +#ifndef _LIBHASHSET_GENERIC_SET_INCLUDED +#define _LIBHASHSET_GENERIC_SET_INCLUDED #include "common.h" @@ -23,7 +23,7 @@ typedef struct DECLARE(_hash_set_data) { - value_t *values; + item_t *items; uint8_t *used, *deleted; size_t capacity; } @@ -44,8 +44,8 @@ static INLINE bool_t alloc_data(hash_data_t *const data, const size_t capacity) { zero_memory(data, 1U, sizeof(hash_data_t)); - data->values = (value_t*) calloc(capacity, sizeof(value_t)); - if (!data->values) + data->items = (item_t*) calloc(capacity, sizeof(item_t)); + if (!data->items) { return FALSE; } @@ -53,7 +53,7 @@ static INLINE bool_t alloc_data(hash_data_t *const data, const size_t capacity) data->used = (uint8_t*) calloc(div_ceil(capacity, 8U), sizeof(uint8_t)); if (!data->used) { - SAFE_FREE(data->values); + SAFE_FREE(data->items); return FALSE; } @@ -61,7 +61,7 @@ static INLINE bool_t alloc_data(hash_data_t *const data, const size_t capacity) if (!data->deleted) { SAFE_FREE(data->used); - SAFE_FREE(data->values); + SAFE_FREE(data->items); return FALSE; } @@ -73,7 +73,7 @@ static INLINE void free_data(hash_data_t *const data) { if (data) { - SAFE_FREE(data->values); + SAFE_FREE(data->items); SAFE_FREE(data->used); SAFE_FREE(data->deleted); data->capacity = 0U; @@ -86,13 +86,13 @@ static INLINE void free_data(hash_data_t *const data) #define INDEX(X) ((size_t)((X) % data->capacity)) -static INLINE bool_t find_slot(const hash_data_t *const data, const value_t value, size_t *const index_out, bool_t *const reused_out) +static INLINE bool_t find_slot(const hash_data_t *const data, const item_t item, size_t *const index_out, bool_t *const reused_out) { uint64_t loop = 0U; bool_t is_saved = FALSE; size_t index; - for (index = INDEX(hash_compute(loop, value)); get_flag(data->used, index); index = INDEX(hash_compute(++loop, value))) + for (index = INDEX(hash_compute(loop, item)); get_flag(data->used, index); index = INDEX(hash_compute(++loop, item))) { if (get_flag(data->deleted, index)) { @@ -105,7 +105,7 @@ static INLINE bool_t find_slot(const hash_data_t *const data, const value_t valu } else { - if (data->values[index] == value) + if (data->items[index] == item) { SAFE_SET(index_out, index); SAFE_SET(reused_out, FALSE); @@ -123,9 +123,10 @@ static INLINE bool_t find_slot(const hash_data_t *const data, const value_t valu return FALSE; } -static INLINE void put_value(hash_data_t *const data, const size_t index, const value_t value, const bool_t reusing) +static INLINE void put_item(hash_data_t *const data, const size_t index, const item_t item, const bool_t reusing) { - data->values[index] = value; + data->items[index] = item; + if (reusing) { assert(get_flag(data->used, index)); @@ -169,13 +170,13 @@ static INLINE errno_t rebuild_set(hash_set_t *const instance, const size_t new_c { if (IS_VALID(instance->data, k)) { - const value_t value = instance->data.values[k]; - if (find_slot(&temp, value, &index, NULL)) + const item_t item = instance->data.items[k]; + if (find_slot(&temp, item, &index, NULL)) { free_data(&temp); return EFAULT; /*this should never happen!*/ } - put_value(&temp, index, value, FALSE); + put_item(&temp, index, item, FALSE); } } @@ -221,17 +222,17 @@ void DECLARE(hash_set_destroy)(hash_set_t *instance) } } -errno_t DECLARE(hash_set_insert)(hash_set_t *const instance, const value_t value) +errno_t DECLARE(hash_set_insert)(hash_set_t *const instance, const item_t item) { size_t index; bool_t slot_reused; - if ((!instance) || (!instance->data.values)) + if ((!instance) || (!instance->data.items)) { return EINVAL; } - if (find_slot(&instance->data, value, &index, &slot_reused)) + if (find_slot(&instance->data, item, &index, &slot_reused)) { return EEXIST; } @@ -243,13 +244,13 @@ errno_t DECLARE(hash_set_insert)(hash_set_t *const instance, const value_t value { return error; } - if (find_slot(&instance->data, value, &index, &slot_reused)) + if (find_slot(&instance->data, item, &index, &slot_reused)) { return EFAULT; } } - put_value(&instance->data, index, value, slot_reused); + put_item(&instance->data, index, item, slot_reused); instance->valid = safe_incr(instance->valid); if (slot_reused) @@ -260,26 +261,26 @@ errno_t DECLARE(hash_set_insert)(hash_set_t *const instance, const value_t value return 0; } -errno_t DECLARE(hash_set_contains)(const hash_set_t *const instance, const value_t value) +errno_t DECLARE(hash_set_contains)(const hash_set_t *const instance, const item_t item) { - if ((!instance) || (!instance->data.values)) + if ((!instance) || (!instance->data.items)) { return EINVAL; } - return (instance->valid && find_slot(&instance->data, value, NULL, NULL)) ? 0 : ENOENT; + return (instance->valid && find_slot(&instance->data, item, NULL, NULL)) ? 0 : ENOENT; } -errno_t DECLARE(hash_set_remove)(hash_set_t *const instance, const value_t value) +errno_t DECLARE(hash_set_remove)(hash_set_t *const instance, const item_t item) { size_t index; - if ((!instance) || (!instance->data.values)) + if ((!instance) || (!instance->data.items)) { return EINVAL; } - if ((!instance->valid) || (!find_slot(&instance->data, value, &index, NULL))) + if ((!instance->valid) || (!find_slot(&instance->data, item, &index, NULL))) { return ENOENT; } @@ -308,7 +309,7 @@ errno_t DECLARE(hash_set_remove)(hash_set_t *const instance, const value_t value errno_t DECLARE(hash_set_clear)(hash_set_t *const instance) { - if ((!instance) || (!instance->data.values)) + if ((!instance) || (!instance->data.items)) { return EINVAL; } @@ -337,29 +338,29 @@ errno_t DECLARE(hash_set_clear)(hash_set_t *const instance) return 0; } -errno_t DECLARE(hash_set_iterate)(const hash_set_t *const instance, uintptr_t *const cursor, value_t *const value) +errno_t DECLARE(hash_set_iterate)(const hash_set_t *const instance, size_t *const cursor, item_t *const item) { size_t index; - if ((!instance) || (!cursor) || (*cursor >= SIZE_MAX) || (!instance->data.values)) + if ((!instance) || (!cursor) || (*cursor >= SIZE_MAX) || (!instance->data.items)) { return EINVAL; } - for (index = (size_t)(*cursor); index < instance->data.capacity; ++index) + for (index = *cursor; index < instance->data.capacity; ++index) { if (IS_VALID(instance->data, index)) { - if (value) + if (item) { - *value = instance->data.values[index]; + *item = instance->data.items[index]; } - *cursor = (uintptr_t)(index + 1U); + *cursor = index + 1U; return 0; } } - *cursor = (uintptr_t)SIZE_MAX; + *cursor = SIZE_MAX; return ENOENT; } @@ -370,7 +371,7 @@ size_t DECLARE(hash_set_size)(const hash_set_t *const instance) errno_t DECLARE(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.items)) { return EINVAL; } @@ -395,18 +396,18 @@ errno_t DECLARE(hash_set_info)(const hash_set_t *const instance, size_t *const c return 0; } -HASHSET_API errno_t DECLARE(hash_set_dump)(const hash_set_t *const instance, int (*const callback)(const size_t index, const char status, const value_t value)) +HASHSET_API errno_t DECLARE(hash_set_dump)(const hash_set_t *const instance, int (*const callback)(const size_t index, const char status, const item_t item)) { size_t index; - if ((!instance) || (!instance->data.values)) + if ((!instance) || (!instance->data.items)) { return EINVAL; } for (index = 0U; index < instance->data.capacity; ++index) { - if (!callback(index, get_flag(instance->data.used, index) ? (get_flag(instance->data.deleted, index) ? 'd' : 'v') : 'u', instance->data.values[index])) + if (!callback(index, get_flag(instance->data.used, index) ? (get_flag(instance->data.deleted, index) ? 'd' : 'v') : 'u', instance->data.items[index])) { return ECANCELED; } @@ -415,4 +416,4 @@ HASHSET_API errno_t DECLARE(hash_set_dump)(const hash_set_t *const instance, int return 0; } -#endif /* _LIBHASHSET_GENERIC_INCLUDED */ +#endif /*_LIBHASHSET_GENERIC_SET_INCLUDED*/ diff --git a/libhashset/src/hash_map_32.c b/libhashset/src/hash_map_32.c new file mode 100644 index 0000000..ad1d195 --- /dev/null +++ b/libhashset/src/hash_map_32.c @@ -0,0 +1,12 @@ +/******************************************************************************/ +/* HashSet for C99, by LoRd_MuldeR */ +/* This work has been released under the CC0 1.0 Universal license! */ +/******************************************************************************/ + +#include + +#define NAME_SUFFIX 32 +typedef hash_map32_t hash_map_t; +typedef uint32_t key_t; + +#include "generic_hash_map.h" diff --git a/libhashset/src/hash_map_64.c b/libhashset/src/hash_map_64.c new file mode 100644 index 0000000..496ecc0 --- /dev/null +++ b/libhashset/src/hash_map_64.c @@ -0,0 +1,12 @@ +/******************************************************************************/ +/* HashSet for C99, by LoRd_MuldeR */ +/* This work has been released under the CC0 1.0 Universal license! */ +/******************************************************************************/ + +#include + +#define NAME_SUFFIX 64 +typedef hash_map64_t hash_map_t; +typedef uint64_t key_t; + +#include "generic_hash_map.h" diff --git a/libhashset/src/hash_set_32.c b/libhashset/src/hash_set_32.c index 40a1671..a6c3a92 100644 --- a/libhashset/src/hash_set_32.c +++ b/libhashset/src/hash_set_32.c @@ -4,10 +4,9 @@ /******************************************************************************/ #include -#include "common.h" #define NAME_SUFFIX 32 typedef hash_set32_t hash_set_t; -typedef uint32_t value_t; +typedef uint32_t item_t; -#include "generic.h" +#include "generic_hash_set.h" diff --git a/libhashset/src/hash_set_64.c b/libhashset/src/hash_set_64.c index c29bd78..12292b4 100644 --- a/libhashset/src/hash_set_64.c +++ b/libhashset/src/hash_set_64.c @@ -7,6 +7,6 @@ #define NAME_SUFFIX 64 typedef hash_set64_t hash_set_t; -typedef uint64_t value_t; +typedef uint64_t item_t; -#include "generic.h" +#include "generic_hash_set.h" diff --git a/libhashset/src/version.c b/libhashset/src/version.c index 17573c4..a79926f 100644 --- a/libhashset/src/version.c +++ b/libhashset/src/version.c @@ -6,8 +6,8 @@ #include const uint16_t HASHSET_VERSION_MAJOR = UINT16_C(1); -const uint16_t HASHSET_VERSION_MINOR = UINT16_C(1); +const uint16_t HASHSET_VERSION_MINOR = UINT16_C(2); const uint16_t HASHSET_VERSION_PATCH = UINT16_C(0); -const char* const HASHSET_BUILD_DATE = __DATE__; -const char* const HASHSET_BUILD_TIME = __TIME__; +const char *const HASHSET_BUILD_DATE = __DATE__; +const char *const HASHSET_BUILD_TIME = __TIME__; diff --git a/test/src/tests.c b/test/src/tests.c index 1e0adbf..28b0e5b 100644 --- a/test/src/tests.c +++ b/test/src/tests.c @@ -180,10 +180,9 @@ int test_function_1(hash_set64_t *const hash_set) int test_function_2(hash_set64_t *const hash_set) { - size_t r, j, capacity, valid, deleted, limit; + size_t r, j, cursor, capacity, valid, deleted, limit; uint64_t value; uint8_t spinner = 0U, *test1, *test2; - uintptr_t cursor; random_t random; random_init(&random);