Derive-C
Loading...
Searching...
No Matches
template.h
Go to the documentation of this file.
1
3
6#if !defined(SKIP_INCLUDES)
7 #include "includes.h"
8#endif
9
12
13#if !defined KEY
14 #if !defined DC_PLACEHOLDERS
15TEMPLATE_ERROR("No KEY")
16 #endif
17 #define KEY map_key_t
18typedef size_t KEY;
19#endif
20
21#if !defined KEY_HASH
22 #if !defined DC_PLACEHOLDERS
23TEMPLATE_ERROR("No KEY_HASH")
24 #endif
25
26 #define KEY_HASH key_hash
27static size_t KEY_HASH(KEY const* key) { return *key; }
28#endif
29
30#if !defined KEY_EQ
31 #define KEY_EQ DC_MEM_EQ
32#endif
33
34#if !defined KEY_DELETE
35 #define KEY_DELETE DC_NO_DELETE
36#endif
37
38#if !defined KEY_CLONE
39 #define KEY_CLONE DC_COPY_CLONE
40#endif
41
42#if !defined KEY_DEBUG
43 #define KEY_DEBUG DC_DEFAULT_DEBUG
44#endif
45
46#if !defined VALUE
47 #if !defined DC_PLACEHOLDERS
48TEMPLATE_ERROR("No VALUE")
49 #endif
50typedef struct {
51 int x;
52} value_t;
53 #define VALUE value_t
54#endif
55
56#if !defined VALUE_DELETE
57 #define VALUE_DELETE DC_NO_DELETE
58#endif
59
60#if !defined VALUE_CLONE
61 #define VALUE_CLONE DC_COPY_CLONE
62#endif
63
64#if !defined VALUE_DEBUG
65 #define VALUE_DEBUG DC_DEFAULT_DEBUG
66#endif
67
68typedef KEY NS(SELF, key_t);
69typedef VALUE NS(SELF, value_t);
70typedef ALLOC NS(SELF, alloc_t);
71
72// JUSTIFY: Using name instead of SELF
73// - We need to use SLOT from within the vector template, so need to avoid using
74// SELF (which is SLOT_VECTOR in that context)
75#define SLOT NS(NAME, slot_t)
76typedef struct {
79} SLOT;
80
81DC_INTERNAL static SLOT PRIV(NS(SLOT, clone))(SLOT const* slot) {
82 return (SLOT){
83 .key = KEY_CLONE(&slot->key),
84 .value = VALUE_CLONE(&slot->value),
85 };
86}
87
88DC_INTERNAL static void PRIV(NS(SLOT, debug))(SLOT const* slot, dc_debug_fmt fmt, FILE* stream) {
89 fprintf(stream, DC_EXPAND_STRING(SLOT) "@%p {\n", slot);
90 fmt = dc_debug_fmt_scope_begin(fmt);
91
92 dc_debug_fmt_print(fmt, stream, "key: ");
93 KEY_DEBUG(&slot->key, fmt, stream);
94 fprintf(stream, ",\n");
95
96 dc_debug_fmt_print(fmt, stream, "value: ");
97 VALUE_DEBUG(&slot->value, fmt, stream);
98 fprintf(stream, ",\n");
99
100 fmt = dc_debug_fmt_scope_end(fmt);
101 dc_debug_fmt_print(fmt, stream, "}");
102}
103
104DC_INTERNAL static void PRIV(NS(SLOT, delete))(SLOT* slot) {
105 KEY_DELETE(&slot->key);
106 VALUE_DELETE(&slot->value);
107}
108
109#define SLOT_VECTOR NS(NAME, item_vectors)
110
111#pragma push_macro("ALLOC")
112
113// ITEM is already defined
114#define ITEM SLOT // [DERIVE-C] for template
115#define ITEM_DELETE PRIV(NS(SLOT, delete)) // [DERIVE-C] for template
116#define ITEM_CLONE PRIV(NS(SLOT, clone)) // [DERIVE-C] for template
117#define ITEM_DEBUG PRIV(NS(SLOT, debug)) // [DERIVE-C] for template
118#define INTERNAL_NAME SLOT_VECTOR // [DERIVE-C] for template
120
121#pragma pop_macro("ALLOC")
122
123#if defined SMALL_BUCKETS
124 #undef SMALL_BUCKETS // [DERIVE-C] for input arg
125 #define BUCKET _dc_ankerl_small_bucket
126#else
127 #define BUCKET _dc_ankerl_bucket
128#endif
129
131
132typedef struct {
136
137 NS(ALLOC, ref) alloc_ref;
138 dc_gdb_marker derive_c_hashmap;
139 // JUSTIFY: No iteration invalidator
140 // - Iteration is dependent on the vector, which already tracks this.
141} SELF;
142
143#define INVARIANT_CHECK(self) \
144 DC_ASSUME(self); \
145 DC_ASSUME(DC_MATH_IS_POWER_OF_2((self)->buckets_capacity)); \
146 DC_ASSUME((self)->buckets);
147
149 NS(ALLOC, ref) alloc_ref) {
150 DC_ASSUME(capacity > 0);
152
153 BUCKET* buckets = (BUCKET*)NS(ALLOC, allocate_zeroed)(alloc_ref, capacity * sizeof(BUCKET));
154
155 return (SELF){
156 .buckets_capacity = capacity,
157 .buckets = buckets,
158 .slots = NS(SLOT_VECTOR, new_with_capacity)(capacity, alloc_ref),
159 .alloc_ref = alloc_ref,
160 };
161}
162
163DC_PUBLIC static SELF NS(SELF, new_with_capacity_for)(size_t for_items, NS(ALLOC, ref) alloc_ref) {
164 DC_ASSERT(for_items > 0, "Cannot create map with capacity for 0 items {for_items=%lu}",
165 for_items);
167 alloc_ref);
168}
169
170DC_PUBLIC static SELF NS(SELF, new)(NS(ALLOC, ref) alloc_ref) {
172}
173
174DC_PUBLIC static SELF NS(SELF, clone)(SELF const* self) {
175 INVARIANT_CHECK(self);
176
177 BUCKET* new_buckets = (BUCKET*)NS(ALLOC, allocate_uninit)(
178 self->alloc_ref, self->buckets_capacity * sizeof(BUCKET));
179 memcpy(new_buckets, self->buckets, self->buckets_capacity * sizeof(BUCKET));
180
181 return (SELF){
182 .buckets_capacity = self->buckets_capacity,
183 .buckets = new_buckets,
184 .slots = NS(SLOT_VECTOR, clone)(&self->slots),
185 .alloc_ref = self->alloc_ref,
186 .derive_c_hashmap = dc_gdb_marker_new(),
187 };
188}
189
191 VALUE value) {
192 INVARIANT_CHECK(self);
193 DC_DEBUG_ASSERT(NS(SLOT_VECTOR, size)(&self->slots) < self->buckets_capacity);
194 const size_t mask = self->buckets_capacity - 1;
195
196 const size_t hash = KEY_HASH(&key);
197 const uint8_t fp = _dc_ankerl_fingerprint_from_hash(hash);
198 const size_t desired = hash & mask;
199
200 {
202 for (size_t pos = desired;; pos = (pos + 1) & mask) {
203 BUCKET const* b = &self->buckets[pos];
204
205 if (!_dc_ankerl_mdata_present(&b->mdata)) {
206 break;
207 }
208
209 // JUSTIFY: Checking for the maximum DFD
210 // - dfd (distance-from-desired) uses saturating arithmetic.
211 // - Once dfd reaches dc_ankerl_dfd_max it no longer encodes a strict ordering,
212 // so the usual Robin Hood early-out (b->dfd < dfd) is only valid while dfd
213 // is not saturated. After saturation we must continue probing until EMPTY.
214 if (dfd != _dc_ankerl_dfd_max && b->mdata.dfd < dfd) {
215 break;
216 }
217
218 if (b->mdata.fingerprint == fp) {
219 const size_t di = NS(BUCKET, get_index)(b);
220 SLOT const* slot = NS(SLOT_VECTOR, read)(&self->slots, di);
221 if (KEY_EQ(&slot->key, &key)) {
222 return NULL;
223 }
224 }
225
226 dfd = _dc_ankerl_dfd_increment(dfd);
227 }
228 }
229
230 const size_t dense_index = NS(SLOT_VECTOR, size)(&self->slots);
231 NS(SLOT_VECTOR, push)(&self->slots, (SLOT){
232 .key = key,
233 .value = value,
234 });
235 BUCKET cur = NS(BUCKET, new)(
237 .fingerprint = fp,
238 .dfd = _dc_ankerl_dfd_new(0),
239 },
240 dense_index);
241
242 for (size_t pos = desired;; pos = (pos + 1) & mask) {
243 BUCKET* b = &self->buckets[pos];
244
245 if (!_dc_ankerl_mdata_present(&b->mdata)) {
246 *b = cur;
247 return &NS(SLOT_VECTOR, write)(&self->slots, dense_index)->value;
248 }
249
250 if (b->mdata.dfd < cur.mdata.dfd) {
251 BUCKET tmp = *b;
252 *b = cur;
253 cur = tmp;
254 }
255
256 cur.mdata.dfd = _dc_ankerl_dfd_increment(cur.mdata.dfd);
257 }
258}
259
260DC_INTERNAL static void PRIV(NS(SELF, rehash))(SELF* self, size_t new_capacity) {
261 INVARIANT_CHECK(self);
262 DC_ASSUME(DC_MATH_IS_POWER_OF_2(new_capacity));
263
264 BUCKET* new_buckets =
265 (BUCKET*)NS(ALLOC, allocate_zeroed)(self->alloc_ref, new_capacity * sizeof(BUCKET));
266
267 const size_t new_mask = new_capacity - 1;
268 const size_t n = NS(SLOT_VECTOR, size)(&self->slots);
269
270 for (size_t dense_index = 0; dense_index < n; ++dense_index) {
271 SLOT const* slot = NS(SLOT_VECTOR, read)(&self->slots, dense_index);
272
273 const size_t hash = KEY_HASH(&slot->key);
274 const uint8_t fp = _dc_ankerl_fingerprint_from_hash(hash);
275 const size_t desired = hash & new_mask;
276
277 BUCKET cur = NS(BUCKET, new)(
279 .fingerprint = fp,
280 .dfd = _dc_ankerl_dfd_new(0),
281 },
282 dense_index);
283
284 for (size_t pos = desired;; pos = (pos + 1) & new_mask) {
285 BUCKET* b = &new_buckets[pos];
286
287 if (!_dc_ankerl_mdata_present(&b->mdata)) {
288 *b = cur;
289 break;
290 }
291
292 if (b->mdata.dfd < cur.mdata.dfd) {
293 BUCKET tmp = *b;
294 *b = cur;
295 cur = tmp;
296 }
297
298 cur.mdata.dfd = _dc_ankerl_dfd_increment(cur.mdata.dfd);
299 }
300 }
301
302 NS(ALLOC, deallocate)(self->alloc_ref, self->buckets, self->buckets_capacity * sizeof(BUCKET));
303 self->buckets = new_buckets;
304 self->buckets_capacity = new_capacity;
305}
306
307DC_PUBLIC static void NS(SELF, extend_capacity_for)(SELF* self, size_t expected_items) {
308 INVARIANT_CHECK(self);
309
310 const size_t required = _dc_ankerl_buckets_capacity(expected_items);
311 if (required <= self->buckets_capacity) {
312 return;
313 }
314
315 PRIV(NS(SELF, rehash))(self, required);
316}
317
318DC_PUBLIC static VALUE* NS(SELF, try_insert)(SELF* self, KEY key, VALUE value) {
319 INVARIANT_CHECK(self);
320
321 if (NS(SLOT_VECTOR, size)(&self->slots) >= NS(SELF, max_capacity)) {
322 return NULL;
323 }
324
325 const size_t size = NS(SLOT_VECTOR, size)(&self->slots);
326 if (size >= self->buckets_capacity) {
327 NS(SELF, extend_capacity_for)(self, size * 2);
328 }
329
330 return PRIV(NS(SELF, try_insert_no_extend_capacity))(self, key, value);
331}
332
333DC_PUBLIC static VALUE* NS(SELF, insert)(SELF* self, KEY key, VALUE value) {
334 VALUE* value_ptr = NS(SELF, try_insert)(self, key, value);
335 DC_ASSERT(value_ptr, "Failed to insert item {key=%s, value=%s}", DC_DEBUG(KEY_DEBUG, &key),
336 DC_DEBUG(VALUE_DEBUG, &value));
337 return value_ptr;
338}
339
340DC_INTERNAL static bool PRIV(NS(SELF, try_find))(SELF const* self, KEY const* key,
341 size_t* out_bucket_pos, size_t* out_dense_index) {
342 INVARIANT_CHECK(self);
343 DC_ASSUME(key);
344 DC_ASSUME(out_bucket_pos);
345 DC_ASSUME(out_dense_index);
346
347 const size_t mask = self->buckets_capacity - 1;
348
349 const size_t hash = KEY_HASH(key);
350 const uint8_t fp = _dc_ankerl_fingerprint_from_hash(hash);
351 const size_t desired = hash & mask;
352
354 for (size_t pos = desired;; pos = (pos + 1) & mask) {
355 BUCKET const* b = &self->buckets[pos];
356
357 if (!_dc_ankerl_mdata_present(&b->mdata)) {
358 return false;
359 }
360
361 // NOTE: capped/saturating dfd: early-out only valid while dfd not saturated.
362 if (dfd != _dc_ankerl_dfd_max && b->mdata.dfd < dfd) {
363 return false;
364 }
365
366 if (b->mdata.fingerprint == fp) {
367 const size_t di = NS(BUCKET, get_index)(b);
368 SLOT const* slot = NS(SLOT_VECTOR, read)(&self->slots, di);
369 if (KEY_EQ(&slot->key, key)) {
370 *out_bucket_pos = pos;
371 *out_dense_index = di;
372 return true;
373 }
374 }
375
376 dfd = _dc_ankerl_dfd_increment(dfd);
377 }
378}
379
380DC_PUBLIC static VALUE const* NS(SELF, try_read)(SELF const* self, KEY key) {
381 INVARIANT_CHECK(self);
382 size_t pos;
383 size_t di;
384 if (!PRIV(NS(SELF, try_find))(self, &key, &pos, &di)) {
385 return NULL;
386 }
387
388 return &NS(SLOT_VECTOR, read)(&self->slots, di)->value;
389}
390
391DC_PUBLIC static VALUE const* NS(SELF, read)(SELF const* self, KEY key) {
392 VALUE const* value = NS(SELF, try_read)(self, key);
393 DC_ASSERT(value, "Cannot read item {key=%s}", DC_DEBUG(KEY_DEBUG, &key));
394 return value;
395}
396
397DC_PUBLIC static VALUE* NS(SELF, try_write)(SELF* self, KEY key) {
398 INVARIANT_CHECK(self);
399 return (VALUE*)NS(SELF, try_read)((SELF const*)self, key);
400}
401
402DC_PUBLIC static VALUE* NS(SELF, write)(SELF* self, KEY key) {
403 VALUE* value = NS(SELF, try_write)(self, key);
404 DC_ASSERT(value, "Cannot write item {key=%s}", DC_DEBUG(KEY_DEBUG, &key));
405 return value;
406}
407
408DC_PUBLIC static bool NS(SELF, try_remove)(SELF* self, KEY key, VALUE* destination) {
409 INVARIANT_CHECK(self);
410
411 size_t found_pos;
412 size_t removed_dense_index;
413 if (!PRIV(NS(SELF, try_find))((SELF const*)self, &key, &found_pos, &removed_dense_index)) {
414 return false; // unchanged
415 }
416
417 const size_t mask = self->buckets_capacity - 1;
418
419 // Move out value (or delete if destination is NULL) and delete key.
420 {
421 SLOT* slot = NS(SLOT_VECTOR, write)(&self->slots, removed_dense_index);
422
423 if (destination) {
424 *destination = slot->value;
425 } else {
426 VALUE_DELETE(&slot->value);
427 }
428
429 KEY_DELETE(&slot->key);
430 }
431
432 // Backshift delete from buckets starting at found_pos.
433 {
434 size_t hole = found_pos;
435
436 for (;;) {
437 const size_t next = (hole + 1) & mask;
438 BUCKET* nb = &self->buckets[next];
439
440 if (!_dc_ankerl_mdata_present(&nb->mdata) || nb->mdata.dfd == _dc_ankerl_dfd_new(0)) {
441 self->buckets[hole].mdata.dfd = _dc_ankerl_dfd_none;
442 break;
443 }
444
445 self->buckets[hole] = *nb;
446 self->buckets[hole].mdata.dfd =
447 _dc_ankerl_dfd_decrement_for_backshift(self->buckets[hole].mdata.dfd);
448 hole = next;
449 }
450 }
451
452 // Dense swap-remove + update moved element’s bucket (if swap occurred).
453 {
454 const size_t size = NS(SLOT_VECTOR, size)(&self->slots);
455 const size_t last = size - 1;
456
457 if (removed_dense_index != last) {
458 SLOT* dst = NS(SLOT_VECTOR, write)(&self->slots, removed_dense_index);
459 SLOT* src = NS(SLOT_VECTOR, write)(&self->slots, last);
460 *dst = *src;
461
462 // Find moved key's bucket and patch its dense index to removed_dense_index.
463 // (One extra probe only when we swapped.)
464 const size_t moved_hash = KEY_HASH(&dst->key);
465 const uint8_t moved_fp = _dc_ankerl_fingerprint_from_hash(moved_hash);
466 const size_t desired = moved_hash & mask;
467
469 for (size_t pos = desired;; pos = (pos + 1) & mask) {
470 BUCKET* b = &self->buckets[pos];
471
473
474 if (dfd != _dc_ankerl_dfd_max && b->mdata.dfd < dfd) {
476 }
477
478 if (b->mdata.fingerprint == moved_fp) {
479 const size_t di = NS(BUCKET, get_index)(b);
480 SLOT const* slot = NS(SLOT_VECTOR, read)(&self->slots, di);
481 if (KEY_EQ(&slot->key, &dst->key)) {
482 *b = NS(BUCKET, new)(b->mdata, removed_dense_index);
483 break;
484 }
485 }
486
487 dfd = _dc_ankerl_dfd_increment(dfd);
488 }
489 }
490
491 (void)NS(SLOT_VECTOR, pop)(&self->slots);
492 }
493
494 return true;
495}
496
497DC_PUBLIC static VALUE NS(SELF, remove)(SELF* self, KEY key) {
498 VALUE value;
499 DC_ASSERT(NS(SELF, try_remove)(self, key, &value), "Failed to remove entry {key=%s}",
500 DC_DEBUG(KEY_DEBUG, &key));
501 return value;
502}
503
504DC_PUBLIC static void NS(SELF, delete_entry)(SELF* self, KEY key) {
505 VALUE value = NS(SELF, remove)(self, key);
506 VALUE_DELETE(&value);
507}
508
509DC_PUBLIC static size_t NS(SELF, size)(SELF const* self) {
510 INVARIANT_CHECK(self);
511 return NS(SLOT_VECTOR, size)(&self->slots);
512}
513
514DC_PUBLIC static void NS(SELF, delete)(SELF* self) {
515 INVARIANT_CHECK(self);
516
517 NS(ALLOC, deallocate)(self->alloc_ref, self->buckets, self->buckets_capacity * sizeof(BUCKET));
518 NS(SLOT_VECTOR, delete)(&self->slots);
519}
520
521#define ITER_CONST NS(SELF, iter_const)
522#define KV_PAIR_CONST NS(ITER_CONST, item)
523
524typedef struct {
525 NS(SLOT_VECTOR, iter_const) iter;
526} ITER_CONST;
527
528typedef struct {
529 KEY const* key;
530 VALUE const* value;
532
534 return item->key == NULL && item->value == NULL;
535}
536
538 SLOT const* next_item = NS(NS(SLOT_VECTOR, iter_const), next)(&iter->iter);
539 if (!next_item) {
540 return (KV_PAIR_CONST){
541 .key = NULL,
542 .value = NULL,
543 };
544 }
545 return (KV_PAIR_CONST){
546 .key = &next_item->key,
547 .value = &next_item->value,
548 };
549}
550
551DC_PUBLIC static bool NS(ITER_CONST, empty)(ITER_CONST const* iter) {
552 DC_ASSUME(iter);
553 return NS(NS(SLOT_VECTOR, iter_const), empty)(&iter->iter);
554}
555
557 INVARIANT_CHECK(self);
558 return (ITER_CONST){
559 .iter = NS(SLOT_VECTOR, get_iter_const)(&self->slots),
560 };
561}
562
563DC_PUBLIC static void NS(SELF, debug)(SELF const* self, dc_debug_fmt fmt, FILE* stream) {
564 fprintf(stream, DC_EXPAND_STRING(SELF) "@%p {\n", (void*)self);
565 fmt = dc_debug_fmt_scope_begin(fmt);
566
567 dc_debug_fmt_print(fmt, stream, "bucket capacity: %lu,\n", self->buckets_capacity);
568
569 dc_debug_fmt_print(fmt, stream, "alloc: ");
570 NS(ALLOC, debug)(NS(NS(ALLOC, ref), deref)(self->alloc_ref), fmt, stream);
571 fprintf(stream, ",\n");
572
573 dc_debug_fmt_print(fmt, stream, "slots: ");
574 NS(SLOT_VECTOR, debug)(&self->slots, fmt, stream);
575 fprintf(stream, ",\n");
576
577 fmt = dc_debug_fmt_scope_end(fmt);
578 dc_debug_fmt_print(fmt, stream, "}");
579}
580
581#undef KV_PAIR_CONST
582#undef ITER_CONST
583
584#define ITER NS(SELF, iter)
585#define KV_PAIR NS(ITER, item)
586
587typedef struct {
589} ITER;
590
591typedef struct {
592 KEY const* key;
593 VALUE const* value;
594} KV_PAIR;
595
596DC_PUBLIC static bool NS(ITER, empty_item)(KV_PAIR const* item) {
597 return item->key == NULL && item->value == NULL;
598}
599
600DC_PUBLIC static KV_PAIR NS(ITER, next)(ITER* iter) {
601 SLOT* next_item = NS(NS(SLOT_VECTOR, iter), next)(&iter->iter);
602 if (!next_item) {
603 return (KV_PAIR){
604 .key = NULL,
605 .value = NULL,
606 };
607 }
608 return (KV_PAIR){
609 .key = &next_item->key,
610 .value = &next_item->value,
611 };
612}
613
614DC_PUBLIC static bool NS(ITER, empty)(ITER const* iter) {
615 DC_ASSUME(iter);
616 return NS(NS(SLOT_VECTOR, iter), empty)(&iter->iter);
617}
618
620 INVARIANT_CHECK(self);
621 return (ITER){
622 .iter = NS(SLOT_VECTOR, get_iter)(&self->slots),
623 };
624}
625
626#undef KV_PAIR
627#undef ITER
628
629#undef INVARIANT_CHECK
630#undef BUCKET
631#undef SLOT_VECTOR
632#undef SLOT
633
634#undef VALUE_DEBUG
635#undef VALUE_CLONE
636#undef VALUE_DELETE
637#undef VALUE
638
639#undef KEY_DEBUG
640#undef KEY_CLONE
641#undef KEY_DELETE
642#undef KEY_EQ
643#undef KEY_HASH
644#undef KEY
645
647
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 bool PRIV try_find(SELF const *self, KEY const *key, size_t *out_bucket_pos, size_t *out_dense_index)
Definition template.h:340
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 BUCKET
Definition template.h:127
#define SLOT_VECTOR
Definition template.h:109
#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
#define KEY
A simple swiss table implementation. See the abseil docs for swss table here.
Definition template.h:18
#define VALUE
Definition template.h:54
#define DC_TRAIT_MAP(SELF)
Definition trait.h:5
static DC_PUBLIC SELF new_with_capacity(size_t front_and_back_capacity, ref alloc_ref)
Definition template.h:78
static DC_PUBLIC ITEM * push(SELF *self, ITEM item)
Definition template.h:263
static DC_PUBLIC ITEM pop(SELF *self)
Definition template.h:289
#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
static DC_INTERNAL size_t _dc_ankerl_buckets_capacity(size_t for_items)
Definition utils.h:11
DC_STATIC_CONSTANT size_t max_index_exclusive
Definition utils.h:61
static const size_t dc_ankerl_initial_items
Definition utils.h:9
static DC_INTERNAL _dc_ankerl_dfd _dc_ankerl_dfd_decrement_for_backshift(_dc_ankerl_dfd dfd)
Definition utils.h:32
static DC_INTERNAL uint8_t _dc_ankerl_fingerprint_from_hash(size_t hash)
Definition utils.h:18
static const _dc_ankerl_dfd _dc_ankerl_dfd_max
Definition utils.h:26
uint8_t _dc_ankerl_dfd
Definition utils.h:24
static const _dc_ankerl_dfd _dc_ankerl_dfd_none
Definition utils.h:25
static DC_INTERNAL bool _dc_ankerl_mdata_present(_dc_ankerl_mdata const *bucket)
Definition utils.h:49
static DC_INTERNAL size_t get_index(_dc_ankerl_small_bucket const *bucket)
Definition utils.h:73
static DC_INTERNAL _dc_ankerl_dfd _dc_ankerl_dfd_new(uint8_t distance)
Definition utils.h:40
static DC_INTERNAL _dc_ankerl_dfd _dc_ankerl_dfd_increment(_dc_ankerl_dfd dfd)
Definition utils.h:28
#define DC_MATH_IS_POWER_OF_2(x)
Definition math.h:14
#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_INTERNAL
Definition namespace.h:30
#define DC_DEBUG_ASSERT
Definition panic.h:78
#define DC_UNREACHABLE(...)
Definition panic.h:44
#define DC_ASSERT(expr,...)
Definition panic.h:37
#define DC_ASSUME(expr,...)
Definition panic.h:57
iter_const iter
Definition template.h:525
iter iter
Definition template.h:588
VALUE const * value
Definition template.h:530
KEY const * key
Definition template.h:529
KEY const * key
Definition template.h:592
VALUE const * value
Definition template.h:593
SLOT * slots
Definition template.h:71
size_t buckets_capacity
Definition template.h:133
dc_gdb_marker derive_c_hashmap
Definition template.h:138
BUCKET * buckets
Definition template.h:134
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
static DC_PUBLIC FILE * stream(SELF *self)
Definition template.h:108