33#ifndef CCC_PRIVATE_FLAT_HASH_MAP_H
34#define CCC_PRIVATE_FLAT_HASH_MAP_H
44#include "private_types.h"
50#if defined(__x86_64) && defined(__SSE2__) \
51 && !defined(CCC_FLAT_HASH_MAP_PORTABLE)
55# define CCC_HAS_X86_SIMD
56#elif defined(__ARM_NEON__) && !defined(CCC_FLAT_HASH_MAP_PORTABLE)
60# define CCC_HAS_ARM_SIMD
93#ifdef CCC_HAS_X86_SIMD
96#elifdef CCC_HAS_ARM_SIMD
231#define CCC_private_flat_hash_map_declare_fixed(fixed_map_type_name, \
232 key_val_type_name, capacity) \
233 static_assert((capacity) > 0, \
234 "fixed size map must have capacity greater than 0"); \
236 (capacity) >= CCC_FLAT_HASH_MAP_GROUP_COUNT, \
237 "fixed size map must have capacity >= CCC_FLAT_HASH_MAP_GROUP_COUNT " \
238 "(8 or 16 depending on platform)"); \
239 static_assert(((capacity) & ((capacity) - 1)) == 0, \
240 "fixed size map must be a power of 2 capacity (32, 64, " \
241 "128, 256, etc.)"); \
244 key_val_type_name data[(capacity) + 1]; \
245 alignas(CCC_FLAT_HASH_MAP_GROUP_COUNT) struct CCC_Flat_hash_map_tag \
246 tag[(capacity) + CCC_FLAT_HASH_MAP_GROUP_COUNT]; \
247 }(fixed_map_type_name)
259#define CCC_private_flat_hash_map_fixed_capacity(fixed_map_type_name) \
260 (sizeof((fixed_map_type_name){}.tag) - CCC_FLAT_HASH_MAP_GROUP_COUNT)
278#define CCC_private_flat_hash_map_initialize( \
279 private_type_name, private_key_field, private_hash, private_key_compare, \
280 private_allocate, private_context_data, private_capacity, \
281 private_fixed_map_pointer) \
283 .data = (private_fixed_map_pointer), \
286 .remain = (((private_capacity) / (size_t)8) * (size_t)7), \
288 = (((private_capacity) > (size_t)0) ? ((private_capacity) - (size_t)1) \
290 .sizeof_type = sizeof(private_type_name), \
291 .key_offset = offsetof(private_type_name, private_key_field), \
292 .compare = (private_key_compare), \
293 .hash = (private_hash), \
294 .allocate = (private_allocate), \
295 .context = (private_context_data), \
299#define CCC_private_flat_hash_map_from( \
300 private_key_field, private_hash, private_key_compare, private_allocate, \
301 private_context_data, private_optional_cap, \
302 private_array_compound_literal...) \
304 typeof(*private_array_compound_literal) \
305 *private_flat_hash_map_initializer_list \
306 = private_array_compound_literal; \
307 struct CCC_Flat_hash_map private_map \
308 = CCC_private_flat_hash_map_initialize( \
309 typeof(*private_flat_hash_map_initializer_list), \
310 private_key_field, private_hash, private_key_compare, \
311 private_allocate, private_context_data, 0, NULL); \
312 size_t const private_n \
313 = sizeof(private_array_compound_literal) \
314 / sizeof(*private_flat_hash_map_initializer_list); \
315 size_t const private_cap = private_optional_cap; \
316 if (CCC_flat_hash_map_reserve( \
318 (private_n > private_cap ? private_n : private_cap), \
322 for (size_t i = 0; i < private_n; ++i) \
324 struct CCC_Flat_hash_map_entry private_ent \
325 = CCC_private_flat_hash_map_entry( \
328 *)&private_flat_hash_map_initializer_list[i] \
329 .private_key_field); \
330 *((typeof(*private_flat_hash_map_initializer_list) *) \
331 CCC_private_flat_hash_map_data_at(private_ent.map, \
332 private_ent.index)) \
333 = private_flat_hash_map_initializer_list[i]; \
334 if (private_ent.status == CCC_ENTRY_VACANT) \
336 CCC_private_flat_hash_map_set_insert(&private_ent); \
344#define CCC_private_flat_hash_map_with_capacity( \
345 private_type_name, private_key_field, private_hash, private_key_compare, \
346 private_allocate, private_context_data, private_cap) \
348 struct CCC_Flat_hash_map private_map \
349 = CCC_private_flat_hash_map_initialize( \
350 private_type_name, private_key_field, private_hash, \
351 private_key_compare, private_allocate, private_context_data, \
353 (void)CCC_flat_hash_map_reserve(&private_map, private_cap, \
359#define CCC_private_flat_hash_map_with_compound_literal( \
360 private_key_field, private_hash, private_key_compare, \
361 private_compound_literal) \
363 .data = &(private_compound_literal), \
366 .remain = ((CCC_private_flat_hash_map_fixed_capacity( \
367 typeof(private_compound_literal)) \
370 .mask = ((CCC_private_flat_hash_map_fixed_capacity( \
371 typeof(private_compound_literal)) \
373 ? (CCC_private_flat_hash_map_fixed_capacity( \
374 typeof(private_compound_literal)) \
377 .sizeof_type = sizeof(*(private_compound_literal.data)), \
379 = offsetof(typeof(*(private_compound_literal.data)), \
380 private_key_field), \
381 .compare = (private_key_compare), \
382 .hash = (private_hash), \
388#define CCC_private_flat_hash_map_with_context_compound_literal( \
389 private_key_field, private_hash, private_key_compare, private_context, \
390 private_compound_literal) \
392 .data = &(private_compound_literal), \
395 .remain = ((CCC_private_flat_hash_map_fixed_capacity( \
396 typeof(private_compound_literal)) \
399 .mask = ((CCC_private_flat_hash_map_fixed_capacity( \
400 typeof(private_compound_literal)) \
402 ? (CCC_private_flat_hash_map_fixed_capacity( \
403 typeof(private_compound_literal)) \
406 .sizeof_type = sizeof(*(private_compound_literal.data)), \
408 = offsetof(typeof(*(private_compound_literal.data)), \
409 private_key_field), \
410 .compare = (private_key_compare), \
411 .hash = (private_hash), \
413 .context = (private_context), \
417#define CCC_private_flat_hash_map_with_allocator( \
418 private_type_name, private_key_field, private_hash, private_key_compare, \
426 .sizeof_type = sizeof(private_type_name), \
427 .key_offset = offsetof(private_type_name, private_key_field), \
428 .compare = (private_key_compare), \
429 .hash = (private_hash), \
430 .allocate = (private_allocate), \
435#define CCC_private_flat_hash_map_with_context_allocator( \
436 private_type_name, private_key_field, private_hash, private_key_compare, \
437 private_allocate, private_context) \
444 .sizeof_type = sizeof(private_type_name), \
445 .key_offset = offsetof(private_type_name, private_key_field), \
446 .compare = (private_key_compare), \
447 .hash = (private_hash), \
448 .allocate = (private_allocate), \
449 .context = (private_context), \
457#define CCC_private_flat_hash_map_and_modify_with( \
458 Flat_hash_map_entry_pointer, type_name, closure_over_T...) \
460 __auto_type private_flat_hash_map_mod_ent_pointer \
461 = (Flat_hash_map_entry_pointer); \
462 struct CCC_Flat_hash_map_entry private_flat_hash_map_mod_with_ent \
463 = {.status = CCC_ENTRY_ARGUMENT_ERROR}; \
464 if (private_flat_hash_map_mod_ent_pointer) \
466 private_flat_hash_map_mod_with_ent \
467 = private_flat_hash_map_mod_ent_pointer->private; \
468 if (private_flat_hash_map_mod_with_ent.status \
469 & CCC_ENTRY_OCCUPIED) \
471 type_name *const T = CCC_private_flat_hash_map_data_at( \
472 private_flat_hash_map_mod_with_ent.map, \
473 private_flat_hash_map_mod_with_ent.index); \
480 private_flat_hash_map_mod_with_ent; \
487#define CCC_private_flat_hash_map_or_insert_with(Flat_hash_map_entry_pointer, \
488 type_compound_literal...) \
490 __auto_type private_flat_hash_map_or_ins_ent_pointer \
491 = (Flat_hash_map_entry_pointer); \
492 typeof(type_compound_literal) *private_flat_hash_map_or_ins_res \
494 if (private_flat_hash_map_or_ins_ent_pointer) \
496 if (!(private_flat_hash_map_or_ins_ent_pointer->private.status \
497 & CCC_ENTRY_INSERT_ERROR)) \
499 private_flat_hash_map_or_ins_res \
500 = CCC_private_flat_hash_map_data_at( \
501 private_flat_hash_map_or_ins_ent_pointer->private.map, \
502 private_flat_hash_map_or_ins_ent_pointer->private \
504 if (private_flat_hash_map_or_ins_ent_pointer->private.status \
505 == CCC_ENTRY_VACANT) \
507 *private_flat_hash_map_or_ins_res = type_compound_literal; \
508 CCC_private_flat_hash_map_set_insert( \
509 &private_flat_hash_map_or_ins_ent_pointer->private); \
513 private_flat_hash_map_or_ins_res; \
519#define CCC_private_flat_hash_map_insert_entry_with( \
520 Flat_hash_map_entry_pointer, type_compound_literal...) \
522 __auto_type private_flat_hash_map_ins_ent_pointer \
523 = (Flat_hash_map_entry_pointer); \
524 typeof(type_compound_literal) *private_flat_hash_map_ins_ent_res \
526 if (private_flat_hash_map_ins_ent_pointer) \
528 if (!(private_flat_hash_map_ins_ent_pointer->private.status \
529 & CCC_ENTRY_INSERT_ERROR)) \
531 private_flat_hash_map_ins_ent_res \
532 = CCC_private_flat_hash_map_data_at( \
533 private_flat_hash_map_ins_ent_pointer->private.map, \
534 private_flat_hash_map_ins_ent_pointer->private.index); \
535 *private_flat_hash_map_ins_ent_res = type_compound_literal; \
536 if (private_flat_hash_map_ins_ent_pointer->private.status \
537 == CCC_ENTRY_VACANT) \
539 CCC_private_flat_hash_map_set_insert( \
540 &private_flat_hash_map_ins_ent_pointer->private); \
544 private_flat_hash_map_ins_ent_res; \
550#define CCC_private_flat_hash_map_try_insert_with(flat_hash_map_pointer, key, \
551 type_compound_literal...) \
553 struct CCC_Flat_hash_map *private_flat_hash_map_pointer \
554 = (flat_hash_map_pointer); \
555 struct CCC_Entry private_flat_hash_map_try_insert_res \
556 = {.status = CCC_ENTRY_ARGUMENT_ERROR}; \
557 if (private_flat_hash_map_pointer) \
559 __auto_type private_flat_hash_map_key = key; \
560 struct CCC_Flat_hash_map_entry private_flat_hash_map_try_ins_ent \
561 = CCC_private_flat_hash_map_entry( \
562 private_flat_hash_map_pointer, \
563 (void *)&private_flat_hash_map_key); \
564 if ((private_flat_hash_map_try_ins_ent.status \
565 & CCC_ENTRY_OCCUPIED) \
566 || (private_flat_hash_map_try_ins_ent.status \
567 & CCC_ENTRY_INSERT_ERROR)) \
569 private_flat_hash_map_try_insert_res = (struct CCC_Entry){ \
570 .type = CCC_private_flat_hash_map_data_at( \
571 private_flat_hash_map_try_ins_ent.map, \
572 private_flat_hash_map_try_ins_ent.index), \
573 .status = private_flat_hash_map_try_ins_ent.status, \
578 private_flat_hash_map_try_insert_res = (struct CCC_Entry){ \
579 .type = CCC_private_flat_hash_map_data_at( \
580 private_flat_hash_map_try_ins_ent.map, \
581 private_flat_hash_map_try_ins_ent.index), \
582 .status = CCC_ENTRY_VACANT, \
584 *((typeof(type_compound_literal) *) \
585 private_flat_hash_map_try_insert_res.type) \
586 = type_compound_literal; \
587 *((typeof(private_flat_hash_map_key) *) \
588 CCC_private_flat_hash_map_key_at( \
589 private_flat_hash_map_try_ins_ent.map, \
590 private_flat_hash_map_try_ins_ent.index)) \
591 = private_flat_hash_map_key; \
592 CCC_private_flat_hash_map_set_insert( \
593 &private_flat_hash_map_try_ins_ent); \
596 private_flat_hash_map_try_insert_res; \
603#define CCC_private_flat_hash_map_insert_or_assign_with( \
604 flat_hash_map_pointer, key, type_compound_literal...) \
606 struct CCC_Flat_hash_map *private_flat_hash_map_pointer \
607 = (flat_hash_map_pointer); \
608 struct CCC_Entry private_flat_hash_map_insert_or_assign_res \
609 = {.status = CCC_ENTRY_ARGUMENT_ERROR}; \
610 if (private_flat_hash_map_pointer) \
612 private_flat_hash_map_insert_or_assign_res.status \
613 = CCC_ENTRY_INSERT_ERROR; \
614 __auto_type private_flat_hash_map_key = key; \
615 struct CCC_Flat_hash_map_entry \
616 private_flat_hash_map_ins_or_assign_ent \
617 = CCC_private_flat_hash_map_entry( \
618 private_flat_hash_map_pointer, \
619 (void *)&private_flat_hash_map_key); \
620 if (!(private_flat_hash_map_ins_or_assign_ent.status \
621 & CCC_ENTRY_INSERT_ERROR)) \
623 private_flat_hash_map_insert_or_assign_res \
624 = (struct CCC_Entry){ \
625 .type = CCC_private_flat_hash_map_data_at( \
626 private_flat_hash_map_ins_or_assign_ent.map, \
627 private_flat_hash_map_ins_or_assign_ent.index), \
629 = private_flat_hash_map_ins_or_assign_ent.status, \
631 *((typeof(type_compound_literal) *) \
632 private_flat_hash_map_insert_or_assign_res.type) \
633 = type_compound_literal; \
634 *((typeof(private_flat_hash_map_key) *) \
635 CCC_private_flat_hash_map_key_at( \
636 private_flat_hash_map_ins_or_assign_ent.map, \
637 private_flat_hash_map_ins_or_assign_ent.index)) \
638 = private_flat_hash_map_key; \
639 if (private_flat_hash_map_ins_or_assign_ent.status \
640 == CCC_ENTRY_VACANT) \
642 CCC_private_flat_hash_map_set_insert( \
643 &private_flat_hash_map_ins_or_assign_ent); \
647 private_flat_hash_map_insert_or_assign_res; \
void CCC_private_flat_hash_map_erase(struct CCC_Flat_hash_map *, size_t)
void CCC_private_flat_hash_map_insert(struct CCC_Flat_hash_map *, void const *, struct CCC_Flat_hash_map_tag, size_t)
struct CCC_Flat_hash_map_entry CCC_private_flat_hash_map_entry(struct CCC_Flat_hash_map *, void const *)
void * CCC_private_flat_hash_map_data_at(struct CCC_Flat_hash_map const *, size_t)
void * CCC_private_flat_hash_map_key_at(struct CCC_Flat_hash_map const *, size_t)
void CCC_private_flat_hash_map_set_insert(struct CCC_Flat_hash_map_entry const *)
enum @6 CCC_FLAT_HASH_MAP_GROUP_COUNT
Definition: private_flat_hash_map.h:172
size_t index
Definition: private_flat_hash_map.h:176
struct CCC_Flat_hash_map_tag tag
Definition: private_flat_hash_map.h:178
enum CCC_Entry_status status
Definition: private_flat_hash_map.h:180
struct CCC_Flat_hash_map * map
Definition: private_flat_hash_map.h:174
Definition: private_flat_hash_map.h:81
uint8_t v
Definition: private_flat_hash_map.h:83
Definition: private_flat_hash_map.h:144
CCC_Key_comparator * compare
Definition: private_flat_hash_map.h:160
void * context
Definition: private_flat_hash_map.h:166
size_t remain
Definition: private_flat_hash_map.h:152
struct CCC_Flat_hash_map_tag * tag
Definition: private_flat_hash_map.h:148
size_t sizeof_type
Definition: private_flat_hash_map.h:156
size_t key_offset
Definition: private_flat_hash_map.h:158
size_t mask
Definition: private_flat_hash_map.h:154
void * data
Definition: private_flat_hash_map.h:146
size_t count
Definition: private_flat_hash_map.h:150
CCC_Key_hasher * hash
Definition: private_flat_hash_map.h:162
CCC_Allocator * allocate
Definition: private_flat_hash_map.h:164
CCC_Order CCC_Key_comparator(CCC_Key_comparator_context)
A callback function for three-way comparing two stored keys.
Definition: types.h:383
void * CCC_Allocator(CCC_Allocator_context)
An allocation function at the core of all containers.
Definition: types.h:340
uint64_t CCC_Key_hasher(CCC_Key_context)
A callback function to hash the key type used in a container.
Definition: types.h:389
Definition: private_flat_hash_map.h:190
struct CCC_Flat_hash_map_entry private
Definition: private_flat_hash_map.h:192