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

Go to the source code of this file.

Data Structures

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

Macros

#define KEY   map_key_t
 A simple open-addressed hashmap using robin-hood hashing.
#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 KEY_ENTRY   NS(SELF, key_entry)
#define INVARIANT_CHECK(self)
#define KV_PAIR   NS(SELF, kv)
#define ITER   NS(SELF, iter)
#define KV_PAIR_CONST   NS(SELF, kv_const)
#define ITER_CONST   NS(SELF, iter_const)

Typedefs

typedef KV_PAIR item

Functions

static size_t KEY_HASH (KEY const *key)
static DC_PUBLIC SELF new_with_capacity_for (size_t capacity, ref alloc_ref)
static DC_PUBLIC SELF new (ref alloc_ref)
static DC_PUBLIC SELF clone (SELF const *self)
static VALUE *PRIV try_insert_no_extend_capacity (SELF *self, KEY key, VALUE value)
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_PUBLIC VALUEtry_write (SELF *self, KEY key)
static DC_PUBLIC VALUEwrite (SELF *self, KEY key)
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 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 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)
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)
 DC_TRAIT_MAP (SELF)

Variables

DC_STATIC_CONSTANT size_t max_capacity = SIZE_MAX

Macro Definition Documentation

◆ INVARIANT_CHECK

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

Definition at line 87 of file template.h.

87#define INVARIANT_CHECK(self) \
88 DC_ASSUME(self); \
89 DC_ASSUME(DC_MATH_IS_POWER_OF_2((self)->capacity)); \
90 DC_ASSUME((self)->keys); \
91 DC_ASSUME((self)->values);

◆ ITER

#define ITER   NS(SELF, iter)

Definition at line 403 of file template.h.

◆ ITER_CONST

#define ITER_CONST   NS(SELF, iter_const)

Definition at line 476 of file template.h.

◆ KEY

#define KEY   map_key_t

A simple open-addressed hashmap using robin-hood hashing.

Definition at line 15 of file template.h.

◆ KEY_CLONE

#define KEY_CLONE   DC_COPY_CLONE

Definition at line 37 of file template.h.

◆ KEY_DEBUG

#define KEY_DEBUG   DC_DEFAULT_DEBUG

Definition at line 41 of file template.h.

◆ KEY_DELETE

#define KEY_DELETE   DC_NO_DELETE

Definition at line 33 of file template.h.

◆ KEY_ENTRY

#define KEY_ENTRY   NS(SELF, key_entry)

Definition at line 70 of file template.h.

◆ KEY_EQ

#define KEY_EQ   DC_MEM_EQ

Definition at line 29 of file template.h.

◆ KEY_HASH

#define KEY_HASH   key_hash

Definition at line 24 of file template.h.

◆ KV_PAIR

#define KV_PAIR   NS(SELF, kv)

Definition at line 396 of file template.h.

◆ KV_PAIR_CONST

#define KV_PAIR_CONST   NS(SELF, kv_const)

Definition at line 469 of file template.h.

◆ VALUE

#define VALUE   value_t

Definition at line 51 of file template.h.

◆ VALUE_CLONE

#define VALUE_CLONE   DC_COPY_CLONE

Definition at line 59 of file template.h.

◆ VALUE_DEBUG

#define VALUE_DEBUG   DC_DEFAULT_DEBUG

Definition at line 63 of file template.h.

◆ VALUE_DELETE

#define VALUE_DELETE   DC_NO_DELETE

Definition at line 55 of file template.h.

Typedef Documentation

◆ item

Definition at line 404 of file template.h.

Function Documentation

◆ clone()

DC_PUBLIC SELF clone ( SELF const * self)
static

Definition at line 130 of file template.h.

