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  __attribute__
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_CLONE   NS(SLOT, clone)
#define ITEM_DEBUG   NS(SLOT, debug)
#define ITEM_CLONE   NS(SLOT, clone)
#define INTERNAL_NAME   SLOT_VECTOR
#define INDEX_KIND   dc_ankerl_index_large
#define BUCKET_SIZE   8
#define BUCKET   NS(SELF, 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 int KEY
typedef KEY key_t

Functions

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

Macro Definition Documentation

◆ BUCKET

#define BUCKET   NS(SELF, bucket)

Definition at line 132 of file template.h.

◆ BUCKET_SIZE

#define BUCKET_SIZE   8

Definition at line 129 of file template.h.

◆ INDEX_KIND

#define INDEX_KIND   dc_ankerl_index_large

Definition at line 128 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); \
DC_ASSUME((self)->alloc);
#define DC_MATH_IS_POWER_OF_2(x)
Definition math.h:12
#define DC_ASSUME(expr,...)
Definition panic.h:56

Definition at line 151 of file template.h.

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

◆ ITEM

#define ITEM   SLOT

Definition at line 114 of file template.h.

◆ ITEM_CLONE [1/2]

#define ITEM_CLONE   NS(SLOT, clone)

Definition at line 115 of file template.h.

◆ ITEM_CLONE [2/2]

#define ITEM_CLONE   NS(SLOT, clone)

Definition at line 115 of file template.h.

◆ ITEM_DEBUG

#define ITEM_DEBUG   NS(SLOT, debug)

Definition at line 116 of file template.h.

◆ ITER

#define ITER   NS(SELF, iter)

Definition at line 583 of file template.h.

◆ ITER_CONST

#define ITER_CONST   NS(SELF, iter_const)

Definition at line 525 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 584 of file template.h.

◆ KV_PAIR_CONST

#define KV_PAIR_CONST   NS(ITER_CONST, item)

Definition at line 526 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 int 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]

SELF clone ( SELF const * self)
static

Definition at line 181 of file template.h.

181 {
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}
static void * malloc(SELF *self, size_t size)
Definition template.h:23
#define ALLOC
Definition template.h:64
#define INVARIANT_CHECK(self)
Definition template.h:88
static SELF clone(SELF const *self)
Definition template.h:215
#define BUCKET
Definition template.h:132
#define SLOT_VECTOR
Definition template.h:109
static dc_gdb_marker dc_gdb_marker_new()
Definition gdb_marker.h:7
#define NS(pre, post)
Definition namespace.h:4
#define DC_ASSERT(expr,...)
Definition panic.h:36
#define SELF
Definition def.h:52

◆ clone() [2/2]

SLOT 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:63
#define VALUE_CLONE
Definition template.h:37
#define KEY_CLONE
Definition template.h:39

◆ DC_STATIC_ASSERT()

DC_STATIC_ASSERT ( sizeof(BUCKET) = =BUCKET_SIZE)

◆ DC_TRAIT_MAP()

DC_TRAIT_MAP ( SELF )

◆ debug() [1/2]

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

Definition at line 562 of file template.h.

562 {
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}
static void debug(SELF const *self, dc_debug_fmt fmt, FILE *stream)
Definition template.h:62
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
#define EXPAND_STRING(NAME)
Definition namespace.h:8
static FILE * stream(SELF *self)
Opens a file for.
Definition template.h:107

◆ debug() [2/2]

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

Definition at line 88 of file template.h.

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

◆ delete() [1/2]

void delete ( SELF * self)
static

Definition at line 518 of file template.h.

518 {
519 INVARIANT_CHECK(self);
520
521 NS(ALLOC, free)(self->alloc, self->buckets);
522 NS(SLOT_VECTOR, delete)(&self->slots);
523}
static void free(SELF *self, void *ptr)
Definition template.h:56
SLOT * slots
Definition template.h:71
BUCKET * buckets
Definition template.h:142
ALLOC * alloc
Definition template.h:71

◆ delete() [2/2]

void 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:35
#define KEY_DELETE
Definition template.h:35
VALUE value
Definition template.h:78
KEY key
Definition template.h:77

◆ delete_entry()

void delete_entry ( SELF * self,
KEY key )
static

Definition at line 508 of file template.h.

508 {
509 VALUE value = NS(SELF, remove)(self, key);
510 VALUE_DELETE(&value);
511}
static VALUE remove(SELF *self, INDEX index)
Definition template.h:292
#define VALUE
Definition template.h:31

◆ empty_item() [1/2]

bool empty_item ( KV_PAIR const * item)
static

Definition at line 595 of file template.h.

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

◆ empty_item() [2/2]

bool empty_item ( KV_PAIR_CONST const * item)
static

Definition at line 537 of file template.h.

537 {
538 return item->key == NULL && item->value == NULL;
539}

◆ extend_capacity_for()

void extend_capacity_for ( SELF * self,
size_t expected_items )
static

Definition at line 317 of file template.h.

317 {
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}
SLOT PRIV(block)[DC_ARENA_CHUNKED_BLOCK_SIZE(BLOCK_INDEX_BITS)]
Definition template.h:73
static void PRIV rehash(SELF *self, size_t new_capacity)
Definition template.h:270
static size_t dc_ankerl_buckets_capacity(size_t for_items)
Definition utils.h:10

◆ get_iter()

ITER get_iter ( SELF * self)
static

Definition at line 613 of file template.h.

