dqn: Upgrade lib to latest version from TELY

This commit is contained in:
doyle 2023-10-25 00:11:48 +11:00
parent b46b44f11c
commit bf413d7e57
23 changed files with 3274 additions and 1796 deletions

File diff suppressed because it is too large Load Diff

View File

@ -19,7 +19,7 @@ pushd Build
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 msvc_compile_flags=%msvc_driver_flags% -analyze -fsanitize=address /Fe:dqn_unit_tests_msvc
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

34
dqn.h
View File

@ -41,7 +41,7 @@
defined(DQN_ONLY_SLICE) || \
defined(DQN_ONLY_DSMAP) || \
defined(DQN_ONLY_LIST) || \
defined(DQN_ONLY_FSTRING8) || \
defined(DQN_ONLY_FSTR8) || \
defined(DQN_ONLY_FS) || \
defined(DQN_ONLY_WINNET) || \
defined(DQN_ONLY_WIN) || \
@ -72,8 +72,8 @@
#if !defined(DQN_ONLY_LIST)
#define DQN_NO_LIST
#endif
#if !defined(DQN_ONLY_FSTRING8)
#define DQN_NO_FSTRING8
#if !defined(DQN_ONLY_FSTR8)
#define DQN_NO_FSTR8
#endif
#if !defined(DQN_ONLY_FS)
#define DQN_NO_FS
@ -202,11 +202,18 @@
// [$ACAT] Dqn_ArenaCatalog | | Collate, create & manage arenas in a catalog
#include "dqn_memory.h"
// NOTE: Dqn_Debug =================================================================================
// [$DEBM] Debug Macros | |
// [$ASAN] Dqn_Asan | | Helpers to manually poison memory using ASAN
// [$STKT] Dqn_StackTrace | | Create stack traces
// [$DEBG] Dqn_Debug | | Debugging tools/helpers
#include "dqn_debug.h"
// NOTE: Dqn_Strings ===============================================================================
// [$CSTR] Dqn_CString8 | | C-string helpers
// [$STR8] Dqn_String8 | | Pointer and length strings
// [$FSTR] Dqn_FString8 | DQN_FSTRING8 | Fixed-size strings
// [$STRB] Dqn_String8Builder | |
// [$CSTR] Dqn_CStr8 | | C-string helpers
// [$STR8] Dqn_Str8 | | Pointer and length strings
// [$FSTR] Dqn_FStr8 | DQN_FSTr8 | Fixed-size strings
// [$STRB] Dqn_Str8Builder | |
// [$CHAR] Dqn_Char | | Character ascii/digit.. helpers
// [$UTFX] Dqn_UTF | | Unicode helpers
#include "dqn_strings.h"
@ -221,13 +228,6 @@
// [$LIST] Dqn_List | DQN_LIST | Chunked linked lists, append only
#include "dqn_containers.h"
// NOTE: Dqn_Debug =================================================================================
// [$DEBM] Debug Macros | |
// [$ASAN] Dqn_Asan | | Helpers to manually poison memory using ASAN
// [$STKT] Dqn_StackTrace | | Create stack traces
// [$DEBG] Dqn_Debug | | Debugging tools/helpers
#include "dqn_debug.h"
// NOTE: Additional Configuration
// - Override the default break into the active debugger function. By default
// we use __debugbreak() on Windows and raise(SIGTRAP) on other platforms.
@ -285,6 +285,10 @@
// [$TCTX] Dqn_ThreadContext | | Per-thread data structure e.g. temp arenas
#include "dqn_platform.h"
// NOTE: Dqn_OS ====================================================================================
// [$EXEC] Dqn_OSExec | | Execute programs programatically
#include "dqn_os.h"
// NOTE: Dqn_Math ==================================================================================
// [$VEC2] Dqn_V2, V2i | DQN_V2 |
// [$VEC3] Dqn_V3, V3i | DQN_V3 |
@ -300,6 +304,7 @@
#include "dqn_hash.h"
// NOTE: Dqn_Helpers ===============================================================================
// [$PCG3] Dqn_PCG32 | | RNG from the PCG family
// [$JSON] Dqn_JSONBuilder | DQN_JSON_BUILDER | Construct json output
// [$BHEX] Dqn_Bin | DQN_BIN | Binary <-> hex helpers
// [$BSEA] Dqn_BinarySearch | | Binary search
@ -319,6 +324,7 @@
#include "dqn_strings.cpp"
#include "dqn_containers.cpp"
#include "dqn_platform.cpp"
#include "dqn_os.cpp"
#include "dqn_math.cpp"
#include "dqn_hash.cpp"
#include "dqn_helpers.cpp"

View File

@ -1,5 +1,5 @@
// NOTE: [$INTR] Intrinsics ========================================================================
#if !defined(DQN_OS_ARM64)
#if !defined(DQN_PLATFORM_ARM64) && !defined(DQN_PLATFORM_EMSCRIPTEN)
#if defined(DQN_COMPILER_GCC) || defined(DQN_COMPILER_CLANG)
#include <cpuid.h>
#endif
@ -16,7 +16,7 @@ Dqn_CPUIDRegisters Dqn_CPUID(int function_id)
#endif
return result;
}
#endif // !defined(DQN_OS_ARM64)
#endif // !defined(DQN_PLATFORM_ARM64) && !defined(DQN_PLATFORM_EMSCRIPTEN)
// NOTE: [$ALLO] Dqn_Allocator =====================================================================
DQN_API void *Dqn_Allocator_Alloc(Dqn_Allocator allocator, size_t size, uint8_t align, Dqn_ZeroMem zero_mem)
@ -110,7 +110,7 @@ DQN_API Dqn_PrintStyle Dqn_Print_StyleBold()
return result;
}
DQN_API void Dqn_Print_Std(Dqn_PrintStd std_handle, Dqn_String8 string)
DQN_API void Dqn_Print_Std(Dqn_PrintStd std_handle, Dqn_Str8 string)
{
DQN_ASSERT(std_handle == Dqn_PrintStd_Out || std_handle == Dqn_PrintStd_Err);
@ -147,26 +147,26 @@ DQN_API void Dqn_Print_Std(Dqn_PrintStd std_handle, Dqn_String8 string)
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));
fprintf(std_handle == Dqn_PrintStd_Out ? stdout : stderr, "%.*s", DQN_STR_FMT(string));
#endif
}
DQN_API void Dqn_Print_StdStyle(Dqn_PrintStd std_handle, Dqn_PrintStyle style, Dqn_String8 string)
DQN_API void Dqn_Print_StdStyle(Dqn_PrintStd std_handle, Dqn_PrintStyle style, Dqn_Str8 string)
{
if (string.data && string.size) {
if (style.colour)
Dqn_Print_Std(std_handle, Dqn_Print_ESCColourFgString(style.r, style.g, style.b));
Dqn_Print_Std(std_handle, Dqn_Print_ESCColourFgStr8(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, Dqn_Print_ESCBoldStr8);
Dqn_Print_Std(std_handle, string);
if (style.colour || style.bold == Dqn_PrintBold_Yes)
Dqn_Print_Std(std_handle, Dqn_Print_ESCResetString);
Dqn_Print_Std(std_handle, Dqn_Print_ESCResetStr8);
}
}
DQN_FILE_SCOPE char *Dqn_Print_VSPrintfChunker_(const char *buf, void *user, int len)
{
Dqn_String8 string = {};
Dqn_Str8 string = {};
string.data = DQN_CAST(char *)buf;
string.size = len;
@ -175,7 +175,7 @@ DQN_FILE_SCOPE char *Dqn_Print_VSPrintfChunker_(const char *buf, void *user, int
return (char *)buf;
}
DQN_API void Dqn_Print_StdF(Dqn_PrintStd std_handle, DQN_FMT_STRING_ANNOTATE char const *fmt, ...)
DQN_API void Dqn_Print_StdF(Dqn_PrintStd std_handle, DQN_FMT_ATTRIB char const *fmt, ...)
{
va_list args;
va_start(args, fmt);
@ -183,7 +183,7 @@ DQN_API void Dqn_Print_StdF(Dqn_PrintStd std_handle, DQN_FMT_STRING_ANNOTATE cha
va_end(args);
}
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_StdFStyle(Dqn_PrintStd std_handle, Dqn_PrintStyle style, DQN_FMT_ATTRIB char const *fmt, ...)
{
va_list args;
va_start(args, fmt);
@ -191,32 +191,32 @@ DQN_API void Dqn_Print_StdFStyle(Dqn_PrintStd std_handle, Dqn_PrintStyle style,
va_end(args);
}
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_StdFV(Dqn_PrintStd std_handle, DQN_FMT_ATTRIB 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)
DQN_API void Dqn_Print_StdFVStyle(Dqn_PrintStd std_handle, Dqn_PrintStyle style, DQN_FMT_ATTRIB 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));
Dqn_Print_Std(std_handle, Dqn_Print_ESCColourFgStr8(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, Dqn_Print_ESCBoldStr8);
Dqn_Print_StdFV(std_handle, fmt, args);
if (style.colour || style.bold == Dqn_PrintBold_Yes)
Dqn_Print_Std(std_handle, Dqn_Print_ESCResetString);
Dqn_Print_Std(std_handle, Dqn_Print_ESCResetStr8);
}
}
DQN_API void Dqn_Print_StdLn(Dqn_PrintStd std_handle, Dqn_String8 string)
DQN_API void Dqn_Print_StdLn(Dqn_PrintStd std_handle, Dqn_Str8 string)
{
Dqn_Print_Std(std_handle, string);
Dqn_Print_Std(std_handle, DQN_STRING8("\n"));
Dqn_Print_Std(std_handle, DQN_STR8("\n"));
}
DQN_API void Dqn_Print_StdLnF(Dqn_PrintStd std_handle, DQN_FMT_STRING_ANNOTATE char const *fmt, ...)
DQN_API void Dqn_Print_StdLnF(Dqn_PrintStd std_handle, DQN_FMT_ATTRIB char const *fmt, ...)
{
va_list args;
va_start(args, fmt);
@ -224,19 +224,19 @@ DQN_API void Dqn_Print_StdLnF(Dqn_PrintStd std_handle, DQN_FMT_STRING_ANNOTATE c
va_end(args);
}
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_StdLnFV(Dqn_PrintStd std_handle, DQN_FMT_ATTRIB char const *fmt, va_list args)
{
Dqn_Print_StdFV(std_handle, fmt, args);
Dqn_Print_Std(std_handle, DQN_STRING8("\n"));
Dqn_Print_Std(std_handle, DQN_STR8("\n"));
}
DQN_API void Dqn_Print_StdLnStyle(Dqn_PrintStd std_handle, Dqn_PrintStyle style, Dqn_String8 string)
DQN_API void Dqn_Print_StdLnStyle(Dqn_PrintStd std_handle, Dqn_PrintStyle style, Dqn_Str8 string)
{
Dqn_Print_StdStyle(std_handle, style, string);
Dqn_Print_Std(std_handle, DQN_STRING8("\n"));
Dqn_Print_Std(std_handle, DQN_STR8("\n"));
}
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_StdLnFStyle(Dqn_PrintStd std_handle, Dqn_PrintStyle style, DQN_FMT_ATTRIB char const *fmt, ...)
{
va_list args;
va_start(args, fmt);
@ -244,87 +244,87 @@ DQN_API void Dqn_Print_StdLnFStyle(Dqn_PrintStd std_handle, Dqn_PrintStyle style
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_API void Dqn_Print_StdLnFVStyle(Dqn_PrintStd std_handle, Dqn_PrintStyle style, DQN_FMT_ATTRIB char const *fmt, va_list args)
{
Dqn_Print_StdFVStyle(std_handle, style, fmt, args);
Dqn_Print_Std(std_handle, DQN_STRING8("\n"));
Dqn_Print_Std(std_handle, DQN_STR8("\n"));
}
DQN_API Dqn_String8 Dqn_Print_ESCColourString(Dqn_PrintESCColour colour, uint8_t r, uint8_t g, uint8_t b)
DQN_API Dqn_Str8 Dqn_Print_ESCColourStr8(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;
buffer[0] = 0;
Dqn_Str8 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)
DQN_API Dqn_Str8 Dqn_Print_ESCColourU32Str8(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);
Dqn_Str8 result = Dqn_Print_ESCColourStr8(colour, r, g, b);
return result;
}
// NOTE: [$LLOG] Dqn_Log ==========================================================================
DQN_API Dqn_String8 Dqn_Log_MakeString(Dqn_Allocator allocator,
bool colour,
Dqn_String8 type,
int log_type,
Dqn_CallSite call_site,
char const *fmt,
va_list args)
DQN_API Dqn_Str8 Dqn_Log_MakeStr8(Dqn_Allocator allocator,
bool colour,
Dqn_Str8 type,
int log_type,
Dqn_CallSite call_site,
DQN_FMT_ATTRIB char const *fmt,
va_list args)
{
Dqn_usize header_size_no_ansi_codes = 0;
Dqn_String8 header = {};
Dqn_usize header_size_no_ansi_codes = 0;
Dqn_Str8 header = {};
{
DQN_LOCAL_PERSIST Dqn_usize max_type_length = 0;
max_type_length = DQN_MAX(max_type_length, type.size);
int type_padding = DQN_CAST(int)(max_type_length - type.size);
Dqn_String8 colour_esc = {};
Dqn_String8 bold_esc = {};
Dqn_String8 reset_esc = {};
Dqn_Str8 colour_esc = {};
Dqn_Str8 bold_esc = {};
Dqn_Str8 reset_esc = {};
if (colour) {
bold_esc = Dqn_Print_ESCBoldString;
reset_esc = Dqn_Print_ESCResetString;
bold_esc = Dqn_Print_ESCBoldStr8;
reset_esc = Dqn_Print_ESCResetStr8;
switch (log_type) {
case Dqn_LogType_Debug: break;
case Dqn_LogType_Info: colour_esc = Dqn_Print_ESCColourFgU32String(Dqn_LogTypeColourU32_Info); break;
case Dqn_LogType_Warning: colour_esc = Dqn_Print_ESCColourFgU32String(Dqn_LogTypeColourU32_Warning); break;
case Dqn_LogType_Error: colour_esc = Dqn_Print_ESCColourFgU32String(Dqn_LogTypeColourU32_Error); break;
case Dqn_LogType_Debug: break;
case Dqn_LogType_Info: colour_esc = Dqn_Print_ESCColourFgU32Str8(Dqn_LogTypeColourU32_Info); break;
case Dqn_LogType_Warning: colour_esc = Dqn_Print_ESCColourFgU32Str8(Dqn_LogTypeColourU32_Warning); break;
case Dqn_LogType_Error: colour_esc = Dqn_Print_ESCColourFgU32Str8(Dqn_LogTypeColourU32_Error); break;
}
}
Dqn_String8 file_name = Dqn_String8_FileNameFromPath(call_site.file);
Dqn_DateHMSTimeString const time = Dqn_Date_HMSLocalTimeStringNow();
header = Dqn_String8_InitF(allocator,
"%.*s " // date
"%.*s " // hms
"%.*s" // colour
"%.*s" // bold
"%.*s" // type
"%*s" // type padding
"%.*s" // reset
" %.*s" // file name
":%05u ", // line number
DQN_CAST(uint32_t)time.date_size - 2, time.date + 2, // date
DQN_CAST(uint32_t)time.hms_size, time.hms, // hms
DQN_CAST(uint32_t)colour_esc.size, colour_esc.data, // colour
DQN_CAST(uint32_t)bold_esc.size, bold_esc.data, // bold
DQN_CAST(uint32_t)type.size, type.data, // type
DQN_CAST(uint32_t)type_padding, "", // type padding
DQN_CAST(uint32_t)reset_esc.size, reset_esc.data, // reset
DQN_CAST(uint32_t)file_name.size, file_name.data, // file name
call_site.line); // line number
header_size_no_ansi_codes = header.size - colour_esc.size - Dqn_Print_ESCResetString.size;
Dqn_Str8 file_name = Dqn_Str8_FileNameFromPath(call_site.file);
Dqn_DateHMSTimeStr8 const time = Dqn_Date_LocalTimeHMSStr8Now();
header = Dqn_Str8_InitF(allocator,
"%.*s " // date
"%.*s " // hms
"%.*s" // colour
"%.*s" // bold
"%.*s" // type
"%*s" // type padding
"%.*s" // reset
" %.*s" // file name
":%05u ", // line number
DQN_CAST(uint32_t)time.date_size - 2, time.date + 2, // date
DQN_CAST(uint32_t)time.hms_size, time.hms, // hms
DQN_CAST(uint32_t)colour_esc.size, colour_esc.data, // colour
DQN_CAST(uint32_t)bold_esc.size, bold_esc.data, // bold
DQN_CAST(uint32_t)type.size, type.data, // type
DQN_CAST(uint32_t)type_padding, "", // type padding
DQN_CAST(uint32_t)reset_esc.size, reset_esc.data, // reset
DQN_CAST(uint32_t)file_name.size, file_name.data, // file name
call_site.line); // line number
header_size_no_ansi_codes = header.size - colour_esc.size - Dqn_Print_ESCResetStr8.size;
}
// NOTE: Header padding ========================================================================
@ -336,15 +336,15 @@ DQN_API Dqn_String8 Dqn_Log_MakeString(Dqn_Allocator allocator,
}
// NOTE: Construct final log ===================================================================
Dqn_String8 user_msg = Dqn_String8_InitFV(allocator, fmt, args);
Dqn_String8 result = Dqn_String8_Allocate(allocator, header.size + header_padding + user_msg.size, Dqn_ZeroMem_No);
Dqn_Str8 user_msg = Dqn_Str8_InitFV(allocator, fmt, args);
Dqn_Str8 result = Dqn_Str8_Allocate(allocator, header.size + header_padding + user_msg.size, Dqn_ZeroMem_No);
DQN_MEMCPY(result.data, header.data, header.size);
DQN_MEMSET(result.data + header.size, ' ', header_padding);
DQN_MEMCPY(result.data + header.size + header_padding, user_msg.data, user_msg.size);
return result;
}
DQN_FILE_SCOPE void Dqn_Log_FVDefault_(Dqn_String8 type, int log_type, void *user_data, Dqn_CallSite call_site, char const *fmt, va_list args)
DQN_FILE_SCOPE void Dqn_Log_FVDefault_(Dqn_Str8 type, int log_type, void *user_data, Dqn_CallSite call_site, DQN_FMT_ATTRIB char const *fmt, va_list args)
{
Dqn_Library *lib = g_dqn_library;
(void)log_type;
@ -354,37 +354,36 @@ DQN_FILE_SCOPE void Dqn_Log_FVDefault_(Dqn_String8 type, int log_type, void *use
Dqn_TicketMutex_Begin(&lib->log_file_mutex);
if (lib->log_to_file && !lib->log_file.handle && lib->log_file.error_size == 0) {
Dqn_ThreadScratch scratch = Dqn_Thread_GetScratch(nullptr);
Dqn_String8 log_path = Dqn_FsPath_ConvertF(scratch.arena, "%.*s/dqn.log", DQN_STRING_FMT(lib->exe_dir));
Dqn_Str8 log_path = Dqn_FsPath_ConvertF(scratch.arena, "%.*s/dqn.log", DQN_STR_FMT(lib->exe_dir));
lib->log_file = Dqn_Fs_OpenFile(log_path, Dqn_FsFileOpen_CreateAlways, Dqn_FsFileAccess_AppendOnly);
}
Dqn_TicketMutex_End(&lib->log_file_mutex);
// NOTE: Generate the log header ===========================================
Dqn_ThreadScratch scratch = Dqn_Thread_GetScratch(nullptr);
Dqn_String8 log_line = Dqn_Log_MakeString(scratch.allocator,
!lib->log_no_colour,
type,
log_type,
call_site,
fmt,
args);
Dqn_ThreadScratch scratch = Dqn_Thread_GetScratch(nullptr);
Dqn_Str8 log_line = Dqn_Log_MakeStr8(scratch.allocator, !lib->log_no_colour, type, log_type, call_site, fmt, args);
// NOTE: Print log =========================================================
Dqn_Print_StdLn(Dqn_PrintStd_Out, log_line);
Dqn_TicketMutex_Begin(&lib->log_file_mutex);
Dqn_Fs_WriteFile(&lib->log_file, log_line);
Dqn_Fs_WriteFile(&lib->log_file, DQN_STRING8("\n"));
Dqn_Fs_WriteFile(&lib->log_file, DQN_STR8("\n"));
Dqn_TicketMutex_End(&lib->log_file_mutex);
}
DQN_API void Dqn_Log_FVCallSite(Dqn_String8 type, Dqn_CallSite call_site, char const *fmt, va_list args)
DQN_API void Dqn_Log_FVCallSite(Dqn_Str8 type, Dqn_CallSite call_site, DQN_FMT_ATTRIB char const *fmt, va_list args)
{
Dqn_LogProc *logging_function = g_dqn_library->log_callback ? g_dqn_library->log_callback : Dqn_Log_FVDefault_;
logging_function(type, -1 /*log_type*/, g_dqn_library->log_user_data, call_site, fmt, args);
if (g_dqn_library) {
Dqn_LogProc *logging_function = g_dqn_library->log_callback ? g_dqn_library->log_callback : Dqn_Log_FVDefault_;
logging_function(type, -1 /*log_type*/, g_dqn_library->log_user_data, call_site, fmt, args);
} else {
// NOTE: Rarely taken branch, only when trying to use this library without initialising it
Dqn_Print_StdLnFV(Dqn_PrintStd_Out, fmt, args);
}
}
DQN_API void Dqn_Log_FCallSite(Dqn_String8 type, Dqn_CallSite call_site, char const *fmt, ...)
DQN_API void Dqn_Log_FCallSite(Dqn_Str8 type, Dqn_CallSite call_site, DQN_FMT_ATTRIB char const *fmt, ...)
{
va_list args;
va_start(args, fmt);
@ -392,26 +391,23 @@ DQN_API void Dqn_Log_FCallSite(Dqn_String8 type, Dqn_CallSite call_site, char co
va_end(args);
}
DQN_API void Dqn_Log_TypeFVCallSite(Dqn_LogType type, Dqn_CallSite call_site, char const *fmt, va_list args)
DQN_API void Dqn_Log_TypeFVCallSite(Dqn_LogType type, Dqn_CallSite call_site, DQN_FMT_ATTRIB char const *fmt, va_list args)
{
Dqn_String8 type_string = DQN_STRING8("DQN-BAD-LOG-TYPE");
Dqn_Str8 type_string = DQN_STR8("DQN-BAD-LOG-TYPE");
switch (type) {
case Dqn_LogType_Error: type_string = DQN_STRING8("ERROR"); break;
case Dqn_LogType_Info: type_string = DQN_STRING8("INFO"); break;
case Dqn_LogType_Warning: type_string = DQN_STRING8("WARN"); break;
case Dqn_LogType_Debug: type_string = DQN_STRING8("DEBUG"); break;
case Dqn_LogType_Count: type_string = DQN_STRING8("BADXX"); break;
case Dqn_LogType_Error: type_string = DQN_STR8("ERROR"); break;
case Dqn_LogType_Info: type_string = DQN_STR8("INFO"); break;
case Dqn_LogType_Warning: type_string = DQN_STR8("WARN"); break;
case Dqn_LogType_Debug: type_string = DQN_STR8("DEBUG"); break;
case Dqn_LogType_Count: type_string = DQN_STR8("BADXX"); break;
}
Dqn_LogProc *logging_function = g_dqn_library->log_callback ? g_dqn_library->log_callback : Dqn_Log_FVDefault_;
logging_function(type_string, type /*log_type*/, g_dqn_library->log_user_data, call_site, fmt, args);
Dqn_Log_FVCallSite(type_string, call_site, fmt, args);
}
DQN_API void Dqn_Log_TypeFCallSite(Dqn_LogType type, Dqn_CallSite call_site, char const *fmt, ...)
DQN_API void Dqn_Log_TypeFCallSite(Dqn_LogType type, Dqn_CallSite call_site, DQN_FMT_ATTRIB char const *fmt, ...)
{
va_list args;
va_start(args, fmt);
Dqn_Log_TypeFVCallSite(type, call_site, fmt, args);
va_end(args);
}

View File

@ -39,12 +39,16 @@
#if defined(_WIN32)
#define DQN_OS_WIN32
#elif defined(__aarch64__) || defined(_M_ARM64)
#define DQN_OS_ARM64
#elif defined(__linux__)
#define DQN_OS_UNIX
#endif
#if defined(__aarch64__) || defined(_M_ARM64)
#define DQN_PLATFORM_ARM64
#elif defined(__EMSCRIPTEN__)
#define DQN_PLATFORM_EMSCRIPTEN
#endif
#if defined(DQN_COMPILER_MSVC) || defined(DQN_COMPILER_CLANG_CL)
#if defined(_CRT_SECURE_NO_WARNINGS)
#define DQN_CRT_SECURE_NO_WARNINGS_PREVIOUSLY_DEFINED
@ -54,12 +58,12 @@
#endif
#if defined(DQN_COMPILER_MSVC)
#define DQN_FMT_STRING_ANNOTATE _Printf_format_string_
#define DQN_FMT_ATTRIB _Printf_format_string_
#define DQN_MSVC_WARNING_PUSH __pragma(warning(push))
#define DQN_MSVC_WARNING_DISABLE(...) __pragma(warning(disable: ##__VA_ARGS__))
#define DQN_MSVC_WARNING_POP __pragma(warning(pop))
#else
#define DQN_FMT_STRING_ANNOTATE
#define DQN_FMT_ATTRIB
#define DQN_MSVC_WARNING_PUSH
#define DQN_MSVC_WARNING_DISABLE(...)
#define DQN_MSVC_WARNING_POP
@ -67,8 +71,9 @@
#if defined(DQN_COMPILER_CLANG) || defined(DQN_COMPILER_GCC) || defined(DQN_COMPILER_CLANG_CL)
#define DQN_GCC_WARNING_PUSH _Pragma("GCC diagnostic push")
#define DQN_GCC_WARNING_DISABLE(warning) DQN_GCC_WARNING_DISABLE_HELPER(GCC diagnostic ignored warning)
#define DQN_GCC_WARNING_DISABLE_HELPER(warning) _Pragma(#warning)
#define DQN_GCC_WARNING_DISABLE_HELPER_0(x) #x
#define DQN_GCC_WARNING_DISABLE_HELPER_1(y) DQN_GCC_WARNING_DISABLE_HELPER_0(GCC diagnostic ignored #y)
#define DQN_GCC_WARNING_DISABLE(warning) _Pragma(DQN_GCC_WARNING_DISABLE_HELPER_1(warning))
#define DQN_GCC_WARNING_POP _Pragma("GCC diagnostic pop")
#else
#define DQN_GCC_WARNING_PUSH
@ -87,11 +92,19 @@
// NOTE: Alloc Macros ==============================================================================
#if !defined(DQN_ALLOC)
#define DQN_ALLOC(size) Dqn_VMem_Reserve(size, Dqn_VMemCommit_Yes, Dqn_VMemPage_ReadWrite)
#if defined(DQN_PLATFORM_EMSCRIPTEN)
#define DQN_ALLOC(size) malloc(size)
#else
#define DQN_ALLOC(size) Dqn_VMem_Reserve(size, Dqn_VMemCommit_Yes, Dqn_VMemPage_ReadWrite)
#endif
#endif
#if !defined(DQN_DEALLOC)
#define DQN_DEALLOC(ptr, size) Dqn_VMem_Release(ptr, size)
#if defined(DQN_PLATFORM_EMSCRIPTEN)
#define DQN_DEALLOC(ptr, size) free(ptr)
#else
#define DQN_DEALLOC(ptr, size) Dqn_VMem_Release(ptr, size)
#endif
#endif
// NOTE: String.h Dependencies =====================================================================
@ -126,6 +139,10 @@
#endif
#endif
#if !defined(DQN_OS_WIN32)
#include <stdlib.h> // exit()
#endif
// NOTE: Math Macros ===============================================================================
#define DQN_PI 3.14159265359f
@ -206,11 +223,11 @@
// NOTE: Assert Macros =============================================================================
#define DQN_HARD_ASSERT(expr) DQN_HARD_ASSERTF(expr, "")
#define DQN_HARD_ASSERTF(expr, fmt, ...) \
if (!(expr)) { \
Dqn_Log_ErrorF("Hard assert triggered " #expr ". " fmt, ##__VA_ARGS__); \
Dqn_StackTrace_Print(128 /*limit*/); \
DQN_DEBUG_BREAK; \
#define DQN_HARD_ASSERTF(expr, fmt, ...) \
if (!(expr)) { \
Dqn_Log_ErrorF("Hard assert triggered [" #expr "]. " fmt, ##__VA_ARGS__); \
Dqn_StackTrace_Print(128 /*limit*/); \
DQN_DEBUG_BREAK; \
}
#if defined(DQN_NO_ASSERT)
@ -218,11 +235,11 @@
#define DQN_ASSERT(...)
#else
#define DQN_ASSERT(expr) DQN_ASSERTF(expr, "")
#define DQN_ASSERTF(expr, fmt, ...) \
if (!(expr)) { \
Dqn_Log_ErrorF("Assert triggered " #expr ". " fmt, ##__VA_ARGS__); \
Dqn_StackTrace_Print(128 /*limit*/); \
DQN_DEBUG_BREAK; \
#define DQN_ASSERTF(expr, fmt, ...) \
if (!(expr)) { \
Dqn_Log_ErrorF("Assert triggered [" #expr "]. " fmt, ##__VA_ARGS__); \
Dqn_StackTrace_Print(128 /*limit*/); \
DQN_DEBUG_BREAK; \
}
#endif
@ -308,6 +325,10 @@ typedef double Dqn_f64;
typedef unsigned int Dqn_uint;
typedef int32_t Dqn_b32;
#define DQN_F32_MAX 3.402823466e+38F
#define DQN_F32_MIN 1.175494351e-38F
#define DQN_F64_MAX 1.7976931348623158e+308
#define DQN_F64_MIN 2.2250738585072014e-308
#define DQN_USIZE_MAX UINTPTR_MAX
#define DQN_ISIZE_MAX INTPTR_MAX
#define DQN_ISIZE_MIN INTPTR_MIN
@ -318,7 +339,7 @@ enum Dqn_ZeroMem
Dqn_ZeroMem_Yes, // Memory should be zero-ed out before giving to the callee
};
struct Dqn_String8
struct Dqn_Str8
{
char *data; // The bytes of the string
Dqn_usize size; // The number of bytes in the string
@ -329,14 +350,27 @@ struct Dqn_String8
char *end () { return data + size; }
};
#if !defined(DQN_NO_SLICE)
template <typename T> struct Dqn_Slice // A pointer and length container of data
{
T *data;
Dqn_usize size;
T *begin() { return data; }
T *end () { return data + size; }
T const *begin() const { return data; }
T const *end () const { return data + size; }
};
#endif
// NOTE: [$CALL] Dqn_CallSite ======================================================================
struct Dqn_CallSite
{
Dqn_String8 file;
Dqn_String8 function;
Dqn_Str8 file;
Dqn_Str8 function;
unsigned int line;
};
#define DQN_CALL_SITE Dqn_CallSite{DQN_STRING8(__FILE__), DQN_STRING8(__func__), __LINE__}
#define DQN_CALL_SITE Dqn_CallSite{DQN_STR8(__FILE__), DQN_STR8(__func__), __LINE__}
// NOTE: [$INTR] Intrinsics ========================================================================
// Platform agnostic functions for CPU level instructions like atomics, barriers
@ -367,9 +401,12 @@ struct Dqn_CallSite
#define Dqn_CompilerWriteBarrierAndCPUWriteFence _WriteBarrier(); _mm_sfence()
#elif defined(DQN_COMPILER_GCC) || defined(DQN_COMPILER_CLANG)
#if defined(__ANDROID__)
#elif defined(DQN_PLATFORM_EMSCRIPTEN)
#include <emmintrin.h>
#else
#include <x86intrin.h>
#endif
#define Dqn_Atomic_AddU32(target, value) __atomic_fetch_add(target, value, __ATOMIC_ACQ_REL)
#define Dqn_Atomic_AddU64(target, value) __atomic_fetch_add(target, value, __ATOMIC_ACQ_REL)
#define Dqn_Atomic_SubU32(target, value) __atomic_fetch_sub(target, value, __ATOMIC_ACQ_REL)
@ -417,14 +454,14 @@ DQN_FORCE_INLINE long Dqn_Atomic_SetValue32(long volatile *target, long value)
#endif
}
#if !defined(DQN_OS_ARM64)
#if !defined(DQN_PLATFORM_ARM64)
struct Dqn_CPUIDRegisters
{
Dqn_uint array[4]; ///< Values from 'CPUID' instruction for each register (EAX, EBX, ECX, EDX)
};
Dqn_CPUIDRegisters Dqn_CPUID(int function_id);
#endif // DQN_OS_ARM64
#endif // DQN_PLATFORM_ARM64
// NOTE: [$TMUT] Dqn_TicketMutex ===================================================================
//
@ -562,40 +599,40 @@ DQN_API Dqn_PrintStyle Dqn_Print_StyleBold ();
// 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_Std (Dqn_PrintStd std_handle, Dqn_Str8 string);
DQN_API void Dqn_Print_StdF (Dqn_PrintStd std_handle, DQN_FMT_ATTRIB char const *fmt, ...);
DQN_API void Dqn_Print_StdFV (Dqn_PrintStd std_handle, DQN_FMT_ATTRIB 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_StdStyle (Dqn_PrintStd std_handle, Dqn_PrintStyle style, Dqn_Str8 string);
DQN_API void Dqn_Print_StdFStyle (Dqn_PrintStd std_handle, Dqn_PrintStyle style, DQN_FMT_ATTRIB char const *fmt, ...);
DQN_API void Dqn_Print_StdFVStyle (Dqn_PrintStd std_handle, Dqn_PrintStyle style, DQN_FMT_ATTRIB 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_StdLn (Dqn_PrintStd std_handle, Dqn_Str8 string);
DQN_API void Dqn_Print_StdLnF (Dqn_PrintStd std_handle, DQN_FMT_ATTRIB char const *fmt, ...);
DQN_API void Dqn_Print_StdLnFV (Dqn_PrintStd std_handle, DQN_FMT_ATTRIB 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);
DQN_API void Dqn_Print_StdLnStyle (Dqn_PrintStd std_handle, Dqn_PrintStyle style, Dqn_Str8 string);
DQN_API void Dqn_Print_StdLnFStyle (Dqn_PrintStd std_handle, Dqn_PrintStyle style, DQN_FMT_ATTRIB char const *fmt, ...);
DQN_API void Dqn_Print_StdLnFVStyle (Dqn_PrintStd std_handle, Dqn_PrintStyle style, DQN_FMT_ATTRIB 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);
Dqn_Str8 Dqn_Print_ESCColourStr8 (Dqn_PrintESCColour colour, uint8_t r, uint8_t g, uint8_t b);
Dqn_Str8 Dqn_Print_ESCColourU32Str8(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_ESCColourFgStr8(r, g, b) Dqn_Print_ESCColourStr8(Dqn_PrintESCColour_Fg, r, g, b)
#define Dqn_Print_ESCColourBgStr8(r, g, b) Dqn_Print_ESCColourStr8(Dqn_PrintESCColour_Bg, r, g, b)
#define Dqn_Print_ESCColourFg(r, g, b) Dqn_Print_ESCColourStr8(Dqn_PrintESCColour_Fg, r, g, b).data
#define Dqn_Print_ESCColourBg(r, g, b) Dqn_Print_ESCColourStr8(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_ESCColourFgU32Str8(value) Dqn_Print_ESCColourU32Str8(Dqn_PrintESCColour_Fg, value)
#define Dqn_Print_ESCColourBgU32Str8(value) Dqn_Print_ESCColourU32Str8(Dqn_PrintESCColour_Bg, value)
#define Dqn_Print_ESCColourFgU32(value) Dqn_Print_ESCColourU32Str8(Dqn_PrintESCColour_Fg, value).data
#define Dqn_Print_ESCColourBgU32(value) Dqn_Print_ESCColourU32Str8(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)
#define Dqn_Print_ESCReset "\x1b[0m"
#define Dqn_Print_ESCBold "\x1b[1m"
#define Dqn_Print_ESCResetStr8 DQN_STR8(Dqn_Print_ESCReset)
#define Dqn_Print_ESCBoldStr8 DQN_STR8(Dqn_Print_ESCBold)
// NOTE: [$LLOG] Dqn_Log ==========================================================================
// NOTE: API
@ -623,7 +660,7 @@ enum Dqn_LogType
#define Dqn_LogTypeColourU32_Warning 0xff'ff'00'ff // Yellow
#define Dqn_LogTypeColourU32_Error 0xff'00'00'ff // Red
typedef void Dqn_LogProc(Dqn_String8 type, int log_type, void *user_data, Dqn_CallSite call_site, char const *fmt, va_list va);
typedef void Dqn_LogProc(Dqn_Str8 type, int log_type, void *user_data, Dqn_CallSite call_site, DQN_FMT_ATTRIB char const *fmt, va_list va);
#define Dqn_Log_DebugF(fmt, ...) Dqn_Log_TypeFCallSite(Dqn_LogType_Debug, DQN_CALL_SITE, fmt, ## __VA_ARGS__)
#define Dqn_Log_InfoF(fmt, ...) Dqn_Log_TypeFCallSite(Dqn_LogType_Info, DQN_CALL_SITE, fmt, ## __VA_ARGS__)
@ -641,8 +678,8 @@ typedef void Dqn_LogProc(Dqn_String8 type, int log_type, void *user_data, Dqn_Ca
#define Dqn_Log_FV(type, fmt, args) Dqn_Log_FVCallSite(type, DQN_CALL_SITE, fmt, args)
#define Dqn_Log_F(type, fmt, ...) Dqn_Log_FCallSite(type, DQN_CALL_SITE, fmt, ## __VA_ARGS__)
DQN_API Dqn_String8 Dqn_Log_MakeString (Dqn_Allocator allocator, bool colour, Dqn_String8 type, int log_type, Dqn_CallSite call_site, char const *fmt, va_list args);
DQN_API void Dqn_Log_TypeFVCallSite(Dqn_LogType type, Dqn_CallSite call_site, DQN_FMT_STRING_ANNOTATE char const *fmt, va_list va);
DQN_API void Dqn_Log_TypeFCallSite (Dqn_LogType type, Dqn_CallSite call_site, DQN_FMT_STRING_ANNOTATE char const *fmt, ...);
DQN_API void Dqn_Log_FVCallSite (Dqn_String8 type, Dqn_CallSite call_site, DQN_FMT_STRING_ANNOTATE char const *fmt, va_list va);
DQN_API void Dqn_Log_FCallSite (Dqn_String8 type, Dqn_CallSite call_site, DQN_FMT_STRING_ANNOTATE char const *fmt, ...);
DQN_API Dqn_Str8 Dqn_Log_MakeStr8 (Dqn_Allocator allocator, bool colour, Dqn_Str8 type, int log_type, Dqn_CallSite call_site, DQN_FMT_ATTRIB char const *fmt, va_list args);
DQN_API void Dqn_Log_TypeFVCallSite(Dqn_LogType type, Dqn_CallSite call_site, DQN_FMT_ATTRIB char const *fmt, va_list va);
DQN_API void Dqn_Log_TypeFCallSite (Dqn_LogType type, Dqn_CallSite call_site, DQN_FMT_ATTRIB char const *fmt, ...);
DQN_API void Dqn_Log_FVCallSite (Dqn_Str8 type, Dqn_CallSite call_site, DQN_FMT_ATTRIB char const *fmt, va_list va);
DQN_API void Dqn_Log_FCallSite (Dqn_Str8 type, Dqn_CallSite call_site, DQN_FMT_ATTRIB char const *fmt, ...);

View File

@ -5,8 +5,32 @@ enum Dqn_ArrayErase
Dqn_ArrayErase_Stable,
};
template <typename T> Dqn_usize Dqn_CArray_EraseRange(T* data, Dqn_usize *size, Dqn_usize begin_index, Dqn_isize count, Dqn_ArrayErase erase);
template <typename T> T * Dqn_CArray_Make (T* data, Dqn_usize *size, Dqn_usize max, Dqn_usize count, Dqn_ZeroMem zero_mem);
struct Dqn_ArrayEraseResult
{
// The next index your for-index should be set to such that you can continue
// to iterate the remainder of the array, e.g:
//
// for (Dqn_usize index = 0; index < array.size; index++) {
// if (erase)
// index = Dqn_FArray_EraseRange(&array, index, -3, Dqn_ArrayErase_Unstable);
// }
Dqn_usize it_index;
Dqn_usize items_erased; // The number of items erased
};
template <typename T>
struct Dqn_ArrayFindResult
{
T *data; // Pointer to the value if a match is found, null pointer otherwise
Dqn_usize index; // Index to the value if a match is found, 0 otherwise
};
template <typename T> Dqn_ArrayEraseResult Dqn_CArray_EraseRange (T *data, Dqn_usize *size, Dqn_usize begin_index, Dqn_isize count, Dqn_ArrayErase erase);
template <typename T> T * Dqn_CArray_MakeArray (T *data, Dqn_usize *size, Dqn_usize max, Dqn_usize count, Dqn_ZeroMem zero_mem);
template <typename T> T * Dqn_CArray_InsertArray(T *data, Dqn_usize *size, Dqn_usize max, Dqn_usize index, T const *items, Dqn_usize count);
template <typename T> T Dqn_CArray_PopFront (T *data, Dqn_usize *size, Dqn_usize count);
template <typename T> T Dqn_CArray_PopBack (T *data, Dqn_usize *size, Dqn_usize count);
template <typename T> Dqn_ArrayFindResult<T> Dqn_CArray_Find (T *data, Dqn_usize size, T const &value);
#if !defined(DQN_NO_VARRAY)
// NOTE: [$VARR] Dqn_VArray ========================================================================
@ -85,18 +109,22 @@ template <typename T> struct Dqn_VArray
};
// NOTE: Setup =====================================================================================
DQN_API template <typename T> Dqn_VArray<T> Dqn_VArray_InitByteSize(Dqn_Arena *arena, Dqn_usize byte_size);
DQN_API template <typename T> Dqn_VArray<T> Dqn_VArray_Init (Dqn_Arena *arena, Dqn_usize max);
DQN_API template <typename T> bool Dqn_VArray_IsValid (Dqn_VArray<T> const *array);
DQN_API template <typename T> void Dqn_VArray_Reserve (Dqn_VArray<T> *array, Dqn_usize count);
DQN_API template <typename T> Dqn_VArray<T> Dqn_VArray_InitByteSize(Dqn_Arena *arena, Dqn_usize byte_size);
DQN_API template <typename T> Dqn_VArray<T> Dqn_VArray_Init (Dqn_Arena *arena, Dqn_usize max);
DQN_API template <typename T> bool Dqn_VArray_IsValid (Dqn_VArray<T> const *array);
DQN_API template <typename T> void Dqn_VArray_Reserve (Dqn_VArray<T> *array, Dqn_usize count);
// NOTE: Insert ====================================================================================
DQN_API template <typename T> T * Dqn_VArray_Make (Dqn_VArray<T> *array, Dqn_usize count, Dqn_ZeroMem zero_mem);
DQN_API template <typename T> T * Dqn_VArray_Add (Dqn_VArray<T> *array, T const *items, Dqn_usize count);
DQN_API template <typename T> T * Dqn_VArray_MakeArray (Dqn_VArray<T> *array, Dqn_usize count, Dqn_ZeroMem zero_mem);
DQN_API template <typename T> T * Dqn_VArray_Make (Dqn_VArray<T> *array, Dqn_ZeroMem zero_mem);
DQN_API template <typename T> T * Dqn_VArray_AddArray (Dqn_VArray<T> *array, T const *items, Dqn_usize count);
DQN_API template <typename T> T * Dqn_VArray_Add (Dqn_VArray<T> *array, T const &item);
DQN_API template <typename T> T Dqn_VArray_PopFront (Dqn_VArray<T> *array, Dqn_usize count);
DQN_API template <typename T> T Dqn_VArray_PopBack (Dqn_VArray<T> *array, Dqn_usize count);
// NOTE: Modify ====================================================================================
DQN_API template <typename T> void Dqn_VArray_EraseRange (Dqn_VArray<T> *array, Dqn_usize begin_index, Dqn_isize count, Dqn_ArrayErase erase);
DQN_API template <typename T> void Dqn_VArray_Clear (Dqn_VArray<T> *array);
DQN_API template <typename T> Dqn_ArrayEraseResult Dqn_VArray_EraseRange (Dqn_VArray<T> *array, Dqn_usize begin_index, Dqn_isize count, Dqn_ArrayErase erase);
DQN_API template <typename T> void Dqn_VArray_Clear (Dqn_VArray<T> *array, Dqn_ZeroMem zero_mem);
#endif // !defined(DQN_NO_VARRAY)
#if !defined(DQN_NO_SARRAY)
@ -114,17 +142,21 @@ template <typename T> struct Dqn_SArray
};
// NOTE: Setup =====================================================================================
DQN_API template <typename T> Dqn_SArray<T> Dqn_SArray_Init (Dqn_Arena *arena, Dqn_usize size, Dqn_ZeroMem zero_mem);
DQN_API template <typename T> bool Dqn_SArray_IsValid (Dqn_SArray<T> const *array);
DQN_API template <typename T> Dqn_SArray<T> Dqn_SArray_Init (Dqn_Arena *arena, Dqn_usize size, Dqn_ZeroMem zero_mem);
DQN_API template <typename T, size_t N> Dqn_SArray<T> Dqn_SArray_InitCArrayCopy (Dqn_Arena *arena, T const (&array)[N]);
DQN_API template <typename T> bool Dqn_SArray_IsValid (Dqn_SArray<T> const *array);
// NOTE: Insert ====================================================================================
DQN_API template <typename T> T * Dqn_SArray_Make (Dqn_SArray<T> *array, Dqn_usize count, Dqn_ZeroMem zero_mem);
DQN_API template <typename T> T * Dqn_SArray_AddArray(Dqn_SArray<T> *array, T const *items, Dqn_usize count);
DQN_API template <typename T> T * Dqn_SArray_Add (Dqn_SArray<T> *array, T const &item);
// NOTE: Modify ====================================================================================
DQN_API template <typename T> void Dqn_SArray_EraseRange(Dqn_SArray<T> *array, Dqn_usize begin_index, Dqn_isize count, Dqn_ArrayErase erase);
DQN_API template <typename T> void Dqn_SArray_Clear (Dqn_SArray<T> *array);
// NOTE: API =======================================================================================
DQN_API template <typename T> T * Dqn_SArray_MakeArray (Dqn_SArray<T> *array, Dqn_usize count, Dqn_ZeroMem zero_mem);
DQN_API template <typename T> T * Dqn_SArray_Make (Dqn_SArray<T> *array, Dqn_ZeroMem zero_mem);
DQN_API template <typename T> T * Dqn_SArray_AddArray (Dqn_SArray<T> *array, T const *items, Dqn_usize count);
DQN_API template <typename T> T * Dqn_SArray_Add (Dqn_SArray<T> *array, T const &item);
DQN_API template <typename T> T * Dqn_SArray_InsertArray(Dqn_SArray<T> *array, Dqn_usize index, T const *items, Dqn_usize count);
DQN_API template <typename T> T * Dqn_SArray_Insert (Dqn_SArray<T> *array, Dqn_usize index, T const &item);
DQN_API template <typename T> T Dqn_SArray_PopFront (Dqn_SArray<T> *array, Dqn_usize count);
DQN_API template <typename T> T Dqn_SArray_PopBack (Dqn_SArray<T> *array, Dqn_usize count);
DQN_API template <typename T> Dqn_ArrayEraseResult Dqn_SArray_EraseRange (Dqn_SArray<T> *array, Dqn_usize begin_index, Dqn_isize count, Dqn_ArrayErase erase);
DQN_API template <typename T> void Dqn_SArray_Clear (Dqn_SArray<T> *array);
#endif // !defined(DQN_NO_SARRAY)
#if !defined(DQN_NO_FARRAY)
@ -141,35 +173,30 @@ template <typename T, Dqn_usize N> struct Dqn_FArray
};
// NOTE: Setup =====================================================================================
DQN_API template <typename T, Dqn_usize N> Dqn_FArray<T, N> Dqn_FArray_Init (T const *array, Dqn_usize count);
DQN_API template <typename T, Dqn_usize N> bool Dqn_FArray_IsValid (Dqn_FArray<T, N> const *array);
DQN_API template <typename T, Dqn_usize N> Dqn_FArray<T, N> Dqn_FArray_Init (T const *array, Dqn_usize count);
DQN_API template <typename T, Dqn_usize N> bool Dqn_FArray_IsValid (Dqn_FArray<T, N> const *array);
DQN_API template <typename T, Dqn_usize N> Dqn_usize Dqn_FArray_Max (Dqn_FArray<T, N> const *) { return N; }
// NOTE: Insert ====================================================================================
DQN_API template <typename T, Dqn_usize N> T * Dqn_FArray_Make (Dqn_FArray<T, N> *array, Dqn_usize count, Dqn_ZeroMem zero_mem);
DQN_API template <typename T, Dqn_usize N> T * Dqn_FArray_Add (Dqn_FArray<T, N> *array, T const *items, Dqn_usize count);
// NOTE: Modify ====================================================================================
DQN_API template <typename T, Dqn_usize N> void Dqn_FArray_EraseRange(Dqn_FArray<T, N> *array, Dqn_usize begin_index, Dqn_isize count, Dqn_ArrayErase erase);
DQN_API template <typename T, Dqn_usize N> void Dqn_FArray_Clear (Dqn_FArray<T, N> *array);
// NOTE: API =======================================================================================
DQN_API template <typename T, Dqn_usize N> T * Dqn_FArray_MakeArray (Dqn_FArray<T, N> *array, Dqn_usize count, Dqn_ZeroMem zero_mem);
DQN_API template <typename T, Dqn_usize N> T * Dqn_FArray_Make (Dqn_FArray<T, N> *array, Dqn_ZeroMem zero_mem);
DQN_API template <typename T, Dqn_usize N> T * Dqn_FArray_AddArray (Dqn_FArray<T, N> *array, T const *items, Dqn_usize count);
DQN_API template <typename T, Dqn_usize N> T * Dqn_FArray_Add (Dqn_FArray<T, N> *array, T const &item);
DQN_API template <typename T, Dqn_usize N> T * Dqn_FArray_InsertArray(Dqn_FArray<T, N> *array, T const &item, Dqn_usize index);
DQN_API template <typename T, Dqn_usize N> T * Dqn_FArray_Insert (Dqn_FArray<T, N> *array, Dqn_usize index, T const &item);
DQN_API template <typename T, Dqn_usize N> T Dqn_FArray_PopFront (Dqn_FArray<T, N> *array, Dqn_usize count);
DQN_API template <typename T, Dqn_usize N> T Dqn_FArray_PopBack (Dqn_FArray<T, N> *array, Dqn_usize count);
DQN_API template <typename T, Dqn_usize N> Dqn_ArrayFindResult<T> Dqn_FArray_Find (Dqn_FArray<T, N> *array, T const &find);
DQN_API template <typename T, Dqn_usize N> Dqn_ArrayEraseResult Dqn_FArray_EraseRange (Dqn_FArray<T, N> *array, Dqn_usize begin_index, Dqn_isize count, Dqn_ArrayErase erase);
DQN_API template <typename T, Dqn_usize N> void Dqn_FArray_Clear (Dqn_FArray<T, N> *array);
#endif // !defined(DQN_NO_FARRAY)
#if !defined(DQN_NO_SLICE)
// NOTE: [$SLIC] Dqn_Slice =========================================================================
// A pointer and length container of data
template <typename T> Dqn_Slice<T> Dqn_Slice_Init (T* const data, Dqn_usize size);
template <typename T, Dqn_usize N> Dqn_Slice<T> Dqn_Slice_InitCArrayCopy(Dqn_Arena *arena, T const *(&array)[N]);
template <typename T> Dqn_Slice<T> Dqn_Slice_Alloc (Dqn_Arena *arena, Dqn_usize size, Dqn_ZeroMem zero_mem);
template <typename T> struct Dqn_Slice
{
T *data;
Dqn_usize size;
T *begin() { return data; }
T *end () { return data + size; }
T const *begin() const { return data; }
T const *end () const { return data + size; }
};
template <typename T> Dqn_Slice<T> Dqn_Slice_Init (T* const data, Dqn_usize size);
template <typename T> Dqn_Slice<T> Dqn_Slice_Alloc(Dqn_Arena *arena, Dqn_usize size, Dqn_ZeroMem zero_mem);
#endif // !defined(DQN_NO_SLICE)
#if !defined(DQN_NO_DSMAP)
@ -241,30 +268,27 @@ template <typename T> Dqn_Slice<T> Dqn_Slice_Alloc(Dqn_Arena *arena, Dqn_usize s
// @proc Dqn_DSMap_HashToSlotIndex
// @desc Calculate the index into the map's `slots` array from the given hash.
// @proc Dqn_DSMap_FindSlot, Dqn_DSMap_Find
// @proc Dqn_DSMap_Find
// @desc Find the slot in the map's `slots` array corresponding to the given
// key and hash. If the map does not contain the key, a null pointer is
// returned.
// key and hash. If the map does not contain the key `found` is set to false
// and `slot` and `value` are null.
//
// `Find` returns the value.
// `FindSlot` returns the map's hash table slot.
// @proc Dqn_DSMap_MakeSlot, Dqn_DSMap_Make, Dqn_DSMap_Set, Dqn_DSMap_SetSlot
// @proc Dqn_DSMap_Make, Dqn_DSMap_Set
// @desc Same as `DSMap_Find*` except if the key does not exist in the table,
// a hash-table slot will be made.
//
// `Make` assigns the key to the table and returns the hash table slot's value.
// `Set` assigns the key-value to the table and returns the hash table slot's value.
// `MakeSlot` assigns the key to the table and returns the hash table slot.
// `SetSlot` assigns the key-value to the table and returns the hash table slot.
// `Make` assigns the key to the table and returns the hash table slot's value.
// `Set` assigns the key-value to the table and returns the hash table slot's value.
//
// If by adding the key-value pair to the table puts the table over 75% load,
// the table will be grown to 2x the current the size before insertion
// completes.
//
// @param found[out] Pass a pointer to a bool. The bool will be set to true
// if the item already existed in the map before, or false if the item was
// just created by this call.
// `found` will be set to true if the item already existed in the map before,
// or false if the item was just created by this call.
// @proc Dqn_DSMap_Resize
// @desc Resize the table and move all elements to the new map.
@ -280,14 +304,14 @@ template <typename T> Dqn_Slice<T> Dqn_Slice_Alloc(Dqn_Arena *arena, Dqn_usize s
// initial size that the table was initialised as.
// @proc Dqn_DSMap_KeyCStringLit, Dqn_DSMap_KeyU64, Dqn_DSMap_KeyBuffer,
// Dqn_DSMap_KeyString8 Dqn_DSMap_KeyString8Copy
// Dqn_DSMap_KeyStr8 Dqn_DSMap_KeyStr8Copy
// @desc Create a hash-table key given
//
// `KeyCStringLit` a cstring literal
// `KeyU64` a u64
// `KeyBuffer` a (ptr+len) slice of bytes
// `KeyString8` a Dqn_String8 string
// `KeyString8Copy` a Dqn_String8 string that is copied first using the allocator
// `KeyStr8` a Dqn_Str8 string
// `KeyStr8Copy` a Dqn_Str8 string that is copied first using the allocator
//
// If the key points to an array of bytes, the lifetime of those bytes *must*
// remain valid throughout the lifetime of the map as the pointers are value
@ -343,33 +367,50 @@ template <typename T> struct Dqn_DSMap
};
// NOTE: Setup =====================================================================================
DQN_API template <typename T> Dqn_DSMap<T> Dqn_DSMap_Init (uint32_t size);
DQN_API template <typename T> void Dqn_DSMap_Deinit (Dqn_DSMap<T> *map);
DQN_API template <typename T> bool Dqn_DSMap_IsValid (Dqn_DSMap<T> const *map);
DQN_API template <typename T> Dqn_DSMap<T> Dqn_DSMap_Init (uint32_t size);
DQN_API template <typename T> void Dqn_DSMap_Deinit (Dqn_DSMap<T> *map);
DQN_API template <typename T> bool Dqn_DSMap_IsValid (Dqn_DSMap<T> const *map);
// NOTE: Hash ======================================================================================
DQN_API template <typename T> uint32_t Dqn_DSMap_Hash (Dqn_DSMap<T> const *map, Dqn_DSMapKey key);
DQN_API template <typename T> uint32_t Dqn_DSMap_HashToSlotIndex(Dqn_DSMap<T> const *map, Dqn_DSMapKey key);
DQN_API template <typename T> uint32_t Dqn_DSMap_Hash (Dqn_DSMap<T> const *map, Dqn_DSMapKey key);
DQN_API template <typename T> uint32_t Dqn_DSMap_HashToSlotIndex(Dqn_DSMap<T> const *map, Dqn_DSMapKey key);
// NOTE: Insert ====================================================================================
DQN_API template <typename T> Dqn_DSMapSlot<T> *Dqn_DSMap_FindSlot (Dqn_DSMap<T> const *map, Dqn_DSMapKey key);
DQN_API template <typename T> Dqn_DSMapSlot<T> *Dqn_DSMap_MakeSlot (Dqn_DSMap<T> *map, Dqn_DSMapKey key, bool *found);
DQN_API template <typename T> Dqn_DSMapSlot<T> *Dqn_DSMap_SetSlot (Dqn_DSMap<T> *map, Dqn_DSMapKey key, T const &value, bool *found);
DQN_API template <typename T> T * Dqn_DSMap_Find (Dqn_DSMap<T> const *map, Dqn_DSMapKey key);
DQN_API template <typename T> T * Dqn_DSMap_Make (Dqn_DSMap<T> *map, Dqn_DSMapKey key, bool *found);
DQN_API template <typename T> T * Dqn_DSMap_Set (Dqn_DSMap<T> *map, Dqn_DSMapKey key, T const &value, bool *found);
DQN_API template <typename T> bool Dqn_DSMap_Resize (Dqn_DSMap<T> *map, uint32_t size);
DQN_API template <typename T> bool Dqn_DSMap_Erase (Dqn_DSMap<T> *map, Dqn_DSMapKey key);
template <typename T>
struct Dqn_DSMapResult
{
bool found;
Dqn_DSMapSlot<T> *slot;
T *value;
};
DQN_API template <typename T> Dqn_DSMapResult<T> Dqn_DSMap_Find (Dqn_DSMap<T> const *map, Dqn_DSMapKey key);
DQN_API template <typename T> Dqn_DSMapResult<T> Dqn_DSMap_Make (Dqn_DSMap<T> *map, Dqn_DSMapKey key);
DQN_API template <typename T> Dqn_DSMapResult<T> Dqn_DSMap_Set (Dqn_DSMap<T> *map, Dqn_DSMapKey key, T const &value);
DQN_API template <typename T> Dqn_DSMapResult<T> Dqn_DSMap_FindKeyU64 (Dqn_DSMap<T> const *map, uint64_t key);
DQN_API template <typename T> Dqn_DSMapResult<T> Dqn_DSMap_MakeKeyU64 (Dqn_DSMap<T> *map, uint64_t key);
DQN_API template <typename T> Dqn_DSMapResult<T> Dqn_DSMap_SetKeyU64 (Dqn_DSMap<T> *map, uint64_t key, T const &value);
DQN_API template <typename T> Dqn_DSMapResult<T> Dqn_DSMap_FindKeyStr8 (Dqn_DSMap<T> const *map, Dqn_Str8 key);
DQN_API template <typename T> Dqn_DSMapResult<T> Dqn_DSMap_MakeKeyStr8 (Dqn_DSMap<T> *map, Dqn_Str8 key);
DQN_API template <typename T> Dqn_DSMapResult<T> Dqn_DSMap_SetKeyStr8 (Dqn_DSMap<T> *map, Dqn_Str8 key, T const &value);
DQN_API template <typename T> Dqn_DSMapResult<T> Dqn_DSMap_MakeKeyStr8Copy(Dqn_DSMap<T> *map, Dqn_Allocator allocator, Dqn_Str8 key);
DQN_API template <typename T> Dqn_DSMapResult<T> Dqn_DSMap_SetKeyStr8Copy (Dqn_DSMap<T> *map, Dqn_Allocator allocator, Dqn_Str8 key, T const &value);
DQN_API template <typename T> bool Dqn_DSMap_Resize (Dqn_DSMap<T> *map, uint32_t size);
DQN_API template <typename T> bool Dqn_DSMap_Erase (Dqn_DSMap<T> *map, Dqn_DSMapKey key);
// NOTE: Table Keys ================================================================================
DQN_API template <typename T> Dqn_DSMapKey Dqn_DSMap_KeyBuffer (Dqn_DSMap<T> const *map, void const *data, uint32_t size);
DQN_API template <typename T> Dqn_DSMapKey Dqn_DSMap_KeyU64 (Dqn_DSMap<T> const *map, uint64_t u64);
DQN_API template <typename T> Dqn_DSMapKey Dqn_DSMap_KeyString8 (Dqn_DSMap<T> const *map, Dqn_String8 string);
DQN_API template <typename T> Dqn_DSMapKey Dqn_DSMap_KeyString8Copy (Dqn_DSMap<T> const *map, Dqn_Allocator allocator, Dqn_String8 string);
#define Dqn_DSMap_KeyCStringLit(map, string) Dqn_DSMap_KeyBuffer(map, string, sizeof((string))/sizeof((string)[0]) - 1)
DQN_API Dqn_DSMapKey Dqn_DSMap_KeyU64NoHash (uint64_t u64);
DQN_API bool Dqn_DSMap_KeyEquals (Dqn_DSMapKey lhs, Dqn_DSMapKey rhs);
DQN_API bool operator== (Dqn_DSMapKey lhs, Dqn_DSMapKey rhs);
DQN_API template <typename T> Dqn_DSMapKey Dqn_DSMap_KeyBuffer (Dqn_DSMap<T> const *map, void const *data, uint32_t size);
DQN_API template <typename T> Dqn_DSMapKey Dqn_DSMap_KeyU64 (Dqn_DSMap<T> const *map, uint64_t u64);
DQN_API template <typename T> Dqn_DSMapKey Dqn_DSMap_KeyStr8 (Dqn_DSMap<T> const *map, Dqn_Str8 string);
DQN_API template <typename T> Dqn_DSMapKey Dqn_DSMap_KeyStr8Copy (Dqn_DSMap<T> const *map, Dqn_Allocator allocator, Dqn_Str8 string);
#define Dqn_DSMap_KeyCStr8(map, string) Dqn_DSMap_KeyBuffer(map, string, sizeof((string))/sizeof((string)[0]) - 1)
DQN_API Dqn_DSMapKey Dqn_DSMap_KeyU64NoHash (uint64_t u64);
DQN_API bool Dqn_DSMap_KeyEquals (Dqn_DSMapKey lhs, Dqn_DSMapKey rhs);
DQN_API bool operator== (Dqn_DSMapKey lhs, Dqn_DSMapKey rhs);
#endif // !defined(DQN_NO_DSMAP)
#if !defined(DQN_NO_LIST)
@ -408,6 +449,7 @@ template <typename T> struct Dqn_ListIterator
Dqn_b32 init; // True if Dqn_List_Iterate has been called at-least once on this iterator
Dqn_ListChunk<T> *chunk; // The chunk that the iterator is reading from
Dqn_usize chunk_data_index; // The index in the chunk the iterator is referencing
Dqn_usize index; // The index of the item in the list as if it was flat array
T *data; // Pointer to the data the iterator is referencing. Nullptr if invalid.
};
@ -421,18 +463,21 @@ template <typename T> struct Dqn_List
};
// NOTE: API =======================================================================================
template <typename T> Dqn_List<T> Dqn_List_Init (Dqn_Arena *arena, Dqn_usize chunk_size);
template <typename T> T * Dqn_List_At (Dqn_List<T> *list, Dqn_usize index, Dqn_ListChunk<T> *at_chunk);
template <typename T> bool Dqn_List_Iterate(Dqn_List<T> *list, Dqn_ListIterator<T> *it, Dqn_usize start_index);
template <typename T> Dqn_List<T> Dqn_List_Init (Dqn_Arena *arena, Dqn_usize chunk_size);
template <typename T, size_t N> Dqn_List<T> Dqn_List_InitCArrayCopy (Dqn_Arena *arena, Dqn_usize chunk_size, T const (&array)[N]);
template <typename T> T * Dqn_List_At (Dqn_List<T> *list, Dqn_usize index, Dqn_ListChunk<T> *at_chunk);
template <typename T> bool Dqn_List_Iterate (Dqn_List<T> *list, Dqn_ListIterator<T> *it, Dqn_usize start_index);
template <typename T> T * Dqn_List_Make (Dqn_List<T> *list, Dqn_usize count);
template <typename T> T * Dqn_List_Add (Dqn_List<T> *list, T const &value);
template <typename T> T * Dqn_List_Make (Dqn_List<T> *list, Dqn_usize count);
template <typename T> T * Dqn_List_Add (Dqn_List<T> *list, T const &value);
template <typename T> void Dqn_List_AddList (Dqn_List<T> *list, Dqn_List<T> other);
template <typename T> Dqn_Slice<T> Dqn_List_ToSliceCopy(Dqn_List<T> const *list, Dqn_Arena* arena);
#endif // !defined(DQN_NO_LIST)
// NOTE: [$CARR] Dqn_CArray ========================================================================
template <typename T> Dqn_usize Dqn_CArray_EraseRange(T* data, Dqn_usize *size, Dqn_usize begin_index, Dqn_isize count, Dqn_ArrayErase erase)
template <typename T> Dqn_ArrayEraseResult Dqn_CArray_EraseRange(T* data, Dqn_usize *size, Dqn_usize begin_index, Dqn_isize count, Dqn_ArrayErase erase)
{
Dqn_usize result = 0;
Dqn_ArrayEraseResult result = {};
if (!data || !size || *size == 0 || count == 0)
return result;
@ -476,16 +521,17 @@ template <typename T> Dqn_usize Dqn_CArray_EraseRange(T* data, Dqn_usize *size,
*size -= erase_count;
}
result = erase_count;
result.items_erased = erase_count;
result.it_index = begin_index;
return result;
}
template <typename T> T *Dqn_CArray_Make(T* data, Dqn_usize *size, Dqn_usize max, Dqn_usize count, Dqn_ZeroMem zero_mem)
template <typename T> T *Dqn_CArray_MakeArray(T* data, Dqn_usize *size, Dqn_usize max, Dqn_usize count, Dqn_ZeroMem zero_mem)
{
if (!data || !size || count == 0)
return nullptr;
if (!DQN_CHECKF((*size + count) < max, "Array is out of memory"))
if (!DQN_CHECKF((*size + count) <= max, "Array is out of memory"))
return nullptr;
// TODO: Use placement new? Why doesn't this work?
@ -496,6 +542,69 @@ template <typename T> T *Dqn_CArray_Make(T* data, Dqn_usize *size, Dqn_usize max
return result;
}
DQN_API template <typename T> T *Dqn_CArray_InsertArray(T *data, Dqn_usize *size, Dqn_usize max, Dqn_usize index, T const *items, Dqn_usize count)
{
T *result = nullptr;
if (!data || !size || !items || count <= 0 || ((*size + count) > max))
return result;
Dqn_usize clamped_index = *size ? DQN_MIN(index, *size) : 0;
if (clamped_index != *size) {
char const *src = DQN_CAST(char *)(data + clamped_index);
char const *dest = DQN_CAST(char *)(data + (clamped_index + count));
char const *end = DQN_CAST(char *)(data + (*size));
Dqn_usize bytes_to_move = end - src;
DQN_MEMMOVE(DQN_CAST(void *)dest, src, bytes_to_move);
}
result = data + clamped_index;
DQN_MEMCPY(result, items, sizeof(T) * count);
*size += count;
return result;
}
template <typename T> T Dqn_CArray_PopFront(T* data, Dqn_usize *size, Dqn_usize count)
{
T result = {};
if (!data || !size || *size <= 0)
return result;
result = data[0];
Dqn_usize pop_count = DQN_MIN(count, *size);
DQN_MEMMOVE(data, data + pop_count, (*size - pop_count) * sizeof(T));
*size -= pop_count;
return result;
}
template <typename T> T Dqn_CArray_PopBack(T* data, Dqn_usize *size, Dqn_usize count)
{
T result = {};
if (!data || !size || *size <= 0)
return result;
Dqn_usize pop_count = DQN_MIN(count, *size);
result = data[(*size - 1)];
*size -= pop_count;
return result;
}
template <typename T> Dqn_ArrayFindResult<T> Dqn_CArray_Find(T *data, Dqn_usize size, T const &value)
{
Dqn_ArrayFindResult<T> result = {};
if (!data || size <= 0)
return result;
for (Dqn_usize index = 0; !result.data && index < size; index++) {
T *item = data + index;
if (*item == value) {
result.data = item;
result.index = index;
}
}
return result;
}
#if !defined(DQN_NO_VARRAY)
// NOTE: [$VARR] Dqn_VArray ========================================================================
DQN_API template <typename T> Dqn_VArray<T> Dqn_VArray_InitByteSize(Dqn_Arena *arena, Dqn_usize byte_size)
@ -520,7 +629,7 @@ DQN_API template <typename T> bool Dqn_VArray_IsValid(Dqn_VArray<T> const *array
return result;
}
DQN_API template <typename T> T *Dqn_VArray_Make(Dqn_VArray<T> *array, Dqn_usize count, Dqn_ZeroMem zero_mem)
DQN_API template <typename T> T *Dqn_VArray_MakeArray(Dqn_VArray<T> *array, Dqn_usize count, Dqn_ZeroMem zero_mem)
{
if (!Dqn_VArray_IsValid(array))
return nullptr;
@ -535,26 +644,72 @@ DQN_API template <typename T> T *Dqn_VArray_Make(Dqn_VArray<T> *array, Dqn_usize
return result;
}
DQN_API template <typename T> T *Dqn_VArray_Add(Dqn_VArray<T> *array, T const *items, Dqn_usize count)
DQN_API template <typename T> T *Dqn_VArray_Make(Dqn_VArray<T> *array, Dqn_ZeroMem zero_mem)
{
T *result = Dqn_VArray_Make(array, count, Dqn_ZeroMem_No);
T *result = Dqn_VArray_MakeArray(array, 1, zero_mem);
return result;
}
DQN_API template <typename T> T *Dqn_VArray_AddArray(Dqn_VArray<T> *array, T const *items, Dqn_usize count)
{
T *result = Dqn_VArray_MakeArray(array, count, Dqn_ZeroMem_No);
if (result)
DQN_MEMCPY(result, items, count * sizeof(T));
return result;
}
DQN_API template <typename T> void Dqn_VArray_EraseRange(Dqn_VArray<T> *array, Dqn_usize begin_index, Dqn_isize count, Dqn_ArrayErase erase)
DQN_API template <typename T> T *Dqn_VArray_Add(Dqn_VArray<T> *array, T const &item)
{
if (!Dqn_VArray_IsValid(array))
return;
Dqn_usize erase_count = Dqn_CArray_EraseRange<T>(array->data, &array->size, begin_index, count, erase);
Dqn_MemBlock_Pop(array->block, erase_count * sizeof(T));
T *result = Dqn_VArray_AddArray(array, &item, 1);
return result;
}
DQN_API template <typename T> void Dqn_VArray_Clear(Dqn_VArray<T> *array)
DQN_API template <typename T, Dqn_usize N> T *Dqn_VArray_InsertArray(Dqn_VArray<T> *array, Dqn_usize index, T const *items, Dqn_usize count)
{
if (array)
T *result = nullptr;
if (!Dqn_VArray_IsValid(array))
return result;
Dqn_VArray_Reserve(array, array->size + count);
result = Dqn_CArray_InsertArray(array->data, &array->size, array->max, index, items, count);
return result;
}
DQN_API template <typename T, Dqn_usize N> T *Dqn_VArray_Insert(Dqn_VArray<T> *array, Dqn_usize index, T const &item)
{
T *result = Dqn_VArray_InsertArray(array, index, &item, 1);
return result;
}
DQN_API template <typename T> T *Dqn_VArray_PopFront(Dqn_VArray<T> *array, Dqn_usize count)
{
T *result = Dqn_CArray_PopFront(array->data, &array->size, count);
return result;
}
DQN_API template <typename T> T *Dqn_VArray_PopBack(Dqn_VArray<T> *array, Dqn_usize count)
{
T *result = Dqn_CArray_PopBack(array->data, &array->size, count);
return result;
}
DQN_API template <typename T> Dqn_ArrayEraseResult Dqn_VArray_EraseRange(Dqn_VArray<T> *array, Dqn_usize begin_index, Dqn_isize count, Dqn_ArrayErase erase)
{
Dqn_ArrayEraseResult result = {};
if (!Dqn_VArray_IsValid(array))
return result;
result = Dqn_CArray_EraseRange<T>(array->data, &array->size, begin_index, count, erase);
Dqn_MemBlock_Pop(array->block, result.items_erased * sizeof(T));
return result;
}
DQN_API template <typename T> void Dqn_VArray_Clear(Dqn_VArray<T> *array, Dqn_ZeroMem zero_mem)
{
if (array) {
if (zero_mem == Dqn_ZeroMem_Yes)
DQN_MEMSET(array->data, 0, array->size * sizeof(T));
Dqn_MemBlock_PopTo(array->block, 0);
array->size = 0;
}
}
DQN_API template <typename T> void Dqn_VArray_Reserve(Dqn_VArray<T> *array, Dqn_usize count)
@ -571,25 +726,45 @@ DQN_API template <typename T> void Dqn_VArray_Reserve(Dqn_VArray<T> *array, Dqn_
DQN_API template <typename T> Dqn_SArray<T> Dqn_SArray_Init(Dqn_Arena *arena, Dqn_usize size, Dqn_ZeroMem zero_mem)
{
Dqn_SArray<T> result = {};
if (!arena || !count)
if (!arena || !size)
return result;
result.data = Dqn_Arena_NewArray(arena, T, size, zero_mem);
if (result.data)
result.max = size;
return result;
}
template <typename T, size_t N> Dqn_SArray<T> Dqn_SArray_InitCArrayCopy(Dqn_Arena *arena, T const (&array)[N])
{
Dqn_SArray<T> result = {};
if (!arena || !N)
return result;
result.data = Dqn_Arena_NewArray(arena, T, N, Dqn_ZeroMem_No);
if (result.data) {
DQN_MEMCOPY(result.data, array, sizeof(T) * N);
result.size = size;
result.max = size;
}
return result;
}
DQN_API template <typename T> bool Dqn_SArray_IsValid(Dqn_SArray<T> const *array)
{
bool result = array && array->data && array->size <= array->max;
return result;
}
DQN_API template <typename T> T *Dqn_SArray_Make(Dqn_SArray<T> *array, Dqn_usize count, Dqn_ZeroMem zero_mem)
DQN_API template <typename T> T *Dqn_SArray_MakeArray(Dqn_SArray<T> *array, Dqn_usize count, Dqn_ZeroMem zero_mem)
{
if (!Dqn_SArray_IsValid(array))
return nullptr;
T *result = Dqn_CArray_Make(array->data, &array->size, array->max, count, zero_mem);
T *result = Dqn_CArray_MakeArray(array->data, &array->size, array->max, count, zero_mem);
return result;
}
DQN_API template <typename T> T *Dqn_SArray_Make(Dqn_SArray<T> *array, Dqn_ZeroMem zero_mem)
{
T *result = Dqn_SArray_MakeArray(array, 1, zero_mem);
return result;
}
@ -606,11 +781,38 @@ DQN_API template <typename T> T *Dqn_SArray_Add(Dqn_SArray<T> *array, T const &i
return result;
}
DQN_API template <typename T> void Dqn_SArray_EraseRange(Dqn_SArray<T> *array, Dqn_usize begin_index, Dqn_isize count, Dqn_ArrayErase erase)
DQN_API template <typename T, Dqn_usize N> T *Dqn_SArray_InsertArray(Dqn_SArray<T> *array, Dqn_usize index, T const *items, Dqn_usize count)
{
if (!Dqn_SArray_IsValid(array))
return result;
T *result = Dqn_CArray_InsertArray(array->data, &array->size, array->max, index, items, count);
return result;
}
DQN_API template <typename T, Dqn_usize N> T *Dqn_SArray_Insert(Dqn_SArray<T> *array, Dqn_usize index, T const &item)
{
T *result = Dqn_SArray_InsertArray(array, index, &item, 1);
return result;
}
DQN_API template <typename T> T Dqn_SArray_PopFront(Dqn_SArray<T> *array, Dqn_usize count)
{
T result = Dqn_CArray_PopFront(array->data, &array->size, count);
return result;
}
DQN_API template <typename T> T Dqn_SArray_PopBack(Dqn_SArray<T> *array, Dqn_usize count)
{
T result = Dqn_CArray_PopBack(array->data, &array->size, count);
return result;
}
DQN_API template <typename T> Dqn_ArrayEraseResult Dqn_SArray_EraseRange(Dqn_SArray<T> *array, Dqn_usize begin_index, Dqn_isize count, Dqn_ArrayErase erase)
{
if (!Dqn_SArray_IsValid(array) || array->size == 0 || count == 0)
return;
Dqn_CArray_EraseRange(array->data, &array->size, being_index, count, erase);
Dqn_ArrayEraseResult result = Dqn_CArray_EraseRange(array->data, &array->size, being_index, count, erase);
return result;
}
DQN_API template <typename T> void Dqn_SArray_Clear(Dqn_SArray<T> *array)
@ -625,7 +827,7 @@ DQN_API template <typename T> void Dqn_SArray_Clear(Dqn_SArray<T> *array)
DQN_API template <typename T, Dqn_usize N> Dqn_FArray<T, N> Dqn_FArray_Init(T const *array, Dqn_usize count)
{
Dqn_FArray<T, N> result = {};
bool added = Dqn_FArray_Add(&result, array, count);
bool added = Dqn_FArray_AddArray(&result, array, count);
DQN_ASSERT(added);
return result;
}
@ -635,27 +837,74 @@ DQN_API template <typename T, Dqn_usize N> bool Dqn_FArray_IsValid(Dqn_FArray<T,
return result;
}
DQN_API template <typename T, Dqn_usize N> T *Dqn_FArray_Make(Dqn_FArray<T, N> *array, Dqn_usize count, Dqn_ZeroMem zero_mem)
DQN_API template <typename T, Dqn_usize N> T *Dqn_FArray_MakeArray(Dqn_FArray<T, N> *array, Dqn_usize count, Dqn_ZeroMem zero_mem)
{
if (!Dqn_FArray_IsValid(array))
return nullptr;
T *result = Dqn_CArray_Make(array->data, &array->size, N, count, zero_mem);
T *result = Dqn_CArray_MakeArray(array->data, &array->size, N, count, zero_mem);
return result;
}
DQN_API template <typename T, Dqn_usize N> T *Dqn_FArray_Add(Dqn_FArray<T, N> *array, T const *items, Dqn_usize count)
DQN_API template <typename T, Dqn_usize N> T *Dqn_FArray_Make(Dqn_FArray<T, N> *array, Dqn_ZeroMem zero_mem)
{
T *result = Dqn_FArray_Make(array, count, Dqn_ZeroMem_No);
T *result = Dqn_FArray_MakeArray(array, 1, zero_mem);
return result;
}
DQN_API template <typename T, Dqn_usize N> T *Dqn_FArray_AddArray(Dqn_FArray<T, N> *array, T const *items, Dqn_usize count)
{
T *result = Dqn_FArray_MakeArray(array, count, Dqn_ZeroMem_No);
if (result)
DQN_MEMCPY(result, items, count * sizeof(T));
return result;
}
DQN_API template <typename T, Dqn_usize N> void Dqn_FArray_EraseRange(Dqn_FArray<T, N> *array, Dqn_usize begin_index, Dqn_isize count, Dqn_ArrayErase erase)
DQN_API template <typename T, Dqn_usize N> T *Dqn_FArray_Add(Dqn_FArray<T, N> *array, T const &item)
{
T *result = Dqn_FArray_AddArray(array, &item, 1);
return result;
}
DQN_API template <typename T, Dqn_usize N> T *Dqn_FArray_InsertArray(Dqn_FArray<T, N> *array, Dqn_usize index, T const *items, Dqn_usize count)
{
T *result = nullptr;
if (!Dqn_FArray_IsValid(array))
return result;
result = Dqn_CArray_InsertArray(array->data, &array->size, N, index, items, count);
return result;
}
DQN_API template <typename T, Dqn_usize N> T *Dqn_FArray_Insert(Dqn_FArray<T, N> *array, Dqn_usize index, T const &item)
{
T *result = Dqn_FArray_InsertArray(array, index, &item, 1);
return result;
}
DQN_API template <typename T, Dqn_usize N> T Dqn_FArray_PopFront(Dqn_FArray<T, N> *array, Dqn_usize count)
{
T result = Dqn_CArray_PopFront(array->data, &array->size, count);
return result;
}
DQN_API template <typename T, Dqn_usize N> T Dqn_FArray_PopBack(Dqn_FArray<T, N> *array, Dqn_usize count)
{
T result = Dqn_CArray_PopBack(array->data, &array->size, count);
return result;
}
DQN_API template <typename T, Dqn_usize N> Dqn_ArrayFindResult<T> Dqn_FArray_Find(Dqn_FArray<T, N> *array, T const &find)
{
Dqn_ArrayFindResult<T> result = Dqn_CArray_Find<T>(array->data, array->size, find);
return result;
}
DQN_API template <typename T, Dqn_usize N> Dqn_ArrayEraseResult Dqn_FArray_EraseRange(Dqn_FArray<T, N> *array, Dqn_usize begin_index, Dqn_isize count, Dqn_ArrayErase erase)
{
Dqn_ArrayEraseResult result = {};
if (!Dqn_FArray_IsValid(array) || array->size == 0 || count == 0)
return;
Dqn_CArray_EraseRange(array->data, &array->size, begin_index, count, erase);
return result;
result = Dqn_CArray_EraseRange(array->data, &array->size, begin_index, count, erase);
return result;
}
DQN_API template <typename T, Dqn_usize N> void Dqn_FArray_Clear(Dqn_FArray<T, N> *array)
@ -676,6 +925,15 @@ template <typename T> Dqn_Slice<T> Dqn_Slice_Init(T* const data, Dqn_usize size)
return result;
}
template <typename T, Dqn_usize N>
Dqn_Slice<T> Dqn_Slice_InitCArrayCopy(Dqn_Arena *arena, T const (&array)[N])
{
Dqn_Slice<T> result = Dqn_Slice_Alloc<T>(arena, N, Dqn_ZeroMem_No);
if (result.data)
DQN_MEMCPY(result.data, array, sizeof(T) * N);
return result;
}
template <typename T> Dqn_Slice<T> Dqn_Slice_Alloc(Dqn_Arena *arena, Dqn_usize size, Dqn_ZeroMem zero_mem)
{
Dqn_Slice<T> result = {};
@ -686,6 +944,7 @@ template <typename T> Dqn_Slice<T> Dqn_Slice_Alloc(Dqn_Arena *arena, Dqn_usize s
result.size = size;
return result;
}
#endif // !defined(DQN_NO_SLICE)
#if !defined(DQN_NO_DSMAP)
@ -830,83 +1089,125 @@ uint32_t Dqn_DSMap_HashToSlotIndex(Dqn_DSMap<T> const *map, Dqn_DSMapKey key)
}
template <typename T>
Dqn_DSMapSlot<T> *Dqn_DSMap_FindSlot(Dqn_DSMap<T> const *map, Dqn_DSMapKey key)
Dqn_DSMapResult<T> Dqn_DSMap_Find(Dqn_DSMap<T> const *map, Dqn_DSMapKey key)
{
Dqn_DSMapSlot<T> const *result = nullptr;
Dqn_DSMapResult<T> result = {};
if (Dqn_DSMap_IsValid(map)) {
uint32_t index = Dqn_DSMap_HashToSlotIndex(map, key);
if (map->hash_to_slot[index] != DQN_DS_MAP_SENTINEL_SLOT)
result = map->slots + map->hash_to_slot[index];
}
return DQN_CAST(Dqn_DSMapSlot<T> *)result;
}
template <typename T>
Dqn_DSMapSlot<T> *Dqn_DSMap_MakeSlot(Dqn_DSMap<T> *map, Dqn_DSMapKey key, bool *found)
{
Dqn_DSMapSlot<T> *result = nullptr;
if (Dqn_DSMap_IsValid(map)) {
uint32_t index = Dqn_DSMap_HashToSlotIndex(map, key);
if (map->hash_to_slot[index] == DQN_DS_MAP_SENTINEL_SLOT) {
// NOTE: Create the slot
map->hash_to_slot[index] = map->occupied++;
// NOTE: Check if resize is required
bool map_is_75pct_full = (map->occupied * 4) > (map->size * 3);
if (map_is_75pct_full) {
if (!Dqn_DSMap_Resize(map, map->size * 2))
return result;
result = Dqn_DSMap_MakeSlot(map, key, nullptr /*found*/);
} else {
result = map->slots + map->hash_to_slot[index];
}
// NOTE: Update the slot
result->key = key;
if (found)
*found = false;
} else {
result = map->slots + map->hash_to_slot[index];
if (found)
*found = true;
if (map->hash_to_slot[index] != DQN_DS_MAP_SENTINEL_SLOT) {
result.slot = map->slots + map->hash_to_slot[index];
result.value = &result.slot->value;
result.found = true;
}
}
return result;
}
template <typename T>
Dqn_DSMapSlot<T> *Dqn_DSMap_SetSlot(Dqn_DSMap<T> *map, Dqn_DSMapKey key, T const &value, bool *found)
Dqn_DSMapResult<T> Dqn_DSMap_Make(Dqn_DSMap<T> *map, Dqn_DSMapKey key)
{
Dqn_DSMapSlot<T> *result = nullptr;
Dqn_DSMapResult<T> result = {};
if (!Dqn_DSMap_IsValid(map))
return result;
result = Dqn_DSMap_MakeSlot(map, key, found);
result->value = value;
uint32_t index = Dqn_DSMap_HashToSlotIndex(map, key);
if (map->hash_to_slot[index] == DQN_DS_MAP_SENTINEL_SLOT) {
// NOTE: Create the slot
map->hash_to_slot[index] = map->occupied++;
// NOTE: Check if resize is required
bool map_is_75pct_full = (map->occupied * 4) > (map->size * 3);
if (map_is_75pct_full) {
if (!Dqn_DSMap_Resize(map, map->size * 2))
return result;
result = Dqn_DSMap_Make(map, key);
} else {
result.slot = map->slots + map->hash_to_slot[index];
result.slot->key = key; // NOTE: Assign key to new slot
}
} else {
result.slot = map->slots + map->hash_to_slot[index];
result.found = true;
}
result.value = &result.slot->value;
return result;
}
template <typename T>
T *Dqn_DSMap_Find(Dqn_DSMap<T> const *map, Dqn_DSMapKey key)
Dqn_DSMapResult<T> Dqn_DSMap_Set(Dqn_DSMap<T> *map, Dqn_DSMapKey key, T const &value)
{
Dqn_DSMapSlot<T> const *slot = Dqn_DSMap_FindSlot(map, key);
T const *result = slot ? &slot->value : nullptr;
return DQN_CAST(T *)result;
}
Dqn_DSMapResult<T> result = {};
if (!Dqn_DSMap_IsValid(map))
return result;
template <typename T>
T *Dqn_DSMap_Make(Dqn_DSMap<T> *map, Dqn_DSMapKey key, bool *found)
{
Dqn_DSMapSlot<T> *slot = Dqn_DSMap_MakeSlot(map, key, found);
T *result = &slot->value;
result = Dqn_DSMap_Make(map, key);
result.slot->value = value;
return result;
}
template <typename T>
T *Dqn_DSMap_Set(Dqn_DSMap<T> *map, Dqn_DSMapKey key, T const &value, bool *found)
Dqn_DSMapResult<T> Dqn_DSMap_FindKeyU64(Dqn_DSMap<T> const *map, uint64_t key)
{
Dqn_DSMapSlot<T> *result = Dqn_DSMap_SetSlot(map, key, value, found);
return &result->value;
Dqn_DSMapKey map_key = Dqn_DSMap_KeyU64(map, key);
Dqn_DSMapResult<T> result = Dqn_DSMap_Find(map, map_key);
return result;
}
template <typename T>
Dqn_DSMapResult<T> Dqn_DSMap_MakeKeyU64(Dqn_DSMap<T> *map, uint64_t key)
{
Dqn_DSMapKey map_key = Dqn_DSMap_KeyU64(map, key);
Dqn_DSMapResult<T> result = Dqn_DSMap_Make(map, map_key);
return result;
}
template <typename T>
Dqn_DSMapResult<T> Dqn_DSMap_SetKeyU64(Dqn_DSMap<T> *map, uint64_t key, T const &value)
{
Dqn_DSMapKey map_key = Dqn_DSMap_KeyU64(map, key);
Dqn_DSMapResult<T> result = Dqn_DSMap_Set(map, map_key, value);
return result;
}
template <typename T>
Dqn_DSMapResult<T> Dqn_DSMap_FindKeyStr8(Dqn_DSMap<T> const *map, Dqn_Str8 key)
{
Dqn_DSMapKey map_key = Dqn_DSMap_KeyStr8(map, key);
Dqn_DSMapResult<T> result = Dqn_DSMap_Find(map, map_key);
return result;
}
template <typename T>
Dqn_DSMapResult<T> Dqn_DSMap_MakeKeyStr8(Dqn_DSMap<T> *map, Dqn_Str8 key)
{
Dqn_DSMapKey map_key = Dqn_DSMap_KeyStr8(map, key);
Dqn_DSMapResult<T> result = Dqn_DSMap_Make(map, map_key);
return result;
}
template <typename T>
Dqn_DSMapResult<T> Dqn_DSMap_SetKeyStr8(Dqn_DSMap<T> *map, Dqn_Str8 key, T const &value)
{
Dqn_DSMapKey map_key = Dqn_DSMap_KeyStr8(map, key);
Dqn_DSMapResult<T> result = Dqn_DSMap_Set(map, map_key);
return result;
}
template <typename T>
Dqn_DSMapResult<T> Dqn_DSMap_MakeKeyStr8Copy(Dqn_DSMap<T> *map, Dqn_Allocator allocator, Dqn_Str8 key)
{
Dqn_DSMapKey map_key = Dqn_DSMap_KeyStr8Copy(map, allocator, key);
Dqn_DSMapResult<T> result = Dqn_DSMap_Make(map, map_key);
return result;
}
template <typename T>
Dqn_DSMapResult<T> Dqn_DSMap_SetKeyStr8Copy(Dqn_DSMap<T> *map, Dqn_Allocator allocator, Dqn_Str8 key, T const &value)
{
Dqn_DSMapKey map_key = Dqn_DSMap_KeyStr8Copy(map, allocator, key);
Dqn_DSMapResult<T> result = Dqn_DSMap_Set(map, map_key);
return result;
}
template <typename T>
@ -923,7 +1224,7 @@ bool Dqn_DSMap_Resize(Dqn_DSMap<T> *map, uint32_t size)
for (uint32_t old_index = 1 /*Sentinel*/; old_index < map->occupied; old_index++) {
Dqn_DSMapSlot<T> *old_slot = map->slots + old_index;
if (old_slot->key.type != Dqn_DSMapKeyType_Invalid) {
Dqn_DSMap_Set(&new_map, old_slot->key, old_slot->value, nullptr /*found*/);
Dqn_DSMap_Set(&new_map, old_slot->key, old_slot->value);
}
}
@ -933,7 +1234,6 @@ bool Dqn_DSMap_Resize(Dqn_DSMap<T> *map, uint32_t size)
return true;
}
template <typename T>
bool Dqn_DSMap_Erase(Dqn_DSMap<T> *map, Dqn_DSMapKey key)
{
@ -970,7 +1270,6 @@ bool Dqn_DSMap_Erase(Dqn_DSMap<T> *map, Dqn_DSMapKey key)
map->hash_to_slot[index] = map->hash_to_slot[probe_index];
map->hash_to_slot[probe_index] = DQN_DS_MAP_SENTINEL_SLOT;
index = probe_index;
DQN_ASSERT(Dqn_DSMap_FindSlot(map, probe->key) == probe);
}
// NOTE: We have erased a slot from the hash table, this leaves a gap
@ -1020,7 +1319,7 @@ DQN_API Dqn_DSMapKey Dqn_DSMap_KeyU64(Dqn_DSMap<T> const *map, uint64_t u64)
}
template <typename T>
DQN_API Dqn_DSMapKey Dqn_DSMap_KeyString8(Dqn_DSMap<T> const *map, Dqn_String8 string)
DQN_API Dqn_DSMapKey Dqn_DSMap_KeyStr8(Dqn_DSMap<T> const *map, Dqn_Str8 string)
{
DQN_ASSERT(string.size > 0 && string.size <= UINT32_MAX);
Dqn_DSMapKey result = {};
@ -1032,10 +1331,10 @@ DQN_API Dqn_DSMapKey Dqn_DSMap_KeyString8(Dqn_DSMap<T> const *map, Dqn_String8 s
}
template <typename T>
DQN_API Dqn_DSMapKey Dqn_DSMap_KeyString8Copy(Dqn_DSMap<T> const *map, Dqn_Allocator allocator, Dqn_String8 string)
DQN_API Dqn_DSMapKey Dqn_DSMap_KeyStr8Copy(Dqn_DSMap<T> const *map, Dqn_Allocator allocator, Dqn_Str8 string)
{
Dqn_String8 copy = Dqn_String8_Copy(allocator, string);
Dqn_DSMapKey result = Dqn_DSMap_KeyString8(map, copy);
Dqn_Str8 copy = Dqn_Str8_Copy(allocator, string);
Dqn_DSMapKey result = Dqn_DSMap_KeyStr8(map, copy);
return result;
}
#endif // !defined(DQN_NO_DSMAP)
@ -1050,6 +1349,22 @@ template <typename T> DQN_API Dqn_List<T> Dqn_List_Init(Dqn_Arena *arena, Dqn_us
return result;
}
template <typename T, size_t N> Dqn_List<T> Dqn_List_InitCArrayCopy(Dqn_Arena *arena, Dqn_usize chunk_size, T const (&array)[N])
{
Dqn_List<T> result = Dqn_List_Init<T>(arena, chunk_size);
DQN_FOR_UINDEX (index, N)
Dqn_List_Add(&result, array[index]);
return result;
}
template <typename T> Dqn_List<T> Dqn_List_InitSliceCopy(Dqn_Arena *arena, Dqn_usize chunk_size, Dqn_Slice<T> slice)
{
Dqn_List<T> result = Dqn_List_Init<T>(arena, chunk_size);
DQN_FOR_UINDEX (index, slice.size)
Dqn_List_Add(&result, slice.data[index]);
return result;
}
template <typename T> DQN_API T *Dqn_List_Make(Dqn_List<T> *list, Dqn_usize count)
{
if (list->chunk_size == 0)
@ -1090,13 +1405,25 @@ template <typename T> DQN_API T *Dqn_List_Add(Dqn_List<T> *list, T const &value)
return result;
}
template <typename T> DQN_API void Dqn_List_AddList(Dqn_List<T> *list, Dqn_List<T> other)
{
if (!list || list->chunk_size <= 0)
return;
// TODO(doyle): Copy chunk by chunk
for (Dqn_ListIterator<Dqn_Str8> it = {}; Dqn_List_Iterate(&other, &it, 0 /*start_index*/); )
Dqn_List_Add(list, *it.data);
}
template <typename T> DQN_API bool Dqn_List_Iterate(Dqn_List<T> *list, Dqn_ListIterator<T> *it, Dqn_usize start_index)
{
bool result = false;
if (!list || !it || list->chunk_size <= 0)
return result;
if (!it->init) {
if (it->init) {
it->index++;
} else {
*it = {};
if (start_index == 0) {
it->chunk = list->head;
@ -1161,4 +1488,17 @@ template <typename T> DQN_API T *Dqn_List_At(Dqn_List<T> *list, Dqn_usize index,
return result;
}
template <typename T> Dqn_Slice<T> Dqn_List_ToSliceCopy(Dqn_List<T> const *list, Dqn_Arena *arena)
{
// TODO(doyle): Chunk memcopies is much faster
Dqn_Slice<T> result = Dqn_Slice_Alloc<T>(arena, list->count, Dqn_ZeroMem_No);
if (result.size) {
Dqn_usize slice_index = 0;
for (Dqn_ListIterator<T> it = {}; Dqn_List_Iterate<T>(DQN_CAST(Dqn_List<T> *)list, &it, 0);)
result.data[slice_index++] = *it.data;
DQN_ASSERT(slice_index == result.size);
}
return result;
}
#endif // !defined(DQN_NO_LIST)

183
dqn_cppbuild.h Normal file
View File

@ -0,0 +1,183 @@
#if !defined(DQN_CPP_BUILD_H)
#define DQN_CPP_BUILD_H
struct Dqn_CPPBuildCompileFile
{
Dqn_Slice<Dqn_Str8> flags;
Dqn_Str8 input_file_path;
Dqn_Str8 output_file_path;
};
Dqn_Str8 const DQN_CPP_BUILD_OBJ_SUFFIX_OBJ = DQN_STR8(".obj");
Dqn_Str8 const DQN_CPP_BUILD_OBJ_SUFFIX_O = DQN_STR8(".o");
enum Dqn_CPPBuildCompiler
{
Dqn_CPPBuildCompiler_MSVC,
Dqn_CPPBuildCompiler_GCC,
};
struct Dqn_CPPBuildContext
{
Dqn_CPPBuildCompiler compiler;
Dqn_Str8 compile_file_obj_suffix;
Dqn_Slice<Dqn_CPPBuildCompileFile> compile_files;
Dqn_Slice<Dqn_Str8> compile_flags;
Dqn_Slice<Dqn_Str8> include_dirs;
Dqn_Slice<Dqn_Str8> link_flags;
Dqn_Str8 build_dir;
};
enum Dqn_CPPBuildStatus
{
Dqn_CPPBuildStatus_Ok,
Dqn_CPPBuildStatus_BuildDirectoryFailedToBeMade,
};
struct Dqn_CPPBuildAsyncResult
{
Dqn_CPPBuildStatus status;
Dqn_OSExecAsyncHandle async_handle;
};
enum Dqn_CPPBuildMode
{
Dqn_CPPBuildMode_AlwaysRebuild,
Dqn_CPPBuildMode_CacheBuild,
};
DQN_API Dqn_Str8 Dqn_CPPBuild_ToCommandLine(Dqn_CPPBuildContext build_context, Dqn_CPPBuildMode mode, Dqn_Allocator allocator);
DQN_API Dqn_CPPBuildAsyncResult Dqn_CPPBuild_Async (Dqn_CPPBuildContext build_context, Dqn_CPPBuildMode mode);
DQN_API void Dqn_CPPBuild_ExecOrAbort (Dqn_CPPBuildContext build_context, Dqn_CPPBuildMode mode);
#endif // DQN_CPP_BUILD_H
#if defined(DQN_CPP_BUILD_IMPLEMENTATION)
DQN_API Dqn_Str8 Dqn_CPPBuild_ToCommandLine(Dqn_CPPBuildContext build_context, Dqn_CPPBuildMode mode, Dqn_Allocator allocator)
{
// NOTE: Check if object files are newer than the source files =================================
Dqn_ThreadScratch scratch = Dqn_Thread_GetScratch(allocator.user_context);
Dqn_Str8 result = {};
Dqn_Slice<Dqn_CPPBuildCompileFile> dirtied_compile_files = build_context.compile_files;
if (mode == Dqn_CPPBuildMode_CacheBuild) {
dirtied_compile_files = Dqn_Slice_Alloc<Dqn_CPPBuildCompileFile>(scratch.arena, build_context.compile_files.size, Dqn_ZeroMem_Yes);
dirtied_compile_files.size = 0;
DQN_FOR_UINDEX (index, build_context.compile_files.size) {
Dqn_CPPBuildCompileFile file = build_context.compile_files.data[index];
Dqn_Str8 obj_file_name = {};
if (file.output_file_path.size) {
obj_file_name = file.output_file_path;
} else {
// NOTE: Determine the object file suffix
Dqn_Str8 compile_file_obj_suffix = build_context.compile_file_obj_suffix;
if (compile_file_obj_suffix.size == 0)
compile_file_obj_suffix = DQN_CPP_BUILD_OBJ_SUFFIX_OBJ;
// NOTE: Create the object file path
Dqn_Str8 file_stem = Dqn_Str8_FileNameNoExtension(file.input_file_path);
obj_file_name = Dqn_Str8_InitF(scratch.allocator, "%.*s%.*s", DQN_STR_FMT(file_stem), DQN_STR_FMT(compile_file_obj_suffix));
}
Dqn_Str8 obj_file_path = obj_file_name;
if (build_context.build_dir.size)
obj_file_path = Dqn_FsPath_ConvertF(scratch.arena, "%.*s/%.*s", DQN_STR_FMT(build_context.build_dir), DQN_STR_FMT(obj_file_name));
Dqn_FsInfo file_info = Dqn_Fs_GetInfo(file.input_file_path);
Dqn_FsInfo obj_file_info = Dqn_Fs_GetInfo(obj_file_path);
if (obj_file_info.last_write_time_in_s >= file_info.last_write_time_in_s)
continue;
dirtied_compile_files.data[dirtied_compile_files.size++] = file;
}
if (dirtied_compile_files.size <= 0)
return result;
}
// NOTE: Build the command line invocation =====================================================
Dqn_Str8Builder builder = {};
builder.allocator = allocator;
DQN_FOR_UINDEX (index, build_context.compile_flags.size) {
Dqn_Str8 flag = build_context.compile_flags.data[index];
if (index)
Dqn_Str8Builder_AppendF(&builder, " ");
Dqn_Str8Builder_AppendRef(&builder, flag);
}
DQN_FOR_UINDEX (index, build_context.include_dirs.size) {
Dqn_Str8 include_dir = build_context.include_dirs.data[index];
if (builder.count)
Dqn_Str8Builder_AppendF(&builder, " ");
Dqn_Str8Builder_AppendF(&builder, "/I %.*s", DQN_STR_FMT(include_dir));
}
DQN_FOR_UINDEX (index, dirtied_compile_files.size) {
Dqn_CPPBuildCompileFile file = dirtied_compile_files.data[index];
Dqn_Str8 obj_file = {};
if (builder.count)
Dqn_Str8Builder_AppendF(&builder, " ");
if (file.output_file_path.size) {
switch (build_context.compiler) {
case Dqn_CPPBuildCompiler_MSVC: {
Dqn_Str8Builder_AppendF(&builder, "/Fo%.*s ", DQN_STR_FMT(file.output_file_path));
} break;
case Dqn_CPPBuildCompiler_GCC: {
Dqn_Str8Builder_AppendF(&builder, "-o %.*s ", DQN_STR_FMT(file.output_file_path));
} break;
}
}
DQN_FOR_UINDEX (flag_index, file.flags.size) {
Dqn_Str8 flag = file.flags.data[flag_index];
Dqn_Str8Builder_AppendF(&builder, "%s%.*s", flag_index ? " " : "", DQN_STR_FMT(flag));
}
if (file.flags.size)
Dqn_Str8Builder_AppendF(&builder, " ");
Dqn_Str8Builder_AppendRef(&builder, file.input_file_path);
}
DQN_FOR_UINDEX (index, build_context.link_flags.size) {
Dqn_Str8 file = build_context.link_flags.data[index];
if (builder.count)
Dqn_Str8Builder_AppendF(&builder, " ");
Dqn_Str8Builder_AppendRef(&builder, file);
}
result = Dqn_Str8Builder_Build(&builder, allocator);
return result;
}
DQN_API Dqn_CPPBuildAsyncResult Dqn_CPPBuild_Async(Dqn_CPPBuildContext build_context, Dqn_CPPBuildMode mode)
{
Dqn_ThreadScratch scratch = Dqn_Thread_GetScratch(nullptr);
Dqn_Str8 cmd = Dqn_CPPBuild_ToCommandLine(build_context, mode, scratch.allocator);
Dqn_CPPBuildAsyncResult result = {};
if (!cmd.size)
return result;
if (!Dqn_Fs_MakeDir(build_context.build_dir)) {
result.status = Dqn_CPPBuildStatus_BuildDirectoryFailedToBeMade;
return result;
}
result.async_handle = Dqn_OS_ExecAsync(cmd, build_context.build_dir);
return result;
}
void Dqn_CPPBuild_ExecOrAbort(Dqn_CPPBuildContext build_context, Dqn_CPPBuildMode mode)
{
if (!Dqn_Fs_MakeDir(build_context.build_dir)) {
Dqn_Log_ErrorF("Failed to make build dir '%.*s'", DQN_STR_FMT(build_context.build_dir));
exit(-1);
}
Dqn_ThreadScratch scratch = Dqn_Thread_GetScratch(nullptr);
Dqn_Str8 cmd = Dqn_CPPBuild_ToCommandLine(build_context, mode, scratch.allocator);
Dqn_OS_ExecOrAbort(cmd, build_context.build_dir);
}
#endif // DQN_CPP_BUILD_IMPLEMENTATION

View File

@ -42,7 +42,7 @@ DQN_API Dqn_StackTraceWalkResult Dqn_StackTrace_Walk(Dqn_Arena *arena, uint16_t
if (!SymInitialize(result.process, nullptr /*UserSearchPath*/, true /*fInvadeProcess*/)) {
Dqn_ThreadScratch scratch = Dqn_Thread_GetScratch(nullptr);
Dqn_WinError error = Dqn_Win_LastError(scratch.arena);
Dqn_Log_ErrorF("SymInitialize failed, stack trace can not be generated (%lu): %.*s\n", error.code, DQN_STRING_FMT(error.msg));
Dqn_Log_ErrorF("SymInitialize failed, stack trace can not be generated (%lu): %.*s\n", error.code, DQN_STR_FMT(error.msg));
}
}
@ -132,16 +132,16 @@ DQN_API Dqn_StackTraceFrame Dqn_StackTrace_RawFrameToFrame(Dqn_Arena *arena, Dqn
// NOTE: Construct result ======================================================================
Dqn_String16 file_name16 = Dqn_String16{line.FileName, Dqn_CString16_Size(line.FileName)};
Dqn_String16 function_name16 = Dqn_String16{symbol->Name, symbol->NameLen};
Dqn_Str16 file_name16 = Dqn_Str16{line.FileName, Dqn_CStr16_Size(line.FileName)};
Dqn_Str16 function_name16 = Dqn_Str16{symbol->Name, symbol->NameLen};
Dqn_StackTraceFrame result = {};
result.address = raw_frame.base_addr;
result.line_number = line.LineNumber;
result.file_name = Dqn_Win_String16ToString8(arena, file_name16);
result.function_name = Dqn_Win_String16ToString8(arena, function_name16);
Dqn_StackTraceFrame result = {};
result.address = raw_frame.base_addr;
result.line_number = line.LineNumber;
result.file_name = Dqn_Win_Str16ToStr8(arena, file_name16);
result.function_name = Dqn_Win_Str16ToStr8(arena, function_name16);
#else
Dqn_StackTraceFrame result = {};
Dqn_StackTraceFrame result = {};
#endif
return result;
}
@ -168,12 +168,12 @@ DQN_API void Dqn_StackTrace_Print(uint16_t limit)
Dqn_ThreadScratch scratch = Dqn_Thread_GetScratch(nullptr);
Dqn_Slice<Dqn_StackTraceFrame> stack_trace = Dqn_StackTrace_GetFrames(scratch.arena, limit);
for (Dqn_StackTraceFrame& frame : stack_trace)
Dqn_Print_ErrLnF("%.*s(%I64u): %.*s", DQN_STRING_FMT(frame.file_name), frame.line_number, DQN_STRING_FMT(frame.function_name));
Dqn_Print_ErrLnF("%.*s(%I64u): %.*s", DQN_STR_FMT(frame.file_name), frame.line_number, DQN_STR_FMT(frame.function_name));
}
// NOTE: [$DEBG] Dqn_Debug =========================================================================
#if defined(DQN_LEAK_TRACING)
DQN_API void Dqn_Debug_TrackAlloc_(Dqn_String8 stack_trace, void *ptr, Dqn_usize size, bool leak_permitted)
DQN_API void Dqn_Debug_TrackAlloc_(Dqn_Str8 stack_trace, void *ptr, Dqn_usize size, bool leak_permitted)
{
if (!ptr)
return;
@ -202,9 +202,9 @@ DQN_API void Dqn_Debug_TrackAlloc_(Dqn_String8 stack_trace, void *ptr, Dqn_usize
Dqn_AllocRecord *alloc = Dqn_DSMap_Find(alloc_table, key);
if (alloc) {
if ((alloc->flags & Dqn_AllocRecordFlag_Freed) == 0) {
Dqn_String8 alloc_stack_trace = Dqn_String8_Init(alloc->stack_trace, alloc->stack_trace_size);
Dqn_String8 alloc_clean_stack_trace = Dqn_String8_Slice(alloc_stack_trace, g_dqn_library->stack_trace_offset_to_our_call_stack, alloc_stack_trace.size);
Dqn_String8 clean_stack_trace = Dqn_String8_Slice(stack_trace, g_dqn_library->stack_trace_offset_to_our_call_stack, stack_trace.size);
Dqn_Str8 alloc_stack_trace = Dqn_Str8_Init(alloc->stack_trace, alloc->stack_trace_size);
Dqn_Str8 alloc_clean_stack_trace = Dqn_Str8_Slice(alloc_stack_trace, g_dqn_library->stack_trace_offset_to_our_call_stack, alloc_stack_trace.size);
Dqn_Str8 clean_stack_trace = Dqn_Str8_Slice(stack_trace, g_dqn_library->stack_trace_offset_to_our_call_stack, stack_trace.size);
DQN_HARD_ASSERTF(
alloc->flags & Dqn_AllocRecordFlag_Freed,
"\n\nThis pointer is already in the leak tracker, however it has not "
@ -221,8 +221,8 @@ DQN_API void Dqn_Debug_TrackAlloc_(Dqn_String8 stack_trace, void *ptr, Dqn_usize
"%.*s"
,
ptr, alloc->size,
DQN_STRING_FMT(alloc_clean_stack_trace),
DQN_STRING_FMT(clean_stack_trace));
DQN_STR_FMT(alloc_clean_stack_trace),
DQN_STR_FMT(clean_stack_trace));
}
// NOTE: Pointer was reused, clean up the prior entry
@ -243,7 +243,7 @@ DQN_API void Dqn_Debug_TrackAlloc_(Dqn_String8 stack_trace, void *ptr, Dqn_usize
alloc->flags |= Dqn_AllocRecordFlag_LeakPermitted;
}
DQN_API void Dqn_Debug_TrackDealloc_(Dqn_String8 stack_trace, void *ptr)
DQN_API void Dqn_Debug_TrackDealloc_(Dqn_Str8 stack_trace, void *ptr)
{
if (!ptr || g_dqn_library->alloc_tracking_disabled)
return;
@ -261,13 +261,13 @@ DQN_API void Dqn_Debug_TrackDealloc_(Dqn_String8 stack_trace, void *ptr)
ptr);
if (alloc->flags & Dqn_AllocRecordFlag_Freed) {
Dqn_String8 alloc_stack_trace = Dqn_String8_Init(alloc->stack_trace, alloc->stack_trace_size);
Dqn_String8 alloc_clean_stack_trace = Dqn_String8_Slice(alloc_stack_trace, g_dqn_library->stack_trace_offset_to_our_call_stack, alloc_stack_trace.size);
Dqn_Str8 alloc_stack_trace = Dqn_Str8_Init(alloc->stack_trace, alloc->stack_trace_size);
Dqn_Str8 alloc_clean_stack_trace = Dqn_Str8_Slice(alloc_stack_trace, g_dqn_library->stack_trace_offset_to_our_call_stack, alloc_stack_trace.size);
Dqn_String8 alloc_freed_stack_trace = Dqn_String8_Init(alloc->freed_stack_trace, alloc->freed_stack_trace_size);
Dqn_String8 alloc_freed_clean_stack_trace = Dqn_String8_Slice(alloc_freed_stack_trace, g_dqn_library->stack_trace_offset_to_our_call_stack, alloc_freed_stack_trace.size);
Dqn_Str8 alloc_freed_stack_trace = Dqn_Str8_Init(alloc->freed_stack_trace, alloc->freed_stack_trace_size);
Dqn_Str8 alloc_freed_clean_stack_trace = Dqn_Str8_Slice(alloc_freed_stack_trace, g_dqn_library->stack_trace_offset_to_our_call_stack, alloc_freed_stack_trace.size);
Dqn_String8 dealloc_stack_trace = Dqn_String8_Slice(stack_trace, g_dqn_library->stack_trace_offset_to_our_call_stack, stack_trace.size);
Dqn_Str8 dealloc_stack_trace = Dqn_Str8_Slice(stack_trace, g_dqn_library->stack_trace_offset_to_our_call_stack, stack_trace.size);
DQN_HARD_ASSERTF((alloc->flags & Dqn_AllocRecordFlag_Freed) == 0,
"\n\nDouble free detected, pointer to free was already marked "
@ -286,9 +286,9 @@ DQN_API void Dqn_Debug_TrackDealloc_(Dqn_String8 stack_trace, void *ptr)
"%.*s"
,
ptr, alloc->freed_size,
DQN_STRING_FMT(alloc_clean_stack_trace),
DQN_STRING_FMT(alloc_freed_clean_stack_trace),
DQN_STRING_FMT(dealloc_stack_trace));
DQN_STR_FMT(alloc_clean_stack_trace),
DQN_STR_FMT(alloc_freed_clean_stack_trace),
DQN_STR_FMT(dealloc_stack_trace));
}
alloc->flags |= Dqn_AllocRecordFlag_Freed;
@ -310,12 +310,12 @@ DQN_API void Dqn_Debug_DumpLeaks()
leaked_bytes += alloc->size;
leak_count++;
Dqn_String8 stack_trace = Dqn_String8_Init(alloc->stack_trace, alloc->stack_trace_size);
Dqn_String8 clean_stack_trace = Dqn_String8_Slice(stack_trace, g_dqn_library->stack_trace_offset_to_our_call_stack, stack_trace.size);
Dqn_Str8 stack_trace = Dqn_Str8_Init(alloc->stack_trace, alloc->stack_trace_size);
Dqn_Str8 clean_stack_trace = Dqn_Str8_Slice(stack_trace, g_dqn_library->stack_trace_offset_to_our_call_stack, stack_trace.size);
Dqn_Log_WarningF("Pointer (0x%p) leaked %_$$zu at:\n"
"%.*s",
alloc->ptr, alloc->size,
DQN_STRING_FMT(clean_stack_trace));
DQN_STR_FMT(clean_stack_trace));
}
}

View File

@ -63,10 +63,10 @@ DQN_API void Dqn_ASAN_UnpoisonMemoryRegion(void const volatile *ptr, Dqn_usize s
struct Dqn_StackTraceFrame
{
uint64_t address;
uint64_t line_number;
Dqn_String8 file_name;
Dqn_String8 function_name;
uint64_t address;
uint64_t line_number;
Dqn_Str8 file_name;
Dqn_Str8 function_name;
};
struct Dqn_StackTraceRawFrame
@ -113,17 +113,17 @@ struct Dqn_AllocRecord
uint16_t flags; // Bit flags from `Dqn_AllocRecordFlag`
char padding[2];
};
static_assert(sizeof(Dqn_AllocRecord) == 48,
static_assert(sizeof(Dqn_AllocRecord) == 48 || sizeof(Dqn_AllocRecord) == 28, // NOTE: 64 bit vs 32 bit pointers respectively
"We aim to keep the allocation record as light as possible as "
"memory tracking can get expensive. Enforce that there is no "
"unexpected padding.");
#if defined(DQN_LEAK_TRACING)
#define Dqn_Debug_TrackAlloc(ptr, size, leak_permitted) Dqn_Debug_TrackAlloc_ (Dqn_String8_InitCString8(b_stacktrace_get_string()), ptr, size, leak_permitted)
#define Dqn_Debug_TrackDealloc(ptr) Dqn_Debug_TrackDealloc_(Dqn_String8_InitCString8(b_stacktrace_get_string()), ptr)
#define Dqn_Debug_TrackAlloc(ptr, size, leak_permitted) Dqn_Debug_TrackAlloc_ (Dqn_Str8_InitCString8(b_stacktrace_get_string()), ptr, size, leak_permitted)
#define Dqn_Debug_TrackDealloc(ptr) Dqn_Debug_TrackDealloc_(Dqn_Str8_InitCString8(b_stacktrace_get_string()), ptr)
DQN_API void Dqn_Debug_TrackAlloc_(Dqn_String8 stack_trace, void *ptr, Dqn_usize size, bool leak_permitted);
DQN_API void Dqn_Debug_TrackDealloc_(Dqn_String8 stack_trace, void *ptr);
DQN_API void Dqn_Debug_TrackAlloc_(Dqn_Str8 stack_trace, void *ptr, Dqn_usize size, bool leak_permitted);
DQN_API void Dqn_Debug_TrackDealloc_(Dqn_Str8 stack_trace, void *ptr);
DQN_API void Dqn_Debug_DumpLeaks();
#else
#define Dqn_Debug_TrackAlloc(...)

View File

@ -1,16 +1,21 @@
// NOTE: [$OS_H] OS Headers ========================================================================
#if defined(DQN_OS_UNIX)
#if defined(DQN_OS_UNIX) || defined(DQN_PLATFORM_EMSCRIPTEN)
#include <errno.h> // errno
#include <fcntl.h> // O_RDONLY ... etc
#include <linux/fs.h> // FICLONE
#include <sys/ioctl.h> // ioctl
#include <sys/types.h> // pid_t
#include <sys/wait.h> // waitpid
#include <sys/random.h> // getrandom
#include <sys/stat.h> // stat
#include <sys/sendfile.h> // sendfile
#include <sys/mman.h> // mmap
#include <time.h> // clock_gettime, nanosleep
#include <unistd.h> // access, gettid
#include <unistd.h> // access, gettid, write
#if defined(DQN_PLATFORM_EMSCRIPTEN)
#else
#include <sys/sendfile.h> // sendfile
#include <linux/fs.h> // FICLONE
#endif
#endif
// NOTE: [$STBS] stb_sprintf =======================================================================

View File

@ -1,3 +1,79 @@
// NOTE: [$PCGX] Dqn_PCG32 =========================================================================
#define DQN_PCG_DEFAULT_MULTIPLIER_64 6364136223846793005ULL
#define DQN_PCG_DEFAULT_INCREMENT_64 1442695040888963407ULL
DQN_API uint32_t Dqn_PCG32_Next(Dqn_PCG32 *rng)
{
uint64_t state = rng->state;
rng->state = state * DQN_PCG_DEFAULT_MULTIPLIER_64 + DQN_PCG_DEFAULT_INCREMENT_64;
// XSH-RR
uint32_t value = (uint32_t)((state ^ (state >> 18)) >> 27);
int rot = state >> 59;
return rot ? (value >> rot) | (value << (32 - rot)) : value;
}
DQN_API uint64_t Dqn_PCG32_Next64(Dqn_PCG32 *rng)
{
uint64_t value = Dqn_PCG32_Next(rng);
value <<= 32;
value |= Dqn_PCG32_Next(rng);
return value;
}
DQN_API uint32_t Dqn_PCG32_Range(Dqn_PCG32 *rng, uint32_t low, uint32_t high)
{
uint32_t bound = high - low;
uint32_t threshold = -(int32_t)bound % bound;
for (;;) {
uint32_t r = Dqn_PCG32_Next(rng);
if (r >= threshold)
return low + (r % bound);
}
}
DQN_API float Dqn_PCG32_NextF32(Dqn_PCG32 *rng)
{
uint32_t x = Dqn_PCG32_Next(rng);
return (float)(int32_t)(x >> 8) * 0x1.0p-24f;
}
DQN_API double Dqn_PCG32_NextF64(Dqn_PCG32 *rng)
{
uint64_t x = Dqn_PCG32_Next64(rng);
return (double)(int64_t)(x >> 11) * 0x1.0p-53;
}
DQN_API void Dqn_PCG32_Seed(Dqn_PCG32 *rng, uint64_t seed)
{
rng->state = 0ULL;
Dqn_PCG32_Next(rng);
rng->state += seed;
Dqn_PCG32_Next(rng);
}
DQN_API void Dqn_PCG32_Advance(Dqn_PCG32 *rng, uint64_t delta)
{
uint64_t cur_mult = DQN_PCG_DEFAULT_MULTIPLIER_64;
uint64_t cur_plus = DQN_PCG_DEFAULT_INCREMENT_64;
uint64_t acc_mult = 1;
uint64_t acc_plus = 0;
while (delta != 0) {
if (delta & 1) {
acc_mult *= cur_mult;
acc_plus = acc_plus * cur_mult + cur_plus;
}
cur_plus = (cur_mult + 1) * cur_plus;
cur_mult *= cur_mult;
delta >>= 1;
}
rng->state = acc_mult * rng->state + acc_plus;
}
#if !defined(DQN_NO_JSON_BUILDER)
// NOTE: [$JSON] Dqn_JSONBuilder ===================================================================
DQN_API Dqn_JSONBuilder Dqn_JSONBuilder_Init(Dqn_Allocator allocator, int spaces_per_indent)
@ -8,13 +84,13 @@ DQN_API Dqn_JSONBuilder Dqn_JSONBuilder_Init(Dqn_Allocator allocator, int spaces
return result;
}
DQN_API Dqn_String8 Dqn_JSONBuilder_Build(Dqn_JSONBuilder const *builder, Dqn_Allocator allocator)
DQN_API Dqn_Str8 Dqn_JSONBuilder_Build(Dqn_JSONBuilder const *builder, Dqn_Allocator allocator)
{
Dqn_String8 result = Dqn_String8Builder_Build(&builder->string_builder, allocator);
Dqn_Str8 result = Dqn_Str8Builder_Build(&builder->string_builder, allocator);
return result;
}
DQN_API void Dqn_JSONBuilder_KeyValue(Dqn_JSONBuilder *builder, Dqn_String8 key, Dqn_String8 value)
DQN_API void Dqn_JSONBuilder_KeyValue(Dqn_JSONBuilder *builder, Dqn_Str8 key, Dqn_Str8 value)
{
if (key.size == 0 && value.size == 0)
return;
@ -47,18 +123,18 @@ DQN_API void Dqn_JSONBuilder_KeyValue(Dqn_JSONBuilder *builder, Dqn_String8 key,
int spaces = builder->indent_level * spaces_per_indent;
if (key.size) {
Dqn_String8Builder_AppendF(&builder->string_builder,
Dqn_Str8Builder_AppendF(&builder->string_builder,
"%.*s%*c\"%.*s\": %.*s",
prefix_size, prefix,
spaces, ' ',
DQN_STRING_FMT(key),
DQN_STRING_FMT(value));
DQN_STR_FMT(key),
DQN_STR_FMT(value));
} else {
Dqn_String8Builder_AppendF(&builder->string_builder,
Dqn_Str8Builder_AppendF(&builder->string_builder,
"%.*s%*c%.*s",
prefix_size, prefix,
spaces, ' ',
DQN_STRING_FMT(value));
DQN_STR_FMT(value));
}
if (item == Dqn_JSONBuilderItem_OpenContainer)
@ -67,14 +143,14 @@ DQN_API void Dqn_JSONBuilder_KeyValue(Dqn_JSONBuilder *builder, Dqn_String8 key,
builder->last_item = item;
}
DQN_API void Dqn_JSONBuilder_KeyValueFV(Dqn_JSONBuilder *builder, Dqn_String8 key, char const *value_fmt, va_list args)
DQN_API void Dqn_JSONBuilder_KeyValueFV(Dqn_JSONBuilder *builder, Dqn_Str8 key, char const *value_fmt, va_list args)
{
Dqn_ThreadScratch scratch = Dqn_Thread_GetScratch(builder->string_builder.allocator.user_context);
Dqn_String8 value = Dqn_String8_InitFV(scratch.allocator, value_fmt, args);
Dqn_Str8 value = Dqn_Str8_InitFV(scratch.allocator, value_fmt, args);
Dqn_JSONBuilder_KeyValue(builder, key, value);
}
DQN_API void Dqn_JSONBuilder_KeyValueF(Dqn_JSONBuilder *builder, Dqn_String8 key, char const *value_fmt, ...)
DQN_API void Dqn_JSONBuilder_KeyValueF(Dqn_JSONBuilder *builder, Dqn_Str8 key, char const *value_fmt, ...)
{
va_list args;
va_start(args, value_fmt);
@ -82,47 +158,47 @@ DQN_API void Dqn_JSONBuilder_KeyValueF(Dqn_JSONBuilder *builder, Dqn_String8 key
va_end(args);
}
DQN_API void Dqn_JSONBuilder_ObjectBeginNamed(Dqn_JSONBuilder *builder, Dqn_String8 name)
DQN_API void Dqn_JSONBuilder_ObjectBeginNamed(Dqn_JSONBuilder *builder, Dqn_Str8 name)
{
Dqn_JSONBuilder_KeyValue(builder, name, DQN_STRING8("{"));
Dqn_JSONBuilder_KeyValue(builder, name, DQN_STR8("{"));
}
DQN_API void Dqn_JSONBuilder_ObjectEnd(Dqn_JSONBuilder *builder)
{
Dqn_JSONBuilder_KeyValue(builder, DQN_STRING8(""), DQN_STRING8("}"));
Dqn_JSONBuilder_KeyValue(builder, DQN_STR8(""), DQN_STR8("}"));
}
DQN_API void Dqn_JSONBuilder_ArrayBeginNamed(Dqn_JSONBuilder *builder, Dqn_String8 name)
DQN_API void Dqn_JSONBuilder_ArrayBeginNamed(Dqn_JSONBuilder *builder, Dqn_Str8 name)
{
Dqn_JSONBuilder_KeyValue(builder, name, DQN_STRING8("["));
Dqn_JSONBuilder_KeyValue(builder, name, DQN_STR8("["));
}
DQN_API void Dqn_JSONBuilder_ArrayEnd(Dqn_JSONBuilder *builder)
{
Dqn_JSONBuilder_KeyValue(builder, DQN_STRING8(""), DQN_STRING8("]"));
Dqn_JSONBuilder_KeyValue(builder, DQN_STR8(""), DQN_STR8("]"));
}
DQN_API void Dqn_JSONBuilder_StringNamed(Dqn_JSONBuilder *builder, Dqn_String8 key, Dqn_String8 value)
DQN_API void Dqn_JSONBuilder_StrNamed(Dqn_JSONBuilder *builder, Dqn_Str8 key, Dqn_Str8 value)
{
Dqn_JSONBuilder_KeyValueF(builder, key, "\"%.*s\"", value.size, value.data);
}
DQN_API void Dqn_JSONBuilder_LiteralNamed(Dqn_JSONBuilder *builder, Dqn_String8 key, Dqn_String8 value)
DQN_API void Dqn_JSONBuilder_LiteralNamed(Dqn_JSONBuilder *builder, Dqn_Str8 key, Dqn_Str8 value)
{
Dqn_JSONBuilder_KeyValueF(builder, key, "%.*s", value.size, value.data);
}
DQN_API void Dqn_JSONBuilder_U64Named(Dqn_JSONBuilder *builder, Dqn_String8 key, uint64_t value)
DQN_API void Dqn_JSONBuilder_U64Named(Dqn_JSONBuilder *builder, Dqn_Str8 key, uint64_t value)
{
Dqn_JSONBuilder_KeyValueF(builder, key, "%I64u", value);
}
DQN_API void Dqn_JSONBuilder_I64Named(Dqn_JSONBuilder *builder, Dqn_String8 key, int64_t value)
DQN_API void Dqn_JSONBuilder_I64Named(Dqn_JSONBuilder *builder, Dqn_Str8 key, int64_t value)
{
Dqn_JSONBuilder_KeyValueF(builder, key, "%I64d", value);
}
DQN_API void Dqn_JSONBuilder_F64Named(Dqn_JSONBuilder *builder, Dqn_String8 key, double value, int decimal_places)
DQN_API void Dqn_JSONBuilder_F64Named(Dqn_JSONBuilder *builder, Dqn_Str8 key, double value, int decimal_places)
{
if (!builder)
return;
@ -150,9 +226,9 @@ DQN_API void Dqn_JSONBuilder_F64Named(Dqn_JSONBuilder *builder, Dqn_String8 key,
Dqn_JSONBuilder_KeyValueF(builder, key, fmt, value);
}
DQN_API void Dqn_JSONBuilder_BoolNamed(Dqn_JSONBuilder *builder, Dqn_String8 key, bool value)
DQN_API void Dqn_JSONBuilder_BoolNamed(Dqn_JSONBuilder *builder, Dqn_Str8 key, bool value)
{
Dqn_String8 value_string = value ? DQN_STRING8("true") : DQN_STRING8("false");
Dqn_Str8 value_string = value ? DQN_STR8("true") : DQN_STR8("false");
Dqn_JSONBuilder_KeyValueF(builder, key, "%.*s", value_string.size, value_string.data);
}
#endif // !defined(DQN_NO_JSON_BUILDER)
@ -161,32 +237,32 @@ DQN_API void Dqn_JSONBuilder_BoolNamed(Dqn_JSONBuilder *builder, Dqn_String8 key
// NOTE: [$BHEX] Dqn_Bin ===========================================================================
DQN_API char const *Dqn_Bin_HexBufferTrim0x(char const *hex, Dqn_usize size, Dqn_usize *real_size)
{
Dqn_String8 result = Dqn_String8_TrimWhitespaceAround(Dqn_String8_Init(hex, size));
result = Dqn_String8_TrimPrefix(result, DQN_STRING8("0x"), Dqn_String8EqCase_Insensitive);
Dqn_Str8 result = Dqn_Str8_TrimWhitespaceAround(Dqn_Str8_Init(hex, size));
result = Dqn_Str8_TrimPrefix(result, DQN_STR8("0x"), Dqn_Str8EqCase_Insensitive);
if (real_size)
*real_size = result.size;
return result.data;
}
DQN_API Dqn_String8 Dqn_Bin_HexTrim0x(Dqn_String8 string)
DQN_API Dqn_Str8 Dqn_Bin_HexTrim0x(Dqn_Str8 string)
{
Dqn_usize trimmed_size = 0;
char const *trimmed = Dqn_Bin_HexBufferTrim0x(string.data, string.size, &trimmed_size);
Dqn_String8 result = Dqn_String8_Init(trimmed, trimmed_size);
Dqn_usize trimmed_size = 0;
char const *trimmed = Dqn_Bin_HexBufferTrim0x(string.data, string.size, &trimmed_size);
Dqn_Str8 result = Dqn_Str8_Init(trimmed, trimmed_size);
return result;
}
DQN_API Dqn_BinHexU64String Dqn_Bin_U64ToHexU64String(uint64_t number, uint32_t flags)
DQN_API Dqn_BinHexU64Str8 Dqn_Bin_U64ToHexU64Str8(uint64_t number, uint32_t flags)
{
Dqn_String8 prefix = {};
if (!(flags & Dqn_BinHexU64StringFlags_No0xPrefix))
prefix = DQN_STRING8("0x");
Dqn_Str8 prefix = {};
if (!(flags & Dqn_BinHexU64Str8Flags_No0xPrefix))
prefix = DQN_STR8("0x");
Dqn_BinHexU64String result = {};
Dqn_BinHexU64Str8 result = {};
DQN_MEMCPY(result.data, prefix.data, prefix.size);
result.size += DQN_CAST(int8_t)prefix.size;
char const *fmt = (flags & Dqn_BinHexU64StringFlags_UppercaseHex) ? "%I64X" : "%I64x";
char const *fmt = (flags & Dqn_BinHexU64Str8Flags_UppercaseHex) ? "%I64X" : "%I64x";
int size = STB_SPRINTF_DECORATE(snprintf)(result.data + result.size, DQN_ARRAY_UCOUNT(result.data) - result.size, fmt, number);
result.size += DQN_CAST(uint8_t)size;
DQN_ASSERT(result.size < DQN_ARRAY_UCOUNT(result.data));
@ -198,17 +274,17 @@ DQN_API Dqn_BinHexU64String Dqn_Bin_U64ToHexU64String(uint64_t number, uint32_t
return result;
}
DQN_API Dqn_String8 Dqn_Bin_U64ToHex(Dqn_Allocator allocator, uint64_t number, uint32_t flags)
DQN_API Dqn_Str8 Dqn_Bin_U64ToHex(Dqn_Allocator allocator, uint64_t number, uint32_t flags)
{
Dqn_String8 prefix = {};
if (!(flags & Dqn_BinHexU64StringFlags_No0xPrefix))
prefix = DQN_STRING8("0x");
Dqn_Str8 prefix = {};
if (!(flags & Dqn_BinHexU64Str8Flags_No0xPrefix))
prefix = DQN_STR8("0x");
char const *fmt = (flags & Dqn_BinHexU64StringFlags_UppercaseHex) ? "%I64X" : "%I64x";
Dqn_usize required_size = Dqn_CString8_FSize(fmt, number) + prefix.size;
Dqn_String8 result = Dqn_String8_Allocate(allocator, required_size, Dqn_ZeroMem_No);
char const *fmt = (flags & Dqn_BinHexU64Str8Flags_UppercaseHex) ? "%I64X" : "%I64x";
Dqn_usize required_size = Dqn_CStr8_FSize(fmt, number) + prefix.size;
Dqn_Str8 result = Dqn_Str8_Allocate(allocator, required_size, Dqn_ZeroMem_No);
if (Dqn_String8_IsValid(result)) {
if (Dqn_Str8_IsValid(result)) {
DQN_MEMCPY(result.data, prefix.data, prefix.size);
int space = DQN_CAST(int)DQN_MAX((result.size - prefix.size) + 1, 0); /*null-terminator*/
STB_SPRINTF_DECORATE(snprintf)(result.data + prefix.size, space, fmt, number);
@ -241,7 +317,7 @@ DQN_API uint64_t Dqn_Bin_HexBufferToU64(char const *hex, Dqn_usize size)
return result;
}
DQN_API uint64_t Dqn_Bin_HexToU64(Dqn_String8 hex)
DQN_API uint64_t Dqn_Bin_HexToU64(Dqn_Str8 hex)
{
uint64_t result = Dqn_Bin_HexBufferToU64(hex.data, hex.size);
return result;
@ -279,9 +355,9 @@ DQN_API char *Dqn_Bin_BytesToHexBufferArena(Dqn_Arena *arena, void const *src, D
return result;
}
DQN_API Dqn_String8 Dqn_Bin_BytesToHexArena(Dqn_Arena *arena, void const *src, Dqn_usize size)
DQN_API Dqn_Str8 Dqn_Bin_BytesToHexArena(Dqn_Arena *arena, void const *src, Dqn_usize size)
{
Dqn_String8 result = {};
Dqn_Str8 result = {};
result.data = Dqn_Bin_BytesToHexBufferArena(arena, src, size);
if (result.data)
result.size = size * 2;
@ -346,13 +422,13 @@ DQN_API Dqn_usize Dqn_Bin_HexBufferToBytesUnchecked(char const *hex, Dqn_usize h
return result;
}
DQN_API Dqn_usize Dqn_Bin_HexToBytesUnchecked(Dqn_String8 hex, void *dest, Dqn_usize dest_size)
DQN_API Dqn_usize Dqn_Bin_HexToBytesUnchecked(Dqn_Str8 hex, void *dest, Dqn_usize dest_size)
{
Dqn_usize result = Dqn_Bin_HexBufferToBytesUnchecked(hex.data, hex.size, dest, dest_size);
return result;
}
DQN_API Dqn_usize Dqn_Bin_HexToBytes(Dqn_String8 hex, void *dest, Dqn_usize dest_size)
DQN_API Dqn_usize Dqn_Bin_HexToBytes(Dqn_Str8 hex, void *dest, Dqn_usize dest_size)
{
Dqn_usize result = Dqn_Bin_HexBufferToBytes(hex.data, hex.size, dest, dest_size);
return result;
@ -364,13 +440,10 @@ DQN_API char *Dqn_Bin_HexBufferToBytesArena(Dqn_Arena *arena, char const *hex, D
if (!arena || !hex || size <= 0)
return result;
Dqn_usize trim_size = 0;
char const *trim_hex = Dqn_Bin_HexBufferTrim0x(hex,
size,
&trim_size);
Dqn_usize binary_size = trim_size / 2;
result = Dqn_Arena_NewArray(arena, char, binary_size, Dqn_ZeroMem_No);
Dqn_usize trim_size = 0;
char const *trim_hex = Dqn_Bin_HexBufferTrim0x(hex, size, &trim_size);
Dqn_usize binary_size = trim_size / 2;
result = Dqn_Arena_NewArray(arena, char, binary_size, Dqn_ZeroMem_No);
if (result) {
Dqn_usize convert_size = Dqn_Bin_HexBufferToBytesUnchecked(trim_hex, trim_size, result, binary_size);
if (real_size)
@ -379,10 +452,10 @@ DQN_API char *Dqn_Bin_HexBufferToBytesArena(Dqn_Arena *arena, char const *hex, D
return result;
}
DQN_API Dqn_String8 Dqn_Bin_HexToBytesArena(Dqn_Arena *arena, Dqn_String8 hex)
DQN_API Dqn_Str8 Dqn_Bin_HexToBytesArena(Dqn_Arena *arena, Dqn_Str8 hex)
{
Dqn_String8 result = {};
result.data = Dqn_Bin_HexBufferToBytesArena(arena, hex.data, hex.size, &result.size);
Dqn_Str8 result = {};
result.data = Dqn_Bin_HexBufferToBytesArena(arena, hex.data, hex.size, &result.size);
return result;
}
#endif // !defined(DQN_NO_BIN)
@ -505,7 +578,7 @@ DQN_API uint32_t Dqn_Safe_SaturateCastUSizeToU32(Dqn_usize val)
DQN_API uint64_t Dqn_Safe_SaturateCastUSizeToU64(Dqn_usize val)
{
uint64_t result = DQN_CHECK(val <= UINT64_MAX) ? DQN_CAST(uint64_t)val : UINT64_MAX;
uint64_t result = DQN_CHECK(DQN_CAST(uint64_t)val <= UINT64_MAX) ? DQN_CAST(uint64_t)val : UINT64_MAX;
return result;
}
@ -572,8 +645,8 @@ DQN_API int32_t Dqn_Safe_SaturateCastISizeToI32(Dqn_isize val)
DQN_API int64_t Dqn_Safe_SaturateCastISizeToI64(Dqn_isize val)
{
DQN_ASSERT(val >= INT64_MIN && val <= INT64_MAX);
int64_t result = DQN_CAST(int64_t)DQN_CLAMP(val, INT64_MIN, INT64_MAX);
DQN_ASSERT(DQN_CAST(int64_t)val >= INT64_MIN && DQN_CAST(int64_t)val <= INT64_MAX);
int64_t result = DQN_CAST(int64_t)DQN_CLAMP(DQN_CAST(int64_t)val, INT64_MIN, INT64_MAX);
return result;
}
@ -733,7 +806,7 @@ DQN_API uint64_t Dqn_Safe_SaturateCastIntToU64(int val)
}
// NOTE: [$MISC] Misc ==============================================================================
DQN_API int Dqn_SNPrintFDotTruncate(char *buffer, int size, char const *fmt, ...)
DQN_API int Dqn_SNPrintFDotTruncate(char *buffer, int size, DQN_FMT_ATTRIB char const *fmt, ...)
{
va_list args;
va_start(args, fmt);
@ -747,16 +820,16 @@ DQN_API int Dqn_SNPrintFDotTruncate(char *buffer, int size, char const *fmt, ...
return result;
}
DQN_API Dqn_U64String Dqn_U64ToString(uint64_t val, char separator)
DQN_API Dqn_U64Str8 Dqn_U64ToStr8(uint64_t val, char separator)
{
Dqn_U64String result = {};
Dqn_U64Str8 result = {};
if (val == 0) {
result.data[result.size++] = '0';
} else {
// NOTE: The number is written in reverse because we form the string by
// dividing by 10, so we write it in, then reverse it out after all is
// done.
Dqn_U64String temp = {};
Dqn_U64Str8 temp = {};
for (Dqn_usize digit_count = 0; val > 0; digit_count++) {
if (separator && (digit_count != 0) && (digit_count % 3 == 0))
temp.data[temp.size++] = separator;
@ -783,7 +856,7 @@ DQN_API Dqn_U64String Dqn_U64ToString(uint64_t val, char separator)
// NOTE: [$DLIB] Dqn_Library =======================================================================
Dqn_Library *g_dqn_library;
DQN_API Dqn_Library *Dqn_Library_Init()
DQN_API Dqn_Library *Dqn_Library_Init(Dqn_LibraryOnInit on_init)
{
if (!g_dqn_library) {
static Dqn_Library default_instance = {};
@ -801,8 +874,8 @@ DQN_API Dqn_Library *Dqn_Library_Init()
// NOTE: Query OS page size ====================================================================
{
SYSTEM_INFO system_info = {};
#if defined(DQN_OS_WIN32)
SYSTEM_INFO system_info = {};
GetSystemInfo(&system_info);
result->os_page_size = system_info.dwPageSize;
result->os_alloc_granularity = system_info.dwAllocationGranularity;
@ -829,8 +902,8 @@ DQN_API Dqn_Library *Dqn_Library_Init()
{
result->alloc_tracking_disabled = true; // TODO(doyle): @robust Does this need to be atomic?
Dqn_String8 sample_backtrace = Dqn_String8_InitCString8(b_stacktrace_get_string());
Dqn_String8 clean_backtrace = Dqn_Debug_CleanStackTrace(sample_backtrace);
Dqn_Str8 sample_backtrace = Dqn_Str8_InitCStr8(b_stacktrace_get_string());
Dqn_Str8 clean_backtrace = Dqn_Debug_CleanStackTrace(sample_backtrace);
result->stack_trace_offset_to_our_call_stack = DQN_CAST(uint16_t)(sample_backtrace.size - clean_backtrace.size);
free(sample_backtrace.data);
@ -840,28 +913,34 @@ DQN_API Dqn_Library *Dqn_Library_Init()
#endif
// NOTE: Print out init features ===============================================================
if (on_init == Dqn_LibraryOnInit_LogFeatures) {
Dqn_Log_DebugF("Dqn Library initialised:\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);
// NOTE: %$$_I32u is a stb_sprintf format specifier, non-standard
DQN_MSVC_WARNING_PUSH
DQN_MSVC_WARNING_DISABLE(6271) // Extra argument passed to 'Dqn_Print_StdLnF'.
Dqn_Print_StdLnF(Dqn_PrintStd_Err, " OS Page Size/Alloc Granularity: %$$_I32u/%$$_I32u", result->os_page_size, result->os_alloc_granularity);
DQN_MSVC_WARNING_POP
#if __has_feature(address_sanitizer) || defined(__SANITIZE_ADDRESS__)
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 __has_feature(address_sanitizer) || defined(__SANITIZE_ADDRESS__)
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);
}
#endif
#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
// TODO(doyle): Add stacktrace feature log
Dqn_Print_StdLnF(Dqn_PrintStd_Err, "");
}
#endif
#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
// TODO(doyle): Add stacktrace feature log
Dqn_Print_StdLnF(Dqn_PrintStd_Err, "");
return result;
}
@ -885,14 +964,14 @@ DQN_API void Dqn_Library_SetLogCallback(Dqn_LogProc *proc, void *user_data)
g_dqn_library->log_user_data = user_data;
}
DQN_API void Dqn_Library_DumpThreadContextArenaStat(Dqn_String8 file_path)
DQN_API void Dqn_Library_DumpThreadContextArenaStat(Dqn_Str8 file_path)
{
#if defined(DQN_DEBUG_THREAD_CONTEXT)
// NOTE: Open a file to write the arena stats to
FILE *file = nullptr;
fopen_s(&file, file_path.data, "a+b");
if (file) {
Dqn_Log_ErrorF("Failed to dump thread context arenas [file=%.*s]", DQN_STRING_FMT(file_path));
Dqn_Log_ErrorF("Failed to dump thread context arenas [file=%.*s]", DQN_STR_FMT(file_path));
return;
}
@ -908,7 +987,7 @@ DQN_API void Dqn_Library_DumpThreadContextArenaStat(Dqn_String8 file_path)
Dqn_TicketMutex_End(&g_dqn_library->thread_context_mutex);
// NOTE: Print the cumulative stat
Dqn_DateHMSTimeString now = Dqn_Date_HMSLocalTimeStringNow();
Dqn_DateHMSTimeStr now = Dqn_Date_HMSLocalTimeStrNow();
fprintf(file,
"Time=%.*s %.*s | Thread Context Arenas | Count=%d\n",
now.date_size, now.date,
@ -931,19 +1010,19 @@ DQN_API void Dqn_Library_DumpThreadContextArenaStat(Dqn_String8 file_path)
stat.blocks_hwm = DQN_MAX(stat.blocks_hwm, current->blocks_hwm);
}
Dqn_ArenaStatString stats_string = Dqn_Arena_StatString(&stat);
Dqn_ArenaStatStr stats_string = Dqn_Arena_StatStr(&stat);
fprintf(file, " [ALL] CURR %.*s\n", stats_string.size, stats_string.data);
}
// NOTE: Print individual thread arena data
for (Dqn_usize index = 0; index < stats_size; index++) {
Dqn_ArenaStat const *current = stats + index;
Dqn_ArenaStatString current_string = Dqn_Arena_StatString(current);
Dqn_ArenaStatStr current_string = Dqn_Arena_StatStr(current);
fprintf(file, " [%03d] CURR %.*s\n", DQN_CAST(int)index, current_string.size, current_string.data);
}
fclose(file);
Dqn_Log_InfoF("Dumped thread context arenas [file=%.*s]", DQN_STRING_FMT(file_path));
Dqn_Log_InfoF("Dumped thread context arenas [file=%.*s]", DQN_STR_FMT(file_path));
#else
(void)file_path;
#endif // #if defined(DQN_DEBUG_THREAD_CONTEXT)
@ -952,7 +1031,7 @@ DQN_API void Dqn_Library_DumpThreadContextArenaStat(Dqn_String8 file_path)
#if !defined(DQN_NO_PROFILER)
// NOTE: [$PROF] Dqn_Profiler ======================================================================
Dqn_ProfilerZoneScope::Dqn_ProfilerZoneScope(Dqn_String8 name, uint16_t anchor_index)
Dqn_ProfilerZoneScope::Dqn_ProfilerZoneScope(Dqn_Str8 name, uint16_t anchor_index)
{
zone = Dqn_Profiler_BeginZoneWithIndex(name, anchor_index);
}
@ -962,7 +1041,7 @@ Dqn_ProfilerZoneScope::~Dqn_ProfilerZoneScope()
Dqn_Profiler_EndZone(zone);
}
Dqn_ProfilerZone Dqn_Profiler_BeginZoneWithIndex(Dqn_String8 name, uint16_t anchor_index)
Dqn_ProfilerZone Dqn_Profiler_BeginZoneWithIndex(Dqn_Str8 name, uint16_t anchor_index)
{
Dqn_ProfilerAnchor *anchor = Dqn_Profiler_AnchorBuffer(Dqn_ProfilerAnchorBuffer_Back) + anchor_index;
anchor->name = name;
@ -998,11 +1077,11 @@ Dqn_ProfilerAnchor *Dqn_Profiler_AnchorBuffer(Dqn_ProfilerAnchorBuffer buffer)
return result;
}
void Dqn_Profiler_SwapAnchorBuffer(uint32_t anchor_count)
void Dqn_Profiler_SwapAnchorBuffer()
{
g_dqn_library->profiler->active_anchor_buffer++;
Dqn_ProfilerAnchor *anchors = Dqn_Profiler_AnchorBuffer(Dqn_ProfilerAnchorBuffer_Back);
DQN_MEMSET(anchors, 0, anchor_count * sizeof(g_dqn_library->profiler->anchors[0][0]));
DQN_MEMSET(anchors, 0, DQN_ARRAY_UCOUNT(g_dqn_library->profiler->anchors[0]) * sizeof(g_dqn_library->profiler->anchors[0][0]));
}
void Dqn_Profiler_Dump(uint64_t tsc_per_second)
@ -1018,13 +1097,13 @@ void Dqn_Profiler_Dump(uint64_t tsc_per_second)
Dqn_f64 tsc_exclusive_milliseconds = tsc_exclusive * 1000 / DQN_CAST(Dqn_f64)tsc_per_second;
if (tsc_exclusive == tsc_inclusive) {
Dqn_Print_LnF("%.*s[%u]: %.1fms",
DQN_STRING_FMT(anchor->name),
DQN_STR_FMT(anchor->name),
anchor->hit_count,
tsc_exclusive_milliseconds);
} else {
Dqn_f64 tsc_inclusive_milliseconds = tsc_inclusive * 1000 / DQN_CAST(Dqn_f64)tsc_per_second;
Dqn_Print_LnF("%.*s[%u]: %.1f/%.1fms",
DQN_STRING_FMT(anchor->name),
DQN_STR_FMT(anchor->name),
anchor->hit_count,
tsc_exclusive_milliseconds,
tsc_inclusive_milliseconds);

View File

@ -1,3 +1,25 @@
// NOTE: [$PCGX] Dqn_PCG32 =========================================================================
// Random number generator of the PCG family. Implementation taken from Martins
// Mmozeiko from Handmade Network.
// https://gist.github.com/mmozeiko/1561361cd4105749f80bb0b9223e9db8
//
// NOTE: API =======================================================================================
// @proc Dqn_PCG32_Range
// @desc Returns a value in the [low; high) interval
// @proc Dqn_PCG32_NextF
// @desc Returns a float & double in [0; 1) interval;
struct Dqn_PCG32 { uint64_t state; };
DQN_API uint32_t Dqn_PCG32_Next (Dqn_PCG32 *rng);
DQN_API uint64_t Dqn_PCG32_Next64 (Dqn_PCG32 *rng);
DQN_API uint32_t Dqn_PCG32_Range (Dqn_PCG32 *rng, uint32_t low, uint32_t high);
DQN_API Dqn_f32 Dqn_PCG32_NextF32(Dqn_PCG32 *rng);
DQN_API Dqn_f64 Dqn_PCG32_NextF64(Dqn_PCG32 *rng);
DQN_API void Dqn_PCG32_Seed (Dqn_PCG32 *rng, uint64_t seed);
DQN_API void Dqn_PCG32_Advance(Dqn_PCG32 *rng, uint64_t delta);
#if !defined(DQN_NO_JSON_BUILDER)
// NOTE: [$JSON] Dqn_JSONBuilder ===================================================================
// Basic helper class to construct JSON output to a string
@ -44,7 +66,7 @@ enum Dqn_JSONBuilderItem
struct Dqn_JSONBuilder
{
bool use_stdout; // When set, ignore the string builder and dump immediately to stdout
Dqn_String8Builder string_builder; // (Internal)
Dqn_Str8Builder string_builder; // (Internal)
int indent_level; // (Internal)
int spaces_per_indent; // The number of spaces per indent level
Dqn_JSONBuilderItem last_item;
@ -68,23 +90,23 @@ struct Dqn_JSONBuilder
DQN_API Dqn_JSONBuilder Dqn_JSONBuilder_Init (Dqn_Allocator allocator, int spaces_per_indent);
DQN_API Dqn_String8 Dqn_JSONBuilder_Build (Dqn_JSONBuilder const *builder, Dqn_Allocator allocator);
DQN_API void Dqn_JSONBuilder_KeyValue (Dqn_JSONBuilder *builder, Dqn_String8 key, Dqn_String8 value);
DQN_API void Dqn_JSONBuilder_KeyValueF (Dqn_JSONBuilder *builder, Dqn_String8 key, char const *value_fmt, ...);
DQN_API void Dqn_JSONBuilder_ObjectBeginNamed(Dqn_JSONBuilder *builder, Dqn_String8 name);
DQN_API Dqn_Str8 Dqn_JSONBuilder_Build (Dqn_JSONBuilder const *builder, Dqn_Allocator allocator);
DQN_API void Dqn_JSONBuilder_KeyValue (Dqn_JSONBuilder *builder, Dqn_Str8 key, Dqn_Str8 value);
DQN_API void Dqn_JSONBuilder_KeyValueF (Dqn_JSONBuilder *builder, Dqn_Str8 key, char const *value_fmt, ...);
DQN_API void Dqn_JSONBuilder_ObjectBeginNamed(Dqn_JSONBuilder *builder, Dqn_Str8 name);
DQN_API void Dqn_JSONBuilder_ObjectEnd (Dqn_JSONBuilder *builder);
DQN_API void Dqn_JSONBuilder_ArrayBeginNamed (Dqn_JSONBuilder *builder, Dqn_String8 name);
DQN_API void Dqn_JSONBuilder_ArrayBeginNamed (Dqn_JSONBuilder *builder, Dqn_Str8 name);
DQN_API void Dqn_JSONBuilder_ArrayEnd (Dqn_JSONBuilder *builder);
DQN_API void Dqn_JSONBuilder_StringNamed (Dqn_JSONBuilder *builder, Dqn_String8 key, Dqn_String8 value);
DQN_API void Dqn_JSONBuilder_LiteralNamed (Dqn_JSONBuilder *builder, Dqn_String8 key, Dqn_String8 value);
DQN_API void Dqn_JSONBuilder_U64Named (Dqn_JSONBuilder *builder, Dqn_String8 key, uint64_t value);
DQN_API void Dqn_JSONBuilder_I64Named (Dqn_JSONBuilder *builder, Dqn_String8 key, int64_t value);
DQN_API void Dqn_JSONBuilder_F64Named (Dqn_JSONBuilder *builder, Dqn_String8 key, double value, int decimal_places);
DQN_API void Dqn_JSONBuilder_BoolNamed (Dqn_JSONBuilder *builder, Dqn_String8 key, bool value);
DQN_API void Dqn_JSONBuilder_Str8Named (Dqn_JSONBuilder *builder, Dqn_Str8 key, Dqn_Str8 value);
DQN_API void Dqn_JSONBuilder_LiteralNamed (Dqn_JSONBuilder *builder, Dqn_Str8 key, Dqn_Str8 value);
DQN_API void Dqn_JSONBuilder_U64Named (Dqn_JSONBuilder *builder, Dqn_Str8 key, uint64_t value);
DQN_API void Dqn_JSONBuilder_I64Named (Dqn_JSONBuilder *builder, Dqn_Str8 key, int64_t value);
DQN_API void Dqn_JSONBuilder_F64Named (Dqn_JSONBuilder *builder, Dqn_Str8 key, double value, int decimal_places);
DQN_API void Dqn_JSONBuilder_BoolNamed (Dqn_JSONBuilder *builder, Dqn_Str8 key, bool value);
#define Dqn_JSONBuilder_ObjectBegin(builder) Dqn_JSONBuilder_ObjectBeginNamed(builder, DQN_STRING8(""))
#define Dqn_JSONBuilder_ArrayBegin(builder) Dqn_JSONBuilder_ArrayBeginNamed(builder, DQN_STRING8(""))
#define Dqn_JSONBuilder_String(builder, value) Dqn_JSONBuilder_StringNamed(builder, DQN_STRING8(""), value)
#define Dqn_JSONBuilder_Str8(builder, value) Dqn_JSONBuilder_Str8Named(builder, DQN_STRING8(""), value)
#define Dqn_JSONBuilder_Literal(builder, value) Dqn_JSONBuilder_LiteralNamed(builder, DQN_STRING8(""), value)
#define Dqn_JSONBuilder_U64(builder, value) Dqn_JSONBuilder_U64Named(builder, DQN_STRING8(""), value)
#define Dqn_JSONBuilder_I64(builder, value) Dqn_JSONBuilder_I64Named(builder, DQN_STRING8(""), value)
@ -95,20 +117,20 @@ DQN_API void Dqn_JSONBuilder_BoolNamed (Dqn_JSONBuilder *builde
#if !defined(DQN_NO_BIN)
// NOTE: [$BHEX] Dqn_Bin ===========================================================================
// NOTE: API =======================================================================================
// @proc Dqn_Bin_U64ToHexU64String
// @proc Dqn_Bin_U64ToHexU64Str8
// @desc Convert a 64 bit number to a hex string
// @param[in] number Number to convert to hexadecimal representation
// @param[in] flags Bit flags from Dqn_BinHexU64StringFlags to customise the
// @param[in] flags Bit flags from Dqn_BinHexU64Str8Flags to customise the
// output of the hexadecimal string.
// @return The hexadecimal representation of the number. This string is always
// null-terminated.
// @proc Dqn_Bin_U64ToHex
// @copybrief Dqn_Bin_U64ToHexU64String
// @copybrief Dqn_Bin_U64ToHexU64Str8
// @param[in] allocator The memory allocator to use for the memory of the
// hexadecimal string.
// @copyparams Dqn_Bin_U64ToHexU64String
// @copyparams Dqn_Bin_U64ToHexU64Str8
// @proc Dqn_Bin_HexBufferToU64
// @desc Convert a hexadecimal string a 64 bit value.
@ -151,17 +173,17 @@ DQN_API void Dqn_JSONBuilder_BoolNamed (Dqn_JSONBuilder *builde
// be greater than `dest_size`.
// @proc Dqn_Bin_HexToBytes
// @desc String8 variant of @see Dqn_Bin_HexBufferToBytes
// @desc Str8 variant of @see Dqn_Bin_HexBufferToBytes
// @proc Dqn_Bin_StringHexBufferToBytesUnchecked
// @proc Dqn_Bin_Str8HexBufferToBytesUnchecked
// @desc Unchecked variant of @see Dqn_Bin_HexBufferToBytes
//
// This function skips some string checks, it assumes the hex is a valid hex
// stream and that the arguments are valid e.g. no trimming or 0x prefix
// stripping is performed
// @proc Dqn_Bin_String
// @desc String8 variant of @see Dqn_Bin_HexBufferToBytesUnchecked
// @proc Dqn_Bin_Str8
// @desc Str8 variant of @see Dqn_Bin_HexBufferToBytesUnchecked
// @proc Dqn_Bin_HexBufferToBytesArena
// Dynamic allocating variant of @see Dqn_Bin_HexBufferToBytesUnchecked
@ -181,28 +203,28 @@ DQN_API void Dqn_JSONBuilder_BoolNamed (Dqn_JSONBuilder *builde
//
// @return The byte representation of the hex string.
struct Dqn_BinHexU64String
struct Dqn_BinHexU64Str8
{
char data[2 /*0x*/ + 16 /*hex*/ + 1 /*null-terminator*/];
uint8_t size;
};
enum Dqn_BinHexU64StringFlags
enum Dqn_BinHexU64Str8Flags
{
Dqn_BinHexU64StringFlags_No0xPrefix = 1 << 0, /// Remove the 0x prefix from the string
Dqn_BinHexU64StringFlags_UppercaseHex = 1 << 1, /// Use uppercase ascii characters for hex
Dqn_BinHexU64Str8Flags_No0xPrefix = 1 << 0, /// Remove the 0x prefix from the string
Dqn_BinHexU64Str8Flags_UppercaseHex = 1 << 1, /// Use uppercase ascii characters for hex
};
DQN_API char const * Dqn_Bin_HexBufferTrim0x (char const *hex, Dqn_usize size, Dqn_usize *real_size);
DQN_API Dqn_String8 Dqn_Bin_HexTrim0x (Dqn_String8 string);
DQN_API Dqn_Str8 Dqn_Bin_HexTrim0x (Dqn_Str8 string);
DQN_API Dqn_BinHexU64String Dqn_Bin_U64ToHexU64String (uint64_t number, uint32_t flags);
DQN_API Dqn_String8 Dqn_Bin_U64ToHex (Dqn_Allocator allocator, uint64_t number, uint32_t flags);
DQN_API Dqn_BinHexU64Str8 Dqn_Bin_U64ToHexU64Str8 (uint64_t number, uint32_t flags);
DQN_API Dqn_Str8 Dqn_Bin_U64ToHex (Dqn_Allocator allocator, uint64_t number, uint32_t flags);
DQN_API uint64_t Dqn_Bin_HexBufferToU64 (char const *hex, Dqn_usize size);
DQN_API uint64_t Dqn_Bin_HexToU64 (Dqn_String8 hex);
DQN_API uint64_t Dqn_Bin_HexToU64 (Dqn_Str8 hex);
DQN_API Dqn_String8 Dqn_Bin_BytesToHexArena (Dqn_Arena *arena, void const *src, Dqn_usize size);
DQN_API Dqn_Str8 Dqn_Bin_BytesToHexArena (Dqn_Arena *arena, void const *src, Dqn_usize size);
DQN_API char * Dqn_Bin_BytesToHexBufferArena (Dqn_Arena *arena, void const *src, Dqn_usize size);
DQN_API bool Dqn_Bin_BytesToHexBuffer (void const *src, Dqn_usize src_size, char *dest, Dqn_usize dest_size);
@ -210,9 +232,9 @@ DQN_API Dqn_usize Dqn_Bin_HexBufferToBytesUnchecked(char const *hex,
DQN_API Dqn_usize Dqn_Bin_HexBufferToBytes (char const *hex, Dqn_usize hex_size, void *dest, Dqn_usize dest_size);
DQN_API char * Dqn_Bin_HexBufferToBytesArena (Dqn_Arena *arena, char const *hex, Dqn_usize hex_size, Dqn_usize *real_size);
DQN_API Dqn_usize Dqn_Bin_HexToBytesUnchecked (Dqn_String8 hex, void *dest, Dqn_usize dest_size);
DQN_API Dqn_usize Dqn_Bin_HexToBytes (Dqn_String8 hex, void *dest, Dqn_usize dest_size);
DQN_API Dqn_String8 Dqn_Bin_HexToBytesArena (Dqn_Arena *arena, Dqn_String8 hex);
DQN_API Dqn_usize Dqn_Bin_HexToBytesUnchecked (Dqn_Str8 hex, void *dest, Dqn_usize dest_size);
DQN_API Dqn_usize Dqn_Bin_HexToBytes (Dqn_Str8 hex, void *dest, Dqn_usize dest_size);
DQN_API Dqn_Str8 Dqn_Bin_HexToBytesArena (Dqn_Arena *arena, Dqn_Str8 hex);
#endif // !defined(DQN_NO_BIN)
// NOTE: [$BSEA] Dqn_BinarySearch ==================================================================
@ -220,17 +242,26 @@ template <typename T>
using Dqn_BinarySearchLessThanProc = bool(T const &lhs, T const &rhs);
template <typename T>
DQN_FORCE_INLINE bool Dqn_BinarySearch_DefaultLessThan(T const &lhs, T const &rhs);
bool Dqn_BinarySearch_DefaultLessThan(T const &lhs, T const &rhs);
// TODO(doyle): Implement lower/upper bound searching
enum Dqn_BinarySearchType
{
/// Index of the match. If no match is found, found is set to false and the
/// index is set to 0
// Index of the match. If no match is found, found is set to false and the
// index is set to the index where the match should be inserted/exist, if
// it were in the array (in practice this turns out to be the first or
// [last index + 1] of the array).
Dqn_BinarySearchType_Match,
/// Index after the match. If no match is found, found is set to false and
/// the index is set to one past the closest match.
Dqn_BinarySearchType_OnePastMatch,
// Index of the first element in the array that is `<= find`. If no such
// item is found or the array is empty, then, the index is set to the array
// size and found is set to `false`.
Dqn_BinarySearchType_LowerBound,
// Index of the first element in the array that is `> find`. If no such
// item is found or the array is empty, then, the index is set to the array
// size and found is set to `false`.
Dqn_BinarySearchType_UpperBound,
};
struct Dqn_BinarySearchResult
@ -240,15 +271,14 @@ struct Dqn_BinarySearchResult
};
template <typename T>
Dqn_BinarySearchResult
Dqn_BinarySearch(T const *array,
Dqn_usize array_size,
T const &find,
Dqn_BinarySearchType type = Dqn_BinarySearchType_Match,
Dqn_BinarySearchLessThanProc<T> less_than = Dqn_BinarySearch_DefaultLessThan);
Dqn_BinarySearchResult Dqn_BinarySearch(T const *array,
Dqn_usize array_size,
T const &find,
Dqn_BinarySearchType type = Dqn_BinarySearchType_Match,
Dqn_BinarySearchLessThanProc<T> less_than = Dqn_BinarySearch_DefaultLessThan);
template <typename T> DQN_FORCE_INLINE bool Dqn_BinarySearch_DefaultLessThan(T const &lhs, T const &rhs)
template <typename T>
bool Dqn_BinarySearch_DefaultLessThan(T const &lhs, T const &rhs)
{
bool result = lhs < rhs;
return result;
@ -256,37 +286,47 @@ template <typename T> DQN_FORCE_INLINE bool Dqn_BinarySearch_DefaultLessThan(T c
template <typename T>
Dqn_BinarySearchResult
Dqn_BinarySearch(T const *array,
Dqn_usize array_size,
T const &find,
Dqn_BinarySearchType type,
Dqn_BinarySearchLessThanProc<T> less_than)
Dqn_BinarySearch(T const *array,
Dqn_usize array_size,
T const &find,
Dqn_BinarySearchType type,
Dqn_BinarySearchLessThanProc<T> less_than)
{
Dqn_BinarySearchResult result = {};
Dqn_usize head = 0;
Dqn_usize tail = array_size - 1;
if (array && array_size > 0) {
while (!result.found && head <= tail) {
Dqn_usize mid = (head + tail) / 2;
T const &value = array[mid];
if (less_than(find, value)) {
tail = mid - 1;
if (mid == 0)
break;
} else if (less_than(value, find)) {
head = mid + 1;
} else {
result.found = true;
result.index = mid;
}
}
if (!array || array_size <= 0)
return result;
T const *end = array + array_size;
T const *first = array;
T const *last = end;
while (first != last) {
Dqn_usize count = last - first;
T const *it = first + (count / 2);
bool advance_first = false;
if (type == Dqn_BinarySearchType_UpperBound)
advance_first = !less_than(find, it[0]);
else
advance_first = less_than(it[0], find);
if (advance_first)
first = it + 1;
else
last = it;
}
if (type == Dqn_BinarySearchType_OnePastMatch)
result.index = result.found ? result.index + 1 : tail + 1;
else
DQN_ASSERT(type == Dqn_BinarySearchType_Match);
switch (type) {
case Dqn_BinarySearchType_Match: {
result.found = first != end && !less_than(find, *first);
} break;
case Dqn_BinarySearchType_LowerBound: /*FALLTHRU*/
case Dqn_BinarySearchType_UpperBound: {
result.found = first != end;
} break;
}
result.index = first - array;
return result;
}
@ -453,20 +493,20 @@ DQN_API uint64_t Dqn_Safe_SaturateCastIntToU64 (int val);
// @return The size of the string written to the buffer *not* including the
// null-terminator.
//
// @proc Dqn_U64ToString
// @proc Dqn_U64ToStr8
// @desc Convert a 64 bit unsigned value to its string representation.
// @param[in] val Value to convert into a string
// @param[in] separator The separator to insert every 3 digits. Set this to
// 0 if no separator is desired.
struct Dqn_U64String
struct Dqn_U64Str8
{
char data[27+1]; // NOTE(dqn): 27 is the maximum size of uint64_t including a separtor
uint8_t size;
};
DQN_API int Dqn_SNPrintFDotTruncate(char *buffer, int size, char const *fmt, ...);
DQN_API Dqn_U64String Dqn_U64ToString (uint64_t val, char separator);
DQN_API int Dqn_SNPrintFDotTruncate(char *buffer, int size, DQN_FMT_ATTRIB char const *fmt, ...);
DQN_API Dqn_U64Str8 Dqn_U64ToStr8 (uint64_t val, char separator);
#if !defined(DQN_NO_PROFILER)
// NOTE: [$PROF] Dqn_Profiler ======================================================================
@ -524,29 +564,29 @@ struct Dqn_ProfilerAnchor
// time spent in children functions that we call that are also being
// profiled. If we recursively call into ourselves, the time we spent in
// our function is accumulated.
uint64_t tsc_inclusive;
uint64_t tsc_exclusive;
uint16_t hit_count;
Dqn_String8 name;
uint64_t tsc_inclusive;
uint64_t tsc_exclusive;
uint16_t hit_count;
Dqn_Str8 name;
};
struct Dqn_ProfilerZone
{
uint16_t anchor_index;
uint64_t begin_tsc;
uint16_t parent_zone;
uint64_t elapsed_tsc_at_zone_start;
uint16_t anchor_index;
uint64_t begin_tsc;
uint16_t parent_zone;
uint64_t elapsed_tsc_at_zone_start;
};
#if defined(__cplusplus)
struct Dqn_ProfilerZoneScope
{
Dqn_ProfilerZoneScope(Dqn_String8 name, uint16_t anchor_index);
Dqn_ProfilerZoneScope(Dqn_Str8 name, uint16_t anchor_index);
~Dqn_ProfilerZoneScope();
Dqn_ProfilerZone zone;
};
#define Dqn_Profiler_ZoneScope(name) auto DQN_UNIQUE_NAME(profile_zone_) = Dqn_ProfilerZoneScope(DQN_STRING8(name), __COUNTER__ + 1)
#define Dqn_Profiler_ZoneScopeWithIndex(name, anchor_index) auto DQN_UNIQUE_NAME(profile_zone_) = Dqn_ProfilerZoneScope(DQN_STRING8(name), anchor_index)
#define Dqn_Profiler_ZoneScope(name) auto DQN_UNIQUE_NAME(profile_zone_) = Dqn_ProfilerZoneScope(DQN_STR8(name), __COUNTER__ + 1)
#define Dqn_Profiler_ZoneScopeWithIndex(name, anchor_index) auto DQN_UNIQUE_NAME(profile_zone_) = Dqn_ProfilerZoneScope(DQN_STR8(name), anchor_index)
#endif
enum Dqn_ProfilerAnchorBuffer
@ -566,10 +606,10 @@ struct Dqn_Profiler
#define Dqn_Profiler_BeginZone(name) Dqn_Profiler_BeginZoneWithIndex(DQN_STRING8(name), __COUNTER__ + 1)
// NOTE: API =======================================================================================
Dqn_ProfilerZone Dqn_Profiler_BeginZoneWithIndex(Dqn_String8 name, uint16_t anchor_index);
Dqn_ProfilerZone Dqn_Profiler_BeginZoneWithIndex(Dqn_Str8 name, uint16_t anchor_index);
void Dqn_Profiler_EndZone (Dqn_ProfilerZone zone);
Dqn_ProfilerAnchor *Dqn_Profiler_AnchorBuffer (Dqn_ProfilerAnchorBuffer buffer);
void Dqn_Profiler_SwapAnchorBuffer (uint32_t anchor_count);
void Dqn_Profiler_SwapAnchorBuffer ();
void Dqn_Profiler_Dump (uint64_t tsc_per_second);
#endif // !defined(DQN_NO_PROFILER)
@ -596,7 +636,7 @@ struct Dqn_Library
{
bool lib_init; // True if the library has been initialised via `Dqn_Library_Init`
Dqn_TicketMutex lib_mutex;
Dqn_String8 exe_dir; // The directory of the current executable
Dqn_Str8 exe_dir; // The directory of the current executable
Dqn_Arena arena;
Dqn_ArenaCatalog arena_catalog;
@ -642,12 +682,18 @@ struct Dqn_Library
#endif
} extern *g_dqn_library;
enum Dqn_LibraryOnInit
{
Dqn_LibraryOnInit_Nil,
Dqn_LibraryOnInit_LogFeatures,
};
// NOTE: API =======================================================================================
DQN_API Dqn_Library *Dqn_Library_Init ();
DQN_API Dqn_Library *Dqn_Library_Init (Dqn_LibraryOnInit on_init);
DQN_API void Dqn_Library_SetPointer (Dqn_Library *library);
#if !defined(DQN_NO_PROFILER)
DQN_API void Dqn_Library_SetProfiler (Dqn_Profiler *profiler);
#endif
DQN_API void Dqn_Library_SetLogCallback (Dqn_LogProc *proc, void *user_data);
DQN_API void Dqn_Library_DumpThreadContextArenaStat(Dqn_String8 file_path);
DQN_API void Dqn_Library_DumpThreadContextArenaStat(Dqn_Str8 file_path);

View File

@ -43,6 +43,12 @@ DQN_API Dqn_V2I operator-(Dqn_V2I lhs, Dqn_V2I rhs)
return result;
}
DQN_API Dqn_V2I operator-(Dqn_V2I lhs)
{
Dqn_V2I result = Dqn_V2I_InitNx2(-lhs.x, -lhs.y);
return result;
}
DQN_API Dqn_V2I operator+(Dqn_V2I lhs, Dqn_V2I rhs)
{
Dqn_V2I result = Dqn_V2I_InitNx2(lhs.x + rhs.x, lhs.y + rhs.y);
@ -315,6 +321,12 @@ DQN_API Dqn_V2 operator-(Dqn_V2 lhs, Dqn_f32 rhs)
return result;
}
DQN_API Dqn_V2 operator-(Dqn_V2 lhs)
{
Dqn_V2 result = Dqn_V2_InitNx2(-lhs.x, -lhs.y);
return result;
}
DQN_API Dqn_V2 operator+(Dqn_V2 lhs, Dqn_V2 rhs)
{
Dqn_V2 result = Dqn_V2_InitNx2(lhs.x + rhs.x, lhs.y + rhs.y);
@ -405,12 +417,24 @@ DQN_API Dqn_V2 &operator-=(Dqn_V2 &lhs, Dqn_V2 rhs)
return lhs;
}
DQN_API Dqn_V2 &operator-=(Dqn_V2 &lhs, Dqn_f32 rhs)
{
lhs = lhs - rhs;
return lhs;
}
DQN_API Dqn_V2 &operator+=(Dqn_V2 &lhs, Dqn_V2 rhs)
{
lhs = lhs + rhs;
return lhs;
}
DQN_API Dqn_V2 &operator+=(Dqn_V2 &lhs, Dqn_f32 rhs)
{
lhs = lhs + rhs;
return lhs;
}
DQN_API Dqn_V2 Dqn_V2_Min(Dqn_V2 a, Dqn_V2 b)
{
Dqn_V2 result = Dqn_V2_InitNx2(DQN_MIN(a.x, b.x), DQN_MIN(a.y, b.y));
@ -431,31 +455,126 @@ DQN_API Dqn_V2 Dqn_V2_Abs(Dqn_V2 a)
DQN_API Dqn_f32 Dqn_V2_Dot(Dqn_V2 a, Dqn_V2 b)
{
// NOTE: Scalar projection of B onto A =========================================================
//
// Scalar projection calculates the signed distance between `b` and `a`
// where `a` is a unit vector then, the dot product calculates the projection
// of `b` onto the infinite line that the direction of `a` represents. This
// calculation is the signed distance.
//
// signed_distance = dot_product(a, b) = (a.x * b.x) + (a.y * b.y)
//
// Y
// ^ b
// | /|
// | / |
// | / |
// | / | Projection
// | / |
// |/ V
// +--->--------> X
// . a .
// . .
// |------| <- Calculated signed distance
//
// The signed-ness of the result indicates the relationship:
//
// Distance <0 means `b` is behind `a`
// Distance >0 means `b` is in-front of `a`
// Distance ==0 means `b` is perpendicular to `a`
//
// If `a` is not normalized then the signed-ness of the result still holds
// however result no longer represents the actual distance between the
// 2 objects. One of the vectors must be normalised (e.g. turned into a unit
// vector).
//
// NOTE: Vector projection =====================================================================
//
// Vector projection calculates the exact X,Y coordinates of where `b` meets
// `a` when it was projected. This is calculated by multipying the
// 'scalar projection' result by the unit vector of `a`
//
// vector_projection = a * signed_distance = a * dot_product(a, b)
Dqn_f32 result = (a.x * b.x) + (a.y * b.y);
return result;
}
DQN_API Dqn_f32 Dqn_V2_LengthSq(Dqn_V2 a, Dqn_V2 b)
DQN_API Dqn_f32 Dqn_V2_LengthSq_V2x2(Dqn_V2 lhs, Dqn_V2 rhs)
{
Dqn_f32 x_side = b.x - a.x;
Dqn_f32 y_side = b.y - a.y;
Dqn_f32 result = DQN_SQUARED(x_side) + DQN_SQUARED(y_side);
// NOTE: Pythagoras's theorem (a^2 + b^2 = c^2) without the square root
Dqn_f32 a = rhs.x - lhs.x;
Dqn_f32 b = rhs.y - lhs.y;
Dqn_f32 c_squared = DQN_SQUARED(a) + DQN_SQUARED(b);
Dqn_f32 result = c_squared;
return result;
}
DQN_API Dqn_f32 Dqn_V2_Length_V2x2(Dqn_V2 lhs, Dqn_V2 rhs)
{
Dqn_f32 result_squared = Dqn_V2_LengthSq_V2x2(lhs, rhs);
Dqn_f32 result = DQN_SQRTF(result_squared);
return result;
}
DQN_API Dqn_f32 Dqn_V2_LengthSq(Dqn_V2 lhs)
{
// NOTE: Pythagoras's theorem without the square root
Dqn_f32 c_squared = DQN_SQUARED(lhs.x) + DQN_SQUARED(lhs.y);
Dqn_f32 result = c_squared;
return result;
}
DQN_API Dqn_f32 Dqn_V2_Length(Dqn_V2 lhs)
{
Dqn_f32 c_squared = Dqn_V2_LengthSq(lhs);
Dqn_f32 result = DQN_SQRTF(c_squared);
return result;
}
DQN_API Dqn_V2 Dqn_V2_Normalise(Dqn_V2 a)
{
Dqn_f32 length_sq = DQN_SQUARED(a.x) + DQN_SQUARED(a.y);
Dqn_f32 length = DQN_SQRTF(length_sq);
Dqn_V2 result = a / length;
Dqn_f32 length = Dqn_V2_Length(a);
Dqn_V2 result = a / length;
return result;
}
DQN_API Dqn_V2 Dqn_V2_Perpendicular(Dqn_V2 a)
{
// NOTE: Matrix form of a 2D vector can be defined as
//
// x' = x cos(t) - y sin(t)
// y' = x sin(t) + y cos(t)
//
// Calculate a line perpendicular to a vector means rotating the vector by
// 90 degrees
//
// x' = x cos(90) - y sin(90)
// y' = x sin(90) + y cos(90)
//
// Where `cos(90) = 0` and `sin(90) = 1` then,
//
// x' = -y
// y' = +x
Dqn_V2 result = Dqn_V2_InitNx2(-a.y, a.x);
return result;
}
DQN_API Dqn_V2 Dqn_V2_Reflect(Dqn_V2 in, Dqn_V2 surface)
{
Dqn_V2 normal = Dqn_V2_Perpendicular(surface);
Dqn_V2 normal_norm = Dqn_V2_Normalise(normal);
Dqn_f32 signed_dist = Dqn_V2_Dot(in, normal_norm);
Dqn_V2 result = Dqn_V2_InitNx2(in.x, in.y + (-signed_dist * 2.f));
return result;
}
DQN_API Dqn_f32 Dqn_V2_Area(Dqn_V2 a)
{
Dqn_f32 result = a.w * a.h;
return result;
}
#endif // !defined(DQN_NO_V2)
#if !defined(DQN_NO_V3)
@ -502,6 +621,12 @@ DQN_API Dqn_V3 operator-(Dqn_V3 lhs, Dqn_V3 rhs)
return result;
}
DQN_API Dqn_V3 operator-(Dqn_V3 lhs)
{
Dqn_V3 result = Dqn_V3_InitNx3(-lhs.x, -lhs.y, -lhs.z);
return result;
}
DQN_API Dqn_V3 operator+(Dqn_V3 lhs, Dqn_V3 rhs)
{
Dqn_V3 result = Dqn_V3_InitNx3(lhs.x + rhs.x, lhs.y + rhs.y, lhs.z + rhs.z);
@ -657,6 +782,12 @@ DQN_API Dqn_V4 operator-(Dqn_V4 lhs, Dqn_V4 rhs)
return result;
}
DQN_API Dqn_V4 operator-(Dqn_V4 lhs)
{
Dqn_V4 result = Dqn_V4_InitNx4(-lhs.x, -lhs.y, -lhs.z, -lhs.w);
return result;
}
DQN_API Dqn_V4 operator+(Dqn_V4 lhs, Dqn_V4 rhs)
{
Dqn_V4 result = Dqn_V4_InitNx4(lhs.x + rhs.x, lhs.y + rhs.y, lhs.z + rhs.z, lhs.w + rhs.w);
@ -957,16 +1088,16 @@ DQN_API Dqn_M4 Dqn_M4_DivF(Dqn_M4 lhs, Dqn_f32 rhs)
return result;
}
#if !defined(DQN_NO_FSTRING8)
DQN_API Dqn_FString8<256> Dqn_M4_ColumnMajorString(Dqn_M4 mat)
#if !defined(DQN_NO_FSTR8)
DQN_API Dqn_FStr8<256> Dqn_M4_ColumnMajorString(Dqn_M4 mat)
{
Dqn_FString8<256> result = {};
Dqn_FStr8<256> result = {};
for (int row = 0; row < 4; row++) {
for (int it = 0; it < 4; it++) {
if (it == 0) Dqn_FString8_Append(&result, DQN_STRING8("|"));
Dqn_FString8_AppendF(&result, "%.5f", mat.columns[it][row]);
if (it != 3) Dqn_FString8_Append(&result, DQN_STRING8(", "));
else Dqn_FString8_Append(&result, DQN_STRING8("|\n"));
if (it == 0) Dqn_FStr8_Append(&result, DQN_STR8("|"));
Dqn_FStr8_AppendF(&result, "%.5f", mat.columns[it][row]);
if (it != 3) Dqn_FStr8_Append(&result, DQN_STR8(", "));
else Dqn_FStr8_Append(&result, DQN_STR8("|\n"));
}
}
@ -975,6 +1106,94 @@ DQN_API Dqn_FString8<256> Dqn_M4_ColumnMajorString(Dqn_M4 mat)
#endif
#endif // !defined(DQN_M4)
// NOTE: [$M2x3] Dqn_M2x3 ==========================================================================
DQN_API bool operator==(Dqn_M2x3 const &lhs, Dqn_M2x3 const &rhs)
{
bool result = DQN_MEMCMP(lhs.e, rhs.e, sizeof(lhs.e[0]) * DQN_ARRAY_UCOUNT(lhs.e)) == 0;
return result;
}
DQN_API bool operator!=(Dqn_M2x3 const &lhs, Dqn_M2x3 const &rhs)
{
bool result = !(lhs == rhs);
return result;
}
DQN_API Dqn_M2x3 Dqn_M2x3_Identity()
{
Dqn_M2x3 result = {{
1, 0, 0,
0, 1, 0,
}};
return result;
}
DQN_API Dqn_M2x3 Dqn_M2x3_Translate(Dqn_V2 offset)
{
Dqn_M2x3 result = {{
1, 0, offset.x,
0, 1, offset.y,
}};
return result;
}
DQN_API Dqn_M2x3 Dqn_M2x3_Scale(Dqn_V2 scale)
{
Dqn_M2x3 result = {{
scale.x, 0, 0,
0, scale.y, 0,
}};
return result;
}
DQN_API Dqn_M2x3 Dqn_M2x3_Rotate(Dqn_f32 radians)
{
Dqn_M2x3 result = {{
DQN_COSF(radians), DQN_SINF(radians), 0,
-DQN_SINF(radians), DQN_COSF(radians), 0,
}};
return result;
}
DQN_API Dqn_M2x3 Dqn_M2x3_Mul(Dqn_M2x3 m1, Dqn_M2x3 m2)
{
// NOTE: Ordinarily you can't multiply M2x3 with M2x3 because column count
// (3) != row count (2). We pretend we have two 3x3 matrices with the last
// row set to [0 0 1] and perform a 3x3 matrix multiply.
//
// | (0)a (1)b (2)c | | (0)g (1)h (2)i |
// | (3)d (4)e (5)f | x | (3)j (4)k (5)l |
// | (6)0 (7)0 (8)1 | | (6)0 (7)0 (8)1 |
Dqn_M2x3 result = {{
m1.e[0]*m2.e[0] + m1.e[1]*m2.e[3], // a*g + b*j + c*0[omitted],
m1.e[0]*m2.e[1] + m1.e[1]*m2.e[4], // a*h + b*k + c*0[omitted],
m1.e[0]*m2.e[2] + m1.e[1]*m2.e[5] + m1.e[2], // a*i + b*l + c*1,
m1.e[3]*m2.e[0] + m1.e[4]*m2.e[3], // d*g + e*j + f*0[omitted],
m1.e[3]*m2.e[1] + m1.e[4]*m2.e[4], // d*h + e*k + f*0[omitted],
m1.e[3]*m2.e[2] + m1.e[4]*m2.e[5] + m1.e[5], // d*i + e*l + f*1,
}};
return result;
}
DQN_API Dqn_V2 Dqn_M2x3_MulV2(Dqn_M2x3 m1, Dqn_V2 v2)
{
// NOTE: Ordinarily you can't multiply M2x3 with V2 because column count (3)
// != row count (2). We pretend we have a V3 with `z` set to `1`.
//
// | (0)a (1)b (2)c | | x |
// | (3)d (4)e (5)f | x | y |
// | 1 |
Dqn_V2 result = {{
m1.e[0]*v2.x + m1.e[1]*v2.y + m1.e[2], // a*x + b*y + c*1
m1.e[3]*v2.x + m1.e[4]*v2.y + m1.e[5], // d*x + e*y + f*1
}};
return result;
}
#if !defined(DQN_NO_RECT)
// NOTE: [$RECT] Dqn_Rect ==========================================================================
DQN_API bool operator==(const Dqn_Rect& lhs, const Dqn_Rect& rhs)
@ -1007,6 +1226,22 @@ DQN_API bool Dqn_Rect_ContainsRect(Dqn_Rect a, Dqn_Rect b)
return result;
}
DQN_API Dqn_Rect Dqn_Rect_Expand(Dqn_Rect a, Dqn_f32 amount)
{
Dqn_Rect result = a;
result.pos -= amount;
result.size += (amount * 2.f);
return result;
}
DQN_API Dqn_Rect Dqn_Rect_ExpandV2(Dqn_Rect a, Dqn_V2 amount)
{
Dqn_Rect result = a;
result.pos -= amount;
result.size += (amount * 2.f);
return result;
}
DQN_API bool Dqn_Rect_Intersects(Dqn_Rect a, Dqn_Rect b)
{
Dqn_V2 a_min = a.pos;
@ -1062,6 +1297,12 @@ DQN_API Dqn_RectMinMax Dqn_Rect_MinMax(Dqn_Rect a)
return result;
}
DQN_API Dqn_f32 Dqn_Rect_Area(Dqn_Rect a)
{
Dqn_f32 result = a.size.w * a.size.h;
return result;
}
DQN_API Dqn_Rect Dqn_Rect_CutLeftClip(Dqn_Rect *rect, Dqn_f32 amount, Dqn_RectCutClip clip)
{
Dqn_f32 min_x = rect->pos.x;
@ -1126,8 +1367,71 @@ DQN_API Dqn_Rect Dqn_RectCut_Cut(Dqn_RectCut rect_cut, Dqn_V2 size, Dqn_RectCutC
return result;
}
DQN_API Dqn_V2 Dqn_Rect_InterpolatedPoint(Dqn_Rect rect, Dqn_V2 t01)
{
Dqn_V2 result = Dqn_V2_InitNx2(rect.pos.w + (rect.size.w * t01.x),
rect.pos.h + (rect.size.h * t01.y));
return result;
}
DQN_API Dqn_V2 Dqn_Rect_TopLeft(Dqn_Rect rect)
{
Dqn_V2 result = Dqn_Rect_InterpolatedPoint(rect, Dqn_V2_InitNx2(0, 0));
return result;
}
DQN_API Dqn_V2 Dqn_Rect_TopRight(Dqn_Rect rect)
{
Dqn_V2 result = Dqn_Rect_InterpolatedPoint(rect, Dqn_V2_InitNx2(1, 0));
return result;
}
DQN_API Dqn_V2 Dqn_Rect_BottomLeft(Dqn_Rect rect)
{
Dqn_V2 result = Dqn_Rect_InterpolatedPoint(rect, Dqn_V2_InitNx2(0, 1));
return result;
}
DQN_API Dqn_V2 Dqn_Rect_BottomRight(Dqn_Rect rect)
{
Dqn_V2 result = Dqn_Rect_InterpolatedPoint(rect, Dqn_V2_InitNx2(1, 1));
return result;
}
#endif // !defined(DQN_NO_RECT)
// NOTE: [$MATH] Raycast ===========================================================================
DQN_API Dqn_RaycastLineIntersectV2Result Dqn_Raycast_LineIntersectV2(Dqn_V2 origin_a, Dqn_V2 dir_a, Dqn_V2 origin_b, Dqn_V2 dir_b)
{
// NOTE: Parametric equation of a line
//
// p = o + (t*d)
//
// - o is the starting 2d point
// - d is the direction of the line
// - t is a scalar that scales along the direction of the point
//
// To determine if a ray intersections a ray, we want to solve
//
// (o_a + (t_a * d_a)) = (o_b + (t_b * d_b))
//
// Where '_a' and '_b' represent the 1st and 2nd point's origin, direction
// and 't' components respectively. This is 2 equations with 2 unknowns
// (`t_a` and `t_b`) which we can solve for by expressing the equation in
// terms of `t_a` and `t_b`.
//
// Working that math out produces the formula below for 't'.
Dqn_RaycastLineIntersectV2Result result = {};
Dqn_f32 denominator = ((dir_b.y * dir_a.x) - (dir_b.x * dir_a.y));
if (denominator != 0.0f) {
result.t_a = (((origin_a.y - origin_b.y) * dir_b.x) + ((origin_b.x - origin_a.x) * dir_b.y)) / denominator;
result.t_b = (((origin_a.y - origin_b.y) * dir_a.x) + ((origin_b.x - origin_a.x) * dir_a.y)) / denominator;
result.hit = true;
}
return result;
}
// NOTE: [$MATH] Other =============================================================================
DQN_API Dqn_V2 Dqn_Lerp_V2(Dqn_V2 a, Dqn_f32 t, Dqn_V2 b)
{

View File

@ -10,8 +10,9 @@ union Dqn_V2I
int32_t data[2];
};
#define Dqn_V2I_InitNx1(x) DQN_LITERAL(Dqn_V2I){{(int32_t)(x), (int32_t)(x)}}
#define Dqn_V2I_InitNx2(x, y) DQN_LITERAL(Dqn_V2I){{(int32_t)(x), (int32_t)(y)}}
#define Dqn_V2I_InitNx1(x) DQN_LITERAL(Dqn_V2I){{(int32_t)(x), (int32_t)(x)}}
#define Dqn_V2I_InitNx2(x, y) DQN_LITERAL(Dqn_V2I){{(int32_t)(x), (int32_t)(y)}}
#define Dqn_V2I_InitV2(xy) DQN_LITERAL(Dqn_V2I){{(int32_t)(xy).x, (int32_t)(xy).y}}
DQN_API bool operator!=(Dqn_V2I lhs, Dqn_V2I rhs);
DQN_API bool operator==(Dqn_V2I lhs, Dqn_V2I rhs);
@ -20,6 +21,7 @@ DQN_API bool operator<=(Dqn_V2I lhs, Dqn_V2I rhs);
DQN_API bool operator< (Dqn_V2I lhs, Dqn_V2I rhs);
DQN_API bool operator> (Dqn_V2I lhs, Dqn_V2I rhs);
DQN_API Dqn_V2I operator- (Dqn_V2I lhs, Dqn_V2I rhs);
DQN_API Dqn_V2I operator- (Dqn_V2I lhs);
DQN_API Dqn_V2I operator+ (Dqn_V2I lhs, Dqn_V2I rhs);
DQN_API Dqn_V2I operator* (Dqn_V2I lhs, Dqn_V2I rhs);
DQN_API Dqn_V2I operator* (Dqn_V2I lhs, Dqn_f32 rhs);
@ -76,8 +78,11 @@ union Dqn_V2
Dqn_f32 data[2];
};
#define Dqn_V2_InitNx1(x) DQN_LITERAL(Dqn_V2){{(Dqn_f32)(x), (Dqn_f32)(x)}}
#define Dqn_V2_InitNx2(x, y) DQN_LITERAL(Dqn_V2){{(Dqn_f32)(x), (Dqn_f32)(y)}}
#define Dqn_V2_Zero DQN_LITERAL(Dqn_V2){{(Dqn_f32)(0), (Dqn_f32)(0)}}
#define Dqn_V2_One DQN_LITERAL(Dqn_V2){{(Dqn_f32)(1), (Dqn_f32)(1)}}
#define Dqn_V2_InitNx1(x) DQN_LITERAL(Dqn_V2){{(Dqn_f32)(x), (Dqn_f32)(x)}}
#define Dqn_V2_InitNx2(x, y) DQN_LITERAL(Dqn_V2){{(Dqn_f32)(x), (Dqn_f32)(y)}}
#define Dqn_V2_InitV2I(xy) DQN_LITERAL(Dqn_V2){{(Dqn_f32)(xy).x, (Dqn_f32)(xy).y}}
DQN_API bool operator!=(Dqn_V2 lhs, Dqn_V2 rhs);
DQN_API bool operator==(Dqn_V2 lhs, Dqn_V2 rhs);
@ -87,6 +92,7 @@ DQN_API bool operator< (Dqn_V2 lhs, Dqn_V2 rhs);
DQN_API bool operator> (Dqn_V2 lhs, Dqn_V2 rhs);
DQN_API Dqn_V2 operator- (Dqn_V2 lhs, Dqn_V2 rhs);
DQN_API Dqn_V2 operator- (Dqn_V2 lhs, Dqn_f32 rhs);
DQN_API Dqn_V2 operator- (Dqn_V2 lhs);
DQN_API Dqn_V2 operator+ (Dqn_V2 lhs, Dqn_V2 rhs);
DQN_API Dqn_V2 operator+ (Dqn_V2 lhs, Dqn_f32 rhs);
DQN_API Dqn_V2 operator* (Dqn_V2 lhs, Dqn_V2 rhs);
@ -102,16 +108,23 @@ DQN_API Dqn_V2 &operator/=(Dqn_V2& lhs, Dqn_V2 rhs);
DQN_API Dqn_V2 &operator/=(Dqn_V2& lhs, Dqn_f32 rhs);
DQN_API Dqn_V2 &operator/=(Dqn_V2& lhs, int32_t rhs);
DQN_API Dqn_V2 &operator-=(Dqn_V2& lhs, Dqn_V2 rhs);
DQN_API Dqn_V2 &operator-=(Dqn_V2& lhs, Dqn_f32 rhs);
DQN_API Dqn_V2 &operator+=(Dqn_V2& lhs, Dqn_V2 rhs);
DQN_API Dqn_V2 &operator+=(Dqn_V2& lhs, Dqn_f32 rhs);
DQN_API Dqn_V2I Dqn_V2_ToV2I(Dqn_V2 a);
DQN_API Dqn_V2 Dqn_V2_Min(Dqn_V2 a, Dqn_V2 b);
DQN_API Dqn_V2 Dqn_V2_Max(Dqn_V2 a, Dqn_V2 b);
DQN_API Dqn_V2 Dqn_V2_Abs(Dqn_V2 a);
DQN_API Dqn_f32 Dqn_V2_Dot(Dqn_V2 a, Dqn_V2 b);
DQN_API Dqn_f32 Dqn_V2_LengthSq(Dqn_V2 a, Dqn_V2 b);
DQN_API Dqn_V2 Dqn_V2_Normalise(Dqn_V2 a);
DQN_API Dqn_V2I Dqn_V2_ToV2I (Dqn_V2 a);
DQN_API Dqn_V2 Dqn_V2_Min (Dqn_V2 a, Dqn_V2 b);
DQN_API Dqn_V2 Dqn_V2_Max (Dqn_V2 a, Dqn_V2 b);
DQN_API Dqn_V2 Dqn_V2_Abs (Dqn_V2 a);
DQN_API Dqn_f32 Dqn_V2_Dot (Dqn_V2 a, Dqn_V2 b);
DQN_API Dqn_f32 Dqn_V2_LengthSq_V2x2(Dqn_V2 lhs, Dqn_V2 rhs);
DQN_API Dqn_f32 Dqn_V2_Length_V2x2 (Dqn_V2 lhs, Dqn_V2 rhs);
DQN_API Dqn_f32 Dqn_V2_LengthSq (Dqn_V2 lhs);
DQN_API Dqn_f32 Dqn_V2_Length (Dqn_V2 lhs);
DQN_API Dqn_V2 Dqn_V2_Normalise (Dqn_V2 a);
DQN_API Dqn_V2 Dqn_V2_Perpendicular(Dqn_V2 a);
DQN_API Dqn_V2 Dqn_V2_Reflect (Dqn_V2 in, Dqn_V2 surface);
DQN_API Dqn_f32 Dqn_V2_Area (Dqn_V2 a);
#endif // !defined(DQN_NO_V2)
#if !defined(DQN_NO_V3)
@ -134,6 +147,7 @@ DQN_API bool operator<=(Dqn_V3 lhs, Dqn_V3 rhs);
DQN_API bool operator< (Dqn_V3 lhs, Dqn_V3 rhs);
DQN_API bool operator> (Dqn_V3 lhs, Dqn_V3 rhs);
DQN_API Dqn_V3 operator- (Dqn_V3 lhs, Dqn_V3 rhs);
DQN_API Dqn_V3 operator- (Dqn_V3 lhs);
DQN_API Dqn_V3 operator+ (Dqn_V3 lhs, Dqn_V3 rhs);
DQN_API Dqn_V3 operator* (Dqn_V3 lhs, Dqn_V3 rhs);
DQN_API Dqn_V3 operator* (Dqn_V3 lhs, Dqn_f32 rhs);
@ -163,30 +177,33 @@ union Dqn_V4
struct { Dqn_f32 r, g, b, a; };
#if !defined(DQN_NO_V3)
Dqn_V3 rgb;
Dqn_V3 xyz;
#endif
Dqn_f32 data[4];
};
#define Dqn_V4_InitNx1(x) DQN_LITERAL(Dqn_V4){{(Dqn_f32)(x), (Dqn_f32)(x), (Dqn_f32)(x), (Dqn_f32)(x)}}
#define Dqn_V4_InitNx4(x, y, z, w) DQN_LITERAL(Dqn_V4){{(Dqn_f32)(x), (Dqn_f32)(y), (Dqn_f32)(z), (Dqn_f32)(w)}}
#define Dqn_V4_InitNx1(x) DQN_LITERAL(Dqn_V4){{(Dqn_f32)(x), (Dqn_f32)(x), (Dqn_f32)(x), (Dqn_f32)(x)}}
#define Dqn_V4_InitNx4(x, y, z, w) DQN_LITERAL(Dqn_V4){{(Dqn_f32)(x), (Dqn_f32)(y), (Dqn_f32)(z), (Dqn_f32)(w)}}
#define Dqn_V4_Init_V3x1_Nx1(xyz, w) DQN_LITERAL(Dqn_V4){{xyz.x, xyz.y, xyz.z, w}}
bool operator!=(Dqn_V4 lhs, Dqn_V4 rhs);
bool operator==(Dqn_V4 lhs, Dqn_V4 rhs);
bool operator>=(Dqn_V4 lhs, Dqn_V4 rhs);
bool operator<=(Dqn_V4 lhs, Dqn_V4 rhs);
bool operator< (Dqn_V4 lhs, Dqn_V4 rhs);
bool operator> (Dqn_V4 lhs, Dqn_V4 rhs);
Dqn_V4 operator- (Dqn_V4 lhs, Dqn_V4 rhs);
Dqn_V4 operator+ (Dqn_V4 lhs, Dqn_V4 rhs);
Dqn_V4 operator* (Dqn_V4 lhs, Dqn_V4 rhs);
Dqn_V4 operator* (Dqn_V4 lhs, Dqn_f32 rhs);
Dqn_V4 operator* (Dqn_V4 lhs, int32_t rhs);
Dqn_V4 operator/ (Dqn_V4 lhs, Dqn_f32 rhs);
Dqn_V4 &operator*=(Dqn_V4 &lhs, Dqn_V4 rhs);
Dqn_V4 &operator*=(Dqn_V4 &lhs, Dqn_f32 rhs);
Dqn_V4 &operator*=(Dqn_V4 &lhs, int32_t rhs);
Dqn_V4 &operator-=(Dqn_V4 &lhs, Dqn_V4 rhs);
Dqn_V4 &operator+=(Dqn_V4 &lhs, Dqn_V4 rhs);
DQN_API bool operator!=(Dqn_V4 lhs, Dqn_V4 rhs);
DQN_API bool operator==(Dqn_V4 lhs, Dqn_V4 rhs);
DQN_API bool operator>=(Dqn_V4 lhs, Dqn_V4 rhs);
DQN_API bool operator<=(Dqn_V4 lhs, Dqn_V4 rhs);
DQN_API bool operator< (Dqn_V4 lhs, Dqn_V4 rhs);
DQN_API bool operator> (Dqn_V4 lhs, Dqn_V4 rhs);
DQN_API Dqn_V4 operator- (Dqn_V4 lhs, Dqn_V4 rhs);
DQN_API Dqn_V4 operator- (Dqn_V4 lhs);
DQN_API Dqn_V4 operator+ (Dqn_V4 lhs, Dqn_V4 rhs);
DQN_API Dqn_V4 operator* (Dqn_V4 lhs, Dqn_V4 rhs);
DQN_API Dqn_V4 operator* (Dqn_V4 lhs, Dqn_f32 rhs);
DQN_API Dqn_V4 operator* (Dqn_V4 lhs, int32_t rhs);
DQN_API Dqn_V4 operator/ (Dqn_V4 lhs, Dqn_f32 rhs);
DQN_API Dqn_V4 &operator*=(Dqn_V4 &lhs, Dqn_V4 rhs);
DQN_API Dqn_V4 &operator*=(Dqn_V4 &lhs, Dqn_f32 rhs);
DQN_API Dqn_V4 &operator*=(Dqn_V4 &lhs, int32_t rhs);
DQN_API Dqn_V4 &operator-=(Dqn_V4 &lhs, Dqn_V4 rhs);
DQN_API Dqn_V4 &operator+=(Dqn_V4 &lhs, Dqn_V4 rhs);
#endif // !defined(DQN_NO_V4)
#if !defined(DQN_NO_M4)
@ -217,11 +234,26 @@ DQN_API Dqn_M4 Dqn_M4_SubF(Dqn_M4 lhs, Dqn_f32 rhs);
DQN_API Dqn_M4 Dqn_M4_MulF(Dqn_M4 lhs, Dqn_f32 rhs);
DQN_API Dqn_M4 Dqn_M4_DivF(Dqn_M4 lhs, Dqn_f32 rhs);
#if !defined(DQN_NO_FSTRING8)
DQN_API Dqn_FString8<256> Dqn_M4_ColumnMajorString(Dqn_M4 mat);
#if !defined(DQN_NO_FSTR8)
DQN_API Dqn_FStr8<256> Dqn_M4_ColumnMajorString(Dqn_M4 mat);
#endif
#endif // !defined(DQN_M4)
union Dqn_M2x3
{
Dqn_f32 e[6];
Dqn_f32 row[2][3];
};
DQN_API bool operator==(Dqn_M2x3 const &lhs, Dqn_M2x3 const &rhs);
DQN_API bool operator!=(Dqn_M2x3 const &lhs, Dqn_M2x3 const &rhs);
DQN_API Dqn_M2x3 Dqn_M2x3_Identity ();
DQN_API Dqn_M2x3 Dqn_M2x3_Translate(Dqn_V2 offset);
DQN_API Dqn_M2x3 Dqn_M2x3_Scale (Dqn_V2 scale);
DQN_API Dqn_M2x3 Dqn_M2x3_Rotate (Dqn_f32 radians);
DQN_API Dqn_M2x3 Dqn_M2x3_Mul (Dqn_M2x3 m1, Dqn_M2x3 m2);
DQN_API Dqn_V2 Dqn_M2x3_MulV2 (Dqn_M2x3 m1, Dqn_V2 v2);
// NOTE: [$RECT] Dqn_Rect ==========================================================================
#if !defined(DQN_NO_RECT)
#if defined(DQN_NO_V2)
@ -241,14 +273,22 @@ struct Dqn_RectMinMax
#define Dqn_Rect_InitV2x2(pos, size) DQN_LITERAL(Dqn_Rect){(pos), (size)}
#define Dqn_Rect_InitNx4(pos_x, pos_y, size_w, size_h) DQN_LITERAL(Dqn_Rect){DQN_LITERAL(Dqn_V2){{pos_x, pos_y}}, DQN_LITERAL(Dqn_V2){{size_w, size_h}}}
DQN_API bool operator== (const Dqn_Rect& lhs, const Dqn_Rect& rhs);
DQN_API Dqn_V2 Dqn_Rect_Center (Dqn_Rect rect);
DQN_API bool Dqn_Rect_ContainsPoint(Dqn_Rect rect, Dqn_V2 p);
DQN_API bool Dqn_Rect_ContainsRect (Dqn_Rect a, Dqn_Rect b);
DQN_API bool Dqn_Rect_Intersects (Dqn_Rect a, Dqn_Rect b);
DQN_API Dqn_Rect Dqn_Rect_Intersection (Dqn_Rect a, Dqn_Rect b);
DQN_API Dqn_Rect Dqn_Rect_Union (Dqn_Rect a, Dqn_Rect b);
DQN_API Dqn_RectMinMax Dqn_Rect_MinMax (Dqn_Rect a);
DQN_API bool operator== (const Dqn_Rect& lhs, const Dqn_Rect& rhs);
DQN_API Dqn_V2 Dqn_Rect_Center (Dqn_Rect rect);
DQN_API bool Dqn_Rect_ContainsPoint (Dqn_Rect rect, Dqn_V2 p);
DQN_API bool Dqn_Rect_ContainsRect (Dqn_Rect a, Dqn_Rect b);
DQN_API Dqn_Rect Dqn_Rect_Expand (Dqn_Rect a, Dqn_f32 amount);
DQN_API Dqn_Rect Dqn_Rect_ExpandV2 (Dqn_Rect a, Dqn_V2 amount);
DQN_API bool Dqn_Rect_Intersects (Dqn_Rect a, Dqn_Rect b);
DQN_API Dqn_Rect Dqn_Rect_Intersection (Dqn_Rect a, Dqn_Rect b);
DQN_API Dqn_Rect Dqn_Rect_Union (Dqn_Rect a, Dqn_Rect b);
DQN_API Dqn_RectMinMax Dqn_Rect_MinMax (Dqn_Rect a);
DQN_API Dqn_f32 Dqn_Rect_Area (Dqn_Rect a);
DQN_API Dqn_V2 Dqn_Rect_InterpolatedPoint(Dqn_Rect rect, Dqn_V2 t01);
DQN_API Dqn_V2 Dqn_Rect_TopLeft (Dqn_Rect rect);
DQN_API Dqn_V2 Dqn_Rect_TopRight (Dqn_Rect rect);
DQN_API Dqn_V2 Dqn_Rect_BottomLeft (Dqn_Rect rect);
DQN_API Dqn_V2 Dqn_Rect_BottomRight (Dqn_Rect rect);
enum Dqn_RectCutClip
{
@ -294,6 +334,26 @@ struct Dqn_RectCut
DQN_API Dqn_Rect Dqn_RectCut_Cut(Dqn_RectCut rect_cut, Dqn_V2 size, Dqn_RectCutClip clip);
#endif // !defined(DQN_NO_RECT)
// NOTE: [$MATH] Raycast ===========================================================================
//
// NOTE: API
// @proc Dqn_Raycast_LineIntersectV2
// @desc Calculate the intersection point of 2 rays returning a `t` value
// which is how much along the direction of the 'ray' did the intersection
// occur.
//
// The arguments passed in do not need to be normalised for the function to
// work.
struct Dqn_RaycastLineIntersectV2Result
{
bool hit; // True if there was an intersection, false if the lines are parallel
Dqn_f32 t_a; // Distance along `dir_a` that the intersection occurred, e.g. `origin_a + (dir_a * t_a)`
Dqn_f32 t_b; // Distance along `dir_b` that the intersection occurred, e.g. `origin_b + (dir_b * t_b)`
};
DQN_API Dqn_RaycastLineIntersectV2Result Dqn_Raycast_LineIntersectV2(Dqn_V2 origin_a, Dqn_V2 dir_a, Dqn_V2 origin_b, Dqn_V2 dir_b);
// NOTE: [$MATH] Other =============================================================================
DQN_API Dqn_V2 Dqn_Lerp_V2(Dqn_V2 a, Dqn_f32 t, Dqn_V2 b);
DQN_API Dqn_f32 Dqn_Lerp_F32(Dqn_f32 a, Dqn_f32 t, Dqn_f32 b);

View File

@ -1,3 +1,4 @@
#if !defined(DQN_PLATFORM_EMSCRIPTEN)
// NOTE: [$VMEM] Dqn_VMem ==========================================================================
DQN_FILE_SCOPE uint32_t Dqn_VMem_ConvertPageToOSFlags_(uint32_t protect)
{
@ -115,9 +116,9 @@ DQN_API int Dqn_VMem_Protect(void *ptr, Dqn_usize size, uint32_t page_flags)
if (!ptr || size == 0)
return 0;
static Dqn_String8 const ALIGNMENT_ERROR_MSG =
DQN_STRING8("Page protection requires pointers to be page aligned because we "
"can only guard memory at a multiple of the page boundary.");
static Dqn_Str8 const ALIGNMENT_ERROR_MSG =
DQN_STR8("Page protection requires pointers to be page aligned because we "
"can only guard memory at a multiple of the page boundary.");
DQN_ASSERTF(Dqn_IsPowerOfTwoAligned(DQN_CAST(uintptr_t)ptr, g_dqn_library->os_page_size), "%s", ALIGNMENT_ERROR_MSG.data);
DQN_ASSERTF(Dqn_IsPowerOfTwoAligned(size, g_dqn_library->os_page_size), "%s", ALIGNMENT_ERROR_MSG.data);
@ -132,7 +133,7 @@ DQN_API int Dqn_VMem_Protect(void *ptr, Dqn_usize size, uint32_t page_flags)
#else
Dqn_ThreadScratch scratch = Dqn_Thread_GetScratch(nullptr);
Dqn_WinError error = Dqn_Win_LastError(scratch.arena);
DQN_ASSERTF(result, "VirtualProtect failed (%d): %.*s", error.code, DQN_STRING_FMT(error.msg));
DQN_ASSERTF(result, "VirtualProtect failed (%u): %.*s", error.code, DQN_STR_FMT(error.msg));
#endif
}
#else
@ -142,6 +143,48 @@ DQN_API int Dqn_VMem_Protect(void *ptr, Dqn_usize size, uint32_t page_flags)
return result;
}
#endif // !defined(DQN_PLATFORM_EMSCRIPTEN)
// NOTE: [$MEMF] Dqn_MemAPI ==================================================================
#if !defined(DQN_PLATFORM_EMSCRIPTEN)
DQN_API Dqn_MemAPI Dqn_MemAPI_InitOSVirtual()
{
Dqn_MemAPI result = {};
result.reserve = Dqn_VMem_Reserve;
result.commit = Dqn_VMem_Commit;
result.release = Dqn_VMem_Release;
return result;
}
#endif // !defined(DQN_PLATFORM_EMSCRIPTEN)
void *Dqn_MemAPI_CRTReserve(Dqn_usize size, Dqn_VMemCommit commit, uint32_t page_flags)
{
(void)page_flags;
(void)commit;
void *result = calloc(1, size);
return result;
}
bool Dqn_MemAPI_CRTCommit(void *ptr, Dqn_usize size, uint32_t page_flags)
{
(void)ptr; (void)size; (void)page_flags;
return true;
}
void Dqn_MemAPI_CRTRelease(void *ptr, Dqn_usize size)
{
(void)size;
free(ptr);
}
DQN_API Dqn_MemAPI Dqn_MemAPI_InitCRT()
{
Dqn_MemAPI result = {};
result.reserve = Dqn_MemAPI_CRTReserve;
result.commit = Dqn_MemAPI_CRTCommit;
result.release = Dqn_MemAPI_CRTRelease;
return result;
}
// NOTE: [$MEMB] Dqn_MemBlock ======================================================================
DQN_API Dqn_MemBlockSizeRequiredResult Dqn_MemBlock_SizeRequired(Dqn_MemBlock const *block, Dqn_usize size, uint8_t alignment, uint32_t flags)
@ -176,7 +219,7 @@ DQN_API Dqn_MemBlockSizeRequiredResult Dqn_MemBlock_SizeRequired(Dqn_MemBlock co
return result;
}
Dqn_usize Dqn_MemBlock_MetadataSize()
DQN_API Dqn_usize Dqn_MemBlock_MetadataSize()
{
Dqn_usize init_poison_page = DQN_ASAN_POISON ? DQN_ASAN_POISON_GUARD_SIZE : 0;
Dqn_usize alignment = DQN_ASAN_POISON ? DQN_ASAN_POISON_ALIGNMENT : alignof(Dqn_MemBlock);
@ -184,7 +227,7 @@ Dqn_usize Dqn_MemBlock_MetadataSize()
return result;
}
DQN_API Dqn_MemBlock *Dqn_MemBlock_Init(Dqn_usize reserve, Dqn_usize commit, uint32_t flags)
DQN_API Dqn_MemBlock *Dqn_MemBlock_InitMemAPI(Dqn_usize reserve, Dqn_usize commit, uint32_t flags, Dqn_MemAPI mem_api)
{
DQN_ASSERTF(g_dqn_library->os_page_size, "Library needs to be initialised by calling Dqn_Library_Init()");
DQN_ASSERTF(Dqn_IsPowerOfTwo(g_dqn_library->os_page_size), "Invalid page size");
@ -200,16 +243,17 @@ DQN_API Dqn_MemBlock *Dqn_MemBlock_Init(Dqn_usize reserve, Dqn_usize commit, uin
// NOTE: Avoid 1 syscall by committing on reserve if amounts are equal
Dqn_VMemCommit commit_on_reserve = commit_aligned == reserve_aligned ? Dqn_VMemCommit_Yes : Dqn_VMemCommit_No;
auto *result = DQN_CAST(Dqn_MemBlock *)Dqn_VMem_Reserve(reserve_aligned, commit_on_reserve, Dqn_VMemPage_ReadWrite);
auto *result = DQN_CAST(Dqn_MemBlock *)mem_api.reserve(reserve_aligned, commit_on_reserve, Dqn_VMemPage_ReadWrite);
if (result) {
// NOTE: Commit pages if we did not commit on the initial range.
if (!commit_on_reserve)
Dqn_VMem_Commit(result, commit_aligned, Dqn_VMemPage_ReadWrite);
mem_api.commit(result, commit_aligned, Dqn_VMemPage_ReadWrite);
result->data = DQN_CAST(uint8_t *)result + metadata_size;
result->size = reserve_aligned - metadata_size;
result->commit = commit_aligned - metadata_size;
result->flags = DQN_CAST(uint8_t)flags;
result->mem_api = mem_api;
result->data = DQN_CAST(uint8_t *)result + metadata_size;
result->size = reserve_aligned - metadata_size;
result->commit = commit_aligned - metadata_size;
result->flags = DQN_CAST(uint8_t)flags;
// NOTE: Poison (guard page + commit). We do *not* poison the entire
// block, only the commit pages. Since we may reserve large amounts of
@ -226,6 +270,12 @@ DQN_API Dqn_MemBlock *Dqn_MemBlock_Init(Dqn_usize reserve, Dqn_usize commit, uin
return result;
}
DQN_API Dqn_MemBlock *Dqn_MemBlock_Init(Dqn_usize reserve, Dqn_usize commit, uint32_t flags, Dqn_MemAPI mem_api)
{
Dqn_MemBlock *result = Dqn_MemBlock_InitMemAPI(reserve, commit, flags, mem_api);
return result;
}
DQN_API void *Dqn_MemBlock_Alloc(Dqn_MemBlock *block, Dqn_usize size, uint8_t alignment, Dqn_ZeroMem zero_mem)
{
DQN_ASSERT(zero_mem == Dqn_ZeroMem_Yes || zero_mem == Dqn_ZeroMem_No);
@ -239,8 +289,9 @@ DQN_API void *Dqn_MemBlock_Alloc(Dqn_MemBlock *block, Dqn_usize size, uint8_t al
if (new_used > block->size)
return result;
result = DQN_CAST(char *)block->data + size_required.data_offset;
block->used = new_used;
result = DQN_CAST(char *)block->data + size_required.data_offset;
block->used = new_used;
block->used_hwm = DQN_MAX(block->used_hwm, new_used);
DQN_ASSERT(Dqn_IsPowerOfTwoAligned(result, alignment));
if (DQN_ASAN_POISON)
@ -255,7 +306,7 @@ DQN_API void *Dqn_MemBlock_Alloc(Dqn_MemBlock *block, Dqn_usize size, uint8_t al
Dqn_usize commit_size = Dqn_AlignUpPowerOfTwo(block->used - block->commit, g_dqn_library->os_page_size);
void *commit_ptr = (void *)Dqn_AlignUpPowerOfTwo((char *)block->data + block->commit, g_dqn_library->os_page_size);
block->commit += commit_size;
Dqn_VMem_Commit(commit_ptr, commit_size, Dqn_VMemPage_ReadWrite);
block->mem_api.commit(commit_ptr, commit_size, Dqn_VMemPage_ReadWrite);
DQN_ASSERT(block->commit <= block->size);
if (DQN_ASAN_POISON) { // NOTE: Poison newly committed pages that aren't being used.
@ -275,7 +326,7 @@ DQN_API void Dqn_MemBlock_Free(Dqn_MemBlock *block)
Dqn_usize release_size = block->size + Dqn_MemBlock_MetadataSize();
if (DQN_ASAN_POISON)
Dqn_ASAN_UnpoisonMemoryRegion(block, release_size);
Dqn_VMem_Release(block, release_size);
block->mem_api.release(block, release_size);
}
DQN_API void Dqn_MemBlock_Pop(Dqn_MemBlock *block, Dqn_usize size)
@ -339,7 +390,15 @@ DQN_API Dqn_MemBlock *Dqn_Arena_Grow(Dqn_Arena *arena, Dqn_usize reserve, Dqn_us
if (arena->allocs_are_allowed_to_leak)
mem_block_flags |= Dqn_MemBlockFlag_AllocRecordLeakPermitted;
Dqn_MemBlock *result = Dqn_MemBlock_Init(reserve, commit, mem_block_flags);
if (!arena->mem_api.reserve) {
#if defined(DQN_PLATFORM_EMSCRIPTEN)
arena->mem_api = Dqn_MemAPI_InitCRT();
#else
arena->mem_api = Dqn_MemAPI_InitOSVirtual();
#endif
}
Dqn_MemBlock *result = Dqn_MemBlock_Init(reserve, commit, mem_block_flags, arena->mem_api);
if (result) {
if (!arena->head)
arena->head = result;
@ -475,29 +534,19 @@ Dqn_ArenaTempMemoryScope::~Dqn_ArenaTempMemoryScope()
Dqn_Arena_EndTempMemory(temp_memory, cancel);
}
DQN_API Dqn_ArenaStatString Dqn_Arena_StatString(Dqn_ArenaStat const *stat)
DQN_API Dqn_ArenaInfo Dqn_Arena_Info(Dqn_Arena const *arena)
{
// NOTE: We use a non-standard format string that is only usable via
// stb sprintf that GCC warns about as an error. This pragma mutes that.
DQN_GCC_WARNING_PUSH
DQN_GCC_WARNING_DISABLE("-Wformat-invalid-specifier")
DQN_GCC_WARNING_DISABLE("-Wformat-extra-args")
Dqn_ArenaStatString result = {};
int size16 = STB_SPRINTF_DECORATE(snprintf)(result.data, DQN_ARRAY_ICOUNT(result.data),
"ArenaStat{"
"used/hwm=%_$$zd/%_$$zd, "
"cap/hwm=%_$$zd/%_$$zd, "
"wasted/hwm=%_$$zd/%_$$zd, "
"blocks/hwm=%_$$u/%_$$u, "
"syscalls=%'zd"
"}",
stat->used, stat->used_hwm,
stat->capacity, stat->capacity_hwm,
stat->wasted, stat->wasted_hwm,
stat->blocks, stat->blocks_hwm,
stat->syscalls);
result.size = Dqn_Safe_SaturateCastIntToU16(size16);
DQN_GCC_WARNING_POP
Dqn_ArenaInfo result = {};
if (!arena)
return result;
for (Dqn_MemBlock const *block = arena->head; block; block = block->next) {
result.capacity += block->size;
result.used += block->used;
result.used_hwm += block->used_hwm;
result.commit += block->commit;
result.wasted += block->next ? (block->size - block->used) : 0;
}
return result;
}
@ -541,14 +590,14 @@ DQN_API Dqn_Arena *Dqn_ArenaCatalog_Alloc(Dqn_ArenaCatalog *catalog, Dqn_usize b
return result;
}
DQN_API Dqn_Arena *Dqn_ArenaCatalog_AllocFV(Dqn_ArenaCatalog *catalog, Dqn_usize byte_size, Dqn_usize commit, char const *fmt, va_list args)
DQN_API Dqn_Arena *Dqn_ArenaCatalog_AllocFV(Dqn_ArenaCatalog *catalog, Dqn_usize byte_size, Dqn_usize commit, DQN_FMT_ATTRIB char const *fmt, va_list args)
{
Dqn_Arena *result = Dqn_ArenaCatalog_Alloc(catalog, byte_size, commit);
result->label = Dqn_String8_InitFV(Dqn_Arena_Allocator(result), fmt, args);
result->label = Dqn_Str8_InitFV(Dqn_Arena_Allocator(result), fmt, args);
return result;
}
DQN_API Dqn_Arena *Dqn_ArenaCatalog_AllocF(Dqn_ArenaCatalog *catalog, Dqn_usize byte_size, Dqn_usize commit, char const *fmt, ...)
DQN_API Dqn_Arena *Dqn_ArenaCatalog_AllocF(Dqn_ArenaCatalog *catalog, Dqn_usize byte_size, Dqn_usize commit, DQN_FMT_ATTRIB char const *fmt, ...)
{
va_list args;
va_start(args, fmt);

View File

@ -33,11 +33,32 @@ enum Dqn_VMemPage
Dqn_VMemPage_AllocRecordLeakPermitted = 1 << 2,
};
#if !defined(DQN_PLATFORM_EMSCRIPTEN)
DQN_API void *Dqn_VMem_Reserve (Dqn_usize size, Dqn_VMemCommit commit, uint32_t page_flags);
DQN_API bool Dqn_VMem_Commit (void *ptr, Dqn_usize size, uint32_t page_flags);
DQN_API void Dqn_VMem_Decommit(void *ptr, Dqn_usize size);
DQN_API void Dqn_VMem_Release (void *ptr, Dqn_usize size);
DQN_API int Dqn_VMem_Protect (void *ptr, Dqn_usize size, uint32_t page_flags);
#endif
// NOTE: [$MEMF] Dqn_MemAPI ==================================================================
// Interface for specifying the routines for memory allocation for Dqn_MemBlock
typedef void *(Dqn_MemReserveFunc)(Dqn_usize size, Dqn_VMemCommit commit, uint32_t page_flags);
typedef bool (Dqn_MemCommitFunc) (void *ptr, Dqn_usize size, uint32_t page_flags);
typedef void (Dqn_MemReleaseFunc)(void *ptr, Dqn_usize size);
struct Dqn_MemAPI
{
Dqn_MemReserveFunc *reserve;
Dqn_MemCommitFunc *commit;
Dqn_MemReleaseFunc *release;
};
#if !defined(DQN_PLATFORM_EMSCRIPTEN)
DQN_API Dqn_MemAPI Dqn_MemAPI_InitOSVirtual();
#endif
DQN_API Dqn_MemAPI Dqn_MemAPI_InitCRT();
// NOTE: [$MEMB] Dqn_MemBlock ======================================================================
// Encapsulates allocation of objects from a raw block of memory by bumping a
@ -103,8 +124,10 @@ enum Dqn_MemBlockFlag
struct Dqn_MemBlock
{
Dqn_MemAPI mem_api;
void *data;
Dqn_usize used;
Dqn_usize used_hwm;
Dqn_usize size;
Dqn_usize commit;
Dqn_MemBlock *next;
@ -130,13 +153,14 @@ struct Dqn_MemBlockSizeRequiredResult
Dqn_usize block_size;
};
DQN_API Dqn_usize Dqn_MemBlock_MetadataSize(uint8_t flags);
DQN_API Dqn_MemBlockSizeRequiredResult Dqn_MemBlock_SizeRequired(Dqn_MemBlock const *block, Dqn_usize size, uint8_t alignment, uint32_t flags);
DQN_API Dqn_MemBlock * Dqn_MemBlock_Init (Dqn_usize reserve, Dqn_usize commit, uint32_t flags);
DQN_API void * Dqn_MemBlock_Alloc (Dqn_MemBlock *block, Dqn_usize size, uint8_t alignment, Dqn_ZeroMem zero_mem);
DQN_API void Dqn_MemBlock_Free (Dqn_MemBlock *block);
DQN_API void Dqn_MemBlock_Pop (Dqn_MemBlock *block, Dqn_usize size);
DQN_API void Dqn_MemBlock_PopTo (Dqn_MemBlock *block, Dqn_usize to);
DQN_API Dqn_usize Dqn_MemBlock_MetadataSize (uint8_t flags);
DQN_API Dqn_MemBlockSizeRequiredResult Dqn_MemBlock_SizeRequired (Dqn_MemBlock const *block, Dqn_usize size, uint8_t alignment, uint32_t flags);
DQN_API Dqn_MemBlock * Dqn_MemBlock_InitMemAPI(Dqn_usize reserve, Dqn_usize commit, uint32_t flags, Dqn_MemAPI mem_functions);
DQN_API Dqn_MemBlock * Dqn_MemBlock_Init (Dqn_usize reserve, Dqn_usize commit, uint32_t flags);
DQN_API void * Dqn_MemBlock_Alloc (Dqn_MemBlock *block, Dqn_usize size, uint8_t alignment, Dqn_ZeroMem zero_mem);
DQN_API void Dqn_MemBlock_Free (Dqn_MemBlock *block);
DQN_API void Dqn_MemBlock_Pop (Dqn_MemBlock *block, Dqn_usize size);
DQN_API void Dqn_MemBlock_PopTo (Dqn_MemBlock *block, Dqn_usize to);
#define Dqn_MemBlock_New(block, Type, zero_mem) (Type *)Dqn_MemBlock_Alloc(block, sizeof(Type), alignof(Type), zero_mem)
#define Dqn_MemBlock_NewArray(block, Type, count, zero_mem) (Type *)Dqn_MemBlock_Alloc(block, sizeof(Type) * count, alignof(Type), zero_mem)
@ -205,27 +229,13 @@ DQN_API void Dqn_MemBlock_PopTo (Dqn_MemBlock *b
// @proc Dqn_Arena_EndTempMemory
// @desc End an allocation scope previously begun by calling begin scope.
// @proc Dqn_Arena_StatString
// @desc Dump the stats of the given arena to a string
// @param[in] arena The arena to dump stats for
// @return A stack allocated string containing the stats of the arena
// @proc Dqn_Arena_LogStats
// @desc Dump the stats of the given arena to the memory log-stream.
// @param[in] arena The arena to dump stats for
struct Dqn_ArenaStat
struct Dqn_ArenaInfo
{
Dqn_usize capacity; // Total allocating capacity of the arena in bytes
Dqn_usize used; // Total amount of bytes used in the arena
Dqn_usize wasted; // Orphaned space in blocks due to allocations requiring more space than available in the active block
uint32_t blocks; // Number of memory blocks in the arena
Dqn_usize syscalls; // Number of memory allocation syscalls into the OS
Dqn_usize capacity_hwm; // High-water mark for 'capacity'
Dqn_usize used_hwm; // High-water mark for 'used'
Dqn_usize wasted_hwm; // High-water mark for 'wasted'
uint32_t blocks_hwm; // High-water mark for 'blocks'
Dqn_usize capacity; // Total allocating capacity of the arena in bytes
Dqn_usize used; // Total amount of bytes used in the arena
Dqn_usize commit; // Total amount of bytes committed in the arena
Dqn_usize wasted; // Orphaned space in blocks due to allocations requiring more space than available in the active block
Dqn_usize used_hwm; // High-water mark for 'used'
};
struct Dqn_ArenaBlock
@ -234,7 +244,7 @@ struct Dqn_ArenaBlock
void *memory; // Backing memory of the block
Dqn_usize size; // Size of the block
Dqn_usize used; // Number of bytes used up in the block. Always less than the commit amount.
Dqn_usize hwm_used;// High-water mark for 'used' bytes in this block
Dqn_usize used_hwm;// High-water mark for 'used' bytes in this block
Dqn_usize commit; // Number of bytes in the block physically backed by pages
Dqn_ArenaBlock *prev; // Previous linked block
Dqn_ArenaBlock *next; // Next linked block
@ -249,12 +259,13 @@ struct Dqn_ArenaStatString
struct Dqn_Arena
{
bool allocs_are_allowed_to_leak;
Dqn_String8 label; // Optional label to describe the arena
Dqn_MemBlock *head; // Active block the arena is allocating from
Dqn_MemBlock *curr; // Active block the arena is allocating from
Dqn_MemBlock *tail; // Last block in the linked list of blocks
uint64_t blocks;
Dqn_MemAPI mem_api;
bool allocs_are_allowed_to_leak;
Dqn_Str8 label; // Optional label to describe the arena
Dqn_MemBlock *head; // Active block the arena is allocating from
Dqn_MemBlock *curr; // Active block the arena is allocating from
Dqn_MemBlock *tail; // Last block in the linked list of blocks
uint64_t blocks;
};
struct Dqn_ArenaTempMemory
@ -305,9 +316,8 @@ DQN_API void Dqn_Arena_Free (Dqn_Arena *arena, Dqn_Zero
DQN_API Dqn_ArenaTempMemory Dqn_Arena_BeginTempMemory(Dqn_Arena *arena);
DQN_API void Dqn_Arena_EndTempMemory (Dqn_ArenaTempMemory temp_memory, bool cancel);
// NOTE: Arena Stats ===============================================================================
DQN_API Dqn_ArenaStatString Dqn_Arena_StatString (Dqn_ArenaStat const *stat);
DQN_API void Dqn_Arena_LogStats (Dqn_Arena const *arena);
// NOTE: Arena Info ===============================================================================
DQN_API Dqn_ArenaInfo Dqn_Arena_Info (Dqn_Arena const *arena);
// NOTE: [$ACAT] Dqn_ArenaCatalog ==================================================================
struct Dqn_ArenaCatalogItem
@ -328,5 +338,5 @@ struct Dqn_ArenaCatalog
DQN_API void Dqn_ArenaCatalog_Init (Dqn_ArenaCatalog *catalog, Dqn_Arena *arena);
DQN_API void Dqn_ArenaCatalog_Add (Dqn_ArenaCatalog *catalog, Dqn_Arena *arena);
DQN_API Dqn_Arena *Dqn_ArenaCatalog_Alloc (Dqn_ArenaCatalog *catalog, Dqn_usize byte_size, Dqn_usize commit);
DQN_API Dqn_Arena *Dqn_ArenaCatalog_AllocFV(Dqn_ArenaCatalog *catalog, Dqn_usize byte_size, Dqn_usize commit, char const *fmt, va_list args);
DQN_API Dqn_Arena *Dqn_ArenaCatalog_AllocF (Dqn_ArenaCatalog *catalog, Dqn_usize byte_size, Dqn_usize commit, char const *fmt, ...);
DQN_API Dqn_Arena *Dqn_ArenaCatalog_AllocFV(Dqn_ArenaCatalog *catalog, Dqn_usize byte_size, Dqn_usize commit, DQN_FMT_ATTRIB char const *fmt, va_list args);
DQN_API Dqn_Arena *Dqn_ArenaCatalog_AllocF (Dqn_ArenaCatalog *catalog, Dqn_usize byte_size, Dqn_usize commit, DQN_FMT_ATTRIB char const *fmt, ...);

136
dqn_os.cpp Normal file
View File

@ -0,0 +1,136 @@
DQN_API void Dqn_OS_Exit(uint32_t exit_code)
{
#if defined(DQN_OS_WIN32)
ExitProcess(exit_code);
#else
exit(exit_code);
#endif
}
// NOTE: [$EXEC] Dqn_OSExec ========================================================================
DQN_API Dqn_OSExecResult Dqn_OS_ExecWait(Dqn_OSExecAsyncHandle handle)
{
Dqn_OSExecResult result = {};
if (!handle.process || handle.os_error_code) {
result.os_error_code = handle.os_error_code;
return result;
}
#if defined(DQN_OS_WIN32)
DWORD exec_result = WaitForSingleObject(handle.process, INFINITE);
if (exec_result == WAIT_FAILED) {
result.os_error_code = GetLastError();
return result;
}
DWORD exit_status;
if (!GetExitCodeProcess(handle.process, &exit_status)) {
result.os_error_code = GetLastError();
return result;
}
result.exit_code = exit_status;
CloseHandle(handle.process);
#elif defined(DQN_PLATFORM_EMSCRIPTEN)
DQN_ASSERTF(false, "Unsupported operation");
#else
for (;;) {
int status = 0;
if (waitpid(DQN_CAST(pid_t)handle.process, &status, 0) < 0) {
result.os_error_code = errno;
break;
}
if (WIFEXITED(status)) {
result.exit_code = WEXITSTATUS(status);
break;
}
if (WIFSIGNALLED(status)) {
result.os_error_code = WTERMSIG(status);
break;
}
}
#endif
return result;
}
DQN_API Dqn_OSExecAsyncHandle Dqn_OS_ExecAsync(Dqn_Str8 cmd, Dqn_Str8 working_dir)
{
Dqn_OSExecAsyncHandle result = {};
if (cmd.size == 0)
return result;
#if defined(DQN_OS_WIN32)
Dqn_ThreadScratch scratch = Dqn_Thread_GetScratch(nullptr);
Dqn_Str16 cmd16 = Dqn_Win_Str8ToStr16(scratch.arena, cmd);
Dqn_Str16 working_dir16 = Dqn_Win_Str8ToStr16(scratch.arena, working_dir);
PROCESS_INFORMATION proc_info = {};
STARTUPINFOW startup_info = {};
startup_info.cb = sizeof(STARTUPINFOW);
startup_info.hStdError = GetStdHandle(STD_ERROR_HANDLE);
startup_info.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE);
startup_info.hStdInput = GetStdHandle(STD_INPUT_HANDLE);
startup_info.dwFlags |= STARTF_USESTDHANDLES;
BOOL create_result = CreateProcessW(nullptr, cmd16.data, nullptr, nullptr, true, 0, nullptr, working_dir16.data, &startup_info, &proc_info);
if (!create_result) {
result.os_error_code = GetLastError();
return result;
}
CloseHandle(proc_info.hThread);
result.process = proc_info.hProcess;
#else
DQN_ASSERTF(false, "Unsupported operation");
// TODO: This API will need to switch to an array of strings for unix
#if 0
pid_t child_pid = fork();
if (child_pid < 0) {
result.os_error_code = errno;
return result;
}
if (child_pid == 0) {
if (working_dir.size) {
if (chdir(working_dir.data) == -1) {
result.os_error_code = errno;
return result;
}
}
if (execvp(cmd.items[0], (char * const*) cmd_null.items) < 0) {
result.os_error_code = errno;
return result;
}
DQN_INVALID_CODE_PATH;
}
result.process = DQN_CAST(void *)child_pid;
#endif
#endif
return result;
}
DQN_API Dqn_OSExecResult Dqn_OS_Exec(Dqn_Str8 cmd, Dqn_Str8 working_dir)
{
Dqn_OSExecAsyncHandle async_handle = Dqn_OS_ExecAsync(cmd, working_dir);
Dqn_OSExecResult result = Dqn_OS_ExecWait(async_handle);
return result;
}
DQN_API void Dqn_OS_ExecOrAbort(Dqn_Str8 cmd, Dqn_Str8 working_dir)
{
Dqn_OSExecResult result = Dqn_OS_Exec(cmd, working_dir);
if (result.os_error_code || result.exit_code) {
if (result.os_error_code) {
Dqn_Log_ErrorF("OS failed to execute the requested command returning the error code %u. The command was\n\n%.*s", result.os_error_code, DQN_STR_FMT(cmd));
Dqn_OS_Exit(result.os_error_code);
}
if (result.exit_code) {
Dqn_Log_ErrorF("OS executed command and returned a non-zero status: %u. The command was\n\n%.*s", result.exit_code, DQN_STR_FMT(cmd));
Dqn_OS_Exit(result.exit_code);
}
}
}

18
dqn_os.h Normal file
View File

@ -0,0 +1,18 @@
// NOTE: [$EXEC] Dqn_OSExec ========================================================================
struct Dqn_OSExecAsyncHandle
{
uint32_t os_error_code;
void *process;
};
struct Dqn_OSExecResult
{
uint32_t os_error_code;
uint32_t exit_code;
};
DQN_API void Dqn_OS_Exit (uint32_t exit_code);
DQN_API Dqn_OSExecResult Dqn_OS_ExecWait (Dqn_OSExecAsyncHandle handle);
DQN_API Dqn_OSExecAsyncHandle Dqn_OS_ExecAsync (Dqn_Str8 cmd, Dqn_Str8 working_dir);
DQN_API Dqn_OSExecResult Dqn_OS_Exec (Dqn_Str8 cmd, Dqn_Str8 working_dir);
DQN_API void Dqn_OS_ExecOrAbort(Dqn_Str8 cmd, Dqn_Str8 working_dir);

File diff suppressed because it is too large Load Diff

View File

@ -4,7 +4,7 @@
#endif
// NOTE: [$FSYS] Dqn_Fs ============================================================================
// NOTE: FS Manipulation ===========================================================================
// TODO(dqn): We should have a Dqn_String8 interface and a CString interface
// TODO(dqn): We should have a Dqn_Str8 interface and a CStr8 interface
//
// NOTE: API =======================================================================================
// @proc Dqn_FsDelete
@ -29,26 +29,26 @@ struct Dqn_FsInfo
uint64_t size;
};
DQN_API bool Dqn_Fs_Exists (Dqn_String8 path);
DQN_API bool Dqn_Fs_DirExists(Dqn_String8 path);
DQN_API Dqn_FsInfo Dqn_Fs_GetInfo (Dqn_String8 path);
DQN_API bool Dqn_Fs_Copy (Dqn_String8 src, Dqn_String8 dest, bool overwrite);
DQN_API bool Dqn_Fs_MakeDir (Dqn_String8 path);
DQN_API bool Dqn_Fs_Move (Dqn_String8 src, Dqn_String8 dest, bool overwrite);
DQN_API bool Dqn_Fs_Delete (Dqn_String8 path);
DQN_API bool Dqn_Fs_Exists (Dqn_Str8 path);
DQN_API bool Dqn_Fs_DirExists(Dqn_Str8 path);
DQN_API Dqn_FsInfo Dqn_Fs_GetInfo (Dqn_Str8 path);
DQN_API bool Dqn_Fs_Copy (Dqn_Str8 src, Dqn_Str8 dest, bool overwrite);
DQN_API bool Dqn_Fs_MakeDir (Dqn_Str8 path);
DQN_API bool Dqn_Fs_Move (Dqn_Str8 src, Dqn_Str8 dest, bool overwrite);
DQN_API bool Dqn_Fs_Delete (Dqn_Str8 path);
// NOTE: R/W Entire File ===========================================================================
// NOTE: API =======================================================================================
// @proc Dqn_Fs_WriteString8, Dqn_Fs_WriteCString8
// @proc Dqn_Fs_WriteStr8, Dqn_Fs_WriteCStr8
// @desc Write the string to a file at the path overwriting if necessary.
// @proc Dqn_Fs_ReadString8, Dqn_Fs_ReadCString8
// @proc Dqn_Fs_ReadStr8, Dqn_Fs_ReadCStr8
// @desc Read the file at the path to a string.
DQN_API bool Dqn_Fs_WriteCString8(char const *file_path, Dqn_usize file_path_size, char const *buffer, Dqn_usize buffer_size);
DQN_API bool Dqn_Fs_Write (Dqn_String8 file_path, Dqn_String8 buffer);
DQN_API char *Dqn_Fs_ReadCString8 (char const *path, Dqn_usize path_size, Dqn_usize *file_size, Dqn_Allocator allocator);
DQN_API Dqn_String8 Dqn_Fs_Read (Dqn_String8 path, Dqn_Allocator allocator);
DQN_API bool Dqn_Fs_WriteCStr8(char const *file_path, Dqn_usize file_path_size, char const *buffer, Dqn_usize buffer_size);
DQN_API bool Dqn_Fs_Write (Dqn_Str8 file_path, Dqn_Str8 buffer);
DQN_API char *Dqn_Fs_ReadCStr8 (char const *path, Dqn_usize path_size, Dqn_usize *file_size, Dqn_Allocator allocator);
DQN_API Dqn_Str8 Dqn_Fs_Read (Dqn_Str8 path, Dqn_Allocator allocator);
// NOTE: R/W Stream API ============================================================================
// NOTE: API =======================================================================================
@ -85,11 +85,11 @@ enum Dqn_FsFileAccess
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_Str8 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, 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 bool Dqn_Fs_WriteFile (Dqn_FsFile *file, Dqn_Str8 buffer);
DQN_API bool Dqn_Fs_WriteFileFV (Dqn_FsFile *file, DQN_FMT_ATTRIB char const *fmt, va_list args);
DQN_API bool Dqn_Fs_WriteFileF (Dqn_FsFile *file, DQN_FMT_ATTRIB char const *fmt, ...);
DQN_API void Dqn_Fs_CloseFile (Dqn_FsFile *file);
#endif // !defined(DQN_NO_FS)
@ -124,16 +124,17 @@ DQN_API void Dqn_Fs_CloseFile (Dqn_FsFile *file);
#else
#define Dqn_FsPathOSSeperator "/"
#endif
#define Dqn_FsPathOSSeperatorString DQN_STRING8(Dqn_FsPathOSSeperator)
#define Dqn_FsPathOSSeperatorString DQN_STR8(Dqn_FsPathOSSeperator)
#endif
struct Dqn_FsPathLink
{
Dqn_String8 string;
Dqn_Str8 string;
Dqn_FsPathLink *next;
Dqn_FsPathLink *prev;
};
struct Dqn_FsPath
{
Dqn_FsPathLink *head;
@ -142,15 +143,15 @@ struct Dqn_FsPath
uint16_t links_size;
};
DQN_API bool Dqn_FsPath_AddRef (Dqn_Arena *arena, Dqn_FsPath *fs_path, Dqn_String8 path);
DQN_API bool Dqn_FsPath_Add (Dqn_Arena *arena, Dqn_FsPath *fs_path, Dqn_String8 path);
DQN_API bool Dqn_FsPath_AddF (Dqn_Arena *arena, Dqn_FsPath *fs_path, DQN_FMT_STRING_ANNOTATE char const *fmt, ...);
DQN_API bool Dqn_FsPath_Pop (Dqn_FsPath *fs_path);
DQN_API Dqn_String8 Dqn_FsPath_BuildWithSeparator(Dqn_Arena *arena, Dqn_FsPath const *fs_path, Dqn_String8 path_separator);
DQN_API Dqn_String8 Dqn_FsPath_Convert (Dqn_Arena *arena, Dqn_String8 path);
DQN_API Dqn_String8 Dqn_FsPath_ConvertF (Dqn_Arena *arena, DQN_FMT_STRING_ANNOTATE char const *fmt, ...);
#define Dqn_FsPath_BuildFwdSlash(arena, fs_path) Dqn_FsPath_BuildWithSeparator(arena, fs_path, DQN_STRING8("/"))
#define Dqn_FsPath_BuildBackSlash(arena, fs_path) Dqn_FsPath_BuildWithSeparator(arena, fs_path, DQN_STRING8("\\"))
DQN_API bool Dqn_FsPath_AddRef (Dqn_Arena *arena, Dqn_FsPath *fs_path, Dqn_Str8 path);
DQN_API bool Dqn_FsPath_Add (Dqn_Arena *arena, Dqn_FsPath *fs_path, Dqn_Str8 path);
DQN_API bool Dqn_FsPath_AddF (Dqn_Arena *arena, Dqn_FsPath *fs_path, DQN_FMT_ATTRIB char const *fmt, ...);
DQN_API bool Dqn_FsPath_Pop (Dqn_FsPath *fs_path);
DQN_API Dqn_Str8 Dqn_FsPath_BuildWithSeparator(Dqn_Arena *arena, Dqn_FsPath const *fs_path, Dqn_Str8 path_separator);
DQN_API Dqn_Str8 Dqn_FsPath_Convert (Dqn_Arena *arena, Dqn_Str8 path);
DQN_API Dqn_Str8 Dqn_FsPath_ConvertF (Dqn_Arena *arena, DQN_FMT_ATTRIB char const *fmt, ...);
#define Dqn_FsPath_BuildFwdSlash(arena, fs_path) Dqn_FsPath_BuildWithSeparator(arena, fs_path, DQN_STR8("/"))
#define Dqn_FsPath_BuildBackSlash(arena, fs_path) Dqn_FsPath_BuildWithSeparator(arena, fs_path, DQN_STR8("\\"))
#if !defined(Dqn_FsPath_Build)
#if defined(DQN_OS_WIN32)
@ -166,7 +167,7 @@ DQN_API Dqn_String8 Dqn_FsPath_ConvertF (Dqn_Arena *arena, DQN_FMT_STRI
// @desc Produce the time elapsed since the Unix epoch
// (e.g. 1970-01-01T00:00:00Z) in seconds
struct Dqn_DateHMSTimeString
struct Dqn_DateHMSTimeStr8
{
char date[DQN_ARRAY_UCOUNT("YYYY-MM-SS")];
uint8_t date_size;
@ -186,10 +187,10 @@ struct Dqn_DateHMSTime
uint8_t seconds;
};
DQN_API Dqn_DateHMSTime Dqn_Date_HMSLocalTimeNow ();
DQN_API Dqn_DateHMSTimeString Dqn_Date_HMSLocalTimeStringNow(char date_separator = '-', char hms_separator = ':');
DQN_API Dqn_DateHMSTimeString Dqn_Date_HMSLocalTimeString (Dqn_DateHMSTime time, char date_separator = '-', char hms_separator = ':');
DQN_API uint64_t Dqn_Date_EpochTime ();
DQN_API Dqn_DateHMSTime Dqn_Date_LocalTimeHMSNow ();
DQN_API Dqn_DateHMSTimeStr8 Dqn_Date_LocalTimeHMSStr8Now(char date_separator = '-', char hms_separator = ':');
DQN_API Dqn_DateHMSTimeStr8 Dqn_Date_LocalTimeHMSStr8 (Dqn_DateHMSTime time, char date_separator = '-', char hms_separator = ':');
DQN_API uint64_t Dqn_Date_EpochTime ();
#if defined(DQN_OS_WIN32)
#if !defined(DQN_NO_WIN)
@ -207,12 +208,12 @@ DQN_API uint64_t Dqn_Date_EpochTime ();
struct Dqn_WinError
{
unsigned long code;
Dqn_String8 msg;
Dqn_Str8 msg;
};
DQN_API Dqn_WinError Dqn_Win_LastError(Dqn_Arena *arena);
DQN_API void Dqn_Win_MakeProcessDPIAware();
// NOTE: Windows String8 <-> String16 ===========================================
// NOTE: Windows Str8 <-> Str16 ===========================================
// Convert a UTF8 <-> UTF16 string.
//
// The exact size buffer required for this function can be determined by
@ -225,10 +226,10 @@ DQN_API void Dqn_Win_MakeProcessDPIAware();
// written/required for conversion. 0 if there was a conversion error and can be
// queried using 'Dqn_Win_LastError'
DQN_API Dqn_String16 Dqn_Win_String8ToString16(Dqn_Arena *arena, Dqn_String8 src);
DQN_API int Dqn_Win_String8ToString16Buffer(Dqn_String16 src, char *dest, int dest_size);
DQN_API Dqn_String8 Dqn_Win_String16ToString8(Dqn_Arena *arena, Dqn_String16 src);
DQN_API int Dqn_Win_String16ToString8Buffer(Dqn_String16 src, char *dest, int dest_size);
DQN_API Dqn_Str16 Dqn_Win_Str8ToStr16 (Dqn_Arena *arena, Dqn_Str8 src);
DQN_API int Dqn_Win_Str8ToStr16Buffer(Dqn_Str16 src, char *dest, int dest_size);
DQN_API Dqn_Str8 Dqn_Win_Str16ToStr8 (Dqn_Arena *arena, Dqn_Str16 src);
DQN_API int Dqn_Win_Str16ToStr8Buffer(Dqn_Str16 src, char *dest, int dest_size);
// NOTE: Path navigation ===========================================================================
// NOTE: API =======================================================================================
@ -256,22 +257,23 @@ DQN_API int Dqn_Win_String16ToString8Buffer(Dqn_String16 src, char *des
struct Dqn_Win_FolderIteratorW
{
void *handle;
Dqn_String16 file_name;
Dqn_Str16 file_name;
wchar_t file_name_buf[512];
};
struct Dqn_Win_FolderIterator
{
void *handle;
Dqn_String8 file_name;
char file_name_buf[512];
void *handle;
Dqn_Str8 file_name;
char file_name_buf[512];
};
DQN_API Dqn_String16 Dqn_Win_EXEDirW (Dqn_Arena *arena);
DQN_API Dqn_String8 Dqn_Win_WorkingDir (Dqn_Allocator allocator, Dqn_String8 suffix);
DQN_API Dqn_String16 Dqn_Win_WorkingDirW (Dqn_Allocator allocator, Dqn_String16 suffix);
DQN_API bool Dqn_Win_FolderIterate (Dqn_String8 path, Dqn_Win_FolderIterator *it);
DQN_API bool Dqn_Win_FolderWIterate(Dqn_String16 path, Dqn_Win_FolderIteratorW *it);
DQN_API Dqn_Str16 Dqn_Win_EXEPathW (Dqn_Arena *arena);
DQN_API Dqn_Str16 Dqn_Win_EXEDirW (Dqn_Arena *arena);
DQN_API Dqn_Str8 Dqn_Win_WorkingDir (Dqn_Allocator allocator, Dqn_Str8 suffix);
DQN_API Dqn_Str16 Dqn_Win_WorkingDirW (Dqn_Allocator allocator, Dqn_Str16 suffix);
DQN_API bool Dqn_Win_FolderIterate (Dqn_Str8 path, Dqn_Win_FolderIterator *it);
DQN_API bool Dqn_Win_FolderWIterate(Dqn_Str16 path, Dqn_Win_FolderIteratorW *it);
#endif // !defined(DQN_NO_WIN)
#if !defined(DQN_NO_WINNET)
@ -284,7 +286,7 @@ DQN_API bool Dqn_Win_FolderWIterate(Dqn_String16 path, Dqn_Win_Folder
// INTERNET_OPTION_SEND_TIMEOUT
//
// NOTE: API =======================================================================================
// @proc Dqn_Win_NetHandleInitHTTPMethod, Dqn_Win_NetHandleInitHTTPMethodCString
// @proc Dqn_Win_NetHandleInitHTTPMethod, Dqn_Win_NetHandleInitHTTPMethodCStr8
// @desc Setup a handle to the URL with the given HTTP verb.
//
// This function is the same as calling Dqn_Win_NetHandleInit() followed by
@ -354,32 +356,32 @@ enum Dqn_WinNetHandleRequestHeaderFlag
struct Dqn_WinNetHandleResponse
{
Dqn_String8 raw_headers;
Dqn_String8 *headers;
Dqn_usize headers_size;
Dqn_Str8 raw_headers;
Dqn_Str8 *headers;
Dqn_usize headers_size;
// NOTE: Headers pulled from the 'raw_headers' for convenience
uint64_t content_length;
Dqn_String8 content_type;
uint64_t content_length;
Dqn_Str8 content_type;
};
DQN_API Dqn_WinNetHandle Dqn_Win_NetHandleInitCString (char const *url, int url_size);
DQN_API Dqn_WinNetHandle Dqn_Win_NetHandleInit (Dqn_String8 url);
DQN_API Dqn_WinNetHandle Dqn_Win_NetHandleInitHTTPMethodCString (char const *url, int url_size, char const *http_method);
DQN_API Dqn_WinNetHandle Dqn_Win_NetHandleInitHTTPMethod (Dqn_String8 url, Dqn_String8 http_method);
DQN_API void Dqn_Win_NetHandleClose (Dqn_WinNetHandle *handle);
DQN_API bool Dqn_Win_NetHandleIsValid (Dqn_WinNetHandle const *handle);
DQN_API void Dqn_Win_NetHandleSetUserAgentCString (Dqn_WinNetHandle *handle, char const *user_agent, int user_agent_size);
DQN_API bool Dqn_Win_NetHandleSetHTTPMethod (Dqn_WinNetHandle *handle, char const *method);
DQN_API bool Dqn_Win_NetHandleSetRequestHeaderCString8(Dqn_WinNetHandle *handle, char const *header, int header_size, uint32_t mode);
DQN_API bool Dqn_Win_NetHandleSetRequestHeaderString8 (Dqn_WinNetHandle *handle, Dqn_String8 header, uint32_t mode);
DQN_API Dqn_WinNetHandleResponse Dqn_Win_NetHandleSendRequest (Dqn_WinNetHandle *handle, Dqn_Allocator allocator, char const *post_data, unsigned long post_data_size);
DQN_API bool Dqn_Win_NetHandlePump (Dqn_WinNetHandle *handle, char *dest, int dest_size, size_t *download_size);
DQN_API char * Dqn_Win_NetHandlePumpCString8 (Dqn_WinNetHandle *handle, Dqn_Arena *arena, size_t *download_size);
DQN_API Dqn_String8 Dqn_Win_NetHandlePumpString8 (Dqn_WinNetHandle *handle, Dqn_Arena *arena);
DQN_API void Dqn_Win_NetHandlePumpToCRTFile (Dqn_WinNetHandle *handle, FILE *file);
DQN_API char * Dqn_Win_NetHandlePumpToAllocCString (Dqn_WinNetHandle *handle, size_t *download_size);
DQN_API Dqn_String8 Dqn_Win_NetHandlePumpToAllocString (Dqn_WinNetHandle *handle);
DQN_API Dqn_WinNetHandle Dqn_Win_NetHandleInitCStr8 (char const *url, int url_size);
DQN_API Dqn_WinNetHandle Dqn_Win_NetHandleInit (Dqn_Str8 url);
DQN_API Dqn_WinNetHandle Dqn_Win_NetHandleInitHTTPMethodCStr8 (char const *url, int url_size, char const *http_method);
DQN_API Dqn_WinNetHandle Dqn_Win_NetHandleInitHTTPMethod (Dqn_Str8 url, Dqn_Str8 http_method);
DQN_API void Dqn_Win_NetHandleClose (Dqn_WinNetHandle *handle);
DQN_API bool Dqn_Win_NetHandleIsValid (Dqn_WinNetHandle const *handle);
DQN_API void Dqn_Win_NetHandleSetUserAgentCStr8 (Dqn_WinNetHandle *handle, char const *user_agent, int user_agent_size);
DQN_API bool Dqn_Win_NetHandleSetHTTPMethod (Dqn_WinNetHandle *handle, char const *method);
DQN_API bool Dqn_Win_NetHandleSetRequestHeaderCStr8(Dqn_WinNetHandle *handle, char const *header, int header_size, uint32_t mode);
DQN_API bool Dqn_Win_NetHandleSetRequestHeaderStr8 (Dqn_WinNetHandle *handle, Dqn_Str8 header, uint32_t mode);
DQN_API Dqn_WinNetHandleResponse Dqn_Win_NetHandleSendRequest (Dqn_WinNetHandle *handle, Dqn_Allocator allocator, char const *post_data, unsigned long post_data_size);
DQN_API bool Dqn_Win_NetHandlePump (Dqn_WinNetHandle *handle, char *dest, int dest_size, size_t *download_size);
DQN_API char * Dqn_Win_NetHandlePumpCStr8 (Dqn_WinNetHandle *handle, Dqn_Arena *arena, size_t *download_size);
DQN_API Dqn_Str8 Dqn_Win_NetHandlePumpStr8 (Dqn_WinNetHandle *handle, Dqn_Arena *arena);
DQN_API void Dqn_Win_NetHandlePumpToCRTFile (Dqn_WinNetHandle *handle, FILE *file);
DQN_API char * Dqn_Win_NetHandlePumpToAllocCStr8 (Dqn_WinNetHandle *handle, size_t *download_size);
DQN_API Dqn_Str8 Dqn_Win_NetHandlePumpToAllocStr8 (Dqn_WinNetHandle *handle);
#endif // !defined(DQN_NO_WINNET)
#endif // defined(DQN_OS_WIN32)
@ -405,6 +407,9 @@ DQN_API Dqn_String8 Dqn_Win_NetHandlePumpToAllocString (Dqn_W
// @param duration_ms_to_gauge_tsc_frequency How many milliseconds to spend
// measuring the TSC rate of the current machine. 100ms is sufficient to
// produce a fairly accurate result with minimal blocking in applications.
//
// This may return 0 if querying the CPU timestamp counter is not supported
// on the platform (e.g. __rdtsc() or __builtin_readcyclecounter() returns 0).
/// Record time between two time-points using the OS's performance counter.
struct Dqn_OSTimer
@ -415,7 +420,8 @@ struct Dqn_OSTimer
DQN_API bool Dqn_OS_SecureRNGBytes (void *buffer, uint32_t size);
#if (defined(DQN_OS_WIN32) && !defined(DQN_NO_WIN)) || !defined(DQN_OS_WIN32)
DQN_API Dqn_String8 Dqn_OS_EXEDir (Dqn_Arena* arena);
DQN_API Dqn_Str8 Dqn_OS_EXEPath (Dqn_Arena *arena);
DQN_API Dqn_Str8 Dqn_OS_EXEDir (Dqn_Arena* arena);
#endif
DQN_API void Dqn_OS_SleepMs (Dqn_uint milliseconds);
DQN_API uint64_t Dqn_OS_PerfCounterNow ();

View File

@ -1,5 +1,5 @@
// NOTE: [$CSTR] Dqn_CString8 ======================================================================
DQN_API Dqn_usize Dqn_CString8_FSize(DQN_FMT_STRING_ANNOTATE char const *fmt, ...)
// NOTE: [$CSTR] Dqn_CStr8 ======================================================================
DQN_API Dqn_usize Dqn_CStr8_FSize(DQN_FMT_ATTRIB char const *fmt, ...)
{
va_list args;
va_start(args, fmt);
@ -8,7 +8,7 @@ DQN_API Dqn_usize Dqn_CString8_FSize(DQN_FMT_STRING_ANNOTATE char const *fmt, ..
return result;
}
DQN_API Dqn_usize Dqn_CString8_FVSize(DQN_FMT_STRING_ANNOTATE char const *fmt, va_list args)
DQN_API Dqn_usize Dqn_CStr8_FVSize(DQN_FMT_ATTRIB char const *fmt, va_list args)
{
va_list args_copy;
va_copy(args_copy, args);
@ -17,8 +17,7 @@ DQN_API Dqn_usize Dqn_CString8_FVSize(DQN_FMT_STRING_ANNOTATE char const *fmt, v
return result;
}
DQN_API Dqn_usize Dqn_CString8_Size(char const *src)
DQN_API Dqn_usize Dqn_CStr8_Size(char const *src)
{
Dqn_usize result = 0;
while (src && src[0] != 0) {
@ -28,7 +27,7 @@ DQN_API Dqn_usize Dqn_CString8_Size(char const *src)
return result;
}
DQN_API Dqn_usize Dqn_CString16_Size(wchar_t const *src)
DQN_API Dqn_usize Dqn_CStr16_Size(wchar_t const *src)
{
Dqn_usize result = 0;
while (src && src[0] != 0) {
@ -39,28 +38,28 @@ DQN_API Dqn_usize Dqn_CString16_Size(wchar_t const *src)
return result;
}
// NOTE: [$STR8] Dqn_String8 =======================================================================
DQN_API Dqn_String8 Dqn_String8_InitCString8(char const *src)
// NOTE: [$STR8] Dqn_Str8 =======================================================================
DQN_API Dqn_Str8 Dqn_Str8_InitCStr8(char const *src)
{
Dqn_usize size = Dqn_CString8_Size(src);
Dqn_String8 result = Dqn_String8_Init(src, size);
Dqn_usize size = Dqn_CStr8_Size(src);
Dqn_Str8 result = Dqn_Str8_Init(src, size);
return result;
}
DQN_API bool Dqn_String8_IsAll(Dqn_String8 string, Dqn_String8IsAll is_all)
DQN_API bool Dqn_Str8_IsAll(Dqn_Str8 string, Dqn_Str8IsAll is_all)
{
bool result = Dqn_String8_IsValid(string);
bool result = Dqn_Str8_IsValid(string);
if (!result)
return result;
switch (is_all) {
case Dqn_String8IsAll_Digits: {
case Dqn_Str8IsAll_Digits: {
for (Dqn_usize index = 0; result && index < string.size; index++)
result = string.data[index] >= '0' && string.data[index] <= '9';
} break;
case Dqn_String8IsAll_Hex: {
Dqn_String8 trimmed = Dqn_String8_TrimPrefix(string, DQN_STRING8("0x"), Dqn_String8EqCase_Insensitive);
case Dqn_Str8IsAll_Hex: {
Dqn_Str8 trimmed = Dqn_Str8_TrimPrefix(string, DQN_STR8("0x"), Dqn_Str8EqCase_Insensitive);
for (Dqn_usize index = 0; result && index < string.size; index++) {
char ch = trimmed.data[index];
result = (ch >= '0' && ch <= '9') || (ch >= 'a' && ch <= 'f') || (ch >= 'A' && ch <= 'F');
@ -71,37 +70,37 @@ DQN_API bool Dqn_String8_IsAll(Dqn_String8 string, Dqn_String8IsAll is_all)
return result;
}
DQN_API Dqn_String8 Dqn_String8_Slice(Dqn_String8 string, Dqn_usize offset, Dqn_usize size)
DQN_API Dqn_Str8 Dqn_Str8_Slice(Dqn_Str8 string, Dqn_usize offset, Dqn_usize size)
{
Dqn_String8 result = Dqn_String8_Init(string.data, 0);
if (!Dqn_String8_IsValid(result))
Dqn_Str8 result = Dqn_Str8_Init(string.data, 0);
if (!Dqn_Str8_IsValid(result))
return result;
Dqn_usize capped_offset = DQN_MIN(offset, string.size);
Dqn_usize max_size = string.size - capped_offset;
Dqn_usize capped_size = DQN_MIN(size, max_size);
result = Dqn_String8_Init(string.data + capped_offset, capped_size);
result = Dqn_Str8_Init(string.data + capped_offset, capped_size);
return result;
}
DQN_API Dqn_String8 Dqn_String8_Advance(Dqn_String8 string, Dqn_usize amount)
DQN_API Dqn_Str8 Dqn_Str8_Advance(Dqn_Str8 string, Dqn_usize amount)
{
Dqn_String8 result = Dqn_String8_Slice(string, amount, UINT64_MAX);
Dqn_Str8 result = Dqn_Str8_Slice(string, amount, DQN_USIZE_MAX);
return result;
}
DQN_API Dqn_String8BinarySplitResult Dqn_String8_BinarySplitArray(Dqn_String8 string, Dqn_String8 const *find, Dqn_usize find_size)
DQN_API Dqn_Str8BinarySplitResult Dqn_Str8_BinarySplitArray(Dqn_Str8 string, Dqn_Str8 const *find, Dqn_usize find_size)
{
Dqn_String8BinarySplitResult result = {};
if (!Dqn_String8_IsValid(string) || !find || find_size == 0)
Dqn_Str8BinarySplitResult result = {};
if (!Dqn_Str8_IsValid(string) || !find || find_size == 0)
return result;
result.lhs = string;
for (size_t index = 0; !result.rhs.data && index <= string.size; index++) {
for (size_t index = 0; !result.rhs.data && index < string.size; index++) {
for (Dqn_usize find_index = 0; find_index < find_size; find_index++) {
Dqn_String8 find_item = find[find_index];
Dqn_String8 string_slice = Dqn_String8_Slice(string, index, find_item.size);
if (Dqn_String8_Eq(string_slice, find_item)) {
Dqn_Str8 find_item = find[find_index];
Dqn_Str8 string_slice = Dqn_Str8_Slice(string, index, find_item.size);
if (Dqn_Str8_Eq(string_slice, find_item)) {
result.lhs.size = index;
result.rhs.data = string_slice.data + find_item.size;
result.rhs.size = string.size - (index + find_item.size);
@ -113,72 +112,92 @@ DQN_API Dqn_String8BinarySplitResult Dqn_String8_BinarySplitArray(Dqn_String8 st
return result;
}
DQN_API Dqn_String8BinarySplitResult Dqn_String8_BinarySplit(Dqn_String8 string, Dqn_String8 find)
DQN_API Dqn_Str8BinarySplitResult Dqn_Str8_BinarySplit(Dqn_Str8 string, Dqn_Str8 find)
{
Dqn_String8BinarySplitResult result = Dqn_String8_BinarySplitArray(string, &find, 1);
Dqn_Str8BinarySplitResult result = Dqn_Str8_BinarySplitArray(string, &find, 1);
return result;
}
DQN_API Dqn_usize Dqn_String8_Split(Dqn_String8 string, Dqn_String8 delimiter, Dqn_String8 *splits, Dqn_usize splits_count)
DQN_API Dqn_Str8BinarySplitResult Dqn_Str8_BinarySplitReverseArray(Dqn_Str8 string, Dqn_Str8 const *find, Dqn_usize find_size)
{
Dqn_usize result = 0; // The number of splits in the actual string.
if (!Dqn_String8_IsValid(string) || !Dqn_String8_IsValid(delimiter) || delimiter.size <= 0)
Dqn_Str8BinarySplitResult result = {};
if (!Dqn_Str8_IsValid(string) || !find || find_size == 0)
return result;
Dqn_usize splits_index = 0; // The number of splits written.
Dqn_usize begin = 0;
for (Dqn_usize index = 0; index < string.size; ) {
// NOTE: Check if we encountered the substring that is the delimiter
Dqn_String8 check = Dqn_String8_Slice(string, index, delimiter.size);
if (!Dqn_String8_Eq(check, delimiter)) {
index++;
continue;
result.lhs = string;
for (size_t index = string.size - 1; !result.rhs.data && index < string.size; index--) {
for (Dqn_usize find_index = 0; find_index < find_size; find_index++) {
Dqn_Str8 find_item = find[find_index];
Dqn_Str8 string_slice = Dqn_Str8_Slice(string, index, find_item.size);
if (Dqn_Str8_Eq(string_slice, find_item)) {
result.lhs.size = index;
result.rhs.data = string_slice.data + find_item.size;
result.rhs.size = string.size - (index + find_item.size);
break;
}
}
// NOTE: Generate the split
Dqn_String8 split = Dqn_String8_Init(string.data + begin, index - begin);
if (splits && splits_index < splits_count && split.size)
splits[splits_index++] = split;
// NOTE: Advance the iterators
result += (split.size > 0);
index += delimiter.size;
begin = index;
}
return result;
}
DQN_API Dqn_String8SplitAllocResult Dqn_String8_SplitAlloc(Dqn_Allocator allocator,
Dqn_String8 string,
Dqn_String8 delimiter)
DQN_API Dqn_Str8BinarySplitResult Dqn_Str8_BinarySplitReverse(Dqn_Str8 string, Dqn_Str8 find)
{
Dqn_String8SplitAllocResult result = {};
Dqn_usize splits_required = Dqn_String8_Split(string, delimiter, /*splits*/ nullptr, /*count*/ 0);
result.data = Dqn_Allocator_NewArray(allocator, Dqn_String8, splits_required, Dqn_ZeroMem_No);
Dqn_Str8BinarySplitResult result = Dqn_Str8_BinarySplitReverseArray(string, &find, 1);
return result;
}
DQN_API Dqn_usize Dqn_Str8_Split(Dqn_Str8 string, Dqn_Str8 delimiter, Dqn_Str8 *splits, Dqn_usize splits_count)
{
Dqn_usize result = 0; // The number of splits in the actual string.
if (!Dqn_Str8_IsValid(string) || !Dqn_Str8_IsValid(delimiter) || delimiter.size <= 0)
return result;
Dqn_Str8BinarySplitResult split = {};
Dqn_Str8 first = string;
do {
split = Dqn_Str8_BinarySplit(first, delimiter);
if (split.lhs.size) {
if (splits && result < splits_count)
splits[result] = split.lhs;
result++;
}
first = split.rhs;
} while (first.size);
return result;
}
DQN_API Dqn_Str8SplitAllocResult Dqn_Str8_SplitAlloc(Dqn_Allocator allocator,
Dqn_Str8 string,
Dqn_Str8 delimiter)
{
Dqn_Str8SplitAllocResult result = {};
Dqn_usize splits_required = Dqn_Str8_Split(string, delimiter, /*splits*/ nullptr, /*count*/ 0);
result.data = Dqn_Allocator_NewArray(allocator, Dqn_Str8, splits_required, Dqn_ZeroMem_No);
if (result.data) {
result.size = Dqn_String8_Split(string, delimiter, result.data, splits_required);
result.size = Dqn_Str8_Split(string, delimiter, result.data, splits_required);
DQN_ASSERT(splits_required == result.size);
}
return result;
}
DQN_API Dqn_String8FindResult Dqn_String8_FindFirstStringArray(Dqn_String8 string, Dqn_String8 const *find, Dqn_usize find_size)
DQN_API Dqn_Str8FindResult Dqn_Str8_FindFirstStringArray(Dqn_Str8 string, Dqn_Str8 const *find, Dqn_usize find_size)
{
Dqn_String8FindResult result = {};
if (!Dqn_String8_IsValid(string) || !find || find_size == 0)
Dqn_Str8FindResult result = {};
if (!Dqn_Str8_IsValid(string) || !find || find_size == 0)
return result;
for (Dqn_usize index = 0; !result.found && index < string.size; index++) {
for (Dqn_usize find_index = 0; find_index < find_size; find_index++) {
Dqn_String8 find_item = find[find_index];
Dqn_String8 string_slice = Dqn_String8_Slice(string, index, find_item.size);
if (Dqn_String8_Eq(string_slice, find_item)) {
Dqn_Str8 find_item = find[find_index];
Dqn_Str8 string_slice = Dqn_Str8_Slice(string, index, find_item.size);
if (Dqn_Str8_Eq(string_slice, find_item)) {
result.found = true;
result.index = index;
result.start_to_before_match = Dqn_String8_Init(string.data, index);
result.match = Dqn_String8_Init(string.data + index, find_item.size);
result.match_to_end_of_buffer = Dqn_String8_Init(result.match.data, string.size - index);
result.start_to_before_match = Dqn_Str8_Init(string.data, index);
result.match = Dqn_Str8_Init(string.data + index, find_item.size);
result.match_to_end_of_buffer = Dqn_Str8_Init(result.match.data, string.size - index);
break;
}
}
@ -186,37 +205,37 @@ DQN_API Dqn_String8FindResult Dqn_String8_FindFirstStringArray(Dqn_String8 strin
return result;
}
DQN_API Dqn_String8FindResult Dqn_String8_FindFirstString(Dqn_String8 string, Dqn_String8 find)
DQN_API Dqn_Str8FindResult Dqn_Str8_FindFirstString(Dqn_Str8 string, Dqn_Str8 find)
{
Dqn_String8FindResult result = Dqn_String8_FindFirstStringArray(string, &find, 1);
Dqn_Str8FindResult result = Dqn_Str8_FindFirstStringArray(string, &find, 1);
return result;
}
DQN_API Dqn_String8FindResult Dqn_String8_FindFirst(Dqn_String8 string, uint32_t flags)
DQN_API Dqn_Str8FindResult Dqn_Str8_FindFirst(Dqn_Str8 string, uint32_t flags)
{
Dqn_String8FindResult result = {};
Dqn_Str8FindResult result = {};
for (size_t index = 0; !result.found && index < string.size; index++) {
result.found |= ((flags & Dqn_String8FindFlag_Digit) && Dqn_Char_IsDigit(string.data[index]));
result.found |= ((flags & Dqn_String8FindFlag_Alphabet) && Dqn_Char_IsAlphabet(string.data[index]));
result.found |= ((flags & Dqn_String8FindFlag_Whitespace) && Dqn_Char_IsWhitespace(string.data[index]));
result.found |= ((flags & Dqn_String8FindFlag_Plus) && string.data[index] == '+');
result.found |= ((flags & Dqn_String8FindFlag_Minus) && string.data[index] == '-');
result.found |= ((flags & Dqn_Str8FindFlag_Digit) && Dqn_Char_IsDigit(string.data[index]));
result.found |= ((flags & Dqn_Str8FindFlag_Alphabet) && Dqn_Char_IsAlphabet(string.data[index]));
result.found |= ((flags & Dqn_Str8FindFlag_Whitespace) && Dqn_Char_IsWhitespace(string.data[index]));
result.found |= ((flags & Dqn_Str8FindFlag_Plus) && string.data[index] == '+');
result.found |= ((flags & Dqn_Str8FindFlag_Minus) && string.data[index] == '-');
if (result.found) {
result.index = index;
result.match = Dqn_String8_Init(string.data + index, 1);
result.match_to_end_of_buffer = Dqn_String8_Init(result.match.data, string.size - index);
result.match = Dqn_Str8_Init(string.data + index, 1);
result.match_to_end_of_buffer = Dqn_Str8_Init(result.match.data, string.size - index);
}
}
return result;
}
DQN_API Dqn_String8 Dqn_String8_Segment(Dqn_Allocator allocator, Dqn_String8 src, Dqn_usize segment_size, char segment_char)
DQN_API Dqn_Str8 Dqn_Str8_Segment(Dqn_Allocator allocator, Dqn_Str8 src, Dqn_usize segment_size, char segment_char)
{
Dqn_usize result_size = src.size;
if (result_size > segment_size)
result_size += (src.size / segment_size) - 1; // NOTE: No segment on the first chunk.
Dqn_String8 result = Dqn_String8_Allocate(allocator, result_size, Dqn_ZeroMem_Yes);
Dqn_Str8 result = Dqn_Str8_Allocate(allocator, result_size, Dqn_ZeroMem_Yes);
Dqn_usize write_index = 0;
DQN_FOR_UINDEX(src_index, src.size) {
result.data[write_index++] = src.data[src_index];
@ -230,7 +249,7 @@ DQN_API Dqn_String8 Dqn_String8_Segment(Dqn_Allocator allocator, Dqn_String8 src
}
DQN_API bool Dqn_String8_Eq(Dqn_String8 lhs, Dqn_String8 rhs, Dqn_String8EqCase eq_case)
DQN_API bool Dqn_Str8_Eq(Dqn_Str8 lhs, Dqn_Str8 rhs, Dqn_Str8EqCase eq_case)
{
if (lhs.size != rhs.size)
return false;
@ -243,11 +262,11 @@ DQN_API bool Dqn_String8_Eq(Dqn_String8 lhs, Dqn_String8 rhs, Dqn_String8EqCase
bool result = true;
switch (eq_case) {
case Dqn_String8EqCase_Sensitive: {
case Dqn_Str8EqCase_Sensitive: {
result = (DQN_MEMCMP(lhs.data, rhs.data, lhs.size) == 0);
} break;
case Dqn_String8EqCase_Insensitive: {
case Dqn_Str8EqCase_Insensitive: {
for (Dqn_usize index = 0; index < lhs.size && result; index++)
result = (Dqn_Char_ToLower(lhs.data[index]) == Dqn_Char_ToLower(rhs.data[index]));
} break;
@ -255,39 +274,39 @@ DQN_API bool Dqn_String8_Eq(Dqn_String8 lhs, Dqn_String8 rhs, Dqn_String8EqCase
return result;
}
DQN_API bool Dqn_String8_EqInsensitive(Dqn_String8 lhs, Dqn_String8 rhs)
DQN_API bool Dqn_Str8_EqInsensitive(Dqn_Str8 lhs, Dqn_Str8 rhs)
{
bool result = Dqn_String8_Eq(lhs, rhs, Dqn_String8EqCase_Insensitive);
bool result = Dqn_Str8_Eq(lhs, rhs, Dqn_Str8EqCase_Insensitive);
return result;
}
DQN_API bool Dqn_String8_StartsWith(Dqn_String8 string, Dqn_String8 prefix, Dqn_String8EqCase eq_case)
DQN_API bool Dqn_Str8_StartsWith(Dqn_Str8 string, Dqn_Str8 prefix, Dqn_Str8EqCase eq_case)
{
Dqn_String8 substring = {string.data, DQN_MIN(prefix.size, string.size)};
bool result = Dqn_String8_Eq(substring, prefix, eq_case);
Dqn_Str8 substring = {string.data, DQN_MIN(prefix.size, string.size)};
bool result = Dqn_Str8_Eq(substring, prefix, eq_case);
return result;
}
DQN_API bool Dqn_String8_StartsWithInsensitive(Dqn_String8 string, Dqn_String8 prefix)
DQN_API bool Dqn_Str8_StartsWithInsensitive(Dqn_Str8 string, Dqn_Str8 prefix)
{
bool result = Dqn_String8_StartsWith(string, prefix, Dqn_String8EqCase_Insensitive);
bool result = Dqn_Str8_StartsWith(string, prefix, Dqn_Str8EqCase_Insensitive);
return result;
}
DQN_API bool Dqn_String8_EndsWith(Dqn_String8 string, Dqn_String8 suffix, Dqn_String8EqCase eq_case)
DQN_API bool Dqn_Str8_EndsWith(Dqn_Str8 string, Dqn_Str8 suffix, Dqn_Str8EqCase eq_case)
{
Dqn_String8 substring = {string.data + string.size - suffix.size, DQN_MIN(string.size, suffix.size)};
bool result = Dqn_String8_Eq(substring, suffix, eq_case);
Dqn_Str8 substring = {string.data + string.size - suffix.size, DQN_MIN(string.size, suffix.size)};
bool result = Dqn_Str8_Eq(substring, suffix, eq_case);
return result;
}
DQN_API bool Dqn_String8_EndsWithInsensitive(Dqn_String8 string, Dqn_String8 suffix)
DQN_API bool Dqn_Str8_EndsWithInsensitive(Dqn_Str8 string, Dqn_Str8 suffix)
{
bool result = Dqn_String8_EndsWith(string, suffix, Dqn_String8EqCase_Insensitive);
bool result = Dqn_Str8_EndsWith(string, suffix, Dqn_Str8EqCase_Insensitive);
return result;
}
DQN_API bool Dqn_String8_HasChar(Dqn_String8 string, char ch)
DQN_API bool Dqn_Str8_HasChar(Dqn_Str8 string, char ch)
{
bool result = false;
for (Dqn_usize index = 0; !result && index < string.size; index++)
@ -295,28 +314,35 @@ DQN_API bool Dqn_String8_HasChar(Dqn_String8 string, char ch)
return result;
}
DQN_API Dqn_String8 Dqn_String8_TrimPrefix(Dqn_String8 string, Dqn_String8 prefix, Dqn_String8EqCase eq_case)
DQN_API Dqn_Str8 Dqn_Str8_TrimPrefix(Dqn_Str8 string, Dqn_Str8 prefix, Dqn_Str8EqCase eq_case)
{
Dqn_String8 result = string;
if (Dqn_String8_StartsWith(string, prefix, eq_case)) {
Dqn_Str8 result = string;
if (Dqn_Str8_StartsWith(string, prefix, eq_case)) {
result.data += prefix.size;
result.size -= prefix.size;
}
return result;
}
DQN_API Dqn_String8 Dqn_String8_TrimSuffix(Dqn_String8 string, Dqn_String8 suffix, Dqn_String8EqCase eq_case)
DQN_API Dqn_Str8 Dqn_Str8_TrimSuffix(Dqn_Str8 string, Dqn_Str8 suffix, Dqn_Str8EqCase eq_case)
{
Dqn_String8 result = string;
if (Dqn_String8_EndsWith(string, suffix, eq_case))
Dqn_Str8 result = string;
if (Dqn_Str8_EndsWith(string, suffix, eq_case))
result.size -= suffix.size;
return result;
}
DQN_API Dqn_String8 Dqn_String8_TrimWhitespaceAround(Dqn_String8 string)
DQN_API Dqn_Str8 Dqn_Str8_TrimAround(Dqn_Str8 string, Dqn_Str8 trim_string)
{
Dqn_String8 result = string;
if (!Dqn_String8_IsValid(string))
Dqn_Str8 result = Dqn_Str8_TrimPrefix(string, trim_string);
result = Dqn_Str8_TrimSuffix(result, trim_string);
return result;
}
DQN_API Dqn_Str8 Dqn_Str8_TrimWhitespaceAround(Dqn_Str8 string)
{
Dqn_Str8 result = string;
if (!Dqn_Str8_IsValid(string))
return result;
char const *start = string.data;
@ -327,60 +353,62 @@ DQN_API Dqn_String8 Dqn_String8_TrimWhitespaceAround(Dqn_String8 string)
while (end > start && Dqn_Char_IsWhitespace(end[-1]))
end--;
result = Dqn_String8_Init(start, end - start);
result = Dqn_Str8_Init(start, end - start);
return result;
}
DQN_API Dqn_String8 Dqn_String8_TrimByteOrderMark(Dqn_String8 string)
DQN_API Dqn_Str8 Dqn_Str8_TrimByteOrderMark(Dqn_Str8 string)
{
Dqn_String8 result = string;
if (!Dqn_String8_IsValid(result))
Dqn_Str8 result = string;
if (!Dqn_Str8_IsValid(result))
return result;
// TODO(dqn): This is little endian
Dqn_String8 UTF8_BOM = DQN_STRING8("\xEF\xBB\xBF");
Dqn_String8 UTF16_BOM_BE = DQN_STRING8("\xEF\xFF");
Dqn_String8 UTF16_BOM_LE = DQN_STRING8("\xFF\xEF");
Dqn_String8 UTF32_BOM_BE = DQN_STRING8("\x00\x00\xFE\xFF");
Dqn_String8 UTF32_BOM_LE = DQN_STRING8("\xFF\xFE\x00\x00");
Dqn_Str8 UTF8_BOM = DQN_STR8("\xEF\xBB\xBF");
Dqn_Str8 UTF16_BOM_BE = DQN_STR8("\xEF\xFF");
Dqn_Str8 UTF16_BOM_LE = DQN_STR8("\xFF\xEF");
Dqn_Str8 UTF32_BOM_BE = DQN_STR8("\x00\x00\xFE\xFF");
Dqn_Str8 UTF32_BOM_LE = DQN_STR8("\xFF\xFE\x00\x00");
result = Dqn_String8_TrimPrefix(result, UTF8_BOM, Dqn_String8EqCase_Sensitive);
result = Dqn_String8_TrimPrefix(result, UTF16_BOM_BE, Dqn_String8EqCase_Sensitive);
result = Dqn_String8_TrimPrefix(result, UTF16_BOM_LE, Dqn_String8EqCase_Sensitive);
result = Dqn_String8_TrimPrefix(result, UTF32_BOM_BE, Dqn_String8EqCase_Sensitive);
result = Dqn_String8_TrimPrefix(result, UTF32_BOM_LE, Dqn_String8EqCase_Sensitive);
result = Dqn_Str8_TrimPrefix(result, UTF8_BOM, Dqn_Str8EqCase_Sensitive);
result = Dqn_Str8_TrimPrefix(result, UTF16_BOM_BE, Dqn_Str8EqCase_Sensitive);
result = Dqn_Str8_TrimPrefix(result, UTF16_BOM_LE, Dqn_Str8EqCase_Sensitive);
result = Dqn_Str8_TrimPrefix(result, UTF32_BOM_BE, Dqn_Str8EqCase_Sensitive);
result = Dqn_Str8_TrimPrefix(result, UTF32_BOM_LE, Dqn_Str8EqCase_Sensitive);
return result;
}
DQN_API Dqn_String8 Dqn_String8_FileNameFromPath(Dqn_String8 path)
DQN_API Dqn_Str8 Dqn_Str8_FileNameFromPath(Dqn_Str8 path)
{
Dqn_String8 result = path;
if (!Dqn_String8_IsValid(result))
return result;
DQN_MSVC_WARNING_PUSH
DQN_MSVC_WARNING_DISABLE(6293) // Ill-defined for-loop.
for (Dqn_usize index = result.size - 1; index < result.size; --index) {
if (result.data[index] == '\\' || result.data[index] == '/') {
char const *end = result.data + result.size;
result.data = result.data + (index + 1);
result.size = end - result.data;
break;
}
}
DQN_MSVC_WARNING_POP
Dqn_Str8 separators[] = {DQN_STR8("/"), DQN_STR8("\\")};
Dqn_Str8BinarySplitResult split = Dqn_Str8_BinarySplitReverseArray(path, separators, DQN_ARRAY_UCOUNT(separators));
Dqn_Str8 result = split.rhs;
return result;
}
DQN_API Dqn_String8ToU64Result Dqn_String8_ToU64(Dqn_String8 string, char separator)
DQN_API Dqn_Str8 Dqn_Str8_FileNameNoExtension(Dqn_Str8 path)
{
Dqn_Str8 file_name = Dqn_Str8_FileNameFromPath(path);
Dqn_Str8 result = Dqn_Str8_FilePathNoExtension(file_name);
return result;
}
DQN_API Dqn_Str8 Dqn_Str8_FilePathNoExtension(Dqn_Str8 path)
{
Dqn_Str8BinarySplitResult split = Dqn_Str8_BinarySplitReverse(path, DQN_STR8("."));
Dqn_Str8 result = split.lhs;
return result;
}
DQN_API Dqn_Str8ToU64Result Dqn_Str8_ToU64(Dqn_Str8 string, char separator)
{
// NOTE: Argument check
Dqn_String8ToU64Result result = {};
if (!Dqn_String8_IsValid(string))
Dqn_Str8ToU64Result result = {};
if (!Dqn_Str8_IsValid(string))
return result;
// NOTE: Sanitize input/output
Dqn_String8 trim_string = Dqn_String8_TrimWhitespaceAround(string);
Dqn_Str8 trim_string = Dqn_Str8_TrimWhitespaceAround(string);
if (trim_string.size == 0) {
result.success = false;
return result;
@ -414,15 +442,15 @@ DQN_API Dqn_String8ToU64Result Dqn_String8_ToU64(Dqn_String8 string, char separa
return result;
}
DQN_API Dqn_String8ToI64Result Dqn_String8_ToI64(Dqn_String8 string, char separator)
DQN_API Dqn_Str8ToI64Result Dqn_Str8_ToI64(Dqn_Str8 string, char separator)
{
// NOTE: Argument check
Dqn_String8ToI64Result result = {};
if (!Dqn_String8_IsValid(string))
Dqn_Str8ToI64Result result = {};
if (!Dqn_Str8_IsValid(string))
return result;
// NOTE: Sanitize input/output
Dqn_String8 trim_string = Dqn_String8_TrimWhitespaceAround(string);
Dqn_Str8 trim_string = Dqn_Str8_TrimWhitespaceAround(string);
if (trim_string.size == 0) {
result.success = false;
return result;
@ -460,28 +488,28 @@ DQN_API Dqn_String8ToI64Result Dqn_String8_ToI64(Dqn_String8 string, char separa
return result;
}
DQN_API Dqn_String8 Dqn_String8_Replace(Dqn_String8 string,
Dqn_String8 find,
Dqn_String8 replace,
Dqn_usize start_index,
Dqn_Allocator allocator,
Dqn_String8EqCase eq_case)
DQN_API Dqn_Str8 Dqn_Str8_Replace(Dqn_Str8 string,
Dqn_Str8 find,
Dqn_Str8 replace,
Dqn_usize start_index,
Dqn_Allocator allocator,
Dqn_Str8EqCase eq_case)
{
Dqn_String8 result = {};
if (!Dqn_String8_IsValid(string) || !Dqn_String8_IsValid(find) || find.size > string.size || find.size == 0 || string.size == 0) {
result = Dqn_String8_Copy(allocator, string);
Dqn_Str8 result = {};
if (!Dqn_Str8_IsValid(string) || !Dqn_Str8_IsValid(find) || find.size > string.size || find.size == 0 || string.size == 0) {
result = Dqn_Str8_Copy(allocator, string);
return result;
}
Dqn_ThreadScratch scratch = Dqn_Thread_GetScratch(allocator.user_context);
Dqn_String8Builder string_builder = {};
string_builder.allocator = scratch.allocator;
Dqn_usize max = string.size - find.size;
Dqn_usize head = start_index;
Dqn_ThreadScratch scratch = Dqn_Thread_GetScratch(allocator.user_context);
Dqn_Str8Builder string_builder = {};
string_builder.allocator = scratch.allocator;
Dqn_usize max = string.size - find.size;
Dqn_usize head = start_index;
for (Dqn_usize tail = head; tail <= max; tail++) {
Dqn_String8 check = Dqn_String8_Slice(string, tail, find.size);
if (!Dqn_String8_Eq(check, find, eq_case))
Dqn_Str8 check = Dqn_Str8_Slice(string, tail, find.size);
if (!Dqn_Str8_Eq(check, find, eq_case))
continue;
if (start_index > 0 && string_builder.string_size == 0) {
@ -489,38 +517,38 @@ DQN_API Dqn_String8 Dqn_String8_Replace(Dqn_String8 string,
// need to add the string up to the hint. We only do this if there's
// a replacement action, otherwise we have a special case for no
// replacements, where the entire string gets copied.
Dqn_String8 slice = Dqn_String8_Init(string.data, head);
Dqn_String8Builder_AppendRef(&string_builder, slice);
Dqn_Str8 slice = Dqn_Str8_Init(string.data, head);
Dqn_Str8Builder_AppendRef(&string_builder, slice);
}
Dqn_String8 range = Dqn_String8_Slice(string, head, (tail - head));
Dqn_String8Builder_AppendRef(&string_builder, range);
Dqn_String8Builder_AppendRef(&string_builder, replace);
Dqn_Str8 range = Dqn_Str8_Slice(string, head, (tail - head));
Dqn_Str8Builder_AppendRef(&string_builder, range);
Dqn_Str8Builder_AppendRef(&string_builder, replace);
head = tail + find.size;
tail += find.size - 1; // NOTE: -1 since the for loop will post increment us past the end of the find string
}
if (string_builder.string_size == 0) {
// NOTE: No replacement possible, so we just do a full-copy
result = Dqn_String8_Copy(allocator, string);
result = Dqn_Str8_Copy(allocator, string);
} else {
Dqn_String8 remainder = Dqn_String8_Init(string.data + head, string.size - head);
Dqn_String8Builder_AppendRef(&string_builder, remainder);
result = Dqn_String8Builder_Build(&string_builder, allocator);
Dqn_Str8 remainder = Dqn_Str8_Init(string.data + head, string.size - head);
Dqn_Str8Builder_AppendRef(&string_builder, remainder);
result = Dqn_Str8Builder_Build(&string_builder, allocator);
}
return result;
}
DQN_API Dqn_String8 Dqn_String8_ReplaceInsensitive(Dqn_String8 string, Dqn_String8 find, Dqn_String8 replace, Dqn_usize start_index, Dqn_Allocator allocator)
DQN_API Dqn_Str8 Dqn_Str8_ReplaceInsensitive(Dqn_Str8 string, Dqn_Str8 find, Dqn_Str8 replace, Dqn_usize start_index, Dqn_Allocator allocator)
{
Dqn_String8 result = Dqn_String8_Replace(string, find, replace, start_index, allocator, Dqn_String8EqCase_Insensitive);
Dqn_Str8 result = Dqn_Str8_Replace(string, find, replace, start_index, allocator, Dqn_Str8EqCase_Insensitive);
return result;
}
DQN_API void Dqn_String8_Remove(Dqn_String8 *string, Dqn_usize offset, Dqn_usize size)
DQN_API void Dqn_Str8_Remove(Dqn_Str8 *string, Dqn_usize offset, Dqn_usize size)
{
if (!string || !Dqn_String8_IsValid(*string))
if (!string || !Dqn_Str8_IsValid(*string))
return;
char *end = string->data + string->size;
@ -532,79 +560,79 @@ DQN_API void Dqn_String8_Remove(Dqn_String8 *string, Dqn_usize offset, Dqn_usize
}
#if defined(__cplusplus)
DQN_API bool operator==(Dqn_String8 const &lhs, Dqn_String8 const &rhs)
DQN_API bool operator==(Dqn_Str8 const &lhs, Dqn_Str8 const &rhs)
{
bool result = Dqn_String8_Eq(lhs, rhs, Dqn_String8EqCase_Sensitive);
bool result = Dqn_Str8_Eq(lhs, rhs, Dqn_Str8EqCase_Sensitive);
return result;
}
DQN_API bool operator!=(Dqn_String8 const &lhs, Dqn_String8 const &rhs)
DQN_API bool operator!=(Dqn_Str8 const &lhs, Dqn_Str8 const &rhs)
{
bool result = !(lhs == rhs);
return result;
}
#endif
DQN_API Dqn_String8 Dqn_String8_InitF(Dqn_Allocator allocator, DQN_FMT_STRING_ANNOTATE char const *fmt, ...)
DQN_API Dqn_Str8 Dqn_Str8_InitF(Dqn_Allocator allocator, DQN_FMT_ATTRIB char const *fmt, ...)
{
va_list va;
va_start(va, fmt);
Dqn_String8 result = Dqn_String8_InitFV(allocator, fmt, va);
Dqn_Str8 result = Dqn_Str8_InitFV(allocator, fmt, va);
va_end(va);
return result;
}
DQN_API Dqn_String8 Dqn_String8_InitFV(Dqn_Allocator allocator, DQN_FMT_STRING_ANNOTATE char const *fmt, va_list args)
DQN_API Dqn_Str8 Dqn_Str8_InitFV(Dqn_Allocator allocator, DQN_FMT_ATTRIB char const *fmt, va_list args)
{
Dqn_String8 result = {};
Dqn_Str8 result = {};
if (!fmt)
return result;
Dqn_usize size = Dqn_CString8_FVSize(fmt, args);
Dqn_usize size = Dqn_CStr8_FVSize(fmt, args);
if (size) {
result = Dqn_String8_Allocate(allocator, size, Dqn_ZeroMem_No);
if (Dqn_String8_IsValid(result))
result = Dqn_Str8_Allocate(allocator, size, Dqn_ZeroMem_No);
if (Dqn_Str8_IsValid(result))
STB_SPRINTF_DECORATE(vsnprintf)(result.data, Dqn_Safe_SaturateCastISizeToInt(size + 1 /*null-terminator*/), fmt, args);
}
return result;
}
DQN_API Dqn_String8 Dqn_String8_Allocate(Dqn_Allocator allocator, Dqn_usize size, Dqn_ZeroMem zero_mem)
DQN_API Dqn_Str8 Dqn_Str8_Allocate(Dqn_Allocator allocator, Dqn_usize size, Dqn_ZeroMem zero_mem)
{
Dqn_String8 result = {};
result.data = (char *)Dqn_Allocator_Alloc(allocator, size + 1, alignof(char), zero_mem);
Dqn_Str8 result = {};
result.data = (char *)Dqn_Allocator_Alloc(allocator, size + 1, alignof(char), zero_mem);
if (result.data)
result.size = size;
return result;
}
DQN_API Dqn_String8 Dqn_String8_CopyCString(Dqn_Allocator allocator, char const *string, Dqn_usize size)
DQN_API Dqn_Str8 Dqn_Str8_CopyCString(Dqn_Allocator allocator, char const *string, Dqn_usize size)
{
Dqn_String8 result = {};
Dqn_Str8 result = {};
if (!string)
return result;
result = Dqn_String8_Allocate(allocator, size, Dqn_ZeroMem_No);
if (Dqn_String8_IsValid(result)) {
result = Dqn_Str8_Allocate(allocator, size, Dqn_ZeroMem_No);
if (Dqn_Str8_IsValid(result)) {
DQN_MEMCPY(result.data, string, size);
result.data[size] = 0;
}
return result;
}
DQN_API Dqn_String8 Dqn_String8_Copy(Dqn_Allocator allocator, Dqn_String8 string)
DQN_API Dqn_Str8 Dqn_Str8_Copy(Dqn_Allocator allocator, Dqn_Str8 string)
{
Dqn_String8 result = Dqn_String8_CopyCString(allocator, string.data, string.size);
Dqn_Str8 result = Dqn_Str8_CopyCString(allocator, string.data, string.size);
return result;
}
// NOTE: [$STRB] Dqn_String8Builder ================================================================
DQN_API bool Dqn_String8Builder_AppendRef(Dqn_String8Builder *builder, Dqn_String8 string)
// NOTE: [$STRB] Dqn_Str8Builder ================================================================
DQN_API bool Dqn_Str8Builder_AppendRef(Dqn_Str8Builder *builder, Dqn_Str8 string)
{
if (!builder || !string.data || string.size <= 0)
return false;
Dqn_String8Link *link = Dqn_Allocator_New(builder->allocator, Dqn_String8Link, Dqn_ZeroMem_No);
Dqn_Str8Link *link = Dqn_Allocator_New(builder->allocator, Dqn_Str8Link, Dqn_ZeroMem_No);
if (!link)
return false;
@ -622,37 +650,37 @@ DQN_API bool Dqn_String8Builder_AppendRef(Dqn_String8Builder *builder, Dqn_Strin
return true;
}
DQN_API bool Dqn_String8Builder_AppendCopy(Dqn_String8Builder *builder, Dqn_String8 string)
DQN_API bool Dqn_Str8Builder_AppendCopy(Dqn_Str8Builder *builder, Dqn_Str8 string)
{
Dqn_String8 copy = Dqn_String8_Copy(builder->allocator, string);
bool result = Dqn_String8Builder_AppendRef(builder, copy);
Dqn_Str8 copy = Dqn_Str8_Copy(builder->allocator, string);
bool result = Dqn_Str8Builder_AppendRef(builder, copy);
return result;
}
DQN_API bool Dqn_String8Builder_AppendFV(Dqn_String8Builder *builder, DQN_FMT_STRING_ANNOTATE char const *fmt, va_list args)
DQN_API bool Dqn_Str8Builder_AppendFV(Dqn_Str8Builder *builder, DQN_FMT_ATTRIB char const *fmt, va_list args)
{
Dqn_String8 string = Dqn_String8_InitFV(builder->allocator, fmt, args);
Dqn_Str8 string = Dqn_Str8_InitFV(builder->allocator, fmt, args);
if (string.size == 0)
return true;
bool result = Dqn_String8Builder_AppendRef(builder, string);
bool result = Dqn_Str8Builder_AppendRef(builder, string);
if (!result)
Dqn_Allocator_Dealloc(builder->allocator, string.data, string.size + 1);
return result;
}
DQN_API bool Dqn_String8Builder_AppendF(Dqn_String8Builder *builder, DQN_FMT_STRING_ANNOTATE char const *fmt, ...)
DQN_API bool Dqn_Str8Builder_AppendF(Dqn_Str8Builder *builder, DQN_FMT_ATTRIB char const *fmt, ...)
{
va_list args;
va_start(args, fmt);
bool result = Dqn_String8Builder_AppendFV(builder, fmt, args);
bool result = Dqn_Str8Builder_AppendFV(builder, fmt, args);
va_end(args);
return result;
}
DQN_API Dqn_String8 Dqn_String8Builder_Build(Dqn_String8Builder const *builder, Dqn_Allocator allocator)
DQN_API Dqn_Str8 Dqn_Str8Builder_Build(Dqn_Str8Builder const *builder, Dqn_Allocator allocator)
{
Dqn_String8 result = DQN_ZERO_INIT;
Dqn_Str8 result = DQN_ZERO_INIT;
if (!builder || builder->string_size <= 0 || builder->count <= 0)
return result;
@ -660,7 +688,7 @@ DQN_API Dqn_String8 Dqn_String8Builder_Build(Dqn_String8Builder const *builder,
if (!result.data)
return result;
for (Dqn_String8Link *link = builder->head; link; link = link->next) {
for (Dqn_Str8Link *link = builder->head; link; link = link->next) {
DQN_MEMCPY(result.data + result.size, link->string.data, link->string.size);
result.size += link->string.size;
}
@ -810,4 +838,3 @@ DQN_API int Dqn_UTF16_EncodeCodepoint(uint16_t utf16[2], uint32_t codepoint)
return 0;
}

View File

@ -1,57 +1,57 @@
// NOTE: [$CSTR] Dqn_CString8 ======================================================================
// @proc Dqn_CString8_ArrayCount
// NOTE: [$CSTR] Dqn_CStr8 ======================================================================
// @proc Dqn_CStr8_ArrayCount
// @desc Calculate the size of a cstring literal/array at compile time
// @param literal The cstring literal/array to calculate the size for
// @return The size of the cstring not including the null-terminating byte
// @proc Dqn_CString8_FSize, Dqn_CString8_FVSize
// @proc Dqn_CStr8_FSize, Dqn_CStr8_FVSize
// Calculate the required size to format the given format cstring.
// @param[in] fmt The format string to calculate the size for
// @return The size required to format the string, not including the null
// terminator.
// @proc Dqn_CString8_Size
// @proc Dqn_CStr8_Size
// @desc Calculate the string length of the null-terminated string.
// @param[in] a The string whose length is to be determined
// @return The length of the string
DQN_API template <Dqn_usize N> constexpr Dqn_usize Dqn_CString8_ArrayUCount(char const (&literal)[N]) { (void)literal; return N - 1; }
DQN_API template <Dqn_usize N> constexpr Dqn_usize Dqn_CString8_ArrayICount(char const (&literal)[N]) { (void)literal; return N - 1; }
DQN_API Dqn_usize Dqn_CString8_FSize (DQN_FMT_STRING_ANNOTATE char const *fmt, ...);
DQN_API Dqn_usize Dqn_CString8_FVSize (DQN_FMT_STRING_ANNOTATE char const *fmt, va_list args);
DQN_API Dqn_usize Dqn_CString8_Size (char const *a);
DQN_API Dqn_usize Dqn_CString16_Size (wchar_t const *a);
DQN_API template <Dqn_usize N> constexpr Dqn_usize Dqn_CStr8_ArrayUCount(char const (&literal)[N]) { (void)literal; return N - 1; }
DQN_API template <Dqn_usize N> constexpr Dqn_usize Dqn_CStr8_ArrayICount(char const (&literal)[N]) { (void)literal; return N - 1; }
DQN_API Dqn_usize Dqn_CStr8_FSize (DQN_FMT_ATTRIB char const *fmt, ...);
DQN_API Dqn_usize Dqn_CStr8_FVSize (DQN_FMT_ATTRIB char const *fmt, va_list args);
DQN_API Dqn_usize Dqn_CStr8_Size (char const *a);
DQN_API Dqn_usize Dqn_CStr16_Size (wchar_t const *a);
// NOTE: [$STR8] Dqn_String8 =======================================================================
// NOTE: [$STR8] Dqn_Str8 =======================================================================
// NOTE: API
// @proc Dqn_String8_Init
// @proc Dqn_Str8_Init
// @desc Initialise a string from a pointer and length
// The string is invalid (i.e. Dqn_String8_IsValid() returns false) if size is
// The string is invalid (i.e. Dqn_Str8_IsValid() returns false) if size is
// negative or the string is null.
// @proc Dqn_String8_InitCString
// @proc Dqn_Str8_InitCString
// @desc Initialise a string from a cstring
// The cstring must be null-terminated as its length is evaluated using
// strlen. The string is invalid (i.e. Dqn_String8_IsValid() returns false) if
// strlen. The string is invalid (i.e. Dqn_Str8_IsValid() returns false) if
// size is negative or the string is null.
// @proc Dqn_String8_InitF
// @proc Dqn_Str8_InitF
// @desc Create a string from a printf style format string
// @param[in] allocator The allocator the string will be allocated from
// @param[in] fmt The printf style format cstring
// @proc Dqn_String8_InitFV
// @proc Dqn_Str8_InitFV
// @desc Create a string from a printf style format string using a va_list
// @param[in] arena The allocator the string will be allocated from
// @param[in] fmt The printf style format cstring
// @param[in] va The variable argument list
//
// @proc Dqn_String8_IsValid
// @proc Dqn_Str8_IsValid
// @desc Determine if the values of the given string are valid
// A string is invalid if size is negative or the string is null.
// @return True if the string is valid, false otherwise.
// @proc Dqn_String8 Dqn_String8_Slice
// @proc Dqn_Str8 Dqn_Str8_Slice
// @desc Create a slice from a pre-existing string.
// The requested slice is clamped to within the bounds of the original string.
// @param[in] string The string to slice
@ -59,7 +59,7 @@ DQN_API Dqn_usize Dqn_CString16_Size (wcha
// @param[in] size The size of the slice
// @return The sliced string
// @proc Dqn_String8_BinarySplit
// @proc Dqn_Str8_BinarySplit
// @desc Split a string into the substring occuring prior and after the first
// occurence of the `delimiter`. Neither strings include the `delimiter`.
//
@ -73,7 +73,7 @@ DQN_API Dqn_usize Dqn_CString16_Size (wcha
// @return The left hand side of the split string. The original pointer is
// returned if the arguments were invalid.
// @proc Dqn_String8_Split
// @proc Dqn_Str8_Split
// @desc Split a string by the delimiting character.
// This function can evaluate the number of splits required in the return value
// by setting `splits` to null and `splits_count` to 0.
@ -88,31 +88,31 @@ DQN_API Dqn_usize Dqn_CString16_Size (wcha
// capacity given by the caller, i.e. `splits_count`. This function should be
// called again with a sufficiently sized array if all splits are desired.
// @proc Dqn_String8_Segment
// @proc Dqn_Str8_Segment
// @desc Segment a string by inserting the `segment_char` every `segment_size`
// characters in the string. For example, '123456789' split with
// `segment_char` ' ' and `segment_size` '3' would yield, '123 456 789'.
// @proc Dqn_String8_Allocate
// @proc Dqn_Str8_Allocate
// @desc Create an empty string with the requested size
// @param[in] allocator The allocator the string will be allocated from
// @param[in] size The size in bytes of the string to allocate
// @param[in] zero_mem Enum to indicate if the string's memory should be cleared
// @proc Dqn_String8_CopyCString
// @proc Dqn_Str8_CopyCString
// @desc Create a copy of the given cstring
// @param[in] allocator The allocator the string will be allocated from
// @param[in] string The cstring to copy
// @param[in] size The size of the cstring to copy. This cannot be <= 0
// @return A copy of the string, invalid string if any argument was invalid.
// @proc Dqn_String8_Copy
// @proc Dqn_Str8_Copy
// @desc Create a copy of the given string
// @param[in] allocator The allocator the string will be allocated from
// @param[in] string The string to copy
// @return A copy of the string, invalid string if any argument was invalid.
// @proc Dqn_String8_Eq, Dqn_String8_EqInsensitive
// @proc Dqn_Str8_Eq, Dqn_Str8_EqInsensitive
// @desc Compare a string for equality with or without case sensitivity.
// @param[in] lhs The first string to compare equality with
// @param[in] rhs The second string to compare equality with
@ -122,8 +122,8 @@ DQN_API Dqn_usize Dqn_CString16_Size (wcha
// @return True if the arguments are valid, non-null and the strings
// are equal, false otherwise.
// @proc Dqn_String8_StartsWith, Dqn_String8_StartsWithInsensitive,
// Dqn_String8_EndsWith, Dqn_String8_EndswithInsensitive
// @proc Dqn_Str8_StartsWith, Dqn_Str8_StartsWithInsensitive,
// Dqn_Str8_EndsWith, Dqn_Str8_EndswithInsensitive
// @desc Check if a string starts/ends with the specified prefix
// `EndsWithInsensitive` is case insensitive
// @param[in] string The string to check for the prefix
@ -132,7 +132,7 @@ DQN_API Dqn_usize Dqn_CString16_Size (wcha
// @return True if the string is valid, non-null and has the specified prefix,
// false otherwise.
// @proc Dqn_String8_TrimPrefix, Dqn_String8_TrimSuffix
// @proc Dqn_Str8_TrimPrefix, Dqn_Str8_TrimSuffix
// @desc Remove the prefix/suffix respectively from the given `string.
//
// @param[in] string The string to trim
@ -144,7 +144,7 @@ DQN_API Dqn_usize Dqn_CString16_Size (wcha
// @return The trimmed string. The original input string is returned if
// arguments are invalid or no trim was possible.
// @proc Dqn_String8_TrimWhitespaceAround
// @proc Dqn_Str8_TrimWhitespaceAround
// @desc Trim whitespace from the prefix and suffix of the string
//
// @param[in] string The string to trim
@ -154,7 +154,7 @@ DQN_API Dqn_usize Dqn_CString16_Size (wcha
// @return The trimmed string. The original input string is returned if
// arguments are invalid or no trim was possible.
// @proc Dqn_String8_TrimByteOrderMark
// @proc Dqn_Str8_TrimByteOrderMark
// @desc Trim UTF8, UTF16 BE/LE, UTF32 BE/LE byte order mark prefix in the string.
//
// @param[in] string The string to trim
@ -164,7 +164,7 @@ DQN_API Dqn_usize Dqn_CString16_Size (wcha
// @return The trimmed string. The original input string is returned if
// arguments are invalid or no trim was possible.
// @proc Dqn_String8_FileNameFromPath
// @proc Dqn_Str8_FileNameFromPath
// @desc Get the file name from a file path. The file name is evaluated by
// searching from the end of the string backwards to the first occurring path
// separator '/' or '\'. If no path separator is found, the original string is
@ -178,7 +178,7 @@ DQN_API Dqn_usize Dqn_CString16_Size (wcha
// @return The file name in the file path, if none is found, the original path
// string is returned. Null pointer if arguments are null or invalid.
// @proc Dqn_String8_ToI64, Dqn_String8_ToU64
// @proc Dqn_Str8_ToI64, Dqn_Str8_ToU64
// @desc Convert a number represented as a string to a signed 64 bit number.
//
// The `separator` is an optional digit separator for example, if `separator`
@ -197,37 +197,37 @@ DQN_API Dqn_usize Dqn_CString16_Size (wcha
// @param[in] separator The character used to separate the digits, if any. Set
// this to 0, if no separators are permitted.
// @proc Dqn_String8_Replace, Dqn_String8_ReplaceInsensitive
// @proc Dqn_Str8_Replace, Dqn_Str8_ReplaceInsensitive
// @desc TODO(doyle): Write description
// @proc Dqn_String8_Remove
// @proc Dqn_Str8_Remove
// @desc Remove the substring denoted by the begin index and the size from the string
// string in-place using MEMMOVE to shift the string back.
// @proc Dqn_String8_Find
// @proc Dqn_Str8_Find
// @desc @param start_index Set an index within the string string to start the search
// from, if not desired, set to 0
// @return A string that points to the matching find, otherwise a 0 length string.
// @proc DQN_STRING8
// @desc Construct a UTF8 c-string literal into a Dqn_String8 referencing a
// @proc DQN_STR8
// @desc Construct a UTF8 c-string literal into a Dqn_Str8 referencing a
// string stored in the data-segment. This string is read-only.
// @proc DQN_STRING16
// @desc Construct a UTF16 c-string literal into a Dqn_String16 referencing a string
// @proc DQN_STR16
// @desc Construct a UTF16 c-string literal into a Dqn_Str16 referencing a string
// stored in the data-segment. This string is read-only.
// @proc DQN_STRING_FMT
// @proc DQN_STR_FMT
// @desc Unpack a string into arguments for printing a string into a printf style
// format string.
struct Dqn_String8Link
struct Dqn_Str8Link
{
Dqn_String8 string; // The string
Dqn_String8Link *next; // The next string in the linked list
Dqn_Str8 string; // The string
Dqn_Str8Link *next; // The next string in the linked list
};
struct Dqn_String16 /// A pointer and length style string that holds slices to UTF16 bytes.
struct Dqn_Str16 /// A pointer and length style string that holds slices to UTF16 bytes.
{
wchar_t *data; // The UTF16 bytes of the string
Dqn_usize size; // The number of characters in the string
@ -240,150 +240,155 @@ struct Dqn_String16 /// A pointer and length style string that holds slices to U
#endif
};
struct Dqn_String8BinarySplitResult
struct Dqn_Str8BinarySplitResult
{
Dqn_String8 lhs;
Dqn_String8 rhs;
Dqn_Str8 lhs;
Dqn_Str8 rhs;
};
struct Dqn_String8FindResult
struct Dqn_Str8FindResult
{
bool found; // True if string was found. If false, the subsequent fields below are not set.
Dqn_usize index; // The index in the buffer where the found string starts
Dqn_String8 match; // The matching string in the buffer that was searched
Dqn_String8 match_to_end_of_buffer; // The substring containing the found string to the end of the buffer
Dqn_String8 start_to_before_match; // The substring from the start of the buffer up until the found string, not including it
bool found; // True if string was found. If false, the subsequent fields below are not set.
Dqn_usize index; // The index in the buffer where the found string starts
Dqn_Str8 match; // The matching string in the buffer that was searched
Dqn_Str8 match_to_end_of_buffer; // The substring containing the found string to the end of the buffer
Dqn_Str8 start_to_before_match; // The substring from the start of the buffer up until the found string, not including it
};
// NOTE: Macros ====================================================================================
#define DQN_STRING8(string) Dqn_String8{(char *)(string), sizeof(string) - 1}
#define DQN_STRING16(string) Dqn_String16{(wchar_t *)(string), (sizeof(string)/sizeof(string[0])) - 1}
#define DQN_STRING_FMT(string) (int)((string).size), (string).data
#define DQN_STR8(string) Dqn_Str8{(char *)(string), sizeof(string) - 1}
#define DQN_STR16(string) Dqn_Str16{(wchar_t *)(string), (sizeof(string)/sizeof(string[0])) - 1}
#define DQN_STR_FMT(string) (int)((string).size), (string).data
#if defined(__cplusplus)
#define Dqn_String8_Init(data, size) (Dqn_String8{(char *)(data), (Dqn_usize)(size)})
#define Dqn_Str8_Init(data, size) (Dqn_Str8{(char *)(data), (Dqn_usize)(size)})
#else
#define Dqn_String8_Init(data, size) (Dqn_String8){(data), (size)}
#define Dqn_Str8_Init(data, size) (Dqn_Str8){(data), (size)}
#endif
// NOTE: API =======================================================================================
enum Dqn_String8IsAll
enum Dqn_Str8IsAll
{
Dqn_String8IsAll_Digits,
Dqn_String8IsAll_Hex,
Dqn_Str8IsAll_Digits,
Dqn_Str8IsAll_Hex,
};
enum Dqn_String8EqCase
enum Dqn_Str8EqCase
{
Dqn_String8EqCase_Sensitive,
Dqn_String8EqCase_Insensitive,
Dqn_Str8EqCase_Sensitive,
Dqn_Str8EqCase_Insensitive,
};
enum Dqn_String8FindFlag
enum Dqn_Str8FindFlag
{
Dqn_String8FindFlag_Digit = 1 << 0, // 0-9
Dqn_String8FindFlag_Whitespace = 1 << 1, // '\r', '\t', '\n', ' '
Dqn_String8FindFlag_Alphabet = 1 << 2, // A-Z, a-z
Dqn_String8FindFlag_Plus = 1 << 3, // +
Dqn_String8FindFlag_Minus = 1 << 4, // -
Dqn_String8FindFlag_AlphaNum = Dqn_String8FindFlag_Alphabet | Dqn_String8FindFlag_Digit,
Dqn_Str8FindFlag_Digit = 1 << 0, // 0-9
Dqn_Str8FindFlag_Whitespace = 1 << 1, // '\r', '\t', '\n', ' '
Dqn_Str8FindFlag_Alphabet = 1 << 2, // A-Z, a-z
Dqn_Str8FindFlag_Plus = 1 << 3, // +
Dqn_Str8FindFlag_Minus = 1 << 4, // -
Dqn_Str8FindFlag_AlphaNum = Dqn_Str8FindFlag_Alphabet | Dqn_Str8FindFlag_Digit,
};
struct Dqn_String8SplitAllocResult
struct Dqn_Str8SplitAllocResult
{
Dqn_String8 *data;
Dqn_Str8 *data;
Dqn_usize size;
};
struct Dqn_String8ToU64Result
struct Dqn_Str8ToU64Result
{
bool success;
uint64_t value;
};
struct Dqn_String8ToI64Result
struct Dqn_Str8ToI64Result
{
bool success;
int64_t value;
};
DQN_API Dqn_String8 Dqn_String8_InitCString8 (char const *src);
#define Dqn_String8_IsValid(string) ((string).data)
DQN_API bool Dqn_String8_IsAll (Dqn_String8 string, Dqn_String8IsAll is_all);
DQN_API Dqn_Str8 Dqn_Str8_InitCStr8 (char const *src);
#define Dqn_Str8_IsValid(string) ((string).data)
DQN_API bool Dqn_Str8_IsAll (Dqn_Str8 string, Dqn_Str8IsAll is_all);
DQN_API Dqn_String8 Dqn_String8_InitF (Dqn_Allocator allocator, DQN_FMT_STRING_ANNOTATE char const *fmt, ...);
DQN_API Dqn_String8 Dqn_String8_InitFV (Dqn_Allocator allocator, DQN_FMT_STRING_ANNOTATE char const *fmt, va_list args);
DQN_API Dqn_String8 Dqn_String8_Allocate (Dqn_Allocator allocator, Dqn_usize size, Dqn_ZeroMem zero_mem);
DQN_API Dqn_String8 Dqn_String8_CopyCString (Dqn_Allocator allocator, char const *string, Dqn_usize size);
DQN_API Dqn_String8 Dqn_String8_Copy (Dqn_Allocator allocator, Dqn_String8 string);
DQN_API Dqn_Str8 Dqn_Str8_InitF (Dqn_Allocator allocator, DQN_FMT_ATTRIB char const *fmt, ...);
DQN_API Dqn_Str8 Dqn_Str8_InitFV (Dqn_Allocator allocator, DQN_FMT_ATTRIB char const *fmt, va_list args);
DQN_API Dqn_Str8 Dqn_Str8_Allocate (Dqn_Allocator allocator, Dqn_usize size, Dqn_ZeroMem zero_mem);
DQN_API Dqn_Str8 Dqn_Str8_CopyCString (Dqn_Allocator allocator, char const *string, Dqn_usize size);
DQN_API Dqn_Str8 Dqn_Str8_Copy (Dqn_Allocator allocator, Dqn_Str8 string);
DQN_API Dqn_String8 Dqn_String8_Slice (Dqn_String8 string, Dqn_usize offset, Dqn_usize size);
DQN_API Dqn_String8 Dqn_String8_Advance (Dqn_String8 string, Dqn_usize amount);
DQN_API Dqn_String8BinarySplitResult Dqn_String8_BinarySplitArray (Dqn_String8 string, Dqn_String8 const *find, Dqn_usize find_size);
DQN_API Dqn_String8BinarySplitResult Dqn_String8_BinarySplit (Dqn_String8 string, Dqn_String8 find);
DQN_API Dqn_usize Dqn_String8_Split (Dqn_String8 string, Dqn_String8 delimiter, Dqn_String8 *splits, Dqn_usize splits_count);
DQN_API Dqn_String8SplitAllocResult Dqn_String8_SplitAlloc (Dqn_Allocator allocator, Dqn_String8 string, Dqn_String8 delimiter);
DQN_API Dqn_Str8 Dqn_Str8_Slice (Dqn_Str8 string, Dqn_usize offset, Dqn_usize size);
DQN_API Dqn_Str8 Dqn_Str8_Advance (Dqn_Str8 string, Dqn_usize amount);
DQN_API Dqn_Str8BinarySplitResult Dqn_Str8_BinarySplitArray (Dqn_Str8 string, Dqn_Str8 const *find, Dqn_usize find_size);
DQN_API Dqn_Str8BinarySplitResult Dqn_Str8_BinarySplit (Dqn_Str8 string, Dqn_Str8 find);
DQN_API Dqn_Str8BinarySplitResult Dqn_Str8_BinarySplitReverseArray(Dqn_Str8 string, Dqn_Str8 const *find, Dqn_usize find_size);
DQN_API Dqn_Str8BinarySplitResult Dqn_Str8_BinarySplitReverse (Dqn_Str8 string, Dqn_Str8 find);
DQN_API Dqn_usize Dqn_Str8_Split (Dqn_Str8 string, Dqn_Str8 delimiter, Dqn_Str8 *splits, Dqn_usize splits_count);
DQN_API Dqn_Str8SplitAllocResult Dqn_Str8_SplitAlloc (Dqn_Allocator allocator, Dqn_Str8 string, Dqn_Str8 delimiter);
DQN_API Dqn_String8FindResult Dqn_String8_FindFirstStringArray (Dqn_String8 string, Dqn_String8 const *find, Dqn_usize find_size);
DQN_API Dqn_String8FindResult Dqn_String8_FindFirstString (Dqn_String8 string, Dqn_String8 find);
DQN_API Dqn_String8FindResult Dqn_String8_FindFirst (Dqn_String8 string, uint32_t flags);
DQN_API Dqn_String8 Dqn_String8_Segment (Dqn_Allocator allocator, Dqn_String8 src, Dqn_usize segment_size, char segment_char);
DQN_API Dqn_Str8FindResult Dqn_Str8_FindFirstStringArray (Dqn_Str8 string, Dqn_Str8 const *find, Dqn_usize find_size);
DQN_API Dqn_Str8FindResult Dqn_Str8_FindFirstString (Dqn_Str8 string, Dqn_Str8 find);
DQN_API Dqn_Str8FindResult Dqn_Str8_FindFirst (Dqn_Str8 string, uint32_t flags);
DQN_API Dqn_Str8 Dqn_Str8_Segment (Dqn_Allocator allocator, Dqn_Str8 src, Dqn_usize segment_size, char segment_char);
DQN_API bool Dqn_String8_Eq (Dqn_String8 lhs, Dqn_String8 rhs, Dqn_String8EqCase eq_case = Dqn_String8EqCase_Sensitive);
DQN_API bool Dqn_String8_EqInsensitive (Dqn_String8 lhs, Dqn_String8 rhs);
DQN_API bool Dqn_String8_StartsWith (Dqn_String8 string, Dqn_String8 prefix, Dqn_String8EqCase eq_case = Dqn_String8EqCase_Sensitive);
DQN_API bool Dqn_String8_StartsWithInsensitive (Dqn_String8 string, Dqn_String8 prefix);
DQN_API bool Dqn_String8_EndsWith (Dqn_String8 string, Dqn_String8 prefix, Dqn_String8EqCase eq_case = Dqn_String8EqCase_Sensitive);
DQN_API bool Dqn_String8_EndsWithInsensitive (Dqn_String8 string, Dqn_String8 prefix);
DQN_API bool Dqn_String8_HasChar (Dqn_String8 string, char ch);
DQN_API bool Dqn_Str8_Eq (Dqn_Str8 lhs, Dqn_Str8 rhs, Dqn_Str8EqCase eq_case = Dqn_Str8EqCase_Sensitive);
DQN_API bool Dqn_Str8_EqInsensitive (Dqn_Str8 lhs, Dqn_Str8 rhs);
DQN_API bool Dqn_Str8_StartsWith (Dqn_Str8 string, Dqn_Str8 prefix, Dqn_Str8EqCase eq_case = Dqn_Str8EqCase_Sensitive);
DQN_API bool Dqn_Str8_StartsWithInsensitive (Dqn_Str8 string, Dqn_Str8 prefix);
DQN_API bool Dqn_Str8_EndsWith (Dqn_Str8 string, Dqn_Str8 prefix, Dqn_Str8EqCase eq_case = Dqn_Str8EqCase_Sensitive);
DQN_API bool Dqn_Str8_EndsWithInsensitive (Dqn_Str8 string, Dqn_Str8 prefix);
DQN_API bool Dqn_Str8_HasChar (Dqn_Str8 string, char ch);
DQN_API Dqn_String8 Dqn_String8_TrimPrefix (Dqn_String8 string, Dqn_String8 prefix, Dqn_String8EqCase eq_case = Dqn_String8EqCase_Sensitive);
DQN_API Dqn_String8 Dqn_String8_TrimSuffix (Dqn_String8 string, Dqn_String8 suffix, Dqn_String8EqCase eq_case = Dqn_String8EqCase_Sensitive);
DQN_API Dqn_String8 Dqn_String8_TrimWhitespaceAround (Dqn_String8 string);
DQN_API Dqn_String8 Dqn_String8_TrimByteOrderMark (Dqn_String8 string);
DQN_API Dqn_Str8 Dqn_Str8_TrimPrefix (Dqn_Str8 string, Dqn_Str8 prefix, Dqn_Str8EqCase eq_case = Dqn_Str8EqCase_Sensitive);
DQN_API Dqn_Str8 Dqn_Str8_TrimSuffix (Dqn_Str8 string, Dqn_Str8 suffix, Dqn_Str8EqCase eq_case = Dqn_Str8EqCase_Sensitive);
DQN_API Dqn_Str8 Dqn_Str8_TrimAround (Dqn_Str8 string, Dqn_Str8 trim_string);
DQN_API Dqn_Str8 Dqn_Str8_TrimWhitespaceAround (Dqn_Str8 string);
DQN_API Dqn_Str8 Dqn_Str8_TrimByteOrderMark (Dqn_Str8 string);
DQN_API Dqn_String8 Dqn_String8_FileNameFromPath (Dqn_String8 path);
DQN_API Dqn_Str8 Dqn_Str8_FileNameFromPath (Dqn_Str8 path);
DQN_API Dqn_Str8 Dqn_Str8_FileNameNoExtension (Dqn_Str8 path);
DQN_API Dqn_Str8 Dqn_Str8_FilePathNoExtension (Dqn_Str8 path);
DQN_API Dqn_String8ToU64Result Dqn_String8_ToU64 (Dqn_String8 string, char separator);
DQN_API Dqn_String8ToI64Result Dqn_String8_ToI64 (Dqn_String8 string, char separator);
DQN_API Dqn_Str8ToU64Result Dqn_Str8_ToU64 (Dqn_Str8 string, char separator);
DQN_API Dqn_Str8ToI64Result Dqn_Str8_ToI64 (Dqn_Str8 string, char separator);
DQN_API Dqn_String8 Dqn_String8_Replace (Dqn_String8 string, Dqn_String8 find, Dqn_String8 replace, Dqn_usize start_index, Dqn_Allocator allocator, Dqn_String8EqCase eq_case = Dqn_String8EqCase_Sensitive);
DQN_API Dqn_String8 Dqn_String8_ReplaceInsensitive (Dqn_String8 string, Dqn_String8 find, Dqn_String8 replace, Dqn_usize start_index, Dqn_Allocator allocator);
DQN_API void Dqn_String8_Remove (Dqn_String8 *string, Dqn_usize offset, Dqn_usize size);
DQN_API Dqn_Str8 Dqn_Str8_Replace (Dqn_Str8 string, Dqn_Str8 find, Dqn_Str8 replace, Dqn_usize start_index, Dqn_Allocator allocator, Dqn_Str8EqCase eq_case = Dqn_Str8EqCase_Sensitive);
DQN_API Dqn_Str8 Dqn_Str8_ReplaceInsensitive (Dqn_Str8 string, Dqn_Str8 find, Dqn_Str8 replace, Dqn_usize start_index, Dqn_Allocator allocator);
DQN_API void Dqn_Str8_Remove (Dqn_Str8 *string, Dqn_usize offset, Dqn_usize size);
#if defined(__cplusplus)
DQN_API bool operator== (Dqn_String8 const &lhs, Dqn_String8 const &rhs);
DQN_API bool operator!= (Dqn_String8 const &lhs, Dqn_String8 const &rhs);
DQN_API bool operator== (Dqn_Str8 const &lhs, Dqn_Str8 const &rhs);
DQN_API bool operator!= (Dqn_Str8 const &lhs, Dqn_Str8 const &rhs);
#endif
#if !defined(DQN_NO_FSTRING8)
// NOTE: [$FSTR] Dqn_FString8 ======================================================================
#if !defined(DQN_NO_FSTR8)
// NOTE: [$FSTR] Dqn_FStr8 =========================================================================
// NOTE: API =======================================================================================
// @proc Dqn_FString8_InitF
// @proc Dqn_FStr8_InitF
// @desc Create a fixed string from the format string. The result string is
// null-terminated.
// @param fmt[in] Format string specifier to create the fixed string from
// @return The created string, truncated if there was insufficient space
// @proc Dqn_FString8_Max
// @proc Dqn_FStr8_Max
// @desc @param string[in] The string to query the maximum capacity of
// @return Maximum capacity of the fixed string
// @proc Dqn_FString8_Clear
// @proc Dqn_FStr8_Clear
// @desc Reset the characters in the string
// @param string[in] The string to clear
// @proc Dqn_FString8_AppendFV
// @proc Dqn_FStr8_AppendFV
// @desc Append a format string to the fixed string. On failure the string is
// appended to but truncated ensuring null-termination.
// @param string[in] The string to append to
// @param fmt[in] Format string to append to the fixed string
// @return True if append was successful, false otherwise.
// @proc Dqn_FString8_AppendF
// @desc @copydocs Dqn_FString8_AppendF
// @proc Dqn_FStr8_AppendF
// @desc @copydocs Dqn_FStr8_AppendF
// @proc Dqn_FString8_AppendCString8
// @proc Dqn_FStr8_AppendCStr8
// @desc Append a cstring to the fixed string. On failure the string is
// appended to but truncated ensuring null-termination.
// @param string[in] The string to append to
@ -391,7 +396,7 @@ DQN_API bool operator!= (Dqn_Stri
// @param size[in] Size of the cstring
// @return True if append was successful, false otherwise.
// @proc Dqn_FString8_Append
// @proc Dqn_FStr8_Append
// @desc Append a string to the fixed string. On failure the string is
// appended to but truncated ensuring null-termination.
// @param string[in] The string to append to
@ -399,38 +404,38 @@ DQN_API bool operator!= (Dqn_Stri
// determined before appending.
// @return True if append was successful, false otherwise.
// @proc Dqn_FString8_ToString8
// @proc Dqn_FStr8_ToStr8
// @desc Convert a fixed string to a string. The string holds a reference to the
// fixed string and is invalidated once fixed string is deleted.
// @param string[in] The fixed string to create a string from
// @return String referencing the contents of `string`
// @proc Dqn_FString8_Eq
// @desc @see Dqn_String8_Eq
// @proc Dqn_FStr8_Eq
// @desc @see Dqn_Str8_Eq
// @proc Dqn_FString8_EqString8
// @desc @see Dqn_String8_Eq
// @proc Dqn_FStr8_EqStr8
// @desc @see Dqn_Str8_Eq
// @proc Dqn_FString8_EqInsensitive
// @proc Dqn_FStr8_EqInsensitive
// @desc Compare a string for equality, case insensitive
// @see Dqn_String8_Eq
// @see Dqn_Str8_Eq
// @proc Dqn_FString8_EqString8Insensitive
// @proc Dqn_FStr8_EqStr8Insensitive
// @desc Compare a string for equality, case insensitive
// @see Dqn_String8_Eq
// @see Dqn_Str8_Eq
template <Dqn_usize N> struct Dqn_FString8
template <Dqn_usize N> struct Dqn_FStr8
{
char data[N+1];
Dqn_usize size;
bool operator==(Dqn_FString8 const &other) const {
bool operator==(Dqn_FStr8 const &other) const {
if (size != other.size) return false;
bool result = DQN_MEMCMP(data, other.data, size);
return result;
}
bool operator!=(Dqn_FString8 const &other) const { return !(*this == other); }
bool operator!=(Dqn_FStr8 const &other) const { return !(*this == other); }
char *begin() { return data; }
char *end () { return data + size; }
@ -438,26 +443,26 @@ template <Dqn_usize N> struct Dqn_FString8
char const *end () const { return data + size; }
};
template <Dqn_usize N> Dqn_FString8<N> Dqn_FString8_InitF (DQN_FMT_STRING_ANNOTATE char const *fmt, ...);
template <Dqn_usize N> Dqn_usize Dqn_FString8_Max (Dqn_FString8<N> const *string);
template <Dqn_usize N> void Dqn_FString8_Clear (Dqn_FString8<N> *string);
template <Dqn_usize N> bool Dqn_FString8_AppendFV (Dqn_FString8<N> *string, DQN_FMT_STRING_ANNOTATE char const *fmt, va_list va);
template <Dqn_usize N> bool Dqn_FString8_AppendF (Dqn_FString8<N> *string, DQN_FMT_STRING_ANNOTATE char const *fmt, ...);
template <Dqn_usize N> bool Dqn_FString8_AppendCString8 (Dqn_FString8<N> *string, char const *value, Dqn_usize size);
template <Dqn_usize N> bool Dqn_FString8_Append (Dqn_FString8<N> *string, Dqn_String8 value);
template <Dqn_usize N> Dqn_String8 Dqn_FString8_ToString8 (Dqn_FString8<N> const *string);
template <Dqn_usize N> bool Dqn_FString8_Eq (Dqn_FString8<N> const *lhs, Dqn_FString8<N> const *rhs, Dqn_String8EqCase eq_case);
template <Dqn_usize N> bool Dqn_FString8_EqString8 (Dqn_FString8<N> const *lhs, Dqn_String8 rhs, Dqn_String8EqCase eq_case);
template <Dqn_usize N> bool Dqn_FString8_EqInsensitive (Dqn_FString8<N> const *lhs, Dqn_FString8<N> const *rhs);
template <Dqn_usize N> bool Dqn_FString8_EqString8Insensitive (Dqn_FString8<N> const *lhs, Dqn_String8 rhs);
template <Dqn_usize A, Dqn_usize B> bool Dqn_FString8_EqFString8 (Dqn_FString8<A> const *lhs, Dqn_FString8<B> const *rhs, Dqn_String8EqCase eq_case);
template <Dqn_usize A, Dqn_usize B> bool Dqn_FString8_EqFString8Insensitive(Dqn_FString8<A> const *lhs, Dqn_FString8<B> const *rhs);
#endif // !defined(DQN_NO_FSTRING8)
template <Dqn_usize N> Dqn_FStr8<N> Dqn_FStr8_InitF (DQN_FMT_ATTRIB char const *fmt, ...);
template <Dqn_usize N> Dqn_usize Dqn_FStr8_Max (Dqn_FStr8<N> const *string);
template <Dqn_usize N> void Dqn_FStr8_Clear (Dqn_FStr8<N> *string);
template <Dqn_usize N> bool Dqn_FStr8_AppendFV (Dqn_FStr8<N> *string, DQN_FMT_ATTRIB char const *fmt, va_list va);
template <Dqn_usize N> bool Dqn_FStr8_AppendF (Dqn_FStr8<N> *string, DQN_FMT_ATTRIB char const *fmt, ...);
template <Dqn_usize N> bool Dqn_FStr8_AppendCStr8 (Dqn_FStr8<N> *string, char const *value, Dqn_usize size);
template <Dqn_usize N> bool Dqn_FStr8_Append (Dqn_FStr8<N> *string, Dqn_Str8 value);
template <Dqn_usize N> Dqn_Str8 Dqn_FStr8_ToStr8 (Dqn_FStr8<N> const *string);
template <Dqn_usize N> bool Dqn_FStr8_Eq (Dqn_FStr8<N> const *lhs, Dqn_FStr8<N> const *rhs, Dqn_Str8EqCase eq_case);
template <Dqn_usize N> bool Dqn_FStr8_EqStr8 (Dqn_FStr8<N> const *lhs, Dqn_Str8 rhs, Dqn_Str8EqCase eq_case);
template <Dqn_usize N> bool Dqn_FStr8_EqInsensitive (Dqn_FStr8<N> const *lhs, Dqn_FStr8<N> const *rhs);
template <Dqn_usize N> bool Dqn_FStr8_EqStr8Insensitive (Dqn_FStr8<N> const *lhs, Dqn_Str8 rhs);
template <Dqn_usize A, Dqn_usize B> bool Dqn_FStr8_EqFStr8 (Dqn_FStr8<A> const *lhs, Dqn_FStr8<B> const *rhs, Dqn_Str8EqCase eq_case);
template <Dqn_usize A, Dqn_usize B> bool Dqn_FStr8_EqFStr8Insensitive(Dqn_FStr8<A> const *lhs, Dqn_FStr8<B> const *rhs);
#endif // !defined(DQN_NO_FSTR8)
// NOTE: [$STRB] Dqn_String8Builder ================================================================
// NOTE: [$STRB] Dqn_Str8Builder ================================================================
// NOTE: API =======================================================================================
// @proc Dqn_String8Builder_AppendRef, Dqn_String8_AppendCopy,
// Dqn_String8_AppendFV, Dqn_String8_AppendF
// @proc Dqn_Str8Builder_AppendRef, Dqn_Str8_AppendCopy,
// Dqn_Str8_AppendFV, Dqn_Str8_AppendF
// @desc Append a string to the list of strings in the builder.
//
// The string is appended to the builder as follows
@ -472,7 +477,7 @@ template <Dqn_usize A, Dqn_usize B> bool Dqn_FString8_EqFString8Insen
// @return True if append was successful, false if parameters are invalid
// or memory allocation failure.
// @proc Dqn_String8Builder_Build
// @proc Dqn_Str8Builder_Build
// @desc Build the list of strings into the final composite string from the
// string builder
// @param builder The string builder to build the string from
@ -480,20 +485,20 @@ template <Dqn_usize A, Dqn_usize B> bool Dqn_FString8_EqFString8Insen
// @return The string if build was successful, empty string if parameters are
// invalid or memory allocation failure.
struct Dqn_String8Builder
struct Dqn_Str8Builder
{
Dqn_Allocator allocator; ///< Allocator to use to back the string list
Dqn_String8Link *head; ///< First string in the linked list of strings
Dqn_String8Link *tail; ///< Last string in the linked list of strings
Dqn_usize string_size; ///< The size in bytes necessary to construct the current string
Dqn_usize count; ///< The number of links in the linked list of strings
Dqn_Allocator allocator; ///< Allocator to use to back the string list
Dqn_Str8Link *head; ///< First string in the linked list of strings
Dqn_Str8Link *tail; ///< Last string in the linked list of strings
Dqn_usize string_size; ///< The size in bytes necessary to construct the current string
Dqn_usize count; ///< The number of links in the linked list of strings
};
DQN_API bool Dqn_String8Builder_AppendF (Dqn_String8Builder *builder, DQN_FMT_STRING_ANNOTATE char const *fmt, ...);
DQN_API bool Dqn_String8Builder_AppendFV (Dqn_String8Builder *builder, DQN_FMT_STRING_ANNOTATE char const *fmt, va_list args);
DQN_API bool Dqn_String8Builder_AppendRef (Dqn_String8Builder *builder, Dqn_String8 string);
DQN_API bool Dqn_String8Builder_AppendCopy(Dqn_String8Builder *builder, Dqn_String8 string);
DQN_API Dqn_String8 Dqn_String8Builder_Build (Dqn_String8Builder const *builder, Dqn_Allocator allocator);
DQN_API bool Dqn_Str8Builder_AppendF (Dqn_Str8Builder *builder, DQN_FMT_ATTRIB char const *fmt, ...);
DQN_API bool Dqn_Str8Builder_AppendFV (Dqn_Str8Builder *builder, DQN_FMT_ATTRIB char const *fmt, va_list args);
DQN_API bool Dqn_Str8Builder_AppendRef (Dqn_Str8Builder *builder, Dqn_Str8 string);
DQN_API bool Dqn_Str8Builder_AppendCopy(Dqn_Str8Builder *builder, Dqn_Str8 string);
DQN_API Dqn_Str8 Dqn_Str8Builder_Build (Dqn_Str8Builder const *builder, Dqn_Allocator allocator);
// NOTE: [$CHAR] Dqn_Char ==========================================================================
DQN_API bool Dqn_Char_IsAlphabet (char ch);
@ -510,38 +515,38 @@ DQN_API char Dqn_Char_ToLower (char ch);
DQN_API int Dqn_UTF8_EncodeCodepoint(uint8_t utf8[4], uint32_t codepoint);
DQN_API int Dqn_UTF16_EncodeCodepoint(uint16_t utf16[2], uint32_t codepoint);
#if !defined(DQN_NO_FSTRING8)
// NOTE: [$FSTR] Dqn_FString8 ======================================================================
template <Dqn_usize N> Dqn_FString8<N> Dqn_FString8_InitF(DQN_FMT_STRING_ANNOTATE char const *fmt, ...)
#if !defined(DQN_NO_FSTR8)
// NOTE: [$FSTR] Dqn_FStr8 ======================================================================
template <Dqn_usize N> Dqn_FStr8<N> Dqn_FStr8_InitF(DQN_FMT_ATTRIB char const *fmt, ...)
{
Dqn_FString8<N> result = {};
Dqn_FStr8<N> result = {};
if (fmt) {
va_list args;
va_start(args, fmt);
Dqn_FString8_AppendFV(&result, fmt, args);
Dqn_FStr8_AppendFV(&result, fmt, args);
va_end(args);
}
return result;
}
template <Dqn_usize N> Dqn_usize Dqn_FString8_Max(Dqn_FString8<N> const *)
template <Dqn_usize N> Dqn_usize Dqn_FStr8_Max(Dqn_FStr8<N> const *)
{
Dqn_usize result = N;
return result;
}
template <Dqn_usize N> void Dqn_FString8_Clear(Dqn_FString8<N> *string)
template <Dqn_usize N> void Dqn_FStr8_Clear(Dqn_FStr8<N> *string)
{
*string = {};
}
template <Dqn_usize N> bool Dqn_FString8_AppendFV(Dqn_FString8<N> *string, DQN_FMT_STRING_ANNOTATE char const *fmt, va_list args)
template <Dqn_usize N> bool Dqn_FStr8_AppendFV(Dqn_FStr8<N> *string, DQN_FMT_ATTRIB char const *fmt, va_list args)
{
bool result = false;
if (!string || !fmt)
return result;
Dqn_usize require = Dqn_CString8_FVSize(fmt, args) + 1 /*null_terminate*/;
Dqn_usize require = Dqn_CStr8_FVSize(fmt, args) + 1 /*null_terminate*/;
Dqn_usize space = (N + 1) - string->size;
result = require <= space;
string->size += STB_SPRINTF_DECORATE(vsnprintf)(string->data + string->size, DQN_CAST(int)space, fmt, args);
@ -552,19 +557,19 @@ template <Dqn_usize N> bool Dqn_FString8_AppendFV(Dqn_FString8<N> *string, DQN_F
return result;
}
template <Dqn_usize N> bool Dqn_FString8_AppendF(Dqn_FString8<N> *string, DQN_FMT_STRING_ANNOTATE char const *fmt, ...)
template <Dqn_usize N> bool Dqn_FStr8_AppendF(Dqn_FStr8<N> *string, DQN_FMT_ATTRIB char const *fmt, ...)
{
bool result = false;
if (!string || !fmt)
return result;
va_list args;
va_start(args, fmt);
result = Dqn_FString8_AppendFV(string, fmt, args);
result = Dqn_FStr8_AppendFV(string, fmt, args);
va_end(args);
return result;
}
template <Dqn_usize N> bool Dqn_FString8_AppendCString8(Dqn_FString8<N> *string, char const *src, Dqn_usize size)
template <Dqn_usize N> bool Dqn_FStr8_AppendCStr8(Dqn_FStr8<N> *string, char const *src, Dqn_usize size)
{
DQN_ASSERT(string->size <= N);
bool result = false;
@ -579,15 +584,15 @@ template <Dqn_usize N> bool Dqn_FString8_AppendCString8(Dqn_FString8<N> *string,
return result;
}
template <Dqn_usize N> bool Dqn_FString8_Append(Dqn_FString8<N> *string, Dqn_String8 src)
template <Dqn_usize N> bool Dqn_FStr8_Append(Dqn_FStr8<N> *string, Dqn_Str8 src)
{
bool result = Dqn_FString8_AppendCString8(string, src.data, src.size);
bool result = Dqn_FStr8_AppendCStr8(string, src.data, src.size);
return result;
}
template <Dqn_usize N> Dqn_String8 Dqn_FString8_ToString8(Dqn_FString8<N> const *string)
template <Dqn_usize N> Dqn_Str8 Dqn_FStr8_ToStr8(Dqn_FStr8<N> const *string)
{
Dqn_String8 result = {};
Dqn_Str8 result = {};
if (!string || string->size <= 0)
return result;
@ -596,49 +601,49 @@ template <Dqn_usize N> Dqn_String8 Dqn_FString8_ToString8(Dqn_FString8<N> const
return result;
}
template <Dqn_usize N> bool Dqn_FString8_Eq(Dqn_FString8<N> const *lhs, Dqn_FString8<N> const *rhs, Dqn_String8EqCase eq_case)
template <Dqn_usize N> bool Dqn_FStr8_Eq(Dqn_FStr8<N> const *lhs, Dqn_FStr8<N> const *rhs, Dqn_Str8EqCase eq_case)
{
Dqn_String8 lhs_s8 = Dqn_FString8_ToString8(lhs);
Dqn_String8 rhs_s8 = Dqn_FString8_ToString8(rhs);
bool result = Dqn_String8_Eq(lhs_s8, rhs_s8, eq_case);
Dqn_Str8 lhs_s8 = Dqn_FStr8_ToStr8(lhs);
Dqn_Str8 rhs_s8 = Dqn_FStr8_ToStr8(rhs);
bool result = Dqn_Str8_Eq(lhs_s8, rhs_s8, eq_case);
return result;
}
template <Dqn_usize N> bool Dqn_FString8_EqString8(Dqn_FString8<N> const *lhs, Dqn_String8 rhs, Dqn_String8EqCase eq_case)
template <Dqn_usize N> bool Dqn_FStr8_EqStr8(Dqn_FStr8<N> const *lhs, Dqn_Str8 rhs, Dqn_Str8EqCase eq_case)
{
Dqn_String8 lhs_s8 = Dqn_FString8_ToString8(lhs);
bool result = Dqn_String8_Eq(lhs_s8, rhs, eq_case);
Dqn_Str8 lhs_s8 = Dqn_FStr8_ToStr8(lhs);
bool result = Dqn_Str8_Eq(lhs_s8, rhs, eq_case);
return result;
}
template <Dqn_usize N> bool Dqn_FString8_EqInsensitive(Dqn_FString8<N> const *lhs, Dqn_FString8<N> const *rhs)
template <Dqn_usize N> bool Dqn_FStr8_EqInsensitive(Dqn_FStr8<N> const *lhs, Dqn_FStr8<N> const *rhs)
{
Dqn_String8 lhs_s8 = Dqn_FString8_ToString8(lhs);
Dqn_String8 rhs_s8 = Dqn_FString8_ToString8(rhs);
bool result = Dqn_String8_Eq(lhs_s8, rhs_s8, Dqn_String8EqCase_Insensitive);
Dqn_Str8 lhs_s8 = Dqn_FStr8_ToStr8(lhs);
Dqn_Str8 rhs_s8 = Dqn_FStr8_ToStr8(rhs);
bool result = Dqn_Str8_Eq(lhs_s8, rhs_s8, Dqn_Str8EqCase_Insensitive);
return result;
}
template <Dqn_usize N> bool Dqn_FString8_EqString8Insensitive(Dqn_FString8<N> const *lhs, Dqn_String8 rhs)
template <Dqn_usize N> bool Dqn_FStr8_EqStr8Insensitive(Dqn_FStr8<N> const *lhs, Dqn_Str8 rhs)
{
Dqn_String8 lhs_s8 = Dqn_FString8_ToString8(lhs);
bool result = Dqn_String8_Eq(lhs_s8, rhs, Dqn_String8EqCase_Insensitive);
Dqn_Str8 lhs_s8 = Dqn_FStr8_ToStr8(lhs);
bool result = Dqn_Str8_Eq(lhs_s8, rhs, Dqn_Str8EqCase_Insensitive);
return result;
}
template <Dqn_usize A, Dqn_usize B> bool Dqn_FString8_EqFString8(Dqn_FString8<A> const *lhs, Dqn_FString8<B> const *rhs, Dqn_String8EqCase eq_case)
template <Dqn_usize A, Dqn_usize B> bool Dqn_FStr8_EqFStr8(Dqn_FStr8<A> const *lhs, Dqn_FStr8<B> const *rhs, Dqn_Str8EqCase eq_case)
{
Dqn_String8 lhs_s8 = Dqn_FString8_ToString8(lhs);
Dqn_String8 rhs_s8 = Dqn_FString8_ToString8(rhs);
bool result = Dqn_String8_Eq(lhs_s8, rhs_s8, eq_case);
Dqn_Str8 lhs_s8 = Dqn_FStr8_ToStr8(lhs);
Dqn_Str8 rhs_s8 = Dqn_FStr8_ToStr8(rhs);
bool result = Dqn_Str8_Eq(lhs_s8, rhs_s8, eq_case);
return result;
}
template <Dqn_usize A, Dqn_usize B> bool Dqn_FString8_EqFString8Insensitive(Dqn_FString8<A> const *lhs, Dqn_FString8<B> const *rhs)
template <Dqn_usize A, Dqn_usize B> bool Dqn_FStr8_EqFStr8Insensitive(Dqn_FStr8<A> const *lhs, Dqn_FStr8<B> const *rhs)
{
Dqn_String8 lhs_s8 = Dqn_FString8_ToString8(lhs);
Dqn_String8 rhs_s8 = Dqn_FString8_ToString8(rhs);
bool result = Dqn_String8_Eq(lhs_s8, rhs_s8, Dqn_String8EqCase_Insensitive);
Dqn_Str8 lhs_s8 = Dqn_FStr8_ToStr8(lhs);
Dqn_Str8 rhs_s8 = Dqn_FStr8_ToStr8(rhs);
bool result = Dqn_Str8_Eq(lhs_s8, rhs_s8, Dqn_Str8EqCase_Insensitive);
return result;
}
#endif // !defined(DQN_NO_FSTRING8)
#endif // !defined(DQN_NO_FSTR8)

View File

@ -330,6 +330,9 @@
} OVERLAPPED, *LPOVERLAPPED;
// NOTE: um/winbase.h ==========================================================================
#define WAIT_FAILED ((DWORD)0xFFFFFFFF)
#define WAIT_OBJECT_0 ((STATUS_WAIT_0 ) + 0 )
#define INFINITE 0xFFFFFFFF // Wait/Synchronisation: Infinite timeout
#define STD_INPUT_HANDLE ((DWORD)-10)
@ -345,6 +348,9 @@
#define FORMAT_MESSAGE_FROM_HMODULE 0x00000800
#define FORMAT_MESSAGE_FROM_SYSTEM 0x00001000
// NOTE: CreateProcessW
#define STARTF_USESTDHANDLES 0x00000100
extern "C"
{
__declspec(dllimport) BOOL __stdcall MoveFileExW (const WCHAR *lpExistingFileName, const WCHAR *lpNewFileName, DWORD dwFlags);
@ -708,6 +714,34 @@
}
// NOTE: um/processthreadsapi.h ================================================================
typedef struct _PROCESS_INFORMATION {
HANDLE hProcess;
HANDLE hThread;
DWORD dwProcessId;
DWORD dwThreadId;
} PROCESS_INFORMATION, *PPROCESS_INFORMATION, *LPPROCESS_INFORMATION;
typedef struct _STARTUPINFOW {
DWORD cb;
WCHAR *lpReserved;
WCHAR *lpDesktop;
WCHAR *lpTitle;
DWORD dwX;
DWORD dwY;
DWORD dwXSize;
DWORD dwYSize;
DWORD dwXCountChars;
DWORD dwYCountChars;
DWORD dwFillAttribute;
DWORD dwFlags;
WORD wShowWindow;
WORD cbReserved2;
BYTE *lpReserved2;
HANDLE hStdInput;
HANDLE hStdOutput;
HANDLE hStdError;
} STARTUPINFOW, *LPSTARTUPINFOW;
typedef DWORD (__stdcall *PTHREAD_START_ROUTINE)(
VOID *lpThreadParameter
);
@ -715,8 +749,12 @@
extern "C"
{
__declspec(dllimport) BOOL __stdcall CreateProcessW(WCHAR const *lpApplicationName, WCHAR *lpCommandLine, SECURITY_ATTRIBUTES *lpProcessAttributes, SECURITY_ATTRIBUTES *lpThreadAttributes, BOOL bInheritHandles, DWORD dwCreationFlags, VOID *lpEnvironment, WCHAR const *lpCurrentDirectory, STARTUPINFOW *lpStartupInfo, PROCESS_INFORMATION *lpProcessInformation);
__declspec(dllimport) HANDLE __stdcall CreateThread(SECURITY_ATTRIBUTES *lpThreadAttributes, SIZE_T dwStackSize, PTHREAD_START_ROUTINE lpStartAddress, VOID *lpParameter, DWORD dwCreationFlags, DWORD *lpThreadId);
__declspec(dllimport) DWORD __stdcall GetCurrentThreadId(VOID);
__declspec(dllimport) BOOL __stdcall GetExitCodeProcess(HANDLE hProcess, DWORD *lpExitCode);
__declspec(dllimport) void __stdcall ExitProcess(UINT uExitCode);
}
// NOTE: um/memoryapi.h ========================================================================