16#ifndef CCC_IMPL_FLAT_HASH_MAP_H
17#define CCC_IMPL_FLAT_HASH_MAP_H
27#include "impl_types.h"
33#if defined(__x86_64) && defined(__SSE2__) && !defined(CCC_FHM_PORTABLE)
37# define CCC_HAS_X86_SIMD
38#elif defined(__ARM_NEON__) && !defined(CCC_FHM_PORTABLE)
42# define CCC_HAS_ARM_SIMD
72enum : typeof((ccc_fhm_tag){}.v)
74#if defined(CCC_HAS_X86_SIMD)
76 CCC_FHM_GROUP_SIZE = 16,
77#elif defined(CCC_HAS_ARM_SIMD)
79 CCC_FHM_GROUP_SIZE = 8,
82 CCC_FHM_GROUP_SIZE = 8,
150struct ccc_fhash_entry
159 enum ccc_entry_status stats;
169 struct ccc_fhash_entry impl;
177struct ccc_fhash_entry ccc_impl_fhm_entry(struct ccc_fhmap *h,
void const *key);
178void ccc_impl_fhm_insert(
struct ccc_fhmap *h,
void const *key_val_type,
179 ccc_fhm_tag m,
size_t i);
180void ccc_impl_fhm_erase(
struct ccc_fhmap *h,
size_t i);
181void *ccc_impl_fhm_data_at(
struct ccc_fhmap
const *h,
size_t i);
182void *ccc_impl_fhm_key_at(
struct ccc_fhmap
const *h,
size_t i);
183void ccc_impl_fhm_set_insert(
struct ccc_fhash_entry
const *e);
201#define ccc_impl_fhm_declare_fixed_map(fixed_map_type_name, key_val_type_name, \
203 static_assert((capacity) > 0, \
204 "fixed size map must have capacity greater than 0"); \
205 static_assert((capacity) >= CCC_FHM_GROUP_SIZE, \
206 "fixed size map must have capacity >= CCC_FHM_GROUP_SIZE " \
207 "(8 or 16 depending on platform)"); \
208 static_assert(((capacity) & ((capacity) - 1)) == 0, \
209 "fixed size map must be a power of 2 capacity (32, 64, " \
210 "128, 256, etc.)"); \
213 key_val_type_name data[(capacity) + 1]; \
214 alignas(CCC_FHM_GROUP_SIZE) \
215 ccc_fhm_tag tag[(capacity) + CCC_FHM_GROUP_SIZE]; \
216 }(fixed_map_type_name)
228#define ccc_impl_fhm_fixed_capacity(fixed_map_type_name) \
229 (sizeof((fixed_map_type_name){}.tag) - CCC_FHM_GROUP_SIZE)
247#define ccc_impl_fhm_init(impl_fixed_map_ptr, impl_any_type_name, \
248 impl_key_field, impl_hash_fn, impl_key_eq_fn, \
249 impl_alloc_fn, impl_aux_data, impl_capacity) \
251 .data = (impl_fixed_map_ptr), \
254 .remain = (((impl_capacity) / (size_t)8) * (size_t)7), \
255 .mask = (((impl_capacity) > (size_t)0) ? ((impl_capacity) - (size_t)1) \
257 .sizeof_type = sizeof(impl_any_type_name), \
258 .key_offset = offsetof(impl_any_type_name, impl_key_field), \
259 .eq_fn = (impl_key_eq_fn), \
260 .hash_fn = (impl_hash_fn), \
261 .alloc_fn = (impl_alloc_fn), \
262 .aux = (impl_aux_data), \
270#define ccc_impl_fhm_and_modify_w(flat_hash_map_entry_ptr, type_name, \
273 __auto_type impl_fhm_mod_ent_ptr = (flat_hash_map_entry_ptr); \
274 struct ccc_fhash_entry impl_fhm_mod_with_ent \
275 = {.stats = CCC_ENTRY_ARG_ERROR}; \
276 if (impl_fhm_mod_ent_ptr) \
278 impl_fhm_mod_with_ent = impl_fhm_mod_ent_ptr->impl; \
279 if (impl_fhm_mod_with_ent.stats & CCC_ENTRY_OCCUPIED) \
281 type_name *const T = ccc_impl_fhm_data_at( \
282 impl_fhm_mod_with_ent.h, impl_fhm_mod_with_ent.i); \
289 impl_fhm_mod_with_ent; \
296#define ccc_impl_fhm_or_insert_w(flat_hash_map_entry_ptr, lazy_key_value...) \
298 __auto_type impl_fhm_or_ins_ent_ptr = (flat_hash_map_entry_ptr); \
299 typeof(lazy_key_value) *impl_fhm_or_ins_res = NULL; \
300 if (impl_fhm_or_ins_ent_ptr) \
302 if (!(impl_fhm_or_ins_ent_ptr->impl.stats \
303 & CCC_ENTRY_INSERT_ERROR)) \
305 impl_fhm_or_ins_res \
306 = ccc_impl_fhm_data_at(impl_fhm_or_ins_ent_ptr->impl.h, \
307 impl_fhm_or_ins_ent_ptr->impl.i); \
308 if (impl_fhm_or_ins_ent_ptr->impl.stats == CCC_ENTRY_VACANT) \
310 *impl_fhm_or_ins_res = lazy_key_value; \
311 ccc_impl_fhm_set_insert(&impl_fhm_or_ins_ent_ptr->impl); \
315 impl_fhm_or_ins_res; \
320#define ccc_impl_fhm_insert_entry_w(flat_hash_map_entry_ptr, \
323 __auto_type impl_fhm_ins_ent_ptr = (flat_hash_map_entry_ptr); \
324 typeof(lazy_key_value) *impl_fhm_ins_ent_res = NULL; \
325 if (impl_fhm_ins_ent_ptr) \
327 if (!(impl_fhm_ins_ent_ptr->impl.stats & CCC_ENTRY_INSERT_ERROR)) \
329 impl_fhm_ins_ent_res \
330 = ccc_impl_fhm_data_at(impl_fhm_ins_ent_ptr->impl.h, \
331 impl_fhm_ins_ent_ptr->impl.i); \
332 *impl_fhm_ins_ent_res = lazy_key_value; \
333 if (impl_fhm_ins_ent_ptr->impl.stats == CCC_ENTRY_VACANT) \
335 ccc_impl_fhm_set_insert(&impl_fhm_ins_ent_ptr->impl); \
339 impl_fhm_ins_ent_res; \
345#define ccc_impl_fhm_try_insert_w(flat_hash_map_ptr, key, lazy_value...) \
347 struct ccc_fhmap *impl_flat_hash_map_ptr = (flat_hash_map_ptr); \
348 struct ccc_ent impl_fhm_try_insert_res \
349 = {.stats = CCC_ENTRY_ARG_ERROR}; \
350 if (impl_flat_hash_map_ptr) \
352 __auto_type impl_fhm_key = key; \
353 struct ccc_fhash_entry impl_fhm_try_ins_ent = ccc_impl_fhm_entry( \
354 impl_flat_hash_map_ptr, (void *)&impl_fhm_key); \
355 if ((impl_fhm_try_ins_ent.stats & CCC_ENTRY_OCCUPIED) \
356 || (impl_fhm_try_ins_ent.stats & CCC_ENTRY_INSERT_ERROR)) \
358 impl_fhm_try_insert_res = (struct ccc_ent){ \
359 .e = ccc_impl_fhm_data_at(impl_fhm_try_ins_ent.h, \
360 impl_fhm_try_ins_ent.i), \
361 .stats = impl_fhm_try_ins_ent.stats, \
366 impl_fhm_try_insert_res = (struct ccc_ent){ \
367 .e = ccc_impl_fhm_data_at(impl_fhm_try_ins_ent.h, \
368 impl_fhm_try_ins_ent.i), \
369 .stats = CCC_ENTRY_VACANT, \
371 *((typeof(lazy_value) *)impl_fhm_try_insert_res.e) \
373 *((typeof(impl_fhm_key) *)ccc_impl_fhm_key_at( \
374 impl_fhm_try_ins_ent.h, impl_fhm_try_ins_ent.i)) \
376 ccc_impl_fhm_set_insert(&impl_fhm_try_ins_ent); \
379 impl_fhm_try_insert_res; \
386#define ccc_impl_fhm_insert_or_assign_w(flat_hash_map_ptr, key, lazy_value...) \
388 struct ccc_fhmap *impl_flat_hash_map_ptr = (flat_hash_map_ptr); \
389 struct ccc_ent impl_fhm_insert_or_assign_res \
390 = {.stats = CCC_ENTRY_ARG_ERROR}; \
391 if (impl_flat_hash_map_ptr) \
393 impl_fhm_insert_or_assign_res.stats = CCC_ENTRY_INSERT_ERROR; \
394 __auto_type impl_fhm_key = key; \
395 struct ccc_fhash_entry impl_fhm_ins_or_assign_ent \
396 = ccc_impl_fhm_entry(impl_flat_hash_map_ptr, \
397 (void *)&impl_fhm_key); \
398 if (!(impl_fhm_ins_or_assign_ent.stats & CCC_ENTRY_INSERT_ERROR)) \
400 impl_fhm_insert_or_assign_res = (struct ccc_ent){ \
401 .e = ccc_impl_fhm_data_at(impl_fhm_ins_or_assign_ent.h, \
402 impl_fhm_ins_or_assign_ent.i), \
403 .stats = impl_fhm_ins_or_assign_ent.stats, \
405 *((typeof(lazy_value) *)impl_fhm_insert_or_assign_res.e) \
407 *((typeof(impl_fhm_key) *)ccc_impl_fhm_key_at( \
408 impl_fhm_ins_or_assign_ent.h, \
409 impl_fhm_ins_or_assign_ent.i)) \
411 if (impl_fhm_ins_or_assign_ent.stats == CCC_ENTRY_VACANT) \
413 ccc_impl_fhm_set_insert(&impl_fhm_ins_or_assign_ent); \
417 impl_fhm_insert_or_assign_res; \
union ccc_fhmap_entry ccc_fhmap_entry
A container specific entry used to implement the Entry Interface.
Definition: flat_hash_map.h:76
void * ccc_any_alloc_fn(void *ptr, size_t size, void *aux)
An allocation function at the core of all containers.
Definition: types.h:312
ccc_tribool ccc_any_key_eq_fn(ccc_any_key_cmp)
A callback function to determining equality between two stored keys.
Definition: types.h:355
uint64_t ccc_any_key_hash_fn(ccc_any_key to_hash)
A callback function to hash the key type used in a container.
Definition: types.h:368