dqn: Add more container types

This commit is contained in:
doyle 2023-08-31 22:10:47 +10:00
parent 7f47df1bbe
commit 04b5e26ff3
10 changed files with 612 additions and 518 deletions

View File

@ -695,7 +695,7 @@ static Dqn_UTest Dqn_Test_FixedArray()
DQN_UTEST_TEST("Erase stable 1 element from array") {
int raw_array[] = {1, 2, 3};
auto array = Dqn_FArray_Init<int, 4>(raw_array, DQN_ARRAY_UCOUNT(raw_array));
Dqn_FArray_EraseRange(&array, 1 /*begin_index*/, 1 /*count*/, Dqn_FArrayErase_Stable);
Dqn_FArray_EraseRange(&array, 1 /*begin_index*/, 1 /*count*/, Dqn_ArrayErase_Stable);
DQN_UTEST_ASSERT(&test, array.size == 2);
DQN_UTEST_ASSERT(&test, array.data[0] == 1);
DQN_UTEST_ASSERT(&test, array.data[1] == 3);
@ -704,7 +704,7 @@ static Dqn_UTest Dqn_Test_FixedArray()
DQN_UTEST_TEST("Erase unstable 1 element from array") {
int raw_array[] = {1, 2, 3};
auto array = Dqn_FArray_Init<int, 4>(raw_array, DQN_ARRAY_UCOUNT(raw_array));
Dqn_FArray_EraseRange(&array, 0 /*begin_index*/, 1 /*count*/, Dqn_FArrayErase_Unstable);
Dqn_FArray_EraseRange(&array, 0 /*begin_index*/, 1 /*count*/, Dqn_ArrayErase_Unstable);
DQN_UTEST_ASSERT(&test, array.size == 2);
DQN_UTEST_ASSERT(&test, array.data[0] == 3);
DQN_UTEST_ASSERT(&test, array.data[1] == 2);
@ -1578,22 +1578,22 @@ static Dqn_UTest Dqn_Test_VArray()
}
DQN_UTEST_TEST("Test stable erase, 1 item, the '2' value from the array") {
Dqn_VArray_EraseRange(&array, 2 /*begin_index*/, 1 /*count*/, Dqn_VArrayErase_Stable);
Dqn_VArray_EraseRange(&array, 2 /*begin_index*/, 1 /*count*/, Dqn_ArrayErase_Stable);
uint32_t array_literal[] = {0, 1, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15};
DQN_UTEST_ASSERT(&test, array.size == DQN_ARRAY_UCOUNT(array_literal));
DQN_UTEST_ASSERT(&test, DQN_MEMCMP(array.data, array_literal, DQN_ARRAY_UCOUNT(array_literal) * sizeof(array_literal[0])) == 0);
}
DQN_UTEST_TEST("Test unstable erase, 1 item, the '1' value from the array") {
Dqn_VArray_EraseRange(&array, 1 /*begin_index*/, 1 /*count*/, Dqn_VArrayErase_Unstable);
Dqn_VArray_EraseRange(&array, 1 /*begin_index*/, 1 /*count*/, Dqn_ArrayErase_Unstable);
uint32_t array_literal[] = {0, 15, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14};
DQN_UTEST_ASSERT(&test, array.size == DQN_ARRAY_UCOUNT(array_literal));
DQN_UTEST_ASSERT(&test, DQN_MEMCMP(array.data, array_literal, DQN_ARRAY_UCOUNT(array_literal) * sizeof(array_literal[0])) == 0);
}
Dqn_VArrayErase erase_enums[] = {Dqn_VArrayErase_Stable, Dqn_VArrayErase_Unstable};
Dqn_ArrayErase erase_enums[] = {Dqn_ArrayErase_Stable, Dqn_ArrayErase_Unstable};
DQN_UTEST_TEST("Test un/stable erase, OOB") {
for (Dqn_VArrayErase erase : erase_enums) {
for (Dqn_ArrayErase erase : erase_enums) {
uint32_t array_literal[] = {0, 15, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14};
Dqn_VArray_EraseRange(&array, DQN_ARRAY_UCOUNT(array_literal) /*begin_index*/, DQN_ARRAY_UCOUNT(array_literal) + 100 /*count*/, erase);
DQN_UTEST_ASSERT(&test, array.size == DQN_ARRAY_UCOUNT(array_literal));
@ -1602,42 +1602,42 @@ static Dqn_UTest Dqn_Test_VArray()
}
DQN_UTEST_TEST("Test flipped begin/end index stable erase, 2 items, the '15, 3' value from the array") {
Dqn_VArray_EraseRange(&array, 2 /*begin_index*/, -2 /*count*/, Dqn_VArrayErase_Stable);
Dqn_VArray_EraseRange(&array, 2 /*begin_index*/, -2 /*count*/, Dqn_ArrayErase_Stable);
uint32_t array_literal[] = {0, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14};
DQN_UTEST_ASSERT(&test, array.size == DQN_ARRAY_UCOUNT(array_literal));
DQN_UTEST_ASSERT(&test, DQN_MEMCMP(array.data, array_literal, DQN_ARRAY_UCOUNT(array_literal) * sizeof(array_literal[0])) == 0);
}
DQN_UTEST_TEST("Test flipped begin/end index unstable erase, 2 items, the '4, 5' value from the array") {
Dqn_VArray_EraseRange(&array, 2 /*begin_index*/, -2 /*count*/, Dqn_VArrayErase_Unstable);
Dqn_VArray_EraseRange(&array, 2 /*begin_index*/, -2 /*count*/, Dqn_ArrayErase_Unstable);
uint32_t array_literal[] = {0, 13, 14, 6, 7, 8, 9, 10, 11, 12};
DQN_UTEST_ASSERT(&test, array.size == DQN_ARRAY_UCOUNT(array_literal));
DQN_UTEST_ASSERT(&test, DQN_MEMCMP(array.data, array_literal, DQN_ARRAY_UCOUNT(array_literal) * sizeof(array_literal[0])) == 0);
}
DQN_UTEST_TEST("Test stable erase range, 2+1 (oob) item, the '13, 14, +1 OOB' value from the array") {
Dqn_VArray_EraseRange(&array, 8 /*begin_index*/, 3 /*count*/, Dqn_VArrayErase_Stable);
Dqn_VArray_EraseRange(&array, 8 /*begin_index*/, 3 /*count*/, Dqn_ArrayErase_Stable);
uint32_t array_literal[] = {0, 13, 14, 6, 7, 8, 9, 10};
DQN_UTEST_ASSERT(&test, array.size == DQN_ARRAY_UCOUNT(array_literal));
DQN_UTEST_ASSERT(&test, DQN_MEMCMP(array.data, array_literal, DQN_ARRAY_UCOUNT(array_literal) * sizeof(array_literal[0])) == 0);
}
DQN_UTEST_TEST("Test unstable erase range, 3+1 (oob) item, the '11, 12, +1 OOB' value from the array") {
Dqn_VArray_EraseRange(&array, 6 /*begin_index*/, 3 /*count*/, Dqn_VArrayErase_Unstable);
Dqn_VArray_EraseRange(&array, 6 /*begin_index*/, 3 /*count*/, Dqn_ArrayErase_Unstable);
uint32_t array_literal[] = {0, 13, 14, 6, 7, 8};
DQN_UTEST_ASSERT(&test, array.size == DQN_ARRAY_UCOUNT(array_literal));
DQN_UTEST_ASSERT(&test, DQN_MEMCMP(array.data, array_literal, DQN_ARRAY_UCOUNT(array_literal) * sizeof(array_literal[0])) == 0);
}
DQN_UTEST_TEST("Test stable erase -overflow OOB, erasing the '0, 13' value from the array") {
Dqn_VArray_EraseRange(&array, 1 /*begin_index*/, -DQN_ISIZE_MAX /*count*/, Dqn_VArrayErase_Stable);
Dqn_VArray_EraseRange(&array, 1 /*begin_index*/, -DQN_ISIZE_MAX /*count*/, Dqn_ArrayErase_Stable);
uint32_t array_literal[] = {14, 6, 7, 8};
DQN_UTEST_ASSERT(&test, array.size == DQN_ARRAY_UCOUNT(array_literal));
DQN_UTEST_ASSERT(&test, DQN_MEMCMP(array.data, array_literal, DQN_ARRAY_UCOUNT(array_literal) * sizeof(array_literal[0])) == 0);
}
DQN_UTEST_TEST("Test unstable erase +overflow OOB, erasing the '7, 8' value from the array") {
Dqn_VArray_EraseRange(&array, 2 /*begin_index*/, DQN_ISIZE_MAX /*count*/, Dqn_VArrayErase_Unstable);
Dqn_VArray_EraseRange(&array, 2 /*begin_index*/, DQN_ISIZE_MAX /*count*/, Dqn_ArrayErase_Unstable);
uint32_t array_literal[] = {14, 6};
DQN_UTEST_ASSERT(&test, array.size == DQN_ARRAY_UCOUNT(array_literal));
DQN_UTEST_ASSERT(&test, DQN_MEMCMP(array.data, array_literal, DQN_ARRAY_UCOUNT(array_literal) * sizeof(array_literal[0])) == 0);
@ -1843,14 +1843,6 @@ int main(int argc, char *argv[])
{
(void)argv; (void)argc;
Dqn_Library_Init();
Dqn_ThreadScratch scratch = Dqn_Thread_GetScratch(nullptr);
Dqn_StackTraceFrames stack_trace = Dqn_StackTrace_GetFrames(scratch.arena, 128 /*limit*/);
DQN_FOR_UINDEX (index, stack_trace.size) {
Dqn_StackTraceFrame frame = stack_trace.data[index];
Dqn_Print_LnF("%.*s(%I64u): %.*s", DQN_STRING_FMT(frame.file_name), frame.line_number, DQN_STRING_FMT(frame.function_name));
}
Dqn_Test_RunSuite();
return 0;
}

View File

@ -36,13 +36,13 @@ pushd Build
)
REM REM clang-cl ===================================================================================
REM set has_clang_cl=1
REM where /q clang-cl || set has_clang_cl=0
REM if %has_clang_cl% == 1 (
REM echo [BUILD] clang-cl detected, compiling ...
REM set clang_cmd=clang-cl %clang_compile_flags% %clang_link_flags%
REM powershell -Command "$time = Measure-Command { !clang_cmd! | Out-Default }; Write-Host '[BUILD] clang-cl:'$time.TotalSeconds's'; exit $LASTEXITCODE" || exit /b 1
REM )
set has_clang_cl=1
where /q clang-cl || set has_clang_cl=0
if %has_clang_cl% == 1 (
echo [BUILD] clang-cl detected, compiling ...
set clang_cmd=clang-cl %clang_compile_flags% %clang_link_flags%
powershell -Command "$time = Measure-Command { !clang_cmd! | Out-Default }; Write-Host '[BUILD] clang-cl:'$time.TotalSeconds's'; exit $LASTEXITCODE" || exit /b 1
)
REM zig ========================================================================================
REM TODO(doyle):Can't build "Misc\dqn_unit_tests.cpp|1 col 1| error: unable to build C object: FileNotFound"

62
dqn.h
View File

@ -36,7 +36,9 @@
#if !defined(DQN_H)
#if defined(DQN_ONLY_VARRAY) || \
defined(DQN_ONLY_SARRAY) || \
defined(DQN_ONLY_FARRAY) || \
defined(DQN_ONLY_SLICE) || \
defined(DQN_ONLY_DSMAP) || \
defined(DQN_ONLY_LIST) || \
defined(DQN_ONLY_FSTRING8) || \
@ -58,6 +60,12 @@
#if !defined(DQN_ONLY_FARRAY)
#define DQN_NO_FARRAY
#endif
#if !defined(DQN_ONLY_SARRAY)
#define DQN_NO_SARRAY
#endif
#if !defined(DQN_ONLY_SLICE)
#define DQN_NO_SLICE
#endif
#if !defined(DQN_ONLY_DSMAP)
#define DQN_NO_DSMAP
#endif
@ -115,8 +123,11 @@
// [$MACR] Macros | | Define macros used in the library
// [$TYPE] Types | | Basic types and typedefs
// [$INTR] Intrinsics | | Atomics, cpuid, ticket mutex
// [$CALL] Dqn_CallSite | | Source code location/tracing
// [$TMUT] Dqn_TicketMutex | | Userland mutex via spinlocking atomics
// [$ALLO] Dqn_Allocator | | Generic allocator interface
// [$PRIN] Dqn_Print | | Console printing
// [$LLOG] Dqn_Log | | Console logging macros
// NOTE: Additional Configuration
// - Override the default heap-allocation routine that is called when the
@ -166,7 +177,6 @@
#include "dqn_base.h"
// NOTE: Dqn_External ==============================================================================
// [$BSTK] b_stacktrace | | Generating call stacktraces
// [$OS_H] OS Headers | | Headers from the operating system
// [$STBS] stb_sprintf | | Portable sprintf
#include "dqn_external.h"
@ -186,18 +196,36 @@
// DQN_STB_SPRINTF_HEADER_ONLY
// NOTE: Dqn_Memory ================================================================================
// [$ALLO] Dqn_Allocator | | Generic allocator interface
// [$VMEM] Dqn_VMem | | Virtual memory allocation
// [$MEMB] Dqn_MemBlock | | Virtual memory blocks
// [$AREN] Dqn_Arena | | Growing bump allocator
// [$ACAT] Dqn_ArenaCatalog | | Collate, create & manage arenas in a catalog
#include "dqn_memory.h"
// NOTE: Dqn_Strings ===============================================================================
// [$CSTR] Dqn_CString8 | | C-string helpers
// [$STR8] Dqn_String8 | | Pointer and length strings
// [$FSTR] Dqn_FString8 | DQN_FSTRING8 | Fixed-size strings
// [$STRB] Dqn_String8Builder | |
// [$CHAR] Dqn_Char | | Character ascii/digit.. helpers
// [$UTFX] Dqn_UTF | | Unicode helpers
#include "dqn_strings.h"
// NOTE: Dqn_Containers ============================================================================
// [$CARR] Dqn_CArray | | Basic operations on C arrays for VArray/SArray/FArray to reuse
// [$VARR] Dqn_VArray | DQN_VARRAY | Array backed by virtual memory arena
// [$SARR] Dqn_SArray | DQN_SARRAY | Array that are allocated but cannot resize
// [$FARR] Dqn_FArray | DQN_FARRAY | Fixed-size arrays
// [$SLIC] Dqn_Slice | DQN_SLICE | Pointe and length container of data
// [$DMAP] Dqn_DSMap | DQN_DSMAP | Hashtable, 70% max load, PoT size, linear probe, chain repair
// [$LIST] Dqn_List | DQN_LIST | Chunked linked lists, append only
#include "dqn_containers.h"
// NOTE: Dqn_Debug =================================================================================
// [$DEBM] Debug Macros | |
// [$CALL] Dqn_CallSite | | Source code location/tracing
// [$ASAN] Dqn_Asan | | Helpers to manually poison memory using ASAN
// [$STKT] Dqn_StackTrace | | Create stack traces
// [$DEBG] Dqn_Debug | | Debugging tools/helpers
// [$LLOG] Dqn_Log | | Console logging macros
#include "dqn_debug.h"
// NOTE: Additional Configuration
@ -248,22 +276,6 @@
//
// DQN_ASAN_POISON_GUARD_SIZE 128
// NOTE: Dqn_Strings ===============================================================================
// [$CSTR] Dqn_CString8 | | C-string helpers
// [$STR8] Dqn_String8 | | Pointer and length strings
// [$FSTR] Dqn_FString8 | DQN_FSTRING8 | Fixed-size strings
// [$STRB] Dqn_String8Builder | |
// [$CHAR] Dqn_Char | | Character ascii/digit.. helpers
// [$UTFX] Dqn_UTF | | Unicode helpers
#include "dqn_strings.h"
// NOTE: Dqn_Containers ============================================================================
// [$VARR] Dqn_VArray | DQN_VARRAY | Array backed by virtual memory arena
// [$FARR] Dqn_FArray | DQN_FARRAY | Fixed-size arrays
// [$DMAP] Dqn_DSMap | DQN_DSMAP | Hashtable, 70% max load, PoT size, linear probe, chain repair
// [$LIST] Dqn_List | DQN_LIST | Chunked linked lists, append only
#include "dqn_containers.h"
// NOTE: Dqn_Platform ==============================================================================
// [$FSYS] Dqn_Fs | DQN_FS | Filesystem helpers
// [$DATE] Dqn_Date | | Date-time helpers
@ -271,16 +283,6 @@
// [$WINN] Dqn_WinNet | DQN_WINNET | Windows internet download/query helpers
// [$OSYS] Dqn_OS | DQN_WIN | Operating-system APIs
// [$TCTX] Dqn_ThreadContext | | Per-thread data structure e.g. temp arenas
// NOTE: Additional Configuration
// - When compiling with ASAN, set this macro to `1` to enable poisoning of the
// memory allocated and freed by memory arenas in the library. By default this
// is set to `0`. By enabling this, all allocations will be guarded by a page,
// before and after the returned pointer. All allocations will be aligned to
// and padded to atleast DQN_ASAN_POISON_ALIGNMENT (e.g. 8 bytes).
//
// DQN_ASAN_POISON 1
#include "dqn_platform.h"
// NOTE: Dqn_Math ==================================================================================

View File

@ -18,6 +18,27 @@ Dqn_CPUIDRegisters Dqn_CPUID(int function_id)
}
#endif // !defined(DQN_OS_ARM64)
// NOTE: [$ALLO] Dqn_Allocator =====================================================================
DQN_API void *Dqn_Allocator_Alloc(Dqn_Allocator allocator, size_t size, uint8_t align, Dqn_ZeroMem zero_mem)
{
void *result = NULL;
if (allocator.alloc) {
result = allocator.alloc(size, align, zero_mem, allocator.user_context);
} else {
result = DQN_ALLOC(size);
}
return result;
}
DQN_API void Dqn_Allocator_Dealloc(Dqn_Allocator allocator, void *ptr, size_t size)
{
if (allocator.dealloc) {
allocator.dealloc(ptr, size, allocator.user_context);
} else {
DQN_DEALLOC(ptr, size);
}
}
// NOTE: [$TMUT] Dqn_TicketMutex ===================================================================
DQN_API void Dqn_TicketMutex_Begin(Dqn_TicketMutex *mutex)
{
@ -252,3 +273,145 @@ DQN_API Dqn_String8 Dqn_Print_ESCColourU32String(Dqn_PrintESCColour colour, uint
return result;
}
// NOTE: [$LLOG] Dqn_Log ==========================================================================
DQN_API Dqn_String8 Dqn_Log_MakeString(Dqn_Allocator allocator,
bool colour,
Dqn_String8 type,
int log_type,
Dqn_CallSite call_site,
char const *fmt,
va_list args)
{
Dqn_usize header_size_no_ansi_codes = 0;
Dqn_String8 header = {};
{
DQN_LOCAL_PERSIST Dqn_usize max_type_length = 0;
max_type_length = DQN_MAX(max_type_length, type.size);
int type_padding = DQN_CAST(int)(max_type_length - type.size);
Dqn_String8 colour_esc = {};
Dqn_String8 bold_esc = {};
Dqn_String8 reset_esc = {};
if (colour) {
bold_esc = Dqn_Print_ESCBoldString;
reset_esc = Dqn_Print_ESCResetString;
switch (log_type) {
case Dqn_LogType_Debug: break;
case Dqn_LogType_Info: colour_esc = Dqn_Print_ESCColourFgU32String(Dqn_LogTypeColourU32_Info); break;
case Dqn_LogType_Warning: colour_esc = Dqn_Print_ESCColourFgU32String(Dqn_LogTypeColourU32_Warning); break;
case Dqn_LogType_Error: colour_esc = Dqn_Print_ESCColourFgU32String(Dqn_LogTypeColourU32_Error); break;
}
}
Dqn_String8 file_name = Dqn_String8_FileNameFromPath(call_site.file);
Dqn_DateHMSTimeString const time = Dqn_Date_HMSLocalTimeStringNow();
header = Dqn_String8_InitF(allocator,
"%.*s " // date
"%.*s " // hms
"%.*s" // colour
"%.*s" // bold
"%.*s" // type
"%*s" // type padding
"%.*s" // reset
" %.*s" // file name
":%05u ", // line number
DQN_CAST(uint32_t)time.date_size - 2, time.date + 2, // date
DQN_CAST(uint32_t)time.hms_size, time.hms, // hms
DQN_CAST(uint32_t)colour_esc.size, colour_esc.data, // colour
DQN_CAST(uint32_t)bold_esc.size, bold_esc.data, // bold
DQN_CAST(uint32_t)type.size, type.data, // type
DQN_CAST(uint32_t)type_padding, "", // type padding
DQN_CAST(uint32_t)reset_esc.size, reset_esc.data, // reset
DQN_CAST(uint32_t)file_name.size, file_name.data, // file name
call_site.line); // line number
header_size_no_ansi_codes = header.size - colour_esc.size - Dqn_Print_ESCResetString.size;
}
// NOTE: Header padding ========================================================================
Dqn_usize header_padding = 0;
{
DQN_LOCAL_PERSIST Dqn_usize max_header_length = 0;
max_header_length = DQN_MAX(max_header_length, header_size_no_ansi_codes);
header_padding = max_header_length - header_size_no_ansi_codes;
}
// NOTE: Construct final log ===================================================================
Dqn_String8 user_msg = Dqn_String8_InitFV(allocator, fmt, args);
Dqn_String8 result = Dqn_String8_Allocate(allocator, header.size + header_padding + user_msg.size, Dqn_ZeroMem_No);
DQN_MEMCPY(result.data, header.data, header.size);
DQN_MEMSET(result.data + header.size, ' ', header_padding);
DQN_MEMCPY(result.data + header.size + header_padding, user_msg.data, user_msg.size);
return result;
}
DQN_FILE_SCOPE void Dqn_Log_FVDefault_(Dqn_String8 type, int log_type, void *user_data, Dqn_CallSite call_site, char const *fmt, va_list args)
{
Dqn_Library *lib = g_dqn_library;
(void)log_type;
(void)user_data;
// NOTE: Open log file for appending if requested ==========================
Dqn_TicketMutex_Begin(&lib->log_file_mutex);
if (lib->log_to_file && !lib->log_file.handle && lib->log_file.error_size == 0) {
Dqn_ThreadScratch scratch = Dqn_Thread_GetScratch(nullptr);
Dqn_String8 log_path = Dqn_FsPath_ConvertF(scratch.arena, "%.*s/dqn.log", DQN_STRING_FMT(lib->exe_dir));
lib->log_file = Dqn_Fs_OpenFile(log_path, Dqn_FsFileOpen_CreateAlways, Dqn_FsFileAccess_AppendOnly);
}
Dqn_TicketMutex_End(&lib->log_file_mutex);
// NOTE: Generate the log header ===========================================
Dqn_ThreadScratch scratch = Dqn_Thread_GetScratch(nullptr);
Dqn_String8 log_line = Dqn_Log_MakeString(scratch.allocator,
!lib->log_no_colour,
type,
log_type,
call_site,
fmt,
args);
// NOTE: Print log =========================================================
Dqn_Print_StdLn(Dqn_PrintStd_Out, log_line);
Dqn_TicketMutex_Begin(&lib->log_file_mutex);
Dqn_Fs_WriteFile(&lib->log_file, log_line);
Dqn_Fs_WriteFile(&lib->log_file, DQN_STRING8("\n"));
Dqn_TicketMutex_End(&lib->log_file_mutex);
}
DQN_API void Dqn_Log_FVCallSite(Dqn_String8 type, Dqn_CallSite call_site, char const *fmt, va_list args)
{
Dqn_LogProc *logging_function = g_dqn_library->log_callback ? g_dqn_library->log_callback : Dqn_Log_FVDefault_;
logging_function(type, -1 /*log_type*/, g_dqn_library->log_user_data, call_site, fmt, args);
}
DQN_API void Dqn_Log_FCallSite(Dqn_String8 type, Dqn_CallSite call_site, char const *fmt, ...)
{
va_list args;
va_start(args, fmt);
Dqn_Log_FVCallSite(type, call_site, fmt, args);
va_end(args);
}
DQN_API void Dqn_Log_TypeFVCallSite(Dqn_LogType type, Dqn_CallSite call_site, char const *fmt, va_list args)
{
Dqn_String8 type_string = DQN_STRING8("DQN-BAD-LOG-TYPE");
switch (type) {
case Dqn_LogType_Error: type_string = DQN_STRING8("ERROR"); break;
case Dqn_LogType_Info: type_string = DQN_STRING8("INFO"); break;
case Dqn_LogType_Warning: type_string = DQN_STRING8("WARN"); break;
case Dqn_LogType_Debug: type_string = DQN_STRING8("DEBUG"); break;
case Dqn_LogType_Count: type_string = DQN_STRING8("BADXX"); break;
}
Dqn_LogProc *logging_function = g_dqn_library->log_callback ? g_dqn_library->log_callback : Dqn_Log_FVDefault_;
logging_function(type_string, type /*log_type*/, g_dqn_library->log_user_data, call_site, fmt, args);
}
DQN_API void Dqn_Log_TypeFCallSite(Dqn_LogType type, Dqn_CallSite call_site, char const *fmt, ...)
{
va_list args;
va_start(args, fmt);
Dqn_Log_TypeFVCallSite(type, call_site, fmt, args);
va_end(args);
}

View File

@ -182,12 +182,34 @@
#define DQN_DAYS_TO_S(val) (DQN_HOURS_TO_S(val) * 24ULL)
#define DQN_YEARS_TO_S(val) (DQN_DAYS_TO_S(val) * 365ULL)
// NOTE: Debug Break ===============================================================================
#if !defined(DQN_DEBUG_BREAK)
#if defined(NDEBUG)
#define DQN_DEBUG_BREAK
#else
#if defined(DQN_COMPILER_MSVC) || defined(DQN_COMPILER_CLANG_CL)
#define DQN_DEBUG_BREAK __debugbreak()
#elif defined(DQN_COMPILER_CLANG)
#define DQN_DEBUG_BREAK __builtin_debugtrap()
#elif defined(DQN_COMPILER_CLANG) || defined(DQN_COMPILER_GCC)
#include <signal.h>
#define DQN_DEBUG_BREAK raise(SIGTRAP)
#elif
#error "Unhandled compiler"
#endif
#endif
#endif
#if !defined(DQN_MEMSET_BYTE)
#define DQN_MEMSET_BYTE 0
#endif
// NOTE: Assert Macros =============================================================================
#define DQN_HARD_ASSERT(expr) DQN_HARD_ASSERTF(expr, "")
#define DQN_HARD_ASSERTF(expr, fmt, ...) \
if (!(expr)) { \
Dqn_Log_ErrorF("Hard assert triggered " #expr ". " fmt, ##__VA_ARGS__); \
DQN_DUMP_STACK_TRACE; \
Dqn_StackTrace_Print(128 /*limit*/); \
DQN_DEBUG_BREAK; \
}
@ -199,7 +221,7 @@
#define DQN_ASSERTF(expr, fmt, ...) \
if (!(expr)) { \
Dqn_Log_ErrorF("Assert triggered " #expr ". " fmt, ##__VA_ARGS__); \
DQN_DUMP_STACK_TRACE; \
Dqn_StackTrace_Print(128 /*limit*/); \
DQN_DEBUG_BREAK; \
}
#endif
@ -307,6 +329,15 @@ struct Dqn_String8
char *end () { return data + size; }
};
// NOTE: [$CALL] Dqn_CallSite ======================================================================
struct Dqn_CallSite
{
Dqn_String8 file;
Dqn_String8 function;
unsigned int line;
};
#define DQN_CALL_SITE Dqn_CallSite{DQN_STRING8(__FILE__), DQN_STRING8(__func__), __LINE__}
// NOTE: [$INTR] Intrinsics ========================================================================
// Platform agnostic functions for CPU level instructions like atomics, barriers
// and timestamp counters.
@ -446,6 +477,25 @@ Dqn_uint Dqn_TicketMutex_MakeTicket (Dqn_TicketMutex *mutex);
void Dqn_TicketMutex_BeginTicket(Dqn_TicketMutex const *mutex, Dqn_uint ticket);
bool Dqn_TicketMutex_CanLock (Dqn_TicketMutex const *mutex, Dqn_uint ticket);
// NOTE: [$ALLO] Dqn_Allocator =====================================================================
typedef void *Dqn_Allocator_AllocProc(size_t size, uint8_t align, Dqn_ZeroMem zero_mem, void *user_context);
typedef void Dqn_Allocator_DeallocProc(void *ptr, size_t size, void *user_context);
struct Dqn_Allocator
{
void *user_context; // User assigned pointer that is passed into the allocator functions
Dqn_Allocator_AllocProc *alloc; // Memory allocating routine
Dqn_Allocator_DeallocProc *dealloc; // Memory deallocating routine
};
// NOTE: Macros ====================================================================================
#define Dqn_Allocator_NewArray(allocator, Type, count, zero_mem) (Type *)Dqn_Allocator_Alloc(allocator, sizeof(Type) * count, alignof(Type), zero_mem)
#define Dqn_Allocator_New(allocator, Type, zero_mem) (Type *)Dqn_Allocator_Alloc(allocator, sizeof(Type), alignof(Type), zero_mem)
// NOTE: API =======================================================================================
void *Dqn_Allocator_Alloc (Dqn_Allocator allocator, size_t size, uint8_t align, Dqn_ZeroMem zero_mem);
void Dqn_Allocator_Dealloc(Dqn_Allocator allocator, void *ptr, size_t size);
// NOTE: [$PRIN] Dqn_Print =========================================================================
enum Dqn_PrintStd
{
@ -547,3 +597,52 @@ Dqn_String8 Dqn_Print_ESCColourU32String(Dqn_PrintESCColour colour, u
#define Dqn_Print_ESCResetString DQN_STRING8(Dqn_Print_ESCReset)
#define Dqn_Print_ESCBoldString DQN_STRING8(Dqn_Print_ESCBold)
// NOTE: [$LLOG] Dqn_Log ==========================================================================
// NOTE: API
// @proc Dqn_LogProc
// @desc The logging procedure of the library. Users can override the default
// logging function by setting the logging function pointer in Dqn_Library.
// This function will be invoked every time a log is recorded using the
// following functions.
//
// @param[in] log_type This value is one of the Dqn_LogType values if the log
// was generated from one of the default categories. -1 if the log is not from
// one of the default categories.
enum Dqn_LogType
{
Dqn_LogType_Debug,
Dqn_LogType_Info,
Dqn_LogType_Warning,
Dqn_LogType_Error,
Dqn_LogType_Count,
};
/// RGBA
#define Dqn_LogTypeColourU32_Info 0x00'87'ff'ff // Blue
#define Dqn_LogTypeColourU32_Warning 0xff'ff'00'ff // Yellow
#define Dqn_LogTypeColourU32_Error 0xff'00'00'ff // Red
typedef void Dqn_LogProc(Dqn_String8 type, int log_type, void *user_data, Dqn_CallSite call_site, char const *fmt, va_list va);
#define Dqn_Log_DebugF(fmt, ...) Dqn_Log_TypeFCallSite(Dqn_LogType_Debug, DQN_CALL_SITE, fmt, ## __VA_ARGS__)
#define Dqn_Log_InfoF(fmt, ...) Dqn_Log_TypeFCallSite(Dqn_LogType_Info, DQN_CALL_SITE, fmt, ## __VA_ARGS__)
#define Dqn_Log_WarningF(fmt, ...) Dqn_Log_TypeFCallSite(Dqn_LogType_Warning, DQN_CALL_SITE, fmt, ## __VA_ARGS__)
#define Dqn_Log_ErrorF(fmt, ...) Dqn_Log_TypeFCallSite(Dqn_LogType_Error, DQN_CALL_SITE, fmt, ## __VA_ARGS__)
#define Dqn_Log_DebugFV(fmt, args) Dqn_Log_TypeFVCallSite(Dqn_LogType_Debug, DQN_CALL_SITE, fmt, args)
#define Dqn_Log_InfoFV(fmt, args) Dqn_Log_TypeFVCallSite(Dqn_LogType_Info, DQN_CALL_SITE, fmt, args)
#define Dqn_Log_WarningFV(fmt, args) Dqn_Log_TypeFVCallSite(Dqn_LogType_Warning, DQN_CALL_SITE, fmt, args)
#define Dqn_Log_ErrorFV(fmt, args) Dqn_Log_TypeFVCallSite(Dqn_LogType_Error, DQN_CALL_SITE, fmt, args)
#define Dqn_Log_TypeFV(type, fmt, args) Dqn_Log_TypeFVCallSite(type, DQN_CALL_SITE, fmt, args)
#define Dqn_Log_TypeF(type, fmt, ...) Dqn_Log_TypeFCallSite(type, DQN_CALL_SITE, fmt, ## __VA_ARGS__)
#define Dqn_Log_FV(type, fmt, args) Dqn_Log_FVCallSite(type, DQN_CALL_SITE, fmt, args)
#define Dqn_Log_F(type, fmt, ...) Dqn_Log_FCallSite(type, DQN_CALL_SITE, fmt, ## __VA_ARGS__)
DQN_API Dqn_String8 Dqn_Log_MakeString (Dqn_Allocator allocator, bool colour, Dqn_String8 type, int log_type, Dqn_CallSite call_site, char const *fmt, va_list args);
DQN_API void Dqn_Log_TypeFVCallSite(Dqn_LogType type, Dqn_CallSite call_site, DQN_FMT_STRING_ANNOTATE char const *fmt, va_list va);
DQN_API void Dqn_Log_TypeFCallSite (Dqn_LogType type, Dqn_CallSite call_site, DQN_FMT_STRING_ANNOTATE char const *fmt, ...);
DQN_API void Dqn_Log_FVCallSite (Dqn_String8 type, Dqn_CallSite call_site, DQN_FMT_STRING_ANNOTATE char const *fmt, va_list va);
DQN_API void Dqn_Log_FCallSite (Dqn_String8 type, Dqn_CallSite call_site, DQN_FMT_STRING_ANNOTATE char const *fmt, ...);

View File

@ -1,3 +1,13 @@
// NOTE: [$CARR] Dqn_CArray ========================================================================
enum Dqn_ArrayErase
{
Dqn_ArrayErase_Unstable,
Dqn_ArrayErase_Stable,
};
template <typename T> Dqn_usize Dqn_CArray_EraseRange(T* data, Dqn_usize *size, Dqn_usize begin_index, Dqn_isize count, Dqn_ArrayErase erase);
template <typename T> T * Dqn_CArray_Make (T* data, Dqn_usize *size, Dqn_usize max, Dqn_usize count, Dqn_ZeroMem zero_mem);
#if !defined(DQN_NO_VARRAY)
// NOTE: [$VARR] Dqn_VArray ========================================================================
// An array that is backed by virtual memory by reserving addressing space and
@ -74,12 +84,6 @@ template <typename T> struct Dqn_VArray
T const *end () const { return data + size; }
};
enum Dqn_VArrayErase
{
Dqn_VArrayErase_Unstable,
Dqn_VArrayErase_Stable,
};
// NOTE: Setup =====================================================================================
DQN_API template <typename T> Dqn_VArray<T> Dqn_VArray_InitByteSize(Dqn_Arena *arena, Dqn_usize byte_size);
DQN_API template <typename T> Dqn_VArray<T> Dqn_VArray_Init (Dqn_Arena *arena, Dqn_usize max);
@ -91,10 +95,83 @@ DQN_API template <typename T> T * Dqn_VArray_Make (Dqn_VArray<T
DQN_API template <typename T> T * Dqn_VArray_Add (Dqn_VArray<T> *array, T const *items, Dqn_usize count);
// NOTE: Modify ====================================================================================
DQN_API template <typename T> void Dqn_VArray_EraseRange (Dqn_VArray<T> *array, Dqn_usize begin_index, Dqn_isize count, Dqn_VArrayErase erase);
DQN_API template <typename T> void Dqn_VArray_EraseRange (Dqn_VArray<T> *array, Dqn_usize begin_index, Dqn_isize count, Dqn_ArrayErase erase);
DQN_API template <typename T> void Dqn_VArray_Clear (Dqn_VArray<T> *array);
#endif // !defined(DQN_NO_VARRAY)
#if !defined(DQN_NO_SARRAY)
// NOTE: [$SARR] Dqn_SArray ========================================================================
template <typename T> struct Dqn_SArray
{
T *data; // Pointer to the start of the array items in the block of memory
Dqn_usize size; // Number of items currently in the array
Dqn_usize max; // Maximum number of items this array can store
T *begin() { return data; }
T *end () { return data + size; }
T const *begin() const { return data; }
T const *end () const { return data + size; }
};
// NOTE: Setup =====================================================================================
DQN_API template <typename T> Dqn_SArray<T> Dqn_SArray_Init (Dqn_Arena *arena, Dqn_usize size, Dqn_ZeroMem zero_mem);
DQN_API template <typename T> bool Dqn_SArray_IsValid (Dqn_SArray<T> const *array);
// NOTE: Insert ====================================================================================
DQN_API template <typename T> T * Dqn_SArray_Make (Dqn_SArray<T> *array, Dqn_usize count, Dqn_ZeroMem zero_mem);
DQN_API template <typename T> T * Dqn_SArray_AddArray(Dqn_SArray<T> *array, T const *items, Dqn_usize count);
DQN_API template <typename T> T * Dqn_SArray_Add (Dqn_SArray<T> *array, T const &item);
// NOTE: Modify ====================================================================================
DQN_API template <typename T> void Dqn_SArray_EraseRange(Dqn_SArray<T> *array, Dqn_usize begin_index, Dqn_isize count, Dqn_ArrayErase erase);
DQN_API template <typename T> void Dqn_SArray_Clear (Dqn_SArray<T> *array);
#endif // !defined(DQN_NO_SARRAY)
#if !defined(DQN_NO_FARRAY)
// NOTE: [$FARR] Dqn_FArray ========================================================================
template <typename T, Dqn_usize N> struct Dqn_FArray
{
T data[N]; // Pointer to the start of the array items in the block of memory
Dqn_usize size; // Number of items currently in the array
T *begin() { return data; }
T *end () { return data + size; }
T const *begin() const { return data; }
T const *end () const { return data + size; }
};
// NOTE: Setup =====================================================================================
DQN_API template <typename T, Dqn_usize N> Dqn_FArray<T, N> Dqn_FArray_Init (T const *array, Dqn_usize count);
DQN_API template <typename T, Dqn_usize N> bool Dqn_FArray_IsValid (Dqn_FArray<T, N> const *array);
// NOTE: Insert ====================================================================================
DQN_API template <typename T, Dqn_usize N> T * Dqn_FArray_Make (Dqn_FArray<T, N> *array, Dqn_usize count, Dqn_ZeroMem zero_mem);
DQN_API template <typename T, Dqn_usize N> T * Dqn_FArray_Add (Dqn_FArray<T, N> *array, T const *items, Dqn_usize count);
// NOTE: Modify ====================================================================================
DQN_API template <typename T, Dqn_usize N> void Dqn_FArray_EraseRange(Dqn_FArray<T, N> *array, Dqn_usize begin_index, Dqn_isize count, Dqn_ArrayErase erase);
DQN_API template <typename T, Dqn_usize N> void Dqn_FArray_Clear (Dqn_FArray<T, N> *array);
#endif // !defined(DQN_NO_FARRAY)
#if !defined(DQN_NO_SLICE)
// NOTE: [$SLIC] Dqn_Slice =========================================================================
// A pointer and length container of data
template <typename T> struct Dqn_Slice
{
T *data;
Dqn_usize size;
T *begin() { return data; }
T *end () { return data + size; }
T const *begin() const { return data; }
T const *end () const { return data + size; }
};
template <typename T> Dqn_Slice<T> Dqn_Slice_Init (T* const data, Dqn_usize size);
template <typename T> Dqn_Slice<T> Dqn_Slice_Alloc(Dqn_Arena *arena, Dqn_usize size, Dqn_ZeroMem zero_mem);
#endif // !defined(DQN_NO_SLICE)
#if !defined(DQN_NO_DSMAP)
// NOTE: [$DMAP] Dqn_DSMap =========================================================================
// A hash table configured using the presets recommended by Demitri Spanos
@ -295,38 +372,6 @@ DQN_API bool Dqn_DSMap_KeyEquals (Dqn_DS
DQN_API bool operator== (Dqn_DSMapKey lhs, Dqn_DSMapKey rhs);
#endif // !defined(DQN_NO_DSMAP)
#if !defined(DQN_NO_FARRAY)
// NOTE: [$FARR] Dqn_FArray ========================================================================
template <typename T, Dqn_usize N> struct Dqn_FArray
{
T data[N]; // Pointer to the start of the array items in the block of memory
Dqn_usize size; // Number of items currently in the array
T *begin() { return data; }
T *end () { return data + size; }
T const *begin() const { return data; }
T const *end () const { return data + size; }
};
enum Dqn_FArrayErase
{
Dqn_FArrayErase_Unstable,
Dqn_FArrayErase_Stable,
};
// NOTE: Setup =====================================================================================
DQN_API template <typename T, Dqn_usize N> Dqn_FArray<T, N> Dqn_FArray_Init (T const *array, Dqn_usize count);
DQN_API template <typename T, Dqn_usize N> bool Dqn_FArray_IsValid (Dqn_FArray<T, N> const *array);
// NOTE: Insert ====================================================================================
DQN_API template <typename T, Dqn_usize N> T * Dqn_FArray_Make (Dqn_FArray<T, N> *array, Dqn_usize count, Dqn_ZeroMem zero_mem);
DQN_API template <typename T, Dqn_usize N> T * Dqn_FArray_Add (Dqn_FArray<T, N> *array, T const *items, Dqn_usize count);
// NOTE: Modify ====================================================================================
DQN_API template <typename T, Dqn_usize N> void Dqn_FArray_EraseRange(Dqn_FArray<T, N> *array, Dqn_usize begin_index, Dqn_isize count, Dqn_FArrayErase erase);
DQN_API template <typename T, Dqn_usize N> void Dqn_FArray_Clear (Dqn_FArray<T, N> *array);
#endif // !defined(DQN_NO_FARRAY)
#if !defined(DQN_NO_LIST)
// NOTE: [$LIST] Dqn_List ==========================================================================
//
@ -384,6 +429,73 @@ template <typename T> T * Dqn_List_Make (Dqn_List<T> *list, Dqn_usize
template <typename T> T * Dqn_List_Add (Dqn_List<T> *list, T const &value);
#endif // !defined(DQN_NO_LIST)
// NOTE: [$CARR] Dqn_CArray ========================================================================
template <typename T> Dqn_usize Dqn_CArray_EraseRange(T* data, Dqn_usize *size, Dqn_usize begin_index, Dqn_isize count, Dqn_ArrayErase erase)
{
Dqn_usize result = 0;
if (!data || !size || *size == 0 || count == 0)
return result;
// NOTE: Caculate the end index of the erase range
Dqn_isize abs_count = DQN_ABS(count);
Dqn_usize end_index = 0;
if (count < 0) {
end_index = begin_index - (abs_count - 1);
if (end_index > begin_index)
end_index = 0;
} else {
end_index = begin_index + (abs_count - 1);
if (end_index < begin_index)
end_index = (*size) - 1;
}
// NOTE: Ensure begin_index < one_past_end_index
if (end_index < begin_index) {
Dqn_usize tmp = begin_index;
begin_index = end_index;
end_index = tmp;
}
// NOTE: Ensure indexes are within valid bounds
begin_index = DQN_MIN(begin_index, *size);
end_index = DQN_MIN(end_index, *size - 1);
// NOTE: Erase the items in the range [begin_index, one_past_end_index)
Dqn_usize one_past_end_index = end_index + 1;
Dqn_usize erase_count = one_past_end_index - begin_index;
if (erase_count) {
T *end = data + *size;
T *dest = data + begin_index;
if (erase == Dqn_ArrayErase_Stable) {
T *src = dest + erase_count;
DQN_MEMMOVE(dest, src, (end - src) * sizeof(T));
} else {
T *src = end - erase_count;
DQN_MEMCPY(dest, src, (end - src) * sizeof(T));
}
*size -= erase_count;
}
result = erase_count;
return result;
}
template <typename T> T *Dqn_CArray_Make(T* data, Dqn_usize *size, Dqn_usize max, Dqn_usize count, Dqn_ZeroMem zero_mem)
{
if (!data || !size || count == 0)
return nullptr;
if (!DQN_CHECKF((*size + count) < max, "Array is out of memory"))
return nullptr;
// TODO: Use placement new? Why doesn't this work?
T *result = data + *size;
*size += count;
if (zero_mem == Dqn_ZeroMem_Yes)
DQN_MEMSET(result, DQN_MEMSET_BYTE, sizeof(*result) * count);
return result;
}
#if !defined(DQN_NO_VARRAY)
// NOTE: [$VARR] Dqn_VArray ========================================================================
DQN_API template <typename T> Dqn_VArray<T> Dqn_VArray_InitByteSize(Dqn_Arena *arena, Dqn_usize byte_size)
@ -431,52 +543,13 @@ DQN_API template <typename T> T *Dqn_VArray_Add(Dqn_VArray<T> *array, T const *i
return result;
}
DQN_API template <typename T> void Dqn_VArray_EraseRange(Dqn_VArray<T> *array, Dqn_usize begin_index, Dqn_isize count, Dqn_VArrayErase erase)
DQN_API template <typename T> void Dqn_VArray_EraseRange(Dqn_VArray<T> *array, Dqn_usize begin_index, Dqn_isize count, Dqn_ArrayErase erase)
{
if (!Dqn_VArray_IsValid(array) || array->size == 0 || count == 0)
if (!Dqn_VArray_IsValid(array))
return;
// NOTE: Caculate the end index of the erase range
Dqn_isize abs_count = DQN_ABS(count);
Dqn_usize end_index = 0;
if (count < 0) {
end_index = begin_index - (abs_count - 1);
if (end_index > begin_index)
end_index = 0;
} else {
end_index = begin_index + (abs_count - 1);
if (end_index < begin_index)
end_index = array->size - 1;
}
// NOTE: Ensure begin_index < one_past_end_index
if (end_index < begin_index) {
Dqn_usize tmp = begin_index;
begin_index = end_index;
end_index = tmp;
}
// NOTE: Ensure indexes are within valid bounds
begin_index = DQN_MIN(begin_index, array->size);
end_index = DQN_MIN(end_index, array->size - 1);
// NOTE: Erase the items in the range [begin_index, one_past_end_index)
Dqn_usize one_past_end_index = end_index + 1;
Dqn_usize erase_count = one_past_end_index - begin_index;
if (erase_count) {
T *end = array->data + array->size;
T *dest = array->data + begin_index;
if (erase == Dqn_VArrayErase_Stable) {
T *src = dest + erase_count;
DQN_MEMMOVE(dest, src, (end - src) * sizeof(T));
} else {
T *src = end - erase_count;
DQN_MEMCPY(dest, src, (end - src) * sizeof(T));
}
array->size -= erase_count;
Dqn_usize erase_count = Dqn_CArray_EraseRange<T>(array->data, &array->size, begin_index, count, erase);
Dqn_MemBlock_Pop(array->block, erase_count * sizeof(T));
}
}
DQN_API template <typename T> void Dqn_VArray_Clear(Dqn_VArray<T> *array)
{
@ -493,6 +566,128 @@ DQN_API template <typename T> void Dqn_VArray_Reserve(Dqn_VArray<T> *array, Dqn_
}
#endif // !defined(DQN_NO_VARRAY)
#if !defined(DQN_NO_SARRAY)
// NOTE: [$FARR] Dqn_SArray ========================================================================
DQN_API template <typename T> Dqn_SArray<T> Dqn_SArray_Init(Dqn_Arena *arena, Dqn_usize size, Dqn_ZeroMem zero_mem)
{
Dqn_SArray<T> result = {};
if (!arena || !count)
return result;
result.data = Dqn_Arena_NewArray(arena, T, size, zero_mem);
if (result.data)
result.max = size;
return result;
}
DQN_API template <typename T> bool Dqn_SArray_IsValid(Dqn_SArray<T> const *array)
{
bool result = array && array->data && array->size <= array->max;
return result;
}
DQN_API template <typename T> T *Dqn_SArray_Make(Dqn_SArray<T> *array, Dqn_usize count, Dqn_ZeroMem zero_mem)
{
if (!Dqn_SArray_IsValid(array))
return nullptr;
T *result = Dqn_CArray_Make(array->data, &array->size, array->max, count, zero_mem);
return result;
}
DQN_API template <typename T> T *Dqn_SArray_AddArray(Dqn_SArray<T> *array, T const *items, Dqn_usize count)
{
T *result = Dqn_SArray_Make(array, count, Dqn_ZeroMem_No);
if (result)
DQN_MEMCPY(result, items, count * sizeof(T));
}
DQN_API template <typename T> T *Dqn_SArray_Add(Dqn_SArray<T> *array, T const &item)
{
T *result = Dqn_SArray_AddArray(array, &item, 1);
return result;
}
DQN_API template <typename T> void Dqn_SArray_EraseRange(Dqn_SArray<T> *array, Dqn_usize begin_index, Dqn_isize count, Dqn_ArrayErase erase)
{
if (!Dqn_SArray_IsValid(array) || array->size == 0 || count == 0)
return;
Dqn_CArray_EraseRange(array->data, &array->size, being_index, count, erase);
}
DQN_API template <typename T> void Dqn_SArray_Clear(Dqn_SArray<T> *array)
{
if (array)
array->size = 0;
}
#endif // !defined(DQN_NO_SARRAY)
#if !defined(DQN_NO_FARRAY)
// NOTE: [$FARR] Dqn_FArray ========================================================================
DQN_API template <typename T, Dqn_usize N> Dqn_FArray<T, N> Dqn_FArray_Init(T const *array, Dqn_usize count)
{
Dqn_FArray<T, N> result = {};
bool added = Dqn_FArray_Add(&result, array, count);
DQN_ASSERT(added);
return result;
}
DQN_API template <typename T, Dqn_usize N> bool Dqn_FArray_IsValid(Dqn_FArray<T, N> const *array)
{
bool result = array && array->size <= DQN_ARRAY_UCOUNT(array->data);
return result;
}
DQN_API template <typename T, Dqn_usize N> T *Dqn_FArray_Make(Dqn_FArray<T, N> *array, Dqn_usize count, Dqn_ZeroMem zero_mem)
{
if (!Dqn_FArray_IsValid(array))
return nullptr;
T *result = Dqn_CArray_Make(array->data, &array->size, N, count, zero_mem);
return result;
}
DQN_API template <typename T, Dqn_usize N> T *Dqn_FArray_Add(Dqn_FArray<T, N> *array, T const *items, Dqn_usize count)
{
T *result = Dqn_FArray_Make(array, count, Dqn_ZeroMem_No);
if (result)
DQN_MEMCPY(result, items, count * sizeof(T));
return result;
}
DQN_API template <typename T, Dqn_usize N> void Dqn_FArray_EraseRange(Dqn_FArray<T, N> *array, Dqn_usize begin_index, Dqn_isize count, Dqn_ArrayErase erase)
{
if (!Dqn_FArray_IsValid(array) || array->size == 0 || count == 0)
return;
Dqn_CArray_EraseRange(array->data, &array->size, begin_index, count, erase);
}
DQN_API template <typename T, Dqn_usize N> void Dqn_FArray_Clear(Dqn_FArray<T, N> *array)
{
if (array)
array->size = 0;
}
#endif // !defined(DQN_NO_FARRAY)
#if !defined(DQN_NO_SLICE)
template <typename T> Dqn_Slice<T> Dqn_Slice_Init(T* const data, Dqn_usize size)
{
Dqn_Slice<T> result = {};
if (data) {
result.data = data;
result.size = size;
}
return result;
}
template <typename T> Dqn_Slice<T> Dqn_Slice_Alloc(Dqn_Arena *arena, Dqn_usize size, Dqn_ZeroMem zero_mem)
{
Dqn_Slice<T> result = {};
if (!arena || size == 0)
return result;
result.data = Dqn_Arena_NewArray(arena, T, size, zero_mem);
if (result.data)
result.size = size;
return result;
}
#endif // !defined(DQN_NO_SLICE)
#if !defined(DQN_NO_DSMAP)
// NOTE: [$DMAP] Dqn_DSMap =========================================================================
uint32_t const DQN_DS_MAP_DEFAULT_HASH_SEED = 0x8a1ced49;
@ -845,98 +1040,6 @@ DQN_API Dqn_DSMapKey Dqn_DSMap_KeyString8Copy(Dqn_DSMap<T> const *map, Dqn_Alloc
}
#endif // !defined(DQN_NO_DSMAP)
#if !defined(DQN_NO_FARRAY)
// NOTE: [$FARR] Dqn_FArray ========================================================================
DQN_API template <typename T, Dqn_usize N> Dqn_FArray<T, N> Dqn_FArray_Init(T const *array, Dqn_usize count)
{
Dqn_FArray<T, N> result = {};
bool added = Dqn_FArray_Add(&result, array, count);
DQN_ASSERT(added);
return result;
}
DQN_API template <typename T, Dqn_usize N> bool Dqn_FArray_IsValid(Dqn_FArray<T, N> const *array)
{
bool result = array && array->size <= DQN_ARRAY_UCOUNT(array->data);
return result;
}
DQN_API template <typename T, Dqn_usize N> T *Dqn_FArray_Make(Dqn_FArray<T, N> *array, Dqn_usize count, Dqn_ZeroMem zero_mem)
{
if (!Dqn_FArray_IsValid(array))
return nullptr;
if (!DQN_CHECKF((array->size + count) < DQN_ARRAY_UCOUNT(array->data), "Array is out of memory"))
return nullptr;
// TODO: Use placement new? Why doesn't this work?
T *result = array->data + array->size;
array->size += count;
if (zero_mem == Dqn_ZeroMem_Yes)
DQN_MEMSET(result, DQN_MEMSET_BYTE, sizeof(*result) * count);
return result;
}
DQN_API template <typename T, Dqn_usize N> T *Dqn_FArray_Add(Dqn_FArray<T, N> *array, T const *items, Dqn_usize count)
{
T *result = Dqn_FArray_Make(array, count, Dqn_ZeroMem_No);
if (result)
DQN_MEMCPY(result, items, count * sizeof(T));
return result;
}
DQN_API template <typename T, Dqn_usize N> void Dqn_FArray_EraseRange(Dqn_FArray<T, N> *array, Dqn_usize begin_index, Dqn_isize count, Dqn_FArrayErase erase)
{
if (!Dqn_FArray_IsValid(array) || array->size == 0 || count == 0)
return;
// NOTE: Caculate the end index of the erase range
Dqn_isize abs_count = DQN_ABS(count);
Dqn_usize end_index = 0;
if (count < 0) {
end_index = begin_index - (abs_count - 1);
if (end_index > begin_index)
end_index = 0;
} else {
end_index = begin_index + (abs_count - 1);
if (end_index < begin_index)
end_index = array->size - 1;
}
// NOTE: Ensure begin_index < one_past_end_index
if (end_index < begin_index) {
Dqn_usize tmp = begin_index;
begin_index = end_index;
end_index = tmp;
}
// NOTE: Ensure indexes are within valid bounds
begin_index = DQN_MIN(begin_index, array->size);
end_index = DQN_MIN(end_index, array->size - 1);
// NOTE: Erase the items in the range [begin_index, one_past_end_index)
Dqn_usize one_past_end_index = end_index + 1;
Dqn_usize erase_count = one_past_end_index - begin_index;
if (erase_count) {
T *end = array->data + array->size;
T *dest = array->data + begin_index;
if (erase == Dqn_FArrayErase_Stable) {
T *src = dest + erase_count;
DQN_MEMMOVE(dest, src, (end - src) * sizeof(T));
} else {
T *src = end - erase_count;
DQN_MEMCPY(dest, src, (end - src) * sizeof(T));
}
array->size -= erase_count;
}
}
DQN_API template <typename T, Dqn_usize N> void Dqn_FArray_Clear(Dqn_FArray<T, N> *array)
{
if (array)
array->size = 0;
}
#endif // !defined(DQN_NO_FARRAY)
#if !defined(DQN_NO_LIST)
// NOTE: [$LIST] Dqn_List ==========================================================================
template <typename T> DQN_API Dqn_List<T> Dqn_List_Init(Dqn_Arena *arena, Dqn_usize chunk_size)

View File

@ -146,22 +146,31 @@ DQN_API Dqn_StackTraceFrame Dqn_StackTrace_RawFrameToFrame(Dqn_Arena *arena, Dqn
return result;
}
DQN_API Dqn_StackTraceFrames Dqn_StackTrace_GetFrames(Dqn_Arena *arena, uint16_t limit)
DQN_API Dqn_Slice<Dqn_StackTraceFrame> Dqn_StackTrace_GetFrames(Dqn_Arena *arena, uint16_t limit)
{
Dqn_StackTraceFrames result = {};
Dqn_Slice<Dqn_StackTraceFrame> result = {};
Dqn_ThreadScratch scratch = Dqn_Thread_GetScratch(arena);
Dqn_StackTraceWalkResult walk = Dqn_StackTrace_Walk(scratch.arena, limit);
if (!walk.size)
return result;
result.data = Dqn_Arena_NewArray(arena, Dqn_StackTraceFrame, walk.size, Dqn_ZeroMem_No);
Dqn_usize slice_index = 0;
result = Dqn_Slice_Alloc<Dqn_StackTraceFrame>(arena, walk.size, Dqn_ZeroMem_No);
for (Dqn_StackTraceWalkResultIterator it = {}; Dqn_StackTrace_WalkResultIterate(&it, &walk); ) {
result.data[result.size++] = Dqn_StackTrace_RawFrameToFrame(arena, it.raw_frame);
result.data[slice_index++] = Dqn_StackTrace_RawFrameToFrame(arena, it.raw_frame);
}
return result;
}
DQN_API void Dqn_StackTrace_Print(uint16_t limit)
{
Dqn_ThreadScratch scratch = Dqn_Thread_GetScratch(nullptr);
Dqn_Slice<Dqn_StackTraceFrame> stack_trace = Dqn_StackTrace_GetFrames(scratch.arena, limit);
for (Dqn_StackTraceFrame& frame : stack_trace)
Dqn_Print_ErrLnF("%.*s(%I64u): %.*s", DQN_STRING_FMT(frame.file_name), frame.line_number, DQN_STRING_FMT(frame.function_name));
}
// NOTE: [$DEBG] Dqn_Debug =========================================================================
#if defined(DQN_LEAK_TRACING)
DQN_API void Dqn_Debug_TrackAlloc_(Dqn_String8 stack_trace, void *ptr, Dqn_usize size, bool leak_permitted)
@ -315,146 +324,3 @@ DQN_API void Dqn_Debug_DumpLeaks()
}
}
#endif // defined(DQN_LEAK_TRACING)
// NOTE: [$LLOG] Dqn_Log ==========================================================================
DQN_API Dqn_String8 Dqn_Log_MakeString(Dqn_Allocator allocator,
bool colour,
Dqn_String8 type,
int log_type,
Dqn_CallSite call_site,
char const *fmt,
va_list args)
{
Dqn_usize header_size_no_ansi_codes = 0;
Dqn_String8 header = {};
{
DQN_LOCAL_PERSIST Dqn_usize max_type_length = 0;
max_type_length = DQN_MAX(max_type_length, type.size);
int type_padding = DQN_CAST(int)(max_type_length - type.size);
Dqn_String8 colour_esc = {};
Dqn_String8 bold_esc = {};
Dqn_String8 reset_esc = {};
if (colour) {
bold_esc = Dqn_Print_ESCBoldString;
reset_esc = Dqn_Print_ESCResetString;
switch (log_type) {
case Dqn_LogType_Debug: break;
case Dqn_LogType_Info: colour_esc = Dqn_Print_ESCColourFgU32String(Dqn_LogTypeColourU32_Info); break;
case Dqn_LogType_Warning: colour_esc = Dqn_Print_ESCColourFgU32String(Dqn_LogTypeColourU32_Warning); break;
case Dqn_LogType_Error: colour_esc = Dqn_Print_ESCColourFgU32String(Dqn_LogTypeColourU32_Error); break;
}
}
Dqn_String8 file_name = Dqn_String8_FileNameFromPath(call_site.file);
Dqn_DateHMSTimeString const time = Dqn_Date_HMSLocalTimeStringNow();
header = Dqn_String8_InitF(allocator,
"%.*s " // date
"%.*s " // hms
"%.*s" // colour
"%.*s" // bold
"%.*s" // type
"%*s" // type padding
"%.*s" // reset
" %.*s" // file name
":%05u ", // line number
DQN_CAST(uint32_t)time.date_size - 2, time.date + 2, // date
DQN_CAST(uint32_t)time.hms_size, time.hms, // hms
DQN_CAST(uint32_t)colour_esc.size, colour_esc.data, // colour
DQN_CAST(uint32_t)bold_esc.size, bold_esc.data, // bold
DQN_CAST(uint32_t)type.size, type.data, // type
DQN_CAST(uint32_t)type_padding, "", // type padding
DQN_CAST(uint32_t)reset_esc.size, reset_esc.data, // reset
DQN_CAST(uint32_t)file_name.size, file_name.data, // file name
call_site.line); // line number
header_size_no_ansi_codes = header.size - colour_esc.size - Dqn_Print_ESCResetString.size;
}
// NOTE: Header padding ========================================================================
Dqn_usize header_padding = 0;
{
DQN_LOCAL_PERSIST Dqn_usize max_header_length = 0;
max_header_length = DQN_MAX(max_header_length, header_size_no_ansi_codes);
header_padding = max_header_length - header_size_no_ansi_codes;
}
// NOTE: Construct final log ===================================================================
Dqn_String8 user_msg = Dqn_String8_InitFV(allocator, fmt, args);
Dqn_String8 result = Dqn_String8_Allocate(allocator, header.size + header_padding + user_msg.size, Dqn_ZeroMem_No);
DQN_MEMCPY(result.data, header.data, header.size);
DQN_MEMSET(result.data + header.size, ' ', header_padding);
DQN_MEMCPY(result.data + header.size + header_padding, user_msg.data, user_msg.size);
return result;
}
DQN_FILE_SCOPE void Dqn_Log_FVDefault_(Dqn_String8 type, int log_type, void *user_data, Dqn_CallSite call_site, char const *fmt, va_list args)
{
Dqn_Library *lib = g_dqn_library;
(void)log_type;
(void)user_data;
// NOTE: Open log file for appending if requested ==========================
Dqn_TicketMutex_Begin(&lib->log_file_mutex);
if (lib->log_to_file && !lib->log_file.handle && lib->log_file.error_size == 0) {
Dqn_ThreadScratch scratch = Dqn_Thread_GetScratch(nullptr);
Dqn_String8 log_path = Dqn_FsPath_ConvertF(scratch.arena, "%.*s/dqn.log", DQN_STRING_FMT(lib->exe_dir));
lib->log_file = Dqn_Fs_OpenFile(log_path, Dqn_FsFileOpen_CreateAlways, Dqn_FsFileAccess_AppendOnly);
}
Dqn_TicketMutex_End(&lib->log_file_mutex);
// NOTE: Generate the log header ===========================================
Dqn_ThreadScratch scratch = Dqn_Thread_GetScratch(nullptr);
Dqn_String8 log_line = Dqn_Log_MakeString(scratch.allocator,
!lib->log_no_colour,
type,
log_type,
call_site,
fmt,
args);
// NOTE: Print log =========================================================
Dqn_Print_StdLn(Dqn_PrintStd_Out, log_line);
Dqn_TicketMutex_Begin(&lib->log_file_mutex);
Dqn_Fs_WriteFile(&lib->log_file, log_line);
Dqn_Fs_WriteFile(&lib->log_file, DQN_STRING8("\n"));
Dqn_TicketMutex_End(&lib->log_file_mutex);
}
DQN_API void Dqn_Log_FVCallSite(Dqn_String8 type, Dqn_CallSite call_site, char const *fmt, va_list args)
{
Dqn_LogProc *logging_function = g_dqn_library->log_callback ? g_dqn_library->log_callback : Dqn_Log_FVDefault_;
logging_function(type, -1 /*log_type*/, g_dqn_library->log_user_data, call_site, fmt, args);
}
DQN_API void Dqn_Log_FCallSite(Dqn_String8 type, Dqn_CallSite call_site, char const *fmt, ...)
{
va_list args;
va_start(args, fmt);
Dqn_Log_FVCallSite(type, call_site, fmt, args);
va_end(args);
}
DQN_API void Dqn_Log_TypeFVCallSite(Dqn_LogType type, Dqn_CallSite call_site, char const *fmt, va_list args)
{
Dqn_String8 type_string = DQN_STRING8("DQN-BAD-LOG-TYPE");
switch (type) {
case Dqn_LogType_Error: type_string = DQN_STRING8("ERROR"); break;
case Dqn_LogType_Info: type_string = DQN_STRING8("INFO"); break;
case Dqn_LogType_Warning: type_string = DQN_STRING8("WARN"); break;
case Dqn_LogType_Debug: type_string = DQN_STRING8("DEBUG"); break;
case Dqn_LogType_Count: type_string = DQN_STRING8("BADXX"); break;
}
Dqn_LogProc *logging_function = g_dqn_library->log_callback ? g_dqn_library->log_callback : Dqn_Log_FVDefault_;
logging_function(type_string, type /*log_type*/, g_dqn_library->log_user_data, call_site, fmt, args);
}
DQN_API void Dqn_Log_TypeFCallSite(Dqn_LogType type, Dqn_CallSite call_site, char const *fmt, ...)
{
va_list args;
va_start(args, fmt);
Dqn_Log_TypeFVCallSite(type, call_site, fmt, args);
va_end(args);
}

View File

@ -1,30 +1,3 @@
// NOTE: Debug Macros ==============================================================================
#if !defined(DQN_DEBUG_BREAK)
#if defined(NDEBUG)
#define DQN_DEBUG_BREAK
#else
#if defined(DQN_COMPILER_MSVC) || defined(DQN_COMPILER_CLANG_CL)
#define DQN_DEBUG_BREAK __debugbreak()
#elif defined(DQN_COMPILER_CLANG)
#define DQN_DEBUG_BREAK __builtin_debugtrap()
#elif defined(DQN_COMPILER_CLANG) || defined(DQN_COMPILER_GCC)
#include <signal.h>
#define DQN_DEBUG_BREAK raise(SIGTRAP)
#elif
#error "Unhandled compiler"
#endif
#endif
#endif
#if !defined(DQN_MEMSET_BYTE)
#define DQN_MEMSET_BYTE 0
#endif
// TODO(doyle): Use our new stacktrace library
#if !defined(DQN_DUMP_STACK_TRACE)
#define DQN_DUMP_STACK_TRACE
#endif
#if !defined(DQN_ASAN_POISON)
#define DQN_ASAN_POISON 0
#endif
@ -115,26 +88,12 @@ struct Dqn_StackTraceWalkResultIterator
uint16_t index;
};
struct Dqn_StackTraceFrames
{
Dqn_StackTraceFrame *data;
uint16_t size;
};
DQN_API Dqn_StackTraceWalkResult Dqn_StackTrace_Walk (Dqn_Arena *arena, uint16_t limit);
DQN_API bool Dqn_StackTrace_WalkResultIterate(Dqn_StackTraceWalkResultIterator *it, Dqn_StackTraceWalkResult *walk);
DQN_API Dqn_StackTraceFrames Dqn_StackTrace_GetFrames (Dqn_Arena *arena, uint16_t limit);
DQN_API Dqn_Slice<Dqn_StackTraceFrame> Dqn_StackTrace_GetFrames (Dqn_Arena *arena, uint16_t limit);
DQN_API void Dqn_StackTrace_Print (uint16_t limit);
DQN_API Dqn_StackTraceFrame Dqn_StackTrace_RawFrameToFrame (Dqn_Arena *arena, Dqn_StackTraceRawFrame raw_frame);
// NOTE: [$CALL] Dqn_CallSite ======================================================================
struct Dqn_CallSite
{
Dqn_String8 file;
Dqn_String8 function;
unsigned int line;
};
#define DQN_CALL_SITE Dqn_CallSite{DQN_STRING8(__FILE__), DQN_STRING8(__func__), __LINE__}
// NOTE: [$DEBG] Dqn_Debug =========================================================================
enum Dqn_AllocRecordFlag
{
@ -171,53 +130,3 @@ DQN_API void Dqn_Debug_DumpLeaks();
#define Dqn_Debug_TrackDealloc(...)
#define Dqn_Debug_DumpLeaks(...)
#endif
// NOTE: [$LLOG] Dqn_Log ==========================================================================
// NOTE: API
// @proc Dqn_LogProc
// @desc The logging procedure of the library. Users can override the default
// logging function by setting the logging function pointer in Dqn_Library.
// This function will be invoked every time a log is recorded using the
// following functions.
//
// @param[in] log_type This value is one of the Dqn_LogType values if the log
// was generated from one of the default categories. -1 if the log is not from
// one of the default categories.
enum Dqn_LogType
{
Dqn_LogType_Debug,
Dqn_LogType_Info,
Dqn_LogType_Warning,
Dqn_LogType_Error,
Dqn_LogType_Count,
};
/// RGBA
#define Dqn_LogTypeColourU32_Info 0x00'87'ff'ff // Blue
#define Dqn_LogTypeColourU32_Warning 0xff'ff'00'ff // Yellow
#define Dqn_LogTypeColourU32_Error 0xff'00'00'ff // Red
typedef void Dqn_LogProc(Dqn_String8 type, int log_type, void *user_data, Dqn_CallSite call_site, char const *fmt, va_list va);
#define Dqn_Log_DebugF(fmt, ...) Dqn_Log_TypeFCallSite(Dqn_LogType_Debug, DQN_CALL_SITE, fmt, ## __VA_ARGS__)
#define Dqn_Log_InfoF(fmt, ...) Dqn_Log_TypeFCallSite(Dqn_LogType_Info, DQN_CALL_SITE, fmt, ## __VA_ARGS__)
#define Dqn_Log_WarningF(fmt, ...) Dqn_Log_TypeFCallSite(Dqn_LogType_Warning, DQN_CALL_SITE, fmt, ## __VA_ARGS__)
#define Dqn_Log_ErrorF(fmt, ...) Dqn_Log_TypeFCallSite(Dqn_LogType_Error, DQN_CALL_SITE, fmt, ## __VA_ARGS__)
#define Dqn_Log_DebugFV(fmt, args) Dqn_Log_TypeFVCallSite(Dqn_LogType_Debug, DQN_CALL_SITE, fmt, args)
#define Dqn_Log_InfoFV(fmt, args) Dqn_Log_TypeFVCallSite(Dqn_LogType_Info, DQN_CALL_SITE, fmt, args)
#define Dqn_Log_WarningFV(fmt, args) Dqn_Log_TypeFVCallSite(Dqn_LogType_Warning, DQN_CALL_SITE, fmt, args)
#define Dqn_Log_ErrorFV(fmt, args) Dqn_Log_TypeFVCallSite(Dqn_LogType_Error, DQN_CALL_SITE, fmt, args)
#define Dqn_Log_TypeFV(type, fmt, args) Dqn_Log_TypeFVCallSite(type, DQN_CALL_SITE, fmt, args)
#define Dqn_Log_TypeF(type, fmt, ...) Dqn_Log_TypeFCallSite(type, DQN_CALL_SITE, fmt, ## __VA_ARGS__)
#define Dqn_Log_FV(type, fmt, args) Dqn_Log_FVCallSite(type, DQN_CALL_SITE, fmt, args)
#define Dqn_Log_F(type, fmt, ...) Dqn_Log_FCallSite(type, DQN_CALL_SITE, fmt, ## __VA_ARGS__)
DQN_API Dqn_String8 Dqn_Log_MakeString (Dqn_Allocator allocator, bool colour, Dqn_String8 type, int log_type, Dqn_CallSite call_site, char const *fmt, va_list args);
DQN_API void Dqn_Log_TypeFVCallSite(Dqn_LogType type, Dqn_CallSite call_site, char const *fmt, va_list va);
DQN_API void Dqn_Log_TypeFCallSite (Dqn_LogType type, Dqn_CallSite call_site, char const *fmt, ...);
DQN_API void Dqn_Log_FVCallSite (Dqn_String8 type, Dqn_CallSite call_site, char const *fmt, va_list va);
DQN_API void Dqn_Log_FCallSite (Dqn_String8 type, Dqn_CallSite call_site, char const *fmt, ...);

View File

@ -1,24 +1,3 @@
// NOTE: [$ALLO] Dqn_Allocator =====================================================================
DQN_API void *Dqn_Allocator_Alloc(Dqn_Allocator allocator, size_t size, uint8_t align, Dqn_ZeroMem zero_mem)
{
void *result = NULL;
if (allocator.alloc) {
result = allocator.alloc(size, align, zero_mem, allocator.user_context);
} else {
result = DQN_ALLOC(size);
}
return result;
}
DQN_API void Dqn_Allocator_Dealloc(Dqn_Allocator allocator, void *ptr, size_t size)
{
if (allocator.dealloc) {
allocator.dealloc(ptr, size, allocator.user_context);
} else {
DQN_DEALLOC(ptr, size);
}
}
// NOTE: [$VMEM] Dqn_VMem ==========================================================================
DQN_FILE_SCOPE uint32_t Dqn_VMem_ConvertPageToOSFlags_(uint32_t protect)
{

View File

@ -1,22 +1,3 @@
// NOTE: [$ALLO] Dqn_Allocator =====================================================================
typedef void *Dqn_Allocator_AllocProc(size_t size, uint8_t align, Dqn_ZeroMem zero_mem, void *user_context);
typedef void Dqn_Allocator_DeallocProc(void *ptr, size_t size, void *user_context);
struct Dqn_Allocator
{
void *user_context; // User assigned pointer that is passed into the allocator functions
Dqn_Allocator_AllocProc *alloc; // Memory allocating routine
Dqn_Allocator_DeallocProc *dealloc; // Memory deallocating routine
};
// NOTE: Macros ====================================================================================
#define Dqn_Allocator_NewArray(allocator, Type, count, zero_mem) (Type *)Dqn_Allocator_Alloc(allocator, sizeof(Type) * count, alignof(Type), zero_mem)
#define Dqn_Allocator_New(allocator, Type, zero_mem) (Type *)Dqn_Allocator_Alloc(allocator, sizeof(Type), alignof(Type), zero_mem)
// NOTE: API =======================================================================================
void *Dqn_Allocator_Alloc (Dqn_Allocator allocator, size_t size, uint8_t align, Dqn_ZeroMem zero_mem);
void Dqn_Allocator_Dealloc(Dqn_Allocator allocator, void *ptr, size_t size);
// NOTE: [$VMEM] Dqn_VMem ==========================================================================
enum Dqn_VMemCommit
{