dqn: Add more container types
This commit is contained in:
parent
7f47df1bbe
commit
04b5e26ff3
@ -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;
|
||||
}
|
||||
|
14
build.bat
14
build.bat
@ -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
62
dqn.h
@ -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 ==================================================================================
|
||||
|
163
dqn_base.cpp
163
dqn_base.cpp
@ -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);
|
||||
}
|
||||
|
||||
|
103
dqn_base.h
103
dqn_base.h
@ -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, ...);
|
||||
|
449
dqn_containers.h
449
dqn_containers.h
@ -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)
|
||||
|
160
dqn_debug.cpp
160
dqn_debug.cpp
@ -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);
|
||||
}
|
||||
|
||||
|
95
dqn_debug.h
95
dqn_debug.h
@ -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, ...);
|
||||
|
@ -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)
|
||||
{
|
||||
|
19
dqn_memory.h
19
dqn_memory.h
@ -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
|
||||
{
|
||||
|
Loading…
Reference in New Issue
Block a user