#include #include #include #include "hashtable.h" typedef struct _Node { void* key; void* data; struct _Node* next; } Node; struct _Hashtable { uint32_t size; HashFunc hash; EqualFunc compare; FreeFunc free; PrintFunc print; Node** nodes; }; typedef struct { Hashtable* table; void* dummy2; void* dummy3; int64_t pos; } RealIter; static uint32_t hash_table_index(Hashtable* ht, const void* key) { return (ht->hash(key) % ht->size); } static void hash_table_default_print(void* data) { printf("%p", data); } Hashtable* hash_table_create(HashFunc hf, EqualFunc ef) { return hash_table_create_full(hf, ef, TABLESIZE, NULL, NULL); } Hashtable* hash_table_create_notify(HashFunc hf, EqualFunc ef, FreeFunc ff) { return hash_table_create_full(hf, ef, TABLESIZE, ff, NULL); } Hashtable* hash_table_create_full(HashFunc hf, EqualFunc ef, uint32_t size, FreeFunc ff, PrintFunc pf) { Hashtable* ht = malloc(sizeof(*ht)); ht->size = size; ht->hash = hf; ht->compare = ef; if (ff) { ht->free = ff; } else { ht->free = free; } if (pf) { ht->print = pf; } else { ht->print = hash_table_default_print; } ht->nodes = calloc(sizeof(Node*), ht->size); return ht; } void hash_table_destroy(Hashtable* ht) { for (uint32_t i = 0; i < ht->size; i++) { while (ht->nodes[i]) { Node* node = ht->nodes[i]; ht->nodes[i] = ht->nodes[i]->next; ht->free(node->data); free(node); } } hash_table_print(ht); free(ht->nodes); free(ht); } void hash_table_set_print_func(Hashtable* ht, PrintFunc pf) { ht->print = pf; } void hash_table_print(Hashtable* ht) { printf("Start Table\n"); for (uint32_t i = 0; i < ht->size; i++) { if (ht->nodes[i] == NULL) { //printf("\t%i\t---\n", i); } else { printf("\t%i\t\n", i); Node* node = ht->nodes[i]; while (node != NULL) { printf("\"%p\" - (", node->key); ht->print(node->data); printf(")"); node = node->next; } printf("\n"); } } printf("End Table\n"); } bool hash_table_insert(Hashtable* ht, const void* key, void* obj) { if (key == NULL || obj == NULL || ht == NULL) return false; // implement chaning if (hash_table_lookup(ht, key) != NULL) return false; uint32_t index = hash_table_index(ht, key); Node* node = malloc(sizeof(*node)); node->data = obj; node->key = (void*)key; node->next = ht->nodes[index]; ht->nodes[index] = node; return true; } void* hash_table_lookup(Hashtable* ht, const void* key) { if (key == NULL || ht == NULL) return false; uint32_t index = hash_table_index(ht, key); Node* node = ht->nodes[index]; while (node != NULL && ht->compare(node->data, key) == false) { node = node->next; } if (node == NULL) return NULL; //printf("find: %p -> found: %p\n", key, node->data); return node->data; } void* hash_table_delete(Hashtable* ht, const void* key) { if (key == NULL || ht == NULL) return false; uint64_t index = hash_table_index(ht, key); Node* node = ht->nodes[index]; Node* prev = NULL; while (node != NULL && ht->compare(node->data, key) == false) { prev = node; node = node->next; } if (node == NULL) return NULL; if (prev == NULL) { ht->nodes[index] = node->next; } else{ prev->next = node->next; } void* result = node->data; free(node); return result; } List* hash_table_keys(Hashtable* ht) { List *keys, *head; keys = head = NULL; if (ht != NULL) { for (uint32_t i = 0; i < ht->size; i++) { if (ht->nodes[i] != NULL) { Node* node = ht->nodes[i]; while (node != NULL) { if (head == NULL) { head = calloc(sizeof(List*), 1); keys = head; } else { head->next = calloc(sizeof(List*), 1); head = head->next; } head->data = ht->nodes[i]->key; node = node->next; } } } } return keys; } List* hash_table_values(Hashtable* ht) { List *values, *head; values = head = NULL; if (ht != NULL) { for (uint32_t i = 0; i < ht->size; i++) { if (ht->nodes[i] != NULL) { Node* node = ht->nodes[i]; while (node != NULL) { if (head == NULL) { head = calloc(sizeof(List*), 1); values = head; } else { head->next = calloc(sizeof(List*), 1); head = head->next; } head->data = ht->nodes[i]->data; node = node->next; } } } } return values; } void hash_table_list_free(List* list) { while (list != NULL) { List* prev = list; list = list->next; free(prev); } } void hash_table_foreach(Hashtable* ht, ForeachFunc ff, void* userdata) { if (ht != NULL) { for (uint32_t i = 0; i < ht->size; i++) { if (ht->nodes[i] != NULL) { Node* node = ht->nodes[i]; while (node != NULL) { ff(node->key, node->data, userdata); node = node->next; } } } } } void hash_table_iter_init (HashtableIter* iter, Hashtable* ht) { RealIter* ri = (RealIter*) iter; if (ri != NULL && ht != NULL) { ri->table = ht; ri->pos = -1; } } bool hash_table_iter_next(HashtableIter* iter, void** key, void** value) { RealIter* ri = (RealIter*) iter; Node* node; int64_t pos; if (ri != NULL) { pos = ri->pos; do { pos++; if (pos >= ri->table->size) { ri->pos = pos; return false; } node = ri->table->nodes[pos]; } while (node == NULL); if (key != NULL) *key = node->key; if (value != NULL) *value = node->data; ri->pos = pos; return true; } return false; } bool hash_table_contains(Hashtable* ht, const void* key) { if (ht == NULL || key == NULL) return false; if (hash_table_lookup(ht, key) == NULL) return false; return true; } uint64_t hash_table_size(Hashtable *ht) { uint64_t size = 0; if (ht == NULL) return size; for (uint32_t i = 0; i < ht->size; i++) { if (ht->nodes[i] != NULL) { Node* node = ht->nodes[i]; while (node != NULL) { size++; node = node->next; } } } return size; } bool hash_table_replace(Hashtable *ht, void* key, void* value) { if (ht == NULL || key == NULL || value == NULL) return false; uint32_t index = hash_table_index(ht, key); Node* node = ht->nodes[index]; while (node != NULL && ht->compare(node->data, key) == false) { node = node->next; } if (node == NULL) return hash_table_insert(ht, key, value); else { free(node->data); node->key = key; node->data = value; } return true; } uint64_t int_hash(const void* key) { return *(uint64_t*) key; } uint64_t str_hash(const void* key) { const signed char* p; uint64_t h = 5381; for (p = key; *p != '\0'; p++) { h = (h << 5) + h + *p; } return h; } uint64_t ptr_hash(const void* key) { return (uint64_t)key; } bool int_equal(const void* a, const void* b) { return *((const int*) a) == *((const int*) b); } bool str_equal(const void* a, const void* b) { const char *string1 = (const char*) a; const char *string2 = (const char*) b; return strcmp (string1, string2) == 0; } bool ptr_equal(const void* a, const void* b) { return a == b; }