7#if !defined(SKIP_INCLUDES)
15 #if !defined PLACEHOLDERS
23 #if !defined PLACEHOLDERS
27 #define KEY_HASH key_hash
32 #define KEY_EQ DC_MEM_EQ
35#if !defined KEY_DELETE
36 #define KEY_DELETE DC_NO_DELETE
40 #define KEY_CLONE DC_COPY_CLONE
44 #define KEY_DEBUG DC_DEFAULT_DEBUG
48 #if !defined PLACEHOLDERS
57#if !defined VALUE_DELETE
58 #define VALUE_DELETE DC_NO_DELETE
61#if !defined VALUE_CLONE
62 #define VALUE_CLONE DC_COPY_CLONE
65#if !defined VALUE_DEBUG
66 #define VALUE_DEBUG DC_DEFAULT_DEBUG
73#define SLOT NS(SELF, slot_t)
93#define INVARIANT_CHECK(self) \
95 DC_ASSUME(DC_MATH_IS_POWER_OF_2((self)->capacity)); \
96 DC_ASSUME((self)->slots); \
97 DC_ASSUME((self)->ctrl); \
98 DC_ASSUME((self)->alloc); \
99 DC_ASSUME((self)->count + (self)->tombstones <= (self)->capacity);
111 for (
size_t i = 0; i <
capacity; i++) {
151 memcpy(ctrl, self->ctrl,
sizeof(
dc_swiss_ctrl) * ctrl_capacity);
153 for (
size_t i = 0; i < self->capacity; i++) {
161 .capacity = self->capacity,
162 .count = self->count,
163 .tombstones = self->tombstones,
166 .alloc = self->alloc,
174 DC_ASSUME(self->count + self->tombstones < self->capacity);
177 const size_t mask = self->capacity - 1;
184 const size_t start = hash & mask;
187 const size_t group = (start + step) & mask;
194 const size_t i = (group + j) & mask;
206 const size_t ins = has_deleted ? first_deleted : i;
211 self->slots[ins].key = key;
212 self->slots[ins].value = value;
217 return &self->slots[ins].value;
241 DC_ASSUME(new_capacity >= self->capacity);
246 for (
size_t i = 0; i < self->capacity; i++) {
249 self->slots[i].value);
266 if (new_capacity > self->capacity) {
295 const size_t mask = self->capacity - 1;
300 const size_t start = hash & mask;
303 const size_t group = (start + step) & mask;
306 const size_t i = (group + j) & mask;
322 return &self->slots[i].value;
350 const size_t mask = self->capacity - 1;
355 const size_t start = hash & mask;
358 const size_t group = (start + step) & mask;
361 const size_t i = (group + j) & mask;
379 if (!
KEY_EQ(&self->slots[i].key, &key)) {
384 if (destination != NULL) {
385 *destination = self->slots[i].value;
425 for (
size_t i = 0; i < self->capacity; i++) {
435#define ITER_CONST NS(SELF, iter_const)
436#define KV_PAIR_CONST NS(ITER_CONST, item)
450 return item->key == NULL &&
item->value == NULL;
467 .key = &iter->map->slots[index].key,
468 .value = &iter->map->slots[index].value,
528#define ITER NS(SELF, iter)
529#define KV_PAIR NS(ITER, item)
543 return item->key == NULL &&
item->value == NULL;
560 .key = &iter->map->slots[index].key,
561 .value = &iter->map->slots[index].value,
581#undef INVARIANT_CHECK
static void debug(SELF const *self, dc_debug_fmt fmt, FILE *stream)
static void free(SELF *self, void *ptr)
static void * malloc(SELF *self, size_t size)
static void * calloc(SELF *self, size_t count, size_t size)
static INDEX insert(SELF *self, VALUE value)
static ITER_CONST get_iter_const(SELF const *self)
static ITER get_iter(SELF *self)
static IV_PAIR next(ITER *iter)
static INDEX_TYPE size(SELF const *self)
#define INVARIANT_CHECK(self)
static VALUE remove(SELF *self, INDEX index)
static bool empty_item(IV_PAIR const *item)
SLOT PRIV(block)[DC_ARENA_CHUNKED_BLOCK_SIZE(BLOCK_INDEX_BITS)]
static VALUE * try_write(SELF *self, INDEX index)
static VALUE const * read(SELF const *self, INDEX index)
static VALUE * write(SELF *self, INDEX index)
static bool try_remove(SELF *self, INDEX index, VALUE *destination)
static SELF clone(SELF const *self)
static VALUE const * try_read(SELF const *self, INDEX index)
static SELF new_with_capacity_for(INDEX_TYPE items, ALLOC *alloc)
static VALUE *PRIV try_insert_no_extend_capacity(SELF *self, KEY key, VALUE value)
static VALUE * try_insert(SELF *self, KEY key, VALUE value)
#define KEY
A simple swiss table implementation. See the abseil docs for swss table here.
static void delete_entry(SELF *self, KEY key)
static SELF PRIV new_with_exact_capacity(size_t capacity, ALLOC *alloc)
static void extend_capacity_for(SELF *self, size_t expected_items)
static void PRIV rehash(SELF *self, size_t new_capacity)
static void PRIV next_populated_index(SELF const *self, dc_swiss_optional_index *index)
#define DC_TRAIT_MAP(SELF)
dc_debug_fmt dc_debug_fmt_scope_end(dc_debug_fmt fmt)
dc_debug_fmt dc_debug_fmt_scope_begin(dc_debug_fmt fmt)
static void dc_debug_fmt_print(dc_debug_fmt fmt, FILE *stream, const char *format,...)
static dc_gdb_marker dc_gdb_marker_new()
static void dc_swiss_ctrl_set_at(dc_swiss_ctrl *self, size_t capacity, size_t index, dc_swiss_ctrl val)
#define DC_SWISS_INITIAL_CAPACITY
static size_t dc_swiss_capacity(size_t for_items)
@ DC_SWISS_DOUBLE_CAPACITY
@ DC_SWISS_CLEANUP_TOMBSONES
static bool dc_swiss_is_present(dc_swiss_ctrl ctrl)
#define DC_SWISS_VAL_EMPTY
static dc_swiss_id dc_swiss_id_from_hash(size_t hash)
#define DC_SWISS_SIMD_PROBE_SIZE
static uint8_t dc_swiss_ctrl_get_id(dc_swiss_ctrl ctrl)
size_t dc_swiss_optional_index
#define DC_SWISS_NO_INDEX
#define DC_SWISS_VAL_DELETED
static dc_swiss_rehash_action dc_swiss_heuristic_should_extend(size_t tombstones, size_t count, size_t capacity)
#define DC_SWISS_VAL_SENTINEL
#define DC_MATH_IS_POWER_OF_2(x)
static mutation_tracker mutation_tracker_new()
static void mutation_version_check(mutation_version const *self)
static mutation_version mutation_tracker_get(mutation_tracker const *self)
static void mutation_tracker_mutate(mutation_tracker *self)
#define EXPAND_STRING(NAME)
#define DC_ASSERT(expr,...)
#define DC_ASSUME(expr,...)
#define TEMPLATE_ERROR(...)
With the user provided name, even in nested templates.
mutation_tracker iterator_invalidation_tracker
dc_gdb_marker derive_c_hashmap
Debug format helpers for debug printin data structures.
tracks a specific version of a value, so that this can be compared later to check modification For ex...
static FILE * stream(SELF *self)
Opens a file for.