Compare commits
No commits in common. "76cc1f278ca503ea99ac37414c88af9dd209147d" and "2740987956aa52eef8183f4d9284ff0358da1c9f" have entirely different histories.
76cc1f278c
...
2740987956
@ -15,7 +15,6 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define DQN_ASAN_POISON 1
|
#define DQN_ASAN_POISON 1
|
||||||
#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"
|
||||||
|
@ -16,10 +16,7 @@ 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
|
||||||
|
|
||||||
|
40
dqn.h
40
dqn.h
@ -116,7 +116,6 @@
|
|||||||
// [$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
|
||||||
@ -192,6 +191,10 @@
|
|||||||
// [$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
|
||||||
@ -216,10 +219,8 @@
|
|||||||
//
|
//
|
||||||
// DQN_DUMP_STACK_TRACE
|
// DQN_DUMP_STACK_TRACE
|
||||||
//
|
//
|
||||||
// - Define this macro to enable emory leak tracking when requesting memory
|
// - Enable memory leak tracking when requesting memory from the OS via this
|
||||||
// from the OS via this library. For example calls to Dqn_VMem_Reserve or
|
// library. For example calls to Dqn_VMem_Reserve or DQN_ALLOC are recorded.
|
||||||
// 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()
|
||||||
@ -229,28 +230,6 @@
|
|||||||
// flag.
|
// flag.
|
||||||
//
|
//
|
||||||
// DQN_LEAK_TRACING
|
// DQN_LEAK_TRACING
|
||||||
//
|
|
||||||
// - Define this macro to 1 to enable poisoning of memory from arenas when ASAN
|
|
||||||
// `-fsanitize=address` is enabled. Enabling this will detect memory overwrite
|
|
||||||
// by padding allocated before and after with poisoned memory which will raise
|
|
||||||
// a use-after-poison in ASAN on read/write. This is a no-op if the library is
|
|
||||||
// not compiled with ASAN.
|
|
||||||
//
|
|
||||||
// DQN_ASAN_POISON 1
|
|
||||||
//
|
|
||||||
// - Define this macro 1 to enable sanity checks for manually poisoned memory in
|
|
||||||
// this library when ASAN `-fsanitize=address` is enabled. These sanity checks
|
|
||||||
// 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
|
|
||||||
// compiled with ASAN or `DQN_ASAN_POISON` is not set to `1`.
|
|
||||||
//
|
|
||||||
// DQN_ASAN_VET_POISON 1
|
|
||||||
//
|
|
||||||
// - Define this macro to the size of the guard memory reserved before and after
|
|
||||||
// allocations made that are poisoned to protect against out-of-bounds memory
|
|
||||||
// accesses. By default the library sets the guard to 128 bytes.
|
|
||||||
//
|
|
||||||
// DQN_ASAN_POISON_GUARD_SIZE 128
|
|
||||||
|
|
||||||
// NOTE: Dqn_Strings ===============================================================================
|
// NOTE: Dqn_Strings ===============================================================================
|
||||||
// [$CSTR] Dqn_CString8 | | C-string helpers
|
// [$CSTR] Dqn_CString8 | | C-string helpers
|
||||||
@ -284,6 +263,12 @@
|
|||||||
// 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"
|
||||||
|
|
||||||
@ -317,6 +302,7 @@
|
|||||||
#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"
|
||||||
|
192
dqn_base.cpp
192
dqn_base.cpp
@ -60,195 +60,3 @@ 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;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
113
dqn_base.h
113
dqn_base.h
@ -290,21 +290,24 @@ 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
|
||||||
|
|
||||||
enum Dqn_ZeroMem
|
typedef 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 ========================================================================
|
||||||
@ -436,8 +439,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);
|
||||||
@ -445,105 +448,3 @@ 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)
|
|
||||||
|
|
||||||
|
@ -1,30 +1,3 @@
|
|||||||
// 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
|
||||||
@ -191,7 +164,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,
|
||||||
@ -247,7 +220,8 @@ DQN_API Dqn_String8 Dqn_Log_MakeString(Dqn_Allocator allocator,
|
|||||||
header_size_no_ansi_codes = header.size - colour_esc.size - Dqn_Print_ESCResetString.size;
|
header_size_no_ansi_codes = header.size - colour_esc.size - Dqn_Print_ESCResetString.size;
|
||||||
}
|
}
|
||||||
|
|
||||||
// NOTE: Header padding ========================================================================
|
// NOTE: Header padding
|
||||||
|
// =========================================================================
|
||||||
Dqn_usize header_padding = 0;
|
Dqn_usize header_padding = 0;
|
||||||
{
|
{
|
||||||
DQN_LOCAL_PERSIST Dqn_usize max_header_length = 0;
|
DQN_LOCAL_PERSIST Dqn_usize max_header_length = 0;
|
||||||
@ -255,7 +229,8 @@ DQN_API Dqn_String8 Dqn_Log_MakeString(Dqn_Allocator allocator,
|
|||||||
header_padding = max_header_length - header_size_no_ansi_codes;
|
header_padding = max_header_length - header_size_no_ansi_codes;
|
||||||
}
|
}
|
||||||
|
|
||||||
// NOTE: Construct final log ===================================================================
|
// NOTE: Construct final log
|
||||||
|
// =========================================================================
|
||||||
Dqn_String8 user_msg = Dqn_String8_InitFV(allocator, fmt, args);
|
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_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_MEMCPY(result.data, header.data, header.size);
|
||||||
@ -266,23 +241,27 @@ 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(&lib->log_file_mutex);
|
Dqn_TicketMutex_Begin(&g_dqn_library->log_file_mutex);
|
||||||
if (lib->log_to_file && !lib->log_file.handle && lib->log_file.error_size == 0) {
|
if (g_dqn_library->log_to_file && !g_dqn_library->log_file) {
|
||||||
Dqn_ThreadScratch scratch = Dqn_Thread_GetScratch(nullptr);
|
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));
|
#if (defined(DQN_OS_WIN32) && !defined(DQN_NO_WIN)) || !defined(DQN_OS_WIN32)
|
||||||
lib->log_file = Dqn_Fs_OpenFile(log_path, Dqn_FsFileOpen_CreateAlways, Dqn_FsFileAccess_AppendOnly);
|
Dqn_String8 exe_dir = Dqn_OS_EXEDir(scratch.arena);
|
||||||
|
#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(&lib->log_file_mutex);
|
Dqn_TicketMutex_End(&g_dqn_library->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,
|
||||||
!lib->log_no_colour,
|
!g_dqn_library->log_no_colour,
|
||||||
type,
|
type,
|
||||||
log_type,
|
log_type,
|
||||||
call_site,
|
call_site,
|
||||||
@ -292,10 +271,11 @@ 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(&lib->log_file_mutex);
|
Dqn_TicketMutex_Begin(&g_dqn_library->log_file_mutex);
|
||||||
Dqn_Fs_WriteFile(&lib->log_file, log_line);
|
if (g_dqn_library->log_to_file && g_dqn_library->log_file) {
|
||||||
Dqn_Fs_WriteFile(&lib->log_file, DQN_STRING8("\n"));
|
fprintf(DQN_CAST(FILE *)g_dqn_library->log_file, "%.*s\n", DQN_STRING_FMT(log_line));
|
||||||
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)
|
||||||
|
23
dqn_debug.h
23
dqn_debug.h
@ -34,31 +34,10 @@
|
|||||||
#define DQN_ASAN_POISON 0
|
#define DQN_ASAN_POISON 0
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if !defined(DQN_ASAN_POISON_VET)
|
#if !defined(DQN_ASAN_POISON_ALIGNMENT)
|
||||||
#define DQN_ASAN_POISON_VET 0
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define DQN_ASAN_POISON_ALIGNMENT 8
|
#define DQN_ASAN_POISON_ALIGNMENT 8
|
||||||
#if !defined(DQN_ASAN_POISON_GUARD_SIZE)
|
|
||||||
#define DQN_ASAN_POISON_GUARD_SIZE 128
|
|
||||||
#endif
|
|
||||||
static_assert(Dqn_IsPowerOfTwoAligned(DQN_ASAN_POISON_GUARD_SIZE, DQN_ASAN_POISON_ALIGNMENT),
|
|
||||||
"ASAN poison guard size must be a power-of-two and aligned to ASAN's alignment"
|
|
||||||
"requirement (8 bytes)");
|
|
||||||
|
|
||||||
// NOTE: MSVC does not support the feature detection macro for instance so we
|
|
||||||
// compile it out
|
|
||||||
#if !defined(__has_feature)
|
|
||||||
#define __has_feature(x) 0
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// NOTE: [$ASAN] Dqn_Asan ==========================================================================
|
|
||||||
#if __has_feature(address_sanitizer) || defined(__SANITIZE_ADDRESS__)
|
|
||||||
#include <sanitizer/asan_interface.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
void Dqn_ASAN_PoisonMemoryRegion(void const volatile *ptr, Dqn_usize size);
|
|
||||||
void Dqn_ASAN_UnpoisonMemoryRegion(void const volatile *ptr, Dqn_usize size);
|
|
||||||
|
|
||||||
// NOTE: [$CALL] Dqn_CallSite ======================================================================
|
// NOTE: [$CALL] Dqn_CallSite ======================================================================
|
||||||
struct Dqn_CallSite
|
struct Dqn_CallSite
|
||||||
|
@ -141,10 +141,6 @@ 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";
|
||||||
|
@ -10,6 +10,8 @@
|
|||||||
#include "b_stacktrace.h"
|
#include "b_stacktrace.h"
|
||||||
|
|
||||||
// NOTE: [$OS_H] OS Headers ========================================================================
|
// NOTE: [$OS_H] OS Headers ========================================================================
|
||||||
|
#include <sanitizer/asan_interface.h>
|
||||||
|
|
||||||
#if defined(DQN_OS_WIN32)
|
#if defined(DQN_OS_WIN32)
|
||||||
#pragma comment(lib, "bcrypt")
|
#pragma comment(lib, "bcrypt")
|
||||||
#pragma comment(lib, "wininet")
|
#pragma comment(lib, "wininet")
|
||||||
|
@ -230,14 +230,18 @@ DQN_API uint64_t Dqn_Bin_HexBufferToU64(char const *hex, Dqn_usize size)
|
|||||||
DQN_ASSERT(DQN_CAST(Dqn_usize)(trim_size * 4 / 8) /*maximum amount of bytes represented in the hex string*/ <= sizeof(uint64_t));
|
DQN_ASSERT(DQN_CAST(Dqn_usize)(trim_size * 4 / 8) /*maximum amount of bytes represented in the hex string*/ <= sizeof(uint64_t));
|
||||||
|
|
||||||
uint64_t result = 0;
|
uint64_t result = 0;
|
||||||
|
Dqn_usize bits_written = 0;
|
||||||
Dqn_usize max_size = DQN_MIN(size, 8 /*bytes*/ * 2 /*hex chars per byte*/);
|
Dqn_usize max_size = DQN_MIN(size, 8 /*bytes*/ * 2 /*hex chars per byte*/);
|
||||||
for (Dqn_usize hex_index = 0; hex_index < max_size; hex_index++) {
|
for (Dqn_usize hex_index = 0; hex_index < max_size; hex_index++, bits_written += 4) {
|
||||||
char ch = trim_hex[hex_index];
|
char ch = trim_hex[hex_index];
|
||||||
if (!Dqn_Char_IsHex(ch))
|
if (!Dqn_Char_IsHex(ch))
|
||||||
break;
|
break;
|
||||||
uint8_t val = Dqn_Char_HexToU8(ch);
|
uint8_t val = Dqn_Char_HexToU8(ch);
|
||||||
result = (result << 4) | val;
|
Dqn_usize bit_shift = 60 - bits_written;
|
||||||
|
result |= (DQN_CAST(uint64_t)val << bit_shift);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
result >>= (64 - bits_written); // Shift the remainder digits to the end.
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -790,17 +794,24 @@ 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);
|
||||||
@ -813,17 +824,7 @@ 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
|
||||||
{
|
{
|
||||||
@ -839,25 +840,6 @@ DQN_API Dqn_Library *Dqn_Library_Init()
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// NOTE: Print out init features ===============================================================
|
|
||||||
|
|
||||||
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) {
|
|
||||||
Dqn_Print_StdLnF(Dqn_PrintStd_Err, " ASAN manual poisoning%s", DQN_ASAN_VET_POISON ? " (+vet sanity checks)" : "");
|
|
||||||
Dqn_Print_StdLnF(Dqn_PrintStd_Err, " ASAN poison guard size: %$$_I32u", DQN_ASAN_POISON_GUARD_SIZE);
|
|
||||||
}
|
|
||||||
|
|
||||||
#if defined(DQN_LEAK_TRACING)
|
|
||||||
Dqn_Print_StdLnF(Dqn_PrintStd_Err, " Allocation leak tracing");
|
|
||||||
#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;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -881,6 +863,14 @@ 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)
|
||||||
|
@ -587,19 +587,19 @@ void Dqn_Profiler_SwapAnchorBuffer (uint32_t anchor_count);
|
|||||||
|
|
||||||
struct Dqn_Library
|
struct Dqn_Library
|
||||||
{
|
{
|
||||||
bool lib_init; // True if the library has been initialised via `Dqn_Library_Init`
|
bool lib_init;
|
||||||
Dqn_TicketMutex lib_mutex;
|
Dqn_TicketMutex lib_mutex;
|
||||||
Dqn_String8 exe_dir; // The directory of the current executable
|
|
||||||
|
|
||||||
Dqn_Arena arena;
|
Dqn_LogProc *log_callback; ///< Set this pointer to override the logging routine
|
||||||
Dqn_ArenaCatalog arena_catalog;
|
|
||||||
|
|
||||||
Dqn_LogProc *log_callback; // Set this pointer to override the logging routine
|
|
||||||
void * log_user_data;
|
void * log_user_data;
|
||||||
bool log_to_file; // Output logs to file as well as standard out
|
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... ?
|
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
|
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
|
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;
|
||||||
|
|
||||||
// NOTE: Leak Tracing ==========================================================================
|
// NOTE: Leak Tracing ==========================================================================
|
||||||
|
|
||||||
@ -627,6 +627,14 @@ 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)
|
||||||
@ -642,5 +650,6 @@ 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);
|
||||||
|
|
||||||
|
@ -1,4 +1,6 @@
|
|||||||
// NOTE: [$ALLO] Dqn_Allocator =====================================================================
|
// NOTE: [$ALLO] Dqn_Allocator =====================================================================
|
||||||
|
#include <ios>
|
||||||
|
#include <sanitizer/asan_interface.h>
|
||||||
DQN_API void *Dqn_Allocator_Alloc(Dqn_Allocator allocator, size_t size, uint8_t align, Dqn_ZeroMem zero_mem)
|
DQN_API void *Dqn_Allocator_Alloc(Dqn_Allocator allocator, size_t size, uint8_t align, Dqn_ZeroMem zero_mem)
|
||||||
{
|
{
|
||||||
void *result = NULL;
|
void *result = NULL;
|
||||||
@ -179,7 +181,7 @@ DQN_API Dqn_MemBlockSizeRequiredResult Dqn_MemBlock_SizeRequired(Dqn_MemBlock co
|
|||||||
// is always guarded with poison-ed memory to prevent read/writes behind
|
// is always guarded with poison-ed memory to prevent read/writes behind
|
||||||
// the block of memory.
|
// the block of memory.
|
||||||
if ((block_flags & Dqn_MemBlockFlag_AllocsAreContiguous) == 0) {
|
if ((block_flags & Dqn_MemBlockFlag_AllocsAreContiguous) == 0) {
|
||||||
result.alloc_size = Dqn_AlignUpPowerOfTwo(size + DQN_ASAN_POISON_GUARD_SIZE, DQN_ASAN_POISON_ALIGNMENT);
|
result.alloc_size = Dqn_AlignUpPowerOfTwo(size + g_dqn_library->os_page_size, DQN_ASAN_POISON_ALIGNMENT);
|
||||||
}
|
}
|
||||||
ptr_alignment = DQN_MAX(alignment, DQN_ASAN_POISON_ALIGNMENT);
|
ptr_alignment = DQN_MAX(alignment, DQN_ASAN_POISON_ALIGNMENT);
|
||||||
}
|
}
|
||||||
@ -199,7 +201,7 @@ DQN_API Dqn_MemBlockSizeRequiredResult Dqn_MemBlock_SizeRequired(Dqn_MemBlock co
|
|||||||
|
|
||||||
Dqn_usize Dqn_MemBlock_MetadataSize()
|
Dqn_usize Dqn_MemBlock_MetadataSize()
|
||||||
{
|
{
|
||||||
Dqn_usize init_poison_page = DQN_ASAN_POISON ? DQN_ASAN_POISON_GUARD_SIZE : 0;
|
Dqn_usize init_poison_page = DQN_ASAN_POISON ? g_dqn_library->os_page_size : 0;
|
||||||
Dqn_usize poison_alignment = DQN_ASAN_POISON ? DQN_ASAN_POISON_ALIGNMENT : 0;
|
Dqn_usize poison_alignment = DQN_ASAN_POISON ? DQN_ASAN_POISON_ALIGNMENT : 0;
|
||||||
Dqn_usize result = Dqn_AlignUpPowerOfTwo(sizeof(Dqn_MemBlock), poison_alignment) + init_poison_page;
|
Dqn_usize result = Dqn_AlignUpPowerOfTwo(sizeof(Dqn_MemBlock), poison_alignment) + init_poison_page;
|
||||||
return result;
|
return result;
|
||||||
@ -232,16 +234,11 @@ DQN_API Dqn_MemBlock *Dqn_MemBlock_Init(Dqn_usize reserve, Dqn_usize commit, uin
|
|||||||
result->commit = commit_aligned - metadata_size;
|
result->commit = commit_aligned - metadata_size;
|
||||||
result->flags = DQN_CAST(uint8_t)flags;
|
result->flags = DQN_CAST(uint8_t)flags;
|
||||||
|
|
||||||
// NOTE: Poison (guard page + commit). We do *not* poison the entire
|
if (DQN_ASAN_POISON) { // NOTE: Poison (guard page + entire block), we unpoison as we allocate
|
||||||
// block, only the commit pages. Since we may reserve large amounts of
|
|
||||||
// space vs commit we'd waste time marking those pages as poisoned as
|
|
||||||
// reads or writes outside of committed pages will page fault.
|
|
||||||
if (DQN_ASAN_POISON) {
|
|
||||||
DQN_ASSERT(Dqn_IsPowerOfTwoAligned(result->data, DQN_ASAN_POISON_ALIGNMENT));
|
DQN_ASSERT(Dqn_IsPowerOfTwoAligned(result->data, DQN_ASAN_POISON_ALIGNMENT));
|
||||||
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 = DQN_ASAN_POISON_GUARD_SIZE + result->commit;
|
ASAN_POISON_MEMORY_REGION(poison_ptr, g_dqn_library->os_page_size + result->size);
|
||||||
Dqn_ASAN_PoisonMemoryRegion(poison_ptr, bytes_to_poison);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
@ -264,8 +261,9 @@ DQN_API void *Dqn_MemBlock_Alloc(Dqn_MemBlock *block, Dqn_usize size, uint8_t al
|
|||||||
block->used = new_used;
|
block->used = new_used;
|
||||||
DQN_ASSERT(Dqn_IsPowerOfTwoAligned(result, alignment));
|
DQN_ASSERT(Dqn_IsPowerOfTwoAligned(result, alignment));
|
||||||
|
|
||||||
if (DQN_ASAN_POISON)
|
if (DQN_ASAN_POISON) {
|
||||||
Dqn_ASAN_UnpoisonMemoryRegion(result, size);
|
ASAN_UNPOISON_MEMORY_REGION(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);
|
||||||
@ -278,12 +276,6 @@ DQN_API void *Dqn_MemBlock_Alloc(Dqn_MemBlock *block, Dqn_usize size, uint8_t al
|
|||||||
block->commit += commit_size;
|
block->commit += commit_size;
|
||||||
Dqn_VMem_Commit(commit_ptr, commit_size, Dqn_VMemPage_ReadWrite);
|
Dqn_VMem_Commit(commit_ptr, commit_size, Dqn_VMemPage_ReadWrite);
|
||||||
DQN_ASSERT(block->commit <= block->size);
|
DQN_ASSERT(block->commit <= block->size);
|
||||||
|
|
||||||
if (DQN_ASAN_POISON) { // NOTE: Poison newly committed pages that aren't being used.
|
|
||||||
void *poison_ptr = DQN_CAST(char *)block->data + block->used;
|
|
||||||
Dqn_usize bytes_to_poison = block->commit - block->used;
|
|
||||||
Dqn_ASAN_PoisonMemoryRegion(poison_ptr, bytes_to_poison);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
@ -294,8 +286,9 @@ DQN_API void Dqn_MemBlock_Free(Dqn_MemBlock *block)
|
|||||||
if (!block)
|
if (!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_UnpoisonMemoryRegion(block, release_size);
|
ASAN_UNPOISON_MEMORY_REGION(block, release_size);
|
||||||
|
}
|
||||||
Dqn_VMem_Release(block, release_size);
|
Dqn_VMem_Release(block, release_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -314,10 +307,13 @@ DQN_API void Dqn_MemBlock_PopTo(Dqn_MemBlock *block, Dqn_usize to)
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
if (DQN_ASAN_POISON) {
|
if (DQN_ASAN_POISON) {
|
||||||
void *poison_ptr = DQN_CAST(char *)block->data + to;
|
// TODO(doyle): The poison API takes addresses that are 8 byte aligned
|
||||||
void *end_ptr = DQN_CAST(void *)Dqn_AlignUpPowerOfTwo((DQN_CAST(uintptr_t)block->data + block->used), DQN_ASAN_POISON_ALIGNMENT);
|
// so there are gaps here if we are dealing with objects that aren't 8
|
||||||
|
// byte aligned unfortunately.
|
||||||
|
void *poison_ptr = DQN_CAST(void *)Dqn_AlignUpPowerOfTwo(DQN_CAST(char *)block->data + to, DQN_ASAN_POISON_ALIGNMENT);
|
||||||
|
void *end_ptr = DQN_CAST(char *)block->data + block->used;
|
||||||
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_PoisonMemoryRegion(poison_ptr, bytes_to_poison);
|
ASAN_POISON_MEMORY_REGION(poison_ptr, bytes_to_poison);
|
||||||
}
|
}
|
||||||
block->used = to;
|
block->used = to;
|
||||||
}
|
}
|
||||||
|
@ -295,6 +295,9 @@ 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
|
||||||
|
@ -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_WriteFileBuffer(Dqn_FsFile *file, void const *buffer, Dqn_usize size)
|
DQN_API bool Dqn_Fs_WriteFile(Dqn_FsFile *file, char 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 = DQN_CAST(char *)buffer + size;
|
char const *end = buffer + size;
|
||||||
for (char const *ptr = DQN_CAST(char const *)buffer; result && ptr != end; ) {
|
for (char const *ptr = 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,32 +675,6 @@ DQN_API bool Dqn_Fs_WriteFileBuffer(Dqn_FsFile *file, void const *buffer, Dqn_us
|
|||||||
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)
|
||||||
@ -1928,14 +1902,17 @@ 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)
|
||||||
{
|
{
|
||||||
allocator = context->scratch_allocators[context_index];
|
index = context_index;
|
||||||
arena = context->scratch_arenas[context_index];
|
allocator = context->temp_allocators[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;
|
||||||
@ -1957,18 +1934,26 @@ 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 scratch arenas
|
// NOTE: Setup permanent arena
|
||||||
for (uint8_t index = 0; index < DQN_ARRAY_UCOUNT(result.scratch_arenas); index++) {
|
Dqn_ArenaCatalog *catalog = &g_dqn_library->arena_catalog;
|
||||||
result.scratch_arenas[index] = Dqn_ArenaCatalog_AllocF(catalog,
|
result.allocator = Dqn_Arena_Allocator(result.arena);
|
||||||
|
result.arena = Dqn_ArenaCatalog_AllocF(catalog,
|
||||||
DQN_GIGABYTES(1) /*size*/,
|
DQN_GIGABYTES(1) /*size*/,
|
||||||
DQN_KILOBYTES(64) /*commit*/,
|
DQN_KILOBYTES(64) /*commit*/,
|
||||||
"Thread %u Scratch Arena %u",
|
"Thread %u Arena",
|
||||||
|
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.scratch_allocators[index] = Dqn_Arena_Allocator(result.scratch_arenas[index]);
|
result.temp_allocators[index] = Dqn_Arena_Allocator(result.temp_arenas[index]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return &result;
|
return &result;
|
||||||
@ -1978,10 +1963,11 @@ 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_ARRAY_UCOUNT(context->scratch_arenas); index++) {
|
for (uint8_t index = 0; index < DQN_THREAD_CONTEXT_ARENAS; index++) {
|
||||||
Dqn_Arena *arena = context->scratch_arenas[index];
|
Dqn_Arena *arena = context->temp_arenas[index];
|
||||||
if (!conflict_arena || arena != conflict_arena) {
|
if (!conflict_arena || arena != conflict_arena) {
|
||||||
context_index = index;
|
context_index = index;
|
||||||
break;
|
break;
|
||||||
@ -1991,3 +1977,4 @@ 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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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,16 +80,13 @@ 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 access mode
|
Dqn_FsFileAccess_AppendOnly = 1 << 3, ///< This flag cannot be combined with any other acess 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_WriteFileBuffer(Dqn_FsFile *file, void const *data, Dqn_usize size);
|
DQN_API bool Dqn_Fs_WriteFile(Dqn_FsFile *file, char const *buffer, 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)
|
||||||
|
|
||||||
@ -462,16 +459,27 @@ 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;
|
||||||
|
|
||||||
// Scratch memory arena's for the calling thread
|
Dqn_Arena *arena; ///< Per thread arena
|
||||||
Dqn_Arena *scratch_arenas[2];
|
Dqn_Allocator allocator; ///< Allocator that uses the arena
|
||||||
|
|
||||||
// Allocators that use the corresponding arena from the thread context.
|
/// Temp memory arena's for the calling thread
|
||||||
// Provided for convenience when interfacing with allocator interfaces.
|
Dqn_Arena *temp_arenas[DQN_THREAD_CONTEXT_ARENAS];
|
||||||
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
|
||||||
@ -479,10 +487,16 @@ 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;
|
Dqn_b32 destructed = false; /// Detect copies of the scratch
|
||||||
Dqn_ArenaTempMemory temp_memory;
|
Dqn_ArenaTempMemory temp_memory;
|
||||||
|
#if defined(DQN_LEAK_TRACING)
|
||||||
|
Dqn_CallSite leak_site__;
|
||||||
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
// NOTE: Context ===================================================================================
|
// NOTE: Context ===================================================================================
|
||||||
|
194
dqn_platform_print.cpp
Normal file
194
dqn_platform_print.cpp
Normal file
@ -0,0 +1,194 @@
|
|||||||
|
// 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;
|
||||||
|
}
|
||||||
|
|
84
dqn_platform_print.h
Normal file
84
dqn_platform_print.h
Normal file
@ -0,0 +1,84 @@
|
|||||||
|
// 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)
|
||||||
|
|
Loading…
Reference in New Issue
Block a user