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 PLACEHOLDERS
15TEMPLATE_ERROR("No KEY")
16 #endif
17 #define KEY map_key_t
18typedef int KEY;
19#endif
20
21#if !defined KEY_HASH
22 #if !defined PLACEHOLDERS
23TEMPLATE_ERROR("No KEY_HASH")
24 #endif
25
26 #define KEY_HASH key_hash
27static size_t KEY_HASH(KEY const* 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 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
81static SLOT NS(SLOT, clone)(SLOT const* slot) {
82 return (SLOT){
83 .key = KEY_CLONE(&slot->key),
84 .value = VALUE_CLONE(&slot->value),
85 };
86}
87
88static void NS(SLOT, debug)(SLOT const* slot, dc_debug_fmt fmt, FILE* stream) {
89 fprintf(stream, 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
104static void 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_CLONE NS(SLOT, clone) // [DERIVE-C] for template
116#define ITEM_DEBUG NS(SLOT, debug) // [DERIVE-C] for template
117#define ITEM_CLONE NS(SLOT, clone) // [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 #define INDEX_KIND dc_ankerl_index_small
125 #define BUCKET_SIZE 4
126 #undef SMALL_BUCKETS // [DERIVE-C] for input arg
127#else
128 #define INDEX_KIND dc_ankerl_index_large
129 #define BUCKET_SIZE 8
130#endif
131
132#define BUCKET NS(SELF, bucket)
137
139
140typedef struct {
144
145 ALLOC* alloc;
146 dc_gdb_marker derive_c_hashmap;
147 // JUSTIFY: No iteration invalidator
148 // - Iteration is dependent on the vector, which already tracks this.
149} SELF;
150
151#define INVARIANT_CHECK(self) \
152 DC_ASSUME(self); \
153 DC_ASSUME(DC_MATH_IS_POWER_OF_2((self)->buckets_capacity)); \
154 DC_ASSUME((self)->buckets); \
155 DC_ASSUME((self)->alloc);
156
158 DC_ASSUME(capacity > 0);
160
161 BUCKET* buckets = (BUCKET*)NS(ALLOC, calloc)(alloc, capacity, sizeof(BUCKET));
162 DC_ASSERT(buckets);
163
164 return (SELF){
165 .buckets_capacity = capacity,
166 .buckets = buckets,
167 .slots = NS(SLOT_VECTOR, new_with_capacity)(capacity, alloc),
168 .alloc = alloc,
169 };
170}
171
172static SELF NS(SELF, new_with_capacity_for)(size_t for_items, ALLOC* alloc) {
173 DC_ASSERT(for_items > 0);
175}
176
177static SELF NS(SELF, new)(ALLOC* alloc) {
179}
180
181static SELF NS(SELF, clone)(SELF const* self) {
182 INVARIANT_CHECK(self);
183
184 BUCKET* new_buckets =
185 (BUCKET*)NS(ALLOC, malloc)(self->alloc, self->buckets_capacity * sizeof(BUCKET));
186 DC_ASSERT(new_buckets);
187 memcpy(new_buckets, self->buckets, self->buckets_capacity * sizeof(BUCKET));
188
189 return (SELF){
190 .buckets_capacity = self->buckets_capacity,
191 .buckets = new_buckets,
192 .slots = NS(SLOT_VECTOR, clone)(&self->slots),
193 .alloc = self->alloc,
194 .derive_c_hashmap = dc_gdb_marker_new(),
195 };
196}
197
199 INVARIANT_CHECK(self);
200 DC_ASSUME(NS(SLOT_VECTOR, size)(&self->slots) < self->buckets_capacity);
201 const size_t mask = self->buckets_capacity - 1;
202
203 const size_t hash = KEY_HASH(&key);
204 const uint8_t fp = dc_ankerl_fingerprint_from_hash(hash);
205 const size_t desired = hash & mask;
206
207 {
209 for (size_t pos = desired;; pos = (pos + 1) & mask) {
210 BUCKET const* b = &self->buckets[pos];
211
212 if (!dc_ankerl_mdata_present(&b->mdata)) {
213 break;
214 }
215
216 // JUSTIFY: Checking for the maximum DFD
217 // - dfd (distance-from-desired) uses saturating arithmetic.
218 // - Once dfd reaches dc_ankerl_dfd_max it no longer encodes a strict ordering,
219 // so the usual Robin Hood early-out (b->dfd < dfd) is only valid while dfd
220 // is not saturated. After saturation we must continue probing until EMPTY.
221 if (dfd != dc_ankerl_dfd_max && b->mdata.dfd < dfd) {
222 break;
223 }
224
225 if (b->mdata.fingerprint == fp) {
226 const size_t di = NS(INDEX_KIND, get)(&b->index);
227 SLOT const* slot = NS(SLOT_VECTOR, read)(&self->slots, di);
228 if (KEY_EQ(&slot->key, &key)) {
229 return NULL;
230 }
231 }
232
233 dfd = dc_ankerl_dfd_increment(dfd);
234 }
235 }
236
237 const size_t dense_index = NS(SLOT_VECTOR, size)(&self->slots);
238 NS(SLOT_VECTOR, push)(&self->slots, (SLOT){
239 .key = key,
240 .value = value,
241 });
242
243 BUCKET cur = {
244 .mdata =
245 {
246 .fingerprint = fp,
247 .dfd = dc_ankerl_dfd_new(0),
248 },
249 .index = NS(INDEX_KIND, new)(dense_index),
250 };
251
252 for (size_t pos = desired;; pos = (pos + 1) & mask) {
253 BUCKET* b = &self->buckets[pos];
254
255 if (!dc_ankerl_mdata_present(&b->mdata)) {
256 *b = cur;
257 return &NS(SLOT_VECTOR, write)(&self->slots, dense_index)->value;
258 }
259
260 if (b->mdata.dfd < cur.mdata.dfd) {
261 BUCKET tmp = *b;
262 *b = cur;
263 cur = tmp;
264 }
265
266 cur.mdata.dfd = dc_ankerl_dfd_increment(cur.mdata.dfd);
267 }
268}
269
270static void PRIV(NS(SELF, rehash))(SELF* self, size_t new_capacity) {
271 INVARIANT_CHECK(self);
272 DC_ASSUME(DC_MATH_IS_POWER_OF_2(new_capacity));
273
274 BUCKET* new_buckets = (BUCKET*)NS(ALLOC, calloc)(self->alloc, new_capacity, sizeof(BUCKET));
275 DC_ASSERT(new_buckets);
276
277 const size_t new_mask = new_capacity - 1;
278 const size_t n = NS(SLOT_VECTOR, size)(&self->slots);
279
280 for (size_t dense_index = 0; dense_index < n; ++dense_index) {
281 SLOT const* slot = NS(SLOT_VECTOR, read)(&self->slots, dense_index);
282
283 const size_t hash = KEY_HASH(&slot->key);
284 const uint8_t fp = dc_ankerl_fingerprint_from_hash(hash);
285 const size_t desired = hash & new_mask;
286
287 BUCKET cur = {.mdata =
288 {
289 .fingerprint = fp,
290 .dfd = dc_ankerl_dfd_new(0),
291 },
292 .index = NS(INDEX_KIND, new)(dense_index)};
293
294 for (size_t pos = desired;; pos = (pos + 1) & new_mask) {
295 BUCKET* b = &new_buckets[pos];
296
297 if (!dc_ankerl_mdata_present(&b->mdata)) {
298 *b = cur;
299 break;
300 }
301
302 if (b->mdata.dfd < cur.mdata.dfd) {
303 BUCKET tmp = *b;
304 *b = cur;
305 cur = tmp;
306 }
307
308 cur.mdata.dfd = dc_ankerl_dfd_increment(cur.mdata.dfd);
309 }
310 }
311
312 NS(ALLOC, free)(self->alloc, self->buckets);
313 self->buckets = new_buckets;
314 self->buckets_capacity = new_capacity;
315}
316
317static void NS(SELF, extend_capacity_for)(SELF* self, size_t expected_items) {
318 INVARIANT_CHECK(self);
319
320 const size_t required = dc_ankerl_buckets_capacity(expected_items);
321 if (required <= self->buckets_capacity) {
322 return;
323 }
324
325 PRIV(NS(SELF, rehash))(self, required);
326}
327
328static VALUE* NS(SELF, try_insert)(SELF* self, KEY key, VALUE value) {
329 INVARIANT_CHECK(self);
330
331 const size_t size = NS(SLOT_VECTOR, size)(&self->slots);
332 if (size >= self->buckets_capacity) {
333 NS(SELF, extend_capacity_for)(self, size * 2);
334 }
335
336 return PRIV(NS(SELF, try_insert_no_extend_capacity))(self, key, value);
337}
338
339static VALUE* NS(SELF, insert)(SELF* self, KEY key, VALUE value) {
340 VALUE* value_ptr = NS(SELF, try_insert)(self, key, value);
341 DC_ASSERT(value_ptr);
342 return value_ptr;
343}
344
345static bool PRIV(NS(SELF, try_find))(SELF const* self, KEY const* key, size_t* out_bucket_pos,
346 size_t* out_dense_index) {
347 INVARIANT_CHECK(self);
348 DC_ASSUME(key);
349 DC_ASSUME(out_bucket_pos);
350 DC_ASSUME(out_dense_index);
351
352 const size_t mask = self->buckets_capacity - 1;
353
354 const size_t hash = KEY_HASH(key);
355 const uint8_t fp = dc_ankerl_fingerprint_from_hash(hash);
356 const size_t desired = hash & mask;
357
359 for (size_t pos = desired;; pos = (pos + 1) & mask) {
360 BUCKET const* b = &self->buckets[pos];
361
362 if (!dc_ankerl_mdata_present(&b->mdata)) {
363 return false;
364 }
365
366 // NOTE: capped/saturating dfd: early-out only valid while dfd not saturated.
367 if (dfd != dc_ankerl_dfd_max && b->mdata.dfd < dfd) {
368 return false;
369 }
370
371 if (b->mdata.fingerprint == fp) {
372 const size_t di = NS(INDEX_KIND, get)(&b->index);
373 SLOT const* slot = NS(SLOT_VECTOR, read)(&self->slots, di);
374 if (KEY_EQ(&slot->key, key)) {
375 *out_bucket_pos = pos;
376 *out_dense_index = di;
377 return true;
378 }
379 }
380
381 dfd = dc_ankerl_dfd_increment(dfd);
382 }
383}
384
385static VALUE const* NS(SELF, try_read)(SELF const* self, KEY key) {
386 INVARIANT_CHECK(self);
387 size_t pos;
388 size_t di;
389 if (!PRIV(NS(SELF, try_find))(self, &key, &pos, &di)) {
390 return NULL;
391 }
392
393 return &NS(SLOT_VECTOR, read)(&self->slots, di)->value;
394}
395
396static VALUE const* NS(SELF, read)(SELF const* self, KEY key) {
397 VALUE const* value = NS(SELF, try_read)(self, key);
398 DC_ASSERT(value);
399 return value;
400}
401
402static VALUE* NS(SELF, try_write)(SELF* self, KEY key) {
403 INVARIANT_CHECK(self);
404 return (VALUE*)NS(SELF, try_read)((SELF const*)self, key);
405}
406
407static VALUE* NS(SELF, write)(SELF* self, KEY key) {
408 VALUE* value = NS(SELF, try_write)(self, key);
409 DC_ASSERT(value);
410 return value;
411}
412
413static bool NS(SELF, try_remove)(SELF* self, KEY key, VALUE* destination) {
414 INVARIANT_CHECK(self);
415
416 size_t found_pos;
417 size_t removed_dense_index;
418 if (!PRIV(NS(SELF, try_find))((SELF const*)self, &key, &found_pos, &removed_dense_index)) {
419 return false; // unchanged
420 }
421
422 const size_t mask = self->buckets_capacity - 1;
423
424 // Move out value (or delete if destination is NULL) and delete key.
425 {
426 SLOT* slot = NS(SLOT_VECTOR, write)(&self->slots, removed_dense_index);
427
428 if (destination) {
429 *destination = slot->value;
430 } else {
431 VALUE_DELETE(&slot->value);
432 }
433
434 KEY_DELETE(&slot->key);
435 }
436
437 // Backshift delete from buckets starting at found_pos.
438 {
439 size_t hole = found_pos;
440
441 for (;;) {
442 const size_t next = (hole + 1) & mask;
443 BUCKET* nb = &self->buckets[next];
444
445 if (!dc_ankerl_mdata_present(&nb->mdata) || nb->mdata.dfd == dc_ankerl_dfd_new(0)) {
446 self->buckets[hole].mdata.dfd = dc_ankerl_dfd_none;
447 break;
448 }
449
450 self->buckets[hole] = *nb;
451 self->buckets[hole].mdata.dfd =
452 dc_ankerl_dfd_decrement_for_backshift(self->buckets[hole].mdata.dfd);
453 hole = next;
454 }
455 }
456
457 // Dense swap-remove + update moved element’s bucket (if swap occurred).
458 {
459 const size_t size = NS(SLOT_VECTOR, size)(&self->slots);
460 const size_t last = size - 1;
461
462 if (removed_dense_index != last) {
463 SLOT* dst = NS(SLOT_VECTOR, write)(&self->slots, removed_dense_index);
464 SLOT* src = NS(SLOT_VECTOR, write)(&self->slots, last);
465 *dst = *src;
466
467 // Find moved key's bucket and patch its dense index to removed_dense_index.
468 // (One extra probe only when we swapped.)
469 const size_t moved_hash = KEY_HASH(&dst->key);
470 const uint8_t moved_fp = dc_ankerl_fingerprint_from_hash(moved_hash);
471 const size_t desired = moved_hash & mask;
472
474 for (size_t pos = desired;; pos = (pos + 1) & mask) {
475 BUCKET* b = &self->buckets[pos];
476
478
479 if (dfd != dc_ankerl_dfd_max && b->mdata.dfd < dfd) {
480 DC_ASSERT(false);
481 }
482
483 if (b->mdata.fingerprint == moved_fp) {
484 const size_t di = NS(INDEX_KIND, get)(&b->index);
485 SLOT const* slot = NS(SLOT_VECTOR, read)(&self->slots, di);
486 if (KEY_EQ(&slot->key, &dst->key)) {
487 b->index = NS(INDEX_KIND, new)(removed_dense_index);
488 break;
489 }
490 }
491
492 dfd = dc_ankerl_dfd_increment(dfd);
493 }
494 }
495
496 (void)NS(SLOT_VECTOR, pop)(&self->slots);
497 }
498
499 return true;
500}
501
502static VALUE NS(SELF, remove)(SELF* self, KEY key) {
503 VALUE value;
504 DC_ASSERT(NS(SELF, try_remove)(self, key, &value));
505 return value;
506}
507
508static void NS(SELF, delete_entry)(SELF* self, KEY key) {
509 VALUE value = NS(SELF, remove)(self, key);
510 VALUE_DELETE(&value);
511}
512
513static size_t NS(SELF, size)(SELF const* self) {
514 INVARIANT_CHECK(self);
515 return NS(SLOT_VECTOR, size)(&self->slots);
516}
517
518static void NS(SELF, delete)(SELF* self) {
519 INVARIANT_CHECK(self);
520
521 NS(ALLOC, free)(self->alloc, self->buckets);
522 NS(SLOT_VECTOR, delete)(&self->slots);
523}
524
525#define ITER_CONST NS(SELF, iter_const)
526#define KV_PAIR_CONST NS(ITER_CONST, item)
527
528typedef struct {
529 NS(SLOT_VECTOR, iter_const) iter;
530} ITER_CONST;
531
532typedef struct {
533 KEY const* key;
534 VALUE const* value;
536
538 return item->key == NULL && item->value == NULL;
539}
540
542 SLOT const* next_item = NS(NS(SLOT_VECTOR, iter_const), next)(&iter->iter);
543 if (!next_item) {
544 return (KV_PAIR_CONST){
545 .key = NULL,
546 .value = NULL,
547 };
548 }
549 return (KV_PAIR_CONST){
550 .key = &next_item->key,
551 .value = &next_item->value,
552 };
553}
554
555static ITER_CONST NS(SELF, get_iter_const)(SELF const* self) {
556 INVARIANT_CHECK(self);
557 return (ITER_CONST){
558 .iter = NS(SLOT_VECTOR, get_iter_const)(&self->slots),
559 };
560}
561
562static void NS(SELF, debug)(SELF const* self, dc_debug_fmt fmt, FILE* stream) {
563 fprintf(stream, EXPAND_STRING(SELF) "@%p {\n", self);
564 fmt = dc_debug_fmt_scope_begin(fmt);
565
566 dc_debug_fmt_print(fmt, stream, "bucket capacity: %lu,\n", self->buckets_capacity);
567
568 dc_debug_fmt_print(fmt, stream, "alloc: ");
569 NS(ALLOC, debug)(self->alloc, fmt, stream);
570 fprintf(stream, ",\n");
571
572 dc_debug_fmt_print(fmt, stream, "slots: ");
573 NS(SLOT_VECTOR, debug)(&self->slots, fmt, stream);
574 fprintf(stream, ",\n");
575
576 fmt = dc_debug_fmt_scope_end(fmt);
577 dc_debug_fmt_print(fmt, stream, "}");
578}
579
580#undef KV_PAIR_CONST
581#undef ITER_CONST
582
583#define ITER NS(SELF, iter)
584#define KV_PAIR NS(ITER, item)
585
586typedef struct {
588} ITER;
589
590typedef struct {
591 KEY const* key;
592 VALUE const* value;
593} KV_PAIR;
594
595static bool NS(ITER, empty_item)(KV_PAIR const* item) {
596 return item->key == NULL && item->value == NULL;
597}
598
599static KV_PAIR NS(ITER, next)(ITER* iter) {
600 SLOT* next_item = NS(NS(SLOT_VECTOR, iter), next)(&iter->iter);
601 if (!next_item) {
602 return (KV_PAIR){
603 .key = NULL,
604 .value = NULL,
605 };
606 }
607 return (KV_PAIR){
608 .key = &next_item->key,
609 .value = &next_item->value,
610 };
611}
612
613static ITER NS(SELF, get_iter)(SELF* self) {
614 INVARIANT_CHECK(self);
615 return (ITER){
616 .iter = NS(SLOT_VECTOR, get_iter)(&self->slots),
617 };
618}
619
620#undef KV_PAIR
621#undef ITER
622
623#undef INVARIANT_CHECK
624#undef BUCKET
625#undef BUCKET_SIZE
626#undef INDEX_KIND
627#undef SLOT_VECTOR
628#undef SLOT
629
630#undef VALUE_DEBUG
631#undef VALUE_CLONE
632#undef VALUE_DELETE
633#undef VALUE
634
635#undef KEY_DEBUG
636#undef KEY_CLONE
637#undef KEY_DELETE
638#undef KEY_EQ
639#undef KEY_HASH
640#undef KEY
641
643
static void debug(SELF const *self, dc_debug_fmt fmt, FILE *stream)
Definition template.h:62
static void free(SELF *self, void *ptr)
Definition template.h:56
static void * malloc(SELF *self, size_t size)
Definition template.h:23
static void * calloc(SELF *self, size_t count, size_t size)
Definition template.h:34
#define ALLOC
Definition template.h:64
static INDEX insert(SELF *self, VALUE value)
Definition template.h:127
static ITER_CONST get_iter_const(SELF const *self)
Definition template.h:449
static ITER get_iter(SELF *self)
Definition template.h:370
#define VALUE_DEBUG
Definition template.h:39
static IV_PAIR next(ITER *iter)
Definition template.h:352
static INDEX_TYPE size(SELF const *self)
Definition template.h:252
#define SLOT
Definition template.h:63
#define INVARIANT_CHECK(self)
Definition template.h:88
static VALUE remove(SELF *self, INDEX index)
Definition template.h:292
static bool empty_item(IV_PAIR const *item)
Definition template.h:344
SLOT PRIV(block)[DC_ARENA_CHUNKED_BLOCK_SIZE(BLOCK_INDEX_BITS)]
Definition template.h:73
static VALUE * try_write(SELF *self, INDEX index)
Definition template.h:205
ALLOC alloc_t
Definition template.h:61
static VALUE const * read(SELF const *self, INDEX index)
Definition template.h:199
static VALUE * write(SELF *self, INDEX index)
Definition template.h:209
#define VALUE
Definition template.h:31
#define ITER
Definition template.h:320
#define VALUE_CLONE
Definition template.h:37
#define VALUE_DELETE
Definition template.h:35
static bool try_remove(SELF *self, INDEX index, VALUE *destination)
Definition template.h:264
#define ITER_CONST
Definition template.h:398
static SELF clone(SELF const *self)
Definition template.h:215
static VALUE const * try_read(SELF const *self, INDEX index)
Definition template.h:180
IV_PAIR item
Definition template.h:283
static SELF new_with_capacity_for(INDEX_TYPE items, ALLOC *alloc)
Definition template.h:96
#define KEY_HASH
Definition template.h:26
#define KV_PAIR
Definition template.h:584
#define KEY_DELETE
Definition template.h:35
#define BUCKET_SIZE
Definition template.h:129
static VALUE *PRIV try_insert_no_extend_capacity(SELF *self, KEY key, VALUE value)
Definition template.h:198
#define KEY_CLONE
Definition template.h:39
static VALUE * try_insert(SELF *self, KEY key, VALUE value)
Definition template.h:328
#define KEY
A simple swiss table implementation. See the abseil docs for swss table here.
Definition template.h:17
#define BUCKET
Definition template.h:132
#define SLOT_VECTOR
Definition template.h:109
#define KEY_EQ
Definition template.h:31
#define KEY_DEBUG
Definition template.h:43
static void delete_entry(SELF *self, KEY key)
Definition template.h:508
static SELF PRIV new_with_exact_capacity(size_t capacity, ALLOC *alloc)
Definition template.h:157
static void extend_capacity_for(SELF *self, size_t expected_items)
Definition template.h:317
KEY key_t
Definition template.h:68
#define KV_PAIR_CONST
Definition template.h:526
static bool PRIV try_find(SELF const *self, KEY const *key, size_t *out_bucket_pos, size_t *out_dense_index)
Definition template.h:345
static void PRIV rehash(SELF *self, size_t new_capacity)
Definition template.h:270
#define INDEX_KIND
Definition template.h:128
static size_t capacity()
Definition template.h:66
#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 SELF new_with_capacity(size_t front_and_back_capacity, ALLOC *alloc)
Definition template.h:78
static ITEM * push(SELF *self, ITEM item)
Definition template.h:216
static ITEM pop(SELF *self)
Definition template.h:266
dc_debug_fmt dc_debug_fmt_scope_end(dc_debug_fmt fmt)
Definition fmt.h:39
dc_debug_fmt dc_debug_fmt_scope_begin(dc_debug_fmt fmt)
Definition fmt.h:33
static void dc_debug_fmt_print(dc_debug_fmt fmt, FILE *stream, const char *format,...)
Definition fmt.h:22
static dc_gdb_marker dc_gdb_marker_new()
Definition gdb_marker.h:7
static uint8_t dc_ankerl_fingerprint_from_hash(size_t hash)
Definition utils.h:17
static const size_t dc_ankerl_initial_items
Definition utils.h:8
uint8_t dc_ankerl_dfd
Definition utils.h:23
static bool dc_ankerl_mdata_present(dc_ankerl_mdata const *bucket)
Definition utils.h:46
static dc_ankerl_dfd dc_ankerl_dfd_new(uint8_t distance)
Definition utils.h:39
static const dc_ankerl_dfd dc_ankerl_dfd_none
Definition utils.h:24
static dc_ankerl_dfd dc_ankerl_dfd_decrement_for_backshift(dc_ankerl_dfd dfd)
Definition utils.h:31
static const dc_ankerl_dfd dc_ankerl_dfd_max
Definition utils.h:25
static dc_ankerl_dfd dc_ankerl_dfd_increment(dc_ankerl_dfd dfd)
Definition utils.h:27
static size_t dc_ankerl_buckets_capacity(size_t for_items)
Definition utils.h:10
#define DC_MATH_IS_POWER_OF_2(x)
Definition math.h:12
#define EXPAND_STRING(NAME)
Definition namespace.h:8
#define NS(pre, post)
Definition namespace.h:4
static nullalloc get()
Definition null.h:14
#define DC_ASSERT(expr,...)
Definition panic.h:36
#define DC_STATIC_ASSERT
Definition panic.h:21
#define DC_ASSUME(expr,...)
Definition panic.h:56
#define TEMPLATE_ERROR(...)
With the user provided name, even in nested templates.
Definition def.h:56
#define SELF
Definition def.h:52
iter_const iter
Definition template.h:529
iter iter
Definition template.h:587
VALUE const * value
Definition template.h:534
KEY const * key
Definition template.h:533
KEY const * key
Definition template.h:591
VALUE const * value
Definition template.h:592
SLOT * slots
Definition template.h:71
size_t buckets_capacity
Definition template.h:141
dc_gdb_marker derive_c_hashmap
Definition template.h:146
BUCKET * buckets
Definition template.h:142
ALLOC * alloc
Definition template.h:71
VALUE value
Definition template.h:78
KEY key
Definition template.h:77
dc_ankerl_mdata mdata
Definition template.h:134
INDEX_KIND index
Definition template.h:135
Debug format helpers for debug printin data structures.
Definition fmt.h:10
static FILE * stream(SELF *self)
Opens a file for.
Definition template.h:107