Derive-C
Loading...
Searching...
No Matches
template.h File Reference

Go to the source code of this file.

Data Structures

struct  value_t
struct  SLOT
struct  SELF
 An allocator that prints to stdout when it allocates or frees memory. More...
struct  ITER_CONST
struct  KV_PAIR_CONST
struct  ITER
struct  KV_PAIR

Macros

#define KEY   map_key_t
 A simple swiss table implementation. See the abseil docs for swss table here.
#define KEY_HASH   key_hash
#define KEY_EQ   DC_MEM_EQ
#define KEY_DELETE   DC_NO_DELETE
#define KEY_CLONE   DC_COPY_CLONE
#define KEY_DEBUG   DC_DEFAULT_DEBUG
#define VALUE   value_t
#define VALUE_DELETE   DC_NO_DELETE
#define VALUE_CLONE   DC_COPY_CLONE
#define VALUE_DEBUG   DC_DEFAULT_DEBUG
#define SLOT   NS(NAME, slot_t)
#define SLOT_VECTOR   NS(NAME, item_vectors)
#define ITEM   SLOT
#define ITEM_DELETE   PRIV(NS(SLOT, delete))
#define ITEM_CLONE   PRIV(NS(SLOT, clone))
#define ITEM_DEBUG   PRIV(NS(SLOT, debug))
#define INTERNAL_NAME   SLOT_VECTOR
#define BUCKET   _dc_ankerl_bucket
#define INVARIANT_CHECK(self)
#define ITER_CONST   NS(SELF, iter_const)
#define KV_PAIR_CONST   NS(ITER_CONST, item)
#define ITER   NS(SELF, iter)
#define KV_PAIR   NS(ITER, item)

Typedefs

typedef size_t KEY
typedef KEY key_t

Functions

static size_t KEY_HASH (KEY const *key)
static DC_INTERNAL SLOT PRIV clone (SLOT const *slot)
static DC_INTERNAL void PRIV debug (SLOT const *slot, dc_debug_fmt fmt, FILE *stream)
static DC_INTERNAL void PRIV delete (SLOT *slot)
static DC_INTERNAL SELF PRIV new_with_exact_capacity (size_t capacity, ref alloc_ref)
static DC_PUBLIC SELF new_with_capacity_for (size_t for_items, ref alloc_ref)
static DC_PUBLIC SELF new (ref alloc_ref)
static DC_PUBLIC SELF clone (SELF const *self)
static DC_INTERNAL VALUE *PRIV try_insert_no_extend_capacity (SELF *self, KEY key, VALUE value)
static DC_INTERNAL void PRIV rehash (SELF *self, size_t new_capacity)
static DC_PUBLIC void extend_capacity_for (SELF *self, size_t expected_items)
static DC_PUBLIC VALUEtry_insert (SELF *self, KEY key, VALUE value)
static DC_PUBLIC VALUEinsert (SELF *self, KEY key, VALUE value)
static DC_INTERNAL bool PRIV try_find (SELF const *self, KEY const *key, size_t *out_bucket_pos, size_t *out_dense_index)
static DC_PUBLIC VALUE const * try_read (SELF const *self, KEY key)
static DC_PUBLIC VALUE const * read (SELF const *self, KEY key)
static DC_PUBLIC VALUEtry_write (SELF *self, KEY key)
static DC_PUBLIC VALUEwrite (SELF *self, KEY key)
static DC_PUBLIC bool try_remove (SELF *self, KEY key, VALUE *destination)
static DC_PUBLIC VALUE remove (SELF *self, KEY key)
static DC_PUBLIC void delete_entry (SELF *self, KEY key)
static DC_PUBLIC size_t size (SELF const *self)
static DC_PUBLIC void delete (SELF *self)
static DC_PUBLIC bool empty_item (KV_PAIR_CONST const *item)
static DC_PUBLIC KV_PAIR_CONST next (ITER_CONST *iter)
static DC_PUBLIC bool empty (ITER_CONST const *iter)
static DC_PUBLIC ITER_CONST get_iter_const (SELF const *self)
static DC_PUBLIC void debug (SELF const *self, dc_debug_fmt fmt, FILE *stream)
static DC_PUBLIC bool empty_item (KV_PAIR const *item)
static DC_PUBLIC KV_PAIR next (ITER *iter)
static DC_PUBLIC bool empty (ITER const *iter)
static DC_PUBLIC ITER get_iter (SELF *self)
 DC_TRAIT_MAP (SELF)

