diff --git a/hashmap/Makefile b/hashmap/Makefile new file mode 100644 index 0000000..e03ee9a --- /dev/null +++ b/hashmap/Makefile @@ -0,0 +1,14 @@ +CC = gcc +CFLAGS = -Wall -O2 + +TARGET = main.elf +SRC = main.c hashmap.c + +#LDFLAGS = + +$(TARGET): $(SRC) + @echo CC $@ + @$(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS) + +clean: + rm -f $(TARGET) diff --git a/hashmap/hashmap.c b/hashmap/hashmap.c new file mode 100644 index 0000000..a089cfc --- /dev/null +++ b/hashmap/hashmap.c @@ -0,0 +1,97 @@ +#include "hashmap.h" +#include +#include + +typedef struct hashmap_entry { + char *key; + void *value; + struct hashmap_entry *next; +} hashmap_entry_t; + +struct hashmap { + hashmap_entry_t **buckets; + size_t bucket_count; +}; + +static unsigned long hash(const char *str) { + unsigned long hash = 5381; + int c; + while ((c = *str++)) hash = ((hash << 5) + hash) + c; + return hash; +} + +hashmap_t *hashmap_create(size_t bucket_count) { + hashmap_t *map = malloc(sizeof(hashmap_t)); + map->buckets = calloc(bucket_count, sizeof(hashmap_entry_t *)); + map->bucket_count = bucket_count; + return map; +} + +void hashmap_destroy(hashmap_t *map) { + for (size_t i = 0; i < map->bucket_count; ++i) { + hashmap_entry_t *entry = map->buckets[i]; + while (entry) { + hashmap_entry_t *next = entry->next; + free(entry->key); + free(entry); + entry = next; + } + } + + free(map->buckets); + free(map); +} + +void hashmap_put(hashmap_t *map, const char *key, void *value) { + size_t index = (hash(key) % map->bucket_count); + hashmap_entry_t *entry = map->buckets[index]; + + while (entry) { + if (strcmp(entry->key, key) == 0) { + entry->value = value; + return; + } + + entry = entry->next; + } + + hashmap_entry_t *new_entry = malloc(sizeof(hashmap_entry_t)); + new_entry->key = strdup(key); + new_entry->value = value; + new_entry->next = map->buckets[index]; + map->buckets[index] = new_entry; +} + +void *hashmap_get(hashmap_t *map, const char *key) { + size_t index = (hash(key) % map->bucket_count); + hashmap_entry_t *entry = map->buckets[index]; + + while (entry) { + if (strcmp(entry->key, key) == 0) { + return entry->value; + } + + entry = entry->next; + } + + return NULL; +} + +void hashmap_remove(hashmap_t *map, const char *key) { + size_t index = (hash(key) % map->bucket_count); + + hashmap_entry_t **prev = &map->buckets[index]; + hashmap_entry_t *entry = *prev; + + while (entry) { + if (strcmp(entry->key, key) == 0) { + *prev = entry->next; + free(entry->key); + free(entry); + return; + } + + prev = &entry->next; + entry = entry->next; + } +} diff --git a/hashmap/hashmap.h b/hashmap/hashmap.h new file mode 100644 index 0000000..59126f8 --- /dev/null +++ b/hashmap/hashmap.h @@ -0,0 +1,26 @@ +#pragma once + +#include + +/* + * TODO: Make thread safe + * TODO: Resizing + * TODO: Custom hashing and eq + */ + +typedef struct hashmap hashmap_t; + +/** Initialize the hashmap */ +hashmap_t *hashmap_create(size_t bucket_count); + +/** Deallocate the map */ +void hashmap_destroy(hashmap_t *map); + +/** Put a new entry into the map */ +void hashmap_put(hashmap_t *map, const char *key, void *value); + +/** Get an entry from the map */ +void *hashmap_get(hashmap_t *map, const char *key); + +/** Remove entry from the map */ +void hashmap_remove(hashmap_t *map, const char *key); diff --git a/hashmap/main.c b/hashmap/main.c new file mode 100644 index 0000000..9c8bfa0 --- /dev/null +++ b/hashmap/main.c @@ -0,0 +1,23 @@ +#include "hashmap.h" +#include + +int main() { + hashmap_t *map = hashmap_create(128); + + int value1 = 42; + hashmap_put(map, "answer", &value1); + + int *found = hashmap_get(map, "answer"); + if (found) { + printf("Found: %d\n", *found); + } + + hashmap_remove(map, "answer"); + found = hashmap_get(map, "answer"); + if (!found) { + printf("Entry removed.\n"); + } + + hashmap_destroy(map); + return 0; +}