Skip to content

Commit

Permalink
Moving hashatable to Cutils
Browse files Browse the repository at this point in the history
  • Loading branch information
palkh committed Jul 25, 2024
1 parent fa38903 commit 09a856d
Show file tree
Hide file tree
Showing 2 changed files with 206 additions and 1 deletion.
70 changes: 69 additions & 1 deletion cutils.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand All @@ -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

Expand Down
137 changes: 137 additions & 0 deletions src/hashtable.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
#include "stdio.h"
#include <stdlib.h>
#include <string.h>

#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;
}

0 comments on commit 09a856d

Please sign in to comment.