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