/* _,.---._ .-._ .--.-. ,--.--------. * _,..---._ ,-.' , - `. /==/ \ .-._/==/ //==/, - , -\ * /==/, - \ /==/_, , - \|==|, \/ /, |==\ -\\==\.-. - ,-./ * |==| _ _\==| .=. |==|- \| | \==\- \`--`\==\- \ * |==| .=. |==|_ : ;=: - |==| , | -| `--`-' \==\_ \ * |==|,| | -|==| , '=' |==| - _ | |==|- | * |==| '=' /\==\ - ,_ /|==| /\ , | |==|, | * |==|-, _`/ '.='. - .' /==/, | |- | /==/ -/ * `-.`.____.' `--`--'' `--`./ `--` `--`--` * _ __ ,---. .-._ .=-.-. _,.----. * .-`.' ,`..--.' \ /==/ \ .-._ /==/_ /.' .' - \ * /==/, - \==\-/\ \ |==|, \/ /, /==|, |/==/ , ,-' * |==| _ .=. /==/-|_\ | |==|- \| ||==| ||==|- | . * |==| , '=',\==\, - \ |==| , | -||==|- ||==|_ `-' \ * |==|- '..'/==/ - ,| |==| - _ ||==| ,||==| _ , | * |==|, | /==/- /\ - \|==| /\ , ||==|- |\==\. / * /==/ - | \==\ _.\=\.-'/==/, | |- |/==/. / `-.`.___.-' * `--`---' `--` `--`./ `--``--`-` * * @(#)Copyright (c) 2023, Nathan D. Fisher. * * This is free software. It comes with NO WARRANTY. * Permission to use, modify and distribute this source code * is granted subject to the following conditions. * 1/ that the above copyright notice and this notice * are preserved in all copies and that due credit be given * to the author. * 2/ that any changes to this code are clearly commented * as such so that the author does not get blamed for bugs * other than his own. */ #include #include #include #include #include #include #include "haggis.h" #include "haggis_private.h" #define FNV64_OFFSET_BASIS 14695981039346656037u #define FNV64_PRIME 1099511628211u uint64_t hash_fnv1a_64(uint8_t *key, size_t len) { int i; uint64_t hash = FNV64_OFFSET_BASIS; for (i = 0; i < len; i++) { hash = hash ^ *key; hash = hash * FNV64_PRIME; key++; } return hash; } uint64_t hash_str_fnv1a_64(char * s) { uint64_t hash = FNV64_OFFSET_BASIS; while (*s != '\0') { hash = hash ^ *s; hash = hash * FNV64_PRIME; s++; } return hash; } struct _map_node { struct _map_node *next; void * key; uint64_t hash; void *data; }; typedef struct _map_node hmap_node; typedef struct { size_t capacity; size_t len; size_t keysize; hmap_node *buckets; } hmap; void* hmap_insert(hmap * map, void *key, void *data); hmap_node* hmap_node_init(void *key, size_t keysize, void *data) { hmap_node *node; uint64_t hash; hash = hash_fnv1a_64(key, keysize); node = calloc(1, sizeof(hmap_node)); if (node == NULL) return NULL; node->key = key; node->hash = hash; node->data = data; return node; } void hmap_node_deinit(hmap_node *node) { hmap_node *current = node; while (current != NULL) { current = node->next; free(node); node = current; } } void* hmap_node_attach(hmap_node *root, hmap_node *leaf, size_t keysize) { void *ret = NULL; while (1) { if (memcmp(root->key, leaf->key, keysize) == 0) { ret = root->data; root->data = leaf->data; return ret; } else if (root->next == NULL) { root->next = leaf; break; } else { root = root->next; } } return NULL; // todo } void* hmap_node_search(hmap_node *root, void *key, size_t keysize) { void *ret = NULL; while (1) { if (memcmp(root->key, key, keysize) == 0) { ret = root->data; return ret; } else if (root->next == NULL) { return NULL; } else { root = root->next; } } } hmap* hmap_init(size_t keysize) { hmap* map; map = calloc(1, sizeof(hmap)); if (map == NULL) return NULL; map->len = 0; map->capacity = 64; map->keysize = keysize; map->buckets = calloc(64, sizeof(hmap_node)); if (map->buckets == NULL) { free(map); return NULL; } return map; } void hmap_deinit(hmap *map) { int i; for (i = 0; i < map->capacity; i++) { if (map->buckets[i].next != NULL) { hmap_node_deinit(map->buckets[i].next); } } free(map->buckets); free(map); } int hmap_expand(hmap *map) { hmap_node *old; hmap_node *new; hmap_node *current; int i; new = calloc(map->capacity + 64, sizeof(hmap_node)); if (new == NULL) return 1; old = map->buckets; map->buckets = new; for (i = 0; i < map->capacity; i++) { current = &old[i]; while (current->key != NULL) { hmap_insert(map, current->key, current->data); current = current->next; } } free(old); return 0; } void* hmap_insert(hmap *map, void *key, void *data) { hmap_node *node; size_t idx; hmap_node *ret = NULL; if (map->len >= map->capacity / 2) { if (hmap_expand(map)) return NULL; } node = hmap_node_init(key, map->keysize, data); if (node == NULL) return NULL; idx = node->hash % map->capacity; if (map->buckets[idx].key == NULL) { map->buckets[idx] = *node; } else { ret = hmap_node_attach(&map->buckets[idx], node, map->keysize); } map->len++; if (ret == NULL) return NULL; else return ret->data; } void* hmap_get(hmap *map, void *key) { uint64_t hash; size_t idx; void *ret; hash = hash_fnv1a_64(key, map->keysize); idx = hash % map->capacity; ret = hmap_node_search(&map->buckets[idx], key, map->keysize); return ret; } void* hmap_remove(hmap *map, void *key) { uint64_t hash; size_t idx; void *ret = NULL; hmap_node *previous = NULL; hmap_node *current; hash = hash_fnv1a_64(key, map->keysize); idx = hash % map->capacity; current = &map->buckets[idx]; if (current->key == NULL) return NULL; if (memcmp(current->key, key, map->keysize) == 0) { map->buckets[idx] = *current->next; } while (current->key != NULL) { if (memcmp(current->key, key, map->keysize) == 0) { ret = current->data; map->len--; if (previous != NULL) { previous->next = current; } else { map->buckets[idx] = *current->next; } break; } else { current = current->next; } } return ret; }