From 6449cb037472936658ae36cbc8f47f84971420e0 Mon Sep 17 00:00:00 2001 From: XOR Date: Mon, 3 Apr 2023 12:17:31 +0200 Subject: [PATCH] the hashtable now stores any type of data As it just stores a void pointer --- main.c | 135 ++++++++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 100 insertions(+), 35 deletions(-) diff --git a/main.c b/main.c index 5884483..3ef54d9 100644 --- a/main.c +++ b/main.c @@ -1,81 +1,144 @@ +#include #include #include +#include #include #include -#include #define WORD 32 #define TRANSFORM_TABLE_MAX_RAND 4294967296 #define DELTA 1 +// If set to 1, all strings will be hashed to SIMULATED_COLLISON_HASH +#define SIMULATE_COLLISIONS 0 +#define SIMULATED_COLLISION_HASH 20 + #ifdef __clang__ #include #define rot32_left(x, y) __builtin_rotateleft32(x, y) #else -#define rot32_left(x, y) (x << y) | (x >> 32 - y) +#define rot32_left(x, y) (x << y) | (x >> 32 - y) #endif -// Contains everything the functions for the hashtables need, to work with, including the hash table itself -typedef struct -{ - unsigned int *transformation_table; - int *hash_table; - unsigned int table_size; -}shash_hashtable_t; - typedef struct { char *key; - int value; + void *data; // gets set to 1 if another key, collides with this elemnts location u_int8_t encountered_collision; // On collision, this field stores, where in the hash table array the second key (with the same hash) is located int next_key_location; - -}shash_table_element_t; + +} shash_table_element_t; + +// Contains everything the functions for the hashtables need, to work with, including the hash table itself +typedef struct +{ + unsigned int *transformation_table; + shash_table_element_t *hash_table; + unsigned int table_size; +} shash_hashtable_t; + +// Returns -1 when the hashtable is full +int get_empty_hashtable_slot(shash_hashtable_t *hashtable) +{ + for (int i = 0; i < hashtable->table_size; i++) + { + if (hashtable->hash_table[i].key == 0) + return i; + } + // Full + return -1; +} void shash_init_hashtable(shash_hashtable_t *hashtable, unsigned int table_size) { // Create a random transformation table srand(0); - //srand(time(NULL)); - unsigned int *table = malloc((CHAR_MAX-CHAR_MIN)*sizeof(int)); + // srand(time(NULL)); + unsigned int *table = malloc((CHAR_MAX - CHAR_MIN) * sizeof(int)); - for(int i = 0; i < CHAR_MAX-CHAR_MIN; i++){ - table[i] = TRANSFORM_TABLE_MAX_RAND * rand() / RAND_MAX; + for (int i = 0; i < CHAR_MAX - CHAR_MIN; i++) + { + table[i] = TRANSFORM_TABLE_MAX_RAND * rand() / RAND_MAX; } hashtable->transformation_table = table; - hashtable->hash_table = malloc(table_size * sizeof(int)); + hashtable->hash_table = malloc(table_size * sizeof(shash_table_element_t)); + memset(hashtable->hash_table, 0, table_size * sizeof(shash_table_element_t)); + hashtable->table_size = table_size; } unsigned int shash_hash(char *key, unsigned int len, shash_hashtable_t *hashtable) { - //Slight variation of cyclic polynomial hasing, as described in the Paper: "Recursive Hashing functions for n-Grams" by J. D. Cohen - unsigned int hash_word = 0; - for(int i = 0; i < len; i++) + if (SIMULATE_COLLISIONS == 1) { - hash_word = rot32_left(hash_word, 1); - hash_word = hash_word ^ hashtable->transformation_table[key[i]]; + return SIMULATED_COLLISION_HASH; + } + // Slight variation of cyclic polynomial hasing, as described in the Paper: "Recursive Hashing functions for n-Grams" by J. D. Cohen + unsigned int hash_word = 0; + for (int i = 0; i < len; i++) + { + hash_word = rot32_left(hash_word, 1); + hash_word = hash_word ^ hashtable->transformation_table[key[i]]; } return hash_word % hashtable->table_size; } -void shash_set(char *key, unsigned int len, int value, shash_hashtable_t *hashtable) +int shash_set(char *key, unsigned int len, void *data, shash_hashtable_t *hashtable) { - unsigned int hash = shash_hash(key, len, hashtable); - hashtable->hash_table[hash] = value; + unsigned int slot = shash_hash(key, len, hashtable); + + //Loop to the end of the linked list + while(hashtable->hash_table[slot].encountered_collision != 0){ + slot = hashtable->hash_table[slot].next_key_location; + } + + shash_table_element_t table_element = { + .key = key, + .data = data}; + if (hashtable->hash_table[slot].key == 0) + { + hashtable->hash_table[slot] = table_element; + } + else + { + int empty_slot = get_empty_hashtable_slot(hashtable); + if (empty_slot != -1) + { + hashtable->hash_table[slot].encountered_collision = 1; + hashtable->hash_table[slot].next_key_location = empty_slot; + hashtable->hash_table[empty_slot] = table_element; + return 0; + } + } + //hashtable full + return -1; } -int shash_get(char *key, unsigned int len, shash_hashtable_t *hashtable) +void *shash_get(char *key, unsigned int len, shash_hashtable_t *hashtable) { - unsigned int hash = shash_hash(key, len, hashtable); - int value = hashtable->hash_table[hash]; - return value; + unsigned int slot = shash_hash(key, len, hashtable); + + while (strcmp(hashtable->hash_table[slot].key, key) != 0) + { + if (hashtable->hash_table[slot].encountered_collision == 1) + { + slot = hashtable->hash_table[slot].next_key_location; + } + else + { + /* Invalid key + this return value cannot be identified as an error from outside, TODO: fix */ + return NULL; + } + } + + return hashtable->hash_table[slot].data; } int main(void) @@ -83,11 +146,13 @@ int main(void) // Initialize an empty hashtable shash_hashtable_t hashtable; shash_init_hashtable(&hashtable, 100); - - shash_set("INC", 3, 41, &hashtable); - - int retrieved_val = shash_get("INC", 3, &hashtable); - printf("Stored value %d at INC\n", retrieved_val); + + // Store some data + shash_set("FOO", 3, "Hello, World", &hashtable); + + // And retrieve it + char *retrieved_val = shash_get("FOO", 3, &hashtable); + printf("Stored string %s\n", retrieved_val); return 0; }