Variables

DC_STATIC_CONSTANT size_t max_capacity = max_index_exclusive

Macro Definition Documentation

◆ BUCKET

#define BUCKET   _dc_ankerl_bucket

Definition at line 127 of file template.h.

◆ INTERNAL_NAME

#define INTERNAL_NAME   SLOT_VECTOR

Definition at line 118 of file template.h.

◆ INVARIANT_CHECK

#define INVARIANT_CHECK ( self)
Value:
DC_ASSUME(self); \
DC_ASSUME(DC_MATH_IS_POWER_OF_2((self)->buckets_capacity)); \
DC_ASSUME((self)->buckets);
#define DC_MATH_IS_POWER_OF_2(x)
Definition math.h:14
#define DC_ASSUME(expr,...)
Definition panic.h:57

Definition at line 143 of file template.h.

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);

◆ ITEM

#define ITEM   SLOT

Definition at line 114 of file template.h.

◆ ITEM_CLONE

#define ITEM_CLONE   PRIV(NS(SLOT, clone))

Definition at line 116 of file template.h.

◆ ITEM_DEBUG

#define ITEM_DEBUG   PRIV(NS(SLOT, debug))

Definition at line 117 of file template.h.

◆ ITEM_DELETE

#define ITEM_DELETE   PRIV(NS(SLOT, delete))

Definition at line 115 of file template.h.

◆ ITER

#define ITER   NS(SELF, iter)

Definition at line 584 of file template.h.

◆ ITER_CONST

#define ITER_CONST   NS(SELF, iter_const)

Definition at line 521 of file template.h.

◆ KEY

#define KEY   map_key_t

A simple swiss table implementation. See the abseil docs for swss table here.

Definition at line 17 of file template.h.

◆ KEY_CLONE

#define KEY_CLONE   DC_COPY_CLONE

Definition at line 39 of file template.h.

◆ KEY_DEBUG

#define KEY_DEBUG   DC_DEFAULT_DEBUG

Definition at line 43 of file template.h.

◆ KEY_DELETE

#define KEY_DELETE   DC_NO_DELETE

Definition at line 35 of file template.h.

◆ KEY_EQ

#define KEY_EQ   DC_MEM_EQ

Definition at line 31 of file template.h.

◆ KEY_HASH

#define KEY_HASH   key_hash

Definition at line 26 of file template.h.

◆ KV_PAIR

#define KV_PAIR   NS(ITER, item)

Definition at line 585 of file template.h.

◆ KV_PAIR_CONST

#define KV_PAIR_CONST   NS(ITER_CONST, item)

Definition at line 522 of file template.h.

◆ SLOT

#define SLOT   NS(NAME, slot_t)

Definition at line 75 of file template.h.

◆ SLOT_VECTOR

#define SLOT_VECTOR   NS(NAME, item_vectors)

Definition at line 109 of file template.h.

◆ VALUE

#define VALUE   value_t

Definition at line 53 of file template.h.

◆ VALUE_CLONE

#define VALUE_CLONE   DC_COPY_CLONE

Definition at line 61 of file template.h.

◆ VALUE_DEBUG

#define VALUE_DEBUG   DC_DEFAULT_DEBUG

Definition at line 65 of file template.h.

◆ VALUE_DELETE

#define VALUE_DELETE   DC_NO_DELETE

Definition at line 57 of file template.h.

Typedef Documentation

◆ KEY

typedef size_t KEY

Definition at line 18 of file template.h.

◆ key_t

typedef KEY key_t

Definition at line 68 of file template.h.

Function Documentation

◆ clone() [1/2]

DC_PUBLIC SELF clone ( SELF const * self)
static

Definition at line 174 of file template.h.