130 {
131 INVARIANT_CHECK(self);
132
133 // JUSTIFY: Naive copy
134 // - We could resize (potentially a smaller map) and rehash
135 // - Not confident it would be any better than just a copy.
136 // JUSTIFY: Individually copy keys
137 // - Many entries are zeroed, no need to copy uninit data
138
139 KEY_ENTRY* keys =
140 (KEY_ENTRY*)NS(ALLOC, allocate_zeroed)(self->alloc_ref, sizeof(KEY_ENTRY) * self->capacity);
141 VALUE* values =
142 (VALUE*)NS(ALLOC, allocate_uninit)(self->alloc_ref, sizeof(VALUE) * self->capacity);
143
144 for (size_t i = 0; i < self->capacity; i++) {
145 if (self->keys[i].present) {
146 KEY_ENTRY const* old_entry = &self->keys[i];
147 keys[i] = (KEY_ENTRY){
148 .present = true,
149 .distance_from_desired = old_entry->distance_from_desired,
150 .key = KEY_CLONE(&old_entry->key),
151 };
152 values[i] = VALUE_CLONE(&self->values[i]);
153 } else {
155 &values[i], sizeof(VALUE));
156 }
157 }
158
159 return (SELF){
160 .capacity = self->capacity,
161 .items = self->items,
162 .keys = keys,
163 .values = values,
164 .alloc_ref = self->alloc_ref,
165 .derive_c_hashmap = dc_gdb_marker_new(),
166 .iterator_invalidation_tracker = mutation_tracker_new(),
167 };
168}
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 VALUE
Definition template.h:35
#define INVARIANT_CHECK(self)
Definition template.h:90
#define VALUE_CLONE
Definition template.h:39
#define KEY_CLONE
Definition template.h:39
#define KEY_ENTRY
Definition template.h:70
#define SELF
Definition def.h:52
static DC_PUBLIC dc_gdb_marker dc_gdb_marker_new()
Definition gdb_marker.h:8
static DC_PUBLIC void dc_memory_tracker_set(dc_memory_tracker_level level, dc_memory_tracker_capability cap, const volatile void *addr, size_t size)
@ DC_MEMORY_TRACKER_LVL_CONTAINER
@ DC_MEMORY_TRACKER_CAP_NONE
static DC_PUBLIC mutation_tracker mutation_tracker_new()
#define NS(pre, post)
Definition namespace.h:14
KEY key
Definition template.h:74
uint16_t distance_from_desired
Definition template.h:73

◆ DC_TRAIT_MAP()

DC_TRAIT_MAP ( SELF )

◆ debug()

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

Definition at line 525 of file template.h.

525 {
526 fprintf(stream, DC_EXPAND_STRING(SELF) "@%p {\n", (void*)self);
527 fmt = dc_debug_fmt_scope_begin(fmt);
528
529 dc_debug_fmt_print(fmt, stream, "capacity: %zu,\n", self->capacity);
530 dc_debug_fmt_print(fmt, stream, "size: %zu,\n", NS(SELF, size)(self));
531
532 dc_debug_fmt_print(fmt, stream, "keys: @%p,\n", (void*)self->keys);
533 dc_debug_fmt_print(fmt, stream, "values: @%p,\n", (void*)self->values);
534
535 dc_debug_fmt_print(fmt, stream, "alloc: ");
536 NS(ALLOC, debug)(NS(NS(ALLOC, ref), deref)(self->alloc_ref), fmt, stream);
537 fprintf(stream, ",\n");
538
539 dc_debug_fmt_print(fmt, stream, "items: [\n");
540 fmt = dc_debug_fmt_scope_begin(fmt);
541
542 ITER_CONST iter = NS(SELF, get_iter_const)(self);
544 item = NS(ITER_CONST, next)(&iter)) {
545 dc_debug_fmt_print(fmt, stream, "{\n");
546 fmt = dc_debug_fmt_scope_begin(fmt);
547
548 dc_debug_fmt_print(fmt, stream, "key: ");
549 KEY_DEBUG(item.key, fmt, stream);
550 fprintf(stream, ",\n");
551
552 dc_debug_fmt_print(fmt, stream, "value: ");
553 VALUE_DEBUG(item.value, fmt, stream);
554 fprintf(stream, ",\n");
555
556 fmt = dc_debug_fmt_scope_end(fmt);
557 dc_debug_fmt_print(fmt, stream, "},\n");
558 }
559
560 fmt = dc_debug_fmt_scope_end(fmt);
561 dc_debug_fmt_print(fmt, stream, "],\n");
562 fmt = dc_debug_fmt_scope_end(fmt);
563 dc_debug_fmt_print(fmt, stream, "}");
564}
static DC_PUBLIC void debug(SELF const *self, dc_debug_fmt fmt, FILE *stream)
Definition template.h:212
#define VALUE_DEBUG
Definition template.h:41
static DC_PUBLIC IV_PAIR next(ITER *iter)
Definition template.h:355
static DC_PUBLIC bool empty_item(IV_PAIR const *item)
Definition template.h:347
#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
IV_PAIR item
Definition template.h:281
#define KEY_DEBUG
Definition template.h:43
#define KV_PAIR_CONST
Definition template.h:522
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

