#include "hashmap.h" #include #include #include #define MONS_HASHMAP_MAX_LOAD_FACTOR 3.0f unsigned int djb2_hash(unsigned char *str, unsigned int bucket_count) { unsigned long hash = 5381; int c; while ((c = *str++)) { hash = ((hash << 5) + hash) + c; } return hash % bucket_count; } mons_hashmap mons_hashmap_new(unsigned int member_size, unsigned int buckets) { mons_hashmap result = { .member_size = member_size, .bucket_count = buckets, .data = calloc(buckets, sizeof(mons_hashmap_pair *)), }; return result; } int mons_hashmap_rehash(mons_hashmap *map) { // TODO: Expand number of buckets, re-hash all entries return EXIT_SUCCESS; } int mons_hashmap_insert(mons_hashmap *map, char *key, void *value) { unsigned int bucket = djb2_hash((unsigned char*)key, map->bucket_count); mons_hashmap_pair *tail = map->data[bucket]; if (tail == NULL) { map->data[bucket] = calloc(1, sizeof(mons_hashmap_pair *)); tail = map->data[bucket]; } else { mons_hashmap_pair *node = tail; while(1) { if(strcmp(key, node->key) == 0) { memcpy(node->value, value, map->member_size); return EXIT_SUCCESS; } if(node->next == NULL) { tail = node; break; } node = node->next; } tail->next = calloc(1, sizeof(mons_hashmap_pair *)); tail = tail->next; } tail->key = calloc(strlen(key) + 1, 1); strcpy(tail->key, key); tail->value = calloc(1, map->member_size); memcpy(tail->value, value, map->member_size); map->len++; if (map->len / map->bucket_count > MONS_HASHMAP_MAX_LOAD_FACTOR) { mons_hashmap_rehash(map); } return EXIT_SUCCESS; } int mons_hashmap_get(mons_hashmap map, char *key, void *out) { unsigned int bucket = djb2_hash((unsigned char*)key, map.bucket_count); mons_hashmap_pair *tail = map.data[bucket]; while(tail != NULL) { if(strcmp(key, tail->key) == 0) { memcpy(out, tail->value, map.member_size); return EXIT_SUCCESS; } tail = tail->next; } return EXIT_FAILURE; } int mons_hashmap_remove(mons_hashmap *map, char *key) { unsigned int bucket = djb2_hash((unsigned char*)key, map->bucket_count); mons_hashmap_pair *tail = map->data[bucket]; mons_hashmap_pair *prev = NULL; while(tail != NULL) { if(strcmp(key, tail->key) == 0) { if (prev == NULL) { map->data[bucket] = tail->next; } else { prev->next = tail->next; } free(tail->key); free(tail->value); free(tail); map->len--; return EXIT_SUCCESS; } prev = tail; tail = tail->next; } return EXIT_FAILURE; } void mons_hashmap_free(mons_hashmap *hashmap) { for (int i = 0; i < hashmap->bucket_count; i++) { mons_hashmap_pair *node = hashmap->data[i]; while(node != NULL) { mons_hashmap_pair *next = node->next; free(node->key); free(node->value); free(node); node = next; } } free(hashmap->data); hashmap->data = NULL; hashmap->bucket_count = 0; hashmap->member_size = 0; hashmap->len = 0; } int mons_hashmap_at(mons_hashmap map, unsigned int index, mons_hashmap_pair *out) { mons_hashmap_pair **bucket = map.data; mons_hashmap_pair *node = *bucket; while(node == NULL) { bucket++; node = *bucket; } for(int i = 0; i < index; i++) { if (node == NULL || node->next == NULL) { bucket++; node = *bucket; while(node == NULL) { bucket++; node = *bucket; } } else { node = node->next; } } *out = *node; return EXIT_SUCCESS; }