hash table + basic profiler implemented, now using c23

This commit is contained in:
Matthew 2025-04-20 12:24:33 +10:00
parent a651082dcc
commit c27b200984
18 changed files with 365 additions and 80 deletions

View File

@ -4,6 +4,8 @@ FLAlloc FL_ALLOC = {0};
Allocator ALLOC = {0}; Allocator ALLOC = {0};
read_only FLNode FL_NIL_NODE = {0}; read_only FLNode FL_NIL_NODE = {0};
#define ALLOC_CAP 16
// ::Allocator::Util::Header:: // ::Allocator::Util::Header::
usize CalcPaddingWithHeader(uintptr ptr, uintptr alignment, usize header_size) usize CalcPaddingWithHeader(uintptr ptr, uintptr alignment, usize header_size)
@ -32,7 +34,7 @@ usize CalcPaddingWithHeader(uintptr ptr, uintptr alignment, usize header_size)
// ::Allocator::Arena::Start:: // ::Allocator::Arena::Start::
static Arena *CreateArena(rawptr buffer, usize length) static Arena *ArenaInit(rawptr buffer, usize length)
{ {
Arena *arena = (Arena *)buffer; Arena *arena = (Arena *)buffer;
buffer = PtrAdd(buffer, ARENA_HEADER_SIZE); buffer = PtrAdd(buffer, ARENA_HEADER_SIZE);
@ -87,9 +89,9 @@ static void DeallocArena(Arena *arena)
MemFree(arena, arena->length); MemFree(arena, arena->length);
} }
static Arena * CreateArenaDebug(rawptr buffer, usize length, u32 init_line_no) static Arena * ArenaInitDebug(rawptr buffer, usize length, u32 init_line_no)
{ {
Arena *arena = CreateArena(buffer, length); Arena *arena = ArenaInit(buffer, length);
arena->init_line_no = init_line_no; arena->init_line_no = init_line_no;
return arena; return arena;
} }
@ -100,45 +102,43 @@ static Arena * CreateArenaDebug(rawptr buffer, usize length, u32 init_line_no)
// ::Allocator::GlobalAlloc::Start:: // ::Allocator::GlobalAlloc::Start::
static void InitAllocator(usize init_size, usize grow_size) static void InitAllocator(usize init_size)
{ {
usize size = init_size + sizeof(Allocator) + sizeof(FreeListBuffer) + sizeof(rawptr) + sizeof(RBNode); ALLOC.tree = FLMemAlloc(sizeof(RBTree));
u8 *mem = (u8 *)MemAllocZeroed(size); RBTreeInit(ALLOC.tree);
Allocator *fl_alloc = (Allocator *)mem;
u8 *pre_mem = mem; ALLOC.hash_table = FLMemAlloc(sizeof(HashTable));
mem = (u8 *)PtrAdd(mem, sizeof(Alloc)); HashTableInit(ALLOC.hash_table, 32);
usize rem_size = (size) - (pre_mem - mem);
fl_alloc->buf_len = 1; ALLOC.buffers = FLMemAlloc(sizeof(FreeListBuffer) * ALLOC_CAP);
fl_alloc->grow_size = grow_size; ALLOC.count = 1;
fl_alloc->buffers = (FreeListBuffer *)mem; ALLOC.cap = ALLOC_CAP;
ALLOC.grow_size = init_size;
pre_mem = mem; InitAllocatorBuffer(&ALLOC.buffers[0], init_size);
mem = (u8 *)PtrAdd(mem, sizeof(FreeListBuffer)); }
rem_size -= pre_mem - mem;
fl_alloc->nil = (RBNode *)mem;
pre_mem = mem;
mem = (u8 *)PtrAdd(mem, sizeof(RBNode));
rem_size -= pre_mem - mem;
fl_alloc->buffers[0].buf = mem;
fl_alloc->buffers[0].size = (u32)size;
fl_alloc->buffers[0].free_size = (u32)rem_size;
static void InitAllocatorBuffer(FreeListBuffer *buffer, usize init_size)
{
buffer->buf = MemAllocZeroed(init_size);
buffer->size = init_size;
buffer->free_size = init_size;
} }
static void DeinitAlloc() static void DeinitAlloc()
{ {
for (u8 i = ALLOC.buf_len-1; i >= 0; i--) for (u8 i = 0; i < ALLOC.count; i++)
{ {
MemFree(ALLOC.buffers[i].buf, ALLOC.buffers[i].size); MemFree(ALLOC.buffers[i].buf, ALLOC.buffers[i].size);
} }
} }
static rawptr Alloc(usize size) static rawptr Alloc(usize size)
{
return AllocAlign(size, DEFAULT_ALIGNMENT);
}
static rawptr AllocAlign(usize size, usize alignment)
{ {
return NULL; return NULL;
} }
@ -150,9 +150,9 @@ static void Free(rawptr ptr)
static void AllocGrow() static void AllocGrow()
{ {
u8 *mem = (u8 *)MemAllocZeroed(ALLOC.grow_size); Assert(ALLOC.count < ALLOC.cap, "Global allocator has reached capacity");
InitAllocatorBuffer(&ALLOC.buffers[ALLOC.count], ALLOC.grow_size);
ALLOC.count += 1;
} }
// ::Allocator::GlobalAlloc::End:: // ::Allocator::GlobalAlloc::End::

