From b7b6a6a8d5ce3748c07c4e789b954ec9d22813ba Mon Sep 17 00:00:00 2001 From: "william.valenduc" Date: Sat, 17 Jan 2026 22:45:27 +0000 Subject: [PATCH] feat(hash_map): hash_map --- src/utils/hash_map/hash_map.c | 173 ++++++++++++++++++++++++++++++++++ src/utils/hash_map/hash_map.h | 34 +++++++ 2 files changed, 207 insertions(+) create mode 100644 src/utils/hash_map/hash_map.c create mode 100644 src/utils/hash_map/hash_map.h diff --git a/src/utils/hash_map/hash_map.c b/src/utils/hash_map/hash_map.c new file mode 100644 index 0000000..dec698c --- /dev/null +++ b/src/utils/hash_map/hash_map.c @@ -0,0 +1,173 @@ +#include "hash_map.h" + +#include +#include +#include +#include +#include +#include + +/* +** Hash the key using FNV-1a 32 bits hash algorithm. +*/ +static size_t hash(const char *key) +{ + if (key == NULL) + return 0; + + uint32_t hash = 2166136261; // FNV offset basis + uint32_t prime = 16777619; // FNV prime + + while (*key != 0) + { + hash ^= *key; + hash *= prime; + key++; + } + + return hash; +} + +struct hash_map *hash_map_init(size_t size) +{ + struct hash_map *p = malloc(sizeof(struct hash_map)); + if (p != NULL) + { + p->data = calloc(size, sizeof(struct pair_list *)); + if (p->data == NULL) + { + free(p); + return NULL; + } + p->size = size; + } + return p; +} + +bool hash_map_insert(struct hash_map *hash_map, const char *key, void *value, + bool *updated) +{ + if (hash_map == NULL || hash_map->size == 0 || key == NULL) + return false; + + size_t h = hash(key); + struct pair_list **l = hash_map->data; + size_t i = h % hash_map->size; + + if (l[i] != NULL) + { + // check if key is in linked list + struct pair_list *iter = l[i]; + while (iter) + { + if (strcmp(iter->key, key) == 0) + { + // update + iter->value = value; + if (updated) + *updated = true; + return true; + } + iter = iter->next; + } + + // if not found => collision + } + struct pair_list *p = malloc(sizeof(struct pair_list)); + if (p == NULL) + return false; + + if (updated) + *updated = false; + + p->key = key; + p->value = value; + p->next = l[i]; + l[i] = p; + l[i] = p; + return true; +} + +void hash_map_free(struct hash_map *hash_map) +{ + struct pair_list *l; + struct pair_list *prev; + + if (hash_map) + { + for (size_t i = 0; i < hash_map->size; i++) + { + l = hash_map->data[i]; + while (l != NULL) + { + prev = l; + l = l->next; + free(prev); + } + } + free(hash_map->data); + free(hash_map); + } +} + +void hash_map_foreach(struct hash_map *hash_map, + void (*fn)(const char *, const void *)) +{ + if (hash_map == NULL) + return; + + struct pair_list *iter; + for (size_t i = 0; i < hash_map->size; i++) + { + iter = hash_map->data[i]; + while (iter != NULL) + { + fn(iter->key, iter->value); + iter = iter->next; + } + } +} + +const void *hash_map_get(const struct hash_map *hash_map, const char *key) +{ + if (hash_map == NULL || hash_map->size == 0) + return NULL; + + size_t h = hash(key); + size_t i = h % hash_map->size; + struct pair_list *l = hash_map->data[i]; + while (l != NULL) + { + if (strcmp(l->key, key) == 0) + return l->value; + l = l->next; + } + return NULL; +} + +bool hash_map_remove(struct hash_map *hash_map, const char *key) +{ + if (hash_map == NULL || hash_map->size == 0) + return false; + + size_t h = hash(key); + size_t i = h % hash_map->size; + struct pair_list *l = hash_map->data[i]; + struct pair_list *p = NULL; + + while (l != NULL) + { + if (strcmp(l->key, key) == 0) + { + if (p != NULL) + p->next = l->next; + else + hash_map->data[i] = l->next; + free(l); + return true; + } + p = l; + l = l->next; + } + return false; +} diff --git a/src/utils/hash_map/hash_map.h b/src/utils/hash_map/hash_map.h new file mode 100644 index 0000000..efdabc2 --- /dev/null +++ b/src/utils/hash_map/hash_map.h @@ -0,0 +1,34 @@ +#ifndef HASH_MAP_H +#define HASH_MAP_H + +#include +#include + +struct pair_list +{ + const char *key; + void *value; + struct pair_list *next; +}; + +struct hash_map +{ + struct pair_list **data; + size_t size; +}; + +struct hash_map *hash_map_init(size_t size); + +bool hash_map_insert(struct hash_map *hash_map, const char *key, void *value, + bool *updated); + +void hash_map_free(struct hash_map *hash_map); + +void hash_map_foreach(struct hash_map *hash_map, + void (*fn)(const char *, const void *)); + +const void *hash_map_get(const struct hash_map *hash_map, const char *key); + +bool hash_map_remove(struct hash_map *hash_map, const char *key); + +#endif /* ! HASH_MAP_H */