#include "hmap.h" #include "slice.h" #include #include #include #include #if SIZE_MAX == 0xFFFFFFFF /* If size_t is 32bit */ static const size_t fnv_prime = 16777619u; static const size_t fnv_offsetb = 2166136261u; #elif SIZE_MAX == 0xFFFFFFFFFFFFFFFF /* If size_t is 64bit */ static const size_t fnv_prime = 1099511628211u; static const size_t fnv_offsetb = 14695981039346656037u; #else /* If size_t is 128bit. Maybe this is overdoing it? */ static const size_t fnv_prime = 309485009821345068724781371u; static const size_t fnv_offsetb = 144066263297769815596495629667062367629u; #endif struct hnode { struct slice key; void *value; struct hnode *next; }; /* FNV1a */ static size_t hash(const char *str) { size_t hash = fnv_offsetb; size_t i = 0; while (str[i] != '\0') { hash ^= str[i]; hash *= fnv_prime; i++; } return hash; } static size_t hash_slice(const struct slice *slice) { size_t hash = fnv_offsetb; size_t i = slice->start; while (i < slice->end) { hash ^= slice->str[i]; hash *= fnv_prime; i++; } return hash; } struct hmap * hmap_new_with_cap(size_t cap) { struct hmap *hm = malloc(sizeof *hm); hm->cap = cap; hm->size = 0; if (hm == NULL) return NULL; hm->buckets = calloc(cap, sizeof hm->buckets); if (hm->buckets == NULL) { free(hm); return NULL; } return hm; } void * hmap_sets(struct hmap *hm, struct slice key, void *value) { int pos = hash_slice(&key) % hm->cap; struct hnode *head = hm->buckets[pos]; struct hnode *node = head; void *old_value = NULL; while (node) { if (slice_cmp(&node->key, &key) == 0) { old_value = node->value; node->value = value; return old_value; } node = node->next; } node = malloc(sizeof *node); node->key = key; node->value = value; node->next = head; hm->buckets[pos] = node; hm->size++; return old_value; } void * hmap_set(struct hmap *hm, const char *k, void *value) { struct slice key = slice_fullstr(k); return hmap_sets(hm, key, value); } void * hmap_gets(struct hmap *hm, const struct slice *key) { size_t pos = hash_slice(key) % hm->cap; struct hnode *node = hm->buckets[pos]; while (node != NULL) { if (slice_cmp(&node->key, key) == 0) { return node->value; } node = node->next; } return NULL; } void * hmap_get(struct hmap *hm, const char *k) { struct slice key = slice_fullstr(k); return hmap_gets(hm, &key); } void * hmap_resolve(struct hmap *hm, const char *key) { char tmp_key[64]; int i = 0; int j = 0; while (1) { for (j=0; key[i] != '.' && key[i] != '\0'; i++, j++) { tmp_key[j] = key[i]; } tmp_key[j] = '\0'; hm = hmap_get(hm, tmp_key); // stop if we read key to end of string if (key[i] == '\0') { break; } // otherwise, continue reading keys i++; } return hm; } void * hmap_removes(struct hmap *hm, const struct slice *key) { int pos = hash_slice(key) % hm->cap; struct hnode *node = hm->buckets[pos]; struct hnode *prev = NULL; void *old_value; while (node) { if (slice_cmp(&node->key, key) == 0) { if (prev) { prev->next = node->next; } else { hm->buckets[pos] = node->next; } old_value = node->value; free(node); hm->size--; return old_value; } prev = node; node = node->next; } return NULL; } void * hmap_remove(struct hmap *hm, const char *k) { struct slice key = slice_fullstr(k); return hmap_removes(hm, &key); } #define HMAP_WALK(hm, ...) \ struct hnode *node; \ struct hnode *next; \ for (size_t i = 0; i < hm->cap; i++) { \ node = hm->buckets[i]; \ while (node) { \ next = node->next; \ __VA_ARGS__; \ node = next; \ } \ } void hmap_walk(struct hmap *hm, hmap_cb cb) { HMAP_WALK(hm, cb(&node->key, node->value)); } void hmap_destroy(struct hmap *hm, hmap_cb cb) { HMAP_WALK(hm, cb(&node->key, node->value), free(node)); free(hm->buckets); free(hm); } void hmap_free(struct hmap *hm) { HMAP_WALK(hm, free(node)); free(hm->buckets); free(hm); }