◆ delete()

DC_PUBLIC void delete ( SELF * self)
static

Definition at line 452 of file template.h.

452 {
453 DC_ASSUME(self);
454
455 for (size_t i = 0; i < self->capacity; i++) {
456 if (self->keys[i].present) {
457 KEY_DELETE(&self->keys[i].key);
458 VALUE_DELETE(&self->values[i]);
459 }
460 }
461
462 NS(ALLOC, deallocate)(self->alloc_ref, (void*)self->keys, self->capacity * sizeof(KEY_ENTRY));
463 NS(ALLOC, deallocate)(self->alloc_ref, (void*)self->values, self->capacity * sizeof(VALUE));
464}
static DC_PUBLIC void deallocate(SELF *self, void *ptr, size_t size)
Definition template.h:127
#define VALUE_DELETE
Definition template.h:37
#define KEY_DELETE
Definition template.h:35
bool present
Definition template.h:72
size_t capacity
Definition template.h:72
VALUE * values
Definition template.h:81
ref alloc_ref
Definition template.h:49
KEY_ENTRY * keys
Definition template.h:80

◆ delete_entry()

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

Definition at line 386 of file template.h.

386 {
387 VALUE value = NS(SELF, remove)(self, key);
388 VALUE_DELETE(&value);
389}
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 432 of file template.h.

432 {
433 DC_ASSUME(iter);
434 mutation_version_check(&iter->version);
435 return iter->index >= iter->map->capacity;
436}
static DC_PUBLIC void mutation_version_check(mutation_version const *self)

◆ empty() [2/2]

DC_PUBLIC bool empty ( ITER_CONST const * iter)
static

Definition at line 505 of file template.h.

505 {
506 DC_ASSUME(iter);
507 mutation_version_check(&iter->version);
508 return iter->index >= iter->map->capacity;
509}

◆ empty_item() [1/2]

DC_PUBLIC bool empty_item ( KV_PAIR const * item)
static

Definition at line 406 of file template.h.

406 {
407 return item->key == NULL && item->value == NULL;
408}

◆ empty_item() [2/2]

DC_PUBLIC bool empty_item ( KV_PAIR_CONST const * item)
static

Definition at line 479 of file template.h.

479 {
480 return item->key == NULL && item->value == NULL;
481}

◆ extend_capacity_for()

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

Definition at line 226 of file template.h.

226 {
227 INVARIANT_CHECK(self);
228
230 size_t const target_capacity = dc_apply_capacity_policy(expected_items);
231 if (target_capacity > self->capacity) {
232 SELF new_map = NS(SELF, new_with_capacity_for)(expected_items, self->alloc_ref);
233 for (size_t index = 0; index < self->capacity; index++) {
234 KEY_ENTRY* entry = &self->keys[index];
235 if (entry->present) {
236 PRIV(NS(SELF, try_insert_no_extend_capacity))(&new_map, entry->key,
237 self->values[index]);
238 }
239 }
240 NS(ALLOC, deallocate)(self->alloc_ref, (void*)self->keys,
241 self->capacity * sizeof(KEY_ENTRY));
242 NS(ALLOC, deallocate)(self->alloc_ref, (void*)self->values, self->capacity * sizeof(VALUE));
243
244 INVARIANT_CHECK(&new_map);
245 *self = new_map;
246 }
247}
static DC_PUBLIC SELF new_with_capacity_for(INDEX_TYPE items, ref alloc_ref)
Definition template.h:96
static DC_INTERNAL VALUE *PRIV try_insert_no_extend_capacity(SELF *self, KEY key, VALUE value)
Definition template.h:190
static size_t dc_apply_capacity_policy(size_t capacity)
Definition utils.h:7
static DC_PUBLIC void mutation_tracker_mutate(mutation_tracker *self)
#define PRIV(name)
Definition namespace.h:20
mutation_tracker iterator_invalidation_tracker
Definition template.h:87

