42sh/src/utils/hash_map/hash_map.c

183 lines
3.8 KiB
C
Raw Normal View History

2026-01-17 22:45:27 +00:00
#include "hash_map.h"
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/*
** 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;
}
2026-01-17 23:57:59 +00:00
static void destroy_pair_list(struct pair_list **p)
{
free((char *)(*p)->key);
free((*p)->value);
free((*p));
*p = NULL;
}
2026-01-17 22:45:27 +00:00
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 || value == NULL)
2026-01-17 22:45:27 +00:00
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
free(iter->value);
2026-01-17 22:45:27 +00:00
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)
2026-01-17 22:45:27 +00:00
{
struct pair_list *l;
struct pair_list *prev;
if (hash_map != NULL && *hash_map != NULL)
2026-01-17 22:45:27 +00:00
{
for (size_t i = 0; i < (*hash_map)->size; i++)
2026-01-17 22:45:27 +00:00
{
l = (*hash_map)->data[i];
2026-01-17 22:45:27 +00:00
while (l != NULL)
{
prev = l;
l = l->next;
2026-01-17 23:57:59 +00:00
destroy_pair_list(&prev);
2026-01-17 22:45:27 +00:00
}
}
free((*hash_map)->data);
free(*hash_map);
2026-01-17 22:45:27 +00:00
}
}
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;
2026-01-17 23:57:59 +00:00
destroy_pair_list(&l);
2026-01-17 22:45:27 +00:00
return true;
}
p = l;
l = l->next;
}
return false;
}