diff --git a/hashtable.c b/hashtable.c index 244b453..a48c7b2 100644 --- a/hashtable.c +++ b/hashtable.c @@ -4,6 +4,19 @@ #include "sdbm.h" #include "hashtable.h" +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; +} + bool hashtable_recreate(hashtable* table) { size_t oldcapacity = table->capacity; hashtable_item* olditems = table->items; @@ -17,7 +30,7 @@ bool hashtable_recreate(hashtable* table) { for (size_t i = 0; i < oldcapacity; i++) { if (olditems[i].name == NULL || olditems[i].name == (void*)1) continue; - size_t_optional index = hashtable_insert(&temptable, olditems[i].name); + size_t_optional index = hashtable_insert(&temptable, olditems[i].name, olditems[i].size); if (!index.exists) { hashtable_item* array = temptable.items; for (size_t i = 0; i < temptable.capacity; i++) @@ -42,21 +55,29 @@ hashtable* hashtable_create(void) { return table; } -size_t_optional hashtable_key(hashtable* table, char* name) { - size_t index = sdbm(name) & (table->capacity - 1); +size_t_optional hashtable_key(hashtable* table, char* name, size_t size) { + size_t index; + if (size) + index = sdbm_clean(name, size) & (table->capacity - 1); + else + index = sdbm(name) & (table->capacity - 1); hashtable_item* array = table->items; while (1) { if (array[index].name == NULL) return (size_t_optional) { false, 0 }; if (array[index].name != (void*)(1)) - if (!strcmp(name, array[index].name)) + if (streq(name, size, array[index].name, array[index].size)) return (size_t_optional) { true, index }; index = (index + 1) & (table->capacity - 1); } } -size_t_optional hashtable_insert(hashtable* table, char* name) { - size_t index = sdbm(name) & (table->capacity - 1); +size_t_optional hashtable_insert(hashtable* table, char* name, size_t size) { + size_t index; + if (size) + index = sdbm_clean(name, size) & (table->capacity - 1); + else + index = sdbm(name) & (table->capacity - 1); hashtable_item* array = table->items; if ((table->capacity >> 2) * 3 < table->filled) { hashtable_recreate(table); @@ -64,12 +85,16 @@ size_t_optional hashtable_insert(hashtable* table, char* name) { while (1) { if (array[index].name == NULL || array[index].name == (void*)1) { array[index].name = malloc(strlen(name) + sizeof(name)); - strcpy(array[index].name, name); + array[index].size = size; + if (size) + memcpy(array[index].name, name, size); + else + strcpy(array[index].name, name); table->filled++; return (size_t_optional) {true, index}; } else - if (!strcmp(array[index].name, name)) + if (streq(array[index].name, array[index].size, name, size)) return (size_t_optional) {true, index}; else index = (index + 1) & (table->capacity - 1); @@ -83,21 +108,21 @@ void hashtable_destroy(hashtable* table) { free(table); } -void* hashtable_get(hashtable* table, char* name) { - size_t_optional index = hashtable_key(table, name); +void* hashtable_get(hashtable* table, char* name, size_t size) { + size_t_optional index = hashtable_key(table, name, size); if (!index.exists) return NULL; return table->items[index.sizet].data; } -void hashtable_set(hashtable* table, char* name, void* data) { - size_t_optional index = hashtable_insert(table, name); +void hashtable_set(hashtable* table, char* name, size_t size, void* data) { + size_t_optional index = hashtable_insert(table, name, size); if (index.exists) table->items[index.sizet].data = data; } -bool hashtable_delete(hashtable* table, char* name) { - size_t_optional index = hashtable_key(table, name); +bool hashtable_delete(hashtable* table, char* name, size_t size) { + size_t_optional index = hashtable_key(table, name, size); if (index.exists) { table->items[index.sizet].name = (void*)1; table->filled--; @@ -106,9 +131,9 @@ bool hashtable_delete(hashtable* table, char* name) { return false; } -void hashtable_forall(hashtable* table, void (*callback)(char*, void*, void*), void* userdata) { +void hashtable_forall(hashtable* table, void (*callback)(char*, size_t, void*, void*), void* userdata) { size_t capacity = table->capacity; hashtable_item* items = table->items; for (size_t i = 0; i < capacity; i++) - callback(items[i].name, items[i].data, userdata); + callback(items[i].name, items[i].size, items[i].data, userdata); } diff --git a/hashtable.h b/hashtable.h index b866665..ac7405a 100644 --- a/hashtable.h +++ b/hashtable.h @@ -1,12 +1,16 @@ #include #include +#ifndef HASHTABLE_H +#define HASHTABLE_H + typedef struct { bool exists; size_t sizet; } size_t_optional; typedef struct { + size_t size; char* name; void* data; } hashtable_item; @@ -23,14 +27,16 @@ hashtable* hashtable_create(void); void hashtable_destroy(hashtable*); -size_t_optional hashtable_key(hashtable*, char*); +size_t_optional hashtable_key(hashtable*, char*, size_t); -size_t_optional hashtable_insert(hashtable*, char*); +size_t_optional hashtable_insert(hashtable*, char*, size_t); -void* hashtable_get(hashtable* table, char* name); +void* hashtable_get(hashtable* table, char* name, size_t); -void hashtable_set(hashtable* table, char* name, void* data); +void hashtable_set(hashtable* table, char* name, size_t, void* data); -bool hashtable_delete(hashtable*, char*); +bool hashtable_delete(hashtable*, char*, size_t); -void hashtable_forall(hashtable*, void (*)(char*, void*, void*), void*); +void hashtable_forall(hashtable*, void (*)(char*, size_t, void*, void*), void*); + +#endif diff --git a/sdbm.c b/sdbm.c deleted file mode 100644 index 3715a0f..0000000 --- a/sdbm.c +++ /dev/null @@ -1,8 +0,0 @@ -unsigned long sdbm(char *str) { - unsigned long hash = 0; - - for (int c = *str; c != 0; c = *str++) - hash = c + (hash << 6) + (hash << 16) - hash; - - return hash; -} diff --git a/sdbm.h b/sdbm.h index bfe3187..71f27de 100644 --- a/sdbm.h +++ b/sdbm.h @@ -1 +1,23 @@ -unsigned long sdbm(char *str); +#include +#ifndef SDBM_H +#define SDBM_H +#include + +static unsigned long sdbm(char *str) { + unsigned long hash = 0; + + for (int c = *str; c != 0; c = *str++) + hash = c + (hash << 6) + (hash << 16) - hash; + + return hash; +} + +static unsigned long sdbm_clean(char *str, size_t size) { + unsigned long hash = 0; + + for (size_t i = 0; i < size + 1; i++) + hash = *str + (hash << 6) + (hash << 16) - hash; + + return hash; +} +#endif