Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions src/defs.h
Original file line number Diff line number Diff line change
Expand Up @@ -100,13 +100,13 @@ typedef struct {
typedef struct hashmap_node {
char *key;
void *val;
struct hashmap_node *next;
bool occupied;
} hashmap_node_t;

typedef struct {
int size;
int cap;
hashmap_node_t **buckets;
hashmap_node_t *table;
} hashmap_t;

/* lexer tokens */
Expand Down
132 changes: 60 additions & 72 deletions src/globals.c
Original file line number Diff line number Diff line change
Expand Up @@ -373,6 +373,9 @@ void arena_free(arena_t *arena)
*/
int hashmap_hash_index(int size, char *key)
{
if (!key)
return 0;

int hash = 0x811c9dc5;

for (; *key; key++) {
Expand Down Expand Up @@ -414,90 +417,61 @@ hashmap_t *hashmap_create(int cap)

map->size = 0;
map->cap = round_up_pow2(cap);
map->buckets = calloc(map->cap, sizeof(hashmap_node_t *));
map->table = calloc(map->cap, sizeof(hashmap_node_t));

if (!map->buckets) {
printf("Failed to allocate buckets in hashmap_t\n");
if (!map->table) {
printf("Failed to allocate table in hashmap_t\n");
free(map);
return NULL;
}

return map;
}

/* Create a hashmap node on heap.
* @key: The key of node. Must not be NULL.
* @val: The value of node. Could be NULL.
*
* Return: The pointer of created node.
*/
hashmap_node_t *hashmap_node_new(char *key, void *val)
{
if (!key)
return NULL;

const int len = strlen(key);
hashmap_node_t *node = arena_alloc(HASHMAP_ARENA, sizeof(hashmap_node_t));


if (!node) {
printf("Failed to allocate hashmap_node_t\n");
return NULL;
}

node->key = arena_alloc(HASHMAP_ARENA, len + 1);
if (!node->key) {
printf("Failed to allocate hashmap_node_t key with size %d\n", len + 1);
return NULL;
}

strcpy(node->key, key);
node->val = val;
node->next = NULL;
return node;
}

void hashmap_rehash(hashmap_t *map)
{
if (!map)
return;

int old_cap = map->cap;
hashmap_node_t **old_buckets = map->buckets;
hashmap_node_t *old_table = map->table;

map->cap <<= 1;
map->buckets = calloc(map->cap, sizeof(hashmap_node_t *));
map->table = calloc(map->cap, sizeof(hashmap_node_t));

if (!map->buckets) {
printf("Failed to allocate new buckets in hashmap_t\n");
map->buckets = old_buckets;
if (!map->table) {
printf("Failed to allocate new table in hashmap_t\n");
map->table = old_table;
map->cap = old_cap;
return;
}

map->size = 0;

for (int i = 0; i < old_cap; i++) {
hashmap_node_t *cur = old_buckets[i];
hashmap_node_t *next;
hashmap_node_t *target_cur;

while (cur) {
next = cur->next;
cur->next = NULL;
int index = hashmap_hash_index(map->cap, cur->key);
target_cur = map->buckets[index];

if (!target_cur) {
map->buckets[index] = cur;
} else {
cur->next = target_cur;
map->buckets[index] = cur;
if (old_table[i].occupied) {
char *key = old_table[i].key;
void *val = old_table[i].val;

int index = hashmap_hash_index(map->cap, key);
int start = index;

while (map->table[index].occupied) {
index = (index + 1) & (map->cap - 1);
if (index == start) {
printf("Error: New table is full during rehash\n");
abort();
}
}

cur = next;
map->table[index].key = key;
map->table[index].val = val;
map->table[index].occupied = true;
map->size++;
}
}

free(old_buckets);
free(old_table);
}

/* Put a key-value pair into given hashmap.
Expand All @@ -513,22 +487,30 @@ void hashmap_put(hashmap_t *map, char *key, void *val)
if (!map)
return;

/* Check if size of map exceeds load factor 50% (or 1/2 of capacity) */
if ((map->cap >> 1) <= map->size)
hashmap_rehash(map);

int index = hashmap_hash_index(map->cap, key);
hashmap_node_t *cur = map->buckets[index],
*new_node = hashmap_node_new(key, val);
int start = index;

if (!cur) {
map->buckets[index] = new_node;
} else {
while (cur->next)
cur = cur->next;
cur->next = new_node;
while (map->table[index].occupied) {
if (!strcmp(map->table[index].key, key)) {
map->table[index].val = val;
return;
}

index = (index + 1) & (map->cap - 1);
if (index == start) {
printf("Error: Hashmap is full\n");
abort();
}
}

map->table[index].key = arena_strdup(HASHMAP_ARENA, key);
map->table[index].val = val;
map->table[index].occupied = true;
map->size++;
/* Check if size of map exceeds load factor 75% (or 3/4 of capacity) */
if ((map->cap >> 2) + (map->cap >> 1) <= map->size)
hashmap_rehash(map);
}

/* Get key-value pair node from hashmap from given key.
Expand All @@ -544,10 +526,16 @@ hashmap_node_t *hashmap_get_node(hashmap_t *map, char *key)
return NULL;

int index = hashmap_hash_index(map->cap, key);
int start = index;

while (map->table[index].occupied) {
if (!strcmp(map->table[index].key, key))
return &map->table[index];

for (hashmap_node_t *cur = map->buckets[index]; cur; cur = cur->next)
if (!strcmp(cur->key, key))
return cur;
index = (index + 1) & (map->cap - 1);
if (index == start)
return NULL;
}

return NULL;
}
Expand Down Expand Up @@ -585,7 +573,7 @@ void hashmap_free(hashmap_t *map)
if (!map)
return;

free(map->buckets);
free(map->table);
free(map);
}

Expand Down