◆ get_iter()

DC_PUBLIC ITER get_iter ( SELF * self)
static

Definition at line 438 of file template.h.

438 {
439 DC_ASSUME(self);
440 size_t first_index = 0;
441 while (first_index < self->capacity && !self->keys[first_index].present) {
442 first_index++;
443 }
444 return (ITER){
445 .map = self,
446 .index = first_index,
447 .curr = (KV_PAIR){.key = NULL, .value = NULL},
449 };
450}
#define ITER
Definition template.h:322
#define KV_PAIR
Definition template.h:585
static DC_PUBLIC mutation_version mutation_tracker_get(mutation_tracker const *self)

◆ get_iter_const()

DC_PUBLIC ITER_CONST get_iter_const ( SELF const * self)
static

Definition at line 511 of file template.h.

511 {
512 DC_ASSUME(self);
513 size_t first_index = 0;
514 while (first_index < self->capacity && !self->keys[first_index].present) {
515 first_index++;
516 }
517 return (ITER_CONST){
518 .map = self,
519 .index = first_index,
520 .curr = (KV_PAIR_CONST){.key = NULL, .value = NULL},
521 .version = mutation_tracker_get(&self->iterator_invalidation_tracker),
522 };
523}

◆ insert()

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

Definition at line 264 of file template.h.

264 {
265 VALUE* value_ptr = NS(SELF, try_insert)(self, key, value);
266 DC_ASSERT(value_ptr, "Failed to insert item {key=%s, value=%s}", DC_DEBUG(KEY_DEBUG, &key),
267 DC_DEBUG(VALUE_DEBUG, &value));
268 return value_ptr;
269}
#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 25 of file template.h.

25{ return *key; }

◆ new()

DC_PUBLIC SELF new ( ref alloc_ref)
static

Definition at line 126 of file template.h.

126 {
128}
static size_t const DC_INITIAL_CAPACITY
Definition utils.h:12

◆ new_with_capacity_for()

DC_PUBLIC SELF new_with_capacity_for ( size_t capacity,
ref alloc_ref )
static

Definition at line 95 of file template.h.

95 {
96 DC_ASSERT(capacity > 0, "Cannot create map with capacity for 0 items {capacity=%lu}", capacity);
97 size_t const real_capacity = dc_apply_capacity_policy(capacity);
98 DC_ASSUME(real_capacity > 0);
99
100 // JUSTIFY: calloc of keys
101 // - A cheap way to get all precense flags as zeroed (os & allocater supported get zeroed page)
102 // - for the values, we do not need this (no precense checks are done on values)
103 KEY_ENTRY* keys =
104 (KEY_ENTRY*)NS(ALLOC, allocate_zeroed)(alloc_ref, sizeof(KEY_ENTRY) * real_capacity);
105 VALUE* values = (VALUE*)NS(ALLOC, allocate_uninit)(alloc_ref, sizeof(VALUE) * real_capacity);
106
107 // JUSTIFY: no access for values & but keys are fine
108 // - Keys are calloced/zeroed as we use this for item lookup, therefore it is valid to read
109 // them.
110 // - Values are only accessed when the corresponding key is present, so we can mark them as
111 // deleted.
113 sizeof(VALUE) * real_capacity);
114
115 return (SELF){
116 .capacity = real_capacity,
117 .items = 0,
118 .keys = keys,
119 .values = values,
120 .alloc_ref = alloc_ref,
121 .derive_c_hashmap = dc_gdb_marker_new(),
122 .iterator_invalidation_tracker = mutation_tracker_new(),
123 };
124}

◆ next() [1/2]

DC_PUBLIC KV_PAIR next ( ITER * iter)
static

Definition at line 417 of file template.h.

