193 lines
4.0 KiB
C
193 lines
4.0 KiB
C
#include <stdbool.h>
|
|
#include <stddef.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <stdint.h>
|
|
|
|
struct pair_list
|
|
{
|
|
const char *key;
|
|
char *value;
|
|
struct pair_list *next;
|
|
};
|
|
|
|
struct hash_map
|
|
{
|
|
struct pair_list **data;
|
|
size_t size;
|
|
};
|
|
|
|
size_t hash(const char *key)
|
|
{
|
|
if (!key)
|
|
return 0;
|
|
|
|
uint32_t hash = 2166136261;
|
|
uint32_t prime = 16777619;
|
|
|
|
while (*key)
|
|
{
|
|
hash ^= *key;
|
|
hash *= prime;
|
|
key++;
|
|
}
|
|
|
|
return hash;
|
|
}
|
|
|
|
struct hash_map *hash_map_init(size_t size)
|
|
{
|
|
struct hash_map *res = malloc(sizeof(struct hash_map));
|
|
if (!res)
|
|
return NULL;
|
|
res->data = calloc(size, sizeof(struct pair_list *));
|
|
if (!res->data)
|
|
{
|
|
free(res);
|
|
return NULL;
|
|
}
|
|
res->size = size;
|
|
return res;
|
|
}
|
|
|
|
bool hash_map_insert(struct hash_map *hash_map, const char *key, char *value,
|
|
bool *updated)
|
|
{
|
|
if (!hash_map || hash_map->size == 0 || !key)
|
|
return false;
|
|
|
|
size_t hashed_val = hash(key) % hash_map->size;
|
|
struct pair_list *elt = hash_map->data[hashed_val];
|
|
while (elt)
|
|
{
|
|
if (strcmp(key, elt->key) == 0)
|
|
break;
|
|
elt = elt->next;
|
|
}
|
|
if (!elt)
|
|
{
|
|
struct pair_list *new = calloc(1, sizeof(struct pair_list));
|
|
if (!new)
|
|
return false;
|
|
new->key = key;
|
|
new->value = value;
|
|
struct pair_list *res = hash_map->data[hashed_val];
|
|
new->next = res;
|
|
hash_map->data[hashed_val] = new;
|
|
if (updated)
|
|
*updated = false;
|
|
return true;
|
|
}
|
|
elt->value = value;
|
|
if (updated)
|
|
*updated = true;
|
|
return true;
|
|
}
|
|
|
|
void hash_map_free(struct hash_map *hash_map)
|
|
{
|
|
if (!hash_map)
|
|
return;
|
|
for (size_t i = 0; i < hash_map->size; i++)
|
|
{
|
|
struct pair_list *elt = hash_map->data[i];
|
|
while (elt)
|
|
{
|
|
struct pair_list *n = elt->next;
|
|
free(elt);
|
|
elt = n;
|
|
}
|
|
}
|
|
free(hash_map->data);
|
|
free(hash_map);
|
|
hash_map->data = NULL;
|
|
}
|
|
|
|
void hash_map_dump(struct hash_map *hash_map)
|
|
{
|
|
if (!hash_map)
|
|
return;
|
|
for (size_t i = 0; i < hash_map->size; i++)
|
|
{
|
|
struct pair_list *elt = hash_map->data[i];
|
|
while (elt)
|
|
{
|
|
printf("%s: %s", elt->key, elt->value);
|
|
elt = elt->next;
|
|
if (elt)
|
|
printf(", ");
|
|
else
|
|
putchar('\n');
|
|
}
|
|
}
|
|
}
|
|
|
|
const char *hash_map_get(const struct hash_map *hash_map, const char *key)
|
|
{
|
|
if (!hash_map || hash_map->size == 0)
|
|
return NULL;
|
|
size_t hashed_val = hash(key) % hash_map->size;
|
|
struct pair_list *elt = hash_map->data[hashed_val];
|
|
while (elt)
|
|
{
|
|
if (strcmp(key, elt->key) == 0)
|
|
break;
|
|
elt = elt->next;
|
|
}
|
|
if (elt)
|
|
return elt->value;
|
|
return NULL;
|
|
}
|
|
|
|
bool hash_map_remove(struct hash_map *hash_map, const char *key)
|
|
{
|
|
if (!hash_map || hash_map->size == 0)
|
|
return false;
|
|
size_t hashed_val = hash(key) % hash_map->size;
|
|
struct pair_list *elt = hash_map->data[hashed_val];
|
|
struct pair_list *prev = NULL;
|
|
while (elt)
|
|
{
|
|
if (strcmp(key, elt->key) == 0)
|
|
break;
|
|
prev = elt;
|
|
elt = elt->next;
|
|
}
|
|
if (!elt)
|
|
return false;
|
|
if (prev)
|
|
prev->next = elt->next;
|
|
else
|
|
hash_map->data[hashed_val] = elt->next;
|
|
free(elt);
|
|
printf("removed %s", elt->value);
|
|
return true;
|
|
}
|
|
|
|
int main(void)
|
|
{
|
|
struct hash_map *map = hash_map_init(10);
|
|
if (!map)
|
|
return 1;
|
|
|
|
bool updated;
|
|
hash_map_insert(map, "key1", "value1", &updated);
|
|
hash_map_insert(map, "key2", "value2", &updated);
|
|
hash_map_insert(map, "key1", "new_value1", &updated);
|
|
|
|
hash_map_dump(map);
|
|
|
|
const char *val = hash_map_get(map, "key1");
|
|
if (val)
|
|
printf("Retrieved key1: %s\n", val);
|
|
|
|
hash_map_remove(map, "key2");
|
|
hash_map_dump(map);
|
|
|
|
hash_map_free(map);
|
|
|
|
printf("Everything is ok!\n");
|
|
return 0;
|
|
}
|