dqn: Fix poison vet check, use FsFile for logs, various cleanup

This commit is contained in:
doyle 2023-08-29 22:35:25 +10:00
parent 0872da026a
commit d756a26b42
16 changed files with 464 additions and 452 deletions

View File

@ -15,7 +15,7 @@
#endif #endif
#define DQN_ASAN_POISON 1 #define DQN_ASAN_POISON 1
#define DQN_ASAN_VET_POISON #define DQN_ASAN_VET_POISON 1
#define DQN_NO_CHECK_BREAK #define DQN_NO_CHECK_BREAK
#define DQN_IMPLEMENTATION #define DQN_IMPLEMENTATION
#include "dqn.h" #include "dqn.h"

View File

@ -16,7 +16,10 @@ pushd Build
set common_flags=-D DQN_TEST_WITH_MAIN -I %script_dir% %script_dir%\Misc\dqn_unit_tests.cpp set common_flags=-D DQN_TEST_WITH_MAIN -I %script_dir% %script_dir%\Misc\dqn_unit_tests.cpp
set msvc_driver_flags=%common_flags% -MT -EHa -GR- -Od -Oi -Z7 -wd4201 -W4 -WX -nologo set msvc_driver_flags=%common_flags% -MT -EHa -GR- -Od -Oi -Z7 -wd4201 -W4 -WX -nologo
set msvc_compile_flags=%msvc_driver_flags% -fsanitize=address -analyze /Fe:dqn_unit_tests_msvc
REM Optionally pass `-analyze` to `msvc_compile_flags` for more checks, but,
REM it slows down compilation by around 5s on my old laptop.
set msvc_compile_flags=%msvc_driver_flags% -fsanitize=address /Fe:dqn_unit_tests_msvc
set clang_compile_flags=%msvc_driver_flags% -fsanitize=address -fsanitize=undefined /Fe:dqn_unit_tests_clang set clang_compile_flags=%msvc_driver_flags% -fsanitize=address -fsanitize=undefined /Fe:dqn_unit_tests_clang
set zig_compile_flags=%common_flags% -fsanitize=address -fsanitize=undefined -o dqn_unit_tests_zig set zig_compile_flags=%common_flags% -fsanitize=address -fsanitize=undefined -o dqn_unit_tests_zig

22
dqn.h
View File

@ -116,6 +116,7 @@
// [$TYPE] Types | | Basic types and typedefs // [$TYPE] Types | | Basic types and typedefs
// [$INTR] Intrinsics | | Atomics, cpuid, ticket mutex // [$INTR] Intrinsics | | Atomics, cpuid, ticket mutex
// [$TMUT] Dqn_TicketMutex | | Userland mutex via spinlocking atomics // [$TMUT] Dqn_TicketMutex | | Userland mutex via spinlocking atomics
// [$PRIN] Dqn_Print | | Console printing
// NOTE: Additional Configuration // NOTE: Additional Configuration
// - Override the default heap-allocation routine that is called when the // - Override the default heap-allocation routine that is called when the
@ -191,10 +192,6 @@
// [$ACAT] Dqn_ArenaCatalog | | Collate, create & manage arenas in a catalog // [$ACAT] Dqn_ArenaCatalog | | Collate, create & manage arenas in a catalog
#include "dqn_memory.h" #include "dqn_memory.h"
// NOTE: Dqn_Platform Print ========================================================================
// [$PRIN] Dqn_Print | | Console printing
#include "dqn_platform_print.h"
// NOTE: Dqn_Debug ================================================================================= // NOTE: Dqn_Debug =================================================================================
// [$DEBM] Debug Macros | | // [$DEBM] Debug Macros | |
// [$CALL] Dqn_CallSite | | Source code location/tracing // [$CALL] Dqn_CallSite | | Source code location/tracing
@ -219,8 +216,10 @@
// //
// DQN_DUMP_STACK_TRACE // DQN_DUMP_STACK_TRACE
// //
// - Enable memory leak tracking when requesting memory from the OS via this // - Define this macro to enable emory leak tracking when requesting memory
// library. For example calls to Dqn_VMem_Reserve or DQN_ALLOC are recorded. // from the OS via this library. For example calls to Dqn_VMem_Reserve or
// DQN_ALLOC are recorded to the leak table.
//
// Allocations are stored in a global hash-table and their respective stack // Allocations are stored in a global hash-table and their respective stack
// traces for the allocation location. Memory leaks can be dumped at the end // traces for the allocation location. Memory leaks can be dumped at the end
// of the program or some epoch by calling Dqn_Library_DumpLeaks() // of the program or some epoch by calling Dqn_Library_DumpLeaks()
@ -239,13 +238,13 @@
// //
// DQN_ASAN_POISON 1 // DQN_ASAN_POISON 1
// //
// - Define this macro to enable sanity checks for manually poisoned memory in // - Define this macro 1 to enable sanity checks for manually poisoned memory in
// this library when ASAN `-fsanitize=address` is enabled. These sanity checks // this library when ASAN `-fsanitize=address` is enabled. These sanity checks
// ensure that memory from arenas are correctly un/poisoned when pointers are // ensure that memory from arenas are correctly un/poisoned when pointers are
// allocated and returned to the memory arena's. This is a no-op if we are not // allocated and returned to the memory arena's. This is a no-op if we are not
// compiled with ASAN or `DQN_ASAN_POISON` is not set to `1`. // compiled with ASAN or `DQN_ASAN_POISON` is not set to `1`.
// //
// DQN_ASAN_VET_POISON // DQN_ASAN_VET_POISON 1
// //
// NOTE: Dqn_Strings =============================================================================== // NOTE: Dqn_Strings ===============================================================================
@ -280,12 +279,6 @@
// and padded to atleast DQN_ASAN_POISON_ALIGNMENT (e.g. 8 bytes). // and padded to atleast DQN_ASAN_POISON_ALIGNMENT (e.g. 8 bytes).
// //
// DQN_ASAN_POISON 1 // DQN_ASAN_POISON 1
//
// - Define this macro to record allocation stats for arenas used in the
// thread context. The thread context arena stats can be printed by using
// Dqn_Library_DumpThreadContextArenaStat.
//
// DQN_DEBUG_THREAD_CONTEXT
#include "dqn_platform.h" #include "dqn_platform.h"
@ -319,7 +312,6 @@
#include "dqn_base.cpp" #include "dqn_base.cpp"
#include "dqn_external.cpp" #include "dqn_external.cpp"
#include "dqn_memory.cpp" #include "dqn_memory.cpp"
#include "dqn_platform_print.cpp"
#include "dqn_debug.cpp" #include "dqn_debug.cpp"
#include "dqn_strings.cpp" #include "dqn_strings.cpp"
#include "dqn_containers.cpp" #include "dqn_containers.cpp"

View File

