6#if !defined(SKIP_INCLUDES)
14 #if !defined DC_PLACEHOLDERS
22 #if !defined DC_PLACEHOLDERS
26 #define KEY_HASH key_hash
31 #define KEY_EQ DC_MEM_EQ
34#if !defined KEY_DELETE
35 #define KEY_DELETE DC_NO_DELETE
39 #define KEY_CLONE DC_COPY_CLONE
43 #define KEY_DEBUG DC_DEFAULT_DEBUG
47 #if !defined DC_PLACEHOLDERS
56#if !defined VALUE_DELETE
57 #define VALUE_DELETE DC_NO_DELETE
60#if !defined VALUE_CLONE
61 #define VALUE_CLONE DC_COPY_CLONE
64#if !defined VALUE_DEBUG
65 #define VALUE_DEBUG DC_DEFAULT_DEBUG
75#define SLOT NS(NAME, slot_t)
109#define SLOT_VECTOR NS(NAME, item_vectors)
111#pragma push_macro("ALLOC")
115#define ITEM_DELETE PRIV(NS(SLOT, delete))
116#define ITEM_CLONE PRIV(NS(SLOT, clone))
117#define ITEM_DEBUG PRIV(NS(SLOT, debug))
118#define INTERNAL_NAME SLOT_VECTOR
121#pragma pop_macro("ALLOC")
123#if defined SMALL_BUCKETS
125 #define BUCKET _dc_ankerl_small_bucket
127 #define BUCKET _dc_ankerl_bucket
143#define INVARIANT_CHECK(self) \
145 DC_ASSUME(DC_MATH_IS_POWER_OF_2((self)->buckets_capacity)); \
146 DC_ASSUME((self)->buckets);
156 .buckets_capacity = capacity,
159 .alloc_ref = alloc_ref,
164 DC_ASSERT(for_items > 0,
"Cannot create map with capacity for 0 items {for_items=%lu}",
178 self->alloc_ref, self->buckets_capacity *
sizeof(
BUCKET));
179 memcpy(new_buckets, self->buckets, self->buckets_capacity *
sizeof(
BUCKET));
182 .buckets_capacity = self->buckets_capacity,
183 .buckets = new_buckets,
185 .alloc_ref = self->alloc_ref,
194 const size_t mask = self->buckets_capacity - 1;
198 const size_t desired = hash & mask;
202 for (
size_t pos = desired;; pos = (pos + 1) & mask) {
203 BUCKET const* b = &self->buckets[pos];
218 if (b->mdata.fingerprint == fp) {
242 for (
size_t pos = desired;; pos = (pos + 1) & mask) {
243 BUCKET* b = &self->buckets[pos];
250 if (b->mdata.dfd < cur.mdata.dfd) {
267 const size_t new_mask = new_capacity - 1;
270 for (
size_t dense_index = 0; dense_index < n; ++dense_index) {
275 const size_t desired = hash & new_mask;
284 for (
size_t pos = desired;; pos = (pos + 1) & new_mask) {
285 BUCKET* b = &new_buckets[pos];
292 if (b->mdata.dfd < cur.mdata.dfd) {
303 self->buckets = new_buckets;
304 self->buckets_capacity = new_capacity;
311 if (required <= self->buckets_capacity) {
326 if (
size >= self->buckets_capacity) {
341 size_t* out_bucket_pos,
size_t* out_dense_index) {
347 const size_t mask = self->buckets_capacity - 1;
351 const size_t desired = hash & mask;
354 for (
size_t pos = desired;; pos = (pos + 1) & mask) {
355 BUCKET const* b = &self->buckets[pos];
366 if (b->mdata.fingerprint == fp) {
370 *out_bucket_pos = pos;
371 *out_dense_index = di;
412 size_t removed_dense_index;
424 *destination = slot->
value;
434 size_t hole = found_pos;
437 const size_t next = (hole + 1) & mask;
446 self->
buckets[hole].mdata.dfd =
455 const size_t last =
size - 1;
457 if (removed_dense_index != last) {
466 const size_t desired = moved_hash & mask;
469 for (
size_t pos = desired;; pos = (pos + 1) & mask) {
478 if (b->mdata.fingerprint == moved_fp) {
482 *b =
NS(
BUCKET,
new)(b->mdata, removed_dense_index);
521#define ITER_CONST NS(SELF, iter_const)
522#define KV_PAIR_CONST NS(ITER_CONST, item)
534 return item->key == NULL &&
item->value == NULL;
546 .key = &next_item->
key,
547 .value = &next_item->
value,
584#define ITER NS(SELF, iter)
585#define KV_PAIR NS(ITER, item)
597 return item->key == NULL &&
item->value == NULL;
609 .key = &next_item->
key,
610 .value = &next_item->
value,
629#undef INVARIANT_CHECK
static DC_PUBLIC void deallocate(SELF *self, void *ptr, size_t size)
static DC_PUBLIC void debug(SELF const *self, dc_debug_fmt fmt, FILE *stream)
static DC_PUBLIC void * allocate_zeroed(SELF *self, size_t size)
static DC_PUBLIC void * allocate_uninit(SELF *self, size_t size)
#define DC_STATIC_CONSTANT
static DC_PUBLIC VALUE const * try_read(SELF const *self, INDEX index)
static DC_PUBLIC VALUE * try_write(SELF *self, INDEX index)
#define INVARIANT_CHECK(self)
static DC_PUBLIC IV_PAIR next(ITER *iter)
static DC_PUBLIC INDEX insert(SELF *self, VALUE value)
static DC_PUBLIC bool empty(ITER const *iter)
static DC_PUBLIC VALUE const * read(SELF const *self, INDEX index)
static DC_PUBLIC bool try_remove(SELF *self, INDEX index, VALUE *destination)
static DC_PUBLIC VALUE * write(SELF *self, INDEX index)
static DC_PUBLIC bool empty_item(IV_PAIR const *item)
static DC_PUBLIC VALUE remove(SELF *self, INDEX index)
static DC_PUBLIC ITER get_iter(SELF *self)
static DC_PUBLIC ITER_CONST get_iter_const(SELF const *self)
static DC_PUBLIC size_t size(SELF const *self)
static DC_PUBLIC SELF clone(SELF const *self)
static DC_PUBLIC SELF new_with_capacity_for(INDEX_TYPE items, ref alloc_ref)
static DC_PUBLIC void extend_capacity_for(SELF *self, size_t expected_items)
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_INTERNAL void PRIV rehash(SELF *self, size_t new_capacity)
DC_STATIC_CONSTANT size_t max_capacity
static DC_INTERNAL VALUE *PRIV try_insert_no_extend_capacity(SELF *self, KEY key, VALUE value)
static DC_PUBLIC void delete_entry(SELF *self, KEY key)
static DC_PUBLIC VALUE * try_insert(SELF *self, KEY key, VALUE value)
static DC_INTERNAL SELF PRIV new_with_exact_capacity(size_t capacity, ref alloc_ref)
#define KEY
A simple swiss table implementation. See the abseil docs for swss table here.
#define DC_TRAIT_MAP(SELF)
static DC_PUBLIC SELF new_with_capacity(size_t front_and_back_capacity, ref alloc_ref)
static DC_PUBLIC ITEM * push(SELF *self, ITEM item)
static DC_PUBLIC ITEM pop(SELF *self)
#define TEMPLATE_ERROR(...)
With the user provided name, even in nested templates.
#define DC_DEBUG(DEBUG_FN, DEBUG_PTR)
static DC_PUBLIC void dc_debug_fmt_print(dc_debug_fmt fmt, FILE *stream, const char *format,...)
static DC_PUBLIC dc_debug_fmt dc_debug_fmt_scope_end(dc_debug_fmt fmt)
static DC_PUBLIC dc_debug_fmt dc_debug_fmt_scope_begin(dc_debug_fmt fmt)
static DC_PUBLIC dc_gdb_marker dc_gdb_marker_new()
static DC_INTERNAL size_t _dc_ankerl_buckets_capacity(size_t for_items)
DC_STATIC_CONSTANT size_t max_index_exclusive
static const size_t dc_ankerl_initial_items
static DC_INTERNAL _dc_ankerl_dfd _dc_ankerl_dfd_decrement_for_backshift(_dc_ankerl_dfd dfd)
static DC_INTERNAL uint8_t _dc_ankerl_fingerprint_from_hash(size_t hash)
static const _dc_ankerl_dfd _dc_ankerl_dfd_max
static const _dc_ankerl_dfd _dc_ankerl_dfd_none
static DC_INTERNAL bool _dc_ankerl_mdata_present(_dc_ankerl_mdata const *bucket)
static DC_INTERNAL size_t get_index(_dc_ankerl_small_bucket const *bucket)
static DC_INTERNAL _dc_ankerl_dfd _dc_ankerl_dfd_new(uint8_t distance)
static DC_INTERNAL _dc_ankerl_dfd _dc_ankerl_dfd_increment(_dc_ankerl_dfd dfd)
#define DC_MATH_IS_POWER_OF_2(x)
#define DC_EXPAND_STRING(NAME)
#define DC_UNREACHABLE(...)
#define DC_ASSERT(expr,...)
#define DC_ASSUME(expr,...)
dc_gdb_marker derive_c_hashmap
Debug format helpers for debug printin data structures.
static DC_PUBLIC FILE * stream(SELF *self)