hmap.c (4118B)
1 #include <stdio.h> 2 #include <string.h> 3 4 #include "hmap.h" 5 6 #define INITIAL_BUCKETS 8 7 #define LOAD_FACTOR 0.75 8 9 static void hmap_grow(HashMap* map); 10 11 // Simple string hash function (djb2) 12 static unsigned long hash(const char* str) 13 { 14 unsigned long h = 5381; 15 unsigned char c; 16 while ((c = (unsigned char)*str++)) 17 h = ((h << 5) + h) + c; 18 return h; 19 } 20 21 HashMap* hmap_create(size_t value_size) 22 { 23 HashMap* map = calloc(1, sizeof(HashMap)); 24 if (map == NULL) { 25 fprintf(stderr, "hmap_create: map: could not alloc\n"); 26 } 27 map->bucket_count = INITIAL_BUCKETS; 28 map->size = 0; 29 map->value_size = value_size; 30 map->buckets = calloc(map->bucket_count, sizeof(HashNode*)); 31 if (map->buckets == NULL) { 32 fprintf(stderr, "hmap_create: bucket: could not alloc\n"); 33 exit(1); 34 } 35 return map; 36 } 37 38 void hmap_put(HashMap* map, const char* key, const void* value) 39 { 40 if ((float)(map->size + 1) / map->bucket_count > LOAD_FACTOR) { 41 hmap_grow(map); 42 } 43 unsigned long h = hash(key) % map->bucket_count; 44 HashNode* node = map->buckets[h]; 45 while (node) { 46 if (strcmp(node->key, key) == 0) { 47 memcpy(node->value, value, map->value_size); 48 return; 49 } 50 node = node->next; 51 } 52 HashNode* new_node = calloc(1, sizeof(HashNode)); 53 if (new_node == NULL) { 54 fprintf(stderr, "hmap_put: new_node: could not alloc\n"); 55 exit(1); 56 } 57 new_node->key = strdup(key); 58 new_node->value = calloc(1, map->value_size); 59 if (new_node == NULL) { 60 fprintf(stderr, "hmap_put: new_node->value: could not alloc\n"); 61 exit(1); 62 } 63 memcpy(new_node->value, value, map->value_size); 64 new_node->next = map->buckets[h]; 65 map->buckets[h] = new_node; 66 map->size++; 67 } 68 69 bool hmap_get(HashMap* map, const char* key, void* out) 70 { 71 unsigned long h = hash(key) % map->bucket_count; 72 HashNode* node = map->buckets[h]; 73 while (node) { 74 if (strcmp(node->key, key) == 0) { 75 memcpy(out, node->value, map->value_size); 76 return true; 77 } 78 node = node->next; 79 } 80 return false; 81 } 82 83 bool hmap_remove(HashMap* map, const char* key) 84 { 85 unsigned long h = hash(key) % map->bucket_count; 86 HashNode* node = map->buckets[h]; 87 HashNode* prev = NULL; 88 while (node) { 89 if (strcmp(node->key, key) == 0) { 90 if (prev) { 91 prev->next = node->next; 92 } else { 93 map->buckets[h] = node->next; 94 } 95 free(node->key); 96 free(node->value); 97 free(node); 98 map->size--; 99 return true; 100 } 101 prev = node; 102 node = node->next; 103 } 104 return false; 105 } 106 107 static void hmap_grow(HashMap* map) 108 { 109 size_t new_bucket_count = map->bucket_count * 2; 110 HashNode** new_buckets = calloc(new_bucket_count, sizeof(HashNode*)); 111 if (new_buckets == NULL) { 112 fprintf(stderr, "hmap_grow: could not alloc\n"); 113 exit(1); 114 } 115 for (size_t i = 0; i < map->bucket_count; i++) { 116 HashNode* node = map->buckets[i]; 117 while (node) { 118 HashNode* next = node->next; 119 unsigned long h = hash(node->key) % new_bucket_count; 120 node->next = new_buckets[h]; 121 new_buckets[h] = node; 122 node = next; 123 } 124 } 125 free(map->buckets); 126 map->buckets = new_buckets; 127 map->bucket_count = new_bucket_count; 128 } 129 130 void hmap_free(HashMap* map) 131 { 132 for (size_t i = 0; i < map->bucket_count; i++) { 133 HashNode* node = map->buckets[i]; 134 while (node) { 135 HashNode* next = node->next; 136 free(node->key); 137 free(node->value); 138 free(node); 139 node = next; 140 } 141 } 142 free(map->buckets); 143 free(map); 144 } 145 146 // Example usage for struct T 147 // struct T { 148 // int id; 149 // char name[32]; 150 // }; 151 152 // int main() { 153 // HashMap* map = hmap_create(sizeof(struct T)); 154 // struct T t1 = {1, "Alice"}; 155 // struct T t2 = {2, "Bob"}; 156 // struct T t3 = {3, "Carol"}; 157 158 // hmap_put(map, "alice", &t1); 159 // hmap_put(map, "bob", &t2); 160 // hmap_put(map, "carol", &t3); 161 162 // struct T out; 163 // if (hmap_get(map, "bob", &out)) { 164 // printf("bob: id=%d, name=%s\n", out.id, out.name); 165 // } 166 // if (hmap_get(map, "alice", &out)) { 167 // printf("alice: id=%d, name=%s\n", out.id, out.name); 168 // } 169 // if (hmap_get(map, "dave", &out)) { 170 // printf("dave: id=%d, name=%s\n", out.id, out.name); 171 // } else { 172 // printf("dave not found\n"); 173 // } 174 // hmap_free(map); 175 // return 0; 176 // }