174 {
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}
static DC_PUBLIC void * allocate_uninit(SELF *self, size_t size)
Definition template.h:92
#define ALLOC
Definition template.h:31
#define INVARIANT_CHECK(self)
Definition template.h:90
static DC_PUBLIC SELF clone(SELF const *self)
Definition template.h:215
#define BUCKET
Definition template.h:127
#define SLOT_VECTOR
Definition template.h:109
#define SELF
Definition def.h:52
static DC_PUBLIC dc_gdb_marker dc_gdb_marker_new()
Definition gdb_marker.h:8
#define NS(pre, post)
Definition namespace.h:14

◆ clone() [2/2]

DC_INTERNAL SLOT PRIV clone ( SLOT const * slot)
static

Definition at line 81 of file template.h.

81 {
82 return (SLOT){
83 .key = KEY_CLONE(&slot->key),
84 .value = VALUE_CLONE(&slot->value),
85 };
86}
#define SLOT
Definition template.h:65
#define VALUE_CLONE
Definition template.h:39
#define KEY_CLONE
Definition template.h:39

◆ DC_TRAIT_MAP()

DC_TRAIT_MAP ( SELF )

◆ debug() [1/2]

DC_PUBLIC void debug ( SELF const * self,
dc_debug_fmt fmt,
FILE * stream )
static

Definition at line 563 of file template.h.

563 {
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}
static DC_PUBLIC void debug(SELF const *self, dc_debug_fmt fmt, FILE *stream)
Definition template.h:212
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
#define DC_EXPAND_STRING(NAME)
Definition namespace.h:6
static DC_PUBLIC FILE * stream(SELF *self)
Definition template.h:108

◆ debug() [2/2]

DC_INTERNAL void PRIV debug ( SLOT const * slot,
dc_debug_fmt fmt,
FILE * stream )
static

Definition at line 88 of file template.h.

88 {
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}
#define VALUE_DEBUG
Definition template.h:41
#define KEY_DEBUG
Definition template.h:43

◆ delete() [1/2]

DC_PUBLIC void delete ( SELF * self)
static

Definition at line 514 of file template.h.

514 {
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}
static DC_PUBLIC void deallocate(SELF *self, void *ptr, size_t size)
Definition template.h:127
SLOT * slots
Definition template.h:71
size_t buckets_capacity
Definition template.h:133
BUCKET * buckets
Definition template.h:134
ref alloc_ref
Definition template.h:49

◆ delete() [2/2]

DC_INTERNAL void PRIV delete ( SLOT * slot)
static

Definition at line 104 of file template.h.

104 {
105 KEY_DELETE(&slot->key);
106 VALUE_DELETE(&slot->value);
107}
#define VALUE_DELETE
Definition template.h:37
#define KEY_DELETE
Definition template.h:35
VALUE value
Definition template.h:78
KEY key
Definition template.h:77

◆ delete_entry()

DC_PUBLIC void delete_entry ( SELF * self,
KEY key )
static

Definition at line 504 of file template.h.

504 {
505 VALUE value = NS(SELF, remove)(self, key);
506 VALUE_DELETE(&value);
507}
#define VALUE
Definition template.h:35
static DC_PUBLIC VALUE remove(SELF *self, INDEX index)
Definition template.h:292

◆ empty() [1/2]

DC_PUBLIC bool empty ( ITER const * iter)
static

Definition at line 614 of file template.h.

614 {
615 DC_ASSUME(iter);
616 return NS(NS(SLOT_VECTOR, iter), empty)(&iter->iter);
617}
static DC_PUBLIC bool empty(ITER const *iter)
Definition template.h:349

◆ empty() [2/2]

DC_PUBLIC bool empty ( ITER_CONST const * iter)
static

Definition at line 551 of file template.h.

551 {
552 DC_ASSUME(iter);
553 return NS(NS(SLOT_VECTOR, iter_const), empty)(&iter->iter);
554}

◆ empty_item() [1/2]

DC_PUBLIC bool empty_item ( KV_PAIR const * item)
static

Definition at line 596 of file template.h.

596 {
597 return item->key == NULL && item->value == NULL;
598}
IV_PAIR item
Definition template.h:281

◆ empty_item() [2/2]

DC_PUBLIC bool empty_item ( KV_PAIR_CONST const * item)
static

