Allow non-null terminated strings
This commit is contained in:
parent
34f7eaea19
commit
3ea9100d78
57
hashtable.c
57
hashtable.c
@ -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);
|
||||||
}
|
}
|
||||||
|
18
hashtable.h
18
hashtable.h
@ -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
8
sdbm.c
@ -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
24
sdbm.h
@ -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
|
||||||
|
Loading…
Reference in New Issue
Block a user