Skip to content

Instantly share code, notes, and snippets.

@colbyhall
Created July 13, 2020 16:35
Show Gist options
  • Select an option

  • Save colbyhall/d22cae8309249cb696874582d92ec1d6 to your computer and use it in GitHub Desktop.

Select an option

Save colbyhall/d22cae8309249cb696874582d92ec1d6 to your computer and use it in GitHub Desktop.
#define FNV_OFFSET_BASIC 0xcbf29ce484222325
#define FNV_PRIME 0x100000001b3
inline u64 fnv1_hash(const void* s, usize size) {
u64 hash = FNV_OFFSET_BASIC;
const u8* const casted_s = s;
for (usize i = 0; i < size; ++i) {
hash *= FNV_PRIME;
hash = hash ^ casted_s[i];
}
return hash;
}
typedef struct Hash_Bucket {
u64 hash;
int index;
struct Hash_Bucket* next;
} Hash_Bucket;
typedef u64 (Hash_Table_Func)(void* a, void* b, int size);
u64 hash_string(void* a, void* b, int size) {
assert(size == sizeof(String));
String* const s_a = a;
String* const s_b = b;
if (b) return string_equal(*s_a, *s_b);
return fnv1_hash(s_a->data, s_a->len);
}
typedef struct Hash_Table {
void* keys;
int key_size;
void* values;
int value_size;
Hash_Bucket* buckets;
Hash_Bucket** bucket_layout;
int pair_count;
int pair_cap;
Hash_Table_Func* func;
Allocator allocator;
} Hash_Table;
static void rebuild_hash_table(Hash_Table* ht) {
for (int i = 0; i < ht->pair_count; ++i) {
Hash_Bucket* const bucket = ht->buckets + i;
bucket->hash = ht->func((u8*)ht->keys + ht->key_size * i, 0, ht->key_size);
bucket->index = i;
bucket->next = 0;
const int index = bucket->hash % ht->pair_cap;
Hash_Bucket** last = 0;
Hash_Bucket** slot = ht->bucket_layout + index;
while (*slot) {
last = slot;
slot = &(*slot)->next;
}
*slot = bucket;
if (last) (*last)->next = *slot;
}
}
Hash_Table _make_hash_table(int key_size, int value_size, Hash_Table_Func* func, Allocator allocator) {
assert(func);
return (Hash_Table) {
.key_size = key_size,
.value_size = value_size,
.func = func,
.allocator = allocator
};
}
#define make_hash_table(key, value, func, allocator) _make_hash_table(sizeof(key), sizeof(value), func, allocator)
void reserve_hash_table(Hash_Table* ht, int reserve_amount) {
assert(reserve_amount > 0);
ht->pair_cap += reserve_amount; // @TODO(colby): Small alg for best reserve amount
ht->keys = mem_realloc(ht->allocator, ht->keys, ht->key_size * ht->pair_cap);
ht->values = mem_realloc(ht->allocator, ht->values, ht->value_size * ht->pair_cap);
ht->buckets = mem_realloc(ht->allocator, ht->buckets, sizeof(Hash_Bucket) * ht->pair_cap);
ht->bucket_layout = mem_realloc(ht->allocator, ht->bucket_layout, sizeof(Hash_Bucket*) * ht->pair_cap);
mem_set(ht->bucket_layout, 0, sizeof(Hash_Bucket*) * ht->pair_cap);
}
void* _push_hash_table(Hash_Table* ht, void* key, int key_size, void* value, int value_size) {
assert(key_size == ht->key_size && value_size == ht->value_size);
void* found = _find_hash_table(ht, key, key_size);
if (found) return found;
if (ht->pair_count == ht->pair_cap) {
reserve_hash_table(ht, 1);
mem_copy((u8*)ht->keys + key_size * ht->pair_count, key, key_size);
mem_copy((u8*)ht->values + value_size * ht->pair_count, value, value_size);
ht->pair_count += 1;
rebuild_hash_table(ht);
return 0;
}
mem_copy((u8*)ht->keys + key_size * ht->pair_count, key, key_size);
mem_copy((u8*)ht->values + value_size * ht->pair_count, value, value_size);
Hash_Bucket* const bucket = ht->buckets + ht->pair_count;
bucket->hash = ht->func((u8*)ht->keys + key_size * ht->pair_count, 0, key_size);
bucket->index = ht->pair_count;
bucket->next = 0;
const int index = bucket->hash % ht->pair_cap;
Hash_Bucket** last = 0;
Hash_Bucket** slot = ht->bucket_layout + index;
while (*slot) {
last = slot;
slot = &(*slot)->next;
}
*slot = bucket;
if (last) (*last)->next = *slot;
ht->pair_count++;
return 0;
}
#define push_hash_table(ht, key, value) _push_hash_table(ht, &key, sizeof(key), &value, sizeof(value))
void* _find_hash_table(Hash_Table* ht, void* key, int key_size) {
assert(key_size == ht->key_size);
if (!ht->pair_count) return 0;
const u64 hash = ht->func(key, 0, key_size);
const int index = hash % ht->pair_cap;
Hash_Bucket* found = ht->bucket_layout[index];
while (found) {
const u64 my_hash = found->hash;
if (my_hash == hash) { // @TEMP } && ht->func(key, (u8*)ht->keys + found->index * key_size, key_size)) {
return (u8*)ht->values + ht->value_size * found->index;
}
found = found->next;
}
return 0;
}
#define find_hash_table(ht, key) _find_hash_table(ht, &key, sizeof(key))
@binkiklou
Copy link

wait this isn't an ikea table

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment