Add hash set implementation
Release / release (push) Successful in 4s

This commit is contained in:
2026-09-23 22:34:23 +01:00
parent 20e890964f
commit 68640dc5e2
12 changed files with 590 additions and 44 deletions
+77 -33
View File
@@ -8,26 +8,62 @@
#include "../../../common/assert/assert.h"
#include "../../../common/misc/misc_utils.h"
wp_persist inline void hashTableValidate(const WpHashTable *table, u64 key_size, u64 value_size);
wp_persist inline void *hashTableGetKeyFromBucket(WpHashTable *table, WpHashBucket bucket, u64 key_size);
wp_persist inline void *hashTableGetValueFromBucket(WpHashTable *table, WpHashBucket bucket, u64 value_size);
wp_persist inline u64 hashTableGetDist(u64 dist_and_tag);
wp_persist inline u64 hashTableNextBucket(WpHashTable *table, u64 bucket_index);
wp_persist inline u64 hashTableDistInc(u64 dist_and_tag);
wp_persist inline u64 hashTableDistDec(u64 dist_and_tag);
wp_persist inline void hashTableValidate(const WpHashTable *table, u64 key_size, u64 value_size);
void *hashTableKeys(WpHashTable *table) {
void hashTableAlloc(const WpAllocator *allocator, WpHashTable *table, WpHasher hasher,
WpU8StreamEncoder encoder, WpKeyEqualTest key_eq, u64 capacity, u64 key_size,
u64 value_size, b8 has_values) {
wpDebugAssert(allocator != NULL && table != NULL && encoder != NULL && key_eq != NULL,
"`allocator`, `table`, `encoder` and `key_eq` should not be NULL");
u64 table_capacity = wpMiscUtilsU64RoundUpPow2(capacity);
table->hasher = hasher;
table->encoder = encoder;
table->key_eq = key_eq;
table->keys = arrayAllocCapacity(allocator, table_capacity, WP_ARRAY_INIT_NONE, key_size);;
table->buckets = wpArrayAllocCapacity(WpHashBucket, allocator, table_capacity, WP_ARRAY_INIT_FILLED);
table->magic = WP_HASH_TABLE_MAGIC;
table->bucket_mask = table_capacity - 1;
table->load_factor = WP_HASH_MAX_LOAD_FACTOR;
table->has_values = has_values;
wpRuntimeAssert(table->keys != NULL && table->buckets != NULL, "Failed to allocate keys, buckets or both");
if (has_values) {
table->values = arrayAllocCapacity(allocator, table_capacity, WP_ARRAY_INIT_NONE, value_size);;
wpRuntimeAssert(table->values != NULL, "Failed to allocate values");
}
}
u64 hashTableCalcHash(WpHashTable *table, void *key, u64 key_size) {
hashTableValidate(table, key_size, 0);
wpDebugAssert(key != NULL, "`key` should not be NULL");
WpU8Stream stream = table->encoder(key);
return wpHasherGetHash64(&table->hasher, &stream);
}
WpHashBucketRef hashTableBucketRef(WpHashTable *table, u64 hash) {
hashTableValidate(table, 0, 0);
return (WpHashBucketRef){
.dist_and_tag = WP_HASH_DIST_INC | (hash & WP_HASH_TAG_MASK),
.bucket_index = hash & table->bucket_mask,
};
}
void *hashTableKeys(WpHashTable *table, u64 key_size) {
hashTableValidate(table, key_size, 0);
return table->keys;
}
void *hashTableValues(WpHashTable *table) {
hashTableValidate(table, 0, 0);
return table->values;
}
void *hashTableGetKeyFromBucket(WpHashTable *table, WpHashBucket bucket, u64 key_size) {
hashTableValidate(table, key_size, 0);
return arrayGet(table->keys, bucket.item_index, key_size);
}
void *hashTableGetValueFromBucket(WpHashTable *table, WpHashBucket bucket, u64 value_size) {
void *hashTableValues(WpHashTable *table, u64 value_size) {
hashTableValidate(table, 0, value_size);
return table->has_values ? arrayGet(table->values, bucket.item_index, value_size) : NULL;
return table->values;
}
void *hashTableGetKeyFromBucketRef(WpHashTable *table, WpHashBucketRef ref, u64 key_size) {
@@ -58,25 +94,21 @@ u64 hashTableValueSize(WpHashTable *table) {
return table->has_values ? wpArrayItemSize(table->values) : 0;
}
u64 hashTableCalcHash(WpHashTable *table, void *key, u64 key_size) {
hashTableValidate(table, key_size, 0);
wpDebugAssert(key != NULL, "`key` should not be NULL");
WpU8Stream stream = table->encoder(key);
return wpHasherGetHash64(&table->hasher, &stream);
}
void hashTableGrow(WpHashTable *table, const WpAllocator *allocator, u64 key_size, u64 value_size) {
void hashTableGrow(const WpAllocator *allocator, WpHashTable *table, u64 key_size, u64 value_size) {
hashTableValidate(table, key_size, value_size);
wpDebugAssert(allocator != NULL, "`allocator` should not be NULL");
u64 capacity = hashTableCapacity(table) * 2;
u64 capacity = wpMiscUtilsU64RoundUpPow2(hashTableCapacity(table) * 2);
u64 mask = capacity - wpU64Const(1);
WpArray keys = arrayAllocCapacity(allocator, capacity, WP_ARRAY_INIT_NONE, key_size);
WpArray values = NULL;
WpHashBucketArray buckets = wpArrayAllocCapacity(WpHashBucket, allocator, capacity, WP_ARRAY_INIT_FILLED);
wpRuntimeAssert(keys != NULL && buckets != NULL, "Failed to allocate keys, buckets or both");
if (table->has_values) {
values = arrayAllocCapacity(allocator, capacity, WP_ARRAY_INIT_NONE, value_size);
wpRuntimeAssert(values != NULL, "Failed to allocate values");
}
WpArray old_keys = table->keys;
@@ -212,27 +244,39 @@ void hashTableClear(WpHashTable *table, u64 key_size, u64 value_size) {
wpArrayZero(WpHashBucket, table->buckets);
}
WpHashBucketRef hashTableBucketRef(WpHashTable *table, u64 hash) {
hashTableValidate(table, 0, 0);
return (WpHashBucketRef){
.dist_and_tag = WP_HASH_DIST_INC | (hash & WP_HASH_TAG_MASK),
.bucket_index = hash & table->bucket_mask,
};
void hashTableDealloc(const WpAllocator *allocator, WpHashTable *table, u64 key_size, u64 value_size) {
wpDebugAssert(allocator != NULL, "`allocator` should not be NULL");
hashTableValidate(table, key_size, value_size);
arrayDealloc(allocator, table->keys, key_size);
wpArrayDealloc(WpHashBucket, allocator, table->buckets);
if (table->has_values) {
arrayDealloc(allocator, table->values, value_size);
}
}
u64 hashTableGetDist(u64 dist_and_tag) {
wp_persist inline void *hashTableGetKeyFromBucket(WpHashTable *table, WpHashBucket bucket, u64 key_size) {
hashTableValidate(table, key_size, 0);
return arrayGet(table->keys, bucket.item_index, key_size);
}
wp_persist inline void *hashTableGetValueFromBucket(WpHashTable *table, WpHashBucket bucket, u64 value_size) {
hashTableValidate(table, 0, value_size);
return table->has_values ? arrayGet(table->values, bucket.item_index, value_size) : NULL;
}
wp_persist inline u64 hashTableGetDist(u64 dist_and_tag) {
return dist_and_tag & (~WP_HASH_TAG_MASK);
}
u64 hashTableNextBucket(WpHashTable *table, u64 bucket_index) {
wp_persist inline u64 hashTableNextBucket(WpHashTable *table, u64 bucket_index) {
return (++bucket_index) & table->bucket_mask;
}
u64 hashTableDistInc(u64 dist_and_tag) {
wp_persist inline u64 hashTableDistInc(u64 dist_and_tag) {
return dist_and_tag + WP_HASH_DIST_INC;
}
u64 hashTableDistDec(u64 dist_and_tag) {
wp_persist inline u64 hashTableDistDec(u64 dist_and_tag) {
return dist_and_tag - WP_HASH_DIST_INC;
}