613 {
614 INVARIANT_CHECK(self);
615 return (ITER){
616 .iter = NS(SLOT_VECTOR, get_iter)(&self->slots),
617 };
618}
static ITER get_iter(SELF *self)
Definition template.h:370
#define ITER
Definition template.h:320

◆ get_iter_const()

ITER_CONST get_iter_const ( SELF const * self)
static

Definition at line 555 of file template.h.

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

◆ insert()

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

Definition at line 339 of file template.h.

339 {
340 VALUE* value_ptr = NS(SELF, try_insert)(self, key, value);
341 DC_ASSERT(value_ptr);
342 return value_ptr;
343}
static VALUE * try_insert(SELF *self, KEY key, VALUE value)
Definition template.h:328

◆ KEY_HASH()

size_t KEY_HASH ( KEY const * key)
static

◆ new()

SELF new ( ALLOC * alloc)
static

Definition at line 177 of file template.h.

177 {
179}
static SELF PRIV new_with_exact_capacity(size_t capacity, ALLOC *alloc)
Definition template.h:157
static const size_t dc_ankerl_initial_items
Definition utils.h:8

◆ new_with_capacity_for()

SELF new_with_capacity_for ( size_t for_items,
ALLOC * alloc )
static

Definition at line 172 of file template.h.

172 {
173 DC_ASSERT(for_items > 0);
175}

◆ new_with_exact_capacity()

SELF PRIV new_with_exact_capacity ( size_t capacity,
ALLOC * alloc )
static

Definition at line 157 of file template.h.

157 {
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}
static void * calloc(SELF *self, size_t count, size_t size)
Definition template.h:34
static size_t capacity()
Definition template.h:66
static SELF new_with_capacity(size_t front_and_back_capacity, ALLOC *alloc)
Definition template.h:78

◆ next() [1/2]

KV_PAIR next ( ITER * iter)
static

Definition at line 599 of file template.h.

599 {
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}
static IV_PAIR next(ITER *iter)
Definition template.h:352
#define KV_PAIR
Definition template.h:584
iter iter
Definition template.h:587

◆ next() [2/2]

KV_PAIR_CONST next ( ITER_CONST * iter)
static

Definition at line 541 of file template.h.

541 {
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}
#define KV_PAIR_CONST
Definition template.h:526
iter_const iter
Definition template.h:529

◆ read()

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

Definition at line 396 of file template.h.

396 {
397 VALUE const* value = NS(SELF, try_read)(self, key);
398 DC_ASSERT(value);
399 return value;
400}
static VALUE const * try_read(SELF const *self, INDEX index)
Definition template.h:180

◆ rehash()

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

Definition at line 270 of file template.h.

270 {
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}
static INDEX_TYPE size(SELF const *self)
Definition template.h:252
static VALUE const * read(SELF const *self, INDEX index)
Definition template.h:199
#define KEY_HASH
Definition template.h:26
#define INDEX_KIND
Definition template.h:128
static uint8_t dc_ankerl_fingerprint_from_hash(size_t hash)
Definition utils.h:17
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 dc_ankerl_dfd dc_ankerl_dfd_increment(dc_ankerl_dfd dfd)
Definition utils.h:27
size_t buckets_capacity
Definition template.h:141

◆ remove()

VALUE remove ( SELF * self,
KEY key )
static

Definition at line 502 of file template.h.

502 {
503 VALUE value;
504 DC_ASSERT(NS(SELF, try_remove)(self, key, &value));
505 return value;
506}
static bool try_remove(SELF *self, INDEX index, VALUE *destination)
Definition template.h:264

◆ size()

size_t size ( SELF const * self)
static

Definition at line 513 of file template.h.

513 {
514 INVARIANT_CHECK(self);
515 return NS(SLOT_VECTOR, size)(&self->slots);
516}

◆ try_find()

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

Definition at line 345 of file template.h.

346 {
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}
#define KEY_EQ
Definition template.h:31
uint8_t dc_ankerl_dfd
Definition utils.h:23
static const dc_ankerl_dfd dc_ankerl_dfd_max
Definition utils.h:25
static nullalloc get()
Definition null.h:14

◆ try_insert()

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

Definition at line 328 of file template.h.

328 {
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}
static VALUE *PRIV try_insert_no_extend_capacity(SELF *self, KEY key, VALUE value)
Definition template.h:198
static void extend_capacity_for(SELF *self, size_t expected_items)
Definition template.h:317

◆ try_insert_no_extend_capacity()

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

Definition at line 198 of file template.h.

198 {
199 INVARIANT_CHECK(self);
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}
static VALUE * write(SELF *self, INDEX index)
Definition template.h:209
static ITEM * push(SELF *self, ITEM item)
Definition template.h:216

◆ try_read()

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

Definition at line 385 of file template.h.

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

◆ try_remove()

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

Definition at line 413 of file template.h.

413 {
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}
static ITEM pop(SELF *self)
Definition template.h:266
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

◆ try_write()

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

Definition at line 402 of file template.h.

402 {
403 INVARIANT_CHECK(self);
404 return (VALUE*)NS(SELF, try_read)((SELF const*)self, key);
405}

◆ write()

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

Definition at line 407 of file template.h.

407 {
408 VALUE* value = NS(SELF, try_write)(self, key);
409 DC_ASSERT(value);
410 return value;
411}
static VALUE * try_write(SELF *self, INDEX index)
Definition template.h:205