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#ifdef CCC_HAS_X86_SIMD 
   76    CCC_FHM_GROUP_SIZE = 16,
 
   77#elifdef 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:309
 
ccc_tribool ccc_any_key_eq_fn(ccc_any_key_cmp)
A callback function to determining equality between two stored keys.
Definition: types.h:352
 
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:365