Definition at line 533 of file template.h.

533 {
534 return item->key == NULL && item->value == NULL;
535}

◆ extend_capacity_for()

DC_PUBLIC void extend_capacity_for ( SELF * self,
size_t expected_items )
static

Definition at line 307 of file template.h.

307 {
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}
static DC_INTERNAL void PRIV rehash(SELF *self, size_t new_capacity)
Definition template.h:260
static DC_INTERNAL size_t _dc_ankerl_buckets_capacity(size_t for_items)
Definition utils.h:11
#define PRIV(name)
Definition namespace.h:20

◆ get_iter()

DC_PUBLIC ITER get_iter ( SELF * self)
static

Definition at line 619 of file template.h.

619 {
620 INVARIANT_CHECK(self);
621 return (ITER){
622 .iter = NS(SLOT_VECTOR, get_iter)(&self->slots),
623 };
624}
#define ITER
Definition template.h:322
static DC_PUBLIC ITER get_iter(SELF *self)
Definition template.h:373

◆ get_iter_const()

DC_PUBLIC ITER_CONST get_iter_const ( SELF const * self)
static

Definition at line 556 of file template.h.

556 {
557 INVARIANT_CHECK(self);
558 return (ITER_CONST){
559 .iter = NS(SLOT_VECTOR, get_iter_const)(&self->slots),
560 };
561}
#define ITER_CONST
Definition template.h:411
static DC_PUBLIC ITER_CONST get_iter_const(SELF const *self)
Definition template.h:464

◆ insert()

DC_PUBLIC VALUE * insert ( SELF * self,
KEY key,
VALUE value )
static

Definition at line 333 of file template.h.

333 {
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}
#define KEY_DEBUG
Definition template.h:34
static DC_PUBLIC VALUE * try_insert(SELF *self, KEY key, VALUE value)
Definition template.h:318
#define DC_DEBUG(DEBUG_FN, DEBUG_PTR)
Definition dump.h:92
#define DC_ASSERT(expr,...)
Definition panic.h:37

◆ KEY_HASH()

size_t KEY_HASH ( KEY const * key)
static

Definition at line 27 of file template.h.

27{ return *key; }

◆ new()

DC_PUBLIC SELF new ( ref alloc_ref)
static

Definition at line 170 of file template.h.

170 {
172}
static DC_INTERNAL SELF PRIV new_with_exact_capacity(size_t capacity, ref alloc_ref)
Definition template.h:148
static const size_t dc_ankerl_initial_items
Definition utils.h:9

◆ new_with_capacity_for()

DC_PUBLIC SELF new_with_capacity_for ( size_t for_items,
ref alloc_ref )
static

Definition at line 163 of file template.h.

163 {
164 DC_ASSERT(for_items > 0, "Cannot create map with capacity for 0 items {for_items=%lu}",
165 for_items);
167 alloc_ref);
168}

◆ new_with_exact_capacity()

DC_INTERNAL SELF PRIV new_with_exact_capacity ( size_t capacity,
ref alloc_ref )
static

Definition at line 148 of file template.h.

149 {
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}
static DC_PUBLIC void * allocate_zeroed(SELF *self, size_t size)
Definition template.h:117
static DC_PUBLIC SELF new_with_capacity(size_t front_and_back_capacity, ref alloc_ref)
Definition template.h:78

◆ next() [1/2]

DC_PUBLIC KV_PAIR next ( ITER * iter)
static

Definition at line 600 of file template.h.

600 {
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}
static DC_PUBLIC IV_PAIR next(ITER *iter)
Definition template.h:355
#define KV_PAIR
Definition template.h:585
iter iter
Definition template.h:588

◆ next() [2/2]

DC_PUBLIC KV_PAIR_CONST next ( ITER_CONST * iter)
static

Definition at line 537 of file template.h.

537 {
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}
#define KV_PAIR_CONST
Definition template.h:522
iter_const iter
Definition template.h:525

◆ read()

DC_PUBLIC VALUE const * read ( SELF const * self,
KEY key )
static

Definition at line 391 of file template.h.

391 {
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}
static DC_PUBLIC VALUE const * try_read(SELF const *self, INDEX index)
Definition template.h:180