@ -60,3 +60,195 @@ DQN_API bool Dqn_TicketMutex_CanLock(Dqn_TicketMutex const *mutex, Dqn_uint tick
#undef _CRT_SECURE_NO_WARNINGS #undef _CRT_SECURE_NO_WARNINGS
#endif #endif
#endif #endif
// NOTE: [$PRIN] Dqn_Print =========================================================================
DQN_API Dqn_PrintStyle Dqn_Print_StyleColour(uint8_t r, uint8_t g, uint8_t b, Dqn_PrintBold bold)
{
Dqn_PrintStyle result = {};
result.bold = bold;
result.colour = true;
result.r = r;
result.g = g;
result.b = b;
return result;
}
DQN_API Dqn_PrintStyle Dqn_Print_StyleColourU32(uint32_t rgb, Dqn_PrintBold bold)
{
uint8_t r = (rgb >> 24) & 0xFF;
uint8_t g = (rgb >> 16) & 0xFF;
uint8_t b = (rgb >> 8) & 0xFF;
Dqn_PrintStyle result = Dqn_Print_StyleColour(r, g, b, bold);
return result;
}
DQN_API Dqn_PrintStyle Dqn_Print_StyleBold()
{
Dqn_PrintStyle result = {};
result.bold = Dqn_PrintBold_Yes;
return result;
}
DQN_API void Dqn_Print_Std(Dqn_PrintStd std_handle, Dqn_String8 string)
{
DQN_ASSERT(std_handle == Dqn_PrintStd_Out || std_handle == Dqn_PrintStd_Err);
#if defined(DQN_OS_WIN32)
// NOTE: Get the output handles from kernel ====================================================
DQN_THREAD_LOCAL void *std_out_print_handle = nullptr;
DQN_THREAD_LOCAL void *std_err_print_handle = nullptr;
DQN_THREAD_LOCAL bool std_out_print_to_console = false;
DQN_THREAD_LOCAL bool std_err_print_to_console = false;
if (!std_out_print_handle) {
unsigned long mode = 0; (void)mode;
std_out_print_handle = GetStdHandle(STD_OUTPUT_HANDLE);
std_out_print_to_console = GetConsoleMode(std_out_print_handle, &mode) != 0;
std_err_print_handle = GetStdHandle(STD_ERROR_HANDLE);
std_err_print_to_console = GetConsoleMode(std_err_print_handle, &mode) != 0;
}
// NOTE: Select the output handle ==============================================================
void *print_handle = std_out_print_handle;
bool print_to_console = std_out_print_to_console;
if (std_handle == Dqn_PrintStd_Err) {
print_handle = std_err_print_handle;
print_to_console = std_err_print_to_console;
}
// NOTE: Write the string ======================================================================
DQN_ASSERT(string.size < DQN_CAST(unsigned long)-1);
unsigned long bytes_written = 0; (void)bytes_written;
if (print_to_console) {
WriteConsoleA(print_handle, string.data, DQN_CAST(unsigned long)string.size, &bytes_written, nullptr);
} else {
WriteFile(print_handle, string.data, DQN_CAST(unsigned long)string.size, &bytes_written, nullptr);
}
#else
fprintf(std_handle == Dqn_PrintStd_Out ? stdout : stderr, "%.*s", DQN_STRING_FMT(string));
#endif
}
DQN_API void Dqn_Print_StdStyle(Dqn_PrintStd std_handle, Dqn_PrintStyle style, Dqn_String8 string)
{
if (string.data && string.size) {
if (style.colour)
Dqn_Print_Std(std_handle, Dqn_Print_ESCColourFgString(style.r, style.g, style.b));
if (style.bold == Dqn_PrintBold_Yes)
Dqn_Print_Std(std_handle, Dqn_Print_ESCBoldString);
Dqn_Print_Std(std_handle, string);
if (style.colour || style.bold == Dqn_PrintBold_Yes)
Dqn_Print_Std(std_handle, Dqn_Print_ESCResetString);
}
}
DQN_FILE_SCOPE char *Dqn_Print_VSPrintfChunker_(const char *buf, void *user, int len)
{
Dqn_String8 string = {};
string.data = DQN_CAST(char *)buf;
string.size = len;
Dqn_PrintStd std_handle = DQN_CAST(Dqn_PrintStd)DQN_CAST(uintptr_t)user;
Dqn_Print_Std(std_handle, string);
return (char *)buf;
}
DQN_API void Dqn_Print_StdF(Dqn_PrintStd std_handle, DQN_FMT_STRING_ANNOTATE char const *fmt, ...)
{
va_list args;
va_start(args, fmt);
Dqn_Print_StdFV(std_handle, fmt, args);
va_end(args);
}
DQN_API void Dqn_Print_StdFStyle(Dqn_PrintStd std_handle, Dqn_PrintStyle style, DQN_FMT_STRING_ANNOTATE char const *fmt, ...)
{
va_list args;
va_start(args, fmt);
Dqn_Print_StdFVStyle(std_handle, style, fmt, args);
va_end(args);
}
DQN_API void Dqn_Print_StdFV(Dqn_PrintStd std_handle, DQN_FMT_STRING_ANNOTATE char const *fmt, va_list args)
{
char buffer[STB_SPRINTF_MIN];
STB_SPRINTF_DECORATE(vsprintfcb)(Dqn_Print_VSPrintfChunker_, DQN_CAST(void *)DQN_CAST(uintptr_t)std_handle, buffer, fmt, args);
}
DQN_API void Dqn_Print_StdFVStyle(Dqn_PrintStd std_handle, Dqn_PrintStyle style, DQN_FMT_STRING_ANNOTATE char const *fmt, va_list args)
{
if (fmt) {
if (style.colour)
Dqn_Print_Std(std_handle, Dqn_Print_ESCColourFgString(style.r, style.g, style.b));
if (style.bold == Dqn_PrintBold_Yes)
Dqn_Print_Std(std_handle, Dqn_Print_ESCBoldString);
Dqn_Print_StdFV(std_handle, fmt, args);
if (style.colour || style.bold == Dqn_PrintBold_Yes)
Dqn_Print_Std(std_handle, Dqn_Print_ESCResetString);
}
}
DQN_API void Dqn_Print_StdLn(Dqn_PrintStd std_handle, Dqn_String8 string)
{
Dqn_Print_Std(std_handle, string);
Dqn_Print_Std(std_handle, DQN_STRING8("\n"));
}
DQN_API void Dqn_Print_StdLnF(Dqn_PrintStd std_handle, DQN_FMT_STRING_ANNOTATE char const *fmt, ...)
{
va_list args;
va_start(args, fmt);
Dqn_Print_StdLnFV(std_handle, fmt, args);
va_end(args);
}
DQN_API void Dqn_Print_StdLnFV(Dqn_PrintStd std_handle, DQN_FMT_STRING_ANNOTATE char const *fmt, va_list args)
{
Dqn_Print_StdFV(std_handle, fmt, args);
Dqn_Print_Std(std_handle, DQN_STRING8("\n"));
}
DQN_API void Dqn_Print_StdLnStyle(Dqn_PrintStd std_handle, Dqn_PrintStyle style, Dqn_String8 string)
{
Dqn_Print_StdStyle(std_handle, style, string);
Dqn_Print_Std(std_handle, DQN_STRING8("\n"));
}
DQN_API void Dqn_Print_StdLnFStyle(Dqn_PrintStd std_handle, Dqn_PrintStyle style, DQN_FMT_STRING_ANNOTATE char const *fmt, ...)
{
va_list args;
va_start(args, fmt);
Dqn_Print_StdLnFVStyle(std_handle, style, fmt, args);
va_end(args);
}
DQN_API void Dqn_Print_StdLnFVStyle(Dqn_PrintStd std_handle, Dqn_PrintStyle style, DQN_FMT_STRING_ANNOTATE char const *fmt, va_list args)
{
Dqn_Print_StdFVStyle(std_handle, style, fmt, args);
Dqn_Print_Std(std_handle, DQN_STRING8("\n"));
}
DQN_API Dqn_String8 Dqn_Print_ESCColourString(Dqn_PrintESCColour colour, uint8_t r, uint8_t g, uint8_t b)
{
DQN_THREAD_LOCAL char buffer[32];
buffer[0] = 0;
Dqn_String8 result = {};
result.size = STB_SPRINTF_DECORATE(snprintf)(buffer,
DQN_ARRAY_UCOUNT(buffer),
"\x1b[%d;2;%u;%u;%um",
colour == Dqn_PrintESCColour_Fg ? 38 : 48,
r, g, b);
result.data = buffer;
return result;
}
DQN_API Dqn_String8 Dqn_Print_ESCColourU32String(Dqn_PrintESCColour colour, uint32_t value)
{
uint8_t r = DQN_CAST(uint8_t)(value >> 24);
uint8_t g = DQN_CAST(uint8_t)(value >> 16);
uint8_t b = DQN_CAST(uint8_t)(value >> 8);
Dqn_String8 result = Dqn_Print_ESCColourString(colour, r, g, b);
return result;
}

View File

@ -290,24 +290,21 @@ typedef int32_t Dqn_b32;
#define DQN_ISIZE_MAX INTPTR_MAX #define DQN_ISIZE_MAX INTPTR_MAX
#define DQN_ISIZE_MIN INTPTR_MIN #define DQN_ISIZE_MIN INTPTR_MIN
typedef enum Dqn_ZeroMem enum Dqn_ZeroMem
{ {
Dqn_ZeroMem_No, // Memory can be handed out without zero-ing it out Dqn_ZeroMem_No, // Memory can be handed out without zero-ing it out
Dqn_ZeroMem_Yes, // Memory should be zero-ed out before giving to the callee Dqn_ZeroMem_Yes, // Memory should be zero-ed out before giving to the callee
} };
Dqn_ZeroMem;
struct Dqn_String8 struct Dqn_String8
{ {
char *data; // The bytes of the string char *data; // The bytes of the string
Dqn_usize size; // The number of bytes in the string Dqn_usize size; // The number of bytes in the string
#if defined(__cplusplus)
char const *begin() const { return data; } char const *begin() const { return data; }
char const *end () const { return data + size; } char const *end () const { return data + size; }
char *begin() { return data; } char *begin() { return data; }
char *end () { return data + size; } char *end () { return data + size; }
#endif
}; };
// NOTE: [$INTR] Intrinsics ======================================================================== // NOTE: [$INTR] Intrinsics ========================================================================
@ -439,8 +436,8 @@ Dqn_CPUIDRegisters Dqn_CPUID(int function_id);
struct Dqn_TicketMutex struct Dqn_TicketMutex
{ {
unsigned int volatile ticket; ///< The next ticket to give out to the thread taking the mutex unsigned int volatile ticket; // The next ticket to give out to the thread taking the mutex
unsigned int volatile serving; ///< The ticket ID to block the mutex on until it is returned unsigned int volatile serving; // The ticket ID to block the mutex on until it is returned
}; };
void Dqn_TicketMutex_Begin (Dqn_TicketMutex *mutex); void Dqn_TicketMutex_Begin (Dqn_TicketMutex *mutex);
@ -448,3 +445,105 @@ void Dqn_TicketMutex_End (Dqn_TicketMutex *mutex);
Dqn_uint Dqn_TicketMutex_MakeTicket (Dqn_TicketMutex *mutex); Dqn_uint Dqn_TicketMutex_MakeTicket (Dqn_TicketMutex *mutex);
void Dqn_TicketMutex_BeginTicket(Dqn_TicketMutex const *mutex, Dqn_uint ticket); void Dqn_TicketMutex_BeginTicket(Dqn_TicketMutex const *mutex, Dqn_uint ticket);
bool Dqn_TicketMutex_CanLock (Dqn_TicketMutex const *mutex, Dqn_uint ticket); bool Dqn_TicketMutex_CanLock (Dqn_TicketMutex const *mutex, Dqn_uint ticket);
// NOTE: [$PRIN] Dqn_Print =========================================================================
enum Dqn_PrintStd
{
Dqn_PrintStd_Out,
Dqn_PrintStd_Err,
};
enum Dqn_PrintBold
{
Dqn_PrintBold_No,
Dqn_PrintBold_Yes,
};
struct Dqn_PrintStyle
{
Dqn_PrintBold bold;
bool colour;
uint8_t r, g, b;
};
enum Dqn_PrintESCColour
{
Dqn_PrintESCColour_Fg,
Dqn_PrintESCColour_Bg,
};
// NOTE: Print Style ===============================================================================
DQN_API Dqn_PrintStyle Dqn_Print_StyleColour (uint8_t r, uint8_t g, uint8_t b, Dqn_PrintBold bold);
DQN_API Dqn_PrintStyle Dqn_Print_StyleColourU32 (uint32_t rgb, Dqn_PrintBold bold);
DQN_API Dqn_PrintStyle Dqn_Print_StyleBold ();
// NOTE: Print Standard Out ========================================================================
#define Dqn_Print(string) Dqn_Print_Std(Dqn_PrintStd_Out, string)
#define Dqn_Print_F(fmt, ...) Dqn_Print_StdF(Dqn_PrintStd_Out, fmt, ## __VA_ARGS__)
#define Dqn_Print_FV(fmt, args) Dqn_Print_StdFV(Dqn_PrintStd_Out, fmt, args)
#define Dqn_Print_Style(style, string) Dqn_Print_StdStyle(Dqn_PrintStd_Out, style, string)
#define Dqn_Print_FStyle(style, fmt, ...) Dqn_Print_StdFStyle(Dqn_PrintStd_Out, style, fmt, ## __VA_ARGS__)
#define Dqn_Print_FVStyle(style, fmt, args, ...) Dqn_Print_StdFVStyle(Dqn_PrintStd_Out, style, fmt, args)
#define Dqn_Print_Ln(string) Dqn_Print_StdLn(Dqn_PrintStd_Out, string)
#define Dqn_Print_LnF(fmt, ...) Dqn_Print_StdLnF(Dqn_PrintStd_Out, fmt, ## __VA_ARGS__)
#define Dqn_Print_LnFV(fmt, args) Dqn_Print_StdLnFV(Dqn_PrintStd_Out, fmt, args)
#define Dqn_Print_LnStyle(style, string) Dqn_Print_StdLnStyle(Dqn_PrintStd_Out, style, string);
#define Dqn_Print_LnFStyle(style, fmt, ...) Dqn_Print_StdLnFStyle(Dqn_PrintStd_Out, style, fmt, ## __VA_ARGS__);
#define Dqn_Print_LnFVStyle(style, fmt, args) Dqn_Print_StdLnFVStyle(Dqn_PrintStd_Out, style, fmt, args);
#define Dqn_Print_Err(string) Dqn_Print_Std(Dqn_PrintStd_Err, string)
#define Dqn_Print_ErrF(fmt, ...) Dqn_Print_StdF(Dqn_PrintStd_Err, fmt, ## __VA_ARGS__)
#define Dqn_Print_ErrFV(fmt, args) Dqn_Print_StdFV(Dqn_PrintStd_Err, fmt, args)
#define Dqn_Print_ErrStyle(style, string) Dqn_Print_StdStyle(Dqn_PrintStd_Err, style, string)
#define Dqn_Print_ErrFStyle(style, fmt, ...) Dqn_Print_StdFStyle(Dqn_PrintStd_Err, style, fmt, ## __VA_ARGS__)
#define Dqn_Print_ErrFVStyle(style, fmt, args, ...) Dqn_Print_StdFVStyle(Dqn_PrintStd_Err, style, fmt, args)
#define Dqn_Print_ErrLn(string) Dqn_Print_StdLn(Dqn_PrintStd_Err, string)
#define Dqn_Print_ErrLnF(fmt, ...) Dqn_Print_StdLnF(Dqn_PrintStd_Err, fmt, ## __VA_ARGS__)
#define Dqn_Print_ErrLnFV(fmt, args) Dqn_Print_StdLnFV(Dqn_PrintStd_Err, fmt, args)
#define Dqn_Print_ErrLnStyle(style, string) Dqn_Print_StdLnStyle(Dqn_PrintStd_Err, style, string);
#define Dqn_Print_ErrLnFStyle(style, fmt, ...) Dqn_Print_StdLnFStyle(Dqn_PrintStd_Err, style, fmt, ## __VA_ARGS__);
#define Dqn_Print_ErrLnFVStyle(style, fmt, args) Dqn_Print_StdLnFVStyle(Dqn_PrintStd_Err, style, fmt, args);
// NOTE: Print =====================================================================================
DQN_API void Dqn_Print_Std (Dqn_PrintStd std_handle, Dqn_String8 string);
DQN_API void Dqn_Print_StdF (Dqn_PrintStd std_handle, DQN_FMT_STRING_ANNOTATE char const *fmt, ...);
DQN_API void Dqn_Print_StdFV (Dqn_PrintStd std_handle, DQN_FMT_STRING_ANNOTATE char const *fmt, va_list args);
DQN_API void Dqn_Print_StdStyle (Dqn_PrintStd std_handle, Dqn_PrintStyle style, Dqn_String8 string);
DQN_API void Dqn_Print_StdFStyle (Dqn_PrintStd std_handle, Dqn_PrintStyle style, DQN_FMT_STRING_ANNOTATE char const *fmt, ...);
DQN_API void Dqn_Print_StdFVStyle (Dqn_PrintStd std_handle, Dqn_PrintStyle style, DQN_FMT_STRING_ANNOTATE char const *fmt, va_list args);
DQN_API void Dqn_Print_StdLn (Dqn_PrintStd std_handle, Dqn_String8 string);
DQN_API void Dqn_Print_StdLnF (Dqn_PrintStd std_handle, DQN_FMT_STRING_ANNOTATE char const *fmt, ...);
DQN_API void Dqn_Print_StdLnFV (Dqn_PrintStd std_handle, DQN_FMT_STRING_ANNOTATE char const *fmt, va_list args);
DQN_API void Dqn_Print_StdLnStyle (Dqn_PrintStd std_handle, Dqn_PrintStyle style, Dqn_String8 string);
DQN_API void Dqn_Print_StdLnFStyle (Dqn_PrintStd std_handle, Dqn_PrintStyle style, DQN_FMT_STRING_ANNOTATE char const *fmt, ...);
DQN_API void Dqn_Print_StdLnFVStyle (Dqn_PrintStd std_handle, Dqn_PrintStyle style, DQN_FMT_STRING_ANNOTATE char const *fmt, va_list args);
// NOTE: ANSI Formatting Codes =====================================================================
Dqn_String8 Dqn_Print_ESCColourString (Dqn_PrintESCColour colour, uint8_t r, uint8_t g, uint8_t b);
Dqn_String8 Dqn_Print_ESCColourU32String(Dqn_PrintESCColour colour, uint32_t value);
#define Dqn_Print_ESCColourFgString(r, g, b) Dqn_Print_ESCColourString(Dqn_PrintESCColour_Fg, r, g, b)
#define Dqn_Print_ESCColourBgString(r, g, b) Dqn_Print_ESCColourString(Dqn_PrintESCColour_Bg, r, g, b)
#define Dqn_Print_ESCColourFg(r, g, b) Dqn_Print_ESCColourString(Dqn_PrintESCColour_Fg, r, g, b).data
#define Dqn_Print_ESCColourBg(r, g, b) Dqn_Print_ESCColourString(Dqn_PrintESCColour_Bg, r, g, b).data
#define Dqn_Print_ESCColourFgU32String(value) Dqn_Print_ESCColourU32String(Dqn_PrintESCColour_Fg, value)
#define Dqn_Print_ESCColourBgU32String(value) Dqn_Print_ESCColourU32String(Dqn_PrintESCColour_Bg, value)
#define Dqn_Print_ESCColourFgU32(value) Dqn_Print_ESCColourU32String(Dqn_PrintESCColour_Fg, value).data
#define Dqn_Print_ESCColourBgU32(value) Dqn_Print_ESCColourU32String(Dqn_PrintESCColour_Bg, value).data
#define Dqn_Print_ESCReset "\x1b[0m"
#define Dqn_Print_ESCBold "\x1b[1m"
#define Dqn_Print_ESCResetString DQN_STRING8(Dqn_Print_ESCReset)
#define Dqn_Print_ESCBoldString DQN_STRING8(Dqn_Print_ESCBold)

View File

@ -1,3 +1,30 @@
// NOTE: [$ASAN] Dqn_Asan ========================================================================== ===
void Dqn_ASAN_PoisonMemoryRegion(void const volatile *ptr, Dqn_usize size)
{
#if __has_feature(address_sanitizer) || defined(__SANITIZE_ADDRESS__)
__asan_poison_memory_region(ptr, size);
if (DQN_ASAN_VET_POISON) {
DQN_HARD_ASSERT(__asan_address_is_poisoned(ptr));
DQN_HARD_ASSERT(__asan_address_is_poisoned((char *)ptr + (size - 1)));
}
#else
(void)ptr; (void)size;
#endif
}
void Dqn_ASAN_UnpoisonMemoryRegion(void const volatile *ptr, Dqn_usize size)
{
#if __has_feature(address_sanitizer) || defined(__SANITIZE_ADDRESS__)
__asan_unpoison_memory_region(ptr, size);
if (DQN_ASAN_VET_POISON) {
DQN_HARD_ASSERT(__asan_region_is_poisoned((void *)ptr, size) == 0);
}
#else
(void)ptr; (void)size;
#endif
}
// NOTE: [$DEBG] Dqn_Debug =========================================================================
DQN_API Dqn_String8 Dqn_Debug_CleanStackTrace(Dqn_String8 stack_trace) DQN_API Dqn_String8 Dqn_Debug_CleanStackTrace(Dqn_String8 stack_trace)
{ {
// NOTE: Remove the stacktrace's library invocations from the stack trace // NOTE: Remove the stacktrace's library invocations from the stack trace
@ -164,7 +191,7 @@ DQN_API void Dqn_Debug_DumpLeaks()
Dqn_Log_WarningF("There were %I64u leaked allocations totalling %_$$I64u", leak_count, leaked_bytes); Dqn_Log_WarningF("There were %I64u leaked allocations totalling %_$$I64u", leak_count, leaked_bytes);
} }
} }
#endif /// defined(DQN_LEAK_TRACING) #endif // defined(DQN_LEAK_TRACING)
// NOTE: [$LLOG] Dqn_Log ========================================================================== // NOTE: [$LLOG] Dqn_Log ==========================================================================
DQN_API Dqn_String8 Dqn_Log_MakeString(Dqn_Allocator allocator, DQN_API Dqn_String8 Dqn_Log_MakeString(Dqn_Allocator allocator,
@ -239,27 +266,23 @@ DQN_API Dqn_String8 Dqn_Log_MakeString(Dqn_Allocator allocator,
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_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)log_type;
(void)user_data; (void)user_data;
// NOTE: Open log file for appending if requested ========================== // NOTE: Open log file for appending if requested ==========================
Dqn_TicketMutex_Begin(&g_dqn_library->log_file_mutex); Dqn_TicketMutex_Begin(&lib->log_file_mutex);
if (g_dqn_library->log_to_file && !g_dqn_library->log_file) { if (lib->log_to_file && !lib->log_file.handle && lib->log_file.error_size == 0) {
Dqn_ThreadScratch scratch = Dqn_Thread_GetScratch(nullptr); Dqn_ThreadScratch scratch = Dqn_Thread_GetScratch(nullptr);
#if (defined(DQN_OS_WIN32) && !defined(DQN_NO_WIN)) || !defined(DQN_OS_WIN32) Dqn_String8 log_path = Dqn_FsPath_ConvertF(scratch.arena, "%.*s/dqn.log", DQN_STRING_FMT(lib->exe_dir));
Dqn_String8 exe_dir = Dqn_OS_EXEDir(scratch.arena); lib->log_file = Dqn_Fs_OpenFile(log_path, Dqn_FsFileOpen_CreateAlways, Dqn_FsFileAccess_AppendOnly);
#else
Dqn_String8 exe_dir = DQN_STRING8(".");
#endif
Dqn_String8 log_file = Dqn_String8_InitF(scratch.allocator, "%.*s/dqn.log", DQN_STRING_FMT(exe_dir));
fopen_s(DQN_CAST(FILE **)&g_dqn_library->log_file, log_file.data, "a");
} }
Dqn_TicketMutex_End(&g_dqn_library->log_file_mutex); Dqn_TicketMutex_End(&lib->log_file_mutex);
// NOTE: Generate the log header =========================================== // NOTE: Generate the log header ===========================================
Dqn_ThreadScratch scratch = Dqn_Thread_GetScratch(nullptr); Dqn_ThreadScratch scratch = Dqn_Thread_GetScratch(nullptr);
Dqn_String8 log_line = Dqn_Log_MakeString(scratch.allocator, Dqn_String8 log_line = Dqn_Log_MakeString(scratch.allocator,
!g_dqn_library->log_no_colour, !lib->log_no_colour,
type, type,
log_type, log_type,
call_site, call_site,
@ -269,11 +292,10 @@ DQN_FILE_SCOPE void Dqn_Log_FVDefault_(Dqn_String8 type, int log_type, void *use
// NOTE: Print log ========================================================= // NOTE: Print log =========================================================
Dqn_Print_StdLn(Dqn_PrintStd_Out, log_line); Dqn_Print_StdLn(Dqn_PrintStd_Out, log_line);
Dqn_TicketMutex_Begin(&g_dqn_library->log_file_mutex); Dqn_TicketMutex_Begin(&lib->log_file_mutex);
if (g_dqn_library->log_to_file && g_dqn_library->log_file) { Dqn_Fs_WriteFile(&lib->log_file, log_line);
fprintf(DQN_CAST(FILE *)g_dqn_library->log_file, "%.*s\n", DQN_STRING_FMT(log_line)); Dqn_Fs_WriteFile(&lib->log_file, DQN_STRING8("\n"));
} Dqn_TicketMutex_End(&lib->log_file_mutex);
Dqn_TicketMutex_End(&g_dqn_library->log_file_mutex);
} }
DQN_API void Dqn_Log_FVCallSite(Dqn_String8 type, Dqn_CallSite call_site, char const *fmt, va_list args) DQN_API void Dqn_Log_FVCallSite(Dqn_String8 type, Dqn_CallSite call_site, char const *fmt, va_list args)

View File

@ -34,6 +34,10 @@
#define DQN_ASAN_POISON 0 #define DQN_ASAN_POISON 0
#endif #endif
#if !defined(DQN_ASAN_POISON_VET)
#define DQN_ASAN_POISON_VET 0
#endif
#if !defined(DQN_ASAN_POISON_ALIGNMENT) #if !defined(DQN_ASAN_POISON_ALIGNMENT)
#define DQN_ASAN_POISON_ALIGNMENT 8 #define DQN_ASAN_POISON_ALIGNMENT 8
#endif #endif
@ -44,30 +48,13 @@
#define __has_feature(x) 0 #define __has_feature(x) 0
#endif #endif
// NOTE: [$ASAN] Dqn_Asan ========================================================================== ===
#if __has_feature(address_sanitizer) || defined(__SANITIZE_ADDRESS__) #if __has_feature(address_sanitizer) || defined(__SANITIZE_ADDRESS__)
#include <sanitizer/asan_interface.h> #include <sanitizer/asan_interface.h>
#if defined(DQN_ASAN_VET_POISON) #endif
#define DQN_ASAN_POISON_MEMORY_REGION(ptr, size) \
do { \
__asan_poison_memory_region((ptr), (size)); \
DQN_ASSERT(__asan_address_is_poisoned((ptr))); \
DQN_ASSERT(__asan_address_is_poisoned((char *)(ptr) + ((size) - 1))); \
DQN_ASSERT(!__asan_address_is_poisoned((char *)(ptr) + (size))); \
} while (0)
#define DQN_ASAN_UNPOISON_MEMORY_REGION(ptr, size) \ void Dqn_ASAN_PoisonMemoryRegion(void const volatile *ptr, Dqn_usize size);
do { \ void Dqn_ASAN_UnpoisonMemoryRegion(void const volatile *ptr, Dqn_usize size);
__asan_unpoison_memory_region((ptr), (size)); \
DQN_ASSERT(__asan_region_is_poisoned((ptr), (size)) == 0); \
} while (0)
#else
#define DQN_ASAN_POISON_MEMORY_REGION(ptr, size) __asan_poison_memory_region(ptr, size)
#define DQN_ASAN_UNPOISON_MEMORY_REGION(ptr, size) __asan_unpoison_memory_region(ptr, size)
#endif
#else
#define DQN_ASAN_POISON_MEMORY_REGION(ptr, size) (void)(ptr); (void)(size)
#define DQN_ASAN_UNPOISON_MEMORY_REGION(ptr, size) (void)(ptr); (void)(size)
#endif
// NOTE: [$CALL] Dqn_CallSite ====================================================================== // NOTE: [$CALL] Dqn_CallSite ======================================================================
struct Dqn_CallSite struct Dqn_CallSite

View File

@ -141,6 +141,10 @@ static STBSP__ASAN stbsp__uint32 stbsp__strlen_limited(char const *s, stbsp__uin
return (stbsp__uint32)(sn - s); return (stbsp__uint32)(sn - s);
} }
#if defined(__clang__)
__attribute__((no_sanitize("undefined")))
#endif
STBSP__PUBLICDEF int STB_SPRINTF_DECORATE(vsprintfcb)(STBSP_SPRINTFCB *callback, void *user, char *buf, char const *fmt, va_list va) STBSP__PUBLICDEF int STB_SPRINTF_DECORATE(vsprintfcb)(STBSP_SPRINTFCB *callback, void *user, char *buf, char const *fmt, va_list va)
{ {
static char hex[] = "0123456789abcdefxp"; static char hex[] = "0123456789abcdefxp";

View File

@ -794,24 +794,17 @@ DQN_API Dqn_Library *Dqn_Library_Init()
g_dqn_library = &default_instance; g_dqn_library = &default_instance;
} }
// NOTE: Init check ===========================================================================
Dqn_Library *result = g_dqn_library; Dqn_Library *result = g_dqn_library;
Dqn_TicketMutex_Begin(&result->lib_mutex); Dqn_TicketMutex_Begin(&result->lib_mutex);
DQN_DEFER { Dqn_TicketMutex_End(&result->lib_mutex); }; DQN_DEFER { Dqn_TicketMutex_End(&result->lib_mutex); };
if (result->lib_init) if (result->lib_init)
return result; return result;
// ============================================================================================= // NOTE: Query OS page size ====================================================================
Dqn_ArenaCatalog_Init(&result->arena_catalog, &result->arena_catalog_backup_arena); {
result->lib_init = true;
#if !defined(DQN_NO_PROFILER)
result->profiler = &result->profiler_default_instance;
#endif
// =============================================================================================
{ // NOTE: Query OS page size
SYSTEM_INFO system_info = {}; SYSTEM_INFO system_info = {};
#if defined(DQN_OS_WIN32) #if defined(DQN_OS_WIN32)
GetSystemInfo(&system_info); GetSystemInfo(&system_info);
@ -824,7 +817,17 @@ DQN_API Dqn_Library *Dqn_Library_Init()
#endif #endif
} }
// ============================================================================================= // NOTE Initialise fields ======================================================================
#if !defined(DQN_NO_PROFILER)
result->profiler = &result->profiler_default_instance;
#endif
result->lib_init = true;
Dqn_ArenaCatalog_Init(&result->arena_catalog, &result->arena);
result->exe_dir = Dqn_OS_EXEDir(&result->arena);
// NOTE: Leak tracing ==========================================================================
#if defined(DQN_LEAK_TRACING) // NOTE: Initialise the allocation leak tracker #if defined(DQN_LEAK_TRACING) // NOTE: Initialise the allocation leak tracker
{ {
@ -840,17 +843,23 @@ DQN_API Dqn_Library *Dqn_Library_Init()
} }
#endif #endif
// ============================================================================================ // NOTE: Print out init features ===============================================================
Dqn_Log_DebugF("Dqn Library initialised with features\n"); Dqn_Log_DebugF("Dqn Library initialised:\n");
Dqn_Print_StdLnF(Dqn_PrintStd_Err, " OS Page Size/Alloc Granularity: %$$_I32u/%$$_I32u", result->os_page_size, result->os_alloc_granularity);
if (DQN_ASAN_POISON) if (DQN_ASAN_POISON)
Dqn_Print_StdLnF(Dqn_PrintStd_Err, " - ASAN manual poisoning"); Dqn_Print_StdLnF(Dqn_PrintStd_Err, " ASAN manual poisoning%s", DQN_ASAN_VET_POISON ? " (+vet sanity checks)" : "");
#if defined(DQN_ASAN_VET_POISON) #if defined(DQN_LEAK_TRACING)
Dqn_Print_StdLnF(Dqn_PrintStd_Err, " - ASAN manual poisoning vetting"); Dqn_Print_StdLnF(Dqn_PrintStd_Err, " Allocation leak tracing");
#endif #endif
#if !defined(DQN_NO_PROFILER)
Dqn_Print_StdLnF(Dqn_PrintStd_Err, " TSC profiler available");
#endif
Dqn_Print_StdLnF(Dqn_PrintStd_Err, "");
return result; return result;
} }
@ -874,14 +883,6 @@ DQN_API void Dqn_Library_SetLogCallback(Dqn_LogProc *proc, void *user_data)
g_dqn_library->log_user_data = user_data; g_dqn_library->log_user_data = user_data;
} }
DQN_API void Dqn_Library_SetLogFile(FILE *file)
{
Dqn_TicketMutex_Begin(&g_dqn_library->log_file_mutex);
g_dqn_library->log_file = file;
g_dqn_library->log_to_file = file ? true : false;
Dqn_TicketMutex_End(&g_dqn_library->log_file_mutex);
}
DQN_API void Dqn_Library_DumpThreadContextArenaStat(Dqn_String8 file_path) DQN_API void Dqn_Library_DumpThreadContextArenaStat(Dqn_String8 file_path)
{ {
#if defined(DQN_DEBUG_THREAD_CONTEXT) #if defined(DQN_DEBUG_THREAD_CONTEXT)

View File

@ -587,20 +587,20 @@ void Dqn_Profiler_SwapAnchorBuffer (uint32_t anchor_count);
struct Dqn_Library struct Dqn_Library
{ {
bool lib_init; bool lib_init; // True if the library has been initialised via `Dqn_Library_Init`
Dqn_TicketMutex lib_mutex; Dqn_TicketMutex lib_mutex;
Dqn_String8 exe_dir; // The directory of the current executable
Dqn_LogProc *log_callback; ///< Set this pointer to override the logging routine Dqn_Arena arena;
void * log_user_data;
bool log_to_file; ///< Output logs to file as well as standard out
void * log_file; ///< TODO(dqn): Hmmm, how should we do this... ?
Dqn_TicketMutex log_file_mutex; ///< Is locked when instantiating the log_file for the first time
bool log_no_colour; ///< Disable colours in the logging output
/// The backup arena to use if no arena is passed into Dqn_Library_Init
Dqn_Arena arena_catalog_backup_arena;
Dqn_ArenaCatalog arena_catalog; Dqn_ArenaCatalog arena_catalog;
Dqn_LogProc *log_callback; // Set this pointer to override the logging routine
void * log_user_data;
bool log_to_file; // Output logs to file as well as standard out
Dqn_FsFile log_file; // TODO(dqn): Hmmm, how should we do this... ?
Dqn_TicketMutex log_file_mutex; // Is locked when instantiating the log_file for the first time
bool log_no_colour; // Disable colours in the logging output
// NOTE: Leak Tracing ========================================================================== // NOTE: Leak Tracing ==========================================================================
bool allocs_are_allowed_to_leak; bool allocs_are_allowed_to_leak;
@ -627,14 +627,6 @@ struct Dqn_Library
uint32_t os_page_size; uint32_t os_page_size;
uint32_t os_alloc_granularity; uint32_t os_alloc_granularity;
// NOTE: Thread Context ========================================================================
#if defined(DQN_DEBUG_THREAD_CONTEXT)
Dqn_TicketMutex thread_context_mutex;
Dqn_ArenaStat thread_context_arena_stats[256];
uint8_t thread_context_arena_stats_count;
#endif
// NOTE: Profiler ============================================================================== // NOTE: Profiler ==============================================================================
#if !defined(DQN_NO_PROFILER) #if !defined(DQN_NO_PROFILER)
@ -650,6 +642,5 @@ DQN_API void Dqn_Library_SetPointer (Dqn_Library *library
DQN_API void Dqn_Library_SetProfiler (Dqn_Profiler *profiler); DQN_API void Dqn_Library_SetProfiler (Dqn_Profiler *profiler);
#endif #endif
DQN_API void Dqn_Library_SetLogCallback (Dqn_LogProc *proc, void *user_data); DQN_API void Dqn_Library_SetLogCallback (Dqn_LogProc *proc, void *user_data);
DQN_API void Dqn_Library_SetLogFile (void *file);
DQN_API void Dqn_Library_DumpThreadContextArenaStat(Dqn_String8 file_path); DQN_API void Dqn_Library_DumpThreadContextArenaStat(Dqn_String8 file_path);

View File

@ -237,7 +237,7 @@ DQN_API Dqn_MemBlock *Dqn_MemBlock_Init(Dqn_usize reserve, Dqn_usize commit, uin
DQN_ASSERT(Dqn_IsPowerOfTwoAligned(result->size, DQN_ASAN_POISON_ALIGNMENT)); DQN_ASSERT(Dqn_IsPowerOfTwoAligned(result->size, DQN_ASAN_POISON_ALIGNMENT));
void *poison_ptr = DQN_CAST(void *)Dqn_AlignUpPowerOfTwo(DQN_CAST(char *)result + sizeof(Dqn_MemBlock), DQN_ASAN_POISON_ALIGNMENT); void *poison_ptr = DQN_CAST(void *)Dqn_AlignUpPowerOfTwo(DQN_CAST(char *)result + sizeof(Dqn_MemBlock), DQN_ASAN_POISON_ALIGNMENT);
Dqn_usize bytes_to_poison = g_dqn_library->os_page_size + result->size; Dqn_usize bytes_to_poison = g_dqn_library->os_page_size + result->size;
DQN_ASAN_POISON_MEMORY_REGION(poison_ptr, bytes_to_poison); Dqn_ASAN_PoisonMemoryRegion(poison_ptr, bytes_to_poison);
} }
} }
return result; return result;
@ -261,7 +261,7 @@ DQN_API void *Dqn_MemBlock_Alloc(Dqn_MemBlock *block, Dqn_usize size, uint8_t al
DQN_ASSERT(Dqn_IsPowerOfTwoAligned(result, alignment)); DQN_ASSERT(Dqn_IsPowerOfTwoAligned(result, alignment));
if (DQN_ASAN_POISON) if (DQN_ASAN_POISON)
DQN_ASAN_UNPOISON_MEMORY_REGION(result, size); Dqn_ASAN_UnpoisonMemoryRegion(result, size);
if (zero_mem == Dqn_ZeroMem_Yes) { if (zero_mem == Dqn_ZeroMem_Yes) {
Dqn_usize reused_bytes = DQN_MIN(block->commit - size_required.data_offset, size); Dqn_usize reused_bytes = DQN_MIN(block->commit - size_required.data_offset, size);
@ -285,7 +285,7 @@ DQN_API void Dqn_MemBlock_Free(Dqn_MemBlock *block)
return; return;
Dqn_usize release_size = block->size + Dqn_MemBlock_MetadataSize(); Dqn_usize release_size = block->size + Dqn_MemBlock_MetadataSize();
if (DQN_ASAN_POISON) if (DQN_ASAN_POISON)
DQN_ASAN_UNPOISON_MEMORY_REGION(block, release_size); Dqn_ASAN_UnpoisonMemoryRegion(block, release_size);
Dqn_VMem_Release(block, release_size); Dqn_VMem_Release(block, release_size);
} }
@ -307,7 +307,7 @@ DQN_API void Dqn_MemBlock_PopTo(Dqn_MemBlock *block, Dqn_usize to)
void *poison_ptr = DQN_CAST(char *)block->data + to; void *poison_ptr = DQN_CAST(char *)block->data + to;
void *end_ptr = DQN_CAST(void *)Dqn_AlignUpPowerOfTwo((DQN_CAST(uintptr_t)block->data + block->used), DQN_ASAN_POISON_ALIGNMENT); void *end_ptr = DQN_CAST(void *)Dqn_AlignUpPowerOfTwo((DQN_CAST(uintptr_t)block->data + block->used), DQN_ASAN_POISON_ALIGNMENT);
uintptr_t bytes_to_poison = DQN_CAST(uintptr_t)end_ptr - DQN_CAST(uintptr_t)poison_ptr; uintptr_t bytes_to_poison = DQN_CAST(uintptr_t)end_ptr - DQN_CAST(uintptr_t)poison_ptr;
DQN_ASAN_POISON_MEMORY_REGION(poison_ptr, bytes_to_poison); Dqn_ASAN_PoisonMemoryRegion(poison_ptr, bytes_to_poison);
} }
block->used = to; block->used = to;
} }

