156 lines
4.2 KiB
C
Executable file
156 lines
4.2 KiB
C
Executable file
/* ************************************************************************** */
|
|
/* */
|
|
/* ::: :::::::: */
|
|
/* ft_hashmap.c :+: :+: :+: */
|
|
/* +:+ +:+ +:+ */
|
|
/* By: thrieg <thrieg@student.42mulhouse.fr> +#+ +:+ +#+ */
|
|
/* +#+#+#+#+#+ +#+ */
|
|
/* Created: 2024/11/07 12:14:50 by thrieg #+# #+# */
|
|
/* Updated: 2025/02/16 19:08:34 by thrieg ### ########.fr */
|
|
/* */
|
|
/* ************************************************************************** */
|
|
|
|
#include "ft_hashmap_private.h"
|
|
|
|
//allocates an array of initial_size, and sets nb_elems/hashmap_size to 0
|
|
//cmp is a function that returns 0 if both keys are the same
|
|
//returns NULL if any allocation fails
|
|
t_hashmap *ft_create_hashmap(
|
|
size_t initial_size,
|
|
void (*free_key)(void *),
|
|
void (*free_value)(void *),
|
|
int (*cmp)(void *key, void *key_to_compare))
|
|
{
|
|
t_hashmap *map;
|
|
|
|
if (initial_size == 0)
|
|
return (NULL);
|
|
map = malloc(sizeof(t_hashmap));
|
|
if (!map)
|
|
return (NULL);
|
|
map->nb_elems = 0;
|
|
map->hashmap_size = initial_size;
|
|
map->cmp = cmp;
|
|
map->free_key = free_key;
|
|
map->free_value = free_value;
|
|
map->table = ft_calloc((initial_size), sizeof(t_list *));
|
|
if (!(map->table))
|
|
return (free(map), NULL);
|
|
return (map);
|
|
}
|
|
|
|
// Inserts a key-value pair into the hashmap,
|
|
//returns 0 for an error, 1 for remplaced value for a key and 2 for new key
|
|
int ft_hashmap_insert_element(
|
|
t_hashmap *map,
|
|
void *key,
|
|
void *value,
|
|
size_t hash)
|
|
{
|
|
size_t index;
|
|
t_list *current;
|
|
t_hash_element *element;
|
|
|
|
if (!map || !key)
|
|
return (0);
|
|
if ((map->nb_elems * 100) > map->hashmap_size * HASHMAP_FILL_PERCENT_MAX)
|
|
ft_resize_hashmap(map);
|
|
index = hash % map->hashmap_size;
|
|
current = map->table[index];
|
|
while (current)
|
|
{
|
|
if (map->cmp(((t_hash_element *)(current->content))->key, key) == 0)
|
|
{
|
|
map->free_value(((t_hash_element *)(current->content))->value);
|
|
return (((t_hash_element *)(current->content))->value = value, 1);
|
|
}
|
|
current = current->next;
|
|
}
|
|
element = ft_create_hash_element(key, value, hash);
|
|
if (!element)
|
|
return (0);
|
|
if (!ft_add_hashmap_element(index, map, element))
|
|
return (ft_free_hash_element(element, map), 0);
|
|
return (2);
|
|
}
|
|
|
|
//returns 1 if the element has been deleted
|
|
//returns 0 if the element has not been found
|
|
int ft_delete_hashmap_element(t_hashmap *map, void *key, size_t hash)
|
|
{
|
|
size_t index;
|
|
t_list *curr;
|
|
t_list *prev;
|
|
t_hash_element *elem;
|
|
|
|
if (!map || !key || map->hashmap_size == 0)
|
|
return (0);
|
|
if (((map->nb_elems * 100) / map->hashmap_size)
|
|
<= HASHMAP_FILL_PERCENT_BEFORE_SHRINK)
|
|
ft_shrink_hashmap(map);
|
|
index = hash % map->hashmap_size;
|
|
curr = map->table[index];
|
|
prev = NULL;
|
|
while (curr)
|
|
{
|
|
elem = (t_hash_element *)curr->content;
|
|
if (map->cmp(elem->key, key) == 0)
|
|
{
|
|
return (ft_delete_hashmap_list_node(curr, prev, index, map), 1);
|
|
}
|
|
prev = curr;
|
|
curr = curr->next;
|
|
}
|
|
return (0);
|
|
}
|
|
|
|
//returns a pointer to the value of key, or a NULL pointer if not found
|
|
void *ft_lookup_hashmap_element(t_hashmap *map, void *key, size_t hash)
|
|
{
|
|
size_t index;
|
|
t_list *curr;
|
|
t_hash_element *elem;
|
|
|
|
if (!map || !key || map->hashmap_size == 0)
|
|
return (NULL);
|
|
index = hash % map->hashmap_size;
|
|
curr = map->table[index];
|
|
while (curr)
|
|
{
|
|
elem = (t_hash_element *)curr->content;
|
|
if (map->cmp(elem->key, key) == 0)
|
|
return (elem->value);
|
|
curr = curr->next;
|
|
}
|
|
return (NULL);
|
|
}
|
|
|
|
//frees the entire hashmap and then returns NULL once done
|
|
void *ft_free_hashmap(t_hashmap *map)
|
|
{
|
|
size_t index;
|
|
t_list *curr;
|
|
t_list *next;
|
|
t_hash_element *elem;
|
|
|
|
if (!map)
|
|
return (NULL);
|
|
if (!map->table)
|
|
return (free(map), NULL);
|
|
index = 0;
|
|
while (index < map->hashmap_size)
|
|
{
|
|
curr = map->table[index];
|
|
while (curr)
|
|
{
|
|
next = curr->next;
|
|
elem = (t_hash_element *)curr->content;
|
|
ft_free_hash_element(elem, map);
|
|
free(curr);
|
|
curr = next;
|
|
}
|
|
index++;
|
|
}
|
|
free(map->table);
|
|
return (free(map), NULL);
|
|
}
|