◆ rehash()

DC_INTERNAL void PRIV rehash ( SELF * self,
size_t new_capacity )
static

Definition at line 260 of file template.h.

260 {
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}
static DC_PUBLIC VALUE const * read(SELF const *self, INDEX index)
Definition template.h:199
static DC_PUBLIC size_t size(SELF const *self)
Definition template.h:252
#define KEY_HASH
Definition template.h:26
static DC_INTERNAL uint8_t _dc_ankerl_fingerprint_from_hash(size_t hash)
Definition utils.h:18
static DC_INTERNAL bool _dc_ankerl_mdata_present(_dc_ankerl_mdata const *bucket)
Definition utils.h:49
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

◆ remove()

DC_PUBLIC VALUE remove ( SELF * self,
KEY key )
static

Definition at line 497 of file template.h.

497 {
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}
static DC_PUBLIC bool try_remove(SELF *self, INDEX index, VALUE *destination)
Definition template.h:264

◆ size()

DC_PUBLIC size_t size ( SELF const * self)
static

Definition at line 509 of file template.h.

509 {
510 INVARIANT_CHECK(self);
511 return NS(SLOT_VECTOR, size)(&self->slots);
512}

◆ try_find()

DC_INTERNAL bool PRIV try_find ( SELF const * self,
KEY const * key,
size_t * out_bucket_pos,
size_t * out_dense_index )
static

Definition at line 340 of file template.h.

341 {
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}
#define KEY_EQ
Definition template.h:31
static const _dc_ankerl_dfd _dc_ankerl_dfd_max
Definition utils.h:26
uint8_t _dc_ankerl_dfd
Definition utils.h:24
static DC_INTERNAL size_t get_index(_dc_ankerl_small_bucket const *bucket)
Definition utils.h:73

◆ try_insert()

DC_PUBLIC VALUE * try_insert ( SELF * self,
KEY key,
VALUE value )
static

Definition at line 318 of file template.h.

318 {
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}
static DC_PUBLIC void extend_capacity_for(SELF *self, size_t expected_items)
Definition template.h:307
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

◆ try_insert_no_extend_capacity()

DC_INTERNAL VALUE *PRIV try_insert_no_extend_capacity ( SELF * self,
KEY key,
VALUE value )
static

Definition at line 190 of file template.h.

191 {
192 INVARIANT_CHECK(self);
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}
static DC_PUBLIC VALUE * write(SELF *self, INDEX index)
Definition template.h:209
static DC_PUBLIC ITEM * push(SELF *self, ITEM item)
Definition template.h:263
#define DC_DEBUG_ASSERT
Definition panic.h:78

◆ try_read()

DC_PUBLIC VALUE const * try_read ( SELF const * self,
KEY key )
static

Definition at line 380 of file template.h.

380 {
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}
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

◆ try_remove()

DC_PUBLIC bool try_remove ( SELF * self,
KEY key,
VALUE * destination )
static

Definition at line 408 of file template.h.

408 {
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}
static DC_PUBLIC ITEM pop(SELF *self)
Definition template.h:289
static DC_INTERNAL _dc_ankerl_dfd _dc_ankerl_dfd_decrement_for_backshift(_dc_ankerl_dfd dfd)
Definition utils.h:32
static const _dc_ankerl_dfd _dc_ankerl_dfd_none
Definition utils.h:25
#define DC_UNREACHABLE(...)
Definition panic.h:44

◆ try_write()

DC_PUBLIC VALUE * try_write ( SELF * self,
KEY key )
static

Definition at line 397 of file template.h.

397 {
398 INVARIANT_CHECK(self);
399 return (VALUE*)NS(SELF, try_read)((SELF const*)self, key);
400}

◆ write()

DC_PUBLIC VALUE * write ( SELF * self,
KEY key )
static

Definition at line 402 of file template.h.

402 {
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}
static DC_PUBLIC VALUE * try_write(SELF *self, INDEX index)
Definition template.h:205

Variable Documentation

◆ max_capacity

DC_STATIC_CONSTANT size_t max_capacity = max_index_exclusive

Definition at line 130 of file template.h.