417 {
418 DC_ASSUME(iter);
420 if (iter->index < iter->map->capacity) {
421 iter->curr = (KV_PAIR){.key = &iter->map->keys[iter->index].key,
422 .value = &iter->map->values[iter->index]};
423 iter->index++;
424 while (iter->index < iter->map->capacity && !iter->map->keys[iter->index].present) {
425 iter->index++;
426 }
427 return iter->curr;
428 }
429 return (KV_PAIR){.key = NULL, .value = NULL};
430}
mutation_version version
Definition template.h:328
SELF * map
Definition template.h:411
KV_PAIR curr
Definition template.h:413
size_t index
Definition template.h:412

◆ next() [2/2]

DC_PUBLIC KV_PAIR_CONST next ( ITER_CONST * iter)
static

Definition at line 490 of file template.h.

490 {
491 DC_ASSUME(iter);
493 if (iter->index < iter->map->capacity) {
494 iter->curr = (KV_PAIR_CONST){.key = &iter->map->keys[iter->index].key,
495 .value = &iter->map->values[iter->index]};
496 iter->index++;
497 while (iter->index < iter->map->capacity && !iter->map->keys[iter->index].present) {
498 iter->index++;
499 }
500 return iter->curr;
501 }
502 return (KV_PAIR_CONST){.key = NULL, .value = NULL};
503}
SELF const * map
Definition template.h:484
size_t index
Definition template.h:485
mutation_version version
Definition template.h:417
IV_PAIR_CONST curr
Definition template.h:378

◆ read()

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

Definition at line 313 of file template.h.

313 {
314 VALUE const* value = NS(SELF, try_read)(self, key);
315 DC_ASSERT(value, "Cannot read item {key=%s}", DC_DEBUG(KEY_DEBUG, &key));
316 return value;
317}
static DC_PUBLIC VALUE const * try_read(SELF const *self, INDEX index)
Definition template.h:180

◆ remove()

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

Definition at line 379 of file template.h.

379 {
380 VALUE value;
381 DC_ASSERT(NS(SELF, try_remove)(self, key, &value), "Failed to remove item {key=%s}",
382 DC_DEBUG(KEY_DEBUG, &key));
383 return value;
384}
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 391 of file template.h.

391 {
392 INVARIANT_CHECK(self);
393 return self->items;
394}

◆ try_insert()

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

Definition at line 249 of file template.h.

249 {
250 INVARIANT_CHECK(self);
252
253 if (self->items >= NS(SELF, max_capacity)) {
254 return NULL;
255 }
256
257 if (dc_apply_capacity_policy(self->items) > self->capacity / 2) {
258 NS(SELF, extend_capacity_for)(self, self->items * 2);
259 }
260
261 return PRIV(NS(SELF, try_insert_no_extend_capacity))(self, key, value);
262}
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
size_t items
Definition template.h:79

◆ try_insert_no_extend_capacity()

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

Definition at line 170 of file template.h.

170 {
171 uint16_t distance_from_desired = 0;
172 size_t const hash = KEY_HASH(&key);
173 size_t index = dc_math_modulus_power_of_2_capacity(hash, self->capacity);
174
175 VALUE* inserted_to_entry = NULL;
176
177 for (;;) {
178 KEY_ENTRY* entry = &self->keys[index];
179 DC_ASSUME(distance_from_desired < self->capacity);
180
181 if (entry->present) {
182 if (KEY_EQ(&entry->key, &key)) {
183 return NULL;
184 }
185
186 if (entry->distance_from_desired < distance_from_desired) {
187 KEY const switch_key = entry->key;
188 uint16_t const switch_distance_from_desired = entry->distance_from_desired;
189 VALUE const switch_value = self->values[index];
190
191 entry->key = key;
192 entry->distance_from_desired = distance_from_desired;
193 self->values[index] = value;
194
195 key = switch_key;
196 distance_from_desired = switch_distance_from_desired;
197 value = switch_value;
198
199 if (!inserted_to_entry) {
200 inserted_to_entry = &self->values[index];
201 }
202 }
203
204 distance_from_desired++;
205 index = dc_math_modulus_power_of_2_capacity(index + 1, self->capacity);
206 } else {
207 entry->present = true;
208 entry->distance_from_desired = distance_from_desired;
209 entry->key = key;
210
212 &self->values[index], sizeof(VALUE));
213
214 self->values[index] = value;
215
216 if (!inserted_to_entry) {
217 inserted_to_entry = &self->values[index];
218 }
219
220 self->items++;
221 return inserted_to_entry;
222 }
223 }
224}
#define KEY
Definition template.h:32
#define KEY_HASH
Definition template.h:26
#define KEY_EQ
Definition template.h:31
static DC_PUBLIC size_t DC_INLINE DC_CONST dc_math_modulus_power_of_2_capacity(size_t index, size_t capacity)
Definition math.h:61
@ DC_MEMORY_TRACKER_CAP_WRITE

