From 09a856de04a9f5ffe870d76025cf76613e6c5380 Mon Sep 17 00:00:00 2001 From: pkd Date: Thu, 25 Jul 2024 15:09:55 +0200 Subject: [PATCH] Moving hashatable to Cutils --- cutils.h | 70 ++++++++++++++++++++++++- src/hashtable.c | 137 ++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 206 insertions(+), 1 deletion(-) create mode 100644 src/hashtable.c diff --git a/cutils.h b/cutils.h index bffe5b6..cb0271f 100644 --- a/cutils.h +++ b/cutils.h @@ -109,6 +109,73 @@ int f_dbg__(int level,int line,const char* function,const char* file,char* messa #define dbg(level,message,...) f_dbg__(level,__LINE__,__func__,__FILE__,message,##__VA_ARGS__) +/* Hashtable (Dict) implementation */ + +// A pair of values : +// * key : the key of the pair (in bytes) +// * value : the value of the pair (pointer to anything) +typedef struct pair { + char* key; + void* value; +} pair; + +// An item in the hashtable : +// * data : the pairs of the item +// * size : the number of pairs in the item +// * capacity : the capacity of the item +typedef struct { + pair* data; + int size; + int capacity; +} item; + +// The hashtable : +// * items : the items in the hashtable +// * capacity : the capacity of the hashtable +typedef struct { + item *items; + int capacity; +} hashtable; + +// create a new hashtable +// * capacity : the capacity of the hashtable you want +hashtable *hm_create(int capacity); +// destroy a hashtable (free the memory) +// * hm : the hashtable you want to destroy +void hm_destroy(hashtable *hm); +// add a pair to the hashtable +// * hm : the hashtable you want to add the pair to +// * key : the key of the pair +// * value : the value of the pair +// Equivalent to hm[key] = value +int hm_add(hashtable *hm, char *key, void *value); +// get a value from the hashtable +// * hm : the hashtable you want to get the value from +// * key : the key of the pair +// Equivalent to hm[key] +void* hm_get(hashtable *hm, char *key); +// remove a pair from the hashtable +// * hm : the hashtable you want to remove the pair from +// * key : the key of the pair +// Equivalent to del hm[key] +int hm_rm(hashtable *hm, char *key); +// visualize the hashtable +// basic pretty print of the hashtable +// * hm : the hashtable you want to visualize +int hm_visualize(hashtable *hm); +// initialize a hashtable with a list of key-value pairs +// * kvlist : the list of key-value pairs +// * size : the size of the list +hashtable* hm_init(void* kvlist[][2],int size); +// get the hash of a key +// * hm : the hashtable you want to get the hash from +// * key : the key you want to get the hash of +// WARNING : Used only internally +unsigned int hm_hash(hashtable *hm, char *key);; + + + + // memory safety and debugging void* dbg_malloc(size_t size,char* file,int line); void* dbg_calloc(size_t nmemb,size_t size,char* file,int line); @@ -123,9 +190,10 @@ void dbg_free(void* ptr,char* file,int line); #define realloc(ptr,size) dbg_realloc(ptr,size,__FILE__,__LINE__) #define strdup(str) dbg_strdup(str,__FILE__,__LINE__) #define free(ptr) dbg_free(ptr,__FILE__,__LINE__) + + int check_leaks(); #endif -int check_leaks(); #endif diff --git a/src/hashtable.c b/src/hashtable.c new file mode 100644 index 0000000..001f0df --- /dev/null +++ b/src/hashtable.c @@ -0,0 +1,137 @@ +#include "stdio.h" +#include +#include + +#include "hashtable.h" +#include "cutils.h" + +hashtable* hm_create(int capacity) +{ + if (capacity == 0) capacity = 1024; + + hashtable *hm = calloc(1,sizeof(hashtable)); + hm->items = calloc(capacity, sizeof(item)); + if (hm->items == NULL) { + fprintf(stderr, "Out of memory"); + exit(1); + } + hm->capacity = capacity; + return hm; +} + +void hm_destroy(hashtable *hm) +{ + for (int i = 0; i < hm->capacity; i++) { + if (hm->items[i].data != NULL) { + free(hm->items[i].data); + } + } + free(hm->items); + free(hm); +} + +int hm_add(hashtable *hm, char *key, void *value) +{ + + int index = hm_hash(hm,key); + item x = hm->items[index]; + if (x.data == NULL) { + x.data = calloc(8, sizeof(pair)); + x.size = 0; + x.capacity = 8; + } + else if (x.size == x.capacity) { + x.capacity += 8; + //printf("reallocating %d\n", x.capacity); + x.data = realloc(x.data, sizeof(pair)*(x.capacity)); + } + + pair apair = {key, value}; + x.data[x.size++] = apair; + hm->items[index] = x; + + return 0; +} + +void* hm_get(hashtable *hm, char *key) +{ + int index = hm_hash(hm,key); + item x = hm->items[index]; + if (x.data == NULL) return NULL; + for (int i = 0; i < x.size; i++) { + if (strcmp(x.data[i].key,key) == 0) { + return x.data[i].value; + } + } + return NULL; +} + +// here we are converting a pair list into a hash table +hashtable* hm_init(void* kvlist[][2],int size) { + hashtable* hm = hm_create(size*2); + for (int i = 0; i < size; i++) { + hm_add(hm, kvlist[i][0], kvlist[i][1]); + } + return hm; +} + +int hm_rm(hashtable *hm, char *key) +{ + int index = hm_hash(hm,key); + item *x = &hm->items[index]; + if (x->data == NULL) return 1; + for (int i = 0; i < x->size; i++) { + if (strcmp(x->data[i].key,key) == 0) { + x->data[i] = x->data[x->size-1]; + //printf("replacing %s with %s\n", x->data[i].key, x->data[x->size-1].key); + x->size--; + if (x->size == 0) { + //printf("freeing %s\n", x->data[i].key); + free(x->data); + x->data = NULL; + } + return 0; + } + } + return 1; +} + +int hm_visualize(hashtable *hm) +{ + for (int i = 0; i < hm->capacity; i++) { + item x = hm->items[i]; + if (x.data == NULL) continue; + printf("===========================\n"); + printf("%d: ", i); + for (int j = 0; j < x.size; j++) { + printf("%s ", x.data[j].key); + } + printf("\n"); + printf("===========================\n"); + } + return 0; +} + +unsigned int hm_hash(hashtable *hm, char *key) +{ + if (key == NULL) return 0; + + unsigned int len = strlen(key); + + unsigned char *p = (unsigned char*) key; + unsigned int h = 0; + + while(len--) { + h += *p++; + h += (h << 9); + h ^= (h >> 19); + } + + h += (h << 3); + h ^= (h >> 17); + h += (h << 11); + + //printf("hash: %d\n", h % hm->capacity); + + return h % hm->capacity; +} \ No newline at end of file