feat(hash_map): hash_map

This commit is contained in:
william.valenduc 2026-01-17 22:45:27 +00:00
parent c299882586
commit 78068f53bd
2 changed files with 207 additions and 0 deletions

View file

@ -0,0 +1,173 @@
#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;
}
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;
}

View file

@ -0,0 +1,34 @@
#ifndef HASH_MAP_H
#define HASH_MAP_H
#include <stdbool.h>
#include <stddef.h>
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 */