From 8447522dc230a9ce2187f648acd4385396c85f54 Mon Sep 17 00:00:00 2001 From: Danila Fedorin Date: Wed, 21 Dec 2016 01:07:47 -0800 Subject: [PATCH] Add and implement a hash table. --- CMakeLists.txt | 2 +- include/ht.h | 39 +++++++++++++++ src/ht.c | 129 +++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 169 insertions(+), 1 deletion(-) create mode 100644 include/ht.h create mode 100644 src/ht.c diff --git a/CMakeLists.txt b/CMakeLists.txt index 42907ae..c4f2349 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -3,7 +3,7 @@ project(libds) include_directories(include) -add_library(ds src/libds.c src/vec.c) +add_library(ds src/libds.c src/vec.c src/ht.c) add_executable(libds src/main.c) target_link_libraries(libds ds) diff --git a/include/ht.h b/include/ht.h new file mode 100644 index 0000000..bbab4f7 --- /dev/null +++ b/include/ht.h @@ -0,0 +1,39 @@ +#ifndef LIBDS_HT_HEADER +#define LIBDS_HT_HEADER + +#define LIBDS_HT_SIZE 32 + +#include "libds.h" + +struct ht_node_s { + void* key; + void* data; + struct ht_node_s* next; +}; + +struct ht_s { + struct ht_node_s* data[LIBDS_HT_SIZE]; + unsigned int (*hash_func)(void*); + int (*cmp_func)(void*, void*); + void* (*copy_func)(void*); + void (*free_func)(void*); +}; + +typedef struct ht_node_s ht_node; +typedef struct ht_s ht; + +unsigned int ht_default_hash_func(void*); +int ht_default_cmp_func(void*, void*); +void* ht_default_copy_func(void*); +void ht_default_free_func(void*); + +void ht_init(ht*); +void ht_free(ht*); + +libds_result ht_put(ht*, void*, void*); +void* ht_get(ht*, void*); +void ht_remove(ht*, void*); + +int ht_foreach(ht*, void*, compare_func, foreach_func, ...); + +#endif diff --git a/src/ht.c b/src/ht.c new file mode 100644 index 0000000..3347953 --- /dev/null +++ b/src/ht.c @@ -0,0 +1,129 @@ +#include "ht.h" +#include +#include + +unsigned int ht_default_hash_func(void* data){ + const unsigned int fnv_prime = 16777619; + const unsigned int fnv_offset_basis = 2166136261; + unsigned int hash; + char* string; + hash = fnv_offset_basis; + string = data; + while (*string) { + hash = hash * fnv_prime; + hash = hash ^ (*(string++)); + } + return hash; +} +int ht_default_cmp_func(void* a, void* b){ + return strcmp(a, b) == 0; +} +void* ht_default_copy_func(void* from) { + void* copy = malloc(sizeof(char) * (strlen(from) + 1)); + if(copy) { + strcpy(copy, from); + } + return copy; +} +void ht_default_free_func(void* data){ + free(data); +} + +void ht_init(ht* ht){ + ht->cmp_func = ht_default_cmp_func; + ht->copy_func = ht_default_copy_func; + ht->free_func = ht_default_free_func; + ht->hash_func = ht_default_hash_func; + memset(ht->data, 0, sizeof(ht->data)); +} +void ht_free(ht* ht){ + int index = 0; + for(; index < LIBDS_HT_SIZE; index++){ + ht_node* head = ht->data[index]; + while(head){ + ht_node* to_delete = head; + head = head->next; + ht->free_func(to_delete->key); + free(to_delete); + } + } +} + +libds_result ht_put(ht* ht, void* key, void* data){ + libds_result result = SUCCESS; + ht_node* new_node = NULL; + unsigned int key_int = ht->hash_func(key) % LIBDS_HT_SIZE; + + + new_node = malloc(sizeof(*new_node)); + if(new_node) { + new_node->data = data; + new_node->key = ht->copy_func(key); + if(new_node->key == NULL){ + result = MALLOC; + } + } else { + result = MALLOC; + } + + if(result != SUCCESS) { + if(new_node) { + free(new_node); + new_node = NULL; + } + } else { + new_node->next = ht->data[key_int]; + ht->data[key_int] = new_node; + } + + return result; +} +void* ht_get(ht* ht, void* key) { + void* data = NULL; + ht_node* search_node; + unsigned int key_int = ht->hash_func(key) % LIBDS_HT_SIZE; + + search_node = ht->data[key_int]; + while(search_node && data == NULL){ + if(ht->cmp_func(search_node->key, key)) { + data = search_node->data; + } + search_node = search_node->next; + } + + return data; +} +void ht_remove(ht* ht, void* key){ + ht_node** search_ptr; + unsigned int key_int = ht->hash_func(key) % LIBDS_HT_SIZE; + + search_ptr = &ht->data[key_int]; + while(*search_ptr){ + if(ht->cmp_func((*search_ptr)->key, key)){ + ht_node* to_delete = *search_ptr; + *search_ptr = (*search_ptr)->next; + ht->free_func(to_delete->key); + free(to_delete); + } else { + search_ptr = &(*search_ptr)->next; + } + } +} + +int ht_foreach(ht* ht, void* data, compare_func compare, foreach_func foreach, ...){ + int index = 0; + int return_code = 0; + va_list args; + for(; index < LIBDS_HT_SIZE && return_code == 0; index++){ + ht_node* search_node = ht->data[index]; + while(search_node && return_code == 0){ + if(compare(data, search_node->data)) { + va_start(args, foreach); + return_code = foreach(search_node->data, args); + va_end(args); + } + search_node = search_node->next; + } + } + return return_code; +} \ No newline at end of file