16#ifndef CCC_IMPL_FLAT_HASH_MAP_H
17#define CCC_IMPL_FLAT_HASH_MAP_H
26#include "impl_types.h"
37#if defined(__x86_64) && defined(__SSE2__) && !defined(CCC_FHM_PORTABLE)
41# define CCC_HAS_X86_SIMD
42#elif defined(__ARM_NEON__) && !defined(CCC_FHM_PORTABLE)
46# define CCC_HAS_ARM_SIMD
76enum : typeof((ccc_fhm_tag){}.v)
78#if defined(CCC_HAS_X86_SIMD)
80 CCC_FHM_GROUP_SIZE = 16,
81#elif defined(CCC_HAS_ARM_SIMD)
83 CCC_FHM_GROUP_SIZE = 8,
86 CCC_FHM_GROUP_SIZE = 8,
143struct ccc_fhash_entry
150 struct ccc_handl handle;
160 struct ccc_fhash_entry impl;
168struct ccc_fhash_entry ccc_impl_fhm_entry(struct ccc_fhmap *h,
void const *key);
169void ccc_impl_fhm_insert(
struct ccc_fhmap *h,
void const *key_val_type,
170 ccc_fhm_tag m,
size_t i);
171void ccc_impl_fhm_erase(
struct ccc_fhmap *h,
size_t i);
172void *ccc_impl_fhm_data_at(
struct ccc_fhmap
const *h,
size_t i);
173void *ccc_impl_fhm_key_at(
struct ccc_fhmap
const *h,
size_t i);
174void ccc_impl_fhm_set_insert(
struct ccc_fhash_entry
const *e);
185#define ccc_impl_fhm_declare_fixed_map(fixed_map_type_name, key_val_type_name, \
187 static_assert((capacity) != 0, \
188 "fixed size map must have capacity greater than 0."); \
189 static_assert((capacity) >= CCC_FHM_GROUP_SIZE, \
190 "fixed size map must have capacity >= CCC_FHM_GROUP_SIZE " \
191 "(8 or 16 depending on platform)."); \
192 static_assert(((capacity) & ((capacity) - 1)) == 0, \
193 "fixed size map must be a power of 2 capacity (32, 64, " \
194 "128, 256, etc.)."); \
197 key_val_type_name data[(capacity) + 1]; \
198 ccc_fhm_tag tag[(capacity) + CCC_FHM_GROUP_SIZE]; \
199 }(fixed_map_type_name);
211#define ccc_impl_fhm_fixed_capacity(fixed_map_type_name) \
212 (sizeof((fixed_map_type_name){}.tag) - CCC_FHM_GROUP_SIZE)
230#define ccc_impl_fhm_init(impl_fixed_map_ptr, impl_any_type_name, \
231 impl_key_field, impl_hash_fn, impl_key_eq_fn, \
232 impl_alloc_fn, impl_aux_data, impl_capacity) \
234 .data = (impl_fixed_map_ptr), \
237 .remain = (((impl_capacity) / (size_t)8) * (size_t)7), \
238 .mask = (((impl_capacity) > (size_t)0) ? ((impl_capacity) - (size_t)1) \
240 .sizeof_type = sizeof(impl_any_type_name), \
241 .key_offset = offsetof(impl_any_type_name, impl_key_field), \
242 .eq_fn = (impl_key_eq_fn), \
243 .hash_fn = (impl_hash_fn), \
244 .alloc_fn = (impl_alloc_fn), \
245 .aux = (impl_aux_data), \
253#define ccc_impl_fhm_and_modify_w(flat_hash_map_entry_ptr, type_name, \
256 __auto_type impl_fhm_mod_ent_ptr = (flat_hash_map_entry_ptr); \
257 struct ccc_fhash_entry impl_fhm_mod_with_ent \
258 = {.handle = {.stats = CCC_ENTRY_ARG_ERROR}}; \
259 if (impl_fhm_mod_ent_ptr) \
261 impl_fhm_mod_with_ent = impl_fhm_mod_ent_ptr->impl; \
262 if (impl_fhm_mod_with_ent.handle.stats & CCC_ENTRY_OCCUPIED) \
264 type_name *const T = ccc_impl_fhm_data_at( \
265 impl_fhm_mod_with_ent.h, impl_fhm_mod_with_ent.handle.i); \
272 impl_fhm_mod_with_ent; \
279#define ccc_impl_fhm_or_insert_w(flat_hash_map_entry_ptr, lazy_key_value...) \
281 __auto_type impl_fhm_or_ins_ent_ptr = (flat_hash_map_entry_ptr); \
282 typeof(lazy_key_value) *impl_fhm_or_ins_res = NULL; \
283 if (impl_fhm_or_ins_ent_ptr) \
285 struct ccc_fhash_entry *impl_fhm_or_ins_entry \
286 = &impl_fhm_or_ins_ent_ptr->impl; \
287 if (!(impl_fhm_or_ins_entry->handle.stats \
288 & CCC_ENTRY_INSERT_ERROR)) \
290 impl_fhm_or_ins_res \
291 = ccc_impl_fhm_data_at(impl_fhm_or_ins_entry->h, \
292 impl_fhm_or_ins_entry->handle.i); \
293 if (impl_fhm_or_ins_entry->handle.stats == CCC_ENTRY_VACANT) \
295 *impl_fhm_or_ins_res = lazy_key_value; \
296 ccc_impl_fhm_set_insert(impl_fhm_or_ins_entry); \
300 impl_fhm_or_ins_res; \
305#define ccc_impl_fhm_insert_entry_w(flat_hash_map_entry_ptr, \
308 __auto_type impl_fhm_ins_ent_ptr = (flat_hash_map_entry_ptr); \
309 typeof(lazy_key_value) *impl_fhm_ins_ent_res = NULL; \
310 if (impl_fhm_ins_ent_ptr) \
312 struct ccc_fhash_entry *impl_fhm_ins_entry \
313 = &impl_fhm_ins_ent_ptr->impl; \
314 if (!(impl_fhm_ins_entry->handle.stats & CCC_ENTRY_INSERT_ERROR)) \
316 impl_fhm_ins_ent_res = ccc_impl_fhm_data_at( \
317 impl_fhm_ins_entry->h, impl_fhm_ins_entry->handle.i); \
318 *impl_fhm_ins_ent_res = lazy_key_value; \
319 if (impl_fhm_ins_entry->handle.stats == CCC_ENTRY_VACANT) \
321 ccc_impl_fhm_set_insert(impl_fhm_ins_entry); \
325 impl_fhm_ins_ent_res; \
331#define ccc_impl_fhm_try_insert_w(flat_hash_map_ptr, key, lazy_value...) \
333 struct ccc_fhmap *impl_flat_hash_map_ptr = (flat_hash_map_ptr); \
334 struct ccc_ent impl_fhm_try_insert_res \
335 = {.stats = CCC_ENTRY_ARG_ERROR}; \
336 if (impl_flat_hash_map_ptr) \
338 __auto_type impl_fhm_key = key; \
339 struct ccc_fhash_entry impl_fhm_try_ins_ent = ccc_impl_fhm_entry( \
340 impl_flat_hash_map_ptr, (void *)&impl_fhm_key); \
341 if ((impl_fhm_try_ins_ent.handle.stats & CCC_ENTRY_OCCUPIED) \
342 || (impl_fhm_try_ins_ent.handle.stats \
343 & CCC_ENTRY_INSERT_ERROR)) \
345 impl_fhm_try_insert_res = (struct ccc_ent){ \
346 .e = ccc_impl_fhm_data_at(impl_fhm_try_ins_ent.h, \
347 impl_fhm_try_ins_ent.handle.i), \
348 .stats = impl_fhm_try_ins_ent.handle.stats, \
353 impl_fhm_try_insert_res = (struct ccc_ent){ \
354 .e = ccc_impl_fhm_data_at(impl_fhm_try_ins_ent.h, \
355 impl_fhm_try_ins_ent.handle.i), \
356 .stats = CCC_ENTRY_VACANT, \
358 *((typeof(lazy_value) *)impl_fhm_try_insert_res.e) \
360 *((typeof(impl_fhm_key) *)ccc_impl_fhm_key_at( \
361 impl_fhm_try_ins_ent.h, impl_fhm_try_ins_ent.handle.i)) \
363 ccc_impl_fhm_set_insert(&impl_fhm_try_ins_ent); \
366 impl_fhm_try_insert_res; \
373#define ccc_impl_fhm_insert_or_assign_w(flat_hash_map_ptr, key, lazy_value...) \
375 struct ccc_fhmap *impl_flat_hash_map_ptr = (flat_hash_map_ptr); \
376 struct ccc_ent impl_fhm_insert_or_assign_res \
377 = {.stats = CCC_ENTRY_ARG_ERROR}; \
378 if (impl_flat_hash_map_ptr) \
380 impl_fhm_insert_or_assign_res.stats = CCC_ENTRY_INSERT_ERROR; \
381 __auto_type impl_fhm_key = key; \
382 struct ccc_fhash_entry impl_fhm_ins_or_assign_ent \
383 = ccc_impl_fhm_entry(impl_flat_hash_map_ptr, \
384 (void *)&impl_fhm_key); \
385 if (!(impl_fhm_ins_or_assign_ent.handle.stats \
386 & CCC_ENTRY_INSERT_ERROR)) \
388 impl_fhm_insert_or_assign_res = (struct ccc_ent){ \
389 .e = ccc_impl_fhm_data_at( \
390 impl_fhm_ins_or_assign_ent.h, \
391 impl_fhm_ins_or_assign_ent.handle.i), \
392 .stats = impl_fhm_ins_or_assign_ent.handle.stats, \
394 *((typeof(lazy_value) *)impl_fhm_insert_or_assign_res.e) \
396 *((typeof(impl_fhm_key) *)ccc_impl_fhm_key_at( \
397 impl_fhm_ins_or_assign_ent.h, \
398 impl_fhm_ins_or_assign_ent.handle.i)) \
400 if (impl_fhm_ins_or_assign_ent.handle.stats \
401 == CCC_ENTRY_VACANT) \
403 ccc_impl_fhm_set_insert(&impl_fhm_ins_or_assign_ent); \
407 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:65
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