View File

@ -22,13 +22,13 @@ typedef struct TempArena
u64 pos; u64 pos;
} TempArena; } TempArena;
static Arena *CreateArena(rawptr buffer, usize length); static Arena *ArenaInit(rawptr buffer, usize length);
static rawptr ArenaAllocAlign(Arena *arena, usize size, usize align); static rawptr ArenaAllocAlign(Arena *arena, usize size, usize align);
static rawptr ArenaAlloc(Arena *arena, usize size); static rawptr ArenaAlloc(Arena *arena, usize size);
static void ArenaFree(Arena *arena); static void ArenaFree(Arena *arena);
static void ArenaFreeZeroed(Arena *arena); static void ArenaFreeZeroed(Arena *arena);
static void DeallocArena(Arena *arena); static void DeallocArena(Arena *arena);
static Arena *CreateArenaDebug(rawptr buffer, usize length, u32 init_line_no); static Arena *ArenaInitDebug(rawptr buffer, usize length, u32 init_line_no);
// ::Allocator::GlobalAlloc::Header:: // ::Allocator::GlobalAlloc::Header::
@ -41,17 +41,20 @@ typedef struct FreeListBuffer
typedef struct Allocator typedef struct Allocator
{ {
RBNode *head; RBTree *tree;
RBNode *nil;
FreeListBuffer *buffers; FreeListBuffer *buffers;
HashTable *hash_table;
usize grow_size; usize grow_size;
u8 buf_len; u64 count;
u64 cap;
} Allocator; } Allocator;
static void InitAllocator(usize init_size, usize grow_size); static void InitAllocator(usize init_size);
static void InitAllocatorBuffer(FreeListBuffer *buffer, usize init_size);
static void DeinitAlloc(); static void DeinitAlloc();
static void AllocGrow(); static void AllocGrow();
static rawptr Alloc(usize size); static rawptr Alloc(usize size);
static rawptr AllocAlign(usize size, usize alignment);
static void Free(rawptr ptr); static void Free(rawptr ptr);
// ::Allocator::FreeList::Header:: // ::Allocator::FreeList::Header::

111
src/ds.c
View File

