Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #ifndef HASH_TABLE_H
- #define HASH_TABLE_H
- #include <stdbool.h>
- #include <stdint.h>
- #include <stddef.h>
- struct allocator_t {
- void* (*malloc)(size_t);
- void* (*calloc)(size_t,size_t);
- void* (*realloc)(void*,size_t);
- void (*free)(void*);
- };
- struct hash_bucket_t {
- bool owns_key;
- void (*free_key)(void*); // This can be NULL if the key is a scalar type :D
- bool owns_value;
- void (*free_value)(void*);
- uintptr_t key;
- void* value;
- struct hash_bucket_t* next; // Links directly to next bucket there
- };
- struct hash_table_t {
- unsigned int HASH_MODULUS; // DON'T CHANGE THIS
- struct hash_bucket_t *buckets;
- struct allocator_t allocator; // SHOULD NEVER CHANGE
- unsigned int (*hash_function)(uintptr_t); // THIS IS UNCHANGEABLE
- bool (*equals_function)(uintptr_t,uintptr_t); // DO NOT CHANGE.
- };
- struct optional_t {
- bool is_present;
- void* value;
- };
- struct hash_table_mem_info_t {
- bool passes_ownership;
- struct allocator_t allocator;
- };
- #define HASH_LIB_HASH_VALIDATOR(one) {if (one == 0) return 0;}
- #define HASH_LIB_EQUALS_VALIDATOR(one, two) {if (one == two) return true; if (one == 0 || two == 0) return false;}
- struct hash_table_t create_hash_table(unsigned int modulus, struct allocator_t allocator, unsigned int (*hash_function)(uintptr_t), bool (*equals_function)(uintptr_t,uintptr_t));
- struct optional_t get_from_hash_table(struct hash_table_t table, uintptr_t key);
- void put_in_hash_table(struct hash_table_t table, uintptr_t key, void* value, struct hash_table_mem_info_t key_info, struct hash_table_mem_info_t value_info);
- struct optional_t remove_from_hash_table(struct hash_table_t table, uintptr_t key, bool free_if_possible);
- void free_hash_table(struct hash_table_t table); // PLEASE call after
- #endif
- #include <stdlib.h>
- struct hash_table_t create_hash_table(unsigned int modulus, struct allocator_t allocator, unsigned int (*hash_function)(uintptr_t), bool (*equals_function)(uintptr_t,uintptr_t)) {
- if (!allocator.calloc) {
- allocator.calloc = calloc;
- }
- if (!allocator.free) {
- allocator.free = free; // Setting default values
- }
- struct hash_bucket_t *buckets = (struct hash_bucket_t*) allocator.calloc(modulus, sizeof(struct hash_bucket_t));
- return (struct hash_table_t){modulus, buckets, allocator, hash_function, equals_function};
- }
- struct optional_t get_from_hash_table(struct hash_table_t table, uintptr_t key) {
- struct optional_t result = { false, NULL };
- unsigned int hash = table.hash_function(key);
- unsigned int hash0 = hash % table.HASH_MODULUS;
- struct hash_bucket_t bucket = table.buckets[hash0];
- goto into_loop1;
- do {
- bucket = *bucket.next;
- into_loop1:
- if (bucket.key == key || table.equals_function(key, bucket.key)) {
- result.is_present = true;
- result.value = bucket.value;
- break;
- }
- } while (bucket.next != NULL);
- return result;
- }
- void put_in_hash_table(struct hash_table_t table, uintptr_t key, void* value, struct hash_table_mem_info_t key_info, struct hash_table_mem_info_t value_info) {
- unsigned int hash = table.hash_function(key);
- unsigned int hash0 = hash % table.HASH_MODULUS;
- struct hash_bucket_t bucket = table.buckets[hash0];
- goto into_loop2;
- do {
- bucket = *bucket.next;
- into_loop2:
- if (bucket.key == key || table.equals_function(key, bucket.key)) {
- if (bucket.owns_key) {
- bucket.free_key((void*) bucket.key);
- }
- bucket.owns_key = key_info.passes_ownership;
- bucket.free_key = key_info.allocator.free;
- bucket.key = key;
- if (bucket.owns_value) {
- bucket.free_value(bucket.value);
- }
- bucket.owns_value = value_info.passes_ownership;
- bucket.free_value = value_info.allocator.free;
- bucket.value = value;
- return;
- }
- } while (bucket.next != NULL);
- // Program only lands here if it hasn't found anything.
- struct hash_bucket_t* new_bucket = table.allocator.malloc(sizeof(struct hash_bucket_t));
- new_bucket->owns_key = key_info.passes_ownership;
- new_bucket->free_key = key_info.allocator.free;
- new_bucket->owns_value = value_info.passes_ownership;
- new_bucket->free_value = value_info.allocator.free;
- new_bucket->key = key;
- new_bucket->value = value;
- new_bucket->next = NULL;
- bucket.next = new_bucket;
- return;
- } // TODO
- struct optional_t remove_from_hash_table(struct hash_table_t table, uintptr_t key, bool free_if_possible) {
- struct optional_t result = { false, NULL };
- unsigned int hash = table.hash_function(key);
- unsigned int hash0 = hash % table.HASH_MODULUS;
- struct hash_bucket_t* bucket = table.buckets + hash0;
- struct hash_bucket_t* old_bucket = NULL;
- goto into_loop3;
- do {
- old_bucket = bucket;
- bucket = bucket->next;
- // Here we need to store the bucket above
- into_loop3:
- if (bucket->key == key || table.equals_function(key, bucket->key)) {
- result.is_present = true;
- result.value = bucket->value;
- break;
- }
- } while (bucket->next != NULL);
- if (result.is_present = false) {
- goto removal_ending; // Yee
- }
- // Cut out bucket and then free contents if possible
- if (bucket->owns_key) {
- bucket->free_key((void *)bucket->key);
- }
- if (bucket->owns_value) {
- bucket->free_value(bucket->value);
- }
- if (old_bucket == NULL) {
- goto removal_ending;
- }
- old_bucket->next = bucket->next;
- table.allocator.free(bucket);
- removal_ending:
- return result;
- }
- static void recursively_free(struct hash_bucket_t bucket, struct allocator_t allocator) {
- }
- void free_hash_table(struct hash_table_t table) {
- for (int i = 0; i < table.HASH_MODULUS; i++) {
- recursively_free(table.buckets[i], table.allocator);
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment