hash/hashtable.c

140 lines
3.9 KiB
C
Raw Permalink Normal View History

2024-06-28 22:37:51 +00:00
#include <string.h>
#include <stdio.h>
#include "sdbm.h"
#include "hashtable.h"
2024-08-16 19:08:58 +00:00
bool streq(char* str1, size_t len1, char* str2, size_t len2) {
if (len1 == 0 && len2 == 0) {
return !strcmp(str1, str2);
} else if (len1 == len2) {
return !memcmp(str1, str2, len1);
} else if (len1 == 0) {
return !memcmp(str1, str2, len2);
} else if (len2 == 0) {
return !memcmp(str1, str2, len1);
}
return true;
}
2024-08-16 19:27:19 +00:00
bool hashtable_recreate(HashTable* table) {
2024-06-28 22:37:51 +00:00
size_t oldcapacity = table->capacity;
2024-08-16 19:27:19 +00:00
HashTable_item* olditems = table->items;
HashTable_item* newitems = calloc(16, sizeof(HashTable_item));
2024-06-28 22:37:51 +00:00
if (newitems == NULL)
return false;
2024-08-16 19:27:19 +00:00
HashTable temptable;
2024-07-28 20:22:58 +00:00
temptable.capacity = 16;
2024-06-28 22:37:51 +00:00
temptable.filled = 0;
temptable.items = newitems;
for (size_t i = 0; i < oldcapacity; i++) {
2024-07-28 19:57:08 +00:00
if (olditems[i].name == NULL || olditems[i].name == (void*)1)
2024-06-28 22:37:51 +00:00
continue;
2024-08-16 19:08:58 +00:00
size_t_optional index = hashtable_insert(&temptable, olditems[i].name, olditems[i].size);
2024-07-28 19:57:08 +00:00
if (!index.exists) {
2024-08-16 19:27:19 +00:00
HashTable_item* array = temptable.items;
2024-07-28 19:57:08 +00:00
for (size_t i = 0; i < temptable.capacity; i++)
free(array[i].name);
2024-07-28 20:22:58 +00:00
free(newitems);
2024-07-28 19:57:08 +00:00
return false;
}
newitems[index.sizet].data = olditems[i].data;
2024-06-28 22:37:51 +00:00
}
2024-07-28 20:22:58 +00:00
table->capacity = temptable.capacity;
2024-06-28 22:37:51 +00:00
table->filled = temptable.filled;
table->items = newitems;
return true;
}
2024-08-16 19:27:19 +00:00
HashTable* hashtable_create(void) {
HashTable* table = malloc(sizeof(HashTable));
2024-07-28 19:57:08 +00:00
if (table == NULL)
return NULL;
2024-06-28 22:37:51 +00:00
table->capacity = 16;
2024-08-16 19:27:19 +00:00
table->items = calloc(16, sizeof(HashTable_item));
2024-06-28 22:37:51 +00:00
return table;
}
2024-08-16 19:27:19 +00:00
size_t_optional hashtable_key(HashTable* table, char* name, size_t size) {
2024-08-16 19:08:58 +00:00
size_t index;
if (size)
index = sdbm_clean(name, size) & (table->capacity - 1);
else
index = sdbm(name) & (table->capacity - 1);
2024-08-16 19:27:19 +00:00
HashTable_item* array = table->items;
2024-06-28 22:37:51 +00:00
while (1) {
if (array[index].name == NULL)
return (size_t_optional) { false, 0 };
2024-07-28 19:57:08 +00:00
if (array[index].name != (void*)(1))
2024-08-16 19:08:58 +00:00
if (streq(name, size, array[index].name, array[index].size))
2024-07-28 19:57:08 +00:00
return (size_t_optional) { true, index };
index = (index + 1) & (table->capacity - 1);
2024-06-28 22:37:51 +00:00
}
}
2024-08-16 19:27:19 +00:00
size_t_optional hashtable_insert(HashTable* table, char* name, size_t size) {
2024-08-16 19:08:58 +00:00
size_t index;
if (size)
index = sdbm_clean(name, size) & (table->capacity - 1);
else
index = sdbm(name) & (table->capacity - 1);
2024-08-16 19:27:19 +00:00
HashTable_item* array = table->items;
2024-06-28 22:37:51 +00:00
if ((table->capacity >> 2) * 3 < table->filled) {
2024-07-28 20:22:58 +00:00
hashtable_recreate(table);
2024-06-28 22:37:51 +00:00
}
while (1) {
2024-07-28 19:57:08 +00:00
if (array[index].name == NULL || array[index].name == (void*)1) {
2024-06-28 22:37:51 +00:00
array[index].name = malloc(strlen(name) + sizeof(name));
2024-08-16 19:08:58 +00:00
array[index].size = size;
if (size)
memcpy(array[index].name, name, size);
else
strcpy(array[index].name, name);
2024-06-28 22:37:51 +00:00
table->filled++;
2024-07-28 19:57:08 +00:00
return (size_t_optional) {true, index};
2024-06-28 22:37:51 +00:00
}
else
2024-08-16 19:08:58 +00:00
if (streq(array[index].name, array[index].size, name, size))
2024-07-28 19:57:08 +00:00
return (size_t_optional) {true, index};
2024-06-28 22:37:51 +00:00
else
index = (index + 1) & (table->capacity - 1);
}
}
2024-08-16 19:27:19 +00:00
void hashtable_destroy(HashTable* table) {
HashTable_item* array = table->items;
2024-06-28 22:37:51 +00:00
for (size_t i = 0; i < table->capacity; i++)
free(array[i].name);
free(table);
}
2024-08-16 19:27:19 +00:00
void* hashtable_get(HashTable* table, char* name, size_t size) {
2024-08-16 19:08:58 +00:00
size_t_optional index = hashtable_key(table, name, size);
2024-06-28 22:37:51 +00:00
if (!index.exists)
return NULL;
return table->items[index.sizet].data;
}
2024-08-16 19:27:19 +00:00
void hashtable_set(HashTable* table, char* name, size_t size, void* data) {
2024-08-16 19:08:58 +00:00
size_t_optional index = hashtable_insert(table, name, size);
2024-07-28 19:57:08 +00:00
if (index.exists)
table->items[index.sizet].data = data;
}
2024-08-16 19:27:19 +00:00
bool hashtable_delete(HashTable* table, char* name, size_t size) {
2024-08-16 19:08:58 +00:00
size_t_optional index = hashtable_key(table, name, size);
2024-07-28 19:57:08 +00:00
if (index.exists) {
table->items[index.sizet].name = (void*)1;
table->filled--;
2024-07-28 20:22:58 +00:00
return true;
} else
return false;
2024-07-28 19:57:08 +00:00
}
2024-08-16 19:27:19 +00:00
void hashtable_forall(HashTable* table, void (*callback)(char*, size_t, void*, void*), void* userdata) {
2024-07-28 19:57:08 +00:00
size_t capacity = table->capacity;
2024-08-16 19:27:19 +00:00
HashTable_item* items = table->items;
2024-07-28 19:57:08 +00:00
for (size_t i = 0; i < capacity; i++)
2024-08-16 19:08:58 +00:00
callback(items[i].name, items[i].size, items[i].data, userdata);
2024-06-28 22:37:51 +00:00
}