@ -1,6 +1,10 @@
// ::DataStructures::Globals::Start:: // ::DataStructures::Globals::Start::
RBNode RB_NIL = { .color = RB_BLACK }; RBNode RB_NIL = { .color = RB_BLACK };
RBNode *P_RB_NIL = &RB_NIL;
HashNode HT_NIL = {0};
HashNode *P_HT_NIL = &HT_NIL;
// ::DataStructures::Globals::End:: // ::DataStructures::Globals::End::
@ -8,17 +12,19 @@ RBNode RB_NIL = { .color = RB_BLACK };
// ::DataStructures::RedBlackTree::Functions::Start:: // ::DataStructures::RedBlackTree::Functions::Start::
static void CreateRBTree(RBTree *tree) static void RBTreeInit(RBTree *tree)
{ {
Assert(tree != NULL, "RBTree is null"); Assert(tree != NULL, "RBTree is null");
RB_NIL.right = RB_NIL.left = RB_NIL.parent = &RB_NIL; RB_NIL.right = RB_NIL.left = RB_NIL.parent = P_RB_NIL;
tree->root = &RB_NIL; tree->root = P_RB_NIL;
tree->nil = &RB_NIL; tree->nil = P_RB_NIL;
} }
static void RBTreeInsert(RBTree *tree, RBNode *node) static RBNode *RBTreeFindOrInsert(RBTree *tree, RBNode *node)
{ {
RBNode *existing_node = P_RB_NIL;
node->left = node->right = tree->nil; node->left = node->right = tree->nil;
node->color = RB_RED; node->color = RB_RED;
@ -35,7 +41,12 @@ static void RBTreeInsert(RBTree *tree, RBNode *node)
{ {
Assert(curr_node != tree->nil, "Current Node is NIL"); Assert(curr_node != tree->nil, "Current Node is NIL");
if (curr_node->value < node->value) if (curr_node->value == node->value)
{
existing_node = curr_node;
break;
}
else if (curr_node->value < node->value)
{ {
if (curr_node->right == tree->nil) if (curr_node->right == tree->nil)
{ {
@ -64,8 +75,10 @@ static void RBTreeInsert(RBTree *tree, RBNode *node)
} }
} }
if (node->parent->color != RB_BLACK) if (node->parent->color != RB_BLACK && existing_node != P_RB_NIL)
RBTreeCorrect(tree, node); RBTreeCorrect(tree, node);
return existing_node;
} }
static void RBTreeCorrect(RBTree *tree, RBNode *node) static void RBTreeCorrect(RBTree *tree, RBNode *node)
@ -332,15 +345,95 @@ static void RBTreeRightRotate(RBTree *tree, RBNode *node)
// ::DataStructures::HashTable::Functions::Start:: // ::DataStructures::HashTable::Functions::Start::
static void InitHashTable(HashTable *table, u32 init_size) static void HashTableInit(HashTable *table, u32 init_size)
{ {
table->elem_count = init_size; table->cap = init_size;
table->count = 0;
table->lists = FLMemAlloc(sizeof(HashList) * init_size); table->lists = FLMemAlloc(sizeof(HashList) * init_size);
table->free_lists.first = P_HT_NIL;
table->free_lists.last = P_HT_NIL;
}
static void HashTableConcatInPlace(HashList *list, HashList *to_concat)
{
SLLConcatInPlaceNoCount(list, to_concat);
} }
static void HashTableClear(HashTable *table) static void HashTableClear(HashTable *table)
{ {
table->count = 0;
for (u32 i = 0; i < table->count; i++)
{
HashTableConcatInPlace(&table->free_lists, &table->lists[i]);
}
}
static HashNode *HashListPop(HashList *list)
{
HashNode *result = list->first;
HTQueuePop(list->first, list->last);
return result;
}
static HashNode *HashTablePush(HashTable *table, u64 hash, KeyValuePair value)
{
HashNode *node = NULL;
if (table->free_lists.first != P_HT_NIL)
node = HashListPop(&table->free_lists);
else
node = FLMemAlloc(sizeof(HashNode));
node->next = P_HT_NIL;
node->v = value;
u64 index = hash % table->cap;
HTQueuePush(table->lists[index].first, table->lists[index].last, node);
table->count += 1;
return node;
}
static HashNode *HashTablePushU32(HashTable *table, u64 key, u32 value)
{
u64 hash = HashFromString(String8Struct(&key));
return HashTablePush(table, hash, (KeyValuePair){ .key_u64 = key, .value_u32 = value });
}
static HashNode *HashTablePushU64(HashTable *table, u64 key, u64 value)
{
u64 hash = HashFromString(String8Struct(&key));
return HashTablePush(table, hash, (KeyValuePair){ .key_u64 = key, .value_u64 = value });
}
static HashNode *HashTablePushString8(HashTable *table, u64 key, String8 value)
{
u64 hash = HashFromString(String8Struct(&key));
return HashTablePush(table, hash, (KeyValuePair){ .key_u64 = key, .value_string = value });
}
static HashNode *HashTablePushRawptr(HashTable *table, u64 key, rawptr value)
{
u64 hash = HashFromString(String8Struct(&key));
return HashTablePush(table, hash, (KeyValuePair){ .key_u64 = key, .value_rawptr = value });
}
static KeyValuePair *HashTableSearchU64(HashTable *table, u64 key)
{
KeyValuePair *result = NULL;
u64 hash = HashFromString(String8Struct(&key));
u64 index = hash % table->cap;
HashList *list = table->lists + index;
for (HashNode *node = list->first; node != P_HT_NIL; node = node->next)
{
if (node->v.key_u64 == key)
{
result = &node->v;
break;
}
}
return result;
} }
// ::DataStructures::HashTable::Functions::End:: // ::DataStructures::HashTable::Functions::End::

View File

@ -41,8 +41,8 @@ typedef struct RBTree
RBNode *nil; RBNode *nil;
} RBTree; } RBTree;
static void CreateRBTree (RBTree *tree); static void RBTreeInit (RBTree *tree);
static void RBTreeInsert (RBTree *tree, RBNode *node); static RBNode *RBTreeFindOrInsert(RBTree *tree, RBNode *node);
static b32 RBTreeSearch (RBTree *tree, i32 value, RBNode **node); static b32 RBTreeSearch (RBTree *tree, i32 value, RBNode **node);
static void RBTreeDelete (RBTree *tree, i32 value); static void RBTreeDelete (RBTree *tree, i32 value);
static void RBTreeLeftRotate (RBTree *tree, RBNode *node); static void RBTreeLeftRotate (RBTree *tree, RBNode *node);
@ -53,6 +53,10 @@ static void RBTreeTransplant (RBTree *tree, RBNode *node, RBNode *placed_node);
// ::DataStructures::HashTable::Functions::Header:: // ::DataStructures::HashTable::Functions::Header::
#define HTQueuePop(f, l) SLLQueuePop(&HT_NIL, f, l)
#define HTQueuePush(f, l, n) SLLQueuePush(&HT_NIL, f, l, n)
#define HTQueuePushFront(f, l, n) SLLQueuePush(&HT_NIL, f, l, n)
typedef struct KeyValuePair typedef struct KeyValuePair
{ {
union union
@ -61,7 +65,7 @@ typedef struct KeyValuePair
}; };
union union
{ {
Str8 value_string; String8 value_string;
rawptr value_rawptr; rawptr value_rawptr;
u32 value_u32; u32 value_u32;
u64 value_u64; u64 value_u64;
@ -82,15 +86,21 @@ typedef struct HashList
typedef struct HashTable typedef struct HashTable
{ {
HashElement *lists; HashList *lists;
u32 elem_count; HashList free_lists;
} HashTable; u64 count;
u32 cap;
} HashTable;
static void InitHashTable(HashTable *table, u32 init_size); static void HashTableInit(HashTable *table, u32 init_size);
static void HashTableClear(HashTable *table); static void HashTableClear(HashTable *table);
static void HashTableConcatInPlace(HashList *list, HashList *to_concat);
static u64 HashTableHash(String8 str);
static HashNode *HashListPop(HashList *list);
static KeyValuePair *HashTableSearchU64(HashTable *table, u64 key);
static HashNode *HashTablePush(HashTable *table, u64 hash, KeyValuePair value); static HashNode *HashTablePush(HashTable *table, u64 hash, KeyValuePair value);
static HashNode *HashTablePushU32(HashTable *table, u64 key, u32 value); static HashNode *HashTablePushU32(HashTable *table, u64 key, u32 value);
static HashNode *HashTablePushU64(HashTable *table, u64 key, u64 value); static HashNode *HashTablePushU64(HashTable *table, u64 key, u64 value);
static HashNode *HashTablePushStr8(HashTable *table, u64 key, Str8 value); static HashNode *HashTablePushString8(HashTable *table, u64 key, String8 value);
static HashNode *HashTablePushRawptr(HashTable *table, u64 key, rawptr value); static HashNode *HashTablePushRawptr(HashTable *table, u64 key, rawptr value);

View File

@ -16,6 +16,8 @@
# include "tests.c" # include "tests.c"
#endif #endif
static_assert(__COUNTER__ < Len(GLOBAL_PROFILER.anchors));
void TraverseNode(RBTree *tree, RBNode *node, RBNodeDir *dir) void TraverseNode(RBTree *tree, RBNode *node, RBNodeDir *dir)
{ {
char *dir_str = dir == NULL ? "Root" : *dir == RB_RIGHT ? "Right" : "Left"; char *dir_str = dir == NULL ? "Root" : *dir == RB_RIGHT ? "Right" : "Left";
@ -48,16 +50,16 @@ int main(int argc, char **argv)
#endif #endif
u8 *mem = (u8 *)MemAllocZeroed(MB(64)); u8 *mem = (u8 *)MemAllocZeroed(MB(64));
Arena *arena = CreateArenaDebug(mem, MB(64), __LINE__); Arena *arena = ArenaInitDebug(mem, MB(64), __LINE__);
usize renderer_mem_size = MB(16); usize renderer_mem_size = MB(16);
usize game_mem_size = MB(16); usize game_mem_size = MB(16);
rawptr renderer_mem = ArenaAlloc(arena, renderer_mem_size); rawptr renderer_mem = ArenaAlloc(arena, renderer_mem_size);
Arena *renderer_arena = CreateArenaDebug(renderer_mem, renderer_mem_size, 2); Arena *renderer_arena = ArenaInitDebug(renderer_mem, renderer_mem_size, 2);
rawptr game_mem = ArenaAlloc(arena, game_mem_size); rawptr game_mem = ArenaAlloc(arena, game_mem_size);
Arena *game_arena = CreateArenaDebug(game_mem, game_mem_size, 3); Arena *game_arena = ArenaInitDebug(game_mem, game_mem_size, 3);
Assert(CreatePlatformWindow(WINDOW_NAME), "Failed to initialize the window"); Assert(CreatePlatformWindow(WINDOW_NAME), "Failed to initialize the window");

View File

@ -20,16 +20,16 @@ int CALLBACK WinMain(HINSTANCE instance, HINSTANCE prev_instance, LPSTR cmd_line
#endif #endif
u8 *mem = (u8 *)MemAllocZeroed(MB(32)); u8 *mem = (u8 *)MemAllocZeroed(MB(32));
Arena *arena = CreateArenaDebug(mem, MB(32), 1); Arena *arena = ArenaInitDebug(mem, MB(32), 1);
isize renderer_mem_size = MB(16); isize renderer_mem_size = MB(16);
isize game_mem_size = MB(16); isize game_mem_size = MB(16);
rawptr renderer_mem = ArenaAlloc(arena, renderer_mem_size); rawptr renderer_mem = ArenaAlloc(arena, renderer_mem_size);
Arena *renderer_arena = CreateArenaDebug(renderer_mem, renderer_mem_size, 2); Arena *renderer_arena = ArenaInitDebug(renderer_mem, renderer_mem_size, 2);
rawptr game_mem = ArenaAlloc(arena, game_mem_size); rawptr game_mem = ArenaAlloc(arena, game_mem_size);
Arena *game_arena = CreateArenaDebug(game_mem, game_mem_size, 3); Arena *game_arena = ArenaInitDebug(game_mem, game_mem_size, 3);
Assert(CreatePlatformWindow(WINDOW_NAME), "Failed to initialize window"); Assert(CreatePlatformWindow(WINDOW_NAME), "Failed to initialize window");

View File

@ -186,7 +186,7 @@ static inline void PrepareGUICtx(GameContext *ctx)
static b32 UIButton(GameContext *ctx, char *label, f32 x0, f32 y0, f32 x1, f32 y1) static b32 UIButton(GameContext *ctx, char *label, f32 x0, f32 y0, f32 x1, f32 y1)
{ {
GUIButton *btn = NULL; GUIButton *btn = NULL;
u64 id = HashFromString(Str8L(label)); u64 id = HashFromString(String8CStr(label));
if (ctx->btn_len == 0) if (ctx->btn_len == 0)
{ {
ctx->buttons[0].p0.x = x0; ctx->buttons[0].p0.x = x0;
@ -246,7 +246,7 @@ static b32 UIButton(GameContext *ctx, char *label, f32 x0, f32 y0, f32 x1, f32 y
static b32 UIWindow(GameContext *ctx, char *title, f32 x0, f32 y0, f32 x1, f32 y1) static b32 UIWindow(GameContext *ctx, char *title, f32 x0, f32 y0, f32 x1, f32 y1)
{ {
GUIWindow *win = NULL; GUIWindow *win = NULL;
u32 id = HashFromString(Str8L(title)); u32 id = HashFromString(String8CStr(title));
if (ctx->window_len == 0) if (ctx->window_len == 0)
{ {
ctx->windows[0].p0.x = x0; ctx->windows[0].p0.x = x0;

View File

@ -375,7 +375,7 @@ int main(int argc, c8 **argv)
SetArrayLookups(); SetArrayLookups();
void *mem = MemAllocZeroed(GB(1)); void *mem = MemAllocZeroed(GB(1));
Arena *arena = CreateArenaDebug(mem, GB(1), __LINE__); Arena *arena = ArenaInitDebug(mem, GB(1), __LINE__);
FILE *file = fopen("assets.sgp", "w+"); FILE *file = fopen("assets.sgp", "w+");
Assert(file != NULL, "File is null"); Assert(file != NULL, "File is null");

View File

@ -64,3 +64,9 @@ u32 AvailableCPUCount();
b32 ChangeDir(c8 *dir); b32 ChangeDir(c8 *dir);
c8 **GetFileNamesInDir(Arena *arena, u32 *count); c8 **GetFileNamesInDir(Arena *arena, u32 *count);
b8 DirVisible(c8 *dir_name); b8 DirVisible(c8 *dir_name);
// ::Platform::Profiling::Functions::Header::
static u64 GetOSTimerFreq();
static u64 ReadOSTimer();
static inline u64 ReadCPUTimer();

View File

@ -23,6 +23,8 @@
#include <sched.h> #include <sched.h>
#include <unistd.h> #include <unistd.h>
#include <dirent.h> #include <dirent.h>
#include <x86intrin.h>
#include <sys/time.h>
// ::Platform::Linux::Defines::Header:: // ::Platform::Linux::Defines::Header::

View File

@ -305,3 +305,27 @@ b8 DirVisible(c8 *dir_name)
} }
// ::Platform::Functions::Directory::End:: // ::Platform::Functions::Directory::End::
// ::Platform::Profiling::Functions::Start::
static u64 GetOSTimerFreq()
{
return 1000000;
}
static u64 ReadOSTimer()
{
struct timeval value;
gettimeofday(&value, 0);
return GetOSTimerFreq() * u64(value.tv_sec) + u64(value.tv_usec);
}
static inline u64 ReadCPUTimer()
{
return __rdtsc();
}
// ::Platform::Profiling::Functions::End::

View File

@ -70,7 +70,6 @@ static void BindIndexBuffer(RenderBuffer *buffer);
static void GetViewportSize(Vec2 *size); static void GetViewportSize(Vec2 *size);
static void SetGlobalUniform(ShaderGlobals *globals); static void SetGlobalUniform(ShaderGlobals *globals);
static void SetPushConstants(PushConst *pc); static void SetPushConstants(PushConst *pc);
static DescHandle UploadImageUniform();
// ::Renderer::Config::Header:: // ::Renderer::Config::Header::

View File

@ -9,7 +9,7 @@ b32 InitRenderer(Arena *arena)
Assert(arena != NULL, "Vulkan memory is null"); Assert(arena != NULL, "Vulkan memory is null");
renderer.perm_arena = arena; renderer.perm_arena = arena;
void *mem = ArenaAlloc(arena, MB(8)); void *mem = ArenaAlloc(arena, MB(8));
renderer.arena = CreateArena(mem, MB(8)); renderer.arena = ArenaInit(mem, MB(8));
Assert(InitVkGlobalFunctions(), "Unable to load vulkan functions"); Assert(InitVkGlobalFunctions(), "Unable to load vulkan functions");
{ {

View File

@ -177,11 +177,11 @@ typedef uint32_t b32;
typedef void * rawptr; typedef void * rawptr;
typedef struct Str8 typedef struct String8
{ {
u32 len;
u8 *value; u8 *value;
} Str8; u64 len;
} String8;
#ifdef __linux__ #ifdef __linux__

View File

@ -1,11 +1,16 @@
// TODO: Make the tests actually decent
void RunTests() void RunTests()
{ {
GlobalFreeListInit(MB(32));
TestFreeListAlloc(); TestFreeListAlloc();
TestHashTable();
} }
void TestFreeListAlloc() void TestFreeListAlloc()
{ {
Printfln("Starting free list allocator tests...");
FLAlloc alloc = {0}; FLAlloc alloc = {0};
usize alloc_size = KB(256); usize alloc_size = KB(256);
FreeListInit(&alloc, alloc_size); FreeListInit(&alloc, alloc_size);
@ -46,3 +51,27 @@ void TestFreeListAlloc()
Assert(f64_arr[i] == f64(i), "f64 memory incorrect post free"); Assert(f64_arr[i] == f64(i), "f64 memory incorrect post free");
} }
} }
void TestHashTable()
{
Printfln("Starting hash table tests...");
HashTable table;
HashTableInit(&table, 16);
for (u64 i = 1; i < 2000; i++)
{
HashTablePushU64(&table, i*3, i);
}
for (u64 i = 1; i < 2000; i++)
{
KeyValuePair *result = HashTableSearchU64(&table, i*3);
Assert(result != P_HT_NIL, "HashTable result isn't found");
Assert(result->value_u64 == i, "HashTable result doesn't match");
}
HashTableClear(&table);
KeyValuePair *result = HashTableSearchU64(&table, 1);
Assert(result == NULL, "Result isn't nil after HashTable clear");
}

View File

@ -2,4 +2,5 @@
void RunTests(); void RunTests();
void TestFreeListAlloc(); void TestFreeListAlloc();
void TestHashTable();

View File

@ -1,3 +1,11 @@
// ::Util::Globals::Start::
static Profiler GLOBAL_PROFILER;
// ::Util::Globals::End::
// ::Util::Strings::Functions::Start:: // ::Util::Strings::Functions::Start::
b32 StrEq(const char *l, const char *r) { b32 StrEq(const char *l, const char *r) {
@ -26,12 +34,12 @@ i32 SPrintf(char *buf, rawptr fmt, ...)
return sprf_res; return sprf_res;
} }
Str8 MakeStr8(u8 *str, u32 len) String8 MakeString8(u8 *str, u64 len)
{ {
return (Str8){ .len = len, .value = str }; return (String8){ .len = len, .value = str };
} }
Str8 PreSplitStr8(Str8 string, Str8 delimiter) String8 PreSplitString8(String8 string, String8 delimiter)
{ {
if (string.len == 0 || delimiter.len == 0) return string; if (string.len == 0 || delimiter.len == 0) return string;
@ -53,12 +61,12 @@ Str8 PreSplitStr8(Str8 string, Str8 delimiter)
} }
} }
return (Str8){ .len = new_len, .value = string.value }; return (String8){ .len = new_len, .value = string.value };
} }
Str8 PreSplitNewStr8(Arena *arena, Str8 string, Str8 delimiter) String8 PreSplitNewString8(Arena *arena, String8 string, String8 delimiter)
{ {
Str8 result = PreSplitStr8(string, delimiter); String8 result = PreSplitString8(string, delimiter);
if (result.len > 0) if (result.len > 0)
{ {
@ -192,9 +200,9 @@ u32 u32Clamp(u32 v, u32 min, u32 max)
// ::Util::Hashing::Functions::Start:: // ::Util::Hashing::Functions::Start::
u64 static inline HashFromString(Str8 string) u64 static inline HashFromString(String8 string)
{ {
return XXH3_64bits_withSeed(string.value, string.len, HASH_SEED); return XXH3_64bits(string.value, string.len);
} }
// ::Util::Hashing::Functions::End:: // ::Util::Hashing::Functions::End::
@ -289,3 +297,26 @@ i32 _Printfln(char *fmt, va_list arg)
} }
// ::Util::Print::Functions::End:: // ::Util::Print::Functions::End::
// ::Util::Profiling::Functions::Start::
static inline void StartProfileBlock(ProfileBlock *block, c8 *label, u32 anchor_index)
{
block->anchor_index = anchor_index;
block->label = label;
block->start_tsc = ReadCPUTimer();
}
static inline void EndProfileBlock(ProfileBlock *block)
{
u64 elapsed = ReadCPUTimer() - block->start_tsc;
ProfileAnchor *anchor = GLOBAL_PROFILER.anchors + block->anchor_index;
anchor->tsc_elapsed += elapsed;
anchor->hit_count += 1;
anchor->label = block->label;
}
// ::Util::Profiling::Functions::End::

View File

@ -21,7 +21,6 @@ typedef struct Arena Arena;
#define MakeArray(arena, type, count) ArenaAlloc(arena, (isize)(sizeof(type)) * (isize)(count)) #define MakeArray(arena, type, count) ArenaAlloc(arena, (isize)(sizeof(type)) * (isize)(count))
#define Len(x) ((sizeof(x)/sizeof(0[x])) / ((size_t)(!(sizeof(x) % sizeof(0[x]))))) #define Len(x) ((sizeof(x)/sizeof(0[x])) / ((size_t)(!(sizeof(x) % sizeof(0[x])))))
#define Str8L(x) (Str8){ .len = StrLen(x), .value = (u8 *)x }
#define MakeString(x) #x #define MakeString(x) #x
#define i8(x) ((i8)(x)) #define i8(x) ((i8)(x))
@ -49,6 +48,49 @@ typedef struct Arena Arena;
#define cast(T, x) ((T)(x)) #define cast(T, x) ((T)(x))
// ::Util::LinkedList::Macros::
#define CheckNil(nil, p) ((p) == 0 || (p) == nil)
#define SetNil(nil, p) ((p) = nil)
// ::Util::DoubleHeadedLinkedList::Macros::
#define SLLConcatInPlaceNoCount(list, to_concat) do { \
if ((to_concat)->first) \
{ \
if ((list)->first) \
{ \
(list)->last->next = (to_concat)->first; \
(list)->last = (to_concat)->last; \
} \
else \
{ \
(list)->first = (to_concat)->first; \
(list)->last = (to_concat)->last; \
} \
MemZero(to_concat, sizeof(*to_concat)); \
} \
} while (0)
#define _SLLQueuePop(nil, f, l, next) ((f) == (l) ? \
(SetNil(nil, f), SetNil(nil, l)) : \
((f) = (f)->next))
#define _SLLQueuePushFront(nil, f, l, n, next) (CheckNil(nil, f) ? \
((f) = (l) = (n), SetNil(nil, (n)->next)) : \
((n)->next = (f), (f) = (n)))
#define _SLLQueuePush(nil, f, l, n, next) (CheckNil(nil, f) ? \
((f) = (l) = (n), SetNil(nil, (n)->next)) : \
((l)->next = (n), (l) = (n), SetNil(nil, (n)->next)))
#define SLLQueuePop(nil, f, l) _SLLQueuePop(nil, f, l, next)
#define SLLQueuePush(nil, f, l, n) _SLLQueuePush(nil, f, l, n, next)
#define SLLQueuePushFront(nil, f, l, n) _SLLQueuePushFront(nil, f, l, n, next)
// ::Util::String8::Macros::
#define String8Array(v, c) MakeString8((u8 *)(v), sizeof(*(v))*(c))
#define String8Struct(v) MakeString8((u8 *)(v), sizeof(*(v)))
#define String8CStr(v) MakeString8((u8 *)v, StrLen(v))
// ::Util::Defines::Header:: // ::Util::Defines::Header::
#define HM_MAX_SYMBOLS 256 #define HM_MAX_SYMBOLS 256
@ -57,12 +99,12 @@ typedef struct Arena Arena;
// ::Util::Strings::Functions::Header:: // ::Util::Strings::Functions::Header::
String8 MakeString8(u8 *str, u64 len);
u32 StrLen(const char *str); u32 StrLen(const char *str);
b32 StrEq(const char *l, const char *r); b32 StrEq(const char *l, const char *r);
i32 SPrintf(char *buf, rawptr fmt, ...); i32 SPrintf(char *buf, rawptr fmt, ...);
Str8 MakeStr8(u8 *str, u32 len); String8 PreSplitString8(String8 string, String8 delimiter);
Str8 PreSplitStr8(Str8 string, Str8 delimiter); String8 PreSplitNewString8(Arena *arena, String8 string, String8 delimiter);
Str8 PreSplitNewStr8(Arena *arena, Str8 string, Str8 delimiter);
// ::Util::Memory::Functions::Header:: // ::Util::Memory::Functions::Header::
@ -80,7 +122,7 @@ u32 u32Clamp(u32 v, u32 min, u32 max);
// ::Util::Hashing::Functions::Header:: // ::Util::Hashing::Functions::Header::
u64 static inline HashFromString(Str8 string); u64 static inline HashFromString(String8 string);
// ::Util::Print::Functions::Header:: // ::Util::Print::Functions::Header::
@ -92,3 +134,46 @@ i32 _EPrint(void *str);
i32 _Printf(char *fmt, va_list arg); i32 _Printf(char *fmt, va_list arg);
i32 _Printfln(char *fmt, va_list arg); i32 _Printfln(char *fmt, va_list arg);
i32 _EPrintf(char *fmt, va_list arg); i32 _EPrintf(char *fmt, va_list arg);
// ::Util::Profiling::Header::
#define NameConcat2(a, b) a##b
#define NameConcat(a, b) NameConcat2(a, b)
#define TimeBlockStart(name) ProfileBlock NameConcat(Block, name) = {0}; \
StartProfileBlock(&NameConcat(Block, name), #name, __COUNTER__ + 1)
#define TimeBlockEnd(name) EndProfileBlock(&NameConcat(Block, name))
#define TimeBlockFuncStart(name) ProfileBlock NameConcat(Block, function) = {0}; \
StartProfileBlock(& NameConcat(Block, function), name, __COUNTER__ + 1)
#define TimeFunctionStart TimeBlockFuncStart(__func__)
#define TimeFunctionEnd TimeBlockEnd(function)
typedef struct ProfileAnchor
{
u64 tsc_elapsed;
u64 hit_count;
c8 *label;
} ProfileAnchor;
typedef struct ProfileBlock
{
c8 *label;
u64 start_tsc;
u32 anchor_index;
} ProfileBlock;
typedef struct Profiler
{
ProfileAnchor anchors[4096];
u64 start_tsc;
u64 end_tsc;
} Profiler;
static inline void StartProfileBlock(ProfileBlock *block, c8 *label, u32 anchor_index);
static inline void EndProfileBlock(ProfileBlock *block);