Derive-C
Loading...
Searching...
No Matches
template.h
Go to the documentation of this file.
1
3
7#if !defined(SKIP_INCLUDES)
8 #include "includes.h"
9#endif
10
13
14#if !defined KEY
15 #if !defined DC_PLACEHOLDERS
16TEMPLATE_ERROR("No KEY")
17 #endif
18 #define KEY map_key_t
19typedef size_t KEY;
20#endif
21
22#if !defined KEY_HASH
23 #if !defined DC_PLACEHOLDERS
24TEMPLATE_ERROR("No KEY_HASH")
25 #endif
26
27 #define KEY_HASH key_hash
28static size_t KEY_HASH(KEY const* key) { return *key; }
29#endif
30
31#if !defined KEY_EQ
32 #define KEY_EQ DC_MEM_EQ
33#endif
34
35#if !defined KEY_DELETE
36 #define KEY_DELETE DC_NO_DELETE
37#endif
38
39#if !defined KEY_CLONE
40 #define KEY_CLONE DC_COPY_CLONE
41#endif
42
43#if !defined KEY_DEBUG
44 #define KEY_DEBUG DC_DEFAULT_DEBUG
45#endif
46
47#if !defined VALUE
48 #if !defined DC_PLACEHOLDERS
49TEMPLATE_ERROR("No VALUE")
50 #endif
51typedef struct {
52 int x;
53} value_t;
54 #define VALUE value_t
55#endif
56
57#if !defined VALUE_DELETE
58 #define VALUE_DELETE DC_NO_DELETE
59#endif
60
61#if !defined VALUE_CLONE
62 #define VALUE_CLONE DC_COPY_CLONE
63#endif
64
65#if !defined VALUE_DEBUG
66 #define VALUE_DEBUG DC_DEFAULT_DEBUG
67#endif
68
69typedef KEY NS(SELF, key_t);
70typedef VALUE NS(SELF, value_t);
71typedef ALLOC NS(SELF, alloc_t);
72
73#define SLOT NS(SELF, slot_t)
74typedef struct {
75 VALUE value;
76 KEY key;
77} SLOT;
78
79typedef struct {
80 size_t capacity;
81 size_t count;
82 size_t tombstones;
83
85 SLOT* slots;
86
87 NS(ALLOC, ref) alloc_ref;
88 dc_gdb_marker derive_c_hashmap;
90} SELF;
91
93
94#define INVARIANT_CHECK(self) \
95 DC_ASSUME(self); \
96 DC_ASSUME(DC_MATH_IS_POWER_OF_2((self)->capacity)); \
97 DC_ASSUME((self)->slots); \
98 DC_ASSUME((self)->ctrl); \
99 DC_ASSUME((self)->count + (self)->tombstones <= (self)->capacity);
100
101static SELF PRIV(NS(SELF, new_with_exact_capacity))(size_t capacity, NS(ALLOC, ref) alloc_ref) {
104 size_t ctrl_capacity = capacity + _DC_SWISS_SIMD_PROBE_SIZE;
105
107 alloc_ref, sizeof(_dc_swiss_ctrl) * ctrl_capacity);
108 SLOT* slots = (SLOT*)NS(ALLOC, allocate_uninit)(alloc_ref, sizeof(SLOT) * capacity);
109
110 for (size_t i = 0; i < capacity; i++) {
111 ctrl[i] = DC_SWISS_VAL_EMPTY;
112 }
113 ctrl[capacity] = DC_SWISS_VAL_SENTINEL;
114 for (size_t i = 1; i < _DC_SWISS_SIMD_PROBE_SIZE; i++) {
115 ctrl[capacity + i] = ctrl[i - 1]; // currently empty
116 }
117
118 return (SELF){
119 .capacity = capacity,
120 .count = 0,
121 .tombstones = 0,
122 .ctrl = ctrl,
123 .slots = slots,
124 .alloc_ref = alloc_ref,
125 .derive_c_hashmap = dc_gdb_marker_new(),
126 .iterator_invalidation_tracker = mutation_tracker_new(),
127 };
128}
129
130DC_PUBLIC static SELF NS(SELF, new_with_capacity_for)(size_t for_items, NS(ALLOC, ref) alloc_ref) {
131 DC_ASSERT(for_items > 0, "Cannot create map with capacity for 0 items {for_items=%lu}",
132 for_items);
133
134 return PRIV(NS(SELF, new_with_exact_capacity))(dc_swiss_capacity(for_items), alloc_ref);
135}
136
137DC_PUBLIC static SELF NS(SELF, new)(NS(ALLOC, ref) alloc_ref) {
139}
140
141DC_PUBLIC static SELF NS(SELF, clone)(SELF const* self) {
142 INVARIANT_CHECK(self);
143
144 size_t ctrl_capacity = self->capacity + _DC_SWISS_SIMD_PROBE_SIZE;
145
147 self->alloc_ref, sizeof(_dc_swiss_ctrl) * ctrl_capacity);
148 SLOT* slots = (SLOT*)NS(ALLOC, allocate_uninit)(self->alloc_ref, sizeof(SLOT) * self->capacity);
149
150 memcpy(ctrl, self->ctrl, sizeof(_dc_swiss_ctrl) * ctrl_capacity);
151
152 for (size_t i = 0; i < self->capacity; i++) {
153 if (_dc_swiss_is_present(self->ctrl[i])) {
154 slots[i].key = KEY_CLONE(&self->slots[i].key);
155 slots[i].value = VALUE_CLONE(&self->slots[i].value);
156 }
157 }
158
159 return (SELF){
160 .capacity = self->capacity,
161 .count = self->count,
162 .tombstones = self->tombstones,
163 .ctrl = ctrl,
164 .slots = slots,
165 .alloc_ref = self->alloc_ref,
166 .derive_c_hashmap = dc_gdb_marker_new(),
167 .iterator_invalidation_tracker = mutation_tracker_new(),
168 };
169}
170
172 INVARIANT_CHECK(self);
173 DC_ASSUME(self->count + self->tombstones < self->capacity);
174 mutation_tracker_mutate(&self->iterator_invalidation_tracker);
175
176 const size_t mask = self->capacity - 1;
177
178 const size_t hash = KEY_HASH(&key);
180
182
183 // `H1` - the bucket starting position
184 size_t const start = hash & mask;
185
186 for (size_t step = 0;; step += _DC_SWISS_SIMD_PROBE_SIZE) {
187 const size_t group_start = (start + step) & mask;
188
189 _dc_swiss_ctrl_group const group = _dc_swiss_group_load(&self->ctrl[group_start]);
190 _dc_swiss_ctrl_group_bitmask const matches = _dc_swiss_group_match(group, id);
191
192 _DC_SWISS_BITMASK_FOR_EACH(matches, group_offset) {
193 size_t const index =
194 _dc_swiss_group_index_to_slot(group_start, group_offset, self->capacity);
195
196 // Sentinel value, skip over it.
197 if (index == _DC_SWISS_NO_INDEX)
198 continue;
199
200 if (KEY_EQ(&self->slots[index].key, &key)) {
201 return NULL;
202 }
203 }
204
205 if (first_deleted == _DC_SWISS_NO_INDEX) {
206 _dc_swiss_ctrl_group_bitmask const deleted =
208 if (deleted != 0) {
209 size_t const slot = _dc_swiss_group_index_to_slot(
210 group_start, _dc_swiss_ctrl_group_bitmask_lowest(deleted), self->capacity);
211 if (slot != _DC_SWISS_NO_INDEX) {
212 first_deleted = slot;
213 }
214 }
215 }
216
218 if (empty != 0) {
219 size_t const empty_idx = _dc_swiss_group_index_to_slot(
220 group_start, _dc_swiss_ctrl_group_bitmask_lowest(empty), self->capacity);
221 DC_ASSUME(empty_idx != _DC_SWISS_NO_INDEX, "Empty value cannot match the sentinel");
222
223 bool const has_deleted = first_deleted != _DC_SWISS_NO_INDEX;
224 size_t const insert_index = has_deleted ? first_deleted : empty_idx;
225
226 if (has_deleted) {
227 self->tombstones--;
228 }
229
230 self->slots[insert_index] = (SLOT){
231 .value = value,
232 .key = key,
233 };
234 _dc_swiss_ctrl_set_at(self->ctrl, self->capacity, insert_index, id);
235
236 self->count++;
237 return &self->slots[insert_index].value;
238 }
239 }
240}
241
242static void PRIV(NS(SELF, rehash))(SELF* self, size_t new_capacity) {
243 INVARIANT_CHECK(self);
244
245 // NOTE: This code also works for shrinking the hashmap
246 // - we never expect to do this, so are defensive.
247 // - We do expect to rehash with the same capacity (tombstone cleanup)
248 DC_ASSUME(new_capacity >= self->capacity);
249 mutation_tracker_mutate(&self->iterator_invalidation_tracker);
250
251 SELF new_map = PRIV(NS(SELF, new_with_exact_capacity))(new_capacity, self->alloc_ref);
252
253 for (size_t i = 0; i < self->capacity; i++) {
254 if (_dc_swiss_is_present(self->ctrl[i])) {
255 (void)PRIV(NS(SELF, try_insert_no_extend_capacity))(&new_map, self->slots[i].key,
256 self->slots[i].value);
257 }
258 }
259
260 new_map.iterator_invalidation_tracker = self->iterator_invalidation_tracker;
261
262 size_t ctrl_capacity = self->capacity + _DC_SWISS_SIMD_PROBE_SIZE;
263 NS(ALLOC, deallocate)(self->alloc_ref, self->ctrl, sizeof(_dc_swiss_ctrl) * ctrl_capacity);
264 NS(ALLOC, deallocate)(self->alloc_ref, self->slots, sizeof(SLOT) * self->capacity);
265
266 *self = new_map;
267}
268
269DC_PUBLIC static void NS(SELF, extend_capacity_for)(SELF* self, size_t expected_items) {
270 INVARIANT_CHECK(self);
271 mutation_tracker_mutate(&self->iterator_invalidation_tracker);
272
273 size_t new_capacity = dc_swiss_capacity(expected_items);
274 if (new_capacity > self->capacity) {
275 PRIV(NS(SELF, rehash))(self, new_capacity);
276 }
277}
278
279DC_PUBLIC static VALUE* NS(SELF, try_insert)(SELF* self, KEY key, VALUE value) {
280 INVARIANT_CHECK(self);
281
282 if (self->count >= NS(SELF, max_capacity)) {
283 return NULL;
284 }
285
286 switch (_dc_swiss_heuristic_should_extend(self->tombstones, self->count, self->capacity)) {
288 PRIV(NS(SELF, rehash))(self, self->capacity * 2);
289 break;
291 PRIV(NS(SELF, rehash))(self, self->capacity);
292 break;
294 break;
295 }
296
297 return PRIV(NS(SELF, try_insert_no_extend_capacity))(self, key, value);
298}
299
300DC_PUBLIC static VALUE* NS(SELF, insert)(SELF* self, KEY key, VALUE value) {
301 VALUE* value_ptr = NS(SELF, try_insert)(self, key, value);
302 DC_ASSERT(value_ptr, "Failed to insert item {key=%s, value=%s}", DC_DEBUG(KEY_DEBUG, &key),
303 DC_DEBUG(VALUE_DEBUG, &value));
304 return value_ptr;
305}
306
307DC_PUBLIC static VALUE const* NS(SELF, try_read)(SELF const* self, KEY key) {
308 const size_t mask = self->capacity - 1;
309
310 const size_t hash = KEY_HASH(&key);
312
313 const size_t start = hash & mask;
314
315 for (size_t step = 0;; step += _DC_SWISS_SIMD_PROBE_SIZE) {
316 size_t const group_start = (start + step) & mask;
317 _dc_swiss_ctrl_group const group = _dc_swiss_group_load(&self->ctrl[group_start]);
318 _dc_swiss_ctrl_group_bitmask const matches = _dc_swiss_group_match(group, id);
319
320 _DC_SWISS_BITMASK_FOR_EACH(matches, group_offset) {
321 size_t const i =
322 _dc_swiss_group_index_to_slot(group_start, group_offset, self->capacity);
323
324 // Sentinel
325 if (i == _DC_SWISS_NO_INDEX)
326 continue;
327
328 if (KEY_EQ(&self->slots[i].key, &key)) {
329 return &self->slots[i].value;
330 }
331 }
332
334 if (empty != 0) {
335 return NULL;
336 }
337 }
338}
339
340DC_PUBLIC static VALUE const* NS(SELF, read)(SELF const* self, KEY key) {
341 VALUE const* value = NS(SELF, try_read)(self, key);
342 DC_ASSERT(value, "Cannot read item {key=%s}", DC_DEBUG(KEY_DEBUG, &key));
343 return value;
344}
345
346DC_PUBLIC static VALUE* NS(SELF, try_write)(SELF* self, KEY key) {
347 INVARIANT_CHECK(self);
348 return (VALUE*)NS(SELF, try_read)((SELF const*)self, key);
349}
350
351DC_PUBLIC static VALUE* NS(SELF, write)(SELF* self, KEY key) {
352 VALUE* value = NS(SELF, try_write)(self, key);
353 DC_ASSERT(value, "Cannot write item {key=%s}", DC_DEBUG(KEY_DEBUG, &key));
354 return value;
355}
356
357DC_PUBLIC static bool NS(SELF, try_remove)(SELF* self, KEY key, VALUE* destination) {
358 INVARIANT_CHECK(self);
359 DC_ASSERT(destination != NULL, "Passed NULL destination pointer");
360
361 const size_t mask = self->capacity - 1;
362 const size_t hash = KEY_HASH(&key);
364
365 const size_t start = hash & mask;
366
367 for (size_t step = 0;; step += _DC_SWISS_SIMD_PROBE_SIZE) {
368 const size_t group_start = (start + step) & mask;
369
370 _dc_swiss_ctrl_group const group = _dc_swiss_group_load(&self->ctrl[group_start]);
371 _dc_swiss_ctrl_group_bitmask const matches = _dc_swiss_group_match(group, id);
372
373 _DC_SWISS_BITMASK_FOR_EACH(matches, group_offset) {
374 size_t const index =
375 _dc_swiss_group_index_to_slot(group_start, group_offset, self->capacity);
376
377 if (index == _DC_SWISS_NO_INDEX)
378 continue;
379
380 if (KEY_EQ(&self->slots[index].key, &key)) {
381 *destination = self->slots[index].value;
382 _dc_swiss_ctrl_set_at(self->ctrl, self->capacity, index, DC_SWISS_VAL_DELETED);
383 self->count--;
384 self->tombstones++;
385 return true;
386 }
387 }
388
390 if (empty != 0) {
391 return false;
392 }
393 }
394}
395
396DC_PUBLIC static VALUE NS(SELF, remove)(SELF* self, KEY key) {
397 VALUE value;
398 DC_ASSERT(NS(SELF, try_remove)(self, key, &value), "Failed to remove item {key=%s}",
399 DC_DEBUG(KEY_DEBUG, &key));
400 return value;
401}
402
403DC_PUBLIC static void NS(SELF, delete_entry)(SELF* self, KEY key) {
404 VALUE value = NS(SELF, remove)(self, key);
405 VALUE_DELETE(&value);
406}
407
408DC_PUBLIC static size_t NS(SELF, size)(SELF const* self) {
409 INVARIANT_CHECK(self);
410 return self->count;
411}
412
413static void PRIV(NS(SELF, next_populated_index))(SELF const* self,
415 size_t i = *index;
416 while (i < self->capacity && !_dc_swiss_is_present(self->ctrl[i])) {
417 ++i;
418 }
419 *index = (i == self->capacity) ? _DC_SWISS_NO_INDEX : i;
420}
421
422DC_PUBLIC static void NS(SELF, delete)(SELF* self) {
423 for (size_t i = 0; i < self->capacity; i++) {
424 if (_dc_swiss_is_present(self->ctrl[i])) {
425 KEY_DELETE(&self->slots[i].key);
426 VALUE_DELETE(&self->slots[i].value);
427 }
428 }
429
430 size_t ctrl_capacity = self->capacity + _DC_SWISS_SIMD_PROBE_SIZE;
431 NS(ALLOC, deallocate)(self->alloc_ref, self->ctrl, sizeof(_dc_swiss_ctrl) * ctrl_capacity);
432 NS(ALLOC, deallocate)(self->alloc_ref, self->slots, sizeof(SLOT) * self->capacity);
433}
434
435#define ITER_CONST NS(SELF, iter_const)
436#define KV_PAIR_CONST NS(ITER_CONST, item)
437
438typedef struct {
439 SELF const* map;
442} ITER_CONST;
443
444typedef struct {
445 KEY const* key;
446 VALUE const* value;
448
450 return item->key == NULL && item->value == NULL;
451}
452
454 mutation_version_check(&iter->version);
455
456 _dc_swiss_optional_index index = iter->next_index;
457 if (index == _DC_SWISS_NO_INDEX) {
458 return (KV_PAIR_CONST){
459 .key = NULL,
460 .value = NULL,
461 };
462 }
463
464 iter->next_index++;
465 PRIV(NS(SELF, next_populated_index))(iter->map, &iter->next_index);
466 return (KV_PAIR_CONST){
467 .key = &iter->map->slots[index].key,
468 .value = &iter->map->slots[index].value,
469 };
470}
471
472DC_PUBLIC static bool NS(ITER_CONST, empty)(ITER_CONST const* iter) {
473 DC_ASSUME(iter);
474 mutation_version_check(&iter->version);
475 return iter->next_index == _DC_SWISS_NO_INDEX;
476}
477
479 INVARIANT_CHECK(self);
480
481 _dc_swiss_optional_index index = 0;
482 PRIV(NS(SELF, next_populated_index))(self, &index);
483
484 return (ITER_CONST){
485 .map = self,
486 .next_index = index,
487 .version = mutation_tracker_get(&self->iterator_invalidation_tracker),
488 };
489}
490
491DC_PUBLIC static void NS(SELF, debug)(SELF const* self, dc_debug_fmt fmt, FILE* stream) {
492 fprintf(stream, DC_EXPAND_STRING(SELF) "@%p {\n", (void*)self);
493 fmt = dc_debug_fmt_scope_begin(fmt);
494
495 dc_debug_fmt_print(fmt, stream, "capacity: %lu,\n", self->capacity);
496 dc_debug_fmt_print(fmt, stream, "tombstones: %lu,\n", self->tombstones);
497 dc_debug_fmt_print(fmt, stream, "count: %lu,\n", self->count);
498
499 dc_debug_fmt_print(fmt, stream, "ctrl: @%p[%lu + simd probe size additional %lu],\n",
500 (void*)self->ctrl, self->capacity, (size_t)_DC_SWISS_SIMD_PROBE_SIZE);
501 dc_debug_fmt_print(fmt, stream, "slots: @%p[%lu],\n", (void*)self->slots, self->capacity);
502
503 dc_debug_fmt_print(fmt, stream, "alloc: ");
504 NS(ALLOC, debug)(NS(NS(ALLOC, ref), deref)(self->alloc_ref), fmt, stream);
505 fprintf(stream, ",\n");
506
507 dc_debug_fmt_print(fmt, stream, "entries: [\n");
508 fmt = dc_debug_fmt_scope_begin(fmt);
509
510 ITER_CONST iter = NS(SELF, get_iter_const)(self);
511
513 item = NS(ITER_CONST, next)(&iter)) {
514 dc_debug_fmt_print(fmt, stream, "{\n");
515 fmt = dc_debug_fmt_scope_begin(fmt);
516
517 dc_debug_fmt_print(fmt, stream, "key: ");
518 KEY_DEBUG(item.key, fmt, stream);
519 fprintf(stream, ",\n");
520
521 dc_debug_fmt_print(fmt, stream, "value: ");
522 VALUE_DEBUG(item.value, fmt, stream);
523 fprintf(stream, ",\n");
524
525 fmt = dc_debug_fmt_scope_end(fmt);
526 dc_debug_fmt_print(fmt, stream, "},\n");
527 }
528
529 fmt = dc_debug_fmt_scope_end(fmt);
530 dc_debug_fmt_print(fmt, stream, "]\n");
531
532 fmt = dc_debug_fmt_scope_end(fmt);
533 dc_debug_fmt_print(fmt, stream, "}");
534}
535
536#undef KV_PAIR_CONST
537#undef ITER_CONST
538
539#define ITER NS(SELF, iter)
540#define KV_PAIR NS(ITER, item)
541
542typedef struct {
543 SELF const* map;
546} ITER;
547
548typedef struct {
549 KEY const* key;
550 VALUE const* value;
551} KV_PAIR;
552
553DC_PUBLIC static bool NS(ITER, empty_item)(KV_PAIR const* item) {
554 return item->key == NULL && item->value == NULL;
555}
556
557DC_PUBLIC static KV_PAIR NS(ITER, next)(ITER* iter) {
558 mutation_version_check(&iter->version);
559
560 _dc_swiss_optional_index index = iter->next_index;
561 if (index == _DC_SWISS_NO_INDEX) {
562 return (KV_PAIR){
563 .key = NULL,
564 .value = NULL,
565 };
566 }
567
568 iter->next_index++;
569 PRIV(NS(SELF, next_populated_index))(iter->map, &iter->next_index);
570 return (KV_PAIR){
571 .key = &iter->map->slots[index].key,
572 .value = &iter->map->slots[index].value,
573 };
574}
575
576DC_PUBLIC static bool NS(ITER, empty)(ITER const* iter) {
577 DC_ASSUME(iter);
578 mutation_version_check(&iter->version);
579 return iter->next_index == _DC_SWISS_NO_INDEX;
580}
581
583 INVARIANT_CHECK(self);
584
585 _dc_swiss_optional_index index = 0;
586 PRIV(NS(SELF, next_populated_index))(self, &index);
587
588 return (ITER){
589 .map = self,
590 .next_index = index,
591 .version = mutation_tracker_get(&self->iterator_invalidation_tracker),
592 };
593}
594
595#undef KV_PAIR
596#undef ITER
597
598#undef INVARIANT_CHECK
599
600#undef SLOT
601
602#undef VALUE_DEBUG
603#undef VALUE_CLONE
604#undef VALUE_DELETE
605#undef VALUE
606
607#undef KEY_DEBUG
608#undef KEY_CLONE
609#undef KEY_DELETE
610#undef KEY_EQ
611#undef KEY_HASH
612#undef KEY
613
615
static DC_PUBLIC void deallocate(SELF *self, void *ptr, size_t size)
Definition template.h:127
static DC_PUBLIC void debug(SELF const *self, dc_debug_fmt fmt, FILE *stream)
Definition template.h:212
static DC_PUBLIC void * allocate_zeroed(SELF *self, size_t size)
Definition template.h:117
static DC_PUBLIC void * allocate_uninit(SELF *self, size_t size)
Definition template.h:92
#define ALLOC
Definition template.h:31
#define KEY
Definition template.h:32
#define VALUE
Definition template.h:35
#define KEY_DEBUG
Definition template.h:34
#define DC_STATIC_CONSTANT
Definition attributes.h:23
static DC_PUBLIC VALUE const * try_read(SELF const *self, INDEX index)
Definition template.h:180
static DC_PUBLIC VALUE * try_write(SELF *self, INDEX index)
Definition template.h:205
#define VALUE_DEBUG
Definition template.h:41
#define SLOT
Definition template.h:65
#define INVARIANT_CHECK(self)
Definition template.h:90
static DC_PUBLIC IV_PAIR next(ITER *iter)
Definition template.h:355
static DC_PUBLIC INDEX insert(SELF *self, VALUE value)
Definition template.h:126
static DC_PUBLIC bool empty(ITER const *iter)
Definition template.h:349
static DC_PUBLIC VALUE const * read(SELF const *self, INDEX index)
Definition template.h:199
static DC_PUBLIC bool try_remove(SELF *self, INDEX index, VALUE *destination)
Definition template.h:264
ALLOC alloc_t
Definition template.h:63
static DC_PUBLIC VALUE * write(SELF *self, INDEX index)
Definition template.h:209
static DC_PUBLIC bool empty_item(IV_PAIR const *item)
Definition template.h:347
static DC_PUBLIC VALUE remove(SELF *self, INDEX index)
Definition template.h:292
#define ITER
Definition template.h:322
#define VALUE_CLONE
Definition template.h:39
static DC_PUBLIC ITER get_iter(SELF *self)
Definition template.h:373
#define VALUE_DELETE
Definition template.h:37
#define ITER_CONST
Definition template.h:411
static DC_PUBLIC ITER_CONST get_iter_const(SELF const *self)
Definition template.h:464
static DC_PUBLIC size_t size(SELF const *self)
Definition template.h:252
static DC_PUBLIC SELF clone(SELF const *self)
Definition template.h:215
IV_PAIR item
Definition template.h:281
static DC_PUBLIC SELF new_with_capacity_for(INDEX_TYPE items, ref alloc_ref)
Definition template.h:96
#define KEY_HASH
Definition template.h:26
#define KV_PAIR
Definition template.h:585
#define KEY_DELETE
Definition template.h:35
static DC_PUBLIC void extend_capacity_for(SELF *self, size_t expected_items)
Definition template.h:307
static DC_INTERNAL void PRIV rehash(SELF *self, size_t new_capacity)
Definition template.h:260
#define KEY_CLONE
Definition template.h:39
DC_STATIC_CONSTANT size_t max_capacity
Definition template.h:130
static DC_INTERNAL VALUE *PRIV try_insert_no_extend_capacity(SELF *self, KEY key, VALUE value)
Definition template.h:190
static DC_PUBLIC void delete_entry(SELF *self, KEY key)
Definition template.h:504
static DC_PUBLIC VALUE * try_insert(SELF *self, KEY key, VALUE value)
Definition template.h:318
#define KEY_EQ
Definition template.h:31
#define KEY_DEBUG
Definition template.h:43
KEY key_t
Definition template.h:68
#define KV_PAIR_CONST
Definition template.h:522
static DC_INTERNAL SELF PRIV new_with_exact_capacity(size_t capacity, ref alloc_ref)
Definition template.h:148
static void PRIV next_populated_index(SELF const *self, _dc_swiss_optional_index *index)
Definition template.h:413
#define DC_TRAIT_MAP(SELF)
Definition trait.h:5
#define TEMPLATE_ERROR(...)
With the user provided name, even in nested templates.
Definition def.h:56
#define SELF
Definition def.h:52
#define DC_DEBUG(DEBUG_FN, DEBUG_PTR)
Definition dump.h:92
static DC_PUBLIC void dc_debug_fmt_print(dc_debug_fmt fmt, FILE *stream, const char *format,...)
Definition fmt.h:32
static DC_PUBLIC dc_debug_fmt dc_debug_fmt_scope_end(dc_debug_fmt fmt)
Definition fmt.h:57
static DC_PUBLIC dc_debug_fmt dc_debug_fmt_scope_begin(dc_debug_fmt fmt)
Definition fmt.h:50
static DC_PUBLIC dc_gdb_marker dc_gdb_marker_new()
Definition gdb_marker.h:8
#define DC_SWISS_INITIAL_CAPACITY
Definition utils.h:13
__m128i _dc_swiss_ctrl_group
Definition utils.h:18
#define _DC_SWISS_BITMASK_FOR_EACH(mask, idx_var)
Definition utils.h:129
#define DC_SWISS_VAL_EMPTY
Definition utils.h:37
@ DC_SWISS_DO_NOTHING
Definition utils.h:78
@ DC_SWISS_DOUBLE_CAPACITY
Definition utils.h:76
@ DC_SWISS_CLEANUP_TOMBSONES
Definition utils.h:77
#define _DC_SWISS_SIMD_PROBE_SIZE
Definition utils.h:28
static DC_INTERNAL size_t _dc_swiss_group_index_to_slot(size_t group_start, _dc_swiss_ctrl_group_offset idx, size_t capacity)
Definition utils.h:136
static size_t const _dc_swiss_index_capacity
Definition utils.h:104
static DC_INTERNAL _dc_swiss_ctrl_group_offset _dc_swiss_ctrl_group_bitmask_lowest(_dc_swiss_ctrl_group_bitmask mask)
Definition utils.h:118
#define DC_SWISS_VAL_DELETED
Definition utils.h:36
static DC_INTERNAL size_t dc_swiss_capacity(size_t for_items)
Definition utils.h:56
DC_INTERNAL static DC_PURE bool _dc_swiss_is_present(_dc_swiss_ctrl ctrl)
Definition utils.h:40
static DC_INTERNAL void _dc_swiss_ctrl_set_at(_dc_swiss_ctrl *self, size_t capacity, size_t index, _dc_swiss_ctrl val)
Definition utils.h:63
uint16_t _dc_swiss_ctrl_group_bitmask
Definition utils.h:26
static DC_INTERNAL _dc_swiss_rehash_action _dc_swiss_heuristic_should_extend(size_t tombstones, size_t count, size_t capacity)
Definition utils.h:82
static DC_INTERNAL _dc_swiss_ctrl_group _dc_swiss_group_load(const _dc_swiss_ctrl *group_ptr)
Definition utils.h:106
static DC_INTERNAL _dc_swiss_ctrl_group_bitmask _dc_swiss_group_match(_dc_swiss_ctrl_group group, uint8_t value)
Definition utils.h:111
uint8_t _dc_swiss_ctrl
Definition utils.h:19
size_t _dc_swiss_optional_index
Definition utils.h:99
static DC_INTERNAL _dc_swiss_ctrl _dc_swiss_ctrl_from_hash(size_t hash)
Definition utils.h:51
#define DC_SWISS_VAL_SENTINEL
Definition utils.h:35
#define _DC_SWISS_NO_INDEX
Definition utils.h:98
#define DC_MATH_IS_POWER_OF_2(x)
Definition math.h:14
static DC_PUBLIC void mutation_tracker_mutate(mutation_tracker *self)
static DC_PUBLIC void mutation_version_check(mutation_version const *self)
static DC_PUBLIC mutation_tracker mutation_tracker_new()
static DC_PUBLIC mutation_version mutation_tracker_get(mutation_tracker const *self)
#define DC_PUBLIC
Definition namespace.h:25
#define NS(pre, post)
Definition namespace.h:14
#define DC_EXPAND_STRING(NAME)
Definition namespace.h:6
#define PRIV(name)
Definition namespace.h:20
#define DC_ASSERT(expr,...)
Definition panic.h:37
#define DC_ASSUME(expr,...)
Definition panic.h:57
INDEX_TYPE next_index
Definition template.h:416
mutation_version version
Definition template.h:417
INDEX_TYPE next_index
Definition template.h:327
mutation_version version
Definition template.h:328
SELF * map
Definition template.h:411
_dc_swiss_ctrl * ctrl
Definition template.h:84
mutation_tracker iterator_invalidation_tracker
Definition template.h:87
SLOT * slots
Definition template.h:71
dc_gdb_marker derive_c_hashmap
Definition template.h:138
size_t tombstones
Definition template.h:82
ref alloc_ref
Definition template.h:49
VALUE value
Definition template.h:78
KEY key
Definition template.h:77
Debug format helpers for debug printin data structures.
Definition fmt.h:11
tracks a specific version of a value, so that this can be compared later to check modification For ex...
static DC_PUBLIC FILE * stream(SELF *self)
Definition template.h:108