ox

The Ox programming language, compiler and tools (WIP)
Log | Files | Refs | README | LICENSE

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 // }