Allow non-null terminated strings

This commit is contained in:
bʰedoh₂ swé 2024-08-17 00:08:58 +05:00
parent 34f7eaea19
commit 3ea9100d78
4 changed files with 76 additions and 31 deletions

View File

@ -4,6 +4,19 @@
#include "sdbm.h" #include "sdbm.h"
#include "hashtable.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) { bool hashtable_recreate(hashtable* table) {
size_t oldcapacity = table->capacity; size_t oldcapacity = table->capacity;
hashtable_item* olditems = table->items; hashtable_item* olditems = table->items;
@ -17,7 +30,7 @@ bool hashtable_recreate(hashtable* table) {
for (size_t i = 0; i < oldcapacity; i++) { for (size_t i = 0; i < oldcapacity; i++) {
if (olditems[i].name == NULL || olditems[i].name == (void*)1) if (olditems[i].name == NULL || olditems[i].name == (void*)1)
continue; 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) { if (!index.exists) {
hashtable_item* array = temptable.items; hashtable_item* array = temptable.items;
for (size_t i = 0; i < temptable.capacity; i++) for (size_t i = 0; i < temptable.capacity; i++)
@ -42,21 +55,29 @@ hashtable* hashtable_create(void) {
return table; return table;
} }
size_t_optional hashtable_key(hashtable* table, char* name) { size_t_optional hashtable_key(hashtable* table, char* name, size_t size) {
size_t index = sdbm(name) & (table->capacity - 1); 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; hashtable_item* array = table->items;
while (1) { while (1) {
if (array[index].name == NULL) if (array[index].name == NULL)
return (size_t_optional) { false, 0 }; return (size_t_optional) { false, 0 };
if (array[index].name != (void*)(1)) 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 }; return (size_t_optional) { true, index };
index = (index + 1) & (table->capacity - 1); index = (index + 1) & (table->capacity - 1);
} }
} }
size_t_optional hashtable_insert(hashtable* table, char* name) { size_t_optional hashtable_insert(hashtable* table, char* name, size_t size) {
size_t index = sdbm(name) & (table->capacity - 1); 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; hashtable_item* array = table->items;
if ((table->capacity >> 2) * 3 < table->filled) { if ((table->capacity >> 2) * 3 < table->filled) {
hashtable_recreate(table); hashtable_recreate(table);
@ -64,12 +85,16 @@ size_t_optional hashtable_insert(hashtable* table, char* name) {
while (1) { while (1) {
if (array[index].name == NULL || array[index].name == (void*)1) { if (array[index].name == NULL || array[index].name == (void*)1) {
array[index].name = malloc(strlen(name) + sizeof(name)); 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++; table->filled++;
return (size_t_optional) {true, index}; return (size_t_optional) {true, index};
} }
else else
if (!strcmp(array[index].name, name)) if (streq(array[index].name, array[index].size, name, size))
return (size_t_optional) {true, index}; return (size_t_optional) {true, index};
else else
index = (index + 1) & (table->capacity - 1); index = (index + 1) & (table->capacity - 1);
@ -83,21 +108,21 @@ void hashtable_destroy(hashtable* table) {
free(table); free(table);
} }
void* hashtable_get(hashtable* table, char* name) { void* hashtable_get(hashtable* table, char* name, size_t size) {
size_t_optional index = hashtable_key(table, name); size_t_optional index = hashtable_key(table, name, size);
if (!index.exists) if (!index.exists)
return NULL; return NULL;
return table->items[index.sizet].data; return table->items[index.sizet].data;
} }
void hashtable_set(hashtable* table, char* name, void* data) { void hashtable_set(hashtable* table, char* name, size_t size, void* data) {
size_t_optional index = hashtable_insert(table, name); size_t_optional index = hashtable_insert(table, name, size);
if (index.exists) if (index.exists)
table->items[index.sizet].data = data; table->items[index.sizet].data = data;
} }
bool hashtable_delete(hashtable* table, char* name) { bool hashtable_delete(hashtable* table, char* name, size_t size) {
size_t_optional index = hashtable_key(table, name); size_t_optional index = hashtable_key(table, name, size);
if (index.exists) { if (index.exists) {
table->items[index.sizet].name = (void*)1; table->items[index.sizet].name = (void*)1;
table->filled--; table->filled--;
@ -106,9 +131,9 @@ bool hashtable_delete(hashtable* table, char* name) {
return false; 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; size_t capacity = table->capacity;
hashtable_item* items = table->items; hashtable_item* items = table->items;
for (size_t i = 0; i < capacity; i++) 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);
} }

View File

@ -1,12 +1,16 @@
#include <stdlib.h> #include <stdlib.h>
#include <stdbool.h> #include <stdbool.h>
#ifndef HASHTABLE_H
#define HASHTABLE_H
typedef struct { typedef struct {
bool exists; bool exists;
size_t sizet; size_t sizet;
} size_t_optional; } size_t_optional;
typedef struct { typedef struct {
size_t size;
char* name; char* name;
void* data; void* data;
} hashtable_item; } hashtable_item;
@ -23,14 +27,16 @@ hashtable* hashtable_create(void);
void hashtable_destroy(hashtable*); 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

8
sdbm.c
View File

@ -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;
}

24
sdbm.h
View File

@ -1 +1,23 @@
unsigned long sdbm(char *str); #include <stdlib.h>
#ifndef SDBM_H
#define SDBM_H
#include <stdlib.h>
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