From 3dbf0313af23fdd1d0a38bc7c80af975ba34bc2e Mon Sep 17 00:00:00 2001 From: Andy Guenther Date: Wed, 23 Dec 2020 00:49:48 +0100 Subject: [PATCH] add new tpht functions * refactor/clean up code --- CMakeLists.txt | 9 +- include/oha.h | 30 ++-- src/CMakeLists.txt | 4 +- src/binary_heap.c | 32 ++-- src/linear_probing_hash_table.c | 48 +++--- src/prioritized_hash_table.c | 91 ------------ src/temporal_prioritized_hash_table.c | 137 ++++++++++++++++++ src/utils.h | 95 ++++++++++-- test/CMakeLists.txt | 15 +- test/benchmark.cpp | 7 + test/binary_heap_test.c | 8 +- ...est.c => linear_probing_hash_table_test.c} | 2 +- test/temporal_prioritized_hash_table_test.c | 64 ++++++++ 13 files changed, 370 insertions(+), 172 deletions(-) delete mode 100644 src/prioritized_hash_table.c create mode 100644 src/temporal_prioritized_hash_table.c rename test/{linear_hash_table_test.c => linear_probing_hash_table_test.c} (99%) create mode 100644 test/temporal_prioritized_hash_table_test.c diff --git a/CMakeLists.txt b/CMakeLists.txt index 8446807..a075dd1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -2,19 +2,20 @@ cmake_minimum_required (VERSION 3.0) project(oha C CXX) +# global vaiables +set(LIBNAME "oha") +set(PROJECT_COMPILE_OPTIONS -O3 -std=c11 -Wall -Wextra -Wpedantic) + option(ASAN "use adress sanitizer" OFF) if(ASAN) message(STATUS "Enable ASAN.") - add_compile_options(-fsanitize=address -fno-omit-frame-pointer) + set(PROJECT_COMPILE_OPTIONS -fsanitize=address -fno-omit-frame-pointer ${PROJECT_COMPILE_OPTIONS}) set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -fsanitize=address -fno-omit-frame-pointer") set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -fsanitize=address -fno-omit-frame-pointer") endif() option(WITH_KEY_FROM_VALUE_FUNC "enabled the function: 'oha_lpht_get_key_from_value()'" OFF) -set(LIBNAME "oha") -set(PROJECT_COMPILE_OPTIONS -O3 -std=c11 -Wall -Wextra -Wpedantic) - add_subdirectory(src) include(CTest) add_subdirectory(test) diff --git a/include/oha.h b/include/oha.h index 3c16860..307b20b 100644 --- a/include/oha.h +++ b/include/oha.h @@ -50,11 +50,13 @@ struct oha_lpht_status { struct oha_lpht * oha_lpht_create(const struct oha_lpht_config * config); void oha_lpht_destroy(struct oha_lpht * table); -void * oha_lpht_look_up(struct oha_lpht * table, const void * key); +__attribute__((pure)) +void * oha_lpht_look_up(const struct oha_lpht * table, const void * key); void * oha_lpht_insert(struct oha_lpht * table, const void * key); +__attribute__((pure)) void * oha_lpht_get_key_from_value(const void * value); void * oha_lpht_remove(struct oha_lpht * table, const void * key); -bool oha_lpht_get_status(struct oha_lpht * table, struct oha_lpht_status * status); +bool oha_lpht_get_status(const struct oha_lpht * table, struct oha_lpht_status * status); void oha_lpht_clear(struct oha_lpht * table); bool oha_lpht_get_next_element_to_remove(struct oha_lpht * table, struct oha_key_value_pair * pair); @@ -65,7 +67,7 @@ bool oha_lpht_get_next_element_to_remove(struct oha_lpht * table, struct oha_key * **********************************************************************************************************************/ struct oha_bh_config { - struct oha_memory_fp memory; + struct oha_memory_fp memory; size_t value_size; uint32_t max_elems; bool resizable; @@ -74,7 +76,8 @@ struct oha_bh_config { struct oha_bh; struct oha_bh * oha_bh_create(const struct oha_bh_config * config); void oha_bh_destroy(struct oha_bh * heap); -int64_t oha_bh_find_min(struct oha_bh * heap); +__attribute__((pure)) +int64_t oha_bh_find_min(const struct oha_bh * heap); void * oha_bh_delete_min(struct oha_bh * heap); void * oha_bh_insert(struct oha_bh * heap, int64_t key); int64_t oha_bh_change_key(struct oha_bh * heap, void * value, int64_t new_val); @@ -86,21 +89,20 @@ int64_t oha_bh_change_key(struct oha_bh * heap, void * value, int64_t new_val); * **********************************************************************************************************************/ struct oha_tpht; -#define OHA_MAX_TIMEOUT_SLOTS 10 struct oha_tpht_config { struct oha_lpht_config lpht_config; - int64_t timeout_slots[OHA_MAX_TIMEOUT_SLOTS]; - size_t number_of_timeout_slots; }; struct oha_tpht * oha_tpht_create(const struct oha_tpht_config * config); -void oha_tpht_destroy(struct oha_tpht * pht); -void * oha_tpht_insert(struct oha_tpht * pht, void * key, int64_t timestamp); -void * oha_tpht_look_up(struct oha_tpht * pht, void * key); -void * oha_tpht_remove(struct oha_tpht * pht, void * key); -void * oha_tpht_set_timeout_slot(struct oha_tpht * pht, void * key, size_t timeout_slot_id); -bool oha_tpht_next_timeout_entry(struct oha_tpht * pht, struct oha_key_value_pair * next_pair); -void * oha_tpht_update_time_for_entry(struct oha_tpht * pht, void * key, int64_t new_timestamp); +void oha_tpht_destroy(struct oha_tpht * tpht); +void * oha_tpht_insert(struct oha_tpht * tpht, const void * key, int64_t timestamp, uint8_t timeout_slot_id); +__attribute__((pure)) +void * oha_tpht_look_up(const struct oha_tpht * tpht, const void * key); +void * oha_tpht_remove(struct oha_tpht * tpht, const void * key); +int8_t oha_tpht_add_timeout_slot(struct oha_tpht * tpht, int64_t timeout, uint32_t num_elements, bool resizable); +void * oha_tpht_set_timeout_slot(struct oha_tpht * tpht, const void * key, uint8_t timeout_slot_id); +bool oha_tpht_next_timeout_entry(struct oha_tpht * tpht, struct oha_key_value_pair * next_pair); +void * oha_tpht_update_time_for_entry(struct oha_tpht * tpht, const void * key, int64_t new_timestamp); #ifdef __cplusplus } diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 158d9f8..501ec05 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,4 +1,6 @@ -set(SOURCE_FILES linear_probing_hash_table.c binary_heap.c prioritized_hash_table.c) +set(SOURCE_FILES linear_probing_hash_table.c + binary_heap.c + temporal_prioritized_hash_table.c) if(WITH_KEY_FROM_VALUE_FUNC) add_definitions(-DOHA_WITH_KEY_FROM_VALUE_SUPPORT) diff --git a/src/binary_heap.c b/src/binary_heap.c index 2de657f..af2f08f 100644 --- a/src/binary_heap.c +++ b/src/binary_heap.c @@ -40,7 +40,7 @@ static inline uint_fast32_t right(uint_fast32_t i) return (2 * i + 2); } -static inline void swap_keys(struct key_bucket * restrict a, struct key_bucket * restrict b) +static inline void swap_keys(struct key_bucket * const restrict a, struct key_bucket * const restrict b) { a->value->key = b; b->value->key = a; @@ -49,7 +49,7 @@ static inline void swap_keys(struct key_bucket * restrict a, struct key_bucket * *b = tmp_a; } -static inline void connect_keys_values(struct oha_bh * heap) +static inline void connect_keys_values(struct oha_bh * const heap) { // connect keys and values struct value_bucket * tmp_value = heap->values; @@ -60,7 +60,7 @@ static inline void connect_keys_values(struct oha_bh * heap) } } -static bool resize_table(struct oha_bh * heap) +static bool resize_table(struct oha_bh * const heap) { if (!heap->config.resizable) { return false; @@ -69,15 +69,17 @@ static bool resize_table(struct oha_bh * heap) struct oha_memory_fp * memory = &heap->config.memory; struct oha_bh tmp_heap = {0}; tmp_heap.config = heap->config; + // TODO add 32 bit overflow check tmp_heap.config.max_elems *= 2; + const struct oha_bh_config * config = &tmp_heap.config; - tmp_heap.keys = oha_calloc(memory, tmp_heap.config.max_elems * sizeof(struct key_bucket)); + tmp_heap.keys = oha_calloc(memory, config->max_elems * sizeof(struct key_bucket)); if (tmp_heap.keys == NULL) { return false; } - tmp_heap.value_size = add_alignment(sizeof(struct value_bucket) + tmp_heap.config.value_size); - tmp_heap.values = oha_malloc(memory, tmp_heap.config.max_elems * tmp_heap.value_size); + tmp_heap.value_size = add_alignment(sizeof(struct value_bucket) + config->value_size); + tmp_heap.values = oha_malloc(memory, config->max_elems * tmp_heap.value_size); if (tmp_heap.values == NULL) { oha_free(memory, tmp_heap.keys); return false; @@ -89,7 +91,7 @@ static bool resize_table(struct oha_bh * heap) while (OHA_BH_NOT_FOUND != (tmp_key = oha_bh_find_min(heap))) { void * value = oha_bh_delete_min(heap); void * new_value = oha_bh_insert(&tmp_heap, tmp_key); - memcpy(new_value, value, heap->value_size); + memcpy(new_value, value, config->value_size); } // destroy old table buffers @@ -102,7 +104,7 @@ static bool resize_table(struct oha_bh * heap) return true; } -static void heapify(struct oha_bh * heap, uint_fast32_t i) +static void heapify(struct oha_bh * const heap, uint_fast32_t i) { uint_fast32_t l = left(i); uint_fast32_t r = right(i); @@ -117,7 +119,7 @@ static void heapify(struct oha_bh * heap, uint_fast32_t i) } } -void oha_bh_destroy(struct oha_bh * heap) +void oha_bh_destroy(struct oha_bh * const heap) { if (heap == NULL) { return; @@ -128,14 +130,14 @@ void oha_bh_destroy(struct oha_bh * heap) oha_free(memory, heap); } -struct oha_bh * oha_bh_create(const struct oha_bh_config * config) +struct oha_bh * oha_bh_create(const struct oha_bh_config * const config) { if (config == NULL) { return NULL; } const struct oha_memory_fp * memory = &config->memory; - struct oha_bh * heap = oha_calloc(memory, sizeof(struct oha_bh)); + struct oha_bh * const heap = oha_calloc(memory, sizeof(struct oha_bh)); if (heap == NULL) { return NULL; } @@ -160,7 +162,7 @@ struct oha_bh * oha_bh_create(const struct oha_bh_config * config) return heap; } -void * oha_bh_insert(struct oha_bh * heap, int64_t key) +void * oha_bh_insert(struct oha_bh * const heap, int64_t key) { if (heap == NULL) { return NULL; @@ -185,7 +187,7 @@ void * oha_bh_insert(struct oha_bh * heap, int64_t key) return heap->keys[i].value->value_buffer; } -int64_t oha_bh_find_min(struct oha_bh * heap) +int64_t oha_bh_find_min(const struct oha_bh * const heap) { if (heap == NULL || heap->elems == 0) { return OHA_BH_NOT_FOUND; @@ -193,7 +195,7 @@ int64_t oha_bh_find_min(struct oha_bh * heap) return heap->keys[0].key; } -void * oha_bh_delete_min(struct oha_bh * heap) +void * oha_bh_delete_min(struct oha_bh * const heap) { if (heap == NULL) { return NULL; @@ -214,7 +216,7 @@ void * oha_bh_delete_min(struct oha_bh * heap) return heap->keys[heap->elems].value->value_buffer; } -int64_t oha_bh_change_key(struct oha_bh * heap, void * value, int64_t new_val) +int64_t oha_bh_change_key(struct oha_bh * const heap, void * const value, int64_t new_val) { if (heap == NULL || value == NULL) { return 0; diff --git a/src/linear_probing_hash_table.c b/src/linear_probing_hash_table.c index abcbdea..a78234e 100644 --- a/src/linear_probing_hash_table.c +++ b/src/linear_probing_hash_table.c @@ -69,7 +69,7 @@ struct oha_lpht { bool clear_mode_on; }; -static inline void * get_value(struct key_bucket * bucket) +static inline void * get_value(const struct key_bucket * const bucket) { #ifdef OHA_WITH_KEY_FROM_VALUE_SUPPORT return bucket->value->value_buffer; @@ -79,12 +79,12 @@ static inline void * get_value(struct key_bucket * bucket) } // does not support overflow -static void * get_next_value(struct oha_lpht * table, VALUE_BUCKET_TYPE * value) +static void * get_next_value(const struct oha_lpht * const table, const VALUE_BUCKET_TYPE * const value) { return move_ptr_num_bytes(value, table->config.value_size); } -static uint64_t hash_key(struct oha_lpht * table, const void * key) +static uint64_t hash_key(const struct oha_lpht * const table, const void * const key) { #ifdef OHA_FIX_KEY_SIZE_IN_BYTES (void)table; @@ -94,13 +94,13 @@ static uint64_t hash_key(struct oha_lpht * table, const void * key) #endif } -static struct key_bucket * get_start_bucket(struct oha_lpht * table, uint64_t hash) +static struct key_bucket * get_start_bucket(const struct oha_lpht * const table, uint64_t hash) { size_t index = oha_map_range_u32(hash, table->storage.max_indicies); return move_ptr_num_bytes(table->key_buckets, table->storage.key_bucket_size * index); } -static struct key_bucket * get_next_bucket(struct oha_lpht * table, struct key_bucket * bucket) +static struct key_bucket * get_next_bucket(const struct oha_lpht * const table, const struct key_bucket * const bucket) { struct key_bucket * current = move_ptr_num_bytes(bucket, table->storage.key_bucket_size); // overflow, get to the first elem @@ -110,7 +110,7 @@ static struct key_bucket * get_next_bucket(struct oha_lpht * table, struct key_b return current; } -static void swap_bucket_values(struct key_bucket * restrict a, struct key_bucket * restrict b) +static void swap_bucket_values(struct key_bucket * const restrict a, struct key_bucket * const restrict b) { #ifdef OHA_WITH_KEY_FROM_VALUE_SUPPORT a->value->key = b; @@ -121,7 +121,7 @@ static void swap_bucket_values(struct key_bucket * restrict a, struct key_bucket b->value = tmp; } -static bool calculate_storage_values(struct oha_lpht_config * config, struct storage_info * values) +static bool calculate_storage_values(struct oha_lpht_config * const config, struct storage_info * const values) { if (config == NULL || values == NULL) { return false; @@ -150,9 +150,9 @@ static bool calculate_storage_values(struct oha_lpht_config * config, struct sto return true; } -static struct oha_lpht * init_table_value(const struct oha_lpht_config * config, - const struct storage_info * storage, - struct oha_lpht * table) +static struct oha_lpht * init_table_value(const struct oha_lpht_config * const config, + const struct storage_info * const storage, + struct oha_lpht * const table) { table->storage = *storage; const struct oha_memory_fp * memory = &table->config.memory; @@ -189,7 +189,7 @@ static struct oha_lpht * init_table_value(const struct oha_lpht_config * config, } // restores the hash table invariant -static void probify(struct oha_lpht * table, struct key_bucket * start_bucket, uint_fast32_t offset) +static void probify(struct oha_lpht * const table, struct key_bucket * const start_bucket, uint_fast32_t offset) { struct key_bucket * bucket = start_bucket; uint_fast32_t i = 0; @@ -211,7 +211,7 @@ static void probify(struct oha_lpht * table, struct key_bucket * start_bucket, u } while (bucket->is_occupied); } -static bool resize_table(struct oha_lpht * table) +static bool resize_table(struct oha_lpht * const table) { if (!table->config.resizable) { return false; @@ -219,6 +219,7 @@ static bool resize_table(struct oha_lpht * table) struct oha_lpht tmp_table = {0}; tmp_table.config = table->config; + // TODO add overflow check 32 bit tmp_table.config.max_elems *= 2; struct storage_info storage; @@ -267,7 +268,7 @@ static bool resize_table(struct oha_lpht * table) * public functions */ -void oha_lpht_destroy(struct oha_lpht * table) +void oha_lpht_destroy(struct oha_lpht * const table) { if (table == NULL) { return; @@ -279,9 +280,9 @@ void oha_lpht_destroy(struct oha_lpht * table) oha_free(memory, table); } -struct oha_lpht * oha_lpht_create(const struct oha_lpht_config * config) +struct oha_lpht * oha_lpht_create(const struct oha_lpht_config * const config) { - struct oha_lpht * table = oha_calloc(&config->memory, sizeof(struct oha_lpht)); + struct oha_lpht * const table = oha_calloc(&config->memory, sizeof(struct oha_lpht)); if (table == NULL) { return NULL; } @@ -297,7 +298,7 @@ struct oha_lpht * oha_lpht_create(const struct oha_lpht_config * config) } // return pointer to value -void * oha_lpht_look_up(struct oha_lpht * table, const void * key) +void * oha_lpht_look_up(const struct oha_lpht * const table, const void * const key) { if (table == NULL || key == NULL) { return NULL; @@ -315,7 +316,7 @@ void * oha_lpht_look_up(struct oha_lpht * table, const void * key) } // return pointer to value -void * oha_lpht_insert(struct oha_lpht * table, const void * key) +void * oha_lpht_insert(struct oha_lpht * const table, const void * const key) { if (table == NULL || key == NULL) { return NULL; @@ -348,7 +349,7 @@ void * oha_lpht_insert(struct oha_lpht * table, const void * key) return get_value(bucket); } -void * oha_lpht_get_key_from_value(const void * value) +void * oha_lpht_get_key_from_value(const void * const value) { #ifdef OHA_WITH_KEY_FROM_VALUE_SUPPORT if (value == NULL) { @@ -364,7 +365,7 @@ void * oha_lpht_get_key_from_value(const void * value) #endif } -void oha_lpht_clear(struct oha_lpht * table) +void oha_lpht_clear(struct oha_lpht * const table) { if (table == NULL) { return; @@ -375,7 +376,7 @@ void oha_lpht_clear(struct oha_lpht * table) } } -bool oha_lpht_get_next_element_to_remove(struct oha_lpht * table, struct oha_key_value_pair * pair) +bool oha_lpht_get_next_element_to_remove(struct oha_lpht * const table, struct oha_key_value_pair * const pair) { if (table == NULL || !table->clear_mode_on || pair == NULL) { return false; @@ -399,7 +400,7 @@ bool oha_lpht_get_next_element_to_remove(struct oha_lpht * table, struct oha_key } // return true if element was in the table -void * oha_lpht_remove(struct oha_lpht * table, const void * key) +void * oha_lpht_remove(struct oha_lpht * const table, const void * const key) { uint64_t hash = hash_key(table, key); @@ -451,7 +452,7 @@ void * oha_lpht_remove(struct oha_lpht * table, const void * key) return value; } -bool oha_lpht_get_status(struct oha_lpht * table, struct oha_lpht_status * status) +bool oha_lpht_get_status(const struct oha_lpht * const table, struct oha_lpht_status * const status) { if (table == NULL || status == NULL) { return false; @@ -459,6 +460,7 @@ bool oha_lpht_get_status(struct oha_lpht * table, struct oha_lpht_status * statu status->max_elems = table->max_elems; status->elems_in_use = table->elems; - status->size_in_bytes = table->config.value_size; + status->size_in_bytes = + table->storage.hash_table_size_keys + table->storage.hash_table_size_values + sizeof(struct oha_lpht); return true; } diff --git a/src/prioritized_hash_table.c b/src/prioritized_hash_table.c deleted file mode 100644 index ef9718b..0000000 --- a/src/prioritized_hash_table.c +++ /dev/null @@ -1,91 +0,0 @@ -#include "oha.h" - -#include - -struct oha_tpht { - struct oha_lpht * lpht; - struct oha_bh * bh; - int64_t last_timestamp; -}; - -struct storage_info { - size_t hash_table_size; -}; - -struct oha_tpht * oha_tpht_create(const struct oha_tpht_config * config) -{ - if (config == NULL) { - return NULL; - } - - if (config->number_of_timeout_slots == 0 || config->number_of_timeout_slots > OHA_MAX_TIMEOUT_SLOTS) { - return NULL; - } - - struct oha_tpht * table = calloc(1, sizeof(struct oha_tpht)); - if (table == NULL) { - return NULL; - } - table->lpht = oha_lpht_create(&config->lpht_config); - - struct oha_bh_config bh_config = { - .value_size = config->lpht_config.key_size, - .max_elems = config->lpht_config.max_elems, - }; - - table->bh = oha_bh_create(&bh_config); - if (table->bh == NULL) { - oha_lpht_destroy(table->lpht); - return NULL; - } - - return table; -} - -void oha_tpht_destroy(struct oha_tpht * pht) -{ - if (pht == NULL) { - return; - } - oha_lpht_destroy(pht->lpht); - oha_bh_destroy(pht->bh); -} - -void * oha_tpht_insert(struct oha_tpht * pht, void * key, int64_t timestamp) -{ - (void)pht; - (void)key; - (void)timestamp; - return NULL; -} - -void * oha_tpht_look_up(struct oha_tpht * pht, void * key) -{ - (void)pht; - (void)key; - - return NULL; -} - -void * oha_tpht_remove(struct oha_tpht * pht, void * key) -{ - (void)pht; - (void)key; - return NULL; -} - -bool oha_tpht_next_timeout_entry(struct oha_tpht * pht, struct oha_key_value_pair * next_pair) -{ - (void)pht; - (void)next_pair; - - return false; -} - -void * oha_tpht_update_time_for_entry(struct oha_tpht * pht, void * key, int64_t new_timestamp) -{ - (void)pht; - (void)key; - (void)new_timestamp; - return NULL; -} diff --git a/src/temporal_prioritized_hash_table.c b/src/temporal_prioritized_hash_table.c new file mode 100644 index 0000000..e989f3e --- /dev/null +++ b/src/temporal_prioritized_hash_table.c @@ -0,0 +1,137 @@ +#include "oha.h" + +#include +#include + +#include "utils.h" + +struct storage_info { + size_t hash_table_size; + uint8_t number_of_timeout_slots; +}; + +struct timeout_slot { + struct oha_bh * bh; + int64_t timeout; +}; + +struct oha_tpht { + struct oha_lpht * lpht; + struct timeout_slot * slots; + size_t num_timeout_slots; + int64_t last_timestamp; + struct storage_info storage; + struct oha_lpht_config lpht_config; +}; + +struct oha_tpht * oha_tpht_create(const struct oha_tpht_config * const config) +{ + if (config == NULL) { + return NULL; + } + + struct oha_tpht * table = oha_calloc(&config->lpht_config.memory, sizeof(struct oha_tpht)); + if (table == NULL) { + return NULL; + } + table->lpht = oha_lpht_create(&config->lpht_config); + + return table; +} + +int8_t oha_tpht_add_timeout_slot(struct oha_tpht * const tpht, int64_t timeout, uint32_t num_elements, bool resizable) +{ + if (tpht == NULL) { + return -1; + } + + if (tpht->num_timeout_slots >= SCHAR_MAX) { + return -2; + } + + const size_t next_free_index = tpht->num_timeout_slots; + + if (!oha_add_entry_to_array( + &tpht->lpht_config.memory, (void *)&tpht->slots, sizeof(*tpht->slots), &tpht->num_timeout_slots)) { + return -3; + } + + const struct oha_bh_config bh_config = { + .memory = tpht->lpht_config.memory, + .value_size = tpht->lpht_config.key_size, + .max_elems = num_elements, + .resizable = resizable, + }; + + struct timeout_slot * next_free_slot = &tpht->slots[next_free_index]; + + next_free_slot->bh = oha_bh_create(&bh_config); + next_free_slot->timeout = timeout; + if (next_free_slot->bh == NULL) { + oha_remove_entry_from_array(&tpht->lpht_config.memory, + (void *)&tpht->slots, + sizeof(*tpht->slots), + &tpht->num_timeout_slots, + next_free_index); + } + + return tpht->num_timeout_slots; +} + +void oha_tpht_destroy(struct oha_tpht * const tpht) +{ + if (tpht == NULL) { + return; + } + + oha_lpht_destroy(tpht->lpht); + tpht->lpht = NULL; + + for (size_t i = 0; i < tpht->num_timeout_slots; i++) { + oha_bh_destroy(tpht->slots[i].bh); + } + oha_free(&tpht->lpht_config.memory, tpht->slots); + tpht->slots = NULL; + + oha_free(&tpht->lpht_config.memory, tpht); +} + +void * oha_tpht_insert(struct oha_tpht * const pht, const void * const key, int64_t timestamp, uint8_t timeout_slot_id) +{ + (void)pht; + (void)key; + (void)timestamp; + (void)timeout_slot_id; + return NULL; +} + +void * oha_tpht_look_up(const struct oha_tpht * const pht, const void * const key) +{ + (void)pht; + (void)key; + + return NULL; +} + +void * oha_tpht_remove(struct oha_tpht * const pht, const void * const key) +{ + (void)pht; + (void)key; + return NULL; +} + +bool oha_tpht_next_timeout_entry(struct oha_tpht * const pht, struct oha_key_value_pair * const next_pair) +{ + (void)pht; + (void)next_pair; + + return false; +} + +void * oha_tpht_update_time_for_entry(struct oha_tpht * const pht, const void * const key, int64_t new_timestamp) +{ + (void)pht; + (void)key; + (void)new_timestamp; + return NULL; +} diff --git a/src/utils.h b/src/utils.h index 0333f86..6e860ad 100644 --- a/src/utils.h +++ b/src/utils.h @@ -3,6 +3,8 @@ #include #include +#include +#include #include "oha.h" @@ -22,12 +24,12 @@ static inline size_t add_alignment(size_t unaligned_size) return unaligned_size + (unaligned_size % SIZE_T_WIDTH); } -static inline void * move_ptr_num_bytes(void * ptr, size_t num_bytes) +static inline void * move_ptr_num_bytes(const void * const ptr, size_t num_bytes) { return (((uint8_t *)ptr) + num_bytes); } -static inline void oha_free(const struct oha_memory_fp * memory, void * ptr) +static inline void oha_free(const struct oha_memory_fp * const memory, void * const ptr) { assert(memory); if (memory->free != NULL) { @@ -38,7 +40,7 @@ static inline void oha_free(const struct oha_memory_fp * memory, void * ptr) } } -static inline void * oha_calloc(const struct oha_memory_fp * memory, size_t size) +static inline void * oha_calloc(const struct oha_memory_fp * const memory, size_t size) { assert(memory); void * ptr; @@ -53,7 +55,7 @@ static inline void * oha_calloc(const struct oha_memory_fp * memory, size_t size return ptr; } -static inline void * oha_malloc(const struct oha_memory_fp * memory, size_t size) +static inline void * oha_malloc(const struct oha_memory_fp * const memory, size_t size) { assert(memory); void * ptr; @@ -65,9 +67,19 @@ static inline void * oha_malloc(const struct oha_memory_fp * memory, size_t size return ptr; } -static inline void * oha_realloc(const struct oha_memory_fp * memory, void * ptr, size_t size) +static inline void * oha_realloc(const struct oha_memory_fp * const memory, void * const ptr, size_t size) { assert(memory); + + if (ptr == NULL) { + return oha_malloc(memory, size); + } + + if (size == 0) { + oha_free(memory, ptr); + return NULL; + } + if (memory->realloc != NULL) { return memory->realloc(ptr, size, memory->alloc_user_ptr); } else { @@ -75,14 +87,73 @@ static inline void * oha_realloc(const struct oha_memory_fp * memory, void * ptr } } - /** -* creates a modulo without division -* - modulo could takes up to 20 cycles -* - multiplication takes about 3 cycles -*/ -static inline uint32_t oha_map_range_u32(uint32_t word, uint32_t p) { - return (uint32_t)(((uint64_t)word * (uint64_t)p) >> 32); + * creates a modulo without division + * - modulo could takes up to 20 cycles + * - multiplication takes about 3 cycles + */ +static inline uint32_t oha_map_range_u32(uint32_t word, uint32_t p) +{ + return (uint32_t)(((uint64_t)word * (uint64_t)p) >> 32); +} + +static inline bool oha_add_entry_to_array(const struct oha_memory_fp * const memory, + void ** const array, + size_t entry_size, + size_t * const entry_count) +{ + assert(memory); + if (array == NULL || entry_count == NULL) { + return false; + } + + if (entry_size == 0) { + return false; + } + + if (*array == NULL) { + *entry_count = 0; + } + + uint8_t * new_memory = oha_realloc(memory, *array, entry_size * ((*entry_count) + 1)); + if (new_memory != NULL) { + (*entry_count)++; + *array = new_memory; + return true; + } + + return false; +} + +static inline bool oha_remove_entry_from_array(const struct oha_memory_fp * const memory, + void ** const array, + size_t entry_size, + size_t * const entry_count, + size_t entry_index) +{ + assert(memory); + if (array == NULL || entry_count == NULL || entry_index >= (*entry_count)) { + return false; + } + + if (*array == NULL || *entry_count == 0) { + return false; + } + + if (entry_index < (*entry_count) - 1) { + memcpy(((uint8_t *)(*array)) + entry_index * entry_size, + ((uint8_t *)(*array)) + ((*entry_count) - 1) * entry_size, + entry_size); + } + + void * new_memory = oha_realloc(memory, *array, entry_size * (*entry_count - 1)); + if (new_memory != *array) { + *array = new_memory; + } + + (*entry_count)--; + + return true; } #endif diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index db67387..29d8d95 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -20,15 +20,18 @@ target_include_directories(${LIBNAME}_unity PUBLIC ${MODULE_UNITY_PATH}/src/) target_compile_options(${LIBNAME}_unity PRIVATE ${PROJECT_COMPILE_OPTIONS}) # add tests -add_unit_test(linear_hash_table_test_shared linear_hash_table_test.c) -target_link_libraries(linear_hash_table_test_shared ${LIBNAME}) +add_unit_test(linear_probing_hash_table_test_shared linear_probing_hash_table_test.c) +target_link_libraries(linear_probing_hash_table_test_shared ${LIBNAME}) -add_unit_test(linear_hash_table_test_static linear_hash_table_test.c) -target_link_libraries(linear_hash_table_test_static ${LIBNAME}_static) +add_unit_test(linear_probing_hash_table_test_static linear_probing_hash_table_test.c) +target_link_libraries(linear_probing_hash_table_test_static ${LIBNAME}_static) # add tests -add_unit_test(linear_hash_table_test_fix_key_8 linear_hash_table_test.c) -target_link_libraries(linear_hash_table_test_fix_key_8 ${LIBNAME}_static_8) +add_unit_test(linear_probing_hash_table_test_fix_key_8 linear_probing_hash_table_test.c) +target_link_libraries(linear_probing_hash_table_test_fix_key_8 ${LIBNAME}_static_8) + +add_unit_test(temporal_prioritized_hash_table_test_static temporal_prioritized_hash_table_test.c) +target_link_libraries(temporal_prioritized_hash_table_test_static ${LIBNAME}_static) add_unit_test(binary_heap_test_shared binary_heap_test.c) target_link_libraries(binary_heap_test_shared ${LIBNAME}) diff --git a/test/benchmark.cpp b/test/benchmark.cpp index 4c97b94..51adb1d 100644 --- a/test/benchmark.cpp +++ b/test/benchmark.cpp @@ -130,9 +130,16 @@ int main(int argc, char * argv[]) switch (mode) { case 1: value = (struct value *)oha_lpht_look_up(table, &key); + if (value == NULL) { + exit(1); + } break; case 2: unordered_map::const_iterator got = umap->find(key); + if (got == umap->end()) { + exit(2); + } + break; } lookups++; break; diff --git a/test/binary_heap_test.c b/test/binary_heap_test.c index 08e93be..59dd46b 100644 --- a/test/binary_heap_test.c +++ b/test/binary_heap_test.c @@ -119,7 +119,7 @@ void test_insert_delete_min_check_value_ptr() free(big_rand_array); } -void test_insert_delete_min_check_value_ptr_resizable() +void test_insert_delete_min_resizable() { const size_t array_size = 10000; struct oha_bh_config config = {0}; @@ -131,7 +131,6 @@ void test_insert_delete_min_check_value_ptr_resizable() struct key_value_pair { int64_t key; - int64_t value; }; struct key_value_pair * big_rand_array = calloc(sizeof(struct key_value_pair), array_size); @@ -142,7 +141,6 @@ void test_insert_delete_min_check_value_ptr_resizable() int64_t * tmp_value = oha_bh_insert(heap, big_rand_array[i].key); TEST_ASSERT_NOT_NULL(tmp_value); *tmp_value = big_rand_array[i].key; - big_rand_array[i].value = big_rand_array[i].key; } qsort(big_rand_array, array_size, sizeof(struct key_value_pair), compare_int64_t); @@ -152,7 +150,7 @@ void test_insert_delete_min_check_value_ptr_resizable() TEST_ASSERT_EQUAL_INT64(big_rand_array[i].key, next_min); int64_t * tmp_value = oha_bh_delete_min(heap); TEST_ASSERT_NOT_NULL(tmp_value); - TEST_ASSERT_EQUAL_PTR(big_rand_array[i].value, *tmp_value); + TEST_ASSERT_EQUAL_INT64(big_rand_array[i].key, *tmp_value); } oha_bh_destroy(heap); @@ -265,7 +263,7 @@ int main(void) RUN_TEST(test_create_destroy); RUN_TEST(test_insert_delete_min); RUN_TEST(test_insert_delete_min_check_value_ptr); - RUN_TEST(test_insert_delete_min_check_value_ptr_resizable); + RUN_TEST(test_insert_delete_min_resizable); RUN_TEST(test_decrease_key); RUN_TEST(test_increase_key); diff --git a/test/linear_hash_table_test.c b/test/linear_probing_hash_table_test.c similarity index 99% rename from test/linear_hash_table_test.c rename to test/linear_probing_hash_table_test.c index e4ae48f..2ac7764 100644 --- a/test/linear_hash_table_test.c +++ b/test/linear_probing_hash_table_test.c @@ -51,7 +51,7 @@ void test_insert_look_up() TEST_ASSERT_NULL(value_lool_up); } - struct oha_lpht_status status; + struct oha_lpht_status status = {0}; TEST_ASSERT_TRUE(oha_lpht_get_status(table, &status)); TEST_ASSERT_EQUAL_UINT64(i, status.elems_in_use); TEST_ASSERT_EQUAL_UINT64(config.max_elems, status.max_elems); diff --git a/test/temporal_prioritized_hash_table_test.c b/test/temporal_prioritized_hash_table_test.c new file mode 100644 index 0000000..b6a6750 --- /dev/null +++ b/test/temporal_prioritized_hash_table_test.c @@ -0,0 +1,64 @@ +#include + +#include + +#include "oha.h" + +// good for testing to create collisions +#define LOAF_FACTOR 0.7 + +/* Is run before every test, put unit init calls here. */ +void setUp(void) +{ +} +/* Is run after every test, put unit clean-up calls here. */ +void tearDown(void) +{ +} + +void test_create_destroy() +{ + struct oha_lpht_config config_lpht; + memset(&config_lpht, 0, sizeof(config_lpht)); + config_lpht.load_factor = LOAF_FACTOR; + config_lpht.key_size = sizeof(uint64_t); + config_lpht.value_size = sizeof(uint64_t); + config_lpht.max_elems = 100; + struct oha_tpht_config config; + config.lpht_config = config_lpht; + + struct oha_tpht * table = oha_tpht_create(&config); + TEST_ASSERT_NOT_NULL(table); + oha_tpht_destroy(table); +} + +void test_create_destroy_add_slot() +{ + struct oha_lpht_config config_lpht; + memset(&config_lpht, 0, sizeof(config_lpht)); + config_lpht.load_factor = LOAF_FACTOR; + config_lpht.key_size = sizeof(uint64_t); + config_lpht.value_size = sizeof(uint64_t); + config_lpht.max_elems = 100; + struct oha_tpht_config config; + config.lpht_config = config_lpht; + + struct oha_tpht * table = oha_tpht_create(&config); + TEST_ASSERT_NOT_NULL(table); + + for (int8_t i = 1; i < SCHAR_MAX; i++) { + TEST_ASSERT_EQUAL(i, oha_tpht_add_timeout_slot(table, i, 100, false)); + } + + oha_tpht_destroy(table); +} + +int main(void) +{ + UNITY_BEGIN(); + + RUN_TEST(test_create_destroy); + RUN_TEST(test_create_destroy_add_slot); + + return UNITY_END(); +}