View File

@ -295,9 +295,6 @@ struct Dqn_ArenaTempMemoryScope
~Dqn_ArenaTempMemoryScope(); ~Dqn_ArenaTempMemoryScope();
Dqn_ArenaTempMemory temp_memory; Dqn_ArenaTempMemory temp_memory;
bool cancel = false; bool cancel = false;
#if defined(DQN_LEAK_TRACING)
Dqn_CallSite leak_site_;
#endif
}; };
enum Dqn_ArenaCommit enum Dqn_ArenaCommit

View File

@ -645,15 +645,15 @@ DQN_API Dqn_FsFile Dqn_Fs_OpenFile(Dqn_String8 path, Dqn_FsFileOpen open_mode, u
return result; return result;
} }
DQN_API bool Dqn_Fs_WriteFile(Dqn_FsFile *file, char const *buffer, Dqn_usize size) DQN_API bool Dqn_Fs_WriteFileBuffer(Dqn_FsFile *file, void const *buffer, Dqn_usize size)
{ {
if (!file || !file->handle || !buffer || size <= 0 || file->error_size) if (!file || !file->handle || !buffer || size <= 0 || file->error_size)
return false; return false;
bool result = true; bool result = true;
#if defined(DQN_OS_WIN32) #if defined(DQN_OS_WIN32)
char const *end = buffer + size; char const *end = DQN_CAST(char *)buffer + size;
for (char const *ptr = buffer; result && ptr != end; ) { for (char const *ptr = DQN_CAST(char const *)buffer; result && ptr != end; ) {
unsigned long write_size = DQN_CAST(unsigned long)DQN_MIN((unsigned long)-1, end - ptr); unsigned long write_size = DQN_CAST(unsigned long)DQN_MIN((unsigned long)-1, end - ptr);
unsigned long bytes_written = 0; unsigned long bytes_written = 0;
result = WriteFile(file->handle, ptr, write_size, &bytes_written, nullptr /*lpOverlapped*/) != 0; result = WriteFile(file->handle, ptr, write_size, &bytes_written, nullptr /*lpOverlapped*/) != 0;
@ -675,6 +675,32 @@ DQN_API bool Dqn_Fs_WriteFile(Dqn_FsFile *file, char const *buffer, Dqn_usize si
return result; return result;
} }
DQN_API bool Dqn_Fs_WriteFile(Dqn_FsFile *file, Dqn_String8 buffer)
{
bool result = Dqn_Fs_WriteFileBuffer(file, buffer.data, buffer.size);
return result;
}
DQN_API bool Dqn_Fs_WriteFileFV(Dqn_FsFile *file, DQN_FMT_STRING_ANNOTATE char const *fmt, va_list args)
{
bool result = false;
if (!file || !fmt)
return result;
Dqn_ThreadScratch scratch = Dqn_Thread_GetScratch(nullptr);
Dqn_String8 buffer = Dqn_String8_InitFV(scratch.allocator, fmt, args);
result = Dqn_Fs_WriteFileBuffer(file, buffer.data, buffer.size);
return result;
}
DQN_API bool Dqn_Fs_WriteFileF(Dqn_FsFile *file, DQN_FMT_STRING_ANNOTATE char const *fmt, ...)
{
va_list args;
va_start(args, fmt);
bool result = Dqn_Fs_WriteFileFV(file, fmt, args);
va_end(args);
return result;
}
DQN_API void Dqn_Fs_CloseFile(Dqn_FsFile *file) DQN_API void Dqn_Fs_CloseFile(Dqn_FsFile *file)
{ {
if (!file || !file->handle || file->error_size) if (!file || !file->handle || file->error_size)
@ -1902,17 +1928,14 @@ DQN_API uint64_t Dqn_OS_EstimateTSCPerSecond(uint64_t duration_ms_to_gauge_tsc_f
// NOTE: [$TCTX] Dqn_ThreadContext ================================================================= // NOTE: [$TCTX] Dqn_ThreadContext =================================================================
Dqn_ThreadScratch::Dqn_ThreadScratch(Dqn_ThreadContext *context, uint8_t context_index) Dqn_ThreadScratch::Dqn_ThreadScratch(Dqn_ThreadContext *context, uint8_t context_index)
{ {
index = context_index; allocator = context->scratch_allocators[context_index];
allocator = context->temp_allocators[index]; arena = context->scratch_arenas[context_index];
arena = context->temp_arenas[index];
temp_memory = Dqn_Arena_BeginTempMemory(arena); temp_memory = Dqn_Arena_BeginTempMemory(arena);
destructed = false;
} }
Dqn_ThreadScratch::~Dqn_ThreadScratch() Dqn_ThreadScratch::~Dqn_ThreadScratch()
{ {
#if defined(DQN_DEBUG_THREAD_CONTEXT)
temp_arenas_stat[index] = arena->stats;
#endif
DQN_ASSERT(destructed == false); DQN_ASSERT(destructed == false);
Dqn_Arena_EndTempMemory(temp_memory, /*cancel*/ false); Dqn_Arena_EndTempMemory(temp_memory, /*cancel*/ false);
destructed = true; destructed = true;
@ -1934,26 +1957,18 @@ DQN_API Dqn_ThreadContext *Dqn_Thread_GetContext()
DQN_THREAD_LOCAL Dqn_ThreadContext result = {}; DQN_THREAD_LOCAL Dqn_ThreadContext result = {};
if (!result.init) { if (!result.init) {
result.init = true; result.init = true;
Dqn_ArenaCatalog *catalog = &g_dqn_library->arena_catalog;
DQN_ASSERTF(g_dqn_library->lib_init, "Library must be initialised by calling Dqn_Library_Init(nullptr)"); DQN_ASSERTF(g_dqn_library->lib_init, "Library must be initialised by calling Dqn_Library_Init(nullptr)");
// NOTE: Setup permanent arena // NOTE: Setup scratch arenas
Dqn_ArenaCatalog *catalog = &g_dqn_library->arena_catalog; for (uint8_t index = 0; index < DQN_ARRAY_UCOUNT(result.scratch_arenas); index++) {
result.allocator = Dqn_Arena_Allocator(result.arena); result.scratch_arenas[index] = Dqn_ArenaCatalog_AllocF(catalog,
result.arena = Dqn_ArenaCatalog_AllocF(catalog,
DQN_GIGABYTES(1) /*size*/, DQN_GIGABYTES(1) /*size*/,
DQN_KILOBYTES(64) /*commit*/, DQN_KILOBYTES(64) /*commit*/,
"Thread %u Arena", "Thread %u Scratch Arena %u",
Dqn_Thread_GetID());
// NOTE: Setup temporary arenas
for (uint8_t index = 0; index < DQN_THREAD_CONTEXT_ARENAS; index++) {
result.temp_arenas[index] = Dqn_ArenaCatalog_AllocF(catalog,
DQN_GIGABYTES(1) /*size*/,
DQN_KILOBYTES(64) /*commit*/,
"Thread %u Temp Arena %u",
Dqn_Thread_GetID(), Dqn_Thread_GetID(),
index); index);
result.temp_allocators[index] = Dqn_Arena_Allocator(result.temp_arenas[index]); result.scratch_allocators[index] = Dqn_Arena_Allocator(result.scratch_arenas[index]);
} }
} }
return &result; return &result;
@ -1963,11 +1978,10 @@ DQN_API Dqn_ThreadContext *Dqn_Thread_GetContext()
// manually pass it in? // manually pass it in?
DQN_API Dqn_ThreadScratch Dqn_Thread_GetScratch(void const *conflict_arena) DQN_API Dqn_ThreadScratch Dqn_Thread_GetScratch(void const *conflict_arena)
{ {
static_assert(DQN_THREAD_CONTEXT_ARENAS < (uint8_t)-1, "We use UINT8_MAX as a sentinel value");
Dqn_ThreadContext *context = Dqn_Thread_GetContext(); Dqn_ThreadContext *context = Dqn_Thread_GetContext();
uint8_t context_index = (uint8_t)-1; uint8_t context_index = (uint8_t)-1;
for (uint8_t index = 0; index < DQN_THREAD_CONTEXT_ARENAS; index++) { for (uint8_t index = 0; index < DQN_ARRAY_UCOUNT(context->scratch_arenas); index++) {
Dqn_Arena *arena = context->temp_arenas[index]; Dqn_Arena *arena = context->scratch_arenas[index];
if (!conflict_arena || arena != conflict_arena) { if (!conflict_arena || arena != conflict_arena) {
context_index = index; context_index = index;
break; break;
@ -1977,4 +1991,3 @@ DQN_API Dqn_ThreadScratch Dqn_Thread_GetScratch(void const *conflict_arena)
DQN_ASSERT(context_index != (uint8_t)-1); DQN_ASSERT(context_index != (uint8_t)-1);
return Dqn_ThreadScratch(context, context_index); return Dqn_ThreadScratch(context, context_index);
} }

View File

@ -70,9 +70,9 @@ struct Dqn_FsFile
enum Dqn_FsFileOpen enum Dqn_FsFileOpen
{ {
Dqn_FsFileOpen_CreateAlways, ///< Create file if it does not exist, otherwise, zero out the file and open Dqn_FsFileOpen_CreateAlways, // Create file if it does not exist, otherwise, zero out the file and open
Dqn_FsFileOpen_OpenIfExist, ///< Open file at path only if it exists Dqn_FsFileOpen_OpenIfExist, // Open file at path only if it exists
Dqn_FsFileOpen_OpenAlways, ///< Open file at path, create file if it does not exist Dqn_FsFileOpen_OpenAlways, // Open file at path, create file if it does not exist
}; };
enum Dqn_FsFileAccess enum Dqn_FsFileAccess
@ -80,13 +80,16 @@ enum Dqn_FsFileAccess
Dqn_FsFileAccess_Read = 1 << 0, Dqn_FsFileAccess_Read = 1 << 0,
Dqn_FsFileAccess_Write = 1 << 1, Dqn_FsFileAccess_Write = 1 << 1,
Dqn_FsFileAccess_Execute = 1 << 2, Dqn_FsFileAccess_Execute = 1 << 2,
Dqn_FsFileAccess_AppendOnly = 1 << 3, ///< This flag cannot be combined with any other acess mode Dqn_FsFileAccess_AppendOnly = 1 << 3, // This flag cannot be combined with any other access mode
Dqn_FsFileAccess_ReadWrite = Dqn_FsFileAccess_Read | Dqn_FsFileAccess_Write, Dqn_FsFileAccess_ReadWrite = Dqn_FsFileAccess_Read | Dqn_FsFileAccess_Write,
Dqn_FsFileAccess_All = Dqn_FsFileAccess_ReadWrite | Dqn_FsFileAccess_Execute, Dqn_FsFileAccess_All = Dqn_FsFileAccess_ReadWrite | Dqn_FsFileAccess_Execute,
}; };
DQN_API Dqn_FsFile Dqn_Fs_OpenFile (Dqn_String8 path, Dqn_FsFileOpen open_mode, uint32_t access); DQN_API Dqn_FsFile Dqn_Fs_OpenFile (Dqn_String8 path, Dqn_FsFileOpen open_mode, uint32_t access);
DQN_API bool Dqn_Fs_WriteFile(Dqn_FsFile *file, char const *buffer, Dqn_usize size); DQN_API bool Dqn_Fs_WriteFileBuffer(Dqn_FsFile *file, void const *data, Dqn_usize size);
DQN_API bool Dqn_Fs_WriteFile (Dqn_FsFile *file, Dqn_String8 buffer);
DQN_API bool Dqn_Fs_WriteFileFV (Dqn_FsFile *file, DQN_FMT_STRING_ANNOTATE char const *fmt, va_list args);
DQN_API bool Dqn_Fs_WriteFileF (Dqn_FsFile *file, DQN_FMT_STRING_ANNOTATE char const *fmt, ...);
DQN_API void Dqn_Fs_CloseFile (Dqn_FsFile *file); DQN_API void Dqn_Fs_CloseFile (Dqn_FsFile *file);
#endif // !defined(DQN_NO_FS) #endif // !defined(DQN_NO_FS)
@ -459,27 +462,16 @@ DQN_API uint64_t Dqn_OS_EstimateTSCPerSecond(uint64_t duration_ms_to_gauge_ts
// @param[in] conflict_arena A pointer to the arena currently being used in the // @param[in] conflict_arena A pointer to the arena currently being used in the
// function // function
#if !defined(DQN_THREAD_CONTEXT_ARENAS)
#define DQN_THREAD_CONTEXT_ARENAS 2
#endif
struct Dqn_ThreadContext struct Dqn_ThreadContext
{ {
Dqn_b32 init; Dqn_b32 init;
Dqn_Arena *arena; ///< Per thread arena // Scratch memory arena's for the calling thread
Dqn_Allocator allocator; ///< Allocator that uses the arena Dqn_Arena *scratch_arenas[2];
/// Temp memory arena's for the calling thread // Allocators that use the corresponding arena from the thread context.
Dqn_Arena *temp_arenas[DQN_THREAD_CONTEXT_ARENAS]; // Provided for convenience when interfacing with allocator interfaces.
Dqn_Allocator scratch_allocators[2];
/// Allocators that use the corresponding arena from the thread context.
/// Provided for convenience when interfacing with allocator interfaces.
Dqn_Allocator temp_allocators[DQN_THREAD_CONTEXT_ARENAS];
#if defined(DQN_DEBUG_THREAD_CONTEXT)
Dqn_ArenaStat temp_arenas_stat[DQN_THREAD_CONTEXT_ARENAS];
#endif
}; };
struct Dqn_ThreadScratch struct Dqn_ThreadScratch
@ -487,16 +479,10 @@ struct Dqn_ThreadScratch
Dqn_ThreadScratch(Dqn_ThreadContext *context, uint8_t context_index); Dqn_ThreadScratch(Dqn_ThreadContext *context, uint8_t context_index);
~Dqn_ThreadScratch(); ~Dqn_ThreadScratch();
/// Index into the arena/allocator/stat array in the thread context
/// specifying what arena was assigned.
uint8_t index;
Dqn_Allocator allocator; Dqn_Allocator allocator;
Dqn_Arena *arena; Dqn_Arena *arena;
Dqn_b32 destructed = false; /// Detect copies of the scratch Dqn_b32 destructed;
Dqn_ArenaTempMemory temp_memory; Dqn_ArenaTempMemory temp_memory;
#if defined(DQN_LEAK_TRACING)
Dqn_CallSite leak_site__;
#endif
}; };
// NOTE: Context =================================================================================== // NOTE: Context ===================================================================================

View File

@ -1,191 +0,0 @@
// NOTE: [$PRIN] Dqn_Print =========================================================================
DQN_API Dqn_PrintStyle Dqn_Print_StyleColour(uint8_t r, uint8_t g, uint8_t b, Dqn_PrintBold bold)
{
Dqn_PrintStyle result = {};
result.bold = bold;
result.colour = true;
result.r = r;
result.g = g;
result.b = b;
return result;
}
DQN_API Dqn_PrintStyle Dqn_Print_StyleColourU32(uint32_t rgb, Dqn_PrintBold bold)
{
uint8_t r = (rgb >> 24) & 0xFF;
uint8_t g = (rgb >> 16) & 0xFF;
uint8_t b = (rgb >> 8) & 0xFF;
Dqn_PrintStyle result = Dqn_Print_StyleColour(r, g, b, bold);
return result;
}
DQN_API Dqn_PrintStyle Dqn_Print_StyleBold()
{
Dqn_PrintStyle result = {};
result.bold = Dqn_PrintBold_Yes;
return result;
}
DQN_API void Dqn_Print_Std(Dqn_PrintStd std_handle, Dqn_String8 string)
{
DQN_ASSERT(std_handle == Dqn_PrintStd_Out || std_handle == Dqn_PrintStd_Err);
#if defined(DQN_OS_WIN32)
// NOTE: Get the output handles from kernel ====================================================
DQN_THREAD_LOCAL void *std_out_print_handle = nullptr;
DQN_THREAD_LOCAL void *std_err_print_handle = nullptr;
DQN_THREAD_LOCAL bool std_out_print_to_console = false;
DQN_THREAD_LOCAL bool std_err_print_to_console = false;
if (!std_out_print_handle) {
unsigned long mode = 0; (void)mode;
std_out_print_handle = GetStdHandle(STD_OUTPUT_HANDLE);
std_out_print_to_console = GetConsoleMode(std_out_print_handle, &mode) != 0;
std_err_print_handle = GetStdHandle(STD_ERROR_HANDLE);
std_err_print_to_console = GetConsoleMode(std_err_print_handle, &mode) != 0;
}
// NOTE: Select the output handle ==============================================================
void *print_handle = std_out_print_handle;
bool print_to_console = std_out_print_to_console;
if (std_handle == Dqn_PrintStd_Err) {
print_handle = std_err_print_handle;
print_to_console = std_err_print_to_console;
}
// NOTE: Write the string ======================================================================
DQN_ASSERT(string.size < DQN_CAST(unsigned long)-1);
unsigned long bytes_written = 0; (void)bytes_written;
if (print_to_console) {
WriteConsoleA(print_handle, string.data, DQN_CAST(unsigned long)string.size, &bytes_written, nullptr);
} else {
WriteFile(print_handle, string.data, DQN_CAST(unsigned long)string.size, &bytes_written, nullptr);
}
#else
fprintf(std_handle == Dqn_PrintStd_Out ? stdout : stderr, "%.*s", DQN_STRING_FMT(string));
#endif
}
DQN_API void Dqn_Print_StdStyle(Dqn_PrintStd std_handle, Dqn_PrintStyle style, Dqn_String8 string)
{
if (string.data && string.size) {
if (style.colour)
Dqn_Print_Std(std_handle, Dqn_Print_ESCColourFgString(style.r, style.g, style.b));
if (style.bold == Dqn_PrintBold_Yes)
Dqn_Print_Std(std_handle, Dqn_Print_ESCBoldString);
Dqn_Print_Std(std_handle, string);
if (style.colour || style.bold == Dqn_PrintBold_Yes)
Dqn_Print_Std(std_handle, Dqn_Print_ESCResetString);
}
}
DQN_FILE_SCOPE char *Dqn_Print_VSPrintfChunker_(const char *buf, void *user, int len)
{
Dqn_String8 string = {};
string.data = DQN_CAST(char *)buf;
string.size = len;
Dqn_PrintStd std_handle = DQN_CAST(Dqn_PrintStd)DQN_CAST(uintptr_t)user;
Dqn_Print_Std(std_handle, string);
return (char *)buf;
}
DQN_API void Dqn_Print_StdF(Dqn_PrintStd std_handle, DQN_FMT_STRING_ANNOTATE char const *fmt, ...)
{
va_list args;
va_start(args, fmt);
Dqn_Print_StdFV(std_handle, fmt, args);
va_end(args);
}
DQN_API void Dqn_Print_StdFStyle(Dqn_PrintStd std_handle, Dqn_PrintStyle style, DQN_FMT_STRING_ANNOTATE char const *fmt, ...)
{
va_list args;
va_start(args, fmt);
Dqn_Print_StdFVStyle(std_handle, style, fmt, args);
va_end(args);
}
DQN_API void Dqn_Print_StdFV(Dqn_PrintStd std_handle, DQN_FMT_STRING_ANNOTATE char const *fmt, va_list args)
{
char buffer[STB_SPRINTF_MIN];
STB_SPRINTF_DECORATE(vsprintfcb)(Dqn_Print_VSPrintfChunker_, DQN_CAST(void *)DQN_CAST(uintptr_t)std_handle, buffer, fmt, args);
}
DQN_API void Dqn_Print_StdFVStyle(Dqn_PrintStd std_handle, Dqn_PrintStyle style, DQN_FMT_STRING_ANNOTATE char const *fmt, va_list args)
{
if (fmt) {
if (style.colour)
Dqn_Print_Std(std_handle, Dqn_Print_ESCColourFgString(style.r, style.g, style.b));
if (style.bold == Dqn_PrintBold_Yes)
Dqn_Print_Std(std_handle, Dqn_Print_ESCBoldString);
Dqn_Print_StdFV(std_handle, fmt, args);
if (style.colour || style.bold == Dqn_PrintBold_Yes)
Dqn_Print_Std(std_handle, Dqn_Print_ESCResetString);
}
}
DQN_API void Dqn_Print_StdLn(Dqn_PrintStd std_handle, Dqn_String8 string)
{
Dqn_Print_Std(std_handle, string);
Dqn_Print_Std(std_handle, DQN_STRING8("\n"));
}
DQN_API void Dqn_Print_StdLnF(Dqn_PrintStd std_handle, DQN_FMT_STRING_ANNOTATE char const *fmt, ...)
{
va_list args;
va_start(args, fmt);
Dqn_Print_StdLnFV(std_handle, fmt, args);
va_end(args);
}
DQN_API void Dqn_Print_StdLnFV(Dqn_PrintStd std_handle, DQN_FMT_STRING_ANNOTATE char const *fmt, va_list args)
{
Dqn_Print_StdFV(std_handle, fmt, args);
Dqn_Print_Std(std_handle, DQN_STRING8("\n"));
}
DQN_API void Dqn_Print_StdLnStyle(Dqn_PrintStd std_handle, Dqn_PrintStyle style, Dqn_String8 string)
{
Dqn_Print_StdStyle(std_handle, style, string);
Dqn_Print_Std(std_handle, DQN_STRING8("\n"));
}
DQN_API void Dqn_Print_StdLnFStyle(Dqn_PrintStd std_handle, Dqn_PrintStyle style, DQN_FMT_STRING_ANNOTATE char const *fmt, ...)
{
va_list args;
va_start(args, fmt);
Dqn_Print_StdLnFVStyle(std_handle, style, fmt, args);
va_end(args);
}
DQN_API void Dqn_Print_StdLnFVStyle(Dqn_PrintStd std_handle, Dqn_PrintStyle style, DQN_FMT_STRING_ANNOTATE char const *fmt, va_list args)
{
Dqn_Print_StdFVStyle(std_handle, style, fmt, args);
Dqn_Print_Std(std_handle, DQN_STRING8("\n"));
}
DQN_API Dqn_String8 Dqn_Print_ESCColourString(Dqn_PrintESCColour colour, uint8_t r, uint8_t g, uint8_t b)
{
DQN_THREAD_LOCAL char buffer[32];
buffer[0] = 0;
Dqn_String8 result = {};
result.size = STB_SPRINTF_DECORATE(snprintf)(buffer,
DQN_ARRAY_UCOUNT(buffer),
"\x1b[%d;2;%u;%u;%um",
colour == Dqn_PrintESCColour_Fg ? 38 : 48,
r, g, b);
result.data = buffer;
return result;
}
DQN_API Dqn_String8 Dqn_Print_ESCColourU32String(Dqn_PrintESCColour colour, uint32_t value)
{
uint8_t r = DQN_CAST(uint8_t)(value >> 24);
uint8_t g = DQN_CAST(uint8_t)(value >> 16);
uint8_t b = DQN_CAST(uint8_t)(value >> 8);
Dqn_String8 result = Dqn_Print_ESCColourString(colour, r, g, b);
return result;
}

View File

@ -1,84 +0,0 @@
// NOTE: [$PRIN] Dqn_Print =========================================================================
enum Dqn_PrintStd
{
Dqn_PrintStd_Out,
Dqn_PrintStd_Err,
};
enum Dqn_PrintBold
{
Dqn_PrintBold_No,
Dqn_PrintBold_Yes,
};
struct Dqn_PrintStyle
{
Dqn_PrintBold bold;
bool colour;
uint8_t r, g, b;
};
enum Dqn_PrintESCColour
{
Dqn_PrintESCColour_Fg,
Dqn_PrintESCColour_Bg,
};
// NOTE: Print Style ===============================================================================
DQN_API Dqn_PrintStyle Dqn_Print_StyleColour (uint8_t r, uint8_t g, uint8_t b, Dqn_PrintBold bold);
DQN_API Dqn_PrintStyle Dqn_Print_StyleColourU32 (uint32_t rgb, Dqn_PrintBold bold);
DQN_API Dqn_PrintStyle Dqn_Print_StyleBold ();
// NOTE: Print Standard Out ========================================================================
#define Dqn_Print(string) Dqn_Print_Std(Dqn_PrintStd_Out, string)
#define Dqn_Print_F(fmt, ...) Dqn_Print_StdF(Dqn_PrintStd_Out, fmt, ## __VA_ARGS__)
#define Dqn_Print_FV(fmt, args) Dqn_Print_StdFV(Dqn_PrintStd_Out, fmt, args)
#define Dqn_Print_Style(style, string) Dqn_Print_StdStyle(Dqn_PrintStd_Out, style, string)
#define Dqn_Print_FStyle(style, fmt, ...) Dqn_Print_StdFStyle(Dqn_PrintStd_Out, style, fmt, ## __VA_ARGS__)
#define Dqn_Print_FVStyle(style, fmt, args, ...) Dqn_Print_StdFVStyle(Dqn_PrintStd_Out, style, fmt, args)
#define Dqn_Print_Ln(string) Dqn_Print_StdLn(Dqn_PrintStd_Out, string)
#define Dqn_Print_LnF(fmt, ...) Dqn_Print_StdLnF(Dqn_PrintStd_Out, fmt, ## __VA_ARGS__)
#define Dqn_Print_LnFV(fmt, args) Dqn_Print_StdLnFV(Dqn_PrintStd_Out, fmt, args)
#define Dqn_Print_LnStyle(style, string) Dqn_Print_StdLnStyle(Dqn_PrintStd_Out, style, string);
#define Dqn_Print_LnFStyle(style, fmt, ...) Dqn_Print_StdLnFStyle(Dqn_PrintStd_Out, style, fmt, ## __VA_ARGS__);
#define Dqn_Print_LnFVStyle(style, fmt, args) Dqn_Print_StdLnFVStyle(Dqn_PrintStd_Out, style, fmt, args);
// NOTE: Print =====================================================================================
DQN_API void Dqn_Print_Std (Dqn_PrintStd std_handle, Dqn_String8 string);
DQN_API void Dqn_Print_StdF (Dqn_PrintStd std_handle, DQN_FMT_STRING_ANNOTATE char const *fmt, ...);
DQN_API void Dqn_Print_StdFV (Dqn_PrintStd std_handle, DQN_FMT_STRING_ANNOTATE char const *fmt, va_list args);
DQN_API void Dqn_Print_StdStyle (Dqn_PrintStd std_handle, Dqn_PrintStyle style, Dqn_String8 string);
DQN_API void Dqn_Print_StdFStyle (Dqn_PrintStd std_handle, Dqn_PrintStyle style, DQN_FMT_STRING_ANNOTATE char const *fmt, ...);
DQN_API void Dqn_Print_StdFVStyle (Dqn_PrintStd std_handle, Dqn_PrintStyle style, DQN_FMT_STRING_ANNOTATE char const *fmt, va_list args);
DQN_API void Dqn_Print_StdLn (Dqn_PrintStd std_handle, Dqn_String8 string);
DQN_API void Dqn_Print_StdLnF (Dqn_PrintStd std_handle, DQN_FMT_STRING_ANNOTATE char const *fmt, ...);
DQN_API void Dqn_Print_StdLnFV (Dqn_PrintStd std_handle, DQN_FMT_STRING_ANNOTATE char const *fmt, va_list args);
DQN_API void Dqn_Print_StdLnStyle (Dqn_PrintStd std_handle, Dqn_PrintStyle style, Dqn_String8 string);
DQN_API void Dqn_Print_StdLnFStyle (Dqn_PrintStd std_handle, Dqn_PrintStyle style, DQN_FMT_STRING_ANNOTATE char const *fmt, ...);
DQN_API void Dqn_Print_StdLnFVStyle (Dqn_PrintStd std_handle, Dqn_PrintStyle style, DQN_FMT_STRING_ANNOTATE char const *fmt, va_list args);
// NOTE: ANSI Formatting Codes =====================================================================
Dqn_String8 Dqn_Print_ESCColourString (Dqn_PrintESCColour colour, uint8_t r, uint8_t g, uint8_t b);
Dqn_String8 Dqn_Print_ESCColourU32String(Dqn_PrintESCColour colour, uint32_t value);
#define Dqn_Print_ESCColourFgString(r, g, b) Dqn_Print_ESCColourString(Dqn_PrintESCColour_Fg, r, g, b)
#define Dqn_Print_ESCColourBgString(r, g, b) Dqn_Print_ESCColourString(Dqn_PrintESCColour_Bg, r, g, b)
#define Dqn_Print_ESCColourFg(r, g, b) Dqn_Print_ESCColourString(Dqn_PrintESCColour_Fg, r, g, b).data
#define Dqn_Print_ESCColourBg(r, g, b) Dqn_Print_ESCColourString(Dqn_PrintESCColour_Bg, r, g, b).data
#define Dqn_Print_ESCColourFgU32String(value) Dqn_Print_ESCColourU32String(Dqn_PrintESCColour_Fg, value)
#define Dqn_Print_ESCColourBgU32String(value) Dqn_Print_ESCColourU32String(Dqn_PrintESCColour_Bg, value)
#define Dqn_Print_ESCColourFgU32(value) Dqn_Print_ESCColourU32String(Dqn_PrintESCColour_Fg, value).data
#define Dqn_Print_ESCColourBgU32(value) Dqn_Print_ESCColourU32String(Dqn_PrintESCColour_Bg, value).data
#define Dqn_Print_ESCReset "\x1b[0m"
#define Dqn_Print_ESCBold "\x1b[1m"
#define Dqn_Print_ESCResetString DQN_STRING8(Dqn_Print_ESCReset)
#define Dqn_Print_ESCBoldString DQN_STRING8(Dqn_Print_ESCBold)