42#define restrict __restrict__
60#define PASTE(a, b) a##b
68#define XPASTE(a, b) PASTE(a, b)
76#define JOIN(a, b) XPASTE(a, XPASTE(_, b))
87#define IS_POW2(X) ((X) != 0 && ((X) & ((X) - 1)) == 0)
94#ifndef FHASHTABLE_EMPTY_SLOT_OFFSET
95#define FHASHTABLE_EMPTY_SLOT_OFFSET (UINT32_MAX)
110#ifndef FHASHTABLE_FOR_EACH
111#define FHASHTABLE_FOR_EACH(self, index, key_, value_) \
112 for ((index) = 0; (index) < (self)->capacity; (index)++) \
113 if ((self)->slots[(index)].offset != FHASHTABLE_EMPTY_SLOT_OFFSET \
114 && ((key_) = (self)->slots[(index)].key, (value_) = (self)->slots[(index)].value, true))
127#ifndef FHASHTABLE_CALC_SIZEOF
128#define FHASHTABLE_CALC_SIZEOF(fhashtable_name, capacity) \
129 (uint32_t)(offsetof(struct fhashtable_name, slots) + capacity * sizeof(((struct fhashtable_name *)0)->slots[0]))
142#ifndef FHASHTABLE_CALC_SIZEOF_OVERFLOWS
143#define FHASHTABLE_CALC_SIZEOF_OVERFLOWS(fhashtable_name, capacity) \
145 > (UINT32_MAX - offsetof(struct fhashtable_name, slots)) / sizeof(((struct fhashtable_name *)0)->slots[0]))
156#error "Must define NAME."
158#define FHASHTABLE_NAME NAME
170#define FUNCTION_DEFINITIONS
171#define TYPE_DEFINITIONS
172#error "Must define KEY_TYPE."
183#define VALUE_TYPE int
184#error "Must define VALUE_TYPE."
191#ifndef FUNCTION_LINKAGE
192#define FUNCTION_LINKAGE
196#define FHASHTABLE_TYPE struct FHASHTABLE_NAME
197#define FHASHTABLE_SLOT_TYPE struct JOIN(FHASHTABLE_NAME, slot)
198#define FHASHTABLE_SLOT JOIN(FHASHTABLE_NAME, slot)
199#define FHASHTABLE_INIT JOIN(FHASHTABLE_NAME, init)
200#define FHASHTABLE_IS_FULL JOIN(FHASHTABLE_NAME, is_full)
201#define FHASHTABLE_CONTAINS_KEY JOIN(FHASHTABLE_NAME, contains_key)
202#define FHASHTABLE_SWAP_SLOTS JOIN(internal, JOIN(FHASHTABLE_NAME, swap_slots))
203#define FHASHTABLE_BACKSHIFT JOIN(internal, JOIN(FHASHTABLE_NAME, backshift))
210struct JOIN(FHASHTABLE_NAME, slot);
211struct FHASHTABLE_NAME;
217#ifdef TYPE_DEFINITIONS
223struct JOIN(FHASHTABLE_NAME, slot) {
233struct FHASHTABLE_NAME {
251FUNCTION_LINKAGE FHASHTABLE_TYPE *
JOIN(FHASHTABLE_NAME, init)(FHASHTABLE_TYPE *self,
const uint32_t pow2_capacity);
267 JOIN(FHASHTABLE_NAME, create_custom)(
const uint32_t min_capacity,
void *context_ptr,
268 void *(*allocate)(
void *context_ptr,
size_t alignment,
size_t size));
293FUNCTION_LINKAGE void JOIN(FHASHTABLE_NAME, destroy_custom)(FHASHTABLE_TYPE *self,
void *context_ptr,
294 void (*deallocate)(
void *context_ptr,
void *mem));
424 const FHASHTABLE_TYPE *restrict src_ptr);
434#ifdef FUNCTION_DEFINITIONS
441#include "round_up_pow2_32.h"
461#error "Must define KEY_IS_EQUAL."
462#define KEY_IS_EQUAL(a, b) ((a) == (b))
476#error "Must define HASH_FUNCTION."
477#define HASH_FUNCTION(key) (0)
480FUNCTION_LINKAGE FHASHTABLE_TYPE *
JOIN(FHASHTABLE_NAME, init)(FHASHTABLE_TYPE *self,
const uint32_t pow2_capacity)
483 assert(
IS_POW2(pow2_capacity));
486 self->capacity = pow2_capacity;
488 for (uint32_t i = 0; i < self->capacity; i++) {
495FUNCTION_LINKAGE FHASHTABLE_TYPE *
JOIN(FHASHTABLE_NAME, create_custom)(
const uint32_t min_capacity,
void *context_ptr,
496 void *(*allocate)(
void *context_ptr,
497 size_t alignment,
size_t size))
499 if (min_capacity == 0 || min_capacity > UINT32_MAX / 2 + 1) {
503 const uint32_t capacity = round_up_pow2_32(min_capacity);
511 FHASHTABLE_TYPE *self = (FHASHTABLE_TYPE *)allocate(context_ptr,
alignof(FHASHTABLE_TYPE), size);
517 memset(self, 0, size);
518 FHASHTABLE_INIT(self, capacity);
524static inline void *
JOIN(internal,
JOIN(FHASHTABLE_NAME, allocate))(
void *context_ptr,
size_t alignment,
size_t size)
534 return JOIN(FHASHTABLE_NAME, create_custom)(capacity, NULL,
JOIN(internal,
JOIN(FHASHTABLE_NAME, allocate)));
538 void (*deallocate)(
void *context_ptr,
void *mem))
540 assert(self != NULL);
542 deallocate(context_ptr, self);
546static inline void JOIN(internal,
JOIN(FHASHTABLE_NAME, deallocate))(
void *context_ptr,
void *mem)
555 assert(self != NULL);
557 JOIN(FHASHTABLE_NAME, destroy_custom)(self, NULL,
JOIN(internal,
JOIN(FHASHTABLE_NAME, deallocate)));
562 assert(self != NULL);
564 return self->count == 0;
569 assert(self != NULL);
571 return self->count == self->capacity;
576 assert(self != NULL);
579 const uint32_t index_mask = self->capacity - 1;
581 uint32_t index = key_hash & index_mask;
582 uint32_t max_possible_offset = 0;
587 const bool below_max = max_possible_offset <= self->slots[index].offset;
589 if (!(not_empty && below_max)) {
599 max_possible_offset++;
606 assert(self != NULL);
609 const uint32_t index_mask = self->capacity - 1;
611 uint32_t index = key_hash & index_mask;
612 uint32_t max_possible_offset = 0;
617 const bool below_max = max_possible_offset <= self->slots[index].offset;
619 if (!(not_empty && below_max)) {
624 return &self->slots[index].value;
629 max_possible_offset++;
637 assert(self != NULL);
640 const uint32_t index_mask = self->capacity - 1;
642 uint32_t index = key_hash & index_mask;
643 uint32_t max_possible_offset = 0;
648 const bool below_max = max_possible_offset <= self->slots[index].offset;
650 if (!(not_empty && below_max)) {
655 return self->slots[index].value;
660 max_possible_offset++;
662 return default_value;
667 return JOIN(FHASHTABLE_NAME, get_value_mut)(self, key);
671static inline void JOIN(internal,
JOIN(FHASHTABLE_NAME, swap_slots))(FHASHTABLE_SLOT_TYPE *a, FHASHTABLE_SLOT_TYPE *b)
673 FHASHTABLE_SLOT_TYPE temp = *a;
681 assert(self != NULL);
682 assert(FHASHTABLE_CONTAINS_KEY(self, key) ==
false);
684 const uint32_t index_mask = self->capacity - 1;
687 uint32_t index = key_hash & index_mask;
688 FHASHTABLE_SLOT_TYPE current_slot = {.offset = 0, .key = key, .value = value};
697 if (current_slot.offset > self->slots[index].offset) {
698 FHASHTABLE_SWAP_SLOTS(&self->slots[index], ¤t_slot);
703 current_slot.offset++;
705 self->slots[index] = current_slot;
711 assert(self != NULL);
713 const uint32_t index_mask = self->capacity - 1;
716 uint32_t index = key_hash & index_mask;
717 FHASHTABLE_SLOT_TYPE current_slot = {.offset = 0, .key = key, .value = value};
726 const bool offset_is_same = current_slot.offset == self->slots[index].offset;
728 const bool key_is_equal =
KEY_IS_EQUAL(current_slot.key, self->slots[index].key);
730 if (offset_is_same && key_is_equal) {
731 self->slots[index].value = current_slot.value;
735 if (current_slot.offset > self->slots[index].offset) {
736 FHASHTABLE_SWAP_SLOTS(¤t_slot, &self->slots[index]);
741 current_slot.offset++;
744 self->slots[index] = current_slot;
749static inline void JOIN(internal,
JOIN(FHASHTABLE_NAME, backshift))(FHASHTABLE_TYPE *self,
const uint32_t index_mask,
754 uint32_t next_index = (index + 1) & index_mask;
759 const bool offset_is_non_zero = self->slots[next_index].offset > 0;
761 if (!(not_empty && offset_is_non_zero)) {
765 self->slots[index] = self->slots[next_index];
766 self->slots[index].offset--;
771 next_index = (index + 1) & index_mask;
778 assert(self != NULL);
780 const uint32_t index_mask = self->capacity - 1;
783 uint32_t index = key_hash & index_mask;
784 uint32_t max_possible_offset = 0;
789 const bool below_max = max_possible_offset <= self->slots[index].offset;
791 if (!(not_empty && below_max)) {
795 const bool key_is_equal =
KEY_IS_EQUAL(key, self->slots[index].key);
798 index = (index + 1) & index_mask;
799 max_possible_offset++;
806 FHASHTABLE_BACKSHIFT(self, index_mask, index);
815 assert(self != NULL);
817 for (uint32_t i = 0; i < self->capacity; i++) {
824 const FHASHTABLE_TYPE *restrict src_ptr)
826 assert(src_ptr != NULL);
827 assert(dest_ptr != NULL);
828 assert(src_ptr->capacity <= dest_ptr->capacity);
829 assert(dest_ptr->count == 0);
836 JOIN(FHASHTABLE_NAME, insert)(dest_ptr, key, value);
851#undef FUNCTION_LINKAGE
852#undef FUNCTION_DEFINITIONS
853#undef TYPE_DEFINITIONS
855#undef FHASHTABLE_NAME
856#undef FHASHTABLE_TYPE
857#undef FHASHTABLE_SLOT_TYPE
858#undef FHASHTABLE_INIT
859#undef FHASHTABLE_IS_FULL
860#undef FHASHTABLE_CONTAINS_KEY
861#undef FHASHTABLE_CALC_SIZEOF
862#undef FHASHTABLE_SWAP_SLOTS
863#undef FHASHTABLE_BACKSHIFT
#define FHASHTABLE_CALC_SIZEOF(fhashtable_name, capacity)
Calculate the size of the hashtable struct. No overflow checks.
Definition fhashtable_template.h:128
#define JOIN(a, b)
First expand tokens, then paste them together with a _ in between.
Definition fhashtable_template.h:76
#define HASH_FUNCTION(key)
Used to compute indicies of keys. This must be manually defined before including this header file.
Definition fhashtable_template.h:477
#define IS_POW2(X)
Macro to check if a number is a power of two.
Definition fhashtable_template.h:87
#define KEY_IS_EQUAL(a, b)
Used to compare two keys This must be manually defined before including this header file.
Definition fhashtable_template.h:462
#define FHASHTABLE_CALC_SIZEOF_OVERFLOWS(fhashtable_name, capacity)
Check for a given capacity, if the equivalent size of the hashtable struct overflows.
Definition fhashtable_template.h:143
#define FHASHTABLE_EMPTY_SLOT_OFFSET
Offset constant used to flag empty slots.
Definition fhashtable_template.h:95
#define FHASHTABLE_FOR_EACH(self, index, key_, value_)
Iterate over the non-empty slots in the hashtable in arbitary order.
Definition fhashtable_template.h:111
#define VALUE_TYPE
The value type. This must be manually defined before including this header file.
Definition fhashtable_template.h:183
#define KEY_TYPE
The key type. This must be manually defined before including this header file.
Definition fhashtable_template.h:169
#define FUNCTION_LINKAGE
Specify function linkage e.g. static inline.
Definition fstack_template.h:146
#define JOIN(a, b)
First expand tokens, then paste them together with a _ in between.
Definition fstack_template.h:50
#define VALUE_TYPE
Stack value type. This must be manually defined before including this header file.
Definition fstack_template.h:135
uint32_t offset
Offset from the ideal slot index.
Definition fhashtable_template.h:224
VALUE_TYPE value
The value in this slot.
Definition fhashtable_template.h:226
KEY_TYPE key
The key in this slot.
Definition fhashtable_template.h:225
fhashtable_slot_type slots[]
Array of slots.
Definition fhashtable_template.h:236
uint32_t count
Number of non-empty slots.
Definition fhashtable_template.h:234
uint32_t capacity
Number of slots.
Definition fhashtable_template.h:235