◆ try_read()

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

Definition at line 295 of file template.h.

295 {
296 INVARIANT_CHECK(self);
297 size_t const hash = KEY_HASH(&key);
298 size_t index = dc_math_modulus_power_of_2_capacity(hash, self->capacity);
299
300 for (;;) {
301 KEY_ENTRY* entry = &self->keys[index];
302 if (entry->present) {
303 if (KEY_EQ(&entry->key, &key)) {
304 return &self->values[index];
305 }
306 index = dc_math_modulus_power_of_2_capacity(index + 1, self->capacity);
307 } else {
308 return NULL;
309 }
310 }
311}

◆ try_remove()

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

Definition at line 319 of file template.h.

319 {
320 INVARIANT_CHECK(self);
322 size_t const hash = KEY_HASH(&key);
323 size_t index = dc_math_modulus_power_of_2_capacity(hash, self->capacity);
324
325 for (;;) {
326 KEY_ENTRY* entry = &self->keys[index];
327 if (entry->present) {
328 if (KEY_EQ(&entry->key, &key)) {
329 self->items--;
330
331 *destination = self->values[index];
332 KEY_DELETE(&entry->key);
333
334 // NOTE: For robin hood hashing, we need probe chains to be unbroken
335 // - Need to find the entries that might use this chain (
336 // distance_to_desired > 0 until the next not-present or
337 // distance_to_desired=0 slot)
338 // hence we shift entries the left (being careful with modulus index)
339
340 size_t free_index = index;
341 KEY_ENTRY* free_entry = entry;
342
343 size_t check_index =
344 dc_math_modulus_power_of_2_capacity(free_index + 1, self->capacity);
345 KEY_ENTRY* check_entry = &self->keys[check_index];
346
347 while (check_entry->present && (check_entry->distance_from_desired > 0)) {
348 free_entry->key = check_entry->key;
349 free_entry->distance_from_desired = check_entry->distance_from_desired - 1;
350 self->values[free_index] = self->values[check_index];
351
352 free_index = check_index;
353 free_entry = check_entry;
354
355 check_index =
356 dc_math_modulus_power_of_2_capacity(free_index + 1, self->capacity);
357 check_entry = &self->keys[check_index];
358 }
359
360 // JUSTIFY: Only setting free entry to false
361 // - We remove, then shift down an index
362 // - The removed entry already has the flag set
363 // - the free entry was the last one removed/moved down an index, so it
364 // should be false.
365
366 free_entry->present = false;
368 &self->values[free_index], sizeof(VALUE));
369
370 return true;
371 }
372 index = dc_math_modulus_power_of_2_capacity(index + 1, self->capacity);
373 } else {
374 return false;
375 }
376 }
377}

◆ try_write()

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

Definition at line 271 of file template.h.

271 {
272 INVARIANT_CHECK(self);
273 size_t const hash = KEY_HASH(&key);
274 size_t index = dc_math_modulus_power_of_2_capacity(hash, self->capacity);
275
276 for (;;) {
277 KEY_ENTRY* entry = &self->keys[index];
278 if (entry->present) {
279 if (KEY_EQ(&entry->key, &key)) {
280 return &self->values[index];
281 }
282 index = dc_math_modulus_power_of_2_capacity(index + 1, self->capacity);
283 } else {
284 return NULL;
285 }
286 }
287}

◆ write()

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

Definition at line 289 of file template.h.

289 {
290 VALUE* value = NS(SELF, try_write)(self, key);
291 DC_ASSERT(value, "Cannot write item {key=%s}", DC_DEBUG(KEY_DEBUG, &key));
292 return value;
293}
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 = SIZE_MAX

Definition at line 93 of file template.h.