diff --git a/src/linker/lf_hash_table.c b/src/linker/lf_hash_table.c new file mode 100644 index 00000000..6a2f86a7 --- /dev/null +++ b/src/linker/lf_hash_table.c @@ -0,0 +1,89 @@ +// Copyright (c) Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +internal B32 +lfht_insert(Arena *arena, + LFHT_NodeChunkList *node_chunks, + LFHT_Node **root_ptr, + U64 hash, + void *data, + LFHT_IsKeyEqualFunc *is_key_equal, + void *is_key_equal_ud) +{ + B32 was_inserted = 0; + LFHT_Node **curr_ptr = root_ptr; + for (U64 h = hash; ; h <<= 2) { + LFHT_Node *curr = ins_atomic_ptr_eval(curr_ptr); + + if (curr == 0) { + if (node_chunks->last == 0 || node_chunks->last->count >= node_chunks->last->max) { + LFHT_NodeChunk *c = push_array(arena, LFHT_NodeChunk, 1); + c->max = 1024; + c->count = 0; + c->v = push_array_no_zero(arena, LFHT_Node, 1024); + + SLLQueuePush(node_chunks->first, node_chunks->last, c); + node_chunks->chunk_count += 1; + } + + LFHT_Node *n = &node_chunks->last->v[node_chunks->last->count]; + MemoryZeroStruct(n); + n->data = data; + + LFHT_Node *cmp = ins_atomic_ptr_eval_cond_assign(curr_ptr, n, curr); + if (cmp == curr) { + node_chunks->last->count += 1; + node_chunks->total_count += 1; + was_inserted = 1; + break; + } + } + + // was the key already inserted? + if (is_key_equal(is_key_equal_ud, curr->data, data)) { break; } + + // descend + curr_ptr = &curr->children[h >> 62]; + } + return was_inserted; +} + +internal void * +lfht_search(LFHT_Node *root, U64 hash, void *data, LFHT_IsKeyEqualFunc *is_key_equal, void *is_key_equal_ud) +{ + LFHT_Node *curr = root; + for (U64 h = hash; ; h <<= 2) { + if (curr == 0) { break; } + if (is_key_equal(is_key_equal_ud, curr->data, data)) { break; } + curr = curr->children[h >> 62]; + } + return curr ? curr->data : 0; +} + +internal U64 +lfht_total_count_from_node_chunk_lists(U64 list_count, LFHT_NodeChunkList *lists) +{ + U64 total_count = 0; + for EachIndex(i, list_count) { total_count += lists[i].total_count; } + return total_count; +} + +internal void ** +lfht_data_from_node_chunk_lists(Arena *arena, U64 total_count, U64 list_count, LFHT_NodeChunkList *lists) +{ + U64 result_count = 0; + void **result = push_array(arena, void *, total_count); + for EachIndex(list_idx, list_count) { + LFHT_NodeChunkList l = lists[list_idx]; + for EachNode(c, LFHT_NodeChunk, l.first) { + Assert(result_count + c->count <= total_count); + for EachIndex(item_idx, c->count) { + result[result_count++] = c->v[item_idx].data; + } + } + } + + return result; +} + + diff --git a/src/linker/lf_hash_table.h b/src/linker/lf_hash_table.h new file mode 100644 index 00000000..979e911c --- /dev/null +++ b/src/linker/lf_hash_table.h @@ -0,0 +1,36 @@ +// Copyright (c) Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +#ifndef LF_HASH_TABLE_H +#define LF_HAHS_TABLE_H + +typedef struct LFHT_Node +{ + void *data; + struct LFHT_Node *children[4]; +} LFHT_Node; + +typedef struct LFHT_NodeChunk +{ + struct LFHT_NodeChunk *next; + U64 max; + U64 count; + LFHT_Node *v; +} LFHT_NodeChunk; + +typedef struct LFHT_NodeChunkList +{ + U64 chunk_count; + U64 total_count; + LFHT_NodeChunk *first; + LFHT_NodeChunk *last; +} LFHT_NodeChunkList; + +#define LFHT_IS_KEY_EQUAL_FUNC(name) B32 name(void *ud, void *a, void *b) +typedef LFHT_IS_KEY_EQUAL_FUNC(LFHT_IsKeyEqualFunc); + +internal B32 lfht_insert(Arena *arena, LFHT_NodeChunkList *node_chunks, LFHT_Node **root_ptr, U64 hash, void *data, LFHT_IsKeyEqualFunc *is_key_equal, void *is_key_equal_ud); + +internal void ** lfht_data_from_node_chunk_lists(Arena *arena, U64 total_count, U64 list_count, LFHT_NodeChunkList *lists); + +#endif // LF_HASH_TABLE_H \ No newline at end of file