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)
|
|
|
|
|
{
|
2026-01-19 15:28:35 +00:00
|
|
|
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
|
2026-01-19 15:28:35 +00:00
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
2026-01-19 15:28:35 +00:00
|
|
|
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;
|
|
|
|
|
|
2026-01-19 15:28:35 +00:00
|
|
|
if (hash_map != NULL && *hash_map != NULL)
|
2026-01-17 22:45:27 +00:00
|
|
|
{
|
2026-01-19 15:28:35 +00:00
|
|
|
for (size_t i = 0; i < (*hash_map)->size; i++)
|
2026-01-17 22:45:27 +00:00
|
|
|
{
|
2026-01-19 15:28:35 +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
|
|
|
}
|
|
|
|
|
}
|
2026-01-19 15:28:35 +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;
|
|
|
|
|
}
|