Derive-C
Loading...
Searching...
No Matches
template.h
Go to the documentation of this file.
1
2
3#include <stdbool.h>
4#include <stddef.h>
5#include <stdint.h>
6#include <stdlib.h>
7
8#include <derive-c/core.h>
9#include <derive-c/panic.h>
10#include <derive-c/self.h>
12
13#ifndef K
14#error "Key type must be defined to for a hashmap template"
15typedef struct {
16 int x;
17} derive_c_parameter_key;
18#define K derive_c_parameter_key
19static void derive_c_parameter_key_delete(derive_c_parameter_key*) {}
20#define K_DELETE derive_c_parameter_key_delete
21#endif
22
23#ifndef V
24#error "Value type must be defined to for a hashmap template"
25typedef struct {
26 int x;
27} derive_c_parameter_value;
28#define V derive_c_parameter_value
29static void derive_c_parameter_value_delete(derive_c_parameter_value*) {}
30#define V_DELETE derive_c_parameter_value_delete
31#endif
32
33#ifndef HASH
34#error "The hash function for K must be defined"
35static size_t derive_c_parameter_hash(derive_c_parameter_key const* key);
36#define HASH derive_c_parameter_hash
37#endif
38
39#ifndef EQ
40#error "The equality function for K must be defined"
41static bool derive_c_parameter_eq(derive_c_parameter_key const* key_1,
42 derive_c_parameter_key const* key_2);
43#define EQ derive_c_parameter_eq
44#endif
45
46#ifndef K_DELETE
47#define K_DELETE(key)
48#endif
49
50#ifndef V_DELETE
51#define V_DELETE(value)
52#endif
53
54#define KEY_ENTRY NAME(SELF, key_entry)
55typedef struct {
56 bool present;
59} KEY_ENTRY;
60
61typedef struct {
62 size_t capacity; // INV: A power of 2
63 size_t items;
64 // Split keys & values in an old hashmap I used, cannot remember why (many collisions better
65 // decomposed), should probably use 1 buffer.
69} SELF;
70
71static SELF NAME(SELF, new_with_capacity_for)(size_t capacity) {
72 ASSERT(capacity > 0);
73 size_t real_capacity = apply_capacity_policy(capacity);
74 ASSERT(real_capacity > 0);
75 // JUSTIFY: calloc of keys
76 // - A cheap way to get all precense flags as zeroed (os & allocater supported get zeroed page)
77 // - for the values, we do not need this (no precense checks are done on values)
78 KEY_ENTRY* keys = (KEY_ENTRY*)calloc(sizeof(KEY_ENTRY), real_capacity);
79 V* values = (V*)malloc(sizeof(V) * real_capacity);
80 ASSERT(keys && values);
81 return (SELF){
82 .capacity = real_capacity,
83 .items = 0,
84 .keys = keys,
85 .values = values,
86 };
87}
88
90
91static SELF NAME(SELF, shallow_clone)(SELF const* self) {
92 DEBUG_ASSERT(self);
93
94 // JUSTIFY: Naive copy
95 // - We could resize (potentially a smaller map) and rehash
96 // - Not confident it would be any better than just a copy.
97 // JUSTIFY: Individually copy keys
98 // - Many entries are zeroed, no need to copy uninit data
99
100 KEY_ENTRY* keys = (KEY_ENTRY*)calloc(sizeof(KEY_ENTRY), self->capacity);
101 V* values = (V*)malloc(sizeof(V) * self->capacity);
102 ASSERT(keys && values);
103
104 for (size_t i = 0; i < self->capacity; i++) {
105 if (self->keys[i].present) {
106 keys[i] = self->keys[i];
107 values[i] = self->values[i];
108 }
109 }
110
111 return (SELF){.capacity = self->capacity, .items = self->items, .keys = keys, .values = values};
112}
113
114static void NAME(SELF, delete)(SELF* self);
115
116static V* NAME(SELF, insert)(SELF* self, K key, V value);
117
118static void NAME(SELF, extend_capacity_for)(SELF* self, size_t expected_items) {
119 DEBUG_ASSERT(self);
120 size_t target_capacity = apply_capacity_policy(expected_items);
121 if (target_capacity > self->capacity) {
122 SELF new_map = NAME(SELF, new_with_capacity_for)(expected_items);
123 for (size_t index = 0; index < self->capacity; index++) {
124 KEY_ENTRY* entry = &self->keys[index];
125 if (entry->present) {
126 NAME(SELF, insert)(&new_map, entry->key, self->values[index]);
127 }
128 }
129 free(self->keys);
130 free(self->values);
131 *self = new_map;
132 }
133}
134
135static V* NAME(SELF, try_insert)(SELF* self, K key, V value) {
136 DEBUG_ASSERT(self);
137 if (apply_capacity_policy(self->items) > self->capacity / 2) {
138 NAME(SELF, extend_capacity_for)(self, self->items * 2);
139 }
140
141 uint16_t distance_from_desired = 0;
142 size_t hash = HASH(&key);
143 size_t index = modulus_capacity(hash, self->capacity);
144 V* placed_entry = NULL;
145 for (;;) {
146 KEY_ENTRY* entry = &self->keys[index];
147 DEBUG_ASSERT(distance_from_desired < self->capacity);
148
149 if (entry->present) {
150 if (EQ(&entry->key, &key)) {
151 return NULL;
152 }
153
154 if (entry->distance_from_desired < distance_from_desired) {
155 K switch_key = entry->key;
156 uint16_t switch_distance_from_desired = entry->distance_from_desired;
157 V switch_value = self->values[index];
158
159 entry->key = key;
160 entry->distance_from_desired = distance_from_desired;
161 self->values[index] = value;
162
163 key = switch_key;
164 distance_from_desired = switch_distance_from_desired;
165 value = switch_value;
166
167 if (!placed_entry) {
168 placed_entry = &self->values[index];
169 }
170 }
171
172 distance_from_desired++;
173 index = modulus_capacity(index + 1, self->capacity);
174 } else {
175 entry->present = true;
176 entry->distance_from_desired = distance_from_desired;
177 entry->key = key;
178 self->values[index] = value;
179 if (!placed_entry) {
180 placed_entry = &self->values[index];
181 }
182 self->items++;
183 return placed_entry;
184 }
185 }
186}
187
188static V* NAME(SELF, insert)(SELF* self, K key, V value) {
189 V* value_ptr = NAME(SELF, try_insert)(self, key, value);
190 ASSERT(value_ptr);
191 return value_ptr;
192}
193
194static V* NAME(SELF, try_write)(SELF* self, K key) {
195 DEBUG_ASSERT(self);
196 size_t hash = HASH(&key);
197 size_t index = modulus_capacity(hash, self->capacity);
198
199 for (;;) {
200 KEY_ENTRY* entry = &self->keys[index];
201 if (entry->present) {
202 if (EQ(&entry->key, &key)) {
203 return &self->values[index];
204 } else {
205 index = modulus_capacity(index + 1, self->capacity);
206 }
207 } else {
208 return NULL;
209 }
210 }
211}
212
213static V* NAME(SELF, write)(SELF* self, K key) {
214 V* value = NAME(SELF, try_write)(self, key);
215 ASSERT(value);
216 return value;
217}
218
219static V const* NAME(SELF, try_read)(SELF const* self, K key) {
220 DEBUG_ASSERT(self);
221 size_t hash = HASH(&key);
222 size_t index = modulus_capacity(hash, self->capacity);
223
224 for (;;) {
225 KEY_ENTRY* entry = &self->keys[index];
226 if (entry->present) {
227 if (EQ(&entry->key, &key)) {
228 return &self->values[index];
229 } else {
230 index = modulus_capacity(index + 1, self->capacity);
231 }
232 } else {
233 return NULL;
234 }
235 }
236}
237
238static V const* NAME(SELF, read)(SELF const* self, K key) {
239 V const* value = NAME(SELF, try_read)(self, key);
240 ASSERT(value);
241 return value;
242}
243
244static bool NAME(SELF, try_remove)(SELF* self, K key, V* destination) {
245 DEBUG_ASSERT(self);
246 size_t hash = HASH(&key);
247 size_t index = modulus_capacity(hash, self->capacity);
248
249 for (;;) {
250 KEY_ENTRY* entry = &self->keys[index];
251 if (entry->present) {
252 if (EQ(&entry->key, &key)) {
253 self->items--;
254
255 *destination = self->values[index];
256 K_DELETE(&entry->key);
257
258 // NOTE: For robin hood hashing, we need probe chains to be unbroken
259 // - Need to find the entries that might use this chain (
260 // distance_to_desired > 0 until the next not-present or
261 // distance_to_desired=0 slot)
262 // hence we shift entries the left (being careful with modulus index)
263
264 size_t free_index = index;
265 KEY_ENTRY* free_entry = entry;
266
267 size_t check_index = modulus_capacity(free_index + 1, self->capacity);
268 KEY_ENTRY* check_entry = &self->keys[check_index];
269
270 while (check_entry->present && check_entry->distance_from_desired > 0) {
271 free_entry->key = check_entry->key;
272 free_entry->distance_from_desired = check_entry->distance_from_desired - 1;
273 self->values[free_index] = self->values[check_index];
274
275 free_index = check_index;
276 free_entry = check_entry;
277
278 check_index = modulus_capacity(free_index + 1, self->capacity);
279 check_entry = &self->keys[check_index];
280 }
281
282 // JUSTIFY: Only setting free entry to false
283 // - We remove, then shift down an index
284 // - The removed entry already has the flag set
285 // - the free entry was the last one removed/moved down an index, so it
286 // should be false.
287
288 free_entry->present = false;
289
290 return true;
291 } else {
292 index = modulus_capacity(index + 1, self->capacity);
293 }
294 } else {
295 return false;
296 }
297 }
298}
299
300static V NAME(SELF, remove)(SELF* self, K key) {
301 V value;
302 ASSERT(NAME(SELF, try_remove)(self, key, &value));
303 return value;
304}
305
306static void NAME(SELF, delete_entry)(SELF* self, K key) {
307 V value = NAME(SELF, remove)(self, key);
308 V_DELETE(&value);
309}
310
311static size_t NAME(SELF, size)(SELF const* self) {
312 DEBUG_ASSERT(self);
313 return self->items;
314}
315
316#define KV_PAIR NAME(SELF, kv)
317
318typedef struct {
319 K const* key;
321} KV_PAIR;
322
323#define ITER NAME(SELF, iter)
324
325typedef struct {
326 SELF* map;
327 size_t index;
328 size_t pos;
329} ITER;
330
331static KV_PAIR NAME(ITER, next)(ITER* iter) {
332 DEBUG_ASSERT(iter);
333 if (iter->index < iter->map->capacity) {
334 KV_PAIR ret_val = {.key = &iter->map->keys[iter->index].key,
335 .value = &iter->map->values[iter->index]};
336 iter->pos++;
337 iter->index++;
338 while (iter->index < iter->map->capacity && !iter->map->keys[iter->index].present) {
339 iter->index++;
340 }
341
342 return ret_val;
343 } else {
344 return (KV_PAIR){.key = NULL, .value = NULL};
345 }
346}
347
348static size_t NAME(ITER, position)(ITER const* iter) {
349 DEBUG_ASSERT(iter);
350 return iter->pos;
351}
352
353static bool NAME(ITER, empty)(ITER const* iter) {
354 DEBUG_ASSERT(iter);
355 return iter->index >= iter->map->capacity;
356}
357
358static ITER NAME(SELF, get_iter)(SELF* self) {
359 DEBUG_ASSERT(self);
360 size_t first_index = 0;
361 while (first_index < self->capacity && !self->keys[first_index].present) {
362 first_index++;
363 }
364 return (ITER){
365 .map = self,
366 .index = first_index,
367 .pos = 0,
368 };
369}
370
371static void NAME(SELF, delete)(SELF* self) {
372 DEBUG_ASSERT(self);
373 ITER iter = NAME(SELF, get_iter)(self);
374
375 for (size_t i = 0; i < self->capacity; i++) {
376 if (self->keys[i].present) {
377 K_DELETE(&self->keys[i].key);
378 V_DELETE(&self->values[i]);
379 }
380 }
381
382 free(self->keys);
383 free(self->values);
384}
385
386#undef ITER
387#undef KV_PAIR
388
389#define KV_PAIR_CONST NAME(SELF, kv_const)
390
391typedef struct {
392 K const* key;
393 V const* value;
395
396#define ITER_CONST NAME(SELF, iter_const)
397
398typedef struct {
399 SELF const* map;
400 size_t index;
401 size_t pos;
402} ITER_CONST;
403
404static KV_PAIR_CONST NAME(ITER_CONST, next)(ITER_CONST* iter) {
405 DEBUG_ASSERT(iter);
406 if (iter->index < iter->map->capacity) {
407 KV_PAIR_CONST ret_val = {.key = &iter->map->keys[iter->index].key,
408 .value = &iter->map->values[iter->index]};
409 iter->pos++;
410 iter->index++;
411 while (iter->index < iter->map->capacity && !iter->map->keys[iter->index].present) {
412 iter->index++;
413 }
414
415 return ret_val;
416 } else {
417 return (KV_PAIR_CONST){.key = NULL, .value = NULL};
418 }
419}
420
421static size_t NAME(ITER_CONST, position)(ITER_CONST const* iter) {
422 DEBUG_ASSERT(iter);
423 return iter->pos;
424}
425
426static bool NAME(ITER_CONST, empty)(ITER_CONST const* iter) {
427 DEBUG_ASSERT(iter);
428 return iter->index >= iter->map->capacity;
429}
430
431static ITER_CONST NAME(SELF, get_iter_const)(SELF const* self) {
432 DEBUG_ASSERT(self);
433 size_t first_index = 0;
434 while (first_index < self->capacity && !self->keys[first_index].present) {
435 first_index++;
436 }
437 return (ITER_CONST){
438 .map = self,
439 .index = first_index,
440 .pos = 0,
441 };
442}
443
444#undef ITER_CONST
445#undef KV_PAIR_CONST
446
447#undef KEY_ENTRY
448
449#undef K
450#undef V
451#undef HASH
452#undef EQ
453#undef SELF
454#undef V_DELETE
455#undef K_DELETE
static INDEX insert(SELF *self, V value)
Definition template.h:114
static bool try_remove(SELF *self, INDEX index, V *destination)
Definition template.h:212
static ITER_CONST get_iter_const(SELF const *self)
Definition template.h:382
static bool empty(ITER const *iter)
Definition template.h:273
static V remove(SELF *self, INDEX index)
Definition template.h:231
static ITER get_iter(SELF *self)
Definition template.h:305
static IV_PAIR next(ITER *iter)
Definition template.h:281
static INDEX_TYPE size(SELF const *self)
Definition template.h:194
static V const * try_read(SELF const *self, INDEX index)
Definition template.h:162
static SELF new_with_capacity_for(INDEX_TYPE items)
Definition template.h:99
static V * write(SELF *self, INDEX index)
Definition template.h:156
static bool delete_entry(SELF *self, INDEX index)
Definition template.h:237
static SELF shallow_clone(SELF const *self)
Definition template.h:180
static V * try_write(SELF *self, INDEX index)
Definition template.h:144
#define V_DELETE
Definition template.h:25
static size_t position(ITER const *iter)
Definition template.h:300
static V const * read(SELF const *self, INDEX index)
Definition template.h:174
#define V
Definition template.h:23
#define NAME(pre, post)
Definition core.h:5
#define KV_PAIR
Definition template.h:316
#define KEY_ENTRY
Definition template.h:54
#define HASH
Definition template.h:36
#define K
Definition template.h:18
#define K_DELETE
Definition template.h:20
#define EQ
Definition template.h:43
static void extend_capacity_for(SELF *self, size_t expected_items)
Definition template.h:118
#define KV_PAIR_CONST
Definition template.h:389
static V * try_insert(SELF *self, K key, V value)
Definition template.h:135
#define V
Definition template.h:28
#define ASSERT(expr,...)
Definition panic.h:15
#define DEBUG_ASSERT(expr)
Definition panic.h:24
#define SELF
Definition self.h:4
bool present
Definition template.h:56
K key
Definition template.h:58
uint16_t distance_from_desired
Definition template.h:57
K const * key
Definition template.h:392
V const * value
Definition template.h:393
K const * key
Definition template.h:319
V * value
Definition template.h:320
gdb_marker derive_c_hashmap
Definition template.h:68
size_t items
Definition template.h:63
V * values
Definition template.h:67
KEY_ENTRY * keys
Definition template.h:66
static size_t const INITIAL_CAPACITY
Definition utils.h:22
static size_t modulus_capacity(size_t index, size_t capacity)
Definition utils.h:15
static size_t apply_capacity_policy(size_t capacity)
Definition utils.h:10