dqn: Upgrade lib to latest version from TELY
This commit is contained in:
parent
b46b44f11c
commit
bf413d7e57
File diff suppressed because it is too large
Load Diff
@ -19,7 +19,7 @@ pushd Build
|
|||||||
|
|
||||||
REM Optionally pass `-analyze` to `msvc_compile_flags` for more checks, but,
|
REM Optionally pass `-analyze` to `msvc_compile_flags` for more checks, but,
|
||||||
REM it slows down compilation by around 5s on my old laptop.
|
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 clang_compile_flags=%msvc_driver_flags% -fsanitize=address -fsanitize=undefined /Fe:dqn_unit_tests_clang
|
||||||
set zig_compile_flags=%common_flags% -fsanitize=address -fsanitize=undefined -o dqn_unit_tests_zig
|
set zig_compile_flags=%common_flags% -fsanitize=address -fsanitize=undefined -o dqn_unit_tests_zig
|
||||||
|
|
||||||
|
34
dqn.h
34
dqn.h
@ -41,7 +41,7 @@
|
|||||||
defined(DQN_ONLY_SLICE) || \
|
defined(DQN_ONLY_SLICE) || \
|
||||||
defined(DQN_ONLY_DSMAP) || \
|
defined(DQN_ONLY_DSMAP) || \
|
||||||
defined(DQN_ONLY_LIST) || \
|
defined(DQN_ONLY_LIST) || \
|
||||||
defined(DQN_ONLY_FSTRING8) || \
|
defined(DQN_ONLY_FSTR8) || \
|
||||||
defined(DQN_ONLY_FS) || \
|
defined(DQN_ONLY_FS) || \
|
||||||
defined(DQN_ONLY_WINNET) || \
|
defined(DQN_ONLY_WINNET) || \
|
||||||
defined(DQN_ONLY_WIN) || \
|
defined(DQN_ONLY_WIN) || \
|
||||||
@ -72,8 +72,8 @@
|
|||||||
#if !defined(DQN_ONLY_LIST)
|
#if !defined(DQN_ONLY_LIST)
|
||||||
#define DQN_NO_LIST
|
#define DQN_NO_LIST
|
||||||
#endif
|
#endif
|
||||||
#if !defined(DQN_ONLY_FSTRING8)
|
#if !defined(DQN_ONLY_FSTR8)
|
||||||
#define DQN_NO_FSTRING8
|
#define DQN_NO_FSTR8
|
||||||
#endif
|
#endif
|
||||||
#if !defined(DQN_ONLY_FS)
|
#if !defined(DQN_ONLY_FS)
|
||||||
#define DQN_NO_FS
|
#define DQN_NO_FS
|
||||||
@ -202,11 +202,18 @@
|
|||||||
// [$ACAT] Dqn_ArenaCatalog | | Collate, create & manage arenas in a catalog
|
// [$ACAT] Dqn_ArenaCatalog | | Collate, create & manage arenas in a catalog
|
||||||
#include "dqn_memory.h"
|
#include "dqn_memory.h"
|
||||||
|
|
||||||
|
// NOTE: Dqn_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 ===============================================================================
|
// NOTE: Dqn_Strings ===============================================================================
|
||||||
// [$CSTR] Dqn_CString8 | | C-string helpers
|
// [$CSTR] Dqn_CStr8 | | C-string helpers
|
||||||
// [$STR8] Dqn_String8 | | Pointer and length strings
|
// [$STR8] Dqn_Str8 | | Pointer and length strings
|
||||||
// [$FSTR] Dqn_FString8 | DQN_FSTRING8 | Fixed-size strings
|
// [$FSTR] Dqn_FStr8 | DQN_FSTr8 | Fixed-size strings
|
||||||
// [$STRB] Dqn_String8Builder | |
|
// [$STRB] Dqn_Str8Builder | |
|
||||||
// [$CHAR] Dqn_Char | | Character ascii/digit.. helpers
|
// [$CHAR] Dqn_Char | | Character ascii/digit.. helpers
|
||||||
// [$UTFX] Dqn_UTF | | Unicode helpers
|
// [$UTFX] Dqn_UTF | | Unicode helpers
|
||||||
#include "dqn_strings.h"
|
#include "dqn_strings.h"
|
||||||
@ -221,13 +228,6 @@
|
|||||||
// [$LIST] Dqn_List | DQN_LIST | Chunked linked lists, append only
|
// [$LIST] Dqn_List | DQN_LIST | Chunked linked lists, append only
|
||||||
#include "dqn_containers.h"
|
#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
|
// NOTE: Additional Configuration
|
||||||
// - Override the default break into the active debugger function. By default
|
// - Override the default break into the active debugger function. By default
|
||||||
// we use __debugbreak() on Windows and raise(SIGTRAP) on other platforms.
|
// 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
|
// [$TCTX] Dqn_ThreadContext | | Per-thread data structure e.g. temp arenas
|
||||||
#include "dqn_platform.h"
|
#include "dqn_platform.h"
|
||||||
|
|
||||||
|
// NOTE: Dqn_OS ====================================================================================
|
||||||
|
// [$EXEC] Dqn_OSExec | | Execute programs programatically
|
||||||
|
#include "dqn_os.h"
|
||||||
|
|
||||||
// NOTE: Dqn_Math ==================================================================================
|
// NOTE: Dqn_Math ==================================================================================
|
||||||
// [$VEC2] Dqn_V2, V2i | DQN_V2 |
|
// [$VEC2] Dqn_V2, V2i | DQN_V2 |
|
||||||
// [$VEC3] Dqn_V3, V3i | DQN_V3 |
|
// [$VEC3] Dqn_V3, V3i | DQN_V3 |
|
||||||
@ -300,6 +304,7 @@
|
|||||||
#include "dqn_hash.h"
|
#include "dqn_hash.h"
|
||||||
|
|
||||||
// NOTE: Dqn_Helpers ===============================================================================
|
// NOTE: Dqn_Helpers ===============================================================================
|
||||||
|
// [$PCG3] Dqn_PCG32 | | RNG from the PCG family
|
||||||
// [$JSON] Dqn_JSONBuilder | DQN_JSON_BUILDER | Construct json output
|
// [$JSON] Dqn_JSONBuilder | DQN_JSON_BUILDER | Construct json output
|
||||||
// [$BHEX] Dqn_Bin | DQN_BIN | Binary <-> hex helpers
|
// [$BHEX] Dqn_Bin | DQN_BIN | Binary <-> hex helpers
|
||||||
// [$BSEA] Dqn_BinarySearch | | Binary search
|
// [$BSEA] Dqn_BinarySearch | | Binary search
|
||||||
@ -319,6 +324,7 @@
|
|||||||
#include "dqn_strings.cpp"
|
#include "dqn_strings.cpp"
|
||||||
#include "dqn_containers.cpp"
|
#include "dqn_containers.cpp"
|
||||||
#include "dqn_platform.cpp"
|
#include "dqn_platform.cpp"
|
||||||
|
#include "dqn_os.cpp"
|
||||||
#include "dqn_math.cpp"
|
#include "dqn_math.cpp"
|
||||||
#include "dqn_hash.cpp"
|
#include "dqn_hash.cpp"
|
||||||
#include "dqn_helpers.cpp"
|
#include "dqn_helpers.cpp"
|
||||||
|
208
dqn_base.cpp
208
dqn_base.cpp
@ -1,5 +1,5 @@
|
|||||||
// NOTE: [$INTR] Intrinsics ========================================================================
|
// 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)
|
#if defined(DQN_COMPILER_GCC) || defined(DQN_COMPILER_CLANG)
|
||||||
#include <cpuid.h>
|
#include <cpuid.h>
|
||||||
#endif
|
#endif
|
||||||
@ -16,7 +16,7 @@ Dqn_CPUIDRegisters Dqn_CPUID(int function_id)
|
|||||||
#endif
|
#endif
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
#endif // !defined(DQN_OS_ARM64)
|
#endif // !defined(DQN_PLATFORM_ARM64) && !defined(DQN_PLATFORM_EMSCRIPTEN)
|
||||||
|
|
||||||
// NOTE: [$ALLO] Dqn_Allocator =====================================================================
|
// NOTE: [$ALLO] Dqn_Allocator =====================================================================
|
||||||
DQN_API void *Dqn_Allocator_Alloc(Dqn_Allocator allocator, size_t size, uint8_t align, Dqn_ZeroMem zero_mem)
|
DQN_API void *Dqn_Allocator_Alloc(Dqn_Allocator allocator, size_t size, uint8_t align, Dqn_ZeroMem zero_mem)
|
||||||
@ -110,7 +110,7 @@ DQN_API Dqn_PrintStyle Dqn_Print_StyleBold()
|
|||||||
return result;
|
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);
|
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);
|
WriteFile(print_handle, string.data, DQN_CAST(unsigned long)string.size, &bytes_written, nullptr);
|
||||||
}
|
}
|
||||||
#else
|
#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
|
#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 (string.data && string.size) {
|
||||||
if (style.colour)
|
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)
|
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);
|
Dqn_Print_Std(std_handle, string);
|
||||||
if (style.colour || style.bold == Dqn_PrintBold_Yes)
|
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_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.data = DQN_CAST(char *)buf;
|
||||||
string.size = len;
|
string.size = len;
|
||||||
|
|
||||||
@ -175,7 +175,7 @@ DQN_FILE_SCOPE char *Dqn_Print_VSPrintfChunker_(const char *buf, void *user, int
|
|||||||
return (char *)buf;
|
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_list args;
|
||||||
va_start(args, fmt);
|
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);
|
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_list args;
|
||||||
va_start(args, fmt);
|
va_start(args, fmt);
|
||||||
@ -191,32 +191,32 @@ DQN_API void Dqn_Print_StdFStyle(Dqn_PrintStd std_handle, Dqn_PrintStyle style,
|
|||||||
va_end(args);
|
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];
|
char buffer[STB_SPRINTF_MIN];
|
||||||
STB_SPRINTF_DECORATE(vsprintfcb)(Dqn_Print_VSPrintfChunker_, DQN_CAST(void *)DQN_CAST(uintptr_t)std_handle, buffer, fmt, args);
|
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 (fmt) {
|
||||||
if (style.colour)
|
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)
|
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);
|
Dqn_Print_StdFV(std_handle, fmt, args);
|
||||||
if (style.colour || style.bold == Dqn_PrintBold_Yes)
|
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, 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_list args;
|
||||||
va_start(args, fmt);
|
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);
|
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_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_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_list args;
|
||||||
va_start(args, fmt);
|
va_start(args, fmt);
|
||||||
@ -244,87 +244,87 @@ DQN_API void Dqn_Print_StdLnFStyle(Dqn_PrintStd std_handle, Dqn_PrintStyle style
|
|||||||
va_end(args);
|
va_end(args);
|
||||||
}
|
}
|
||||||
|
|
||||||
DQN_API void Dqn_Print_StdLnFVStyle(Dqn_PrintStd std_handle, Dqn_PrintStyle style, DQN_FMT_STRING_ANNOTATE char const *fmt, va_list args)
|
DQN_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_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];
|
DQN_THREAD_LOCAL char buffer[32];
|
||||||
buffer[0] = 0;
|
buffer[0] = 0;
|
||||||
Dqn_String8 result = {};
|
Dqn_Str8 result = {};
|
||||||
result.size = STB_SPRINTF_DECORATE(snprintf)(buffer,
|
result.size = STB_SPRINTF_DECORATE(snprintf)(buffer,
|
||||||
DQN_ARRAY_UCOUNT(buffer),
|
DQN_ARRAY_UCOUNT(buffer),
|
||||||
"\x1b[%d;2;%u;%u;%um",
|
"\x1b[%d;2;%u;%u;%um",
|
||||||
colour == Dqn_PrintESCColour_Fg ? 38 : 48,
|
colour == Dqn_PrintESCColour_Fg ? 38 : 48,
|
||||||
r, g, b);
|
r, g, b);
|
||||||
result.data = buffer;
|
result.data = buffer;
|
||||||
return result;
|
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 r = DQN_CAST(uint8_t)(value >> 24);
|
||||||
uint8_t g = DQN_CAST(uint8_t)(value >> 16);
|
uint8_t g = DQN_CAST(uint8_t)(value >> 16);
|
||||||
uint8_t b = DQN_CAST(uint8_t)(value >> 8);
|
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;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
// NOTE: [$LLOG] Dqn_Log ==========================================================================
|
// NOTE: [$LLOG] Dqn_Log ==========================================================================
|
||||||
DQN_API Dqn_String8 Dqn_Log_MakeString(Dqn_Allocator allocator,
|
DQN_API Dqn_Str8 Dqn_Log_MakeStr8(Dqn_Allocator allocator,
|
||||||
bool colour,
|
bool colour,
|
||||||
Dqn_String8 type,
|
Dqn_Str8 type,
|
||||||
int log_type,
|
int log_type,
|
||||||
Dqn_CallSite call_site,
|
Dqn_CallSite call_site,
|
||||||
char const *fmt,
|
DQN_FMT_ATTRIB char const *fmt,
|
||||||
va_list args)
|
va_list args)
|
||||||
{
|
{
|
||||||
Dqn_usize header_size_no_ansi_codes = 0;
|
Dqn_usize header_size_no_ansi_codes = 0;
|
||||||
Dqn_String8 header = {};
|
Dqn_Str8 header = {};
|
||||||
{
|
{
|
||||||
DQN_LOCAL_PERSIST Dqn_usize max_type_length = 0;
|
DQN_LOCAL_PERSIST Dqn_usize max_type_length = 0;
|
||||||
max_type_length = DQN_MAX(max_type_length, type.size);
|
max_type_length = DQN_MAX(max_type_length, type.size);
|
||||||
int type_padding = DQN_CAST(int)(max_type_length - type.size);
|
int type_padding = DQN_CAST(int)(max_type_length - type.size);
|
||||||
|
|
||||||
Dqn_String8 colour_esc = {};
|
Dqn_Str8 colour_esc = {};
|
||||||
Dqn_String8 bold_esc = {};
|
Dqn_Str8 bold_esc = {};
|
||||||
Dqn_String8 reset_esc = {};
|
Dqn_Str8 reset_esc = {};
|
||||||
if (colour) {
|
if (colour) {
|
||||||
bold_esc = Dqn_Print_ESCBoldString;
|
bold_esc = Dqn_Print_ESCBoldStr8;
|
||||||
reset_esc = Dqn_Print_ESCResetString;
|
reset_esc = Dqn_Print_ESCResetStr8;
|
||||||
switch (log_type) {
|
switch (log_type) {
|
||||||
case Dqn_LogType_Debug: break;
|
case Dqn_LogType_Debug: break;
|
||||||
case Dqn_LogType_Info: colour_esc = Dqn_Print_ESCColourFgU32String(Dqn_LogTypeColourU32_Info); break;
|
case Dqn_LogType_Info: colour_esc = Dqn_Print_ESCColourFgU32Str8(Dqn_LogTypeColourU32_Info); break;
|
||||||
case Dqn_LogType_Warning: colour_esc = Dqn_Print_ESCColourFgU32String(Dqn_LogTypeColourU32_Warning); break;
|
case Dqn_LogType_Warning: colour_esc = Dqn_Print_ESCColourFgU32Str8(Dqn_LogTypeColourU32_Warning); break;
|
||||||
case Dqn_LogType_Error: colour_esc = Dqn_Print_ESCColourFgU32String(Dqn_LogTypeColourU32_Error); 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_Str8 file_name = Dqn_Str8_FileNameFromPath(call_site.file);
|
||||||
Dqn_DateHMSTimeString const time = Dqn_Date_HMSLocalTimeStringNow();
|
Dqn_DateHMSTimeStr8 const time = Dqn_Date_LocalTimeHMSStr8Now();
|
||||||
header = Dqn_String8_InitF(allocator,
|
header = Dqn_Str8_InitF(allocator,
|
||||||
"%.*s " // date
|
"%.*s " // date
|
||||||
"%.*s " // hms
|
"%.*s " // hms
|
||||||
"%.*s" // colour
|
"%.*s" // colour
|
||||||
"%.*s" // bold
|
"%.*s" // bold
|
||||||
"%.*s" // type
|
"%.*s" // type
|
||||||
"%*s" // type padding
|
"%*s" // type padding
|
||||||
"%.*s" // reset
|
"%.*s" // reset
|
||||||
" %.*s" // file name
|
" %.*s" // file name
|
||||||
":%05u ", // line number
|
":%05u ", // line number
|
||||||
DQN_CAST(uint32_t)time.date_size - 2, time.date + 2, // date
|
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)time.hms_size, time.hms, // hms
|
||||||
DQN_CAST(uint32_t)colour_esc.size, colour_esc.data, // colour
|
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)bold_esc.size, bold_esc.data, // bold
|
||||||
DQN_CAST(uint32_t)type.size, type.data, // type
|
DQN_CAST(uint32_t)type.size, type.data, // type
|
||||||
DQN_CAST(uint32_t)type_padding, "", // type padding
|
DQN_CAST(uint32_t)type_padding, "", // type padding
|
||||||
DQN_CAST(uint32_t)reset_esc.size, reset_esc.data, // reset
|
DQN_CAST(uint32_t)reset_esc.size, reset_esc.data, // reset
|
||||||
DQN_CAST(uint32_t)file_name.size, file_name.data, // file name
|
DQN_CAST(uint32_t)file_name.size, file_name.data, // file name
|
||||||
call_site.line); // line number
|
call_site.line); // line number
|
||||||
header_size_no_ansi_codes = header.size - colour_esc.size - Dqn_Print_ESCResetString.size;
|
header_size_no_ansi_codes = header.size - colour_esc.size - Dqn_Print_ESCResetStr8.size;
|
||||||
}
|
}
|
||||||
|
|
||||||
// NOTE: Header padding ========================================================================
|
// NOTE: Header padding ========================================================================
|
||||||
@ -336,15 +336,15 @@ DQN_API Dqn_String8 Dqn_Log_MakeString(Dqn_Allocator allocator,
|
|||||||
}
|
}
|
||||||
|
|
||||||
// NOTE: Construct final log ===================================================================
|
// NOTE: Construct final log ===================================================================
|
||||||
Dqn_String8 user_msg = Dqn_String8_InitFV(allocator, fmt, args);
|
Dqn_Str8 user_msg = Dqn_Str8_InitFV(allocator, fmt, args);
|
||||||
Dqn_String8 result = Dqn_String8_Allocate(allocator, header.size + header_padding + user_msg.size, Dqn_ZeroMem_No);
|
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_MEMCPY(result.data, header.data, header.size);
|
||||||
DQN_MEMSET(result.data + header.size, ' ', header_padding);
|
DQN_MEMSET(result.data + header.size, ' ', header_padding);
|
||||||
DQN_MEMCPY(result.data + header.size + header_padding, user_msg.data, user_msg.size);
|
DQN_MEMCPY(result.data + header.size + header_padding, user_msg.data, user_msg.size);
|
||||||
return result;
|
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;
|
Dqn_Library *lib = g_dqn_library;
|
||||||
(void)log_type;
|
(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);
|
Dqn_TicketMutex_Begin(&lib->log_file_mutex);
|
||||||
if (lib->log_to_file && !lib->log_file.handle && lib->log_file.error_size == 0) {
|
if (lib->log_to_file && !lib->log_file.handle && lib->log_file.error_size == 0) {
|
||||||
Dqn_ThreadScratch scratch = Dqn_Thread_GetScratch(nullptr);
|
Dqn_ThreadScratch scratch = Dqn_Thread_GetScratch(nullptr);
|
||||||
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);
|
lib->log_file = Dqn_Fs_OpenFile(log_path, Dqn_FsFileOpen_CreateAlways, Dqn_FsFileAccess_AppendOnly);
|
||||||
}
|
}
|
||||||
Dqn_TicketMutex_End(&lib->log_file_mutex);
|
Dqn_TicketMutex_End(&lib->log_file_mutex);
|
||||||
|
|
||||||
// NOTE: Generate the log header ===========================================
|
// NOTE: Generate the log header ===========================================
|
||||||
Dqn_ThreadScratch scratch = Dqn_Thread_GetScratch(nullptr);
|
Dqn_ThreadScratch scratch = Dqn_Thread_GetScratch(nullptr);
|
||||||
Dqn_String8 log_line = Dqn_Log_MakeString(scratch.allocator,
|
Dqn_Str8 log_line = Dqn_Log_MakeStr8(scratch.allocator, !lib->log_no_colour, type, log_type, call_site, fmt, args);
|
||||||
!lib->log_no_colour,
|
|
||||||
type,
|
|
||||||
log_type,
|
|
||||||
call_site,
|
|
||||||
fmt,
|
|
||||||
args);
|
|
||||||
|
|
||||||
// NOTE: Print log =========================================================
|
// NOTE: Print log =========================================================
|
||||||
Dqn_Print_StdLn(Dqn_PrintStd_Out, log_line);
|
Dqn_Print_StdLn(Dqn_PrintStd_Out, log_line);
|
||||||
|
|
||||||
Dqn_TicketMutex_Begin(&lib->log_file_mutex);
|
Dqn_TicketMutex_Begin(&lib->log_file_mutex);
|
||||||
Dqn_Fs_WriteFile(&lib->log_file, log_line);
|
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_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_;
|
if (g_dqn_library) {
|
||||||
logging_function(type, -1 /*log_type*/, g_dqn_library->log_user_data, call_site, fmt, 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);
|
||||||
|
} 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_list args;
|
||||||
va_start(args, fmt);
|
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);
|
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) {
|
switch (type) {
|
||||||
case Dqn_LogType_Error: type_string = DQN_STRING8("ERROR"); break;
|
case Dqn_LogType_Error: type_string = DQN_STR8("ERROR"); break;
|
||||||
case Dqn_LogType_Info: type_string = DQN_STRING8("INFO"); break;
|
case Dqn_LogType_Info: type_string = DQN_STR8("INFO"); break;
|
||||||
case Dqn_LogType_Warning: type_string = DQN_STRING8("WARN"); break;
|
case Dqn_LogType_Warning: type_string = DQN_STR8("WARN"); break;
|
||||||
case Dqn_LogType_Debug: type_string = DQN_STRING8("DEBUG"); break;
|
case Dqn_LogType_Debug: type_string = DQN_STR8("DEBUG"); break;
|
||||||
case Dqn_LogType_Count: type_string = DQN_STRING8("BADXX"); break;
|
case Dqn_LogType_Count: type_string = DQN_STR8("BADXX"); break;
|
||||||
}
|
}
|
||||||
|
Dqn_Log_FVCallSite(type_string, call_site, fmt, args);
|
||||||
Dqn_LogProc *logging_function = g_dqn_library->log_callback ? g_dqn_library->log_callback : Dqn_Log_FVDefault_;
|
|
||||||
logging_function(type_string, type /*log_type*/, g_dqn_library->log_user_data, call_site, fmt, args);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
DQN_API void Dqn_Log_TypeFCallSite(Dqn_LogType type, Dqn_CallSite call_site, char const *fmt, ...)
|
DQN_API void Dqn_Log_TypeFCallSite(Dqn_LogType type, Dqn_CallSite call_site, DQN_FMT_ATTRIB char const *fmt, ...)
|
||||||
{
|
{
|
||||||
va_list args;
|
va_list args;
|
||||||
va_start(args, fmt);
|
va_start(args, fmt);
|
||||||
Dqn_Log_TypeFVCallSite(type, call_site, fmt, args);
|
Dqn_Log_TypeFVCallSite(type, call_site, fmt, args);
|
||||||
va_end(args);
|
va_end(args);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
149
dqn_base.h
149
dqn_base.h
@ -39,12 +39,16 @@
|
|||||||
|
|
||||||
#if defined(_WIN32)
|
#if defined(_WIN32)
|
||||||
#define DQN_OS_WIN32
|
#define DQN_OS_WIN32
|
||||||
#elif defined(__aarch64__) || defined(_M_ARM64)
|
|
||||||
#define DQN_OS_ARM64
|
|
||||||
#elif defined(__linux__)
|
#elif defined(__linux__)
|
||||||
#define DQN_OS_UNIX
|
#define DQN_OS_UNIX
|
||||||
#endif
|
#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(DQN_COMPILER_MSVC) || defined(DQN_COMPILER_CLANG_CL)
|
||||||
#if defined(_CRT_SECURE_NO_WARNINGS)
|
#if defined(_CRT_SECURE_NO_WARNINGS)
|
||||||
#define DQN_CRT_SECURE_NO_WARNINGS_PREVIOUSLY_DEFINED
|
#define DQN_CRT_SECURE_NO_WARNINGS_PREVIOUSLY_DEFINED
|
||||||
@ -54,12 +58,12 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(DQN_COMPILER_MSVC)
|
#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_PUSH __pragma(warning(push))
|
||||||
#define DQN_MSVC_WARNING_DISABLE(...) __pragma(warning(disable: ##__VA_ARGS__))
|
#define DQN_MSVC_WARNING_DISABLE(...) __pragma(warning(disable: ##__VA_ARGS__))
|
||||||
#define DQN_MSVC_WARNING_POP __pragma(warning(pop))
|
#define DQN_MSVC_WARNING_POP __pragma(warning(pop))
|
||||||
#else
|
#else
|
||||||
#define DQN_FMT_STRING_ANNOTATE
|
#define DQN_FMT_ATTRIB
|
||||||
#define DQN_MSVC_WARNING_PUSH
|
#define DQN_MSVC_WARNING_PUSH
|
||||||
#define DQN_MSVC_WARNING_DISABLE(...)
|
#define DQN_MSVC_WARNING_DISABLE(...)
|
||||||
#define DQN_MSVC_WARNING_POP
|
#define DQN_MSVC_WARNING_POP
|
||||||
@ -67,8 +71,9 @@
|
|||||||
|
|
||||||
#if defined(DQN_COMPILER_CLANG) || defined(DQN_COMPILER_GCC) || defined(DQN_COMPILER_CLANG_CL)
|
#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_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_0(x) #x
|
||||||
#define DQN_GCC_WARNING_DISABLE_HELPER(warning) _Pragma(#warning)
|
#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")
|
#define DQN_GCC_WARNING_POP _Pragma("GCC diagnostic pop")
|
||||||
#else
|
#else
|
||||||
#define DQN_GCC_WARNING_PUSH
|
#define DQN_GCC_WARNING_PUSH
|
||||||
@ -87,11 +92,19 @@
|
|||||||
|
|
||||||
// NOTE: Alloc Macros ==============================================================================
|
// NOTE: Alloc Macros ==============================================================================
|
||||||
#if !defined(DQN_ALLOC)
|
#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
|
#endif
|
||||||
|
|
||||||
#if !defined(DQN_DEALLOC)
|
#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
|
#endif
|
||||||
|
|
||||||
// NOTE: String.h Dependencies =====================================================================
|
// NOTE: String.h Dependencies =====================================================================
|
||||||
@ -126,6 +139,10 @@
|
|||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if !defined(DQN_OS_WIN32)
|
||||||
|
#include <stdlib.h> // exit()
|
||||||
|
#endif
|
||||||
|
|
||||||
// NOTE: Math Macros ===============================================================================
|
// NOTE: Math Macros ===============================================================================
|
||||||
#define DQN_PI 3.14159265359f
|
#define DQN_PI 3.14159265359f
|
||||||
|
|
||||||
@ -206,11 +223,11 @@
|
|||||||
|
|
||||||
// NOTE: Assert Macros =============================================================================
|
// NOTE: Assert Macros =============================================================================
|
||||||
#define DQN_HARD_ASSERT(expr) DQN_HARD_ASSERTF(expr, "")
|
#define DQN_HARD_ASSERT(expr) DQN_HARD_ASSERTF(expr, "")
|
||||||
#define DQN_HARD_ASSERTF(expr, fmt, ...) \
|
#define DQN_HARD_ASSERTF(expr, fmt, ...) \
|
||||||
if (!(expr)) { \
|
if (!(expr)) { \
|
||||||
Dqn_Log_ErrorF("Hard assert triggered " #expr ". " fmt, ##__VA_ARGS__); \
|
Dqn_Log_ErrorF("Hard assert triggered [" #expr "]. " fmt, ##__VA_ARGS__); \
|
||||||
Dqn_StackTrace_Print(128 /*limit*/); \
|
Dqn_StackTrace_Print(128 /*limit*/); \
|
||||||
DQN_DEBUG_BREAK; \
|
DQN_DEBUG_BREAK; \
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined(DQN_NO_ASSERT)
|
#if defined(DQN_NO_ASSERT)
|
||||||
@ -218,11 +235,11 @@
|
|||||||
#define DQN_ASSERT(...)
|
#define DQN_ASSERT(...)
|
||||||
#else
|
#else
|
||||||
#define DQN_ASSERT(expr) DQN_ASSERTF(expr, "")
|
#define DQN_ASSERT(expr) DQN_ASSERTF(expr, "")
|
||||||
#define DQN_ASSERTF(expr, fmt, ...) \
|
#define DQN_ASSERTF(expr, fmt, ...) \
|
||||||
if (!(expr)) { \
|
if (!(expr)) { \
|
||||||
Dqn_Log_ErrorF("Assert triggered " #expr ". " fmt, ##__VA_ARGS__); \
|
Dqn_Log_ErrorF("Assert triggered [" #expr "]. " fmt, ##__VA_ARGS__); \
|
||||||
Dqn_StackTrace_Print(128 /*limit*/); \
|
Dqn_StackTrace_Print(128 /*limit*/); \
|
||||||
DQN_DEBUG_BREAK; \
|
DQN_DEBUG_BREAK; \
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -308,6 +325,10 @@ typedef double Dqn_f64;
|
|||||||
typedef unsigned int Dqn_uint;
|
typedef unsigned int Dqn_uint;
|
||||||
typedef int32_t Dqn_b32;
|
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_USIZE_MAX UINTPTR_MAX
|
||||||
#define DQN_ISIZE_MAX INTPTR_MAX
|
#define DQN_ISIZE_MAX INTPTR_MAX
|
||||||
#define DQN_ISIZE_MIN INTPTR_MIN
|
#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
|
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
|
char *data; // The bytes of the string
|
||||||
Dqn_usize size; // The number of bytes in the string
|
Dqn_usize size; // The number of bytes in the string
|
||||||
@ -329,14 +350,27 @@ struct Dqn_String8
|
|||||||
char *end () { return data + size; }
|
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 ======================================================================
|
// NOTE: [$CALL] Dqn_CallSite ======================================================================
|
||||||
struct Dqn_CallSite
|
struct Dqn_CallSite
|
||||||
{
|
{
|
||||||
Dqn_String8 file;
|
Dqn_Str8 file;
|
||||||
Dqn_String8 function;
|
Dqn_Str8 function;
|
||||||
unsigned int line;
|
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 ========================================================================
|
// NOTE: [$INTR] Intrinsics ========================================================================
|
||||||
// Platform agnostic functions for CPU level instructions like atomics, barriers
|
// Platform agnostic functions for CPU level instructions like atomics, barriers
|
||||||
@ -367,9 +401,12 @@ struct Dqn_CallSite
|
|||||||
#define Dqn_CompilerWriteBarrierAndCPUWriteFence _WriteBarrier(); _mm_sfence()
|
#define Dqn_CompilerWriteBarrierAndCPUWriteFence _WriteBarrier(); _mm_sfence()
|
||||||
#elif defined(DQN_COMPILER_GCC) || defined(DQN_COMPILER_CLANG)
|
#elif defined(DQN_COMPILER_GCC) || defined(DQN_COMPILER_CLANG)
|
||||||
#if defined(__ANDROID__)
|
#if defined(__ANDROID__)
|
||||||
|
#elif defined(DQN_PLATFORM_EMSCRIPTEN)
|
||||||
|
#include <emmintrin.h>
|
||||||
#else
|
#else
|
||||||
#include <x86intrin.h>
|
#include <x86intrin.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define Dqn_Atomic_AddU32(target, value) __atomic_fetch_add(target, value, __ATOMIC_ACQ_REL)
|
#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_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)
|
#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
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
#if !defined(DQN_OS_ARM64)
|
#if !defined(DQN_PLATFORM_ARM64)
|
||||||
struct Dqn_CPUIDRegisters
|
struct Dqn_CPUIDRegisters
|
||||||
{
|
{
|
||||||
Dqn_uint array[4]; ///< Values from 'CPUID' instruction for each register (EAX, EBX, ECX, EDX)
|
Dqn_uint array[4]; ///< Values from 'CPUID' instruction for each register (EAX, EBX, ECX, EDX)
|
||||||
};
|
};
|
||||||
|
|
||||||
Dqn_CPUIDRegisters Dqn_CPUID(int function_id);
|
Dqn_CPUIDRegisters Dqn_CPUID(int function_id);
|
||||||
#endif // DQN_OS_ARM64
|
#endif // DQN_PLATFORM_ARM64
|
||||||
|
|
||||||
// NOTE: [$TMUT] Dqn_TicketMutex ===================================================================
|
// NOTE: [$TMUT] Dqn_TicketMutex ===================================================================
|
||||||
//
|
//
|
||||||
@ -562,40 +599,40 @@ DQN_API Dqn_PrintStyle Dqn_Print_StyleBold ();
|
|||||||
|
|
||||||
|
|
||||||
// NOTE: Print =====================================================================================
|
// NOTE: Print =====================================================================================
|
||||||
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_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, ...);
|
||||||
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);
|
||||||
|
|
||||||
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);
|
||||||
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, ...);
|
||||||
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);
|
||||||
|
|
||||||
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_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, ...);
|
||||||
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_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_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, ...);
|
||||||
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);
|
||||||
|
|
||||||
// NOTE: ANSI Formatting Codes =====================================================================
|
// NOTE: ANSI Formatting Codes =====================================================================
|
||||||
Dqn_String8 Dqn_Print_ESCColourString (Dqn_PrintESCColour colour, uint8_t r, uint8_t g, uint8_t b);
|
Dqn_Str8 Dqn_Print_ESCColourStr8 (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_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_ESCColourFgStr8(r, g, b) Dqn_Print_ESCColourStr8(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_ESCColourBgStr8(r, g, b) Dqn_Print_ESCColourStr8(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_ESCColourFg(r, g, b) Dqn_Print_ESCColourStr8(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_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_ESCColourFgU32Str8(value) Dqn_Print_ESCColourU32Str8(Dqn_PrintESCColour_Fg, value)
|
||||||
#define Dqn_Print_ESCColourBgU32String(value) Dqn_Print_ESCColourU32String(Dqn_PrintESCColour_Bg, value)
|
#define Dqn_Print_ESCColourBgU32Str8(value) Dqn_Print_ESCColourU32Str8(Dqn_PrintESCColour_Bg, value)
|
||||||
#define Dqn_Print_ESCColourFgU32(value) Dqn_Print_ESCColourU32String(Dqn_PrintESCColour_Fg, value).data
|
#define Dqn_Print_ESCColourFgU32(value) Dqn_Print_ESCColourU32Str8(Dqn_PrintESCColour_Fg, value).data
|
||||||
#define Dqn_Print_ESCColourBgU32(value) Dqn_Print_ESCColourU32String(Dqn_PrintESCColour_Bg, value).data
|
#define Dqn_Print_ESCColourBgU32(value) Dqn_Print_ESCColourU32Str8(Dqn_PrintESCColour_Bg, value).data
|
||||||
|
|
||||||
#define Dqn_Print_ESCReset "\x1b[0m"
|
#define Dqn_Print_ESCReset "\x1b[0m"
|
||||||
#define Dqn_Print_ESCBold "\x1b[1m"
|
#define Dqn_Print_ESCBold "\x1b[1m"
|
||||||
#define Dqn_Print_ESCResetString DQN_STRING8(Dqn_Print_ESCReset)
|
#define Dqn_Print_ESCResetStr8 DQN_STR8(Dqn_Print_ESCReset)
|
||||||
#define Dqn_Print_ESCBoldString DQN_STRING8(Dqn_Print_ESCBold)
|
#define Dqn_Print_ESCBoldStr8 DQN_STR8(Dqn_Print_ESCBold)
|
||||||
|
|
||||||
// NOTE: [$LLOG] Dqn_Log ==========================================================================
|
// NOTE: [$LLOG] Dqn_Log ==========================================================================
|
||||||
// NOTE: API
|
// NOTE: API
|
||||||
@ -623,7 +660,7 @@ enum Dqn_LogType
|
|||||||
#define Dqn_LogTypeColourU32_Warning 0xff'ff'00'ff // Yellow
|
#define Dqn_LogTypeColourU32_Warning 0xff'ff'00'ff // Yellow
|
||||||
#define Dqn_LogTypeColourU32_Error 0xff'00'00'ff // Red
|
#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_DebugF(fmt, ...) Dqn_Log_TypeFCallSite(Dqn_LogType_Debug, DQN_CALL_SITE, fmt, ## __VA_ARGS__)
|
||||||
#define Dqn_Log_InfoF(fmt, ...) Dqn_Log_TypeFCallSite(Dqn_LogType_Info, DQN_CALL_SITE, fmt, ## __VA_ARGS__)
|
#define Dqn_Log_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_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__)
|
#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 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_STRING_ANNOTATE char const *fmt, va_list va);
|
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_STRING_ANNOTATE char const *fmt, ...);
|
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_String8 type, Dqn_CallSite call_site, DQN_FMT_STRING_ANNOTATE char const *fmt, va_list va);
|
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_String8 type, Dqn_CallSite call_site, DQN_FMT_STRING_ANNOTATE char const *fmt, ...);
|
DQN_API void Dqn_Log_FCallSite (Dqn_Str8 type, Dqn_CallSite call_site, DQN_FMT_ATTRIB char const *fmt, ...);
|
||||||
|
686
dqn_containers.h
686
dqn_containers.h
@ -5,8 +5,32 @@ enum Dqn_ArrayErase
|
|||||||
Dqn_ArrayErase_Stable,
|
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);
|
struct Dqn_ArrayEraseResult
|
||||||
template <typename T> T * Dqn_CArray_Make (T* data, Dqn_usize *size, Dqn_usize max, Dqn_usize count, Dqn_ZeroMem zero_mem);
|
{
|
||||||
|
// 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)
|
#if !defined(DQN_NO_VARRAY)
|
||||||
// NOTE: [$VARR] Dqn_VArray ========================================================================
|
// NOTE: [$VARR] Dqn_VArray ========================================================================
|
||||||
@ -85,18 +109,22 @@ template <typename T> struct Dqn_VArray
|
|||||||
};
|
};
|
||||||
|
|
||||||
// NOTE: Setup =====================================================================================
|
// 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_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> 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> 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> void Dqn_VArray_Reserve (Dqn_VArray<T> *array, Dqn_usize count);
|
||||||
|
|
||||||
// NOTE: Insert ====================================================================================
|
// 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_MakeArray (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_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 ====================================================================================
|
// 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> 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_API template <typename T> void Dqn_VArray_Clear (Dqn_VArray<T> *array, Dqn_ZeroMem zero_mem);
|
||||||
#endif // !defined(DQN_NO_VARRAY)
|
#endif // !defined(DQN_NO_VARRAY)
|
||||||
|
|
||||||
#if !defined(DQN_NO_SARRAY)
|
#if !defined(DQN_NO_SARRAY)
|
||||||
@ -114,17 +142,21 @@ template <typename T> struct Dqn_SArray
|
|||||||
};
|
};
|
||||||
|
|
||||||
// NOTE: Setup =====================================================================================
|
// 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> 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, 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 ====================================================================================
|
// NOTE: API =======================================================================================
|
||||||
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);
|
||||||
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_Make (Dqn_SArray<T> *array, Dqn_ZeroMem zero_mem);
|
||||||
DQN_API template <typename T> T * Dqn_SArray_Add (Dqn_SArray<T> *array, T const &item);
|
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> T * Dqn_SArray_InsertArray(Dqn_SArray<T> *array, Dqn_usize index, T const *items, Dqn_usize count);
|
||||||
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> T * Dqn_SArray_Insert (Dqn_SArray<T> *array, Dqn_usize index, T const &item);
|
||||||
DQN_API template <typename T> void Dqn_SArray_Clear (Dqn_SArray<T> *array);
|
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)
|
#endif // !defined(DQN_NO_SARRAY)
|
||||||
|
|
||||||
#if !defined(DQN_NO_FARRAY)
|
#if !defined(DQN_NO_FARRAY)
|
||||||
@ -141,35 +173,30 @@ template <typename T, Dqn_usize N> struct Dqn_FArray
|
|||||||
};
|
};
|
||||||
|
|
||||||
// NOTE: Setup =====================================================================================
|
// 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> 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> 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 ====================================================================================
|
// NOTE: API =======================================================================================
|
||||||
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);
|
||||||
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);
|
||||||
|
DQN_API template <typename T, Dqn_usize N> T * Dqn_FArray_AddArray (Dqn_FArray<T, N> *array, T const *items, Dqn_usize count);
|
||||||
// NOTE: Modify ====================================================================================
|
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> 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_InsertArray(Dqn_FArray<T, N> *array, T const &item, Dqn_usize index);
|
||||||
DQN_API template <typename T, Dqn_usize N> void Dqn_FArray_Clear (Dqn_FArray<T, N> *array);
|
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)
|
#endif // !defined(DQN_NO_FARRAY)
|
||||||
|
|
||||||
#if !defined(DQN_NO_SLICE)
|
#if !defined(DQN_NO_SLICE)
|
||||||
// NOTE: [$SLIC] Dqn_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)
|
#endif // !defined(DQN_NO_SLICE)
|
||||||
|
|
||||||
#if !defined(DQN_NO_DSMAP)
|
#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
|
// @proc Dqn_DSMap_HashToSlotIndex
|
||||||
// @desc Calculate the index into the map's `slots` array from the given hash.
|
// @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
|
// @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
|
// key and hash. If the map does not contain the key `found` is set to false
|
||||||
// returned.
|
// and `slot` and `value` are null.
|
||||||
//
|
//
|
||||||
// `Find` returns the value.
|
// `Find` returns the value.
|
||||||
// `FindSlot` returns the map's hash table slot.
|
// `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,
|
// @desc Same as `DSMap_Find*` except if the key does not exist in the table,
|
||||||
// a hash-table slot will be made.
|
// a hash-table slot will be made.
|
||||||
//
|
//
|
||||||
// `Make` assigns the key to the table and returns the hash table slot's value.
|
// `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.
|
// `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.
|
|
||||||
//
|
//
|
||||||
// If by adding the key-value pair to the table puts the table over 75% load,
|
// 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
|
// the table will be grown to 2x the current the size before insertion
|
||||||
// completes.
|
// completes.
|
||||||
//
|
//
|
||||||
// @param found[out] Pass a pointer to a bool. The bool will be set to true
|
// `found` will be set to true if the item already existed in the map before,
|
||||||
// if the item already existed in the map before, or false if the item was
|
// or false if the item was just created by this call.
|
||||||
// just created by this call.
|
|
||||||
|
|
||||||
// @proc Dqn_DSMap_Resize
|
// @proc Dqn_DSMap_Resize
|
||||||
// @desc Resize the table and move all elements to the new map.
|
// @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.
|
// initial size that the table was initialised as.
|
||||||
|
|
||||||
// @proc Dqn_DSMap_KeyCStringLit, Dqn_DSMap_KeyU64, Dqn_DSMap_KeyBuffer,
|
// @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
|
// @desc Create a hash-table key given
|
||||||
//
|
//
|
||||||
// `KeyCStringLit` a cstring literal
|
// `KeyCStringLit` a cstring literal
|
||||||
// `KeyU64` a u64
|
// `KeyU64` a u64
|
||||||
// `KeyBuffer` a (ptr+len) slice of bytes
|
// `KeyBuffer` a (ptr+len) slice of bytes
|
||||||
// `KeyString8` a Dqn_String8 string
|
// `KeyStr8` a Dqn_Str8 string
|
||||||
// `KeyString8Copy` a Dqn_String8 string that is copied first using the allocator
|
// `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*
|
// 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
|
// 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 =====================================================================================
|
// NOTE: Setup =====================================================================================
|
||||||
DQN_API template <typename T> Dqn_DSMap<T> Dqn_DSMap_Init (uint32_t size);
|
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> 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> bool Dqn_DSMap_IsValid (Dqn_DSMap<T> const *map);
|
||||||
|
|
||||||
// NOTE: Hash ======================================================================================
|
// 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_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_HashToSlotIndex(Dqn_DSMap<T> const *map, Dqn_DSMapKey key);
|
||||||
|
|
||||||
// NOTE: Insert ====================================================================================
|
// NOTE: Insert ====================================================================================
|
||||||
DQN_API template <typename T> Dqn_DSMapSlot<T> *Dqn_DSMap_FindSlot (Dqn_DSMap<T> const *map, Dqn_DSMapKey key);
|
template <typename T>
|
||||||
DQN_API template <typename T> Dqn_DSMapSlot<T> *Dqn_DSMap_MakeSlot (Dqn_DSMap<T> *map, Dqn_DSMapKey key, bool *found);
|
struct Dqn_DSMapResult
|
||||||
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);
|
bool found;
|
||||||
DQN_API template <typename T> T * Dqn_DSMap_Make (Dqn_DSMap<T> *map, Dqn_DSMapKey key, bool *found);
|
Dqn_DSMapSlot<T> *slot;
|
||||||
DQN_API template <typename T> T * Dqn_DSMap_Set (Dqn_DSMap<T> *map, Dqn_DSMapKey key, T const &value, bool *found);
|
T *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);
|
|
||||||
|
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 ================================================================================
|
// 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_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_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_KeyStr8 (Dqn_DSMap<T> const *map, Dqn_Str8 string);
|
||||||
DQN_API template <typename T> Dqn_DSMapKey Dqn_DSMap_KeyString8Copy (Dqn_DSMap<T> const *map, Dqn_Allocator allocator, Dqn_String8 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_KeyCStringLit(map, string) Dqn_DSMap_KeyBuffer(map, string, sizeof((string))/sizeof((string)[0]) - 1)
|
#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 Dqn_DSMapKey Dqn_DSMap_KeyU64NoHash (uint64_t u64);
|
||||||
DQN_API bool Dqn_DSMap_KeyEquals (Dqn_DSMapKey lhs, Dqn_DSMapKey rhs);
|
DQN_API bool Dqn_DSMap_KeyEquals (Dqn_DSMapKey lhs, Dqn_DSMapKey rhs);
|
||||||
DQN_API bool operator== (Dqn_DSMapKey lhs, Dqn_DSMapKey rhs);
|
DQN_API bool operator== (Dqn_DSMapKey lhs, Dqn_DSMapKey rhs);
|
||||||
#endif // !defined(DQN_NO_DSMAP)
|
#endif // !defined(DQN_NO_DSMAP)
|
||||||
|
|
||||||
#if !defined(DQN_NO_LIST)
|
#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_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_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 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.
|
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 =======================================================================================
|
// NOTE: API =======================================================================================
|
||||||
template <typename T> Dqn_List<T> Dqn_List_Init (Dqn_Arena *arena, Dqn_usize chunk_size);
|
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, size_t N> Dqn_List<T> Dqn_List_InitCArrayCopy (Dqn_Arena *arena, Dqn_usize chunk_size, T const (&array)[N]);
|
||||||
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_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_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_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)
|
#endif // !defined(DQN_NO_LIST)
|
||||||
|
|
||||||
// NOTE: [$CARR] Dqn_CArray ========================================================================
|
// 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)
|
if (!data || !size || *size == 0 || count == 0)
|
||||||
return result;
|
return result;
|
||||||
|
|
||||||
@ -476,16 +521,17 @@ template <typename T> Dqn_usize Dqn_CArray_EraseRange(T* data, Dqn_usize *size,
|
|||||||
*size -= erase_count;
|
*size -= erase_count;
|
||||||
}
|
}
|
||||||
|
|
||||||
result = erase_count;
|
result.items_erased = erase_count;
|
||||||
|
result.it_index = begin_index;
|
||||||
return result;
|
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)
|
if (!data || !size || count == 0)
|
||||||
return nullptr;
|
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;
|
return nullptr;
|
||||||
|
|
||||||
// TODO: Use placement new? Why doesn't this work?
|
// 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;
|
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)
|
#if !defined(DQN_NO_VARRAY)
|
||||||
// NOTE: [$VARR] Dqn_VArray ========================================================================
|
// NOTE: [$VARR] Dqn_VArray ========================================================================
|
||||||
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_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;
|
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))
|
if (!Dqn_VArray_IsValid(array))
|
||||||
return nullptr;
|
return nullptr;
|
||||||
@ -535,26 +644,72 @@ DQN_API template <typename T> T *Dqn_VArray_Make(Dqn_VArray<T> *array, Dqn_usize
|
|||||||
return result;
|
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)
|
if (result)
|
||||||
DQN_MEMCPY(result, items, count * sizeof(T));
|
DQN_MEMCPY(result, items, count * sizeof(T));
|
||||||
return result;
|
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))
|
T *result = Dqn_VArray_AddArray(array, &item, 1);
|
||||||
return;
|
return result;
|
||||||
Dqn_usize erase_count = Dqn_CArray_EraseRange<T>(array->data, &array->size, begin_index, count, erase);
|
|
||||||
Dqn_MemBlock_Pop(array->block, erase_count * sizeof(T));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
DQN_API template <typename T> void Dqn_VArray_Clear(Dqn_VArray<T> *array)
|
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;
|
array->size = 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
DQN_API template <typename T> void Dqn_VArray_Reserve(Dqn_VArray<T> *array, Dqn_usize count)
|
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_API template <typename T> Dqn_SArray<T> Dqn_SArray_Init(Dqn_Arena *arena, Dqn_usize size, Dqn_ZeroMem zero_mem)
|
||||||
{
|
{
|
||||||
Dqn_SArray<T> result = {};
|
Dqn_SArray<T> result = {};
|
||||||
if (!arena || !count)
|
if (!arena || !size)
|
||||||
return result;
|
return result;
|
||||||
|
|
||||||
result.data = Dqn_Arena_NewArray(arena, T, size, zero_mem);
|
result.data = Dqn_Arena_NewArray(arena, T, size, zero_mem);
|
||||||
if (result.data)
|
if (result.data)
|
||||||
result.max = size;
|
result.max = size;
|
||||||
return result;
|
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)
|
DQN_API template <typename T> bool Dqn_SArray_IsValid(Dqn_SArray<T> const *array)
|
||||||
{
|
{
|
||||||
bool result = array && array->data && array->size <= array->max;
|
bool result = array && array->data && array->size <= array->max;
|
||||||
return result;
|
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))
|
if (!Dqn_SArray_IsValid(array))
|
||||||
return nullptr;
|
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;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -606,11 +781,38 @@ DQN_API template <typename T> T *Dqn_SArray_Add(Dqn_SArray<T> *array, T const &i
|
|||||||
return result;
|
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)
|
if (!Dqn_SArray_IsValid(array) || array->size == 0 || count == 0)
|
||||||
return;
|
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)
|
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_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 = {};
|
Dqn_FArray<T, N> result = {};
|
||||||
bool added = Dqn_FArray_Add(&result, array, count);
|
bool added = Dqn_FArray_AddArray(&result, array, count);
|
||||||
DQN_ASSERT(added);
|
DQN_ASSERT(added);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
@ -635,27 +837,74 @@ DQN_API template <typename T, Dqn_usize N> bool Dqn_FArray_IsValid(Dqn_FArray<T,
|
|||||||
return result;
|
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))
|
if (!Dqn_FArray_IsValid(array))
|
||||||
return nullptr;
|
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;
|
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)
|
if (result)
|
||||||
DQN_MEMCPY(result, items, count * sizeof(T));
|
DQN_MEMCPY(result, items, count * sizeof(T));
|
||||||
return result;
|
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)
|
if (!Dqn_FArray_IsValid(array) || array->size == 0 || count == 0)
|
||||||
return;
|
return result;
|
||||||
Dqn_CArray_EraseRange(array->data, &array->size, begin_index, count, erase);
|
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)
|
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;
|
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)
|
template <typename T> Dqn_Slice<T> Dqn_Slice_Alloc(Dqn_Arena *arena, Dqn_usize size, Dqn_ZeroMem zero_mem)
|
||||||
{
|
{
|
||||||
Dqn_Slice<T> result = {};
|
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;
|
result.size = size;
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif // !defined(DQN_NO_SLICE)
|
#endif // !defined(DQN_NO_SLICE)
|
||||||
|
|
||||||
#if !defined(DQN_NO_DSMAP)
|
#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>
|
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)) {
|
if (Dqn_DSMap_IsValid(map)) {
|
||||||
uint32_t index = Dqn_DSMap_HashToSlotIndex(map, key);
|
uint32_t index = Dqn_DSMap_HashToSlotIndex(map, key);
|
||||||
if (map->hash_to_slot[index] != DQN_DS_MAP_SENTINEL_SLOT)
|
if (map->hash_to_slot[index] != DQN_DS_MAP_SENTINEL_SLOT) {
|
||||||
result = map->slots + map->hash_to_slot[index];
|
result.slot = map->slots + map->hash_to_slot[index];
|
||||||
}
|
result.value = &result.slot->value;
|
||||||
return DQN_CAST(Dqn_DSMapSlot<T> *)result;
|
result.found = true;
|
||||||
}
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
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))
|
if (!Dqn_DSMap_IsValid(map))
|
||||||
return result;
|
return result;
|
||||||
|
|
||||||
result = Dqn_DSMap_MakeSlot(map, key, found);
|
uint32_t index = Dqn_DSMap_HashToSlotIndex(map, key);
|
||||||
result->value = value;
|
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;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
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);
|
Dqn_DSMapResult<T> result = {};
|
||||||
T const *result = slot ? &slot->value : nullptr;
|
if (!Dqn_DSMap_IsValid(map))
|
||||||
return DQN_CAST(T *)result;
|
return result;
|
||||||
}
|
|
||||||
|
|
||||||
template <typename T>
|
result = Dqn_DSMap_Make(map, key);
|
||||||
T *Dqn_DSMap_Make(Dqn_DSMap<T> *map, Dqn_DSMapKey key, bool *found)
|
result.slot->value = value;
|
||||||
{
|
|
||||||
Dqn_DSMapSlot<T> *slot = Dqn_DSMap_MakeSlot(map, key, found);
|
|
||||||
T *result = &slot->value;
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
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);
|
Dqn_DSMapKey map_key = Dqn_DSMap_KeyU64(map, key);
|
||||||
return &result->value;
|
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>
|
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++) {
|
for (uint32_t old_index = 1 /*Sentinel*/; old_index < map->occupied; old_index++) {
|
||||||
Dqn_DSMapSlot<T> *old_slot = map->slots + old_index;
|
Dqn_DSMapSlot<T> *old_slot = map->slots + old_index;
|
||||||
if (old_slot->key.type != Dqn_DSMapKeyType_Invalid) {
|
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;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
bool Dqn_DSMap_Erase(Dqn_DSMap<T> *map, Dqn_DSMapKey key)
|
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[index] = map->hash_to_slot[probe_index];
|
||||||
map->hash_to_slot[probe_index] = DQN_DS_MAP_SENTINEL_SLOT;
|
map->hash_to_slot[probe_index] = DQN_DS_MAP_SENTINEL_SLOT;
|
||||||
index = probe_index;
|
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
|
// 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>
|
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_ASSERT(string.size > 0 && string.size <= UINT32_MAX);
|
||||||
Dqn_DSMapKey result = {};
|
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>
|
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_Str8 copy = Dqn_Str8_Copy(allocator, string);
|
||||||
Dqn_DSMapKey result = Dqn_DSMap_KeyString8(map, copy);
|
Dqn_DSMapKey result = Dqn_DSMap_KeyStr8(map, copy);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
#endif // !defined(DQN_NO_DSMAP)
|
#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;
|
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)
|
template <typename T> DQN_API T *Dqn_List_Make(Dqn_List<T> *list, Dqn_usize count)
|
||||||
{
|
{
|
||||||
if (list->chunk_size == 0)
|
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;
|
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)
|
template <typename T> DQN_API bool Dqn_List_Iterate(Dqn_List<T> *list, Dqn_ListIterator<T> *it, Dqn_usize start_index)
|
||||||
{
|
{
|
||||||
bool result = false;
|
bool result = false;
|
||||||
if (!list || !it || list->chunk_size <= 0)
|
if (!list || !it || list->chunk_size <= 0)
|
||||||
return result;
|
return result;
|
||||||
|
|
||||||
if (!it->init) {
|
if (it->init) {
|
||||||
|
it->index++;
|
||||||
|
} else {
|
||||||
*it = {};
|
*it = {};
|
||||||
if (start_index == 0) {
|
if (start_index == 0) {
|
||||||
it->chunk = list->head;
|
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;
|
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)
|
#endif // !defined(DQN_NO_LIST)
|
||||||
|
183
dqn_cppbuild.h
Normal file
183
dqn_cppbuild.h
Normal 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
|
@ -42,7 +42,7 @@ DQN_API Dqn_StackTraceWalkResult Dqn_StackTrace_Walk(Dqn_Arena *arena, uint16_t
|
|||||||
if (!SymInitialize(result.process, nullptr /*UserSearchPath*/, true /*fInvadeProcess*/)) {
|
if (!SymInitialize(result.process, nullptr /*UserSearchPath*/, true /*fInvadeProcess*/)) {
|
||||||
Dqn_ThreadScratch scratch = Dqn_Thread_GetScratch(nullptr);
|
Dqn_ThreadScratch scratch = Dqn_Thread_GetScratch(nullptr);
|
||||||
Dqn_WinError error = Dqn_Win_LastError(scratch.arena);
|
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 ======================================================================
|
// NOTE: Construct result ======================================================================
|
||||||
|
|
||||||
Dqn_String16 file_name16 = Dqn_String16{line.FileName, Dqn_CString16_Size(line.FileName)};
|
Dqn_Str16 file_name16 = Dqn_Str16{line.FileName, Dqn_CStr16_Size(line.FileName)};
|
||||||
Dqn_String16 function_name16 = Dqn_String16{symbol->Name, symbol->NameLen};
|
Dqn_Str16 function_name16 = Dqn_Str16{symbol->Name, symbol->NameLen};
|
||||||
|
|
||||||
Dqn_StackTraceFrame result = {};
|
Dqn_StackTraceFrame result = {};
|
||||||
result.address = raw_frame.base_addr;
|
result.address = raw_frame.base_addr;
|
||||||
result.line_number = line.LineNumber;
|
result.line_number = line.LineNumber;
|
||||||
result.file_name = Dqn_Win_String16ToString8(arena, file_name16);
|
result.file_name = Dqn_Win_Str16ToStr8(arena, file_name16);
|
||||||
result.function_name = Dqn_Win_String16ToString8(arena, function_name16);
|
result.function_name = Dqn_Win_Str16ToStr8(arena, function_name16);
|
||||||
#else
|
#else
|
||||||
Dqn_StackTraceFrame result = {};
|
Dqn_StackTraceFrame result = {};
|
||||||
#endif
|
#endif
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
@ -168,12 +168,12 @@ DQN_API void Dqn_StackTrace_Print(uint16_t limit)
|
|||||||
Dqn_ThreadScratch scratch = Dqn_Thread_GetScratch(nullptr);
|
Dqn_ThreadScratch scratch = Dqn_Thread_GetScratch(nullptr);
|
||||||
Dqn_Slice<Dqn_StackTraceFrame> stack_trace = Dqn_StackTrace_GetFrames(scratch.arena, limit);
|
Dqn_Slice<Dqn_StackTraceFrame> stack_trace = Dqn_StackTrace_GetFrames(scratch.arena, limit);
|
||||||
for (Dqn_StackTraceFrame& frame : stack_trace)
|
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 =========================================================================
|
// NOTE: [$DEBG] Dqn_Debug =========================================================================
|
||||||
#if defined(DQN_LEAK_TRACING)
|
#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)
|
if (!ptr)
|
||||||
return;
|
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);
|
Dqn_AllocRecord *alloc = Dqn_DSMap_Find(alloc_table, key);
|
||||||
if (alloc) {
|
if (alloc) {
|
||||||
if ((alloc->flags & Dqn_AllocRecordFlag_Freed) == 0) {
|
if ((alloc->flags & Dqn_AllocRecordFlag_Freed) == 0) {
|
||||||
Dqn_String8 alloc_stack_trace = Dqn_String8_Init(alloc->stack_trace, alloc->stack_trace_size);
|
Dqn_Str8 alloc_stack_trace = Dqn_Str8_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_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 clean_stack_trace = Dqn_String8_Slice(stack_trace, g_dqn_library->stack_trace_offset_to_our_call_stack, 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(
|
DQN_HARD_ASSERTF(
|
||||||
alloc->flags & Dqn_AllocRecordFlag_Freed,
|
alloc->flags & Dqn_AllocRecordFlag_Freed,
|
||||||
"\n\nThis pointer is already in the leak tracker, however it has not "
|
"\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"
|
"%.*s"
|
||||||
,
|
,
|
||||||
ptr, alloc->size,
|
ptr, alloc->size,
|
||||||
DQN_STRING_FMT(alloc_clean_stack_trace),
|
DQN_STR_FMT(alloc_clean_stack_trace),
|
||||||
DQN_STRING_FMT(clean_stack_trace));
|
DQN_STR_FMT(clean_stack_trace));
|
||||||
}
|
}
|
||||||
|
|
||||||
// NOTE: Pointer was reused, clean up the prior entry
|
// 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;
|
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)
|
if (!ptr || g_dqn_library->alloc_tracking_disabled)
|
||||||
return;
|
return;
|
||||||
@ -261,13 +261,13 @@ DQN_API void Dqn_Debug_TrackDealloc_(Dqn_String8 stack_trace, void *ptr)
|
|||||||
ptr);
|
ptr);
|
||||||
|
|
||||||
if (alloc->flags & Dqn_AllocRecordFlag_Freed) {
|
if (alloc->flags & Dqn_AllocRecordFlag_Freed) {
|
||||||
Dqn_String8 alloc_stack_trace = Dqn_String8_Init(alloc->stack_trace, alloc->stack_trace_size);
|
Dqn_Str8 alloc_stack_trace = Dqn_Str8_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_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_Str8 alloc_freed_stack_trace = Dqn_Str8_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_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,
|
DQN_HARD_ASSERTF((alloc->flags & Dqn_AllocRecordFlag_Freed) == 0,
|
||||||
"\n\nDouble free detected, pointer to free was already marked "
|
"\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"
|
"%.*s"
|
||||||
,
|
,
|
||||||
ptr, alloc->freed_size,
|
ptr, alloc->freed_size,
|
||||||
DQN_STRING_FMT(alloc_clean_stack_trace),
|
DQN_STR_FMT(alloc_clean_stack_trace),
|
||||||
DQN_STRING_FMT(alloc_freed_clean_stack_trace),
|
DQN_STR_FMT(alloc_freed_clean_stack_trace),
|
||||||
DQN_STRING_FMT(dealloc_stack_trace));
|
DQN_STR_FMT(dealloc_stack_trace));
|
||||||
}
|
}
|
||||||
|
|
||||||
alloc->flags |= Dqn_AllocRecordFlag_Freed;
|
alloc->flags |= Dqn_AllocRecordFlag_Freed;
|
||||||
@ -310,12 +310,12 @@ DQN_API void Dqn_Debug_DumpLeaks()
|
|||||||
leaked_bytes += alloc->size;
|
leaked_bytes += alloc->size;
|
||||||
leak_count++;
|
leak_count++;
|
||||||
|
|
||||||
Dqn_String8 stack_trace = Dqn_String8_Init(alloc->stack_trace, alloc->stack_trace_size);
|
Dqn_Str8 stack_trace = Dqn_Str8_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 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"
|
Dqn_Log_WarningF("Pointer (0x%p) leaked %_$$zu at:\n"
|
||||||
"%.*s",
|
"%.*s",
|
||||||
alloc->ptr, alloc->size,
|
alloc->ptr, alloc->size,
|
||||||
DQN_STRING_FMT(clean_stack_trace));
|
DQN_STR_FMT(clean_stack_trace));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
18
dqn_debug.h
18
dqn_debug.h
@ -63,10 +63,10 @@ DQN_API void Dqn_ASAN_UnpoisonMemoryRegion(void const volatile *ptr, Dqn_usize s
|
|||||||
|
|
||||||
struct Dqn_StackTraceFrame
|
struct Dqn_StackTraceFrame
|
||||||
{
|
{
|
||||||
uint64_t address;
|
uint64_t address;
|
||||||
uint64_t line_number;
|
uint64_t line_number;
|
||||||
Dqn_String8 file_name;
|
Dqn_Str8 file_name;
|
||||||
Dqn_String8 function_name;
|
Dqn_Str8 function_name;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Dqn_StackTraceRawFrame
|
struct Dqn_StackTraceRawFrame
|
||||||
@ -113,17 +113,17 @@ struct Dqn_AllocRecord
|
|||||||
uint16_t flags; // Bit flags from `Dqn_AllocRecordFlag`
|
uint16_t flags; // Bit flags from `Dqn_AllocRecordFlag`
|
||||||
char padding[2];
|
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 "
|
"We aim to keep the allocation record as light as possible as "
|
||||||
"memory tracking can get expensive. Enforce that there is no "
|
"memory tracking can get expensive. Enforce that there is no "
|
||||||
"unexpected padding.");
|
"unexpected padding.");
|
||||||
|
|
||||||
#if defined(DQN_LEAK_TRACING)
|
#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_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_String8_InitCString8(b_stacktrace_get_string()), ptr)
|
#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_TrackAlloc_(Dqn_Str8 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_TrackDealloc_(Dqn_Str8 stack_trace, void *ptr);
|
||||||
DQN_API void Dqn_Debug_DumpLeaks();
|
DQN_API void Dqn_Debug_DumpLeaks();
|
||||||
#else
|
#else
|
||||||
#define Dqn_Debug_TrackAlloc(...)
|
#define Dqn_Debug_TrackAlloc(...)
|
||||||
|
@ -1,16 +1,21 @@
|
|||||||
// NOTE: [$OS_H] OS Headers ========================================================================
|
// NOTE: [$OS_H] OS Headers ========================================================================
|
||||||
#if defined(DQN_OS_UNIX)
|
#if defined(DQN_OS_UNIX) || defined(DQN_PLATFORM_EMSCRIPTEN)
|
||||||
#include <errno.h> // errno
|
#include <errno.h> // errno
|
||||||
#include <fcntl.h> // O_RDONLY ... etc
|
#include <fcntl.h> // O_RDONLY ... etc
|
||||||
#include <linux/fs.h> // FICLONE
|
|
||||||
#include <sys/ioctl.h> // ioctl
|
#include <sys/ioctl.h> // ioctl
|
||||||
#include <sys/types.h> // pid_t
|
#include <sys/types.h> // pid_t
|
||||||
|
#include <sys/wait.h> // waitpid
|
||||||
#include <sys/random.h> // getrandom
|
#include <sys/random.h> // getrandom
|
||||||
#include <sys/stat.h> // stat
|
#include <sys/stat.h> // stat
|
||||||
#include <sys/sendfile.h> // sendfile
|
|
||||||
#include <sys/mman.h> // mmap
|
#include <sys/mman.h> // mmap
|
||||||
#include <time.h> // clock_gettime, nanosleep
|
#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
|
#endif
|
||||||
|
|
||||||
// NOTE: [$STBS] stb_sprintf =======================================================================
|
// NOTE: [$STBS] stb_sprintf =======================================================================
|
||||||
|
281
dqn_helpers.cpp
281
dqn_helpers.cpp
@ -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)
|
#if !defined(DQN_NO_JSON_BUILDER)
|
||||||
// NOTE: [$JSON] Dqn_JSONBuilder ===================================================================
|
// NOTE: [$JSON] Dqn_JSONBuilder ===================================================================
|
||||||
DQN_API Dqn_JSONBuilder Dqn_JSONBuilder_Init(Dqn_Allocator allocator, int spaces_per_indent)
|
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;
|
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;
|
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)
|
if (key.size == 0 && value.size == 0)
|
||||||
return;
|
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;
|
int spaces = builder->indent_level * spaces_per_indent;
|
||||||
|
|
||||||
if (key.size) {
|
if (key.size) {
|
||||||
Dqn_String8Builder_AppendF(&builder->string_builder,
|
Dqn_Str8Builder_AppendF(&builder->string_builder,
|
||||||
"%.*s%*c\"%.*s\": %.*s",
|
"%.*s%*c\"%.*s\": %.*s",
|
||||||
prefix_size, prefix,
|
prefix_size, prefix,
|
||||||
spaces, ' ',
|
spaces, ' ',
|
||||||
DQN_STRING_FMT(key),
|
DQN_STR_FMT(key),
|
||||||
DQN_STRING_FMT(value));
|
DQN_STR_FMT(value));
|
||||||
} else {
|
} else {
|
||||||
Dqn_String8Builder_AppendF(&builder->string_builder,
|
Dqn_Str8Builder_AppendF(&builder->string_builder,
|
||||||
"%.*s%*c%.*s",
|
"%.*s%*c%.*s",
|
||||||
prefix_size, prefix,
|
prefix_size, prefix,
|
||||||
spaces, ' ',
|
spaces, ' ',
|
||||||
DQN_STRING_FMT(value));
|
DQN_STR_FMT(value));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (item == Dqn_JSONBuilderItem_OpenContainer)
|
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;
|
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_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_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_list args;
|
||||||
va_start(args, value_fmt);
|
va_start(args, value_fmt);
|
||||||
@ -82,47 +158,47 @@ DQN_API void Dqn_JSONBuilder_KeyValueF(Dqn_JSONBuilder *builder, Dqn_String8 key
|
|||||||
va_end(args);
|
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_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_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_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_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_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_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)
|
if (!builder)
|
||||||
return;
|
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_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);
|
Dqn_JSONBuilder_KeyValueF(builder, key, "%.*s", value_string.size, value_string.data);
|
||||||
}
|
}
|
||||||
#endif // !defined(DQN_NO_JSON_BUILDER)
|
#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 ===========================================================================
|
// NOTE: [$BHEX] Dqn_Bin ===========================================================================
|
||||||
DQN_API char const *Dqn_Bin_HexBufferTrim0x(char const *hex, Dqn_usize size, Dqn_usize *real_size)
|
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));
|
Dqn_Str8 result = Dqn_Str8_TrimWhitespaceAround(Dqn_Str8_Init(hex, size));
|
||||||
result = Dqn_String8_TrimPrefix(result, DQN_STRING8("0x"), Dqn_String8EqCase_Insensitive);
|
result = Dqn_Str8_TrimPrefix(result, DQN_STR8("0x"), Dqn_Str8EqCase_Insensitive);
|
||||||
if (real_size)
|
if (real_size)
|
||||||
*real_size = result.size;
|
*real_size = result.size;
|
||||||
return result.data;
|
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;
|
Dqn_usize trimmed_size = 0;
|
||||||
char const *trimmed = Dqn_Bin_HexBufferTrim0x(string.data, string.size, &trimmed_size);
|
char const *trimmed = Dqn_Bin_HexBufferTrim0x(string.data, string.size, &trimmed_size);
|
||||||
Dqn_String8 result = Dqn_String8_Init(trimmed, trimmed_size);
|
Dqn_Str8 result = Dqn_Str8_Init(trimmed, trimmed_size);
|
||||||
return result;
|
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 = {};
|
Dqn_Str8 prefix = {};
|
||||||
if (!(flags & Dqn_BinHexU64StringFlags_No0xPrefix))
|
if (!(flags & Dqn_BinHexU64Str8Flags_No0xPrefix))
|
||||||
prefix = DQN_STRING8("0x");
|
prefix = DQN_STR8("0x");
|
||||||
|
|
||||||
Dqn_BinHexU64String result = {};
|
Dqn_BinHexU64Str8 result = {};
|
||||||
DQN_MEMCPY(result.data, prefix.data, prefix.size);
|
DQN_MEMCPY(result.data, prefix.data, prefix.size);
|
||||||
result.size += DQN_CAST(int8_t)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);
|
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;
|
result.size += DQN_CAST(uint8_t)size;
|
||||||
DQN_ASSERT(result.size < DQN_ARRAY_UCOUNT(result.data));
|
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;
|
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 = {};
|
Dqn_Str8 prefix = {};
|
||||||
if (!(flags & Dqn_BinHexU64StringFlags_No0xPrefix))
|
if (!(flags & Dqn_BinHexU64Str8Flags_No0xPrefix))
|
||||||
prefix = DQN_STRING8("0x");
|
prefix = DQN_STR8("0x");
|
||||||
|
|
||||||
char const *fmt = (flags & Dqn_BinHexU64StringFlags_UppercaseHex) ? "%I64X" : "%I64x";
|
char const *fmt = (flags & Dqn_BinHexU64Str8Flags_UppercaseHex) ? "%I64X" : "%I64x";
|
||||||
Dqn_usize required_size = Dqn_CString8_FSize(fmt, number) + prefix.size;
|
Dqn_usize required_size = Dqn_CStr8_FSize(fmt, number) + prefix.size;
|
||||||
Dqn_String8 result = Dqn_String8_Allocate(allocator, required_size, Dqn_ZeroMem_No);
|
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);
|
DQN_MEMCPY(result.data, prefix.data, prefix.size);
|
||||||
int space = DQN_CAST(int)DQN_MAX((result.size - prefix.size) + 1, 0); /*null-terminator*/
|
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);
|
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;
|
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);
|
uint64_t result = Dqn_Bin_HexBufferToU64(hex.data, hex.size);
|
||||||
return result;
|
return result;
|
||||||
@ -279,9 +355,9 @@ DQN_API char *Dqn_Bin_BytesToHexBufferArena(Dqn_Arena *arena, void const *src, D
|
|||||||
return result;
|
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);
|
result.data = Dqn_Bin_BytesToHexBufferArena(arena, src, size);
|
||||||
if (result.data)
|
if (result.data)
|
||||||
result.size = size * 2;
|
result.size = size * 2;
|
||||||
@ -346,13 +422,13 @@ DQN_API Dqn_usize Dqn_Bin_HexBufferToBytesUnchecked(char const *hex, Dqn_usize h
|
|||||||
return result;
|
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);
|
Dqn_usize result = Dqn_Bin_HexBufferToBytesUnchecked(hex.data, hex.size, dest, dest_size);
|
||||||
return result;
|
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);
|
Dqn_usize result = Dqn_Bin_HexBufferToBytes(hex.data, hex.size, dest, dest_size);
|
||||||
return result;
|
return result;
|
||||||
@ -364,13 +440,10 @@ DQN_API char *Dqn_Bin_HexBufferToBytesArena(Dqn_Arena *arena, char const *hex, D
|
|||||||
if (!arena || !hex || size <= 0)
|
if (!arena || !hex || size <= 0)
|
||||||
return result;
|
return result;
|
||||||
|
|
||||||
Dqn_usize trim_size = 0;
|
Dqn_usize trim_size = 0;
|
||||||
char const *trim_hex = Dqn_Bin_HexBufferTrim0x(hex,
|
char const *trim_hex = Dqn_Bin_HexBufferTrim0x(hex, size, &trim_size);
|
||||||
size,
|
Dqn_usize binary_size = trim_size / 2;
|
||||||
&trim_size);
|
result = Dqn_Arena_NewArray(arena, char, binary_size, Dqn_ZeroMem_No);
|
||||||
|
|
||||||
Dqn_usize binary_size = trim_size / 2;
|
|
||||||
result = Dqn_Arena_NewArray(arena, char, binary_size, Dqn_ZeroMem_No);
|
|
||||||
if (result) {
|
if (result) {
|
||||||
Dqn_usize convert_size = Dqn_Bin_HexBufferToBytesUnchecked(trim_hex, trim_size, result, binary_size);
|
Dqn_usize convert_size = Dqn_Bin_HexBufferToBytesUnchecked(trim_hex, trim_size, result, binary_size);
|
||||||
if (real_size)
|
if (real_size)
|
||||||
@ -379,10 +452,10 @@ DQN_API char *Dqn_Bin_HexBufferToBytesArena(Dqn_Arena *arena, char const *hex, D
|
|||||||
return result;
|
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 = {};
|
Dqn_Str8 result = {};
|
||||||
result.data = Dqn_Bin_HexBufferToBytesArena(arena, hex.data, hex.size, &result.size);
|
result.data = Dqn_Bin_HexBufferToBytesArena(arena, hex.data, hex.size, &result.size);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
#endif // !defined(DQN_NO_BIN)
|
#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)
|
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;
|
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_API int64_t Dqn_Safe_SaturateCastISizeToI64(Dqn_isize val)
|
||||||
{
|
{
|
||||||
DQN_ASSERT(val >= INT64_MIN && val <= 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(val, INT64_MIN, INT64_MAX);
|
int64_t result = DQN_CAST(int64_t)DQN_CLAMP(DQN_CAST(int64_t)val, INT64_MIN, INT64_MAX);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -733,7 +806,7 @@ DQN_API uint64_t Dqn_Safe_SaturateCastIntToU64(int val)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// NOTE: [$MISC] Misc ==============================================================================
|
// 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_list args;
|
||||||
va_start(args, fmt);
|
va_start(args, fmt);
|
||||||
@ -747,16 +820,16 @@ DQN_API int Dqn_SNPrintFDotTruncate(char *buffer, int size, char const *fmt, ...
|
|||||||
return result;
|
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) {
|
if (val == 0) {
|
||||||
result.data[result.size++] = '0';
|
result.data[result.size++] = '0';
|
||||||
} else {
|
} else {
|
||||||
// NOTE: The number is written in reverse because we form the string by
|
// 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
|
// dividing by 10, so we write it in, then reverse it out after all is
|
||||||
// done.
|
// done.
|
||||||
Dqn_U64String temp = {};
|
Dqn_U64Str8 temp = {};
|
||||||
for (Dqn_usize digit_count = 0; val > 0; digit_count++) {
|
for (Dqn_usize digit_count = 0; val > 0; digit_count++) {
|
||||||
if (separator && (digit_count != 0) && (digit_count % 3 == 0))
|
if (separator && (digit_count != 0) && (digit_count % 3 == 0))
|
||||||
temp.data[temp.size++] = separator;
|
temp.data[temp.size++] = separator;
|
||||||
@ -783,7 +856,7 @@ DQN_API Dqn_U64String Dqn_U64ToString(uint64_t val, char separator)
|
|||||||
// NOTE: [$DLIB] Dqn_Library =======================================================================
|
// NOTE: [$DLIB] Dqn_Library =======================================================================
|
||||||
Dqn_Library *g_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) {
|
if (!g_dqn_library) {
|
||||||
static Dqn_Library default_instance = {};
|
static Dqn_Library default_instance = {};
|
||||||
@ -801,8 +874,8 @@ DQN_API Dqn_Library *Dqn_Library_Init()
|
|||||||
// NOTE: Query OS page size ====================================================================
|
// NOTE: Query OS page size ====================================================================
|
||||||
|
|
||||||
{
|
{
|
||||||
SYSTEM_INFO system_info = {};
|
|
||||||
#if defined(DQN_OS_WIN32)
|
#if defined(DQN_OS_WIN32)
|
||||||
|
SYSTEM_INFO system_info = {};
|
||||||
GetSystemInfo(&system_info);
|
GetSystemInfo(&system_info);
|
||||||
result->os_page_size = system_info.dwPageSize;
|
result->os_page_size = system_info.dwPageSize;
|
||||||
result->os_alloc_granularity = system_info.dwAllocationGranularity;
|
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?
|
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_Str8 sample_backtrace = Dqn_Str8_InitCStr8(b_stacktrace_get_string());
|
||||||
Dqn_String8 clean_backtrace = Dqn_Debug_CleanStackTrace(sample_backtrace);
|
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);
|
result->stack_trace_offset_to_our_call_stack = DQN_CAST(uint16_t)(sample_backtrace.size - clean_backtrace.size);
|
||||||
free(sample_backtrace.data);
|
free(sample_backtrace.data);
|
||||||
|
|
||||||
@ -840,28 +913,34 @@ DQN_API Dqn_Library *Dqn_Library_Init()
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
// NOTE: Print out init features ===============================================================
|
// 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");
|
// NOTE: %$$_I32u is a stb_sprintf format specifier, non-standard
|
||||||
Dqn_Print_StdLnF(Dqn_PrintStd_Err, " OS Page Size/Alloc Granularity: %$$_I32u/%$$_I32u", result->os_page_size, result->os_alloc_granularity);
|
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 __has_feature(address_sanitizer) || defined(__SANITIZE_ADDRESS__)
|
||||||
if (DQN_ASAN_POISON) {
|
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 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);
|
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;
|
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;
|
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)
|
#if defined(DQN_DEBUG_THREAD_CONTEXT)
|
||||||
// NOTE: Open a file to write the arena stats to
|
// NOTE: Open a file to write the arena stats to
|
||||||
FILE *file = nullptr;
|
FILE *file = nullptr;
|
||||||
fopen_s(&file, file_path.data, "a+b");
|
fopen_s(&file, file_path.data, "a+b");
|
||||||
if (file) {
|
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;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -908,7 +987,7 @@ DQN_API void Dqn_Library_DumpThreadContextArenaStat(Dqn_String8 file_path)
|
|||||||
Dqn_TicketMutex_End(&g_dqn_library->thread_context_mutex);
|
Dqn_TicketMutex_End(&g_dqn_library->thread_context_mutex);
|
||||||
|
|
||||||
// NOTE: Print the cumulative stat
|
// NOTE: Print the cumulative stat
|
||||||
Dqn_DateHMSTimeString now = Dqn_Date_HMSLocalTimeStringNow();
|
Dqn_DateHMSTimeStr now = Dqn_Date_HMSLocalTimeStrNow();
|
||||||
fprintf(file,
|
fprintf(file,
|
||||||
"Time=%.*s %.*s | Thread Context Arenas | Count=%d\n",
|
"Time=%.*s %.*s | Thread Context Arenas | Count=%d\n",
|
||||||
now.date_size, now.date,
|
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);
|
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);
|
fprintf(file, " [ALL] CURR %.*s\n", stats_string.size, stats_string.data);
|
||||||
}
|
}
|
||||||
|
|
||||||
// NOTE: Print individual thread arena data
|
// NOTE: Print individual thread arena data
|
||||||
for (Dqn_usize index = 0; index < stats_size; index++) {
|
for (Dqn_usize index = 0; index < stats_size; index++) {
|
||||||
Dqn_ArenaStat const *current = stats + 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);
|
fprintf(file, " [%03d] CURR %.*s\n", DQN_CAST(int)index, current_string.size, current_string.data);
|
||||||
}
|
}
|
||||||
|
|
||||||
fclose(file);
|
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
|
#else
|
||||||
(void)file_path;
|
(void)file_path;
|
||||||
#endif // #if defined(DQN_DEBUG_THREAD_CONTEXT)
|
#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)
|
#if !defined(DQN_NO_PROFILER)
|
||||||
// NOTE: [$PROF] Dqn_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);
|
zone = Dqn_Profiler_BeginZoneWithIndex(name, anchor_index);
|
||||||
}
|
}
|
||||||
@ -962,7 +1041,7 @@ Dqn_ProfilerZoneScope::~Dqn_ProfilerZoneScope()
|
|||||||
Dqn_Profiler_EndZone(zone);
|
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;
|
Dqn_ProfilerAnchor *anchor = Dqn_Profiler_AnchorBuffer(Dqn_ProfilerAnchorBuffer_Back) + anchor_index;
|
||||||
anchor->name = name;
|
anchor->name = name;
|
||||||
@ -998,11 +1077,11 @@ Dqn_ProfilerAnchor *Dqn_Profiler_AnchorBuffer(Dqn_ProfilerAnchorBuffer buffer)
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Dqn_Profiler_SwapAnchorBuffer(uint32_t anchor_count)
|
void Dqn_Profiler_SwapAnchorBuffer()
|
||||||
{
|
{
|
||||||
g_dqn_library->profiler->active_anchor_buffer++;
|
g_dqn_library->profiler->active_anchor_buffer++;
|
||||||
Dqn_ProfilerAnchor *anchors = Dqn_Profiler_AnchorBuffer(Dqn_ProfilerAnchorBuffer_Back);
|
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)
|
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;
|
Dqn_f64 tsc_exclusive_milliseconds = tsc_exclusive * 1000 / DQN_CAST(Dqn_f64)tsc_per_second;
|
||||||
if (tsc_exclusive == tsc_inclusive) {
|
if (tsc_exclusive == tsc_inclusive) {
|
||||||
Dqn_Print_LnF("%.*s[%u]: %.1fms",
|
Dqn_Print_LnF("%.*s[%u]: %.1fms",
|
||||||
DQN_STRING_FMT(anchor->name),
|
DQN_STR_FMT(anchor->name),
|
||||||
anchor->hit_count,
|
anchor->hit_count,
|
||||||
tsc_exclusive_milliseconds);
|
tsc_exclusive_milliseconds);
|
||||||
} else {
|
} else {
|
||||||
Dqn_f64 tsc_inclusive_milliseconds = tsc_inclusive * 1000 / DQN_CAST(Dqn_f64)tsc_per_second;
|
Dqn_f64 tsc_inclusive_milliseconds = tsc_inclusive * 1000 / DQN_CAST(Dqn_f64)tsc_per_second;
|
||||||
Dqn_Print_LnF("%.*s[%u]: %.1f/%.1fms",
|
Dqn_Print_LnF("%.*s[%u]: %.1f/%.1fms",
|
||||||
DQN_STRING_FMT(anchor->name),
|
DQN_STR_FMT(anchor->name),
|
||||||
anchor->hit_count,
|
anchor->hit_count,
|
||||||
tsc_exclusive_milliseconds,
|
tsc_exclusive_milliseconds,
|
||||||
tsc_inclusive_milliseconds);
|
tsc_inclusive_milliseconds);
|
||||||
|
232
dqn_helpers.h
232
dqn_helpers.h
@ -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)
|
#if !defined(DQN_NO_JSON_BUILDER)
|
||||||
// NOTE: [$JSON] Dqn_JSONBuilder ===================================================================
|
// NOTE: [$JSON] Dqn_JSONBuilder ===================================================================
|
||||||
// Basic helper class to construct JSON output to a string
|
// Basic helper class to construct JSON output to a string
|
||||||
@ -44,7 +66,7 @@ enum Dqn_JSONBuilderItem
|
|||||||
struct Dqn_JSONBuilder
|
struct Dqn_JSONBuilder
|
||||||
{
|
{
|
||||||
bool use_stdout; // When set, ignore the string builder and dump immediately to stdout
|
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 indent_level; // (Internal)
|
||||||
int spaces_per_indent; // The number of spaces per indent level
|
int spaces_per_indent; // The number of spaces per indent level
|
||||||
Dqn_JSONBuilderItem last_item;
|
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_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 Dqn_Str8 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_KeyValue (Dqn_JSONBuilder *builder, Dqn_Str8 key, Dqn_Str8 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, ...);
|
||||||
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_API void Dqn_JSONBuilder_ObjectEnd (Dqn_JSONBuilder *builder);
|
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_ArrayEnd (Dqn_JSONBuilder *builder);
|
||||||
DQN_API void Dqn_JSONBuilder_StringNamed (Dqn_JSONBuilder *builder, Dqn_String8 key, Dqn_String8 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_String8 key, Dqn_String8 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_String8 key, uint64_t 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_String8 key, int64_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_String8 key, double value, int decimal_places);
|
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_String8 key, bool value);
|
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_ObjectBegin(builder) Dqn_JSONBuilder_ObjectBeginNamed(builder, DQN_STRING8(""))
|
||||||
#define Dqn_JSONBuilder_ArrayBegin(builder) Dqn_JSONBuilder_ArrayBeginNamed(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_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_U64(builder, value) Dqn_JSONBuilder_U64Named(builder, DQN_STRING8(""), value)
|
||||||
#define Dqn_JSONBuilder_I64(builder, value) Dqn_JSONBuilder_I64Named(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)
|
#if !defined(DQN_NO_BIN)
|
||||||
// NOTE: [$BHEX] Dqn_Bin ===========================================================================
|
// NOTE: [$BHEX] Dqn_Bin ===========================================================================
|
||||||
// NOTE: API =======================================================================================
|
// NOTE: API =======================================================================================
|
||||||
// @proc Dqn_Bin_U64ToHexU64String
|
// @proc Dqn_Bin_U64ToHexU64Str8
|
||||||
// @desc Convert a 64 bit number to a hex string
|
// @desc Convert a 64 bit number to a hex string
|
||||||
// @param[in] number Number to convert to hexadecimal representation
|
// @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.
|
// output of the hexadecimal string.
|
||||||
// @return The hexadecimal representation of the number. This string is always
|
// @return The hexadecimal representation of the number. This string is always
|
||||||
// null-terminated.
|
// null-terminated.
|
||||||
|
|
||||||
// @proc Dqn_Bin_U64ToHex
|
// @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
|
// @param[in] allocator The memory allocator to use for the memory of the
|
||||||
// hexadecimal string.
|
// hexadecimal string.
|
||||||
// @copyparams Dqn_Bin_U64ToHexU64String
|
// @copyparams Dqn_Bin_U64ToHexU64Str8
|
||||||
|
|
||||||
// @proc Dqn_Bin_HexBufferToU64
|
// @proc Dqn_Bin_HexBufferToU64
|
||||||
// @desc Convert a hexadecimal string a 64 bit value.
|
// @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`.
|
// be greater than `dest_size`.
|
||||||
|
|
||||||
// @proc Dqn_Bin_HexToBytes
|
// @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
|
// @desc Unchecked variant of @see Dqn_Bin_HexBufferToBytes
|
||||||
//
|
//
|
||||||
// This function skips some string checks, it assumes the hex is a valid hex
|
// 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
|
// stream and that the arguments are valid e.g. no trimming or 0x prefix
|
||||||
// stripping is performed
|
// stripping is performed
|
||||||
|
|
||||||
// @proc Dqn_Bin_String
|
// @proc Dqn_Bin_Str8
|
||||||
// @desc String8 variant of @see Dqn_Bin_HexBufferToBytesUnchecked
|
// @desc Str8 variant of @see Dqn_Bin_HexBufferToBytesUnchecked
|
||||||
|
|
||||||
// @proc Dqn_Bin_HexBufferToBytesArena
|
// @proc Dqn_Bin_HexBufferToBytesArena
|
||||||
// Dynamic allocating variant of @see Dqn_Bin_HexBufferToBytesUnchecked
|
// 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.
|
// @return The byte representation of the hex string.
|
||||||
|
|
||||||
struct Dqn_BinHexU64String
|
struct Dqn_BinHexU64Str8
|
||||||
{
|
{
|
||||||
char data[2 /*0x*/ + 16 /*hex*/ + 1 /*null-terminator*/];
|
char data[2 /*0x*/ + 16 /*hex*/ + 1 /*null-terminator*/];
|
||||||
uint8_t size;
|
uint8_t size;
|
||||||
};
|
};
|
||||||
|
|
||||||
enum Dqn_BinHexU64StringFlags
|
enum Dqn_BinHexU64Str8Flags
|
||||||
{
|
{
|
||||||
Dqn_BinHexU64StringFlags_No0xPrefix = 1 << 0, /// Remove the 0x prefix from the string
|
Dqn_BinHexU64Str8Flags_No0xPrefix = 1 << 0, /// Remove the 0x prefix from the string
|
||||||
Dqn_BinHexU64StringFlags_UppercaseHex = 1 << 1, /// Use uppercase ascii characters for hex
|
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 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_BinHexU64Str8 Dqn_Bin_U64ToHexU64Str8 (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_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_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 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);
|
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 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 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_HexToBytesUnchecked (Dqn_Str8 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_usize Dqn_Bin_HexToBytes (Dqn_Str8 hex, void *dest, Dqn_usize dest_size);
|
||||||
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);
|
||||||
#endif // !defined(DQN_NO_BIN)
|
#endif // !defined(DQN_NO_BIN)
|
||||||
|
|
||||||
// NOTE: [$BSEA] Dqn_BinarySearch ==================================================================
|
// NOTE: [$BSEA] Dqn_BinarySearch ==================================================================
|
||||||
@ -220,17 +242,26 @@ template <typename T>
|
|||||||
using Dqn_BinarySearchLessThanProc = bool(T const &lhs, T const &rhs);
|
using Dqn_BinarySearchLessThanProc = bool(T const &lhs, T const &rhs);
|
||||||
|
|
||||||
template <typename T>
|
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
|
enum Dqn_BinarySearchType
|
||||||
{
|
{
|
||||||
/// Index of the match. If no match is found, found is set to false and the
|
// Index of the match. If no match is found, found is set to false and the
|
||||||
/// index is set to 0
|
// 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,
|
Dqn_BinarySearchType_Match,
|
||||||
|
|
||||||
/// Index after the match. If no match is found, found is set to false and
|
// Index of the first element in the array that is `<= find`. If no such
|
||||||
/// the index is set to one past the closest match.
|
// item is found or the array is empty, then, the index is set to the array
|
||||||
Dqn_BinarySearchType_OnePastMatch,
|
// 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
|
struct Dqn_BinarySearchResult
|
||||||
@ -240,15 +271,14 @@ struct Dqn_BinarySearchResult
|
|||||||
};
|
};
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
Dqn_BinarySearchResult
|
Dqn_BinarySearchResult Dqn_BinarySearch(T const *array,
|
||||||
Dqn_BinarySearch(T const *array,
|
Dqn_usize array_size,
|
||||||
Dqn_usize array_size,
|
T const &find,
|
||||||
T const &find,
|
Dqn_BinarySearchType type = Dqn_BinarySearchType_Match,
|
||||||
Dqn_BinarySearchType type = Dqn_BinarySearchType_Match,
|
Dqn_BinarySearchLessThanProc<T> less_than = Dqn_BinarySearch_DefaultLessThan);
|
||||||
Dqn_BinarySearchLessThanProc<T> less_than = Dqn_BinarySearch_DefaultLessThan);
|
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
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)
|
||||||
{
|
{
|
||||||
bool result = lhs < rhs;
|
bool result = lhs < rhs;
|
||||||
return result;
|
return result;
|
||||||
@ -256,37 +286,47 @@ template <typename T> DQN_FORCE_INLINE bool Dqn_BinarySearch_DefaultLessThan(T c
|
|||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
Dqn_BinarySearchResult
|
Dqn_BinarySearchResult
|
||||||
Dqn_BinarySearch(T const *array,
|
Dqn_BinarySearch(T const *array,
|
||||||
Dqn_usize array_size,
|
Dqn_usize array_size,
|
||||||
T const &find,
|
T const &find,
|
||||||
Dqn_BinarySearchType type,
|
Dqn_BinarySearchType type,
|
||||||
Dqn_BinarySearchLessThanProc<T> less_than)
|
Dqn_BinarySearchLessThanProc<T> less_than)
|
||||||
{
|
{
|
||||||
Dqn_BinarySearchResult result = {};
|
Dqn_BinarySearchResult result = {};
|
||||||
Dqn_usize head = 0;
|
if (!array || array_size <= 0)
|
||||||
Dqn_usize tail = array_size - 1;
|
return result;
|
||||||
if (array && array_size > 0) {
|
|
||||||
while (!result.found && head <= tail) {
|
T const *end = array + array_size;
|
||||||
Dqn_usize mid = (head + tail) / 2;
|
T const *first = array;
|
||||||
T const &value = array[mid];
|
T const *last = end;
|
||||||
if (less_than(find, value)) {
|
while (first != last) {
|
||||||
tail = mid - 1;
|
Dqn_usize count = last - first;
|
||||||
if (mid == 0)
|
T const *it = first + (count / 2);
|
||||||
break;
|
|
||||||
} else if (less_than(value, find)) {
|
bool advance_first = false;
|
||||||
head = mid + 1;
|
if (type == Dqn_BinarySearchType_UpperBound)
|
||||||
} else {
|
advance_first = !less_than(find, it[0]);
|
||||||
result.found = true;
|
else
|
||||||
result.index = mid;
|
advance_first = less_than(it[0], find);
|
||||||
}
|
|
||||||
}
|
if (advance_first)
|
||||||
|
first = it + 1;
|
||||||
|
else
|
||||||
|
last = it;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (type == Dqn_BinarySearchType_OnePastMatch)
|
switch (type) {
|
||||||
result.index = result.found ? result.index + 1 : tail + 1;
|
case Dqn_BinarySearchType_Match: {
|
||||||
else
|
result.found = first != end && !less_than(find, *first);
|
||||||
DQN_ASSERT(type == Dqn_BinarySearchType_Match);
|
} break;
|
||||||
|
|
||||||
|
case Dqn_BinarySearchType_LowerBound: /*FALLTHRU*/
|
||||||
|
case Dqn_BinarySearchType_UpperBound: {
|
||||||
|
result.found = first != end;
|
||||||
|
} break;
|
||||||
|
}
|
||||||
|
|
||||||
|
result.index = first - array;
|
||||||
return result;
|
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
|
// @return The size of the string written to the buffer *not* including the
|
||||||
// null-terminator.
|
// null-terminator.
|
||||||
//
|
//
|
||||||
// @proc Dqn_U64ToString
|
// @proc Dqn_U64ToStr8
|
||||||
// @desc Convert a 64 bit unsigned value to its string representation.
|
// @desc Convert a 64 bit unsigned value to its string representation.
|
||||||
// @param[in] val Value to convert into a string
|
// @param[in] val Value to convert into a string
|
||||||
// @param[in] separator The separator to insert every 3 digits. Set this to
|
// @param[in] separator The separator to insert every 3 digits. Set this to
|
||||||
// 0 if no separator is desired.
|
// 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
|
char data[27+1]; // NOTE(dqn): 27 is the maximum size of uint64_t including a separtor
|
||||||
uint8_t size;
|
uint8_t size;
|
||||||
};
|
};
|
||||||
|
|
||||||
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, ...);
|
||||||
DQN_API Dqn_U64String Dqn_U64ToString (uint64_t val, char separator);
|
DQN_API Dqn_U64Str8 Dqn_U64ToStr8 (uint64_t val, char separator);
|
||||||
|
|
||||||
#if !defined(DQN_NO_PROFILER)
|
#if !defined(DQN_NO_PROFILER)
|
||||||
// NOTE: [$PROF] Dqn_Profiler ======================================================================
|
// NOTE: [$PROF] Dqn_Profiler ======================================================================
|
||||||
@ -524,29 +564,29 @@ struct Dqn_ProfilerAnchor
|
|||||||
// time spent in children functions that we call that are also being
|
// time spent in children functions that we call that are also being
|
||||||
// profiled. If we recursively call into ourselves, the time we spent in
|
// profiled. If we recursively call into ourselves, the time we spent in
|
||||||
// our function is accumulated.
|
// our function is accumulated.
|
||||||
uint64_t tsc_inclusive;
|
uint64_t tsc_inclusive;
|
||||||
uint64_t tsc_exclusive;
|
uint64_t tsc_exclusive;
|
||||||
uint16_t hit_count;
|
uint16_t hit_count;
|
||||||
Dqn_String8 name;
|
Dqn_Str8 name;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Dqn_ProfilerZone
|
struct Dqn_ProfilerZone
|
||||||
{
|
{
|
||||||
uint16_t anchor_index;
|
uint16_t anchor_index;
|
||||||
uint64_t begin_tsc;
|
uint64_t begin_tsc;
|
||||||
uint16_t parent_zone;
|
uint16_t parent_zone;
|
||||||
uint64_t elapsed_tsc_at_zone_start;
|
uint64_t elapsed_tsc_at_zone_start;
|
||||||
};
|
};
|
||||||
|
|
||||||
#if defined(__cplusplus)
|
#if defined(__cplusplus)
|
||||||
struct Dqn_ProfilerZoneScope
|
struct Dqn_ProfilerZoneScope
|
||||||
{
|
{
|
||||||
Dqn_ProfilerZoneScope(Dqn_String8 name, uint16_t anchor_index);
|
Dqn_ProfilerZoneScope(Dqn_Str8 name, uint16_t anchor_index);
|
||||||
~Dqn_ProfilerZoneScope();
|
~Dqn_ProfilerZoneScope();
|
||||||
Dqn_ProfilerZone zone;
|
Dqn_ProfilerZone zone;
|
||||||
};
|
};
|
||||||
#define Dqn_Profiler_ZoneScope(name) auto DQN_UNIQUE_NAME(profile_zone_) = Dqn_ProfilerZoneScope(DQN_STRING8(name), __COUNTER__ + 1)
|
#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_STRING8(name), anchor_index)
|
#define Dqn_Profiler_ZoneScopeWithIndex(name, anchor_index) auto DQN_UNIQUE_NAME(profile_zone_) = Dqn_ProfilerZoneScope(DQN_STR8(name), anchor_index)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
enum Dqn_ProfilerAnchorBuffer
|
enum Dqn_ProfilerAnchorBuffer
|
||||||
@ -566,10 +606,10 @@ struct Dqn_Profiler
|
|||||||
#define Dqn_Profiler_BeginZone(name) Dqn_Profiler_BeginZoneWithIndex(DQN_STRING8(name), __COUNTER__ + 1)
|
#define Dqn_Profiler_BeginZone(name) Dqn_Profiler_BeginZoneWithIndex(DQN_STRING8(name), __COUNTER__ + 1)
|
||||||
|
|
||||||
// NOTE: API =======================================================================================
|
// 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);
|
void Dqn_Profiler_EndZone (Dqn_ProfilerZone zone);
|
||||||
Dqn_ProfilerAnchor *Dqn_Profiler_AnchorBuffer (Dqn_ProfilerAnchorBuffer buffer);
|
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);
|
void Dqn_Profiler_Dump (uint64_t tsc_per_second);
|
||||||
#endif // !defined(DQN_NO_PROFILER)
|
#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`
|
bool lib_init; // True if the library has been initialised via `Dqn_Library_Init`
|
||||||
Dqn_TicketMutex lib_mutex;
|
Dqn_TicketMutex lib_mutex;
|
||||||
Dqn_String8 exe_dir; // The directory of the current executable
|
Dqn_Str8 exe_dir; // The directory of the current executable
|
||||||
|
|
||||||
Dqn_Arena arena;
|
Dqn_Arena arena;
|
||||||
Dqn_ArenaCatalog arena_catalog;
|
Dqn_ArenaCatalog arena_catalog;
|
||||||
@ -642,12 +682,18 @@ struct Dqn_Library
|
|||||||
#endif
|
#endif
|
||||||
} extern *g_dqn_library;
|
} extern *g_dqn_library;
|
||||||
|
|
||||||
|
enum Dqn_LibraryOnInit
|
||||||
|
{
|
||||||
|
Dqn_LibraryOnInit_Nil,
|
||||||
|
Dqn_LibraryOnInit_LogFeatures,
|
||||||
|
};
|
||||||
|
|
||||||
// NOTE: API =======================================================================================
|
// 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);
|
DQN_API void Dqn_Library_SetPointer (Dqn_Library *library);
|
||||||
#if !defined(DQN_NO_PROFILER)
|
#if !defined(DQN_NO_PROFILER)
|
||||||
DQN_API void Dqn_Library_SetProfiler (Dqn_Profiler *profiler);
|
DQN_API void Dqn_Library_SetProfiler (Dqn_Profiler *profiler);
|
||||||
#endif
|
#endif
|
||||||
DQN_API void Dqn_Library_SetLogCallback (Dqn_LogProc *proc, void *user_data);
|
DQN_API void Dqn_Library_SetLogCallback (Dqn_LogProc *proc, void *user_data);
|
||||||
DQN_API void Dqn_Library_DumpThreadContextArenaStat(Dqn_String8 file_path);
|
DQN_API void Dqn_Library_DumpThreadContextArenaStat(Dqn_Str8 file_path);
|
||||||
|
|
||||||
|
332
dqn_math.cpp
332
dqn_math.cpp
@ -43,6 +43,12 @@ DQN_API Dqn_V2I operator-(Dqn_V2I lhs, Dqn_V2I rhs)
|
|||||||
return result;
|
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_API Dqn_V2I operator+(Dqn_V2I lhs, Dqn_V2I rhs)
|
||||||
{
|
{
|
||||||
Dqn_V2I result = Dqn_V2I_InitNx2(lhs.x + rhs.x, lhs.y + rhs.y);
|
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;
|
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_API Dqn_V2 operator+(Dqn_V2 lhs, Dqn_V2 rhs)
|
||||||
{
|
{
|
||||||
Dqn_V2 result = Dqn_V2_InitNx2(lhs.x + rhs.x, lhs.y + rhs.y);
|
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;
|
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)
|
DQN_API Dqn_V2 &operator+=(Dqn_V2 &lhs, Dqn_V2 rhs)
|
||||||
{
|
{
|
||||||
lhs = lhs + rhs;
|
lhs = lhs + rhs;
|
||||||
return lhs;
|
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_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));
|
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)
|
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);
|
Dqn_f32 result = (a.x * b.x) + (a.y * b.y);
|
||||||
return result;
|
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;
|
// NOTE: Pythagoras's theorem (a^2 + b^2 = c^2) without the square root
|
||||||
Dqn_f32 y_side = b.y - a.y;
|
Dqn_f32 a = rhs.x - lhs.x;
|
||||||
Dqn_f32 result = DQN_SQUARED(x_side) + DQN_SQUARED(y_side);
|
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;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
DQN_API Dqn_V2 Dqn_V2_Normalise(Dqn_V2 a)
|
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_V2_Length(a);
|
||||||
Dqn_f32 length = DQN_SQRTF(length_sq);
|
Dqn_V2 result = a / length;
|
||||||
Dqn_V2 result = a / length;
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
DQN_API Dqn_V2 Dqn_V2_Perpendicular(Dqn_V2 a)
|
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);
|
Dqn_V2 result = Dqn_V2_InitNx2(-a.y, a.x);
|
||||||
return result;
|
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)
|
#endif // !defined(DQN_NO_V2)
|
||||||
|
|
||||||
#if !defined(DQN_NO_V3)
|
#if !defined(DQN_NO_V3)
|
||||||
@ -502,6 +621,12 @@ DQN_API Dqn_V3 operator-(Dqn_V3 lhs, Dqn_V3 rhs)
|
|||||||
return result;
|
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_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);
|
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;
|
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_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);
|
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;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if !defined(DQN_NO_FSTRING8)
|
#if !defined(DQN_NO_FSTR8)
|
||||||
DQN_API Dqn_FString8<256> Dqn_M4_ColumnMajorString(Dqn_M4 mat)
|
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 row = 0; row < 4; row++) {
|
||||||
for (int it = 0; it < 4; it++) {
|
for (int it = 0; it < 4; it++) {
|
||||||
if (it == 0) Dqn_FString8_Append(&result, DQN_STRING8("|"));
|
if (it == 0) Dqn_FStr8_Append(&result, DQN_STR8("|"));
|
||||||
Dqn_FString8_AppendF(&result, "%.5f", mat.columns[it][row]);
|
Dqn_FStr8_AppendF(&result, "%.5f", mat.columns[it][row]);
|
||||||
if (it != 3) Dqn_FString8_Append(&result, DQN_STRING8(", "));
|
if (it != 3) Dqn_FStr8_Append(&result, DQN_STR8(", "));
|
||||||
else Dqn_FString8_Append(&result, DQN_STRING8("|\n"));
|
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
|
||||||
#endif // !defined(DQN_M4)
|
#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)
|
#if !defined(DQN_NO_RECT)
|
||||||
// NOTE: [$RECT] Dqn_Rect ==========================================================================
|
// NOTE: [$RECT] Dqn_Rect ==========================================================================
|
||||||
DQN_API bool operator==(const Dqn_Rect& lhs, const Dqn_Rect& rhs)
|
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;
|
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_API bool Dqn_Rect_Intersects(Dqn_Rect a, Dqn_Rect b)
|
||||||
{
|
{
|
||||||
Dqn_V2 a_min = a.pos;
|
Dqn_V2 a_min = a.pos;
|
||||||
@ -1062,6 +1297,12 @@ DQN_API Dqn_RectMinMax Dqn_Rect_MinMax(Dqn_Rect a)
|
|||||||
return result;
|
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_API Dqn_Rect Dqn_Rect_CutLeftClip(Dqn_Rect *rect, Dqn_f32 amount, Dqn_RectCutClip clip)
|
||||||
{
|
{
|
||||||
Dqn_f32 min_x = rect->pos.x;
|
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;
|
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)
|
#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 =============================================================================
|
// NOTE: [$MATH] Other =============================================================================
|
||||||
DQN_API Dqn_V2 Dqn_Lerp_V2(Dqn_V2 a, Dqn_f32 t, Dqn_V2 b)
|
DQN_API Dqn_V2 Dqn_Lerp_V2(Dqn_V2 a, Dqn_f32 t, Dqn_V2 b)
|
||||||
{
|
{
|
||||||
|
140
dqn_math.h
140
dqn_math.h
@ -10,8 +10,9 @@ union Dqn_V2I
|
|||||||
int32_t data[2];
|
int32_t data[2];
|
||||||
};
|
};
|
||||||
|
|
||||||
#define Dqn_V2I_InitNx1(x) DQN_LITERAL(Dqn_V2I){{(int32_t)(x), (int32_t)(x)}}
|
#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_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);
|
||||||
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 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_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_V2I rhs);
|
DQN_API Dqn_V2I operator* (Dqn_V2I lhs, Dqn_V2I rhs);
|
||||||
DQN_API Dqn_V2I operator* (Dqn_V2I lhs, Dqn_f32 rhs);
|
DQN_API Dqn_V2I operator* (Dqn_V2I lhs, Dqn_f32 rhs);
|
||||||
@ -76,8 +78,11 @@ union Dqn_V2
|
|||||||
Dqn_f32 data[2];
|
Dqn_f32 data[2];
|
||||||
};
|
};
|
||||||
|
|
||||||
#define Dqn_V2_InitNx1(x) DQN_LITERAL(Dqn_V2){{(Dqn_f32)(x), (Dqn_f32)(x)}}
|
#define Dqn_V2_Zero DQN_LITERAL(Dqn_V2){{(Dqn_f32)(0), (Dqn_f32)(0)}}
|
||||||
#define Dqn_V2_InitNx2(x, y) DQN_LITERAL(Dqn_V2){{(Dqn_f32)(x), (Dqn_f32)(y)}}
|
#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);
|
||||||
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 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_V2 rhs);
|
||||||
DQN_API Dqn_V2 operator- (Dqn_V2 lhs, Dqn_f32 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_V2 rhs);
|
||||||
DQN_API Dqn_V2 operator+ (Dqn_V2 lhs, Dqn_f32 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_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, Dqn_f32 rhs);
|
||||||
DQN_API Dqn_V2 &operator/=(Dqn_V2& lhs, int32_t 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_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_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_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_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_Max (Dqn_V2 a, Dqn_V2 b);
|
||||||
DQN_API Dqn_V2 Dqn_V2_Abs(Dqn_V2 a);
|
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_Dot (Dqn_V2 a, Dqn_V2 b);
|
||||||
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_API Dqn_V2 Dqn_V2_Normalise(Dqn_V2 a);
|
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_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)
|
#endif // !defined(DQN_NO_V2)
|
||||||
|
|
||||||
#if !defined(DQN_NO_V3)
|
#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 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_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_V3 rhs);
|
DQN_API Dqn_V3 operator* (Dqn_V3 lhs, Dqn_V3 rhs);
|
||||||
DQN_API Dqn_V3 operator* (Dqn_V3 lhs, Dqn_f32 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; };
|
struct { Dqn_f32 r, g, b, a; };
|
||||||
#if !defined(DQN_NO_V3)
|
#if !defined(DQN_NO_V3)
|
||||||
Dqn_V3 rgb;
|
Dqn_V3 rgb;
|
||||||
|
Dqn_V3 xyz;
|
||||||
#endif
|
#endif
|
||||||
Dqn_f32 data[4];
|
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_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_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);
|
DQN_API bool operator!=(Dqn_V4 lhs, Dqn_V4 rhs);
|
||||||
bool operator==(Dqn_V4 lhs, Dqn_V4 rhs);
|
DQN_API bool operator==(Dqn_V4 lhs, Dqn_V4 rhs);
|
||||||
bool operator>=(Dqn_V4 lhs, Dqn_V4 rhs);
|
DQN_API bool operator>=(Dqn_V4 lhs, Dqn_V4 rhs);
|
||||||
bool operator<=(Dqn_V4 lhs, Dqn_V4 rhs);
|
DQN_API bool operator<=(Dqn_V4 lhs, Dqn_V4 rhs);
|
||||||
bool operator< (Dqn_V4 lhs, Dqn_V4 rhs);
|
DQN_API bool operator< (Dqn_V4 lhs, Dqn_V4 rhs);
|
||||||
bool operator> (Dqn_V4 lhs, Dqn_V4 rhs);
|
DQN_API bool operator> (Dqn_V4 lhs, Dqn_V4 rhs);
|
||||||
Dqn_V4 operator- (Dqn_V4 lhs, Dqn_V4 rhs);
|
DQN_API Dqn_V4 operator- (Dqn_V4 lhs, Dqn_V4 rhs);
|
||||||
Dqn_V4 operator+ (Dqn_V4 lhs, Dqn_V4 rhs);
|
DQN_API Dqn_V4 operator- (Dqn_V4 lhs);
|
||||||
Dqn_V4 operator* (Dqn_V4 lhs, Dqn_V4 rhs);
|
DQN_API Dqn_V4 operator+ (Dqn_V4 lhs, Dqn_V4 rhs);
|
||||||
Dqn_V4 operator* (Dqn_V4 lhs, Dqn_f32 rhs);
|
DQN_API Dqn_V4 operator* (Dqn_V4 lhs, Dqn_V4 rhs);
|
||||||
Dqn_V4 operator* (Dqn_V4 lhs, int32_t rhs);
|
DQN_API Dqn_V4 operator* (Dqn_V4 lhs, Dqn_f32 rhs);
|
||||||
Dqn_V4 operator/ (Dqn_V4 lhs, Dqn_f32 rhs);
|
DQN_API Dqn_V4 operator* (Dqn_V4 lhs, int32_t rhs);
|
||||||
Dqn_V4 &operator*=(Dqn_V4 &lhs, Dqn_V4 rhs);
|
DQN_API Dqn_V4 operator/ (Dqn_V4 lhs, Dqn_f32 rhs);
|
||||||
Dqn_V4 &operator*=(Dqn_V4 &lhs, Dqn_f32 rhs);
|
DQN_API Dqn_V4 &operator*=(Dqn_V4 &lhs, Dqn_V4 rhs);
|
||||||
Dqn_V4 &operator*=(Dqn_V4 &lhs, int32_t rhs);
|
DQN_API Dqn_V4 &operator*=(Dqn_V4 &lhs, Dqn_f32 rhs);
|
||||||
Dqn_V4 &operator-=(Dqn_V4 &lhs, Dqn_V4 rhs);
|
DQN_API Dqn_V4 &operator*=(Dqn_V4 &lhs, int32_t rhs);
|
||||||
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_V4 rhs);
|
||||||
#endif // !defined(DQN_NO_V4)
|
#endif // !defined(DQN_NO_V4)
|
||||||
|
|
||||||
#if !defined(DQN_NO_M4)
|
#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_MulF(Dqn_M4 lhs, Dqn_f32 rhs);
|
||||||
DQN_API Dqn_M4 Dqn_M4_DivF(Dqn_M4 lhs, Dqn_f32 rhs);
|
DQN_API Dqn_M4 Dqn_M4_DivF(Dqn_M4 lhs, Dqn_f32 rhs);
|
||||||
|
|
||||||
#if !defined(DQN_NO_FSTRING8)
|
#if !defined(DQN_NO_FSTR8)
|
||||||
DQN_API Dqn_FString8<256> Dqn_M4_ColumnMajorString(Dqn_M4 mat);
|
DQN_API Dqn_FStr8<256> Dqn_M4_ColumnMajorString(Dqn_M4 mat);
|
||||||
#endif
|
#endif
|
||||||
#endif // !defined(DQN_M4)
|
#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 ==========================================================================
|
// NOTE: [$RECT] Dqn_Rect ==========================================================================
|
||||||
#if !defined(DQN_NO_RECT)
|
#if !defined(DQN_NO_RECT)
|
||||||
#if defined(DQN_NO_V2)
|
#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_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}}}
|
#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 bool operator== (const Dqn_Rect& lhs, const Dqn_Rect& rhs);
|
||||||
DQN_API Dqn_V2 Dqn_Rect_Center (Dqn_Rect rect);
|
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_ContainsPoint (Dqn_Rect rect, Dqn_V2 p);
|
||||||
DQN_API bool Dqn_Rect_ContainsRect (Dqn_Rect a, Dqn_Rect b);
|
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_Expand (Dqn_Rect a, Dqn_f32 amount);
|
||||||
DQN_API Dqn_Rect Dqn_Rect_Intersection (Dqn_Rect a, Dqn_Rect b);
|
DQN_API Dqn_Rect Dqn_Rect_ExpandV2 (Dqn_Rect a, Dqn_V2 amount);
|
||||||
DQN_API Dqn_Rect Dqn_Rect_Union (Dqn_Rect a, Dqn_Rect b);
|
DQN_API bool Dqn_Rect_Intersects (Dqn_Rect a, Dqn_Rect b);
|
||||||
DQN_API Dqn_RectMinMax Dqn_Rect_MinMax (Dqn_Rect a);
|
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
|
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);
|
DQN_API Dqn_Rect Dqn_RectCut_Cut(Dqn_RectCut rect_cut, Dqn_V2 size, Dqn_RectCutClip clip);
|
||||||
#endif // !defined(DQN_NO_RECT)
|
#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 =============================================================================
|
// NOTE: [$MATH] Other =============================================================================
|
||||||
DQN_API Dqn_V2 Dqn_Lerp_V2(Dqn_V2 a, Dqn_f32 t, Dqn_V2 b);
|
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);
|
DQN_API Dqn_f32 Dqn_Lerp_F32(Dqn_f32 a, Dqn_f32 t, Dqn_f32 b);
|
||||||
|
133
dqn_memory.cpp
133
dqn_memory.cpp
@ -1,3 +1,4 @@
|
|||||||
|
#if !defined(DQN_PLATFORM_EMSCRIPTEN)
|
||||||
// NOTE: [$VMEM] Dqn_VMem ==========================================================================
|
// NOTE: [$VMEM] Dqn_VMem ==========================================================================
|
||||||
DQN_FILE_SCOPE uint32_t Dqn_VMem_ConvertPageToOSFlags_(uint32_t protect)
|
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)
|
if (!ptr || size == 0)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
static Dqn_String8 const ALIGNMENT_ERROR_MSG =
|
static Dqn_Str8 const ALIGNMENT_ERROR_MSG =
|
||||||
DQN_STRING8("Page protection requires pointers to be page aligned because we "
|
DQN_STR8("Page protection requires pointers to be page aligned because we "
|
||||||
"can only guard memory at a multiple of the page boundary.");
|
"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(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);
|
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
|
#else
|
||||||
Dqn_ThreadScratch scratch = Dqn_Thread_GetScratch(nullptr);
|
Dqn_ThreadScratch scratch = Dqn_Thread_GetScratch(nullptr);
|
||||||
Dqn_WinError error = Dqn_Win_LastError(scratch.arena);
|
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
|
#endif
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
@ -142,6 +143,48 @@ DQN_API int Dqn_VMem_Protect(void *ptr, Dqn_usize size, uint32_t page_flags)
|
|||||||
|
|
||||||
return result;
|
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 ======================================================================
|
// NOTE: [$MEMB] Dqn_MemBlock ======================================================================
|
||||||
DQN_API Dqn_MemBlockSizeRequiredResult Dqn_MemBlock_SizeRequired(Dqn_MemBlock const *block, Dqn_usize size, uint8_t alignment, uint32_t flags)
|
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;
|
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 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);
|
Dqn_usize alignment = DQN_ASAN_POISON ? DQN_ASAN_POISON_ALIGNMENT : alignof(Dqn_MemBlock);
|
||||||
@ -184,7 +227,7 @@ Dqn_usize Dqn_MemBlock_MetadataSize()
|
|||||||
return result;
|
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(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");
|
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
|
// 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;
|
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) {
|
if (result) {
|
||||||
// NOTE: Commit pages if we did not commit on the initial range.
|
// NOTE: Commit pages if we did not commit on the initial range.
|
||||||
if (!commit_on_reserve)
|
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->mem_api = mem_api;
|
||||||
result->size = reserve_aligned - metadata_size;
|
result->data = DQN_CAST(uint8_t *)result + metadata_size;
|
||||||
result->commit = commit_aligned - metadata_size;
|
result->size = reserve_aligned - metadata_size;
|
||||||
result->flags = DQN_CAST(uint8_t)flags;
|
result->commit = commit_aligned - metadata_size;
|
||||||
|
result->flags = DQN_CAST(uint8_t)flags;
|
||||||
|
|
||||||
// NOTE: Poison (guard page + commit). We do *not* poison the entire
|
// NOTE: Poison (guard page + commit). We do *not* poison the entire
|
||||||
// block, only the commit pages. Since we may reserve large amounts of
|
// 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;
|
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_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);
|
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)
|
if (new_used > block->size)
|
||||||
return result;
|
return result;
|
||||||
|
|
||||||
result = DQN_CAST(char *)block->data + size_required.data_offset;
|
result = DQN_CAST(char *)block->data + size_required.data_offset;
|
||||||
block->used = new_used;
|
block->used = new_used;
|
||||||
|
block->used_hwm = DQN_MAX(block->used_hwm, new_used);
|
||||||
DQN_ASSERT(Dqn_IsPowerOfTwoAligned(result, alignment));
|
DQN_ASSERT(Dqn_IsPowerOfTwoAligned(result, alignment));
|
||||||
|
|
||||||
if (DQN_ASAN_POISON)
|
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);
|
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);
|
void *commit_ptr = (void *)Dqn_AlignUpPowerOfTwo((char *)block->data + block->commit, g_dqn_library->os_page_size);
|
||||||
block->commit += commit_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);
|
DQN_ASSERT(block->commit <= block->size);
|
||||||
|
|
||||||
if (DQN_ASAN_POISON) { // NOTE: Poison newly committed pages that aren't being used.
|
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();
|
Dqn_usize release_size = block->size + Dqn_MemBlock_MetadataSize();
|
||||||
if (DQN_ASAN_POISON)
|
if (DQN_ASAN_POISON)
|
||||||
Dqn_ASAN_UnpoisonMemoryRegion(block, release_size);
|
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)
|
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)
|
if (arena->allocs_are_allowed_to_leak)
|
||||||
mem_block_flags |= Dqn_MemBlockFlag_AllocRecordLeakPermitted;
|
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 (result) {
|
||||||
if (!arena->head)
|
if (!arena->head)
|
||||||
arena->head = result;
|
arena->head = result;
|
||||||
@ -475,29 +534,19 @@ Dqn_ArenaTempMemoryScope::~Dqn_ArenaTempMemoryScope()
|
|||||||
Dqn_Arena_EndTempMemory(temp_memory, cancel);
|
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
|
Dqn_ArenaInfo result = {};
|
||||||
// stb sprintf that GCC warns about as an error. This pragma mutes that.
|
if (!arena)
|
||||||
DQN_GCC_WARNING_PUSH
|
return result;
|
||||||
DQN_GCC_WARNING_DISABLE("-Wformat-invalid-specifier")
|
|
||||||
DQN_GCC_WARNING_DISABLE("-Wformat-extra-args")
|
for (Dqn_MemBlock const *block = arena->head; block; block = block->next) {
|
||||||
Dqn_ArenaStatString result = {};
|
result.capacity += block->size;
|
||||||
int size16 = STB_SPRINTF_DECORATE(snprintf)(result.data, DQN_ARRAY_ICOUNT(result.data),
|
result.used += block->used;
|
||||||
"ArenaStat{"
|
result.used_hwm += block->used_hwm;
|
||||||
"used/hwm=%_$$zd/%_$$zd, "
|
result.commit += block->commit;
|
||||||
"cap/hwm=%_$$zd/%_$$zd, "
|
result.wasted += block->next ? (block->size - block->used) : 0;
|
||||||
"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
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -541,14 +590,14 @@ DQN_API Dqn_Arena *Dqn_ArenaCatalog_Alloc(Dqn_ArenaCatalog *catalog, Dqn_usize b
|
|||||||
return result;
|
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);
|
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;
|
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_list args;
|
||||||
va_start(args, fmt);
|
va_start(args, fmt);
|
||||||
|
88
dqn_memory.h
88
dqn_memory.h
@ -33,11 +33,32 @@ enum Dqn_VMemPage
|
|||||||
Dqn_VMemPage_AllocRecordLeakPermitted = 1 << 2,
|
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 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 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_Decommit(void *ptr, Dqn_usize size);
|
||||||
DQN_API void Dqn_VMem_Release (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);
|
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 ======================================================================
|
// NOTE: [$MEMB] Dqn_MemBlock ======================================================================
|
||||||
// Encapsulates allocation of objects from a raw block of memory by bumping a
|
// Encapsulates allocation of objects from a raw block of memory by bumping a
|
||||||
@ -103,8 +124,10 @@ enum Dqn_MemBlockFlag
|
|||||||
|
|
||||||
struct Dqn_MemBlock
|
struct Dqn_MemBlock
|
||||||
{
|
{
|
||||||
|
Dqn_MemAPI mem_api;
|
||||||
void *data;
|
void *data;
|
||||||
Dqn_usize used;
|
Dqn_usize used;
|
||||||
|
Dqn_usize used_hwm;
|
||||||
Dqn_usize size;
|
Dqn_usize size;
|
||||||
Dqn_usize commit;
|
Dqn_usize commit;
|
||||||
Dqn_MemBlock *next;
|
Dqn_MemBlock *next;
|
||||||
@ -130,13 +153,14 @@ struct Dqn_MemBlockSizeRequiredResult
|
|||||||
Dqn_usize block_size;
|
Dqn_usize block_size;
|
||||||
};
|
};
|
||||||
|
|
||||||
DQN_API Dqn_usize Dqn_MemBlock_MetadataSize(uint8_t flags);
|
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_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 Dqn_MemBlock * Dqn_MemBlock_InitMemAPI(Dqn_usize reserve, Dqn_usize commit, uint32_t flags, Dqn_MemAPI mem_functions);
|
||||||
DQN_API void * Dqn_MemBlock_Alloc (Dqn_MemBlock *block, Dqn_usize size, uint8_t alignment, Dqn_ZeroMem zero_mem);
|
DQN_API Dqn_MemBlock * Dqn_MemBlock_Init (Dqn_usize reserve, Dqn_usize commit, uint32_t flags);
|
||||||
DQN_API void Dqn_MemBlock_Free (Dqn_MemBlock *block);
|
DQN_API void * Dqn_MemBlock_Alloc (Dqn_MemBlock *block, Dqn_usize size, uint8_t alignment, Dqn_ZeroMem zero_mem);
|
||||||
DQN_API void Dqn_MemBlock_Pop (Dqn_MemBlock *block, Dqn_usize size);
|
DQN_API void Dqn_MemBlock_Free (Dqn_MemBlock *block);
|
||||||
DQN_API void Dqn_MemBlock_PopTo (Dqn_MemBlock *block, Dqn_usize to);
|
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_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)
|
#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
|
// @proc Dqn_Arena_EndTempMemory
|
||||||
// @desc End an allocation scope previously begun by calling begin scope.
|
// @desc End an allocation scope previously begun by calling begin scope.
|
||||||
|
struct Dqn_ArenaInfo
|
||||||
// @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
|
|
||||||
{
|
{
|
||||||
Dqn_usize capacity; // Total allocating capacity of the arena in bytes
|
Dqn_usize capacity; // Total allocating capacity of the arena in bytes
|
||||||
Dqn_usize used; // Total amount of bytes used in the arena
|
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
|
Dqn_usize commit; // Total amount of bytes committed in the arena
|
||||||
uint32_t blocks; // Number of memory blocks in the arena
|
Dqn_usize wasted; // Orphaned space in blocks due to allocations requiring more space than available in the active block
|
||||||
Dqn_usize syscalls; // Number of memory allocation syscalls into the OS
|
Dqn_usize used_hwm; // High-water mark for 'used'
|
||||||
|
|
||||||
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'
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Dqn_ArenaBlock
|
struct Dqn_ArenaBlock
|
||||||
@ -234,7 +244,7 @@ struct Dqn_ArenaBlock
|
|||||||
void *memory; // Backing memory of the block
|
void *memory; // Backing memory of the block
|
||||||
Dqn_usize size; // Size 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 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_usize commit; // Number of bytes in the block physically backed by pages
|
||||||
Dqn_ArenaBlock *prev; // Previous linked block
|
Dqn_ArenaBlock *prev; // Previous linked block
|
||||||
Dqn_ArenaBlock *next; // Next linked block
|
Dqn_ArenaBlock *next; // Next linked block
|
||||||
@ -249,12 +259,13 @@ struct Dqn_ArenaStatString
|
|||||||
|
|
||||||
struct Dqn_Arena
|
struct Dqn_Arena
|
||||||
{
|
{
|
||||||
bool allocs_are_allowed_to_leak;
|
Dqn_MemAPI mem_api;
|
||||||
Dqn_String8 label; // Optional label to describe the arena
|
bool allocs_are_allowed_to_leak;
|
||||||
Dqn_MemBlock *head; // Active block the arena is allocating from
|
Dqn_Str8 label; // Optional label to describe the arena
|
||||||
Dqn_MemBlock *curr; // Active block the arena is allocating from
|
Dqn_MemBlock *head; // Active block the arena is allocating from
|
||||||
Dqn_MemBlock *tail; // Last block in the linked list of blocks
|
Dqn_MemBlock *curr; // Active block the arena is allocating from
|
||||||
uint64_t blocks;
|
Dqn_MemBlock *tail; // Last block in the linked list of blocks
|
||||||
|
uint64_t blocks;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Dqn_ArenaTempMemory
|
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 Dqn_ArenaTempMemory Dqn_Arena_BeginTempMemory(Dqn_Arena *arena);
|
||||||
DQN_API void Dqn_Arena_EndTempMemory (Dqn_ArenaTempMemory temp_memory, bool cancel);
|
DQN_API void Dqn_Arena_EndTempMemory (Dqn_ArenaTempMemory temp_memory, bool cancel);
|
||||||
|
|
||||||
// NOTE: Arena Stats ===============================================================================
|
// NOTE: Arena Info ===============================================================================
|
||||||
DQN_API Dqn_ArenaStatString Dqn_Arena_StatString (Dqn_ArenaStat const *stat);
|
DQN_API Dqn_ArenaInfo Dqn_Arena_Info (Dqn_Arena const *arena);
|
||||||
DQN_API void Dqn_Arena_LogStats (Dqn_Arena const *arena);
|
|
||||||
|
|
||||||
// NOTE: [$ACAT] Dqn_ArenaCatalog ==================================================================
|
// NOTE: [$ACAT] Dqn_ArenaCatalog ==================================================================
|
||||||
struct Dqn_ArenaCatalogItem
|
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_Init (Dqn_ArenaCatalog *catalog, Dqn_Arena *arena);
|
||||||
DQN_API void Dqn_ArenaCatalog_Add (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_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_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, 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, ...);
|
||||||
|
136
dqn_os.cpp
Normal file
136
dqn_os.cpp
Normal 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
18
dqn_os.h
Normal 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);
|
580
dqn_platform.cpp
580
dqn_platform.cpp
File diff suppressed because it is too large
Load Diff
152
dqn_platform.h
152
dqn_platform.h
@ -4,7 +4,7 @@
|
|||||||
#endif
|
#endif
|
||||||
// NOTE: [$FSYS] Dqn_Fs ============================================================================
|
// NOTE: [$FSYS] Dqn_Fs ============================================================================
|
||||||
// NOTE: FS Manipulation ===========================================================================
|
// 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 =======================================================================================
|
// NOTE: API =======================================================================================
|
||||||
// @proc Dqn_FsDelete
|
// @proc Dqn_FsDelete
|
||||||
@ -29,26 +29,26 @@ struct Dqn_FsInfo
|
|||||||
uint64_t size;
|
uint64_t size;
|
||||||
};
|
};
|
||||||
|
|
||||||
DQN_API bool Dqn_Fs_Exists (Dqn_String8 path);
|
DQN_API bool Dqn_Fs_Exists (Dqn_Str8 path);
|
||||||
DQN_API bool Dqn_Fs_DirExists(Dqn_String8 path);
|
DQN_API bool Dqn_Fs_DirExists(Dqn_Str8 path);
|
||||||
DQN_API Dqn_FsInfo Dqn_Fs_GetInfo (Dqn_String8 path);
|
DQN_API Dqn_FsInfo Dqn_Fs_GetInfo (Dqn_Str8 path);
|
||||||
DQN_API bool Dqn_Fs_Copy (Dqn_String8 src, Dqn_String8 dest, bool overwrite);
|
DQN_API bool Dqn_Fs_Copy (Dqn_Str8 src, Dqn_Str8 dest, bool overwrite);
|
||||||
DQN_API bool Dqn_Fs_MakeDir (Dqn_String8 path);
|
DQN_API bool Dqn_Fs_MakeDir (Dqn_Str8 path);
|
||||||
DQN_API bool Dqn_Fs_Move (Dqn_String8 src, Dqn_String8 dest, bool overwrite);
|
DQN_API bool Dqn_Fs_Move (Dqn_Str8 src, Dqn_Str8 dest, bool overwrite);
|
||||||
DQN_API bool Dqn_Fs_Delete (Dqn_String8 path);
|
DQN_API bool Dqn_Fs_Delete (Dqn_Str8 path);
|
||||||
|
|
||||||
// NOTE: R/W Entire File ===========================================================================
|
// NOTE: R/W Entire File ===========================================================================
|
||||||
// NOTE: API =======================================================================================
|
// 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.
|
// @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.
|
// @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_WriteCStr8(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 bool Dqn_Fs_Write (Dqn_Str8 file_path, Dqn_Str8 buffer);
|
||||||
DQN_API char *Dqn_Fs_ReadCString8 (char const *path, Dqn_usize path_size, Dqn_usize *file_size, Dqn_Allocator allocator);
|
DQN_API char *Dqn_Fs_ReadCStr8 (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 Dqn_Str8 Dqn_Fs_Read (Dqn_Str8 path, Dqn_Allocator allocator);
|
||||||
|
|
||||||
// NOTE: R/W Stream API ============================================================================
|
// NOTE: R/W Stream API ============================================================================
|
||||||
// NOTE: API =======================================================================================
|
// NOTE: API =======================================================================================
|
||||||
@ -85,11 +85,11 @@ enum Dqn_FsFileAccess
|
|||||||
Dqn_FsFileAccess_All = Dqn_FsFileAccess_ReadWrite | Dqn_FsFileAccess_Execute,
|
Dqn_FsFileAccess_All = Dqn_FsFileAccess_ReadWrite | Dqn_FsFileAccess_Execute,
|
||||||
};
|
};
|
||||||
|
|
||||||
DQN_API Dqn_FsFile Dqn_Fs_OpenFile (Dqn_String8 path, Dqn_FsFileOpen open_mode, uint32_t access);
|
DQN_API Dqn_FsFile Dqn_Fs_OpenFile (Dqn_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_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_WriteFile (Dqn_FsFile *file, Dqn_Str8 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_WriteFileFV (Dqn_FsFile *file, DQN_FMT_ATTRIB 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_WriteFileF (Dqn_FsFile *file, DQN_FMT_ATTRIB char const *fmt, ...);
|
||||||
DQN_API void Dqn_Fs_CloseFile (Dqn_FsFile *file);
|
DQN_API void Dqn_Fs_CloseFile (Dqn_FsFile *file);
|
||||||
#endif // !defined(DQN_NO_FS)
|
#endif // !defined(DQN_NO_FS)
|
||||||
|
|
||||||
@ -124,16 +124,17 @@ DQN_API void Dqn_Fs_CloseFile (Dqn_FsFile *file);
|
|||||||
#else
|
#else
|
||||||
#define Dqn_FsPathOSSeperator "/"
|
#define Dqn_FsPathOSSeperator "/"
|
||||||
#endif
|
#endif
|
||||||
#define Dqn_FsPathOSSeperatorString DQN_STRING8(Dqn_FsPathOSSeperator)
|
#define Dqn_FsPathOSSeperatorString DQN_STR8(Dqn_FsPathOSSeperator)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
struct Dqn_FsPathLink
|
struct Dqn_FsPathLink
|
||||||
{
|
{
|
||||||
Dqn_String8 string;
|
Dqn_Str8 string;
|
||||||
Dqn_FsPathLink *next;
|
Dqn_FsPathLink *next;
|
||||||
Dqn_FsPathLink *prev;
|
Dqn_FsPathLink *prev;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
struct Dqn_FsPath
|
struct Dqn_FsPath
|
||||||
{
|
{
|
||||||
Dqn_FsPathLink *head;
|
Dqn_FsPathLink *head;
|
||||||
@ -142,15 +143,15 @@ struct Dqn_FsPath
|
|||||||
uint16_t links_size;
|
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_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_String8 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_STRING_ANNOTATE char const *fmt, ...);
|
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 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_Str8 Dqn_FsPath_BuildWithSeparator(Dqn_Arena *arena, Dqn_FsPath const *fs_path, Dqn_Str8 path_separator);
|
||||||
DQN_API Dqn_String8 Dqn_FsPath_Convert (Dqn_Arena *arena, Dqn_String8 path);
|
DQN_API Dqn_Str8 Dqn_FsPath_Convert (Dqn_Arena *arena, Dqn_Str8 path);
|
||||||
DQN_API Dqn_String8 Dqn_FsPath_ConvertF (Dqn_Arena *arena, DQN_FMT_STRING_ANNOTATE char const *fmt, ...);
|
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_STRING8("/"))
|
#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_STRING8("\\"))
|
#define Dqn_FsPath_BuildBackSlash(arena, fs_path) Dqn_FsPath_BuildWithSeparator(arena, fs_path, DQN_STR8("\\"))
|
||||||
|
|
||||||
#if !defined(Dqn_FsPath_Build)
|
#if !defined(Dqn_FsPath_Build)
|
||||||
#if defined(DQN_OS_WIN32)
|
#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
|
// @desc Produce the time elapsed since the Unix epoch
|
||||||
// (e.g. 1970-01-01T00:00:00Z) in seconds
|
// (e.g. 1970-01-01T00:00:00Z) in seconds
|
||||||
|
|
||||||
struct Dqn_DateHMSTimeString
|
struct Dqn_DateHMSTimeStr8
|
||||||
{
|
{
|
||||||
char date[DQN_ARRAY_UCOUNT("YYYY-MM-SS")];
|
char date[DQN_ARRAY_UCOUNT("YYYY-MM-SS")];
|
||||||
uint8_t date_size;
|
uint8_t date_size;
|
||||||
@ -186,10 +187,10 @@ struct Dqn_DateHMSTime
|
|||||||
uint8_t seconds;
|
uint8_t seconds;
|
||||||
};
|
};
|
||||||
|
|
||||||
DQN_API Dqn_DateHMSTime Dqn_Date_HMSLocalTimeNow ();
|
DQN_API Dqn_DateHMSTime Dqn_Date_LocalTimeHMSNow ();
|
||||||
DQN_API Dqn_DateHMSTimeString Dqn_Date_HMSLocalTimeStringNow(char date_separator = '-', char hms_separator = ':');
|
DQN_API Dqn_DateHMSTimeStr8 Dqn_Date_LocalTimeHMSStr8Now(char date_separator = '-', char hms_separator = ':');
|
||||||
DQN_API Dqn_DateHMSTimeString Dqn_Date_HMSLocalTimeString (Dqn_DateHMSTime time, 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 ();
|
DQN_API uint64_t Dqn_Date_EpochTime ();
|
||||||
|
|
||||||
#if defined(DQN_OS_WIN32)
|
#if defined(DQN_OS_WIN32)
|
||||||
#if !defined(DQN_NO_WIN)
|
#if !defined(DQN_NO_WIN)
|
||||||
@ -207,12 +208,12 @@ DQN_API uint64_t Dqn_Date_EpochTime ();
|
|||||||
struct Dqn_WinError
|
struct Dqn_WinError
|
||||||
{
|
{
|
||||||
unsigned long code;
|
unsigned long code;
|
||||||
Dqn_String8 msg;
|
Dqn_Str8 msg;
|
||||||
};
|
};
|
||||||
DQN_API Dqn_WinError Dqn_Win_LastError(Dqn_Arena *arena);
|
DQN_API Dqn_WinError Dqn_Win_LastError(Dqn_Arena *arena);
|
||||||
DQN_API void Dqn_Win_MakeProcessDPIAware();
|
DQN_API void Dqn_Win_MakeProcessDPIAware();
|
||||||
|
|
||||||
// NOTE: Windows String8 <-> String16 ===========================================
|
// NOTE: Windows Str8 <-> Str16 ===========================================
|
||||||
// Convert a UTF8 <-> UTF16 string.
|
// Convert a UTF8 <-> UTF16 string.
|
||||||
//
|
//
|
||||||
// The exact size buffer required for this function can be determined by
|
// 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
|
// written/required for conversion. 0 if there was a conversion error and can be
|
||||||
// queried using 'Dqn_Win_LastError'
|
// queried using 'Dqn_Win_LastError'
|
||||||
|
|
||||||
DQN_API Dqn_String16 Dqn_Win_String8ToString16(Dqn_Arena *arena, Dqn_String8 src);
|
DQN_API Dqn_Str16 Dqn_Win_Str8ToStr16 (Dqn_Arena *arena, Dqn_Str8 src);
|
||||||
DQN_API int Dqn_Win_String8ToString16Buffer(Dqn_String16 src, char *dest, int dest_size);
|
DQN_API int Dqn_Win_Str8ToStr16Buffer(Dqn_Str16 src, char *dest, int dest_size);
|
||||||
DQN_API Dqn_String8 Dqn_Win_String16ToString8(Dqn_Arena *arena, Dqn_String16 src);
|
DQN_API Dqn_Str8 Dqn_Win_Str16ToStr8 (Dqn_Arena *arena, Dqn_Str16 src);
|
||||||
DQN_API int Dqn_Win_String16ToString8Buffer(Dqn_String16 src, char *dest, int dest_size);
|
DQN_API int Dqn_Win_Str16ToStr8Buffer(Dqn_Str16 src, char *dest, int dest_size);
|
||||||
|
|
||||||
// NOTE: Path navigation ===========================================================================
|
// NOTE: Path navigation ===========================================================================
|
||||||
// NOTE: API =======================================================================================
|
// NOTE: API =======================================================================================
|
||||||
@ -256,22 +257,23 @@ DQN_API int Dqn_Win_String16ToString8Buffer(Dqn_String16 src, char *des
|
|||||||
struct Dqn_Win_FolderIteratorW
|
struct Dqn_Win_FolderIteratorW
|
||||||
{
|
{
|
||||||
void *handle;
|
void *handle;
|
||||||
Dqn_String16 file_name;
|
Dqn_Str16 file_name;
|
||||||
wchar_t file_name_buf[512];
|
wchar_t file_name_buf[512];
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Dqn_Win_FolderIterator
|
struct Dqn_Win_FolderIterator
|
||||||
{
|
{
|
||||||
void *handle;
|
void *handle;
|
||||||
Dqn_String8 file_name;
|
Dqn_Str8 file_name;
|
||||||
char file_name_buf[512];
|
char file_name_buf[512];
|
||||||
};
|
};
|
||||||
|
|
||||||
DQN_API Dqn_String16 Dqn_Win_EXEDirW (Dqn_Arena *arena);
|
DQN_API Dqn_Str16 Dqn_Win_EXEPathW (Dqn_Arena *arena);
|
||||||
DQN_API Dqn_String8 Dqn_Win_WorkingDir (Dqn_Allocator allocator, Dqn_String8 suffix);
|
DQN_API Dqn_Str16 Dqn_Win_EXEDirW (Dqn_Arena *arena);
|
||||||
DQN_API Dqn_String16 Dqn_Win_WorkingDirW (Dqn_Allocator allocator, Dqn_String16 suffix);
|
DQN_API Dqn_Str8 Dqn_Win_WorkingDir (Dqn_Allocator allocator, Dqn_Str8 suffix);
|
||||||
DQN_API bool Dqn_Win_FolderIterate (Dqn_String8 path, Dqn_Win_FolderIterator *it);
|
DQN_API Dqn_Str16 Dqn_Win_WorkingDirW (Dqn_Allocator allocator, Dqn_Str16 suffix);
|
||||||
DQN_API bool Dqn_Win_FolderWIterate(Dqn_String16 path, Dqn_Win_FolderIteratorW *it);
|
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)
|
#endif // !defined(DQN_NO_WIN)
|
||||||
|
|
||||||
#if !defined(DQN_NO_WINNET)
|
#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
|
// INTERNET_OPTION_SEND_TIMEOUT
|
||||||
//
|
//
|
||||||
// NOTE: API =======================================================================================
|
// 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.
|
// @desc Setup a handle to the URL with the given HTTP verb.
|
||||||
//
|
//
|
||||||
// This function is the same as calling Dqn_Win_NetHandleInit() followed by
|
// This function is the same as calling Dqn_Win_NetHandleInit() followed by
|
||||||
@ -354,32 +356,32 @@ enum Dqn_WinNetHandleRequestHeaderFlag
|
|||||||
|
|
||||||
struct Dqn_WinNetHandleResponse
|
struct Dqn_WinNetHandleResponse
|
||||||
{
|
{
|
||||||
Dqn_String8 raw_headers;
|
Dqn_Str8 raw_headers;
|
||||||
Dqn_String8 *headers;
|
Dqn_Str8 *headers;
|
||||||
Dqn_usize headers_size;
|
Dqn_usize headers_size;
|
||||||
|
|
||||||
// NOTE: Headers pulled from the 'raw_headers' for convenience
|
// NOTE: Headers pulled from the 'raw_headers' for convenience
|
||||||
uint64_t content_length;
|
uint64_t content_length;
|
||||||
Dqn_String8 content_type;
|
Dqn_Str8 content_type;
|
||||||
};
|
};
|
||||||
|
|
||||||
DQN_API Dqn_WinNetHandle Dqn_Win_NetHandleInitCString (char const *url, int url_size);
|
DQN_API Dqn_WinNetHandle Dqn_Win_NetHandleInitCStr8 (char const *url, int url_size);
|
||||||
DQN_API Dqn_WinNetHandle Dqn_Win_NetHandleInit (Dqn_String8 url);
|
DQN_API Dqn_WinNetHandle Dqn_Win_NetHandleInit (Dqn_Str8 url);
|
||||||
DQN_API Dqn_WinNetHandle Dqn_Win_NetHandleInitHTTPMethodCString (char const *url, int url_size, char const *http_method);
|
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_String8 url, Dqn_String8 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 void Dqn_Win_NetHandleClose (Dqn_WinNetHandle *handle);
|
||||||
DQN_API bool Dqn_Win_NetHandleIsValid (Dqn_WinNetHandle const *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 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_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_NetHandleSetRequestHeaderCStr8(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 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 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 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 char * Dqn_Win_NetHandlePumpCStr8 (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 Dqn_Str8 Dqn_Win_NetHandlePumpStr8 (Dqn_WinNetHandle *handle, Dqn_Arena *arena);
|
||||||
DQN_API void Dqn_Win_NetHandlePumpToCRTFile (Dqn_WinNetHandle *handle, FILE *file);
|
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 char * Dqn_Win_NetHandlePumpToAllocCStr8 (Dqn_WinNetHandle *handle, size_t *download_size);
|
||||||
DQN_API Dqn_String8 Dqn_Win_NetHandlePumpToAllocString (Dqn_WinNetHandle *handle);
|
DQN_API Dqn_Str8 Dqn_Win_NetHandlePumpToAllocStr8 (Dqn_WinNetHandle *handle);
|
||||||
#endif // !defined(DQN_NO_WINNET)
|
#endif // !defined(DQN_NO_WINNET)
|
||||||
#endif // defined(DQN_OS_WIN32)
|
#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
|
// @param duration_ms_to_gauge_tsc_frequency How many milliseconds to spend
|
||||||
// measuring the TSC rate of the current machine. 100ms is sufficient to
|
// measuring the TSC rate of the current machine. 100ms is sufficient to
|
||||||
// produce a fairly accurate result with minimal blocking in applications.
|
// 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.
|
/// Record time between two time-points using the OS's performance counter.
|
||||||
struct Dqn_OSTimer
|
struct Dqn_OSTimer
|
||||||
@ -415,7 +420,8 @@ struct Dqn_OSTimer
|
|||||||
|
|
||||||
DQN_API bool Dqn_OS_SecureRNGBytes (void *buffer, uint32_t size);
|
DQN_API bool Dqn_OS_SecureRNGBytes (void *buffer, uint32_t size);
|
||||||
#if (defined(DQN_OS_WIN32) && !defined(DQN_NO_WIN)) || !defined(DQN_OS_WIN32)
|
#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
|
#endif
|
||||||
DQN_API void Dqn_OS_SleepMs (Dqn_uint milliseconds);
|
DQN_API void Dqn_OS_SleepMs (Dqn_uint milliseconds);
|
||||||
DQN_API uint64_t Dqn_OS_PerfCounterNow ();
|
DQN_API uint64_t Dqn_OS_PerfCounterNow ();
|
||||||
|
439
dqn_strings.cpp
439
dqn_strings.cpp
@ -1,5 +1,5 @@
|
|||||||
// NOTE: [$CSTR] Dqn_CString8 ======================================================================
|
// NOTE: [$CSTR] Dqn_CStr8 ======================================================================
|
||||||
DQN_API Dqn_usize Dqn_CString8_FSize(DQN_FMT_STRING_ANNOTATE char const *fmt, ...)
|
DQN_API Dqn_usize Dqn_CStr8_FSize(DQN_FMT_ATTRIB char const *fmt, ...)
|
||||||
{
|
{
|
||||||
va_list args;
|
va_list args;
|
||||||
va_start(args, fmt);
|
va_start(args, fmt);
|
||||||
@ -8,7 +8,7 @@ DQN_API Dqn_usize Dqn_CString8_FSize(DQN_FMT_STRING_ANNOTATE char const *fmt, ..
|
|||||||
return result;
|
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_list args_copy;
|
||||||
va_copy(args_copy, args);
|
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;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DQN_API Dqn_usize Dqn_CStr8_Size(char const *src)
|
||||||
DQN_API Dqn_usize Dqn_CString8_Size(char const *src)
|
|
||||||
{
|
{
|
||||||
Dqn_usize result = 0;
|
Dqn_usize result = 0;
|
||||||
while (src && src[0] != 0) {
|
while (src && src[0] != 0) {
|
||||||
@ -28,7 +27,7 @@ DQN_API Dqn_usize Dqn_CString8_Size(char const *src)
|
|||||||
return result;
|
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;
|
Dqn_usize result = 0;
|
||||||
while (src && src[0] != 0) {
|
while (src && src[0] != 0) {
|
||||||
@ -39,28 +38,28 @@ DQN_API Dqn_usize Dqn_CString16_Size(wchar_t const *src)
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
// NOTE: [$STR8] Dqn_String8 =======================================================================
|
// NOTE: [$STR8] Dqn_Str8 =======================================================================
|
||||||
DQN_API Dqn_String8 Dqn_String8_InitCString8(char const *src)
|
DQN_API Dqn_Str8 Dqn_Str8_InitCStr8(char const *src)
|
||||||
{
|
{
|
||||||
Dqn_usize size = Dqn_CString8_Size(src);
|
Dqn_usize size = Dqn_CStr8_Size(src);
|
||||||
Dqn_String8 result = Dqn_String8_Init(src, size);
|
Dqn_Str8 result = Dqn_Str8_Init(src, size);
|
||||||
return result;
|
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)
|
if (!result)
|
||||||
return result;
|
return result;
|
||||||
|
|
||||||
switch (is_all) {
|
switch (is_all) {
|
||||||
case Dqn_String8IsAll_Digits: {
|
case Dqn_Str8IsAll_Digits: {
|
||||||
for (Dqn_usize index = 0; result && index < string.size; index++)
|
for (Dqn_usize index = 0; result && index < string.size; index++)
|
||||||
result = string.data[index] >= '0' && string.data[index] <= '9';
|
result = string.data[index] >= '0' && string.data[index] <= '9';
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
case Dqn_String8IsAll_Hex: {
|
case Dqn_Str8IsAll_Hex: {
|
||||||
Dqn_String8 trimmed = Dqn_String8_TrimPrefix(string, DQN_STRING8("0x"), Dqn_String8EqCase_Insensitive);
|
Dqn_Str8 trimmed = Dqn_Str8_TrimPrefix(string, DQN_STR8("0x"), Dqn_Str8EqCase_Insensitive);
|
||||||
for (Dqn_usize index = 0; result && index < string.size; index++) {
|
for (Dqn_usize index = 0; result && index < string.size; index++) {
|
||||||
char ch = trimmed.data[index];
|
char ch = trimmed.data[index];
|
||||||
result = (ch >= '0' && ch <= '9') || (ch >= 'a' && ch <= 'f') || (ch >= 'A' && ch <= 'F');
|
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;
|
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);
|
Dqn_Str8 result = Dqn_Str8_Init(string.data, 0);
|
||||||
if (!Dqn_String8_IsValid(result))
|
if (!Dqn_Str8_IsValid(result))
|
||||||
return result;
|
return result;
|
||||||
|
|
||||||
Dqn_usize capped_offset = DQN_MIN(offset, string.size);
|
Dqn_usize capped_offset = DQN_MIN(offset, string.size);
|
||||||
Dqn_usize max_size = string.size - capped_offset;
|
Dqn_usize max_size = string.size - capped_offset;
|
||||||
Dqn_usize capped_size = DQN_MIN(size, max_size);
|
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;
|
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;
|
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 = {};
|
Dqn_Str8BinarySplitResult result = {};
|
||||||
if (!Dqn_String8_IsValid(string) || !find || find_size == 0)
|
if (!Dqn_Str8_IsValid(string) || !find || find_size == 0)
|
||||||
return result;
|
return result;
|
||||||
|
|
||||||
result.lhs = string;
|
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++) {
|
for (Dqn_usize find_index = 0; find_index < find_size; find_index++) {
|
||||||
Dqn_String8 find_item = find[find_index];
|
Dqn_Str8 find_item = find[find_index];
|
||||||
Dqn_String8 string_slice = Dqn_String8_Slice(string, index, find_item.size);
|
Dqn_Str8 string_slice = Dqn_Str8_Slice(string, index, find_item.size);
|
||||||
if (Dqn_String8_Eq(string_slice, find_item)) {
|
if (Dqn_Str8_Eq(string_slice, find_item)) {
|
||||||
result.lhs.size = index;
|
result.lhs.size = index;
|
||||||
result.rhs.data = string_slice.data + find_item.size;
|
result.rhs.data = string_slice.data + find_item.size;
|
||||||
result.rhs.size = string.size - (index + 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;
|
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;
|
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.
|
Dqn_Str8BinarySplitResult result = {};
|
||||||
if (!Dqn_String8_IsValid(string) || !Dqn_String8_IsValid(delimiter) || delimiter.size <= 0)
|
if (!Dqn_Str8_IsValid(string) || !find || find_size == 0)
|
||||||
return result;
|
return result;
|
||||||
|
|
||||||
Dqn_usize splits_index = 0; // The number of splits written.
|
result.lhs = string;
|
||||||
Dqn_usize begin = 0;
|
for (size_t index = string.size - 1; !result.rhs.data && index < string.size; index--) {
|
||||||
for (Dqn_usize index = 0; index < string.size; ) {
|
for (Dqn_usize find_index = 0; find_index < find_size; find_index++) {
|
||||||
// NOTE: Check if we encountered the substring that is the delimiter
|
Dqn_Str8 find_item = find[find_index];
|
||||||
Dqn_String8 check = Dqn_String8_Slice(string, index, delimiter.size);
|
Dqn_Str8 string_slice = Dqn_Str8_Slice(string, index, find_item.size);
|
||||||
if (!Dqn_String8_Eq(check, delimiter)) {
|
if (Dqn_Str8_Eq(string_slice, find_item)) {
|
||||||
index++;
|
result.lhs.size = index;
|
||||||
continue;
|
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;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
DQN_API Dqn_String8SplitAllocResult Dqn_String8_SplitAlloc(Dqn_Allocator allocator,
|
DQN_API Dqn_Str8BinarySplitResult Dqn_Str8_BinarySplitReverse(Dqn_Str8 string, Dqn_Str8 find)
|
||||||
Dqn_String8 string,
|
|
||||||
Dqn_String8 delimiter)
|
|
||||||
{
|
{
|
||||||
Dqn_String8SplitAllocResult result = {};
|
Dqn_Str8BinarySplitResult result = Dqn_Str8_BinarySplitReverseArray(string, &find, 1);
|
||||||
Dqn_usize splits_required = Dqn_String8_Split(string, delimiter, /*splits*/ nullptr, /*count*/ 0);
|
return result;
|
||||||
result.data = Dqn_Allocator_NewArray(allocator, Dqn_String8, splits_required, Dqn_ZeroMem_No);
|
}
|
||||||
|
|
||||||
|
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) {
|
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);
|
DQN_ASSERT(splits_required == result.size);
|
||||||
}
|
}
|
||||||
return result;
|
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 = {};
|
Dqn_Str8FindResult result = {};
|
||||||
if (!Dqn_String8_IsValid(string) || !find || find_size == 0)
|
if (!Dqn_Str8_IsValid(string) || !find || find_size == 0)
|
||||||
return result;
|
return result;
|
||||||
|
|
||||||
for (Dqn_usize index = 0; !result.found && index < string.size; index++) {
|
for (Dqn_usize index = 0; !result.found && index < string.size; index++) {
|
||||||
for (Dqn_usize find_index = 0; find_index < find_size; find_index++) {
|
for (Dqn_usize find_index = 0; find_index < find_size; find_index++) {
|
||||||
Dqn_String8 find_item = find[find_index];
|
Dqn_Str8 find_item = find[find_index];
|
||||||
Dqn_String8 string_slice = Dqn_String8_Slice(string, index, find_item.size);
|
Dqn_Str8 string_slice = Dqn_Str8_Slice(string, index, find_item.size);
|
||||||
if (Dqn_String8_Eq(string_slice, find_item)) {
|
if (Dqn_Str8_Eq(string_slice, find_item)) {
|
||||||
result.found = true;
|
result.found = true;
|
||||||
result.index = index;
|
result.index = index;
|
||||||
result.start_to_before_match = Dqn_String8_Init(string.data, index);
|
result.start_to_before_match = Dqn_Str8_Init(string.data, index);
|
||||||
result.match = Dqn_String8_Init(string.data + index, find_item.size);
|
result.match = Dqn_Str8_Init(string.data + index, find_item.size);
|
||||||
result.match_to_end_of_buffer = Dqn_String8_Init(result.match.data, string.size - index);
|
result.match_to_end_of_buffer = Dqn_Str8_Init(result.match.data, string.size - index);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -186,37 +205,37 @@ DQN_API Dqn_String8FindResult Dqn_String8_FindFirstStringArray(Dqn_String8 strin
|
|||||||
return result;
|
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;
|
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++) {
|
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_Str8FindFlag_Digit) && Dqn_Char_IsDigit(string.data[index]));
|
||||||
result.found |= ((flags & Dqn_String8FindFlag_Alphabet) && Dqn_Char_IsAlphabet(string.data[index]));
|
result.found |= ((flags & Dqn_Str8FindFlag_Alphabet) && Dqn_Char_IsAlphabet(string.data[index]));
|
||||||
result.found |= ((flags & Dqn_String8FindFlag_Whitespace) && Dqn_Char_IsWhitespace(string.data[index]));
|
result.found |= ((flags & Dqn_Str8FindFlag_Whitespace) && Dqn_Char_IsWhitespace(string.data[index]));
|
||||||
result.found |= ((flags & Dqn_String8FindFlag_Plus) && string.data[index] == '+');
|
result.found |= ((flags & Dqn_Str8FindFlag_Plus) && string.data[index] == '+');
|
||||||
result.found |= ((flags & Dqn_String8FindFlag_Minus) && string.data[index] == '-');
|
result.found |= ((flags & Dqn_Str8FindFlag_Minus) && string.data[index] == '-');
|
||||||
if (result.found) {
|
if (result.found) {
|
||||||
result.index = index;
|
result.index = index;
|
||||||
result.match = Dqn_String8_Init(string.data + index, 1);
|
result.match = Dqn_Str8_Init(string.data + index, 1);
|
||||||
result.match_to_end_of_buffer = Dqn_String8_Init(result.match.data, string.size - index);
|
result.match_to_end_of_buffer = Dqn_Str8_Init(result.match.data, string.size - index);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return result;
|
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;
|
Dqn_usize result_size = src.size;
|
||||||
if (result_size > segment_size)
|
if (result_size > segment_size)
|
||||||
result_size += (src.size / segment_size) - 1; // NOTE: No segment on the first chunk.
|
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_usize write_index = 0;
|
||||||
DQN_FOR_UINDEX(src_index, src.size) {
|
DQN_FOR_UINDEX(src_index, src.size) {
|
||||||
result.data[write_index++] = src.data[src_index];
|
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)
|
if (lhs.size != rhs.size)
|
||||||
return false;
|
return false;
|
||||||
@ -243,11 +262,11 @@ DQN_API bool Dqn_String8_Eq(Dqn_String8 lhs, Dqn_String8 rhs, Dqn_String8EqCase
|
|||||||
|
|
||||||
bool result = true;
|
bool result = true;
|
||||||
switch (eq_case) {
|
switch (eq_case) {
|
||||||
case Dqn_String8EqCase_Sensitive: {
|
case Dqn_Str8EqCase_Sensitive: {
|
||||||
result = (DQN_MEMCMP(lhs.data, rhs.data, lhs.size) == 0);
|
result = (DQN_MEMCMP(lhs.data, rhs.data, lhs.size) == 0);
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
case Dqn_String8EqCase_Insensitive: {
|
case Dqn_Str8EqCase_Insensitive: {
|
||||||
for (Dqn_usize index = 0; index < lhs.size && result; index++)
|
for (Dqn_usize index = 0; index < lhs.size && result; index++)
|
||||||
result = (Dqn_Char_ToLower(lhs.data[index]) == Dqn_Char_ToLower(rhs.data[index]));
|
result = (Dqn_Char_ToLower(lhs.data[index]) == Dqn_Char_ToLower(rhs.data[index]));
|
||||||
} break;
|
} break;
|
||||||
@ -255,39 +274,39 @@ DQN_API bool Dqn_String8_Eq(Dqn_String8 lhs, Dqn_String8 rhs, Dqn_String8EqCase
|
|||||||
return result;
|
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;
|
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)};
|
Dqn_Str8 substring = {string.data, DQN_MIN(prefix.size, string.size)};
|
||||||
bool result = Dqn_String8_Eq(substring, prefix, eq_case);
|
bool result = Dqn_Str8_Eq(substring, prefix, eq_case);
|
||||||
return result;
|
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;
|
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)};
|
Dqn_Str8 substring = {string.data + string.size - suffix.size, DQN_MIN(string.size, suffix.size)};
|
||||||
bool result = Dqn_String8_Eq(substring, suffix, eq_case);
|
bool result = Dqn_Str8_Eq(substring, suffix, eq_case);
|
||||||
return result;
|
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;
|
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;
|
bool result = false;
|
||||||
for (Dqn_usize index = 0; !result && index < string.size; index++)
|
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;
|
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;
|
Dqn_Str8 result = string;
|
||||||
if (Dqn_String8_StartsWith(string, prefix, eq_case)) {
|
if (Dqn_Str8_StartsWith(string, prefix, eq_case)) {
|
||||||
result.data += prefix.size;
|
result.data += prefix.size;
|
||||||
result.size -= prefix.size;
|
result.size -= prefix.size;
|
||||||
}
|
}
|
||||||
return result;
|
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;
|
Dqn_Str8 result = string;
|
||||||
if (Dqn_String8_EndsWith(string, suffix, eq_case))
|
if (Dqn_Str8_EndsWith(string, suffix, eq_case))
|
||||||
result.size -= suffix.size;
|
result.size -= suffix.size;
|
||||||
return result;
|
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;
|
Dqn_Str8 result = Dqn_Str8_TrimPrefix(string, trim_string);
|
||||||
if (!Dqn_String8_IsValid(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;
|
return result;
|
||||||
|
|
||||||
char const *start = string.data;
|
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]))
|
while (end > start && Dqn_Char_IsWhitespace(end[-1]))
|
||||||
end--;
|
end--;
|
||||||
|
|
||||||
result = Dqn_String8_Init(start, end - start);
|
result = Dqn_Str8_Init(start, end - start);
|
||||||
return result;
|
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;
|
Dqn_Str8 result = string;
|
||||||
if (!Dqn_String8_IsValid(result))
|
if (!Dqn_Str8_IsValid(result))
|
||||||
return result;
|
return result;
|
||||||
|
|
||||||
// TODO(dqn): This is little endian
|
// TODO(dqn): This is little endian
|
||||||
Dqn_String8 UTF8_BOM = DQN_STRING8("\xEF\xBB\xBF");
|
Dqn_Str8 UTF8_BOM = DQN_STR8("\xEF\xBB\xBF");
|
||||||
Dqn_String8 UTF16_BOM_BE = DQN_STRING8("\xEF\xFF");
|
Dqn_Str8 UTF16_BOM_BE = DQN_STR8("\xEF\xFF");
|
||||||
Dqn_String8 UTF16_BOM_LE = DQN_STRING8("\xFF\xEF");
|
Dqn_Str8 UTF16_BOM_LE = DQN_STR8("\xFF\xEF");
|
||||||
Dqn_String8 UTF32_BOM_BE = DQN_STRING8("\x00\x00\xFE\xFF");
|
Dqn_Str8 UTF32_BOM_BE = DQN_STR8("\x00\x00\xFE\xFF");
|
||||||
Dqn_String8 UTF32_BOM_LE = DQN_STRING8("\xFF\xFE\x00\x00");
|
Dqn_Str8 UTF32_BOM_LE = DQN_STR8("\xFF\xFE\x00\x00");
|
||||||
|
|
||||||
result = Dqn_String8_TrimPrefix(result, UTF8_BOM, Dqn_String8EqCase_Sensitive);
|
result = Dqn_Str8_TrimPrefix(result, UTF8_BOM, Dqn_Str8EqCase_Sensitive);
|
||||||
result = Dqn_String8_TrimPrefix(result, UTF16_BOM_BE, Dqn_String8EqCase_Sensitive);
|
result = Dqn_Str8_TrimPrefix(result, UTF16_BOM_BE, Dqn_Str8EqCase_Sensitive);
|
||||||
result = Dqn_String8_TrimPrefix(result, UTF16_BOM_LE, Dqn_String8EqCase_Sensitive);
|
result = Dqn_Str8_TrimPrefix(result, UTF16_BOM_LE, Dqn_Str8EqCase_Sensitive);
|
||||||
result = Dqn_String8_TrimPrefix(result, UTF32_BOM_BE, Dqn_String8EqCase_Sensitive);
|
result = Dqn_Str8_TrimPrefix(result, UTF32_BOM_BE, Dqn_Str8EqCase_Sensitive);
|
||||||
result = Dqn_String8_TrimPrefix(result, UTF32_BOM_LE, Dqn_String8EqCase_Sensitive);
|
result = Dqn_Str8_TrimPrefix(result, UTF32_BOM_LE, Dqn_Str8EqCase_Sensitive);
|
||||||
return result;
|
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;
|
Dqn_Str8 separators[] = {DQN_STR8("/"), DQN_STR8("\\")};
|
||||||
if (!Dqn_String8_IsValid(result))
|
Dqn_Str8BinarySplitResult split = Dqn_Str8_BinarySplitReverseArray(path, separators, DQN_ARRAY_UCOUNT(separators));
|
||||||
return result;
|
Dqn_Str8 result = split.rhs;
|
||||||
|
|
||||||
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
|
|
||||||
return result;
|
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
|
// NOTE: Argument check
|
||||||
Dqn_String8ToU64Result result = {};
|
Dqn_Str8ToU64Result result = {};
|
||||||
if (!Dqn_String8_IsValid(string))
|
if (!Dqn_Str8_IsValid(string))
|
||||||
return result;
|
return result;
|
||||||
|
|
||||||
// NOTE: Sanitize input/output
|
// 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) {
|
if (trim_string.size == 0) {
|
||||||
result.success = false;
|
result.success = false;
|
||||||
return result;
|
return result;
|
||||||
@ -414,15 +442,15 @@ DQN_API Dqn_String8ToU64Result Dqn_String8_ToU64(Dqn_String8 string, char separa
|
|||||||
return result;
|
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
|
// NOTE: Argument check
|
||||||
Dqn_String8ToI64Result result = {};
|
Dqn_Str8ToI64Result result = {};
|
||||||
if (!Dqn_String8_IsValid(string))
|
if (!Dqn_Str8_IsValid(string))
|
||||||
return result;
|
return result;
|
||||||
|
|
||||||
// NOTE: Sanitize input/output
|
// 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) {
|
if (trim_string.size == 0) {
|
||||||
result.success = false;
|
result.success = false;
|
||||||
return result;
|
return result;
|
||||||
@ -460,28 +488,28 @@ DQN_API Dqn_String8ToI64Result Dqn_String8_ToI64(Dqn_String8 string, char separa
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
DQN_API Dqn_String8 Dqn_String8_Replace(Dqn_String8 string,
|
DQN_API Dqn_Str8 Dqn_Str8_Replace(Dqn_Str8 string,
|
||||||
Dqn_String8 find,
|
Dqn_Str8 find,
|
||||||
Dqn_String8 replace,
|
Dqn_Str8 replace,
|
||||||
Dqn_usize start_index,
|
Dqn_usize start_index,
|
||||||
Dqn_Allocator allocator,
|
Dqn_Allocator allocator,
|
||||||
Dqn_String8EqCase eq_case)
|
Dqn_Str8EqCase eq_case)
|
||||||
{
|
{
|
||||||
Dqn_String8 result = {};
|
Dqn_Str8 result = {};
|
||||||
if (!Dqn_String8_IsValid(string) || !Dqn_String8_IsValid(find) || find.size > string.size || find.size == 0 || string.size == 0) {
|
if (!Dqn_Str8_IsValid(string) || !Dqn_Str8_IsValid(find) || find.size > string.size || find.size == 0 || string.size == 0) {
|
||||||
result = Dqn_String8_Copy(allocator, string);
|
result = Dqn_Str8_Copy(allocator, string);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
Dqn_ThreadScratch scratch = Dqn_Thread_GetScratch(allocator.user_context);
|
Dqn_ThreadScratch scratch = Dqn_Thread_GetScratch(allocator.user_context);
|
||||||
Dqn_String8Builder string_builder = {};
|
Dqn_Str8Builder string_builder = {};
|
||||||
string_builder.allocator = scratch.allocator;
|
string_builder.allocator = scratch.allocator;
|
||||||
Dqn_usize max = string.size - find.size;
|
Dqn_usize max = string.size - find.size;
|
||||||
Dqn_usize head = start_index;
|
Dqn_usize head = start_index;
|
||||||
|
|
||||||
for (Dqn_usize tail = head; tail <= max; tail++) {
|
for (Dqn_usize tail = head; tail <= max; tail++) {
|
||||||
Dqn_String8 check = Dqn_String8_Slice(string, tail, find.size);
|
Dqn_Str8 check = Dqn_Str8_Slice(string, tail, find.size);
|
||||||
if (!Dqn_String8_Eq(check, find, eq_case))
|
if (!Dqn_Str8_Eq(check, find, eq_case))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (start_index > 0 && string_builder.string_size == 0) {
|
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
|
// 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
|
// a replacement action, otherwise we have a special case for no
|
||||||
// replacements, where the entire string gets copied.
|
// replacements, where the entire string gets copied.
|
||||||
Dqn_String8 slice = Dqn_String8_Init(string.data, head);
|
Dqn_Str8 slice = Dqn_Str8_Init(string.data, head);
|
||||||
Dqn_String8Builder_AppendRef(&string_builder, slice);
|
Dqn_Str8Builder_AppendRef(&string_builder, slice);
|
||||||
}
|
}
|
||||||
|
|
||||||
Dqn_String8 range = Dqn_String8_Slice(string, head, (tail - head));
|
Dqn_Str8 range = Dqn_Str8_Slice(string, head, (tail - head));
|
||||||
Dqn_String8Builder_AppendRef(&string_builder, range);
|
Dqn_Str8Builder_AppendRef(&string_builder, range);
|
||||||
Dqn_String8Builder_AppendRef(&string_builder, replace);
|
Dqn_Str8Builder_AppendRef(&string_builder, replace);
|
||||||
head = tail + find.size;
|
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
|
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) {
|
if (string_builder.string_size == 0) {
|
||||||
// NOTE: No replacement possible, so we just do a full-copy
|
// NOTE: No replacement possible, so we just do a full-copy
|
||||||
result = Dqn_String8_Copy(allocator, string);
|
result = Dqn_Str8_Copy(allocator, string);
|
||||||
} else {
|
} else {
|
||||||
Dqn_String8 remainder = Dqn_String8_Init(string.data + head, string.size - head);
|
Dqn_Str8 remainder = Dqn_Str8_Init(string.data + head, string.size - head);
|
||||||
Dqn_String8Builder_AppendRef(&string_builder, remainder);
|
Dqn_Str8Builder_AppendRef(&string_builder, remainder);
|
||||||
result = Dqn_String8Builder_Build(&string_builder, allocator);
|
result = Dqn_Str8Builder_Build(&string_builder, allocator);
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
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;
|
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;
|
return;
|
||||||
|
|
||||||
char *end = string->data + string->size;
|
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)
|
#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;
|
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);
|
bool result = !(lhs == rhs);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
#endif
|
#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_list va;
|
||||||
va_start(va, fmt);
|
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);
|
va_end(va);
|
||||||
return result;
|
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)
|
if (!fmt)
|
||||||
return result;
|
return result;
|
||||||
|
|
||||||
Dqn_usize size = Dqn_CString8_FVSize(fmt, args);
|
Dqn_usize size = Dqn_CStr8_FVSize(fmt, args);
|
||||||
if (size) {
|
if (size) {
|
||||||
result = Dqn_String8_Allocate(allocator, size, Dqn_ZeroMem_No);
|
result = Dqn_Str8_Allocate(allocator, size, Dqn_ZeroMem_No);
|
||||||
if (Dqn_String8_IsValid(result))
|
if (Dqn_Str8_IsValid(result))
|
||||||
STB_SPRINTF_DECORATE(vsnprintf)(result.data, Dqn_Safe_SaturateCastISizeToInt(size + 1 /*null-terminator*/), fmt, args);
|
STB_SPRINTF_DECORATE(vsnprintf)(result.data, Dqn_Safe_SaturateCastISizeToInt(size + 1 /*null-terminator*/), fmt, args);
|
||||||
}
|
}
|
||||||
return result;
|
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 = {};
|
Dqn_Str8 result = {};
|
||||||
result.data = (char *)Dqn_Allocator_Alloc(allocator, size + 1, alignof(char), zero_mem);
|
result.data = (char *)Dqn_Allocator_Alloc(allocator, size + 1, alignof(char), zero_mem);
|
||||||
if (result.data)
|
if (result.data)
|
||||||
result.size = size;
|
result.size = size;
|
||||||
return result;
|
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)
|
if (!string)
|
||||||
return result;
|
return result;
|
||||||
|
|
||||||
result = Dqn_String8_Allocate(allocator, size, Dqn_ZeroMem_No);
|
result = Dqn_Str8_Allocate(allocator, size, Dqn_ZeroMem_No);
|
||||||
if (Dqn_String8_IsValid(result)) {
|
if (Dqn_Str8_IsValid(result)) {
|
||||||
DQN_MEMCPY(result.data, string, size);
|
DQN_MEMCPY(result.data, string, size);
|
||||||
result.data[size] = 0;
|
result.data[size] = 0;
|
||||||
}
|
}
|
||||||
return result;
|
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;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
// NOTE: [$STRB] Dqn_String8Builder ================================================================
|
// NOTE: [$STRB] Dqn_Str8Builder ================================================================
|
||||||
DQN_API bool Dqn_String8Builder_AppendRef(Dqn_String8Builder *builder, Dqn_String8 string)
|
DQN_API bool Dqn_Str8Builder_AppendRef(Dqn_Str8Builder *builder, Dqn_Str8 string)
|
||||||
{
|
{
|
||||||
if (!builder || !string.data || string.size <= 0)
|
if (!builder || !string.data || string.size <= 0)
|
||||||
return false;
|
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)
|
if (!link)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
@ -622,37 +650,37 @@ DQN_API bool Dqn_String8Builder_AppendRef(Dqn_String8Builder *builder, Dqn_Strin
|
|||||||
return true;
|
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);
|
Dqn_Str8 copy = Dqn_Str8_Copy(builder->allocator, string);
|
||||||
bool result = Dqn_String8Builder_AppendRef(builder, copy);
|
bool result = Dqn_Str8Builder_AppendRef(builder, copy);
|
||||||
return result;
|
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)
|
if (string.size == 0)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
bool result = Dqn_String8Builder_AppendRef(builder, string);
|
bool result = Dqn_Str8Builder_AppendRef(builder, string);
|
||||||
if (!result)
|
if (!result)
|
||||||
Dqn_Allocator_Dealloc(builder->allocator, string.data, string.size + 1);
|
Dqn_Allocator_Dealloc(builder->allocator, string.data, string.size + 1);
|
||||||
return result;
|
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_list args;
|
||||||
va_start(args, fmt);
|
va_start(args, fmt);
|
||||||
bool result = Dqn_String8Builder_AppendFV(builder, fmt, args);
|
bool result = Dqn_Str8Builder_AppendFV(builder, fmt, args);
|
||||||
va_end(args);
|
va_end(args);
|
||||||
return result;
|
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)
|
if (!builder || builder->string_size <= 0 || builder->count <= 0)
|
||||||
return result;
|
return result;
|
||||||
|
|
||||||
@ -660,7 +688,7 @@ DQN_API Dqn_String8 Dqn_String8Builder_Build(Dqn_String8Builder const *builder,
|
|||||||
if (!result.data)
|
if (!result.data)
|
||||||
return result;
|
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);
|
DQN_MEMCPY(result.data + result.size, link->string.data, link->string.size);
|
||||||
result.size += 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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
413
dqn_strings.h
413
dqn_strings.h
@ -1,57 +1,57 @@
|
|||||||
// NOTE: [$CSTR] Dqn_CString8 ======================================================================
|
// NOTE: [$CSTR] Dqn_CStr8 ======================================================================
|
||||||
// @proc Dqn_CString8_ArrayCount
|
// @proc Dqn_CStr8_ArrayCount
|
||||||
// @desc Calculate the size of a cstring literal/array at compile time
|
// @desc Calculate the size of a cstring literal/array at compile time
|
||||||
// @param literal The cstring literal/array to calculate the size for
|
// @param literal The cstring literal/array to calculate the size for
|
||||||
// @return The size of the cstring not including the null-terminating byte
|
// @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.
|
// Calculate the required size to format the given format cstring.
|
||||||
// @param[in] fmt The format string to calculate the size for
|
// @param[in] fmt The format string to calculate the size for
|
||||||
// @return The size required to format the string, not including the null
|
// @return The size required to format the string, not including the null
|
||||||
// terminator.
|
// terminator.
|
||||||
|
|
||||||
// @proc Dqn_CString8_Size
|
// @proc Dqn_CStr8_Size
|
||||||
// @desc Calculate the string length of the null-terminated string.
|
// @desc Calculate the string length of the null-terminated string.
|
||||||
// @param[in] a The string whose length is to be determined
|
// @param[in] a The string whose length is to be determined
|
||||||
// @return The length of the string
|
// @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_CStr8_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 template <Dqn_usize N> constexpr Dqn_usize Dqn_CStr8_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_CStr8_FSize (DQN_FMT_ATTRIB 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_CStr8_FVSize (DQN_FMT_ATTRIB char const *fmt, va_list args);
|
||||||
DQN_API Dqn_usize Dqn_CString8_Size (char const *a);
|
DQN_API Dqn_usize Dqn_CStr8_Size (char const *a);
|
||||||
DQN_API Dqn_usize Dqn_CString16_Size (wchar_t const *a);
|
DQN_API Dqn_usize Dqn_CStr16_Size (wchar_t const *a);
|
||||||
|
|
||||||
// NOTE: [$STR8] Dqn_String8 =======================================================================
|
// NOTE: [$STR8] Dqn_Str8 =======================================================================
|
||||||
// NOTE: API
|
// NOTE: API
|
||||||
// @proc Dqn_String8_Init
|
// @proc Dqn_Str8_Init
|
||||||
// @desc Initialise a string from a pointer and length
|
// @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.
|
// negative or the string is null.
|
||||||
|
|
||||||
// @proc Dqn_String8_InitCString
|
// @proc Dqn_Str8_InitCString
|
||||||
// @desc Initialise a string from a cstring
|
// @desc Initialise a string from a cstring
|
||||||
// The cstring must be null-terminated as its length is evaluated using
|
// 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.
|
// 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
|
// @desc Create a string from a printf style format string
|
||||||
// @param[in] allocator The allocator the string will be allocated from
|
// @param[in] allocator The allocator the string will be allocated from
|
||||||
// @param[in] fmt The printf style format cstring
|
// @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
|
// @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] arena The allocator the string will be allocated from
|
||||||
// @param[in] fmt The printf style format cstring
|
// @param[in] fmt The printf style format cstring
|
||||||
// @param[in] va The variable argument list
|
// @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
|
// @desc Determine if the values of the given string are valid
|
||||||
// A string is invalid if size is negative or the string is null.
|
// A string is invalid if size is negative or the string is null.
|
||||||
// @return True if the string is valid, false otherwise.
|
// @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.
|
// @desc Create a slice from a pre-existing string.
|
||||||
// The requested slice is clamped to within the bounds of the original string.
|
// The requested slice is clamped to within the bounds of the original string.
|
||||||
// @param[in] string The string to slice
|
// @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
|
// @param[in] size The size of the slice
|
||||||
// @return The sliced string
|
// @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
|
// @desc Split a string into the substring occuring prior and after the first
|
||||||
// occurence of the `delimiter`. Neither strings include the `delimiter`.
|
// 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
|
// @return The left hand side of the split string. The original pointer is
|
||||||
// returned if the arguments were invalid.
|
// returned if the arguments were invalid.
|
||||||
|
|
||||||
// @proc Dqn_String8_Split
|
// @proc Dqn_Str8_Split
|
||||||
// @desc Split a string by the delimiting character.
|
// @desc Split a string by the delimiting character.
|
||||||
// This function can evaluate the number of splits required in the return value
|
// This function can evaluate the number of splits required in the return value
|
||||||
// by setting `splits` to null and `splits_count` to 0.
|
// 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
|
// 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.
|
// 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`
|
// @desc Segment a string by inserting the `segment_char` every `segment_size`
|
||||||
// characters in the string. For example, '123456789' split with
|
// characters in the string. For example, '123456789' split with
|
||||||
// `segment_char` ' ' and `segment_size` '3' would yield, '123 456 789'.
|
// `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
|
// @desc Create an empty string with the requested size
|
||||||
// @param[in] allocator The allocator the string will be allocated from
|
// @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] 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
|
// @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
|
// @desc Create a copy of the given cstring
|
||||||
// @param[in] allocator The allocator the string will be allocated from
|
// @param[in] allocator The allocator the string will be allocated from
|
||||||
// @param[in] string The cstring to copy
|
// @param[in] string The cstring to copy
|
||||||
// @param[in] size The size of the cstring to copy. This cannot be <= 0
|
// @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.
|
// @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
|
// @desc Create a copy of the given string
|
||||||
// @param[in] allocator The allocator the string will be allocated from
|
// @param[in] allocator The allocator the string will be allocated from
|
||||||
// @param[in] string The string to copy
|
// @param[in] string The string to copy
|
||||||
// @return A copy of the string, invalid string if any argument was invalid.
|
// @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.
|
// @desc Compare a string for equality with or without case sensitivity.
|
||||||
// @param[in] lhs The first string to compare equality with
|
// @param[in] lhs The first string to compare equality with
|
||||||
// @param[in] rhs The second 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
|
// @return True if the arguments are valid, non-null and the strings
|
||||||
// are equal, false otherwise.
|
// are equal, false otherwise.
|
||||||
|
|
||||||
// @proc Dqn_String8_StartsWith, Dqn_String8_StartsWithInsensitive,
|
// @proc Dqn_Str8_StartsWith, Dqn_Str8_StartsWithInsensitive,
|
||||||
// Dqn_String8_EndsWith, Dqn_String8_EndswithInsensitive
|
// Dqn_Str8_EndsWith, Dqn_Str8_EndswithInsensitive
|
||||||
// @desc Check if a string starts/ends with the specified prefix
|
// @desc Check if a string starts/ends with the specified prefix
|
||||||
// `EndsWithInsensitive` is case insensitive
|
// `EndsWithInsensitive` is case insensitive
|
||||||
// @param[in] string The string to check for the prefix
|
// @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,
|
// @return True if the string is valid, non-null and has the specified prefix,
|
||||||
// false otherwise.
|
// 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.
|
// @desc Remove the prefix/suffix respectively from the given `string.
|
||||||
//
|
//
|
||||||
// @param[in] string The string to trim
|
// @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
|
// @return The trimmed string. The original input string is returned if
|
||||||
// arguments are invalid or no trim was possible.
|
// 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
|
// @desc Trim whitespace from the prefix and suffix of the string
|
||||||
//
|
//
|
||||||
// @param[in] string The string to trim
|
// @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
|
// @return The trimmed string. The original input string is returned if
|
||||||
// arguments are invalid or no trim was possible.
|
// 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.
|
// @desc Trim UTF8, UTF16 BE/LE, UTF32 BE/LE byte order mark prefix in the string.
|
||||||
//
|
//
|
||||||
// @param[in] string The string to trim
|
// @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
|
// @return The trimmed string. The original input string is returned if
|
||||||
// arguments are invalid or no trim was possible.
|
// 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
|
// @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
|
// 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
|
// 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
|
// @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.
|
// 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.
|
// @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`
|
// 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
|
// @param[in] separator The character used to separate the digits, if any. Set
|
||||||
// this to 0, if no separators are permitted.
|
// 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
|
// @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
|
// @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.
|
// 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
|
// @desc @param start_index Set an index within the string string to start the search
|
||||||
// from, if not desired, set to 0
|
// from, if not desired, set to 0
|
||||||
// @return A string that points to the matching find, otherwise a 0 length string.
|
// @return A string that points to the matching find, otherwise a 0 length string.
|
||||||
|
|
||||||
// @proc DQN_STRING8
|
// @proc DQN_STR8
|
||||||
// @desc Construct a UTF8 c-string literal into a Dqn_String8 referencing a
|
// @desc Construct a UTF8 c-string literal into a Dqn_Str8 referencing a
|
||||||
// string stored in the data-segment. This string is read-only.
|
// string stored in the data-segment. This string is read-only.
|
||||||
|
|
||||||
// @proc DQN_STRING16
|
// @proc DQN_STR16
|
||||||
// @desc Construct a UTF16 c-string literal into a Dqn_String16 referencing a string
|
// @desc Construct a UTF16 c-string literal into a Dqn_Str16 referencing a string
|
||||||
// stored in the data-segment. This string is read-only.
|
// 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
|
// @desc Unpack a string into arguments for printing a string into a printf style
|
||||||
// format string.
|
// format string.
|
||||||
|
|
||||||
struct Dqn_String8Link
|
struct Dqn_Str8Link
|
||||||
{
|
{
|
||||||
Dqn_String8 string; // The string
|
Dqn_Str8 string; // The string
|
||||||
Dqn_String8Link *next; // The next string in the linked list
|
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
|
wchar_t *data; // The UTF16 bytes of the string
|
||||||
Dqn_usize size; // The number of characters in 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
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Dqn_String8BinarySplitResult
|
struct Dqn_Str8BinarySplitResult
|
||||||
{
|
{
|
||||||
Dqn_String8 lhs;
|
Dqn_Str8 lhs;
|
||||||
Dqn_String8 rhs;
|
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.
|
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_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_Str8 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_Str8 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
|
Dqn_Str8 start_to_before_match; // The substring from the start of the buffer up until the found string, not including it
|
||||||
};
|
};
|
||||||
|
|
||||||
// NOTE: Macros ====================================================================================
|
// NOTE: Macros ====================================================================================
|
||||||
#define DQN_STRING8(string) Dqn_String8{(char *)(string), sizeof(string) - 1}
|
#define DQN_STR8(string) Dqn_Str8{(char *)(string), sizeof(string) - 1}
|
||||||
#define DQN_STRING16(string) Dqn_String16{(wchar_t *)(string), (sizeof(string)/sizeof(string[0])) - 1}
|
#define DQN_STR16(string) Dqn_Str16{(wchar_t *)(string), (sizeof(string)/sizeof(string[0])) - 1}
|
||||||
#define DQN_STRING_FMT(string) (int)((string).size), (string).data
|
#define DQN_STR_FMT(string) (int)((string).size), (string).data
|
||||||
|
|
||||||
#if defined(__cplusplus)
|
#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
|
#else
|
||||||
#define Dqn_String8_Init(data, size) (Dqn_String8){(data), (size)}
|
#define Dqn_Str8_Init(data, size) (Dqn_Str8){(data), (size)}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// NOTE: API =======================================================================================
|
// NOTE: API =======================================================================================
|
||||||
enum Dqn_String8IsAll
|
enum Dqn_Str8IsAll
|
||||||
{
|
{
|
||||||
Dqn_String8IsAll_Digits,
|
Dqn_Str8IsAll_Digits,
|
||||||
Dqn_String8IsAll_Hex,
|
Dqn_Str8IsAll_Hex,
|
||||||
};
|
};
|
||||||
|
|
||||||
enum Dqn_String8EqCase
|
enum Dqn_Str8EqCase
|
||||||
{
|
{
|
||||||
Dqn_String8EqCase_Sensitive,
|
Dqn_Str8EqCase_Sensitive,
|
||||||
Dqn_String8EqCase_Insensitive,
|
Dqn_Str8EqCase_Insensitive,
|
||||||
};
|
};
|
||||||
|
|
||||||
enum Dqn_String8FindFlag
|
enum Dqn_Str8FindFlag
|
||||||
{
|
{
|
||||||
Dqn_String8FindFlag_Digit = 1 << 0, // 0-9
|
Dqn_Str8FindFlag_Digit = 1 << 0, // 0-9
|
||||||
Dqn_String8FindFlag_Whitespace = 1 << 1, // '\r', '\t', '\n', ' '
|
Dqn_Str8FindFlag_Whitespace = 1 << 1, // '\r', '\t', '\n', ' '
|
||||||
Dqn_String8FindFlag_Alphabet = 1 << 2, // A-Z, a-z
|
Dqn_Str8FindFlag_Alphabet = 1 << 2, // A-Z, a-z
|
||||||
Dqn_String8FindFlag_Plus = 1 << 3, // +
|
Dqn_Str8FindFlag_Plus = 1 << 3, // +
|
||||||
Dqn_String8FindFlag_Minus = 1 << 4, // -
|
Dqn_Str8FindFlag_Minus = 1 << 4, // -
|
||||||
Dqn_String8FindFlag_AlphaNum = Dqn_String8FindFlag_Alphabet | Dqn_String8FindFlag_Digit,
|
Dqn_Str8FindFlag_AlphaNum = Dqn_Str8FindFlag_Alphabet | Dqn_Str8FindFlag_Digit,
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Dqn_String8SplitAllocResult
|
struct Dqn_Str8SplitAllocResult
|
||||||
{
|
{
|
||||||
Dqn_String8 *data;
|
Dqn_Str8 *data;
|
||||||
Dqn_usize size;
|
Dqn_usize size;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Dqn_String8ToU64Result
|
struct Dqn_Str8ToU64Result
|
||||||
{
|
{
|
||||||
bool success;
|
bool success;
|
||||||
uint64_t value;
|
uint64_t value;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Dqn_String8ToI64Result
|
struct Dqn_Str8ToI64Result
|
||||||
{
|
{
|
||||||
bool success;
|
bool success;
|
||||||
int64_t value;
|
int64_t value;
|
||||||
};
|
};
|
||||||
|
|
||||||
DQN_API Dqn_String8 Dqn_String8_InitCString8 (char const *src);
|
DQN_API Dqn_Str8 Dqn_Str8_InitCStr8 (char const *src);
|
||||||
#define Dqn_String8_IsValid(string) ((string).data)
|
#define Dqn_Str8_IsValid(string) ((string).data)
|
||||||
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);
|
||||||
|
|
||||||
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, ...);
|
||||||
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_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_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_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_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_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_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_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_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_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_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_Str8FindResult Dqn_Str8_FindFirstStringArray (Dqn_Str8 string, Dqn_Str8 const *find, Dqn_usize find_size);
|
||||||
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_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_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_API bool Dqn_String8_Eq (Dqn_String8 lhs, Dqn_String8 rhs, Dqn_String8EqCase eq_case = Dqn_String8EqCase_Sensitive);
|
DQN_API bool Dqn_Str8_Eq (Dqn_Str8 lhs, Dqn_Str8 rhs, Dqn_Str8EqCase eq_case = Dqn_Str8EqCase_Sensitive);
|
||||||
DQN_API bool Dqn_String8_EqInsensitive (Dqn_String8 lhs, Dqn_String8 rhs);
|
DQN_API bool Dqn_Str8_EqInsensitive (Dqn_Str8 lhs, Dqn_Str8 rhs);
|
||||||
DQN_API bool Dqn_String8_StartsWith (Dqn_String8 string, Dqn_String8 prefix, Dqn_String8EqCase eq_case = Dqn_String8EqCase_Sensitive);
|
DQN_API bool Dqn_Str8_StartsWith (Dqn_Str8 string, Dqn_Str8 prefix, Dqn_Str8EqCase eq_case = Dqn_Str8EqCase_Sensitive);
|
||||||
DQN_API bool Dqn_String8_StartsWithInsensitive (Dqn_String8 string, Dqn_String8 prefix);
|
DQN_API bool Dqn_Str8_StartsWithInsensitive (Dqn_Str8 string, Dqn_Str8 prefix);
|
||||||
DQN_API bool Dqn_String8_EndsWith (Dqn_String8 string, Dqn_String8 prefix, Dqn_String8EqCase eq_case = Dqn_String8EqCase_Sensitive);
|
DQN_API bool Dqn_Str8_EndsWith (Dqn_Str8 string, Dqn_Str8 prefix, Dqn_Str8EqCase eq_case = Dqn_Str8EqCase_Sensitive);
|
||||||
DQN_API bool Dqn_String8_EndsWithInsensitive (Dqn_String8 string, Dqn_String8 prefix);
|
DQN_API bool Dqn_Str8_EndsWithInsensitive (Dqn_Str8 string, Dqn_Str8 prefix);
|
||||||
DQN_API bool Dqn_String8_HasChar (Dqn_String8 string, char ch);
|
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_Str8 Dqn_Str8_TrimPrefix (Dqn_Str8 string, Dqn_Str8 prefix, Dqn_Str8EqCase eq_case = Dqn_Str8EqCase_Sensitive);
|
||||||
DQN_API Dqn_String8 Dqn_String8_TrimSuffix (Dqn_String8 string, Dqn_String8 suffix, Dqn_String8EqCase eq_case = Dqn_String8EqCase_Sensitive);
|
DQN_API Dqn_Str8 Dqn_Str8_TrimSuffix (Dqn_Str8 string, Dqn_Str8 suffix, Dqn_Str8EqCase eq_case = Dqn_Str8EqCase_Sensitive);
|
||||||
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_API Dqn_String8 Dqn_String8_TrimByteOrderMark (Dqn_String8 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_Str8ToU64Result Dqn_Str8_ToU64 (Dqn_Str8 string, char separator);
|
||||||
DQN_API Dqn_String8ToI64Result Dqn_String8_ToI64 (Dqn_String8 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_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_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_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 defined(__cplusplus)
|
#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);
|
||||||
DQN_API bool operator!= (Dqn_String8 const &lhs, Dqn_String8 const &rhs);
|
DQN_API bool operator!= (Dqn_Str8 const &lhs, Dqn_Str8 const &rhs);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if !defined(DQN_NO_FSTRING8)
|
#if !defined(DQN_NO_FSTR8)
|
||||||
// NOTE: [$FSTR] Dqn_FString8 ======================================================================
|
// NOTE: [$FSTR] Dqn_FStr8 =========================================================================
|
||||||
// NOTE: API =======================================================================================
|
// NOTE: API =======================================================================================
|
||||||
// @proc Dqn_FString8_InitF
|
// @proc Dqn_FStr8_InitF
|
||||||
// @desc Create a fixed string from the format string. The result string is
|
// @desc Create a fixed string from the format string. The result string is
|
||||||
// null-terminated.
|
// null-terminated.
|
||||||
// @param fmt[in] Format string specifier to create the fixed string from
|
// @param fmt[in] Format string specifier to create the fixed string from
|
||||||
// @return The created string, truncated if there was insufficient space
|
// @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
|
// @desc @param string[in] The string to query the maximum capacity of
|
||||||
// @return Maximum capacity of the fixed string
|
// @return Maximum capacity of the fixed string
|
||||||
|
|
||||||
// @proc Dqn_FString8_Clear
|
// @proc Dqn_FStr8_Clear
|
||||||
// @desc Reset the characters in the string
|
// @desc Reset the characters in the string
|
||||||
// @param string[in] The string to clear
|
// @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
|
// @desc Append a format string to the fixed string. On failure the string is
|
||||||
// appended to but truncated ensuring null-termination.
|
// appended to but truncated ensuring null-termination.
|
||||||
// @param string[in] The string to append to
|
// @param string[in] The string to append to
|
||||||
// @param fmt[in] Format string to append to the fixed string
|
// @param fmt[in] Format string to append to the fixed string
|
||||||
// @return True if append was successful, false otherwise.
|
// @return True if append was successful, false otherwise.
|
||||||
|
|
||||||
// @proc Dqn_FString8_AppendF
|
// @proc Dqn_FStr8_AppendF
|
||||||
// @desc @copydocs Dqn_FString8_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
|
// @desc Append a cstring to the fixed string. On failure the string is
|
||||||
// appended to but truncated ensuring null-termination.
|
// appended to but truncated ensuring null-termination.
|
||||||
// @param string[in] The string to append to
|
// @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
|
// @param size[in] Size of the cstring
|
||||||
// @return True if append was successful, false otherwise.
|
// @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
|
// @desc Append a string to the fixed string. On failure the string is
|
||||||
// appended to but truncated ensuring null-termination.
|
// appended to but truncated ensuring null-termination.
|
||||||
// @param string[in] The string to append to
|
// @param string[in] The string to append to
|
||||||
@ -399,38 +404,38 @@ DQN_API bool operator!= (Dqn_Stri
|
|||||||
// determined before appending.
|
// determined before appending.
|
||||||
// @return True if append was successful, false otherwise.
|
// @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
|
// @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.
|
// fixed string and is invalidated once fixed string is deleted.
|
||||||
// @param string[in] The fixed string to create a string from
|
// @param string[in] The fixed string to create a string from
|
||||||
// @return String referencing the contents of `string`
|
// @return String referencing the contents of `string`
|
||||||
|
|
||||||
// @proc Dqn_FString8_Eq
|
// @proc Dqn_FStr8_Eq
|
||||||
// @desc @see Dqn_String8_Eq
|
// @desc @see Dqn_Str8_Eq
|
||||||
|
|
||||||
// @proc Dqn_FString8_EqString8
|
// @proc Dqn_FStr8_EqStr8
|
||||||
// @desc @see Dqn_String8_Eq
|
// @desc @see Dqn_Str8_Eq
|
||||||
|
|
||||||
// @proc Dqn_FString8_EqInsensitive
|
// @proc Dqn_FStr8_EqInsensitive
|
||||||
// @desc Compare a string for equality, case insensitive
|
// @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
|
// @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];
|
char data[N+1];
|
||||||
Dqn_usize size;
|
Dqn_usize size;
|
||||||
|
|
||||||
bool operator==(Dqn_FString8 const &other) const {
|
bool operator==(Dqn_FStr8 const &other) const {
|
||||||
if (size != other.size) return false;
|
if (size != other.size) return false;
|
||||||
bool result = DQN_MEMCMP(data, other.data, size);
|
bool result = DQN_MEMCMP(data, other.data, size);
|
||||||
return result;
|
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 *begin() { return data; }
|
||||||
char *end () { return data + size; }
|
char *end () { return data + size; }
|
||||||
@ -438,26 +443,26 @@ template <Dqn_usize N> struct Dqn_FString8
|
|||||||
char const *end () const { return data + size; }
|
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_FStr8<N> Dqn_FStr8_InitF (DQN_FMT_ATTRIB char const *fmt, ...);
|
||||||
template <Dqn_usize N> Dqn_usize Dqn_FString8_Max (Dqn_FString8<N> const *string);
|
template <Dqn_usize N> Dqn_usize Dqn_FStr8_Max (Dqn_FStr8<N> const *string);
|
||||||
template <Dqn_usize N> void Dqn_FString8_Clear (Dqn_FString8<N> *string);
|
template <Dqn_usize N> void Dqn_FStr8_Clear (Dqn_FStr8<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_FStr8_AppendFV (Dqn_FStr8<N> *string, DQN_FMT_ATTRIB 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_FStr8_AppendF (Dqn_FStr8<N> *string, DQN_FMT_ATTRIB 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_FStr8_AppendCStr8 (Dqn_FStr8<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> bool Dqn_FStr8_Append (Dqn_FStr8<N> *string, Dqn_Str8 value);
|
||||||
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);
|
||||||
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);
|
||||||
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);
|
||||||
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);
|
||||||
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);
|
||||||
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);
|
||||||
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);
|
||||||
#endif // !defined(DQN_NO_FSTRING8)
|
#endif // !defined(DQN_NO_FSTR8)
|
||||||
|
|
||||||
// NOTE: [$STRB] Dqn_String8Builder ================================================================
|
// NOTE: [$STRB] Dqn_Str8Builder ================================================================
|
||||||
// NOTE: API =======================================================================================
|
// NOTE: API =======================================================================================
|
||||||
// @proc Dqn_String8Builder_AppendRef, Dqn_String8_AppendCopy,
|
// @proc Dqn_Str8Builder_AppendRef, Dqn_Str8_AppendCopy,
|
||||||
// Dqn_String8_AppendFV, Dqn_String8_AppendF
|
// Dqn_Str8_AppendFV, Dqn_Str8_AppendF
|
||||||
// @desc Append a string to the list of strings in the builder.
|
// @desc Append a string to the list of strings in the builder.
|
||||||
//
|
//
|
||||||
// The string is appended to the builder as follows
|
// 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
|
// @return True if append was successful, false if parameters are invalid
|
||||||
// or memory allocation failure.
|
// 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
|
// @desc Build the list of strings into the final composite string from the
|
||||||
// string builder
|
// string builder
|
||||||
// @param builder The string builder to build the string from
|
// @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
|
// @return The string if build was successful, empty string if parameters are
|
||||||
// invalid or memory allocation failure.
|
// invalid or memory allocation failure.
|
||||||
|
|
||||||
struct Dqn_String8Builder
|
struct Dqn_Str8Builder
|
||||||
{
|
{
|
||||||
Dqn_Allocator allocator; ///< Allocator to use to back the string list
|
Dqn_Allocator allocator; ///< Allocator to use to back the string list
|
||||||
Dqn_String8Link *head; ///< First string in the linked list of strings
|
Dqn_Str8Link *head; ///< First string in the linked list of strings
|
||||||
Dqn_String8Link *tail; ///< Last 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 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_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_Str8Builder_AppendF (Dqn_Str8Builder *builder, DQN_FMT_ATTRIB 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_Str8Builder_AppendFV (Dqn_Str8Builder *builder, DQN_FMT_ATTRIB char const *fmt, va_list args);
|
||||||
DQN_API bool Dqn_String8Builder_AppendRef (Dqn_String8Builder *builder, Dqn_String8 string);
|
DQN_API bool Dqn_Str8Builder_AppendRef (Dqn_Str8Builder *builder, Dqn_Str8 string);
|
||||||
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_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);
|
||||||
|
|
||||||
// NOTE: [$CHAR] Dqn_Char ==========================================================================
|
// NOTE: [$CHAR] Dqn_Char ==========================================================================
|
||||||
DQN_API bool Dqn_Char_IsAlphabet (char ch);
|
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_UTF8_EncodeCodepoint(uint8_t utf8[4], uint32_t codepoint);
|
||||||
DQN_API int Dqn_UTF16_EncodeCodepoint(uint16_t utf16[2], uint32_t codepoint);
|
DQN_API int Dqn_UTF16_EncodeCodepoint(uint16_t utf16[2], uint32_t codepoint);
|
||||||
|
|
||||||
#if !defined(DQN_NO_FSTRING8)
|
#if !defined(DQN_NO_FSTR8)
|
||||||
// NOTE: [$FSTR] Dqn_FString8 ======================================================================
|
// NOTE: [$FSTR] Dqn_FStr8 ======================================================================
|
||||||
template <Dqn_usize N> Dqn_FString8<N> Dqn_FString8_InitF(DQN_FMT_STRING_ANNOTATE char const *fmt, ...)
|
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) {
|
if (fmt) {
|
||||||
va_list args;
|
va_list args;
|
||||||
va_start(args, fmt);
|
va_start(args, fmt);
|
||||||
Dqn_FString8_AppendFV(&result, fmt, args);
|
Dqn_FStr8_AppendFV(&result, fmt, args);
|
||||||
va_end(args);
|
va_end(args);
|
||||||
}
|
}
|
||||||
return result;
|
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;
|
Dqn_usize result = N;
|
||||||
return result;
|
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 = {};
|
*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;
|
bool result = false;
|
||||||
if (!string || !fmt)
|
if (!string || !fmt)
|
||||||
return result;
|
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;
|
Dqn_usize space = (N + 1) - string->size;
|
||||||
result = require <= space;
|
result = require <= space;
|
||||||
string->size += STB_SPRINTF_DECORATE(vsnprintf)(string->data + string->size, DQN_CAST(int)space, fmt, args);
|
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;
|
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;
|
bool result = false;
|
||||||
if (!string || !fmt)
|
if (!string || !fmt)
|
||||||
return result;
|
return result;
|
||||||
va_list args;
|
va_list args;
|
||||||
va_start(args, fmt);
|
va_start(args, fmt);
|
||||||
result = Dqn_FString8_AppendFV(string, fmt, args);
|
result = Dqn_FStr8_AppendFV(string, fmt, args);
|
||||||
va_end(args);
|
va_end(args);
|
||||||
return result;
|
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);
|
DQN_ASSERT(string->size <= N);
|
||||||
bool result = false;
|
bool result = false;
|
||||||
@ -579,15 +584,15 @@ template <Dqn_usize N> bool Dqn_FString8_AppendCString8(Dqn_FString8<N> *string,
|
|||||||
return result;
|
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;
|
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)
|
if (!string || string->size <= 0)
|
||||||
return result;
|
return result;
|
||||||
|
|
||||||
@ -596,49 +601,49 @@ template <Dqn_usize N> Dqn_String8 Dqn_FString8_ToString8(Dqn_FString8<N> const
|
|||||||
return result;
|
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_Str8 lhs_s8 = Dqn_FStr8_ToStr8(lhs);
|
||||||
Dqn_String8 rhs_s8 = Dqn_FString8_ToString8(rhs);
|
Dqn_Str8 rhs_s8 = Dqn_FStr8_ToStr8(rhs);
|
||||||
bool result = Dqn_String8_Eq(lhs_s8, rhs_s8, eq_case);
|
bool result = Dqn_Str8_Eq(lhs_s8, rhs_s8, eq_case);
|
||||||
return result;
|
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);
|
Dqn_Str8 lhs_s8 = Dqn_FStr8_ToStr8(lhs);
|
||||||
bool result = Dqn_String8_Eq(lhs_s8, rhs, eq_case);
|
bool result = Dqn_Str8_Eq(lhs_s8, rhs, eq_case);
|
||||||
return result;
|
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_Str8 lhs_s8 = Dqn_FStr8_ToStr8(lhs);
|
||||||
Dqn_String8 rhs_s8 = Dqn_FString8_ToString8(rhs);
|
Dqn_Str8 rhs_s8 = Dqn_FStr8_ToStr8(rhs);
|
||||||
bool result = Dqn_String8_Eq(lhs_s8, rhs_s8, Dqn_String8EqCase_Insensitive);
|
bool result = Dqn_Str8_Eq(lhs_s8, rhs_s8, Dqn_Str8EqCase_Insensitive);
|
||||||
return result;
|
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);
|
Dqn_Str8 lhs_s8 = Dqn_FStr8_ToStr8(lhs);
|
||||||
bool result = Dqn_String8_Eq(lhs_s8, rhs, Dqn_String8EqCase_Insensitive);
|
bool result = Dqn_Str8_Eq(lhs_s8, rhs, Dqn_Str8EqCase_Insensitive);
|
||||||
return result;
|
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_Str8 lhs_s8 = Dqn_FStr8_ToStr8(lhs);
|
||||||
Dqn_String8 rhs_s8 = Dqn_FString8_ToString8(rhs);
|
Dqn_Str8 rhs_s8 = Dqn_FStr8_ToStr8(rhs);
|
||||||
bool result = Dqn_String8_Eq(lhs_s8, rhs_s8, eq_case);
|
bool result = Dqn_Str8_Eq(lhs_s8, rhs_s8, eq_case);
|
||||||
return result;
|
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_Str8 lhs_s8 = Dqn_FStr8_ToStr8(lhs);
|
||||||
Dqn_String8 rhs_s8 = Dqn_FString8_ToString8(rhs);
|
Dqn_Str8 rhs_s8 = Dqn_FStr8_ToStr8(rhs);
|
||||||
bool result = Dqn_String8_Eq(lhs_s8, rhs_s8, Dqn_String8EqCase_Insensitive);
|
bool result = Dqn_Str8_Eq(lhs_s8, rhs_s8, Dqn_Str8EqCase_Insensitive);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
#endif // !defined(DQN_NO_FSTRING8)
|
#endif // !defined(DQN_NO_FSTR8)
|
||||||
|
38
dqn_win32.h
38
dqn_win32.h
@ -330,6 +330,9 @@
|
|||||||
} OVERLAPPED, *LPOVERLAPPED;
|
} OVERLAPPED, *LPOVERLAPPED;
|
||||||
|
|
||||||
// NOTE: um/winbase.h ==========================================================================
|
// 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 INFINITE 0xFFFFFFFF // Wait/Synchronisation: Infinite timeout
|
||||||
|
|
||||||
#define STD_INPUT_HANDLE ((DWORD)-10)
|
#define STD_INPUT_HANDLE ((DWORD)-10)
|
||||||
@ -345,6 +348,9 @@
|
|||||||
#define FORMAT_MESSAGE_FROM_HMODULE 0x00000800
|
#define FORMAT_MESSAGE_FROM_HMODULE 0x00000800
|
||||||
#define FORMAT_MESSAGE_FROM_SYSTEM 0x00001000
|
#define FORMAT_MESSAGE_FROM_SYSTEM 0x00001000
|
||||||
|
|
||||||
|
// NOTE: CreateProcessW
|
||||||
|
#define STARTF_USESTDHANDLES 0x00000100
|
||||||
|
|
||||||
extern "C"
|
extern "C"
|
||||||
{
|
{
|
||||||
__declspec(dllimport) BOOL __stdcall MoveFileExW (const WCHAR *lpExistingFileName, const WCHAR *lpNewFileName, DWORD dwFlags);
|
__declspec(dllimport) BOOL __stdcall MoveFileExW (const WCHAR *lpExistingFileName, const WCHAR *lpNewFileName, DWORD dwFlags);
|
||||||
@ -708,6 +714,34 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
// NOTE: um/processthreadsapi.h ================================================================
|
// 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)(
|
typedef DWORD (__stdcall *PTHREAD_START_ROUTINE)(
|
||||||
VOID *lpThreadParameter
|
VOID *lpThreadParameter
|
||||||
);
|
);
|
||||||
@ -715,8 +749,12 @@
|
|||||||
|
|
||||||
extern "C"
|
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) 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) DWORD __stdcall GetCurrentThreadId(VOID);
|
||||||
|
__declspec(dllimport) BOOL __stdcall GetExitCodeProcess(HANDLE hProcess, DWORD *lpExitCode);
|
||||||
|
__declspec(dllimport) void __stdcall ExitProcess(UINT uExitCode);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// NOTE: um/memoryapi.h ========================================================================
|
// NOTE: um/memoryapi.h ========================================================================
|
||||||
|
Loading…
Reference in New Issue
Block a user