33#if defined(__cplusplus)
41#define HASHSET_DEFAULT_CAPACITY 16u
42#define HASHSET_LOAD_FACTOR 0.75
45#define _HS_EMPTY 0x00u
46#define _HS_DELETED 0x01u
48#define _HS_FINGERPRINT(h) (uint8_t)(((h) >> 7) | 0x02u)
61 uint64_t (*hash_fn)(
const void* key,
size_t key_size);
64 bool (*equals_fn)(
const void* a,
const void* b,
size_t key_size);
71static inline uint64_t hashset_default_hash(
const void* key,
size_t key_size) {
72 const uint64_t FNV_OFFSET = 14695981039346656037ULL;
73 const uint64_t FNV_PRIME = 1099511628211ULL;
74 uint64_t hash = FNV_OFFSET;
75 const unsigned char* bytes = (
const unsigned char*)key;
76 for (
size_t i = 0; i < key_size; i++) {
83static inline bool hashset_default_equals(
const void* a,
const void* b,
size_t ks) {
return memcmp(a, b, ks) == 0; }
86static inline size_t _hs_slot(
size_t base,
size_t i,
size_t mask) {
return (base + i) & mask; }
89static inline void* _hs_key(
const hashset_t* s,
size_t idx) {
return (
void*)(s->keys + idx * s->key_size); }
91static inline hashset_t* hashset_create(
size_t key_size,
size_t initial_capacity,
92 uint64_t (*hash_fn)(
const void*,
size_t),
93 bool (*equals_fn)(
const void*,
const void*,
size_t)) {
94 if (key_size == 0)
return NULL;
97 size_t cap = HASHSET_DEFAULT_CAPACITY;
98 while (cap < initial_capacity) cap <<= 1;
100 hashset_t* set = (hashset_t*)malloc(
sizeof(hashset_t));
101 if (!set)
return NULL;
103 set->meta = (uint8_t*)calloc(cap,
sizeof(uint8_t));
104 set->keys = (
char*)malloc(cap * key_size);
106 if (!set->meta || !set->keys) {
115 set->key_size = key_size;
116 set->hash_fn = hash_fn ? hash_fn : hashset_default_hash;
117 set->equals_fn = equals_fn ? equals_fn : hashset_default_equals;
121static inline void hashset_destroy(hashset_t* set) {
135static inline bool hashset_contains(
const hashset_t* set,
const void* key) {
136 if (!set || !key)
return false;
138 const uint64_t hash = set->hash_fn(key, set->key_size);
139 const size_t mask = set->capacity - 1;
140 const uint8_t fp = _HS_FINGERPRINT(hash);
141 size_t idx = (size_t)(hash & mask);
143 for (
size_t i = 0; i < set->capacity; i++) {
144 const uint8_t m = set->meta[idx];
146 if (m == _HS_EMPTY)
return false;
150 if (m != _HS_DELETED && m == fp && set->equals_fn(_hs_key(set, idx), key, set->key_size))
return true;
152 idx = _hs_slot(idx, 1, mask);
161static inline bool _hs_rehash(hashset_t* set,
size_t new_cap) {
162 uint8_t* new_meta = (uint8_t*)calloc(new_cap,
sizeof(uint8_t));
163 char* new_keys = (
char*)malloc(new_cap * set->key_size);
164 if (!new_meta || !new_keys) {
170 const size_t mask = new_cap - 1;
172 for (
size_t i = 0; i < set->capacity; i++) {
173 if (set->meta[i] < 0x02u)
continue;
175 const void* k = _hs_key(set, i);
176 const uint64_t h = set->hash_fn(k, set->key_size);
177 const uint8_t fp = _HS_FINGERPRINT(h);
178 size_t idx = (size_t)(h & mask);
181 while (new_meta[idx] != _HS_EMPTY) idx = (idx + 1) & mask;
184 memcpy(new_keys + idx * set->key_size, k, set->key_size);
189 set->meta = new_meta;
190 set->keys = new_keys;
191 set->capacity = new_cap;
199static inline bool hashset_add(hashset_t* set,
const void* key) {
200 if (!set || !key)
return false;
203 if ((
double)(set->size + 1) / (
double)set->capacity > HASHSET_LOAD_FACTOR) {
204 if (!_hs_rehash(set, set->capacity * 2))
return false;
207 const uint64_t hash = set->hash_fn(key, set->key_size);
208 const size_t mask = set->capacity - 1;
209 const uint8_t fp = _HS_FINGERPRINT(hash);
210 size_t idx = (size_t)(hash & mask);
211 size_t first_del = SIZE_MAX;
213 for (
size_t i = 0; i < set->capacity; i++) {
214 const uint8_t m = set->meta[idx];
216 if (m == _HS_EMPTY) {
218 size_t ins = (first_del != SIZE_MAX) ? first_del : idx;
220 memcpy(_hs_key(set, ins), key, set->key_size);
225 if (m == _HS_DELETED) {
226 if (first_del == SIZE_MAX) first_del = idx;
227 }
else if (m == fp && set->equals_fn(_hs_key(set, idx), key, set->key_size)) {
231 idx = _hs_slot(idx, 1, mask);
235 if (first_del != SIZE_MAX) {
236 set->meta[first_del] = fp;
237 memcpy(_hs_key(set, first_del), key, set->key_size);
252static inline bool hashset_remove(hashset_t* set,
const void* key) {
253 if (!set || !key)
return false;
255 const uint64_t hash = set->hash_fn(key, set->key_size);
256 const size_t mask = set->capacity - 1;
257 const uint8_t fp = _HS_FINGERPRINT(hash);
258 size_t idx = (size_t)(hash & mask);
261 size_t pos = SIZE_MAX;
262 for (
size_t i = 0; i < set->capacity; i++) {
263 const uint8_t m = set->meta[idx];
264 if (m == _HS_EMPTY)
return false;
265 if (m != _HS_DELETED && m == fp && set->equals_fn(_hs_key(set, idx), key, set->key_size)) {
269 idx = _hs_slot(idx, 1, mask);
271 if (pos == SIZE_MAX)
return false;
300 size_t scan = (pos + 1) & mask;
302 for (
size_t i = 0; i < set->capacity - 1; i++, scan = (scan + 1) & mask) {
303 if (set->meta[scan] < 0x02u)
break;
305 uint64_t sh = set->hash_fn(_hs_key(set, scan), set->key_size);
306 size_t s_nat = (size_t)(sh & mask);
307 size_t d_scan = (scan - s_nat) & mask;
308 size_t d_hole = (hole - s_nat) & mask;
310 if (d_hole < d_scan) {
311 set->meta[hole] = set->meta[scan];
312 memcpy(_hs_key(set, hole), _hs_key(set, scan), set->key_size);
318 set->meta[hole] = _HS_EMPTY;
327static inline size_t hashset_size(
const hashset_t* s) {
return s ? s->size : 0; }
328static inline size_t hashset_capacity(
const hashset_t* s) {
return s ? s->capacity : 0; }
329static inline bool hashset_isempty(
const hashset_t* s) {
return !s || s->size == 0; }
331static inline void hashset_clear(hashset_t* set) {
333 memset(set->meta, 0, set->capacity);
341static inline hashset_t* hashset_union(
const hashset_t* A,
const hashset_t* B) {
342 if (!A || !B || A->key_size != B->key_size)
return NULL;
343 hashset_t* r = hashset_create(A->key_size, A->size + B->size, A->hash_fn, A->equals_fn);
345 for (
size_t i = 0; i < A->capacity; i++)
346 if (A->meta[i] >= 0x02u) hashset_add(r, _hs_key(A, i));
347 for (
size_t i = 0; i < B->capacity; i++)
348 if (B->meta[i] >= 0x02u) hashset_add(r, _hs_key(B, i));
352static inline hashset_t* hashset_intersection(
const hashset_t* A,
const hashset_t* B) {
353 if (!A || !B || A->key_size != B->key_size)
return NULL;
354 const hashset_t* small = A->size <= B->size ? A : B;
355 const hashset_t* large = A->size <= B->size ? B : A;
356 hashset_t* r = hashset_create(A->key_size, small->size, A->hash_fn, A->equals_fn);
358 for (
size_t i = 0; i < small->capacity; i++)
359 if (small->meta[i] >= 0x02u && hashset_contains(large, _hs_key(small, i))) hashset_add(r, _hs_key(small, i));
363static inline hashset_t* hashset_difference(
const hashset_t* A,
const hashset_t* B) {
364 if (!A || !B || A->key_size != B->key_size)
return NULL;
365 hashset_t* r = hashset_create(A->key_size, A->size, A->hash_fn, A->equals_fn);
367 for (
size_t i = 0; i < A->capacity; i++)
368 if (A->meta[i] >= 0x02u && !hashset_contains(B, _hs_key(A, i))) hashset_add(r, _hs_key(A, i));
372static inline hashset_t* hashset_symmetric_difference(
const hashset_t* A,
const hashset_t* B) {
373 if (!A || !B || A->key_size != B->key_size)
return NULL;
374 hashset_t* r = hashset_create(A->key_size, A->size + B->size, A->hash_fn, A->equals_fn);
376 for (
size_t i = 0; i < A->capacity; i++)
377 if (A->meta[i] >= 0x02u && !hashset_contains(B, _hs_key(A, i))) hashset_add(r, _hs_key(A, i));
378 for (
size_t i = 0; i < B->capacity; i++)
379 if (B->meta[i] >= 0x02u && !hashset_contains(A, _hs_key(B, i))) hashset_add(r, _hs_key(B, i));
383static inline bool hashset_is_subset(
const hashset_t* A,
const hashset_t* B) {
384 if (!A || !B || A->key_size != B->key_size)
return false;
385 if (A->size > B->size)
return false;
386 for (
size_t i = 0; i < A->capacity; i++)
387 if (A->meta[i] >= 0x02u && !hashset_contains(B, _hs_key(A, i)))
return false;
391static inline bool hashset_is_proper_subset(
const hashset_t* A,
const hashset_t* B) {
392 if (!A || !B)
return false;
393 return A->size < B->size && hashset_is_subset(A, B);
396#if defined(__cplusplus)