-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathstrmap.c
115 lines (96 loc) · 3.1 KB
/
strmap.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
#include "common/strmap.h"
#define MAX_SEARCH 30
static u64 FNV_1a(string key) {
const u64 FNV_OFFSET = 14695981039346656037ull;
const u64 FNV_PRIME = 1099511628211ull;
u64 hash = FNV_OFFSET;
for_urange(i, 0, key.len) {
hash ^= (u64)(u8)(key.raw[i]);
hash *= FNV_PRIME;
}
return hash;
}
void strmap_init(StrMap* hm, size_t capacity) {
hm->cap = capacity;
hm->vals = malloc(sizeof(hm->vals[0]) * hm->cap);
hm->keys = malloc(sizeof(hm->keys[0]) * hm->cap);
memset(hm->vals, 0, sizeof(hm->vals[0]) * hm->cap);
memset(hm->keys, 0, sizeof(hm->keys[0]) * hm->cap);
}
void strmap_destroy(StrMap* hm) {
if (hm->keys) free(hm->keys);
if (hm->vals) free(hm->vals);
*hm = (StrMap){0};
}
void strmap_put(StrMap* hm, string key, void* val) {
if (hm == NULL) return;
if (is_null_str(key)) return;
size_t hash_index = FNV_1a(key) % hm->cap;
// free slot
if (hm->keys[hash_index].raw == NULL || string_eq(hm->keys[hash_index], key)) {
hm->keys[hash_index] = key;
hm->vals[hash_index] = val;
return;
}
// search for nearby free slot
for_urange(index, 1, min(MAX_SEARCH, hm->cap)) {
size_t i = (index + hash_index) % hm->cap;
if ((hm->keys[i].raw == NULL) || string_eq(hm->keys[i], key)) {
hm->keys[i] = key;
hm->vals[i] = val;
return;
}
}
// we gotta resize
StrMap new_hm;
strmap_init(&new_hm, hm->cap * 2);
// copy all the old entries into the new hashmap
for (size_t i = 0; i < hm->cap; i++) {
if (hm->keys[i].raw == NULL) continue;
strmap_put(&new_hm, hm->keys[i], hm->vals[i]);
}
strmap_put(&new_hm, key, val);
// destroy old map
free(hm->keys);
free(hm->vals);
*hm = new_hm;
}
void* strmap_get(StrMap* hm, string key) {
if (!key.raw) return STRMAP_NOT_FOUND;
size_t hash_index = FNV_1a(key) % hm->cap;
// key found in first slot
if (string_eq(hm->keys[hash_index], key)) {
return hm->vals[hash_index];
}
// linear search next slots
for_urange(index, 1, min(MAX_SEARCH, hm->cap)) {
size_t i = (index + hash_index) % hm->cap;
if (hm->keys[i].raw == NULL) return STRMAP_NOT_FOUND;
if (string_eq(hm->keys[i], key)) return hm->vals[i];
}
return STRMAP_NOT_FOUND;
}
void strmap_remove(StrMap* hm, string key) {
if (!key.raw) return;
size_t hash_index = FNV_1a(key) % hm->cap;
// key found in first slot
if (string_eq(hm->keys[hash_index], key)) {
hm->keys[hash_index] = NULL_STR;
hm->vals[hash_index] = NULL;
return;
}
// linear search next slots
for_urange(index, 1, min(MAX_SEARCH, hm->cap)) {
size_t i = (index + hash_index) % hm->cap;
if (hm->keys[i].raw == NULL) return;
if (string_eq(hm->keys[i], key)) {
hm->keys[hash_index] = NULL_STR;
hm->vals[hash_index] = NULL;
return;
}
}
}
void strmap_reset(StrMap* hm) {
memset(hm->vals, 0, sizeof(hm->vals[0]) * hm->cap);
memset(hm->keys, 0, sizeof(hm->keys[0]) * hm->cap);
}