37#define restrict __restrict__
57#define PASTE(a, b) a##b
65#define XPASTE(a, b) PASTE(a, b)
73#define JOIN(a, b) XPASTE(a, XPASTE(_, b))
84#define IS_POW2(X) ((X) != 0 && ((X) & ((X) - 1)) == 0)
91#ifndef FHASHTABLE_EMPTY_SLOT_OFFSET
92#define FHASHTABLE_EMPTY_SLOT_OFFSET (UINT32_MAX)
107#ifndef FHASHTABLE_FOR_EACH
108#define FHASHTABLE_FOR_EACH(self, index, key_, value_) \
109 for ((index) = 0; (index) < (self)->capacity; (index)++) \
110 if ((self)->slots[(index)].offset != FHASHTABLE_EMPTY_SLOT_OFFSET \
111 && ((key_) = (self)->slots[(index)].key, (value_) = (self)->slots[(index)].value, true))
124#ifndef FHASHTABLE_CALC_SIZEOF
125#define FHASHTABLE_CALC_SIZEOF(fhashtable_name, capacity) \
126 (uint32_t)(offsetof(struct fhashtable_name, slots) + capacity * sizeof(((struct fhashtable_name *)0)->slots[0]))
139#ifndef FHASHTABLE_CALC_SIZEOF_OVERFLOWS
140#define FHASHTABLE_CALC_SIZEOF_OVERFLOWS(fhashtable_name, capacity) \
142 > (UINT32_MAX - offsetof(struct fhashtable_name, slots)) / sizeof(((struct fhashtable_name *)0)->slots[0]))
153#error "Must define NAME."
155#define FHASHTABLE_NAME NAME
167#define FUNCTION_DEFINITIONS
168#define TYPE_DEFINITIONS
169#error "Must define KEY_TYPE."
180#define VALUE_TYPE int
181#error "Must define VALUE_TYPE."
202#error "Must define KEY_IS_EQUAL."
203#define KEY_IS_EQUAL(a, b) ((a) == (b))
217#error "Must define HASH_FUNCTION."
218#define HASH_FUNCTION(key) (0)
225#ifndef FUNCTION_LINKAGE
226#define FUNCTION_LINKAGE
230#define FHASHTABLE_TYPE struct FHASHTABLE_NAME
231#define FHASHTABLE_SLOT_TYPE struct JOIN(FHASHTABLE_NAME, slot)
232#define FHASHTABLE_SLOT JOIN(FHASHTABLE_NAME, slot)
233#define FHASHTABLE_INIT JOIN(FHASHTABLE_NAME, init)
234#define FHASHTABLE_IS_FULL JOIN(FHASHTABLE_NAME, is_full)
235#define FHASHTABLE_CONTAINS_KEY JOIN(FHASHTABLE_NAME, contains_key)
236#define FHASHTABLE_SWAP_SLOTS JOIN(internal, JOIN(FHASHTABLE_NAME, swap_slots))
237#define FHASHTABLE_BACKSHIFT JOIN(internal, JOIN(FHASHTABLE_NAME, backshift))
248#ifdef TYPE_DEFINITIONS
254struct JOIN(FHASHTABLE_NAME, slot) {
264struct FHASHTABLE_NAME {
282FUNCTION_LINKAGE FHASHTABLE_TYPE *
JOIN(FHASHTABLE_NAME, init)(FHASHTABLE_TYPE *self,
const uint32_t pow2_capacity);
425 const FHASHTABLE_TYPE *restrict src_ptr);
435#ifdef FUNCTION_DEFINITIONS
437#include "round_up_pow2_32.h"
439FUNCTION_LINKAGE FHASHTABLE_TYPE *
JOIN(FHASHTABLE_NAME, init)(FHASHTABLE_TYPE *self,
const uint32_t pow2_capacity)
442 assert(
IS_POW2(pow2_capacity));
445 self->capacity = pow2_capacity;
447 for (uint32_t i = 0; i < self->capacity; i++) {
456 if (min_capacity == 0 || min_capacity > UINT32_MAX / 2 + 1) {
460 const uint32_t capacity = round_up_pow2_32(min_capacity);
468 FHASHTABLE_TYPE *self = (FHASHTABLE_TYPE *)calloc(1, size);
474 FHASHTABLE_INIT(self, capacity);
488 assert(self != NULL);
490 return self->count == 0;
495 assert(self != NULL);
497 return self->count == self->capacity;
502 assert(self != NULL);
505 const uint32_t index_mask = self->capacity - 1;
507 uint32_t index = key_hash & index_mask;
508 uint32_t max_possible_offset = 0;
513 const bool below_max = max_possible_offset <= self->slots[index].offset;
515 if (!(not_empty && below_max)) {
525 max_possible_offset++;
532 assert(self != NULL);
535 const uint32_t index_mask = self->capacity - 1;
537 uint32_t index = key_hash & index_mask;
538 uint32_t max_possible_offset = 0;
543 const bool below_max = max_possible_offset <= self->slots[index].offset;
545 if (!(not_empty && below_max)) {
550 return &self->slots[index].value;
555 max_possible_offset++;
563 assert(self != NULL);
566 const uint32_t index_mask = self->capacity - 1;
568 uint32_t index = key_hash & index_mask;
569 uint32_t max_possible_offset = 0;
574 const bool below_max = max_possible_offset <= self->slots[index].offset;
576 if (!(not_empty && below_max)) {
581 return self->slots[index].value;
586 max_possible_offset++;
588 return default_value;
593 return JOIN(FHASHTABLE_NAME, get_value_mut)(self, key);
597static inline void JOIN(internal,
JOIN(FHASHTABLE_NAME, swap_slots))(FHASHTABLE_SLOT_TYPE *a, FHASHTABLE_SLOT_TYPE *b)
599 FHASHTABLE_SLOT_TYPE temp = *a;
607 assert(self != NULL);
608 assert(FHASHTABLE_CONTAINS_KEY(self, key) ==
false);
610 const uint32_t index_mask = self->capacity - 1;
613 uint32_t index = key_hash & index_mask;
614 FHASHTABLE_SLOT_TYPE current_slot = {.offset = 0, .key = key, .value = value};
623 if (current_slot.offset > self->slots[index].offset) {
624 FHASHTABLE_SWAP_SLOTS(&self->slots[index], ¤t_slot);
629 current_slot.offset++;
631 self->slots[index] = current_slot;
637 assert(self != NULL);
639 const uint32_t index_mask = self->capacity - 1;
642 uint32_t index = key_hash & index_mask;
643 FHASHTABLE_SLOT_TYPE current_slot = {.offset = 0, .key = key, .value = value};
652 const bool offset_is_same = current_slot.offset == self->slots[index].offset;
654 const bool key_is_equal =
KEY_IS_EQUAL(current_slot.key, self->slots[index].key);
656 if (offset_is_same && key_is_equal) {
657 self->slots[index].value = current_slot.value;
661 if (current_slot.offset > self->slots[index].offset) {
662 FHASHTABLE_SWAP_SLOTS(¤t_slot, &self->slots[index]);
667 current_slot.offset++;
670 self->slots[index] = current_slot;
675static inline void JOIN(internal,
JOIN(FHASHTABLE_NAME, backshift))(FHASHTABLE_TYPE *self,
const uint32_t index_mask,
680 uint32_t next_index = (index + 1) & index_mask;
685 const bool offset_is_non_zero = self->slots[next_index].offset > 0;
687 if (!(not_empty && offset_is_non_zero)) {
691 self->slots[index] = self->slots[next_index];
692 self->slots[index].offset--;
697 next_index = (index + 1) & index_mask;
704 assert(self != NULL);
706 const uint32_t index_mask = self->capacity - 1;
709 uint32_t index = key_hash & index_mask;
710 uint32_t max_possible_offset = 0;
715 const bool below_max = max_possible_offset <= self->slots[index].offset;
717 if (!(not_empty && below_max)) {
721 const bool key_is_equal =
KEY_IS_EQUAL(key, self->slots[index].key);
724 index = (index + 1) & index_mask;
725 max_possible_offset++;
732 FHASHTABLE_BACKSHIFT(self, index_mask, index);
741 assert(self != NULL);
743 for (uint32_t i = 0; i < self->capacity; i++) {
750 const FHASHTABLE_TYPE *restrict src_ptr)
752 assert(src_ptr != NULL);
753 assert(dest_ptr != NULL);
754 assert(src_ptr->capacity <= dest_ptr->capacity);
755 assert(dest_ptr->count == 0);
761 JOIN(FHASHTABLE_NAME, insert)(dest_ptr, key, value);
776#undef FUNCTION_LINKAGE
777#undef FUNCTION_DEFINITIONS
778#undef TYPE_DEFINITIONS
780#undef FHASHTABLE_NAME
781#undef FHASHTABLE_TYPE
782#undef FHASHTABLE_SLOT_TYPE
783#undef FHASHTABLE_INIT
784#undef FHASHTABLE_IS_FULL
785#undef FHASHTABLE_CONTAINS_KEY
786#undef FHASHTABLE_CALC_SIZEOF
787#undef FHASHTABLE_SWAP_SLOTS
788#undef FHASHTABLE_BACKSHIFT
#define FHASHTABLE_CALC_SIZEOF(fhashtable_name, capacity)
Calculate the size of the hashtable struct. No overflow checks.
Definition fhashtable_template.h:125
#define JOIN(a, b)
First expand tokens, then paste them together with a _ in between.
Definition fhashtable_template.h:73
#define HASH_FUNCTION(key)
Used to compute indicies of keys. This must be manually defined before including this header file.
Definition fhashtable_template.h:218
#define IS_POW2(X)
Macro to check if a number is a power of two.
Definition fhashtable_template.h:84
#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:203
#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:140
#define FHASHTABLE_EMPTY_SLOT_OFFSET
Offset constant used to flag empty slots.
Definition fhashtable_template.h:92
#define FHASHTABLE_FOR_EACH(self, index, key_, value_)
Iterate over the non-empty slots in the hashtable in arbitary order.
Definition fhashtable_template.h:108
#define VALUE_TYPE
The value type. This must be manually defined before including this header file.
Definition fhashtable_template.h:180
#define KEY_TYPE
The key type. This must be manually defined before including this header file.
Definition fhashtable_template.h:166
#define FUNCTION_LINKAGE
Specify function linkage e.g. static inline.
Definition fstack_template.h:146
#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:255
VALUE_TYPE value
The value in this slot.
Definition fhashtable_template.h:257
KEY_TYPE key
The key in this slot.
Definition fhashtable_template.h:256
fhashtable_slot_type slots[]
Array of slots.
Definition fhashtable_template.h:267
uint32_t count
Number of non-empty slots.
Definition fhashtable_template.h:265
uint32_t capacity
Number of slots.
Definition fhashtable_template.h:266