16#ifndef CCC_IMPL_FLAT_HASH_MAP_H
17#define CCC_IMPL_FLAT_HASH_MAP_H
26#include "impl_types.h"
32#if defined(__x86_64) && defined(__SSE2__) && !defined(CCC_FHM_PORTABLE)
36# define CCC_HAS_X86_SIMD
37#elif defined(__ARM_NEON__) && !defined(CCC_FHM_PORTABLE)
41# define CCC_HAS_ARM_SIMD
71enum : typeof((ccc_fhm_tag){}.v)
73#if defined(CCC_HAS_X86_SIMD)
75 CCC_FHM_GROUP_SIZE = 16,
76#elif defined(CCC_HAS_ARM_SIMD)
78 CCC_FHM_GROUP_SIZE = 8,
81 CCC_FHM_GROUP_SIZE = 8,
138struct ccc_fhash_entry
147 enum ccc_entry_status stats;
157 struct ccc_fhash_entry impl;
165struct ccc_fhash_entry ccc_impl_fhm_entry(struct ccc_fhmap *h,
void const *key);
166void ccc_impl_fhm_insert(
struct ccc_fhmap *h,
void const *key_val_type,
167 ccc_fhm_tag m,
size_t i);
168void ccc_impl_fhm_erase(
struct ccc_fhmap *h,
size_t i);
169void *ccc_impl_fhm_data_at(
struct ccc_fhmap
const *h,
size_t i);
170void *ccc_impl_fhm_key_at(
struct ccc_fhmap
const *h,
size_t i);
171void ccc_impl_fhm_set_insert(
struct ccc_fhash_entry
const *e);
182#define ccc_impl_fhm_declare_fixed_map(fixed_map_type_name, key_val_type_name, \
184 static_assert((capacity) > 0, \
185 "fixed size map must have capacity greater than 0"); \
186 static_assert((capacity) >= CCC_FHM_GROUP_SIZE, \
187 "fixed size map must have capacity >= CCC_FHM_GROUP_SIZE " \
188 "(8 or 16 depending on platform)"); \
189 static_assert(((capacity) & ((capacity) - 1)) == 0, \
190 "fixed size map must be a power of 2 capacity (32, 64, " \
191 "128, 256, etc.)"); \
194 key_val_type_name data[(capacity) + 1]; \
195 ccc_fhm_tag tag[(capacity) + CCC_FHM_GROUP_SIZE]; \
196 }(fixed_map_type_name)
208#define ccc_impl_fhm_fixed_capacity(fixed_map_type_name) \
209 (sizeof((fixed_map_type_name){}.tag) - CCC_FHM_GROUP_SIZE)
227#define ccc_impl_fhm_init(impl_fixed_map_ptr, impl_any_type_name, \
228 impl_key_field, impl_hash_fn, impl_key_eq_fn, \
229 impl_alloc_fn, impl_aux_data, impl_capacity) \
231 .data = (impl_fixed_map_ptr), \
234 .remain = (((impl_capacity) / (size_t)8) * (size_t)7), \
235 .mask = (((impl_capacity) > (size_t)0) ? ((impl_capacity) - (size_t)1) \
237 .sizeof_type = sizeof(impl_any_type_name), \
238 .key_offset = offsetof(impl_any_type_name, impl_key_field), \
239 .eq_fn = (impl_key_eq_fn), \
240 .hash_fn = (impl_hash_fn), \
241 .alloc_fn = (impl_alloc_fn), \
242 .aux = (impl_aux_data), \
250#define ccc_impl_fhm_and_modify_w(flat_hash_map_entry_ptr, type_name, \
253 __auto_type impl_fhm_mod_ent_ptr = (flat_hash_map_entry_ptr); \
254 struct ccc_fhash_entry impl_fhm_mod_with_ent \
255 = {.stats = CCC_ENTRY_ARG_ERROR}; \
256 if (impl_fhm_mod_ent_ptr) \
258 impl_fhm_mod_with_ent = impl_fhm_mod_ent_ptr->impl; \
259 if (impl_fhm_mod_with_ent.stats & CCC_ENTRY_OCCUPIED) \
261 type_name *const T = ccc_impl_fhm_data_at( \
262 impl_fhm_mod_with_ent.h, impl_fhm_mod_with_ent.i); \
269 impl_fhm_mod_with_ent; \
276#define ccc_impl_fhm_or_insert_w(flat_hash_map_entry_ptr, lazy_key_value...) \
278 __auto_type impl_fhm_or_ins_ent_ptr = (flat_hash_map_entry_ptr); \
279 typeof(lazy_key_value) *impl_fhm_or_ins_res = NULL; \
280 if (impl_fhm_or_ins_ent_ptr) \
282 if (!(impl_fhm_or_ins_ent_ptr->impl.stats \
283 & CCC_ENTRY_INSERT_ERROR)) \
285 impl_fhm_or_ins_res \
286 = ccc_impl_fhm_data_at(impl_fhm_or_ins_ent_ptr->impl.h, \
287 impl_fhm_or_ins_ent_ptr->impl.i); \
288 if (impl_fhm_or_ins_ent_ptr->impl.stats == CCC_ENTRY_VACANT) \
290 *impl_fhm_or_ins_res = lazy_key_value; \
291 ccc_impl_fhm_set_insert(&impl_fhm_or_ins_ent_ptr->impl); \
295 impl_fhm_or_ins_res; \
300#define ccc_impl_fhm_insert_entry_w(flat_hash_map_entry_ptr, \
303 __auto_type impl_fhm_ins_ent_ptr = (flat_hash_map_entry_ptr); \
304 typeof(lazy_key_value) *impl_fhm_ins_ent_res = NULL; \
305 if (impl_fhm_ins_ent_ptr) \
307 if (!(impl_fhm_ins_ent_ptr->impl.stats & CCC_ENTRY_INSERT_ERROR)) \
309 impl_fhm_ins_ent_res \
310 = ccc_impl_fhm_data_at(impl_fhm_ins_ent_ptr->impl.h, \
311 impl_fhm_ins_ent_ptr->impl.i); \
312 *impl_fhm_ins_ent_res = lazy_key_value; \
313 if (impl_fhm_ins_ent_ptr->impl.stats == CCC_ENTRY_VACANT) \
315 ccc_impl_fhm_set_insert(&impl_fhm_ins_ent_ptr->impl); \
319 impl_fhm_ins_ent_res; \
325#define ccc_impl_fhm_try_insert_w(flat_hash_map_ptr, key, lazy_value...) \
327 struct ccc_fhmap *impl_flat_hash_map_ptr = (flat_hash_map_ptr); \
328 struct ccc_ent impl_fhm_try_insert_res \
329 = {.stats = CCC_ENTRY_ARG_ERROR}; \
330 if (impl_flat_hash_map_ptr) \
332 __auto_type impl_fhm_key = key; \
333 struct ccc_fhash_entry impl_fhm_try_ins_ent = ccc_impl_fhm_entry( \
334 impl_flat_hash_map_ptr, (void *)&impl_fhm_key); \
335 if ((impl_fhm_try_ins_ent.stats & CCC_ENTRY_OCCUPIED) \
336 || (impl_fhm_try_ins_ent.stats & CCC_ENTRY_INSERT_ERROR)) \
338 impl_fhm_try_insert_res = (struct ccc_ent){ \
339 .e = ccc_impl_fhm_data_at(impl_fhm_try_ins_ent.h, \
340 impl_fhm_try_ins_ent.i), \
341 .stats = impl_fhm_try_ins_ent.stats, \
346 impl_fhm_try_insert_res = (struct ccc_ent){ \
347 .e = ccc_impl_fhm_data_at(impl_fhm_try_ins_ent.h, \
348 impl_fhm_try_ins_ent.i), \
349 .stats = CCC_ENTRY_VACANT, \
351 *((typeof(lazy_value) *)impl_fhm_try_insert_res.e) \
353 *((typeof(impl_fhm_key) *)ccc_impl_fhm_key_at( \
354 impl_fhm_try_ins_ent.h, impl_fhm_try_ins_ent.i)) \
356 ccc_impl_fhm_set_insert(&impl_fhm_try_ins_ent); \
359 impl_fhm_try_insert_res; \
366#define ccc_impl_fhm_insert_or_assign_w(flat_hash_map_ptr, key, lazy_value...) \
368 struct ccc_fhmap *impl_flat_hash_map_ptr = (flat_hash_map_ptr); \
369 struct ccc_ent impl_fhm_insert_or_assign_res \
370 = {.stats = CCC_ENTRY_ARG_ERROR}; \
371 if (impl_flat_hash_map_ptr) \
373 impl_fhm_insert_or_assign_res.stats = CCC_ENTRY_INSERT_ERROR; \
374 __auto_type impl_fhm_key = key; \
375 struct ccc_fhash_entry impl_fhm_ins_or_assign_ent \
376 = ccc_impl_fhm_entry(impl_flat_hash_map_ptr, \
377 (void *)&impl_fhm_key); \
378 if (!(impl_fhm_ins_or_assign_ent.stats & CCC_ENTRY_INSERT_ERROR)) \
380 impl_fhm_insert_or_assign_res = (struct ccc_ent){ \
381 .e = ccc_impl_fhm_data_at(impl_fhm_ins_or_assign_ent.h, \
382 impl_fhm_ins_or_assign_ent.i), \
383 .stats = impl_fhm_ins_or_assign_ent.stats, \
385 *((typeof(lazy_value) *)impl_fhm_insert_or_assign_res.e) \
387 *((typeof(impl_fhm_key) *)ccc_impl_fhm_key_at( \
388 impl_fhm_ins_or_assign_ent.h, \
389 impl_fhm_ins_or_assign_ent.i)) \
391 if (impl_fhm_ins_or_assign_ent.stats == CCC_ENTRY_VACANT) \
393 ccc_impl_fhm_set_insert(&impl_fhm_ins_or_assign_ent); \
397 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