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