From 7147ad52a2aa4f515ca24c122bd3a6a491384c9c Mon Sep 17 00:00:00 2001 From: doylet Date: Mon, 19 Oct 2026 12:21:40 +1100 Subject: [PATCH] Get latest upstream changes from internal project --- Single-Header/dn_single_header.cpp | 2367 +++++++++++++++++----------- Single-Header/dn_single_header.h | 2258 ++++++++++++++------------ Source/OS/dn_os_posix.cpp | 57 + Source/OS/dn_os_w32.cpp | 274 ++-- Source/OS/dn_os_w32.h | 89 +- Source/OS/dn_os_windows.h | 37 +- Source/Standalone/dn_ini.h | 2 +- Source/dn.cpp | 2034 ++++++++++++++---------- Source/dn.h | 2130 +++++++++++++------------ single_header_generator.cpp | 6 +- 10 files changed, 5428 insertions(+), 3826 deletions(-) diff --git a/Single-Header/dn_single_header.cpp b/Single-Header/dn_single_header.cpp index 1c6749d..6b9a28a 100644 --- a/Single-Header/dn_single_header.cpp +++ b/Single-Header/dn_single_header.cpp @@ -1,4 +1,4 @@ -// Generated by the DN single header generator 2026-10-03 22:35:58 +// Generated by the DN single header generator 2026-10-19 12:20:48 // DN: Single header generator commented out => #if defined(_CLANGD) // #define DN_WITH_TESTS 1 @@ -22,8 +22,134 @@ enum DN_ArenaUAFCheckReportType_ DN_Core *g_dn_; +#if DN_MEM_DEBUGGER +static void DN_MemDebuggerMemListRegister_(DN_MemList *mem) +{ + DN_Core *dn = g_dn_; + if (!dn || !mem || !dn->mem_debugger.mem_list_table.kvs) + return; + DN_TicketMutexBegin(&dn->mem_debugger.mem_list_mutex); + DN_HTableAddResult add = DN_HTableMake(&dn->mem_debugger.mem_list_table, &mem); + DN_MemDebuggerMemList *entry = DN_Cast(DN_MemDebuggerMemList *) add.slot.value; + if (entry) { + entry->mem_list = mem; + if (!add.existed) { + entry->allocs = nullptr; + entry->allocs_count = 0; + entry->allocs_max = 0; + } + } + DN_TicketMutexEnd(&dn->mem_debugger.mem_list_mutex); +} + +static void DN_MemDebuggerMemListUnregister_(DN_MemList *mem) +{ + DN_Core *dn = g_dn_; + if (!dn || !mem || !dn->mem_debugger.mem_list_table.kvs) + return; + DN_TicketMutexBegin(&dn->mem_debugger.mem_list_mutex); + DN_MemDebuggerMemList *entry = DN_Cast(DN_MemDebuggerMemList *) DN_HTableValueFromFind(&dn->mem_debugger.mem_list_table, &mem); + if (entry && entry->allocs) { + DN_HeapDealloc(&dn->mem_debugger.heap, entry->allocs, entry->allocs_max * sizeof(DN_MemDebuggerMemListAlloc)); + entry->allocs = nullptr; + entry->allocs_count = 0; + entry->allocs_max = 0; + } + DN_HTableDel(&dn->mem_debugger.mem_list_table, &mem); + DN_TicketMutexEnd(&dn->mem_debugger.mem_list_mutex); +} + +static void DN_MemDebuggerMemListAllocTrack_(DN_MemList *mem, void *ptr, DN_U64 size, DN_U64 alloc_size, DN_U8 align, DN_CallSite call_site) +{ + DN_Core *dn = g_dn_; + if (!dn || !mem || !ptr || !dn->mem_debugger.mem_list_table.kvs) + return; + + // NOTE: Excluded heaps are not tracked (e.g. the debugger's own snapshot arena while the snapshot + // holds the alloc table mutex). + if (DN_BitIsSet(mem->heap.flags, DN_HeapFlags_ExcludeFromMemDebugger)) + return; + + DN_TicketMutexBegin(&dn->mem_debugger.mem_list_mutex); + DN_MemDebuggerMemList *entry = DN_Cast(DN_MemDebuggerMemList *) DN_HTableValueFromFind(&dn->mem_debugger.mem_list_table, &mem); + if (entry) { + DN_TicketMutexBegin(&entry->alloc_mutex); + DN_MemDebuggerMemListAlloc alloc = {}; + alloc.ptr = ptr; + alloc.size = size; + alloc.alloc_size = alloc_size; + alloc.position = DN_MemListPos(mem) - size; + alloc.align = align; + alloc.call_site = call_site; + DN_PArrayAppendHeap(entry->allocs, &entry->allocs_count, &entry->allocs_max, &dn->mem_debugger.heap, alloc); + DN_TicketMutexEnd(&entry->alloc_mutex); + } + DN_TicketMutexEnd(&dn->mem_debugger.mem_list_mutex); +} + +static void DN_MemDebuggerMemListAllocsSync_(DN_MemList *mem) +{ + DN_Core *dn = g_dn_; + if (!dn || !mem || !dn->mem_debugger.mem_list_table.kvs) + return; + if (DN_BitIsSet(mem->heap.flags, DN_HeapFlags_ExcludeFromMemDebugger)) + return; + + // NOTE: The tail block's used watermark (absolute list position). Any tracked allocation whose data + // ends above it was freed by the reset and can be dropped. Allocations are appended in ascending + // list-position order, so the freed ones form a suffix that we pop off. No block walk required. + DN_U64 live_end = DN_MemListPos(mem); + + DN_TicketMutexBegin(&dn->mem_debugger.mem_list_mutex); + DN_MemDebuggerMemList *entry = DN_Cast(DN_MemDebuggerMemList *) DN_HTableValueFromFind(&dn->mem_debugger.mem_list_table, &mem); + if (entry) { + DN_TicketMutexBegin(&entry->alloc_mutex); + while (entry->allocs_count && entry->allocs[entry->allocs_count - 1].position + entry->allocs[entry->allocs_count - 1].size > live_end) + entry->allocs_count--; + DN_TicketMutexEnd(&entry->alloc_mutex); + } + DN_TicketMutexEnd(&dn->mem_debugger.mem_list_mutex); +} +#else + #define DN_MemDebuggerMemListRegister_(mem) ((void)(mem)) + #define DN_MemDebuggerMemListUnregister_(mem) ((void)(mem)) + #define DN_MemDebuggerMemListAllocTrack_(mem, ptr, size, alloc_size, align, call_site) ((void)0) + #define DN_MemDebuggerMemListAllocsSync_(mem) ((void)(mem)) +#endif + +#if DN_MEM_DEBUGGER +static void DN_MemDebuggerCommitUpdateLocked_(DN_MemDebugger *debugger, DN_MemBlock *block) +{ + DN_UPtr uptr = DN_Cast(DN_UPtr) block; + DN_MemDebuggerPtrData *alloc = DN_Cast(DN_MemDebuggerPtrData *) DN_HTableValueFromFind(&debugger->alloc_table, &uptr); + if (alloc && (alloc->flags & DN_MemDebuggerPtrFlag_Freed) == 0) + alloc->bytes[DN_MemDebuggerAllocType_Commit] = block->commit; +} + +static void DN_MemDebuggerCommitUpdate_(DN_MemList *mem, DN_MemBlock *block) +{ + DN_Core *dn = g_dn_; + if (!dn || !mem || !block || !dn->mem_debugger.alloc_table.kvs) + return; + + // NOTE: Excluded heaps are not tracked by the debugger, and the snapshot holds the alloc table + // mutex while it allocates from its own (excluded) arena, so skip excluded heaps to avoid a + // re-entrant deadlock. + if (DN_BitIsSet(mem->heap.flags, DN_HeapFlags_ExcludeFromMemDebugger)) + return; + + DN_TicketMutexBegin(&dn->mem_debugger.alloc_table_mutex); + DN_MemDebuggerCommitUpdateLocked_(&dn->mem_debugger, block); + DN_TicketMutexEnd(&dn->mem_debugger.alloc_table_mutex); +} +#else + #define DN_MemDebuggerCommitUpdate_(mem, block) ((void)(mem), (void)(block)) + #define DN_MemDebuggerCommitUpdateLocked_(debugger, block) ((void)(debugger), (void)(block)) +#endif + DN_API void DN_Init(DN_Core *dn, DN_InitFlags flags, DN_TcInitArgs args) { + (void)args; DN_Set(dn); dn->init_flags = flags; @@ -61,7 +187,7 @@ DN_API void DN_Init(DN_Core *dn, DN_InitFlags flags, DN_TcInitArgs args) heap.flags |= DN_HeapFlags_ExcludeFromMemDebugger; os->mem = DN_MemListFromHeap(DN_Megabytes(1), DN_Kilobytes(4), DN_MemFlags_Nil, heap, "DN OS MemList"); - os->arena = DN_ArenaFromMemList(&os->mem); + os->arena = DN_ArenaFromMemList(os->mem); #if defined(DN_PLATFORM_WIN32) os->platform_context = DN_ArenaNew(&os->arena, DN_OSW32Core, DN_ZMem_Yes); @@ -81,32 +207,41 @@ DN_API void DN_Init(DN_Core *dn, DN_InitFlags flags, DN_TcInitArgs args) #if DN_MEM_DEBUGGER // NOTE: Setup the mem debugger table with allocation tracking turned off on because we're // allocating before we've setup the table to track allocations itself (and would otherwise cause an recursive loop). - DN_Heap heap = DN_OS_HeapInitBasic(); - heap.flags |= DN_HeapFlags_ExcludeFromMemDebugger; + dn->mem_debugger.heap = DN_OS_HeapInitBasic(); + dn->mem_debugger.heap.flags |= DN_HeapFlags_ExcludeFromMemDebugger; + if (DN_BitIsSet(flags, DN_InitFlags_MemDebuggerHeapAllocCallSiteStrings)) + dn->mem_debugger.flags |= DN_MemDebuggerFlags_HeapAllocCallSiteStrings; + DN_CallSite alloc_call_site = DN_CallSiteNowNamed("DN Memory Debugger Hash Table"); DN_HTableInitArgs table_args = DN_HTableInitArgsDefault(DN_MemDebuggerKV, dn->mem_debugger.alloc_table_kvs, hash, key, value); - dn->mem_debugger.alloc_table = DN_HTableInitHeapAssert(table_args, heap); + dn->mem_debugger.alloc_table = DN_HTableInitHeapAssert(table_args, &dn->mem_debugger.heap); - // NOTE: Unset the exclusion flag and manually add the pointers we allocator - os->mem.heap.flags &= ~DN_HeapFlags_ExcludeFromMemDebugger; + DN_HTableInitArgs mem_list_table_args = DN_HTableInitArgsDefault(DN_MemDebuggerMemListKV, dn->mem_debugger.mem_list_kvs, hash, key, value); + dn->mem_debugger.mem_list_table = DN_HTableInitHeapAssert(mem_list_table_args, &dn->mem_debugger.heap); + + // NOTE: Unset the exclusion flag and manually add the pointers we allocated + os->mem->heap.flags &= ~DN_HeapFlags_ExcludeFromMemDebugger; for (DN_MemBlock *block = os->arena.mem->curr; block; block = block->prev) - DN_MemDebuggerAlloc(&dn->mem_debugger, block, block->reserve, /*alloc_can_leak=*/true, alloc_call_site); + DN_MemDebuggerAlloc(&dn->mem_debugger, block, block->reserve, block->commit, /*alloc_can_leak=*/true, alloc_call_site); + + // NOTE: The OS mem list was created before the registry existed, register it now + DN_MemDebuggerMemListRegister_(os->mem); #endif } - os->cpu_report = DN_CPUGetReport(); + os->cpu_report = DN_CpuGetReport(); - #define DN_CPU_FEAT_XENTRY(label) g_dn_cpu_feature_decl[DN_CPUFeature_##label] = {DN_CPUFeature_##label, DN_Str8Lit(#label)}; - DN_CPU_FEAT_XMACRO - #undef DN_CPU_FEAT_XENTRY + #define DN_Cpu_FEAT_XENTRY(label) g_dn_cpu_feature_decl[DN_CpuFeature_##label] = {DN_CpuFeature_##label, DN_Str8Lit(#label)}; + DN_Cpu_FEAT_XMACRO + #undef DN_Cpu_FEAT_XENTRY DN_Assert(g_dn_); - #endif // NOTE: Initialise thread context DN_Heap tc_heap = DN_OS_HeapInitDefault(); tc_heap.flags |= DN_HeapFlags_MemDebuggerCanLeakPtr; DN_TcInitFromHeap(&dn->main_tc, DN_OS_ThreadID(), args, tc_heap); DN_TcEquip(&dn->main_tc); + #endif // DN_WITH_OS } // NOTE: Print out init features @@ -174,19 +309,19 @@ DN_API void DN_Init(DN_Core *dn, DN_InitFlags flags, DN_TcInitArgs args) if (DN_BitIsSet(flags, DN_InitFlags_LogCPUFeatures)) { DN_Assert(dn->os_init); #if DN_WITH_OS - DN_CPUReport const *report = &dn->os.cpu_report; + DN_CpuReport const *report = &dn->os.cpu_report; DN_Str8 brand = DN_Str8TrimWhitespaceAround(DN_Str8FromPtr(report->brand, sizeof(report->brand) - 1)); DN_FmtAppendTruncate(buf, &buf_size, sizeof(buf), DN_Str8Lit("..."), " CPU '%.*s' from '%s' detected:\n", DN_Str8PrintFmt(brand), report->vendor); DN_USize longest_feature_name = 0; - for (DN_ForIndexU(feature_index, DN_CPUFeature_Count)) { - DN_CPUFeatureDecl feature_decl = g_dn_cpu_feature_decl[feature_index]; + for (DN_ForIndexU(feature_index, DN_CpuFeature_Count)) { + DN_CpuFeatureDecl feature_decl = g_dn_cpu_feature_decl[feature_index]; longest_feature_name = DN_Max(longest_feature_name, feature_decl.label.count); } - for (DN_ForIndexU(feature_index, DN_CPUFeature_Count)) { - DN_CPUFeatureDecl feature_decl = g_dn_cpu_feature_decl[feature_index]; - bool has_feature = DN_CPUHasFeature(report, feature_decl.value); + for (DN_ForIndexU(feature_index, DN_CpuFeature_Count)) { + DN_CpuFeatureDecl feature_decl = g_dn_cpu_feature_decl[feature_index]; + bool has_feature = DN_CpuHasFeature(report, feature_decl.value); DN_FmtAppendTruncate(buf, &buf_size, sizeof(buf), @@ -207,6 +342,7 @@ DN_API void DN_Init(DN_Core *dn, DN_InitFlags flags, DN_TcInitArgs args) DN_API void DN_Set(DN_Core *dn) { g_dn_ = dn; + DN_TcEquip(&dn->main_tc); } DN_API DN_Core *DN_Get() @@ -296,7 +432,7 @@ DN_API bool DN_MemEqUnsafe(void const *lhs, void const *rhs, DN_USize count) #include #endif -DN_CPUFeatureDecl g_dn_cpu_feature_decl[DN_CPUFeature_Count]; +DN_CpuFeatureDecl g_dn_cpu_feature_decl[DN_CpuFeature_Count]; DN_API DN_U64 DN_AtomicSetValue64(DN_U64 volatile *target, DN_U64 value) { @@ -364,21 +500,21 @@ DN_API void DN_ByteSwapU64Ptr(DN_U8 *dest, DN_U64 src) dest[7] = DN_Cast(DN_U8)(src & 0xFF); } -DN_API DN_CPUIDResult DN_CPUID(DN_CPUIDArgs args) +DN_API DN_CpuIDResult DN_CpuID(DN_CpuIDArgs args) { - DN_CPUIDResult result = {}; + DN_CpuIDResult result = {}; #if defined(DN_SUPPORTS_CPU_ID) __cpuidex(result.values, args.eax, args.ecx); #endif return result; } -DN_API DN_USize DN_CPUHasFeatureArray(DN_CPUReport const *report, DN_CPUFeatureQuery *features, DN_USize features_size) +DN_API DN_USize DN_CpuHasFeatureArray(DN_CpuReport const *report, DN_CpuFeatureQuery *features, DN_USize features_size) { DN_USize result = 0; DN_USize const BITS = sizeof(report->features[0]) * 8; for (DN_ForIndexU(feature_index, features_size)) { - DN_CPUFeatureQuery *query = features + feature_index; + DN_CpuFeatureQuery *query = features + feature_index; DN_USize chunk_index = query->feature / BITS; DN_USize chunk_bit = query->feature % BITS; DN_U64 chunk = report->features[chunk_index]; @@ -389,52 +525,52 @@ DN_API DN_USize DN_CPUHasFeatureArray(DN_CPUReport const *report, DN_CPUFeatureQ return result; } -DN_API bool DN_CPUHasFeature(DN_CPUReport const *report, DN_CPUFeature feature) +DN_API bool DN_CpuHasFeature(DN_CpuReport const *report, DN_CpuFeature feature) { - DN_CPUFeatureQuery query = {}; + DN_CpuFeatureQuery query = {}; query.feature = feature; - bool result = DN_CPUHasFeatureArray(report, &query, 1) == 1; + bool result = DN_CpuHasFeatureArray(report, &query, 1) == 1; return result; } -DN_API bool DN_CPUHasAllFeatures(DN_CPUReport const *report, DN_CPUFeature const *features, DN_USize features_size) +DN_API bool DN_CpuHasAllFeatures(DN_CpuReport const *report, DN_CpuFeature const *features, DN_USize features_size) { bool result = true; for (DN_USize index = 0; result && index < features_size; index++) - result &= DN_CPUHasFeature(report, features[index]); + result &= DN_CpuHasFeature(report, features[index]); return result; } -DN_API void DN_CPUSetFeature(DN_CPUReport *report, DN_CPUFeature feature) +DN_API void DN_CpuSetFeature(DN_CpuReport *report, DN_CpuFeature feature) { - DN_Assert(feature < DN_CPUFeature_Count); + DN_Assert(feature < DN_CpuFeature_Count); DN_USize const BITS = sizeof(report->features[0]) * 8; DN_USize chunk_index = feature / BITS; DN_USize chunk_bit = feature % BITS; report->features[chunk_index] |= (1ULL << chunk_bit); } -DN_API DN_CPUReport DN_CPUGetReport() +DN_API DN_CpuReport DN_CpuGetReport() { - DN_CPUReport result = {}; + DN_CpuReport result = {}; #if defined(DN_SUPPORTS_CPU_ID) - DN_CPUIDResult fn_0000_[500] = {}; - DN_CPUIDResult fn_8000_[500] = {}; + DN_CpuIDResult fn_0000_[500] = {}; + DN_CpuIDResult fn_8000_[500] = {}; int const EXTENDED_FUNC_BASE_EAX = 0x8000'0000; int const REGISTER_SIZE = sizeof(fn_0000_[0].reg.eax); // NOTE: Query standard/extended numbers { - DN_CPUIDArgs args = {}; + DN_CpuIDArgs args = {}; // NOTE: Query standard function (e.g. eax = 0x0) for function count + cpu vendor args = {}; - fn_0000_[0] = DN_CPUID(args); + fn_0000_[0] = DN_CpuID(args); // NOTE: Query extended function (e.g. eax = 0x8000'0000) for function count + cpu vendor args = {}; args.eax = DN_Cast(int) EXTENDED_FUNC_BASE_EAX; - fn_8000_[0] = DN_CPUID(args); + fn_8000_[0] = DN_CpuID(args); } // NOTE: Extract function count @@ -451,15 +587,15 @@ DN_API DN_CPUReport DN_CPUGetReport() DN_Cast(DN_ISize) EXTENDED_FUNC_MAX_EAX - EXTENDED_FUNC_BASE_EAX + 1); for (int eax = 1; eax <= STANDARD_FUNC_MAX_EAX; eax++) { - DN_CPUIDArgs args = {}; + DN_CpuIDArgs args = {}; args.eax = eax; - fn_0000_[eax] = DN_CPUID(args); + fn_0000_[eax] = DN_CpuID(args); } for (int eax = EXTENDED_FUNC_BASE_EAX + 1, index = 1; eax <= EXTENDED_FUNC_MAX_EAX; eax++, index++) { - DN_CPUIDArgs args = {}; + DN_CpuIDArgs args = {}; args.eax = eax; - fn_8000_[index] = DN_CPUID(args); + fn_8000_[index] = DN_CpuID(args); } } @@ -491,77 +627,83 @@ DN_API DN_CPUReport DN_CPUGetReport() } // NOTE: Query CPU features - for (DN_USize ext_index = 0; ext_index < DN_CPUFeature_Count; ext_index++) { + for (DN_USize ext_index = 0; ext_index < DN_CpuFeature_Count; ext_index++) { bool available = false; // NOTE: Mask bits taken from various manuals // - AMD64 Architecture Programmer's Manual, Volumes 1-5 // - https://en.wikipedia.org/wiki/CPUID#Calling_CPUID - switch (DN_Cast(DN_CPUFeature) ext_index) { - case DN_CPUFeature_3DNow: available = (fn_8000_[0x0001].reg.edx & (1 << 31)); break; - case DN_CPUFeature_3DNowExt: available = (fn_8000_[0x0001].reg.edx & (1 << 30)); break; - case DN_CPUFeature_ABM: available = (fn_8000_[0x0001].reg.ecx & (1 << 5)); break; - case DN_CPUFeature_AES: available = (fn_0000_[0x0001].reg.ecx & (1 << 25)); break; - case DN_CPUFeature_AVX: available = (fn_0000_[0x0001].reg.ecx & (1 << 28)); break; - case DN_CPUFeature_AVX2: available = (fn_0000_[0x0007].reg.ebx & (1 << 0)); break; - case DN_CPUFeature_AVX512F: available = (fn_0000_[0x0007].reg.ebx & (1 << 16)); break; - case DN_CPUFeature_AVX512DQ: available = (fn_0000_[0x0007].reg.ebx & (1 << 17)); break; - case DN_CPUFeature_AVX512IFMA: available = (fn_0000_[0x0007].reg.ebx & (1 << 21)); break; - case DN_CPUFeature_AVX512PF: available = (fn_0000_[0x0007].reg.ebx & (1 << 26)); break; - case DN_CPUFeature_AVX512ER: available = (fn_0000_[0x0007].reg.ebx & (1 << 27)); break; - case DN_CPUFeature_AVX512CD: available = (fn_0000_[0x0007].reg.ebx & (1 << 28)); break; - case DN_CPUFeature_AVX512BW: available = (fn_0000_[0x0007].reg.ebx & (1 << 30)); break; - case DN_CPUFeature_AVX512VL: available = (fn_0000_[0x0007].reg.ebx & (1 << 31)); break; - case DN_CPUFeature_AVX512VBMI: available = (fn_0000_[0x0007].reg.ecx & (1 << 1)); break; - case DN_CPUFeature_AVX512VBMI2: available = (fn_0000_[0x0007].reg.ecx & (1 << 6)); break; - case DN_CPUFeature_AVX512VNNI: available = (fn_0000_[0x0007].reg.ecx & (1 << 11)); break; - case DN_CPUFeature_AVX512BITALG: available = (fn_0000_[0x0007].reg.ecx & (1 << 12)); break; - case DN_CPUFeature_AVX512VPOPCNTDQ: available = (fn_0000_[0x0007].reg.ecx & (1 << 14)); break; - case DN_CPUFeature_AVX5124VNNIW: available = (fn_0000_[0x0007].reg.edx & (1 << 2)); break; - case DN_CPUFeature_AVX5124FMAPS: available = (fn_0000_[0x0007].reg.edx & (1 << 3)); break; - case DN_CPUFeature_AVX512VP2INTERSECT: available = (fn_0000_[0x0007].reg.edx & (1 << 8)); break; - case DN_CPUFeature_AVX512FP16: available = (fn_0000_[0x0007].reg.edx & (1 << 23)); break; - case DN_CPUFeature_CLZERO: available = (fn_8000_[0x0008].reg.ebx & (1 << 0)); break; - case DN_CPUFeature_CMPXCHG8B: available = (fn_0000_[0x0001].reg.edx & (1 << 8)); break; - case DN_CPUFeature_CMPXCHG16B: available = (fn_0000_[0x0001].reg.ecx & (1 << 13)); break; - case DN_CPUFeature_F16C: available = (fn_0000_[0x0001].reg.ecx & (1 << 29)); break; - case DN_CPUFeature_FMA: available = (fn_0000_[0x0001].reg.ecx & (1 << 12)); break; - case DN_CPUFeature_FMA4: available = (fn_8000_[0x0001].reg.ecx & (1 << 16)); break; - case DN_CPUFeature_FP128: available = (fn_8000_[0x001A].reg.eax & (1 << 0)); break; - case DN_CPUFeature_FP256: available = (fn_8000_[0x001A].reg.eax & (1 << 2)); break; - case DN_CPUFeature_FPU: available = (fn_0000_[0x0001].reg.edx & (1 << 0)); break; - case DN_CPUFeature_MMX: available = (fn_0000_[0x0001].reg.edx & (1 << 23)); break; - case DN_CPUFeature_MONITOR: available = (fn_0000_[0x0001].reg.ecx & (1 << 3)); break; - case DN_CPUFeature_MOVBE: available = (fn_0000_[0x0001].reg.ecx & (1 << 22)); break; - case DN_CPUFeature_MOVU: available = (fn_8000_[0x001A].reg.eax & (1 << 1)); break; - case DN_CPUFeature_MmxExt: available = (fn_8000_[0x0001].reg.edx & (1 << 22)); break; - case DN_CPUFeature_PCLMULQDQ: available = (fn_0000_[0x0001].reg.ecx & (1 << 1)); break; - case DN_CPUFeature_POPCNT: available = (fn_0000_[0x0001].reg.ecx & (1 << 23)); break; - case DN_CPUFeature_RDRAND: available = (fn_0000_[0x0001].reg.ecx & (1 << 30)); break; - case DN_CPUFeature_RDSEED: available = (fn_0000_[0x0007].reg.ebx & (1 << 18)); break; - case DN_CPUFeature_RDTscP: available = (fn_8000_[0x0001].reg.edx & (1 << 27)); break; - case DN_CPUFeature_SHA: available = (fn_0000_[0x0007].reg.ebx & (1 << 29)); break; - case DN_CPUFeature_SSE: available = (fn_0000_[0x0001].reg.edx & (1 << 25)); break; - case DN_CPUFeature_SSE2: available = (fn_0000_[0x0001].reg.edx & (1 << 26)); break; - case DN_CPUFeature_SSE3: available = (fn_0000_[0x0001].reg.ecx & (1 << 0)); break; - case DN_CPUFeature_SSE41: available = (fn_0000_[0x0001].reg.ecx & (1 << 19)); break; - case DN_CPUFeature_SSE42: available = (fn_0000_[0x0001].reg.ecx & (1 << 20)); break; - case DN_CPUFeature_SSE4A: available = (fn_8000_[0x0001].reg.ecx & (1 << 6)); break; - case DN_CPUFeature_SSSE3: available = (fn_0000_[0x0001].reg.ecx & (1 << 9)); break; - case DN_CPUFeature_Tsc: available = (fn_0000_[0x0001].reg.edx & (1 << 4)); break; - case DN_CPUFeature_TscInvariant: available = (fn_8000_[0x0007].reg.edx & (1 << 8)); break; - case DN_CPUFeature_VAES: available = (fn_0000_[0x0007].reg.ecx & (1 << 9)); break; - case DN_CPUFeature_VPCMULQDQ: available = (fn_0000_[0x0007].reg.ecx & (1 << 10)); break; - case DN_CPUFeature_Count: DN_AssertInvalidCodePath; break; + switch (DN_Cast(DN_CpuFeature) ext_index) { + case DN_CpuFeature_3DNow: available = (fn_8000_[0x0001].reg.edx & (1 << 31)); break; + case DN_CpuFeature_3DNowExt: available = (fn_8000_[0x0001].reg.edx & (1 << 30)); break; + case DN_CpuFeature_ABM: available = (fn_8000_[0x0001].reg.ecx & (1 << 5)); break; + case DN_CpuFeature_AES: available = (fn_0000_[0x0001].reg.ecx & (1 << 25)); break; + case DN_CpuFeature_AVX: available = (fn_0000_[0x0001].reg.ecx & (1 << 28)); break; + case DN_CpuFeature_AVX2: available = (fn_0000_[0x0007].reg.ebx & (1 << 0)); break; + case DN_CpuFeature_AVX512F: available = (fn_0000_[0x0007].reg.ebx & (1 << 16)); break; + case DN_CpuFeature_AVX512DQ: available = (fn_0000_[0x0007].reg.ebx & (1 << 17)); break; + case DN_CpuFeature_AVX512IFMA: available = (fn_0000_[0x0007].reg.ebx & (1 << 21)); break; + case DN_CpuFeature_AVX512PF: available = (fn_0000_[0x0007].reg.ebx & (1 << 26)); break; + case DN_CpuFeature_AVX512ER: available = (fn_0000_[0x0007].reg.ebx & (1 << 27)); break; + case DN_CpuFeature_AVX512CD: available = (fn_0000_[0x0007].reg.ebx & (1 << 28)); break; + case DN_CpuFeature_AVX512BW: available = (fn_0000_[0x0007].reg.ebx & (1 << 30)); break; + case DN_CpuFeature_AVX512VL: available = (fn_0000_[0x0007].reg.ebx & (1 << 31)); break; + case DN_CpuFeature_AVX512VBMI: available = (fn_0000_[0x0007].reg.ecx & (1 << 1)); break; + case DN_CpuFeature_AVX512VBMI2: available = (fn_0000_[0x0007].reg.ecx & (1 << 6)); break; + case DN_CpuFeature_AVX512VNNI: available = (fn_0000_[0x0007].reg.ecx & (1 << 11)); break; + case DN_CpuFeature_AVX512BITALG: available = (fn_0000_[0x0007].reg.ecx & (1 << 12)); break; + case DN_CpuFeature_AVX512VPOPCNTDQ: available = (fn_0000_[0x0007].reg.ecx & (1 << 14)); break; + case DN_CpuFeature_AVX5124VNNIW: available = (fn_0000_[0x0007].reg.edx & (1 << 2)); break; + case DN_CpuFeature_AVX5124FMAPS: available = (fn_0000_[0x0007].reg.edx & (1 << 3)); break; + case DN_CpuFeature_AVX512VP2INTERSECT: available = (fn_0000_[0x0007].reg.edx & (1 << 8)); break; + case DN_CpuFeature_AVX512FP16: available = (fn_0000_[0x0007].reg.edx & (1 << 23)); break; + case DN_CpuFeature_CLZERO: available = (fn_8000_[0x0008].reg.ebx & (1 << 0)); break; + case DN_CpuFeature_CMPXCHG8B: available = (fn_0000_[0x0001].reg.edx & (1 << 8)); break; + case DN_CpuFeature_CMPXCHG16B: available = (fn_0000_[0x0001].reg.ecx & (1 << 13)); break; + case DN_CpuFeature_F16C: available = (fn_0000_[0x0001].reg.ecx & (1 << 29)); break; + case DN_CpuFeature_FMA: available = (fn_0000_[0x0001].reg.ecx & (1 << 12)); break; + case DN_CpuFeature_FMA4: available = (fn_8000_[0x0001].reg.ecx & (1 << 16)); break; + case DN_CpuFeature_FP128: available = (fn_8000_[0x001A].reg.eax & (1 << 0)); break; + case DN_CpuFeature_FP256: available = (fn_8000_[0x001A].reg.eax & (1 << 2)); break; + case DN_CpuFeature_FPU: available = (fn_0000_[0x0001].reg.edx & (1 << 0)); break; + case DN_CpuFeature_MMX: available = (fn_0000_[0x0001].reg.edx & (1 << 23)); break; + case DN_CpuFeature_MONITOR: available = (fn_0000_[0x0001].reg.ecx & (1 << 3)); break; + case DN_CpuFeature_MOVBE: available = (fn_0000_[0x0001].reg.ecx & (1 << 22)); break; + case DN_CpuFeature_MOVU: available = (fn_8000_[0x001A].reg.eax & (1 << 1)); break; + case DN_CpuFeature_MmxExt: available = (fn_8000_[0x0001].reg.edx & (1 << 22)); break; + case DN_CpuFeature_PCLMULQDQ: available = (fn_0000_[0x0001].reg.ecx & (1 << 1)); break; + case DN_CpuFeature_POPCNT: available = (fn_0000_[0x0001].reg.ecx & (1 << 23)); break; + case DN_CpuFeature_RDRAND: available = (fn_0000_[0x0001].reg.ecx & (1 << 30)); break; + case DN_CpuFeature_RDSEED: available = (fn_0000_[0x0007].reg.ebx & (1 << 18)); break; + case DN_CpuFeature_RDTscP: available = (fn_8000_[0x0001].reg.edx & (1 << 27)); break; + case DN_CpuFeature_SHA: available = (fn_0000_[0x0007].reg.ebx & (1 << 29)); break; + case DN_CpuFeature_SSE: available = (fn_0000_[0x0001].reg.edx & (1 << 25)); break; + case DN_CpuFeature_SSE2: available = (fn_0000_[0x0001].reg.edx & (1 << 26)); break; + case DN_CpuFeature_SSE3: available = (fn_0000_[0x0001].reg.ecx & (1 << 0)); break; + case DN_CpuFeature_SSE41: available = (fn_0000_[0x0001].reg.ecx & (1 << 19)); break; + case DN_CpuFeature_SSE42: available = (fn_0000_[0x0001].reg.ecx & (1 << 20)); break; + case DN_CpuFeature_SSE4A: available = (fn_8000_[0x0001].reg.ecx & (1 << 6)); break; + case DN_CpuFeature_SSSE3: available = (fn_0000_[0x0001].reg.ecx & (1 << 9)); break; + case DN_CpuFeature_Tsc: available = (fn_0000_[0x0001].reg.edx & (1 << 4)); break; + case DN_CpuFeature_TscInvariant: available = (fn_8000_[0x0007].reg.edx & (1 << 8)); break; + case DN_CpuFeature_VAES: available = (fn_0000_[0x0007].reg.ecx & (1 << 9)); break; + case DN_CpuFeature_VPCMULQDQ: available = (fn_0000_[0x0007].reg.ecx & (1 << 10)); break; + case DN_CpuFeature_Count: DN_AssertInvalidCodePath; break; } if (available) - DN_CPUSetFeature(&result, DN_Cast(DN_CPUFeature) ext_index); + DN_CpuSetFeature(&result, DN_Cast(DN_CpuFeature) ext_index); } #endif // DN_SUPPORTS_CPU_ID return result; } +DN_API DN_U64 DN_CpuTscNowFunctionWrapper() +{ + DN_U64 result = DN_CpuTscNow(); + return result; +} + DN_API void DN_TicketMutexBegin(DN_TicketMutex *mutex) { DN_UInt ticket = DN_AtomicAddU32(&mutex->ticket, 1); @@ -1093,7 +1235,7 @@ static DN_MemBlock *DN_MemBlockFromHeap_(DN_U64 reserve, DN_U64 commit, DN_Heap real_reserve = DN_ARENA_RESERVE_SIZE; DN_AssertF(real_reserve > DN_ARENA_HEADER_SIZE, "%I64u > %I64u", real_reserve, DN_ARENA_HEADER_SIZE); - result = DN_Cast(DN_MemBlock *) DN_HeapAllocCallSite(&heap, real_reserve, 0, DN_HeapAllocFlag_Nil, call_site); + result = DN_Cast(DN_MemBlock *) DN_HeapAllocCallSite(&heap, real_reserve, real_reserve, DN_HeapAllocFlag_Nil, call_site); if (!result) return result; @@ -1212,32 +1354,34 @@ DN_API DN_Heap DN_HeapInitVirtual(DN_U32 page_size, DN_HeapVirtualReserveFunc *v DN_API void *DN_HeapAllocCallSite(DN_Heap *heap, DN_USize reserve, DN_USize commit, DN_HeapAllocFlag flags, DN_CallSite call_site) { void *result = nullptr; - switch (heap->type) { - case DN_HeapType_Nil: - break; + if (heap) { + switch (heap->type) { + case DN_HeapType_Nil: + break; - case DN_HeapType_Basic: { - result = heap->basic_alloc(reserve); - } break; - case DN_HeapType_Virtual: { - DN_MemCommit mem_commit = reserve == commit ? DN_MemCommit_Yes : DN_MemCommit_No; - result = DN_Cast(DN_MemBlock *) heap->virtual_reserve(reserve, mem_commit, DN_MemPage_ReadWrite); - if (result) { - bool commit_success = true; - if (mem_commit == DN_MemCommit_No && commit > 0) { - // NOTE: If mem-commit is yes, then the entire block of memory that was reserved is - // committed in the same syscall as the allocation itself as an optimisation. If - // mem-commit is no, which is this branch, then we commit just the range that the user - // requested in `commit`. - commit_success = heap->virtual_commit(result, commit, DN_MemPage_ReadWrite); - } + case DN_HeapType_Basic: { + result = heap->basic_alloc(reserve); + } break; + case DN_HeapType_Virtual: { + DN_MemCommit mem_commit = reserve == commit ? DN_MemCommit_Yes : DN_MemCommit_No; + result = DN_Cast(DN_MemBlock *) heap->virtual_reserve(reserve, mem_commit, DN_MemPage_ReadWrite); + if (result) { + bool commit_success = true; + if (mem_commit == DN_MemCommit_No && commit > 0) { + // NOTE: If mem-commit is yes, then the entire block of memory that was reserved is + // committed in the same syscall as the allocation itself as an optimisation. If + // mem-commit is no, which is this branch, then we commit just the range that the user + // requested in `commit`. + commit_success = heap->virtual_commit(result, commit, DN_MemPage_ReadWrite); + } - if (!commit_success) { - heap->virtual_release(result, reserve); - result = nullptr; + if (!commit_success) { + heap->virtual_release(result, reserve); + result = nullptr; + } } - } - } break; + } break; + } } if (result) { @@ -1247,7 +1391,7 @@ DN_API void *DN_HeapAllocCallSite(DN_Heap *heap, DN_USize reserve, DN_USize comm DN_BitIsNotSet(heap->flags, DN_HeapFlags_ExcludeFromMemDebugger)) { (void)call_site; bool ptr_can_leak = flags & DN_HeapAllocFlag_MemDebuggerCanLeakPtr || heap->flags & DN_HeapFlags_MemDebuggerCanLeakPtr; - DN_MemDebuggerAlloc(&g_dn_->mem_debugger, result, reserve, ptr_can_leak, call_site); + DN_MemDebuggerAlloc(&g_dn_->mem_debugger, result, reserve, commit, ptr_can_leak, call_site); } } return result; @@ -1267,7 +1411,7 @@ DN_API void DN_HeapDealloc(DN_Heap *heap, void *ptr, DN_USize size) heap->virtual_release(ptr, size); } -DN_API DN_MemList DN_MemListFromBuffer(void *buffer, DN_USize size, DN_MemFlags flags) +DN_API DN_MemList* DN_MemListFromBufferCallSite(void *buffer, DN_USize size, DN_MemFlags flags, DN_CallSite call_site) { DN_Assert(buffer); DN_AssertF(DN_ARENA_HEADER_SIZE < size, "Buffer (%zu bytes) too small, need atleast %zu bytes to store arena metadata", size, DN_ARENA_HEADER_SIZE); @@ -1275,27 +1419,41 @@ DN_API DN_MemList DN_MemListFromBuffer(void *buffer, DN_USize size, DN_MemFlags // NOTE: Init block DN_MemBlock *block = DN_Cast(DN_MemBlock *) buffer; + block->prev = nullptr; block->commit = size; block->reserve = size; block->used = DN_ARENA_HEADER_SIZE; + block->reserve_sum = 0; if (block && DN_ArenaHasPoison_(flags)) DN_ASanPoisonMemoryRegion(DN_Cast(char *) block + DN_ARENA_HEADER_SIZE, block->commit - DN_ARENA_HEADER_SIZE); - DN_MemList result = {}; - result.flags = flags | DN_MemFlags_NoGrow | DN_MemFlags_UserBuffer; - result.curr = block; - DN_MemListOnNewBlock_(&result, result.curr); - return result; + // NOTE: The memory list lives in the block header, immediately after the block + DN_MemList *mem = DN_Cast(DN_MemList *) (DN_Cast(char *) block + DN_MEM_LIST_OFFSET); + *mem = {}; + mem->flags = flags | DN_MemFlags_NoGrow | DN_MemFlags_UserBuffer; + mem->curr = block; + mem->label = call_site.name; + DN_MemListOnNewBlock_(mem, block); + DN_MemDebuggerMemListRegister_(mem); + return mem; } -DN_API DN_MemList DN_MemListFromHeapCallSite(DN_U64 reserve, DN_U64 commit, DN_MemFlags flags, DN_Heap heap, DN_CallSite call_site) +DN_API DN_MemList* DN_MemListFromHeapCallSite(DN_U64 reserve, DN_U64 commit, DN_MemFlags flags, DN_Heap heap, DN_CallSite call_site) { - DN_MemList result = {}; - result.heap = heap; - result.flags |= flags | DN_MemFlags_Heap; - result.curr = DN_MemBlockFromHeapFlags_(reserve, commit, flags, heap, call_site); - DN_MemListOnNewBlock_(&result, result.curr); - return result; + DN_MemBlock *block = DN_MemBlockFromHeapFlags_(reserve, commit, flags, heap, call_site); + if (!block) + return nullptr; + + // NOTE: The memory list lives in the block header, immediately after the block + DN_MemList *mem = DN_Cast(DN_MemList *) (DN_Cast(char *) block + DN_MEM_LIST_OFFSET); + *mem = {}; + mem->heap = heap; + mem->flags = flags | DN_MemFlags_Heap; + mem->curr = block; + mem->label = call_site.name; + DN_MemListOnNewBlock_(mem, block); + DN_MemDebuggerMemListRegister_(mem); + return mem; } static void DN_MemBlockDeinit_(DN_MemList *mem, DN_MemBlock *block) @@ -1303,19 +1461,37 @@ static void DN_MemBlockDeinit_(DN_MemList *mem, DN_MemBlock *block) DN_USize release_size = block->reserve; if (DN_ArenaHasPoison_(mem->flags)) DN_ASanUnpoisonMemoryRegion(block, block->commit); + // NOTE: The DN_MemBlock stays at the allocation base (the memory list is stored in the header + // after it), so the block pointer can be freed directly. if (mem->flags & DN_MemFlags_Heap) DN_HeapDealloc(&mem->heap, block, release_size); } DN_API void DN_MemListDeinit(DN_MemList *mem) { - bool mem_allocated_from_itself = DN_MemListOwnsPtr(mem, mem); - for (DN_MemBlock *block = mem ? mem->curr : nullptr; block;) { + if (!mem) + return; + + DN_MemDebuggerMemListUnregister_(mem); + + // NOTE: The memory list is embedded in the first block's header (see DN_MEM_LIST_OFFSET), so it + // must not be zeroed after the blocks have been freed. + bool mem_in_block_header = false; + for (DN_MemBlock *block = mem->curr; block && !mem_in_block_header; block = block->prev) { + char *begin = (char *)block; + char *end = begin + DN_ARENA_HEADER_SIZE; + char *ptr = (char *)mem; + mem_in_block_header = ptr >= begin && ptr < end; + } + if (!mem_in_block_header) + mem_in_block_header = DN_MemListOwnsPtr(mem, mem); + + for (DN_MemBlock *block = mem->curr; block;) { DN_MemBlock *block_to_free = block; block = block->prev; DN_MemBlockDeinit_(mem, block_to_free); } - if (mem && !mem_allocated_from_itself) + if (!mem_in_block_header) *mem = {}; } @@ -1348,6 +1524,7 @@ DN_API bool DN_MemListCommitTo(DN_MemList *mem, DN_U64 pos) DN_ASanPoisonMemoryRegion(commit_ptr, commit_size); curr->commit = end_commit; + DN_MemDebuggerCommitUpdate_(mem, curr); return true; } @@ -1360,13 +1537,13 @@ DN_API bool DN_MemListCommit(DN_MemList *mem, DN_U64 size) return result; } -DN_API bool DN_MemListGrow(DN_MemList *mem, DN_U64 reserve, DN_U64 commit) +DN_API bool DN_MemListGrowCallSite(DN_MemList *mem, DN_U64 reserve, DN_U64 commit, DN_CallSite call_site) { if (mem->flags & (DN_MemFlags_NoGrow | DN_MemFlags_UserBuffer)) return false; bool result = false; - DN_MemBlock *new_block = DN_MemBlockFromHeapFlags_(reserve, commit, mem->flags, mem->heap, DN_CallSiteNowNamed("DN MemList Grow")); + DN_MemBlock *new_block = DN_MemBlockFromHeapFlags_(reserve, commit, mem->flags, mem->heap, call_site); if (new_block) { result = true; new_block->prev = mem->curr; @@ -1377,13 +1554,13 @@ DN_API bool DN_MemListGrow(DN_MemList *mem, DN_U64 reserve, DN_U64 commit) return result; } -DN_API void *DN_MemListAlloc(DN_MemList *mem, DN_U64 size, DN_U8 align, DN_ZMem z_mem) +DN_API void *DN_MemListAllocCallSite(DN_MemList *mem, DN_U64 size, DN_U8 align, DN_ZMem z_mem, DN_CallSite call_site) { if (!mem) return nullptr; if (!mem->curr) { - mem->curr = DN_MemBlockFromHeapFlags_(DN_ARENA_RESERVE_SIZE, DN_ARENA_COMMIT_SIZE, mem->flags, mem->heap, DN_CallSiteNowNamed("DN MemList Lazy Bootstrap")); + mem->curr = DN_MemBlockFromHeapFlags_(DN_ARENA_RESERVE_SIZE, DN_ARENA_COMMIT_SIZE, mem->flags, mem->heap, call_site); DN_MemListOnNewBlock_(mem, mem->curr); } @@ -1403,7 +1580,7 @@ DN_API void *DN_MemListAlloc(DN_MemList *mem, DN_U64 size, DN_U8 align, DN_ZMem return nullptr; DN_USize new_reserve = DN_Max(DN_ARENA_HEADER_SIZE + alloc_size, DN_ARENA_RESERVE_SIZE); DN_USize new_commit = DN_Max(DN_ARENA_HEADER_SIZE + alloc_size, DN_ARENA_COMMIT_SIZE); - if (!DN_MemListGrow(mem, new_reserve, new_commit)) + if (!DN_MemListGrowCallSite(mem, new_reserve, new_commit, call_site)) return nullptr; goto try_alloc_again; } @@ -1422,12 +1599,14 @@ DN_API void *DN_MemListAlloc(DN_MemList *mem, DN_U64 size, DN_U8 align, DN_ZMem curr->commit = end_commit; mem->stats.info.commit += commit_size; mem->stats.hwm.commit = DN_Max(mem->stats.hwm.commit, mem->stats.info.commit); + DN_MemDebuggerCommitUpdate_(mem, curr); } void *result = DN_Cast(char *) curr + offset_pos; curr->used += alloc_size; mem->stats.info.used += alloc_size; mem->stats.hwm.used = DN_Max(mem->stats.hwm.used, mem->stats.info.used); + DN_MemDebuggerMemListAllocTrack_(mem, result, size, alloc_size, align, call_site); if (poison && DN_BitIsNotSet(mem->flags, DN_MemFlags_SimAlloc)) DN_ASanUnpoisonMemoryRegion(result, size); @@ -1442,20 +1621,20 @@ DN_API void *DN_MemListAlloc(DN_MemList *mem, DN_U64 size, DN_U8 align, DN_ZMem return result; } -DN_API void *DN_MemListAllocContiguous(DN_MemList *mem, DN_U64 size, DN_U8 align, DN_ZMem z_mem) +DN_API void *DN_MemListAllocContiguousCallSite(DN_MemList *mem, DN_U64 size, DN_U8 align, DN_ZMem z_mem, DN_CallSite call_site) { DN_MemFlags prev_flags = mem->flags; mem->flags |= (DN_MemFlags_NoGrow | DN_MemFlags_NoPoison); - void *memory = DN_MemListAlloc(mem, size, align, z_mem); + void *memory = DN_MemListAllocCallSite(mem, size, align, z_mem, call_site); mem->flags = prev_flags; return memory; } -DN_API void *DN_MemListCopy(DN_MemList *mem, void const *data, DN_U64 size, DN_U8 align) +DN_API void *DN_MemListCopyCallSite(DN_MemList *mem, void const *data, DN_U64 size, DN_U8 align, DN_CallSite call_site) { if (!mem || !data || size == 0) return nullptr; - void *result = DN_MemListAlloc(mem, size, align, DN_ZMem_No); + void *result = DN_MemListAllocCallSite(mem, size, align, DN_ZMem_No, call_site); if (result) DN_Memcpy(result, data, size); return result; @@ -1466,7 +1645,9 @@ DN_API void DN_MemListPopTo(DN_MemList *mem, DN_U64 init_used) if (!mem || !mem->curr) return; - // NOTE: Free any memory blocks until we get back to the starting block + // NOTE: Free any memory blocks until we get back to the starting block. The floor is always the + // header: the DN_MemList itself lives inside the block header (see DN_MEM_LIST_OFFSET) so it is + // never scrubbed by a reset. DN_U64 used = DN_Max(DN_ARENA_HEADER_SIZE, init_used); DN_MemBlock *curr = mem->curr; while (curr->reserve_sum >= used) { @@ -1522,6 +1703,8 @@ DN_API void DN_MemListPopTo(DN_MemList *mem, DN_U64 init_used) DN_USize poison_size = ((char *)curr + curr->commit) - poison_ptr; DN_ASanPoisonMemoryRegion(poison_ptr, poison_size); } + + DN_MemDebuggerMemListAllocsSync_(mem); } DN_API void DN_MemListPop(DN_MemList *mem, DN_U64 amount) @@ -1687,10 +1870,9 @@ DN_API DN_Arena DN_ArenaFromMemList(DN_MemList *mem) DN_API DN_Arena DN_ArenaFromHeapCallSite(DN_U64 reserve, DN_U64 commit, DN_MemFlags flags, DN_Heap heap, DN_CallSite call_site) { - DN_MemList mem = DN_MemListFromHeapCallSite(reserve, commit, flags, heap, call_site); - DN_Arena result = {}; - result.flags |= DN_ArenaFlags_OwnsMemList; - result.mem = DN_MemListNewCopy(&mem, DN_MemList, &mem); + DN_Arena result = {}; + result.flags |= DN_ArenaFlags_OwnsMemList; + result.mem = DN_MemListFromHeapCallSite(reserve, commit, flags, heap, call_site); return result; } @@ -1759,27 +1941,33 @@ DN_API void DN_ArenaTempEnd(DN_Arena *arena, DN_ArenaReset reset) #endif } -DN_API void *DN_ArenaAlloc(DN_Arena *arena, DN_U64 size, DN_U8 align, DN_ZMem z_mem) +DN_API void *DN_ArenaAllocCallSite(DN_Arena *arena, DN_U64 size, DN_U8 align, DN_ZMem z_mem, DN_CallSite call_site) { DN_ArenaUAFCheck_(arena, DN_ArenaUAFCheckReportType_AllocViolation); - void *result = DN_MemListAlloc(arena->mem, size, align, z_mem); + void *result = DN_MemListAllocCallSite(arena->mem, size, align, z_mem, call_site); return result; } -DN_API void *DN_ArenaAllocContiguous(DN_Arena *arena, DN_U64 size, DN_U8 align, DN_ZMem z_mem) +DN_API void *DN_ArenaAllocContiguousCallSite(DN_Arena *arena, DN_U64 size, DN_U8 align, DN_ZMem z_mem, DN_CallSite call_site) { DN_ArenaUAFCheck_(arena, DN_ArenaUAFCheckReportType_AllocViolation); - void *result = DN_MemListAllocContiguous(arena->mem, size, align, z_mem); + void *result = DN_MemListAllocContiguousCallSite(arena->mem, size, align, z_mem, call_site); return result; } -DN_API void *DN_ArenaCopy(DN_Arena *arena, void const *data, DN_U64 size, DN_U8 align) +DN_API void *DN_ArenaCopyCallSite(DN_Arena *arena, void const *data, DN_U64 size, DN_U8 align, DN_CallSite call_site) { DN_ArenaUAFCheck_(arena, DN_ArenaUAFCheckReportType_AllocViolation); - void *result = DN_MemListCopy(arena->mem, data, size, align); + void *result = DN_MemListCopyCallSite(arena->mem, data, size, align, call_site); return result; } +DN_API void DN_ArenaClear(DN_Arena *arena) +{ + DN_ArenaUAFCheck_(arena, DN_ArenaUAFCheckReportType_AllocViolation); + DN_MemListPopTo(arena->mem, 0); +} + DN_API void DN_ArenaDeinit(DN_Arena *arena) { if (arena->flags & DN_ArenaFlags_OwnsMemList) @@ -1808,7 +1996,7 @@ DN_API bool DN_PoolIsValid(DN_Pool const *pool) return result; } -DN_API void *DN_PoolAlloc(DN_Pool *pool, DN_USize size) +DN_API void *DN_PoolAllocCallSite(DN_Pool *pool, DN_USize size, DN_CallSite call_site) { void *result = nullptr; if (!DN_PoolIsValid(pool)) @@ -1843,7 +2031,7 @@ DN_API void *DN_PoolAlloc(DN_Pool *pool, DN_USize size) DN_Memset(slot->data, 0, size); DN_Assert(DN_IsPowerOfTwoAligned(slot->data, pool->align)); } else { - void *bytes = DN_ArenaAlloc(pool->arena, slot_size_in_bytes, alignof(DN_PoolSlot), DN_ZMem_Yes); + void *bytes = DN_ArenaAllocCallSite(pool->arena, slot_size_in_bytes, alignof(DN_PoolSlot), DN_ZMem_Yes, call_site); slot = DN_Cast(DN_PoolSlot *) bytes; // NOTE: The raw pointer is round up to the next 'pool->align'-ed @@ -2105,7 +2293,11 @@ DN_API void DN_ErrSinkEndExitIfErrorFV_(DN_ErrSink *err, DN_CallSite call_site, { if (DN_ErrSinkEndLogErrorFV_(err, call_site, fmt, args)) { DN_DebugBreak; + #if DN_WITH_OS DN_OS_Exit(exit_val); + #else + DN_AssertInvalidCodePathF("Exiting with exit code: %u", exit_val); + #endif } } @@ -2173,22 +2365,19 @@ DN_API DN_TcInitArgs DN_TcInitArgsDefault() DN_API void DN_TcInitFromHeap(DN_TcCore *tc, DN_U64 thread_id, DN_TcInitArgs args, DN_Heap heap) { DN_Assert(args.temp_count <= DN_ArrayCountU(tc->temp_arenas)); - DN_MemList main_mem_stack = DN_MemListFromHeap(args.main_reserve, args.main_commit, DN_MemFlags_Nil, heap, "DN Thread Context Main MemList"); - DN_MemList *main_mem = DN_MemListNewCopy(&main_mem_stack, DN_MemList, &main_mem_stack); - DN_Arena *main_arena = DN_MemListNewZ(main_mem, DN_Arena); - *main_arena = DN_ArenaFromMemList(main_mem); + DN_MemList *main_mem = DN_MemListFromHeap(args.main_reserve, args.main_commit, DN_MemFlags_Nil, heap, "DN Thread Context Main MemList"); + DN_Arena *main_arena = DN_MemListNewZ(main_mem, DN_Arena); + *main_arena = DN_ArenaFromMemList(main_mem); DN_Arena *temp_arenas = DN_MemListNewArrayZ(main_mem, DN_Arena, args.temp_count); for (DN_ForIndexU(index, args.temp_count)) { - DN_MemList temp_mem_stack = DN_MemListFromHeap(args.temp_reserve, args.temp_commit, DN_MemFlags_Nil, heap, "DN Thread Context Temp MemList"); - DN_MemList *temp_mem = DN_MemListNewCopy(main_mem, DN_MemList, &temp_mem_stack); - temp_arenas[index] = DN_ArenaFromMemList(temp_mem); + DN_MemList *temp_mem = DN_MemListFromHeap(args.temp_reserve, args.temp_commit, DN_MemFlags_Nil, heap, "DN Thread Context Temp MemList"); + temp_arenas[index] = DN_ArenaFromMemList(temp_mem); } - DN_MemList err_sink_mem_stack = DN_MemListFromHeap(args.err_sink_reserve, args.err_sink_commit, DN_MemFlags_Nil, heap, "DN ThreadContext Err MemList"); - DN_MemList *err_sink_mem = DN_MemListNewCopy(main_mem, DN_MemList, &err_sink_mem_stack); - DN_Arena *err_sink_arena = DN_MemListNewZ(main_mem, DN_Arena); - *err_sink_arena = DN_ArenaFromMemList(err_sink_mem); + DN_MemList *err_sink_mem = DN_MemListFromHeap(args.err_sink_reserve, args.err_sink_commit, DN_MemFlags_Nil, heap, "DN ThreadContext Err MemList"); + DN_Arena *err_sink_arena = DN_MemListNewZ(main_mem, DN_Arena); + *err_sink_arena = DN_ArenaFromMemList(err_sink_mem); DN_TcInit(tc, thread_id, main_arena, temp_arenas, args.temp_count, err_sink_arena); } @@ -2250,6 +2439,8 @@ DN_API DN_Arena DN_TcTempArenaAllocator(DN_Allocator *conflicts, DN_USize count) mem_list = arena->mem; } break; + case DN_AllocatorType_Heap: break; + case DN_AllocatorType_Pool: { DN_Pool *pool = DN_Cast(DN_Pool *) allocator->context; mem_list = pool->arena ? pool->arena->mem : nullptr; @@ -2368,7 +2559,7 @@ DN_API DN_ErrSink *DN_TcErrSink() return result; } -DN_API void *DN_PoolCopy(DN_Pool *pool, void const *data, DN_U64 size, DN_U8 align) +DN_API void *DN_PoolCopyCallSite(DN_Pool *pool, void const *data, DN_U64 size, DN_U8 align, DN_CallSite call_site) { if (!pool || !data || size == 0) return nullptr; @@ -2377,7 +2568,7 @@ DN_API void *DN_PoolCopy(DN_Pool *pool, void const *data, DN_U64 size, DN_U8 ali // about this until we crash because of misalignment. DN_Assert(pool->align >= align); - void *result = DN_PoolAlloc(pool, size); + void *result = DN_PoolAllocCallSite(pool, size, call_site); if (result) DN_Memcpy(result, data, size); return result; @@ -2837,19 +3028,40 @@ DN_API DN_Allocator DN_AllocatorFromPool(DN_Pool *pool) return result; } -DN_API void *DN_AllocatorAlloc(DN_Allocator allocator, DN_USize size, DN_U8 align, DN_ZMem z_mem) +DN_API DN_Allocator DN_AllocatorFromHeap(DN_Heap *heap) +{ + DN_Allocator result = {}; + result.type = DN_AllocatorType_Heap; + result.context = heap; + return result; +} + +DN_API void *DN_AllocatorAllocCallSite(DN_Allocator allocator, DN_USize size, DN_U8 align, DN_ZMem z_mem, DN_CallSite call_site) { void *result = nullptr; if (allocator.context) { switch (allocator.type) { - case DN_AllocatorType_Arena: result = DN_ArenaAlloc (DN_Cast(DN_Arena *) allocator.context, size + 1, align, z_mem); break; - case DN_AllocatorType_Pool: result = DN_PoolAlloc (DN_Cast(DN_Pool *) allocator.context, size + 1); break; - case DN_AllocatorType_MemList: result = DN_MemListAlloc(DN_Cast(DN_MemList *) allocator.context, size + 1, align, z_mem); break; + case DN_AllocatorType_Heap: result = DN_HeapAllocCallSite (DN_Cast(DN_Heap *) allocator.context, size, size, DN_HeapAllocFlag_Nil, call_site); break; + case DN_AllocatorType_Arena: result = DN_ArenaAllocCallSite (DN_Cast(DN_Arena *) allocator.context, size, align, z_mem, call_site); break; + case DN_AllocatorType_Pool: result = DN_PoolAllocCallSite (DN_Cast(DN_Pool *) allocator.context, size, call_site); break; + case DN_AllocatorType_MemList: result = DN_MemListAllocCallSite (DN_Cast(DN_MemList *) allocator.context, size, align, z_mem, call_site); break; } } return result; } +DN_API void DN_AllocatorDealloc(DN_Allocator allocator, void *ptr, DN_USize size) +{ + if (allocator.context) { + switch (allocator.type) { + case DN_AllocatorType_Heap: DN_HeapDealloc(DN_Cast(DN_Heap *)allocator.context, ptr, size); break; + case DN_AllocatorType_Arena: break; + case DN_AllocatorType_Pool: DN_PoolDealloc(DN_Cast(DN_Pool *)allocator.context, ptr); break; + case DN_AllocatorType_MemList: break; + } + } +} + DN_API DN_FmtAppendResult DN_FmtVAppend(char *buf, DN_USize *buf_size, DN_USize buf_max, char const *fmt, va_list args) { DN_FmtAppendResult result = {}; @@ -2918,10 +3130,10 @@ DN_API DN_USize DN_CStr16Count(wchar_t const *src) return result; } -DN_API DN_Str8 DN_Str8AllocAllocator(DN_USize count, DN_ZMem z_mem, DN_Allocator allocator) +DN_API DN_Str8 DN_Str8AllocAllocatorCallSite(DN_USize count, DN_ZMem z_mem, DN_Allocator allocator, DN_CallSite call_site) { DN_Str8 result = {}; - result.data = DN_Cast(char *) DN_AllocatorAlloc(allocator, count + 1, alignof(char), z_mem); + result.data = DN_Cast(char *) DN_AllocatorAllocCallSite(allocator, count + 1, alignof(char), z_mem, call_site); if (result.data) { result.count = count; result.data[result.count] = 0; @@ -2929,15 +3141,15 @@ DN_API DN_Str8 DN_Str8AllocAllocator(DN_USize count, DN_ZMem z_mem, DN_Allocator return result; } -DN_API DN_Str8 DN_Str8AllocArena(DN_USize count, DN_ZMem z_mem, DN_Arena *arena) +DN_API DN_Str8 DN_Str8AllocArenaCallSite(DN_USize count, DN_ZMem z_mem, DN_Arena *arena, DN_CallSite call_site) { - DN_Str8 result = DN_Str8AllocAllocator(count, z_mem, DN_AllocatorFromArena(arena)); + DN_Str8 result = DN_Str8AllocAllocatorCallSite(count, z_mem, DN_AllocatorFromArena(arena), call_site); return result; } -DN_API DN_Str8 DN_Str8AllocPool(DN_USize count, DN_Pool *pool) +DN_API DN_Str8 DN_Str8AllocPoolCallSite(DN_USize count, DN_Pool *pool, DN_CallSite call_site) { - DN_Str8 result = DN_Str8AllocAllocator(count, DN_ZMem_No, DN_AllocatorFromPool(pool)); + DN_Str8 result = DN_Str8AllocAllocatorCallSite(count, DN_ZMem_No, DN_AllocatorFromPool(pool), call_site); return result; } @@ -2948,33 +3160,33 @@ DN_API DN_Str8 DN_Str8FromCStr8(char const *src) return result; } -DN_API DN_Str8 DN_Str8FromCStr8Arena(char const *src, DN_Arena *arena) +DN_API DN_Str8 DN_Str8FromCStr8ArenaCallSite(char const *src, DN_Arena *arena, DN_CallSite call_site) { DN_Str8 shallow = DN_Str8FromCStr8(src); - DN_Str8 result = DN_Str8FromStr8Arena(shallow, arena); + DN_Str8 result = DN_Str8FromStr8ArenaCallSite(shallow, arena, call_site); return result; } -DN_API DN_Str8 DN_Str8FromPtrArena(void const *data, DN_USize count, DN_Arena *arena) +DN_API DN_Str8 DN_Str8FromPtrArenaCallSite(void const *data, DN_USize count, DN_Arena *arena, DN_CallSite call_site) { - DN_Str8 result = DN_Str8AllocArena(count, DN_ZMem_No, arena); + DN_Str8 result = DN_Str8AllocArenaCallSite(count, DN_ZMem_No, arena, call_site); if (result.count) DN_Memcpy(result.data, data, count); return result; } -DN_API DN_Str8 DN_Str8FromPtrPool(void const *data, DN_USize count, DN_Pool *pool) +DN_API DN_Str8 DN_Str8FromPtrPoolCallSite(void const *data, DN_USize count, DN_Pool *pool, DN_CallSite call_site) { - DN_Str8 result = DN_Str8AllocPool(count, pool); + DN_Str8 result = DN_Str8AllocPoolCallSite(count, pool, call_site); if (result.count) DN_Memcpy(result.data, data, count); return result; } -DN_API DN_Str8 DN_Str8FromStr8Allocator(DN_Str8 string, DN_Allocator allocator) +DN_API DN_Str8 DN_Str8FromStr8AllocatorCallSite(DN_Str8 string, DN_Allocator allocator, DN_CallSite call_site) { DN_Str8 result = {}; - result.data = DN_Cast(char *) DN_AllocatorAlloc(allocator, string.count + 1, alignof(char), DN_ZMem_No); + result.data = DN_Cast(char *) DN_AllocatorAllocCallSite(allocator, string.count + 1, alignof(char), DN_ZMem_No, call_site); if (result.data) { DN_Memcpy(result.data, string.data, string.count); result.data[string.count] = 0; @@ -2983,22 +3195,22 @@ DN_API DN_Str8 DN_Str8FromStr8Allocator(DN_Str8 string, DN_Allocator allocator) return result; } -DN_API DN_Str8 DN_Str8FromStr8Arena(DN_Str8 string, DN_Arena *arena) +DN_API DN_Str8 DN_Str8FromStr8ArenaCallSite(DN_Str8 string, DN_Arena *arena, DN_CallSite call_site) { - DN_Str8 result = DN_Str8FromStr8Allocator(string, DN_AllocatorFromArena(arena)); + DN_Str8 result = DN_Str8FromStr8AllocatorCallSite(string, DN_AllocatorFromArena(arena), call_site); return result; } -DN_API DN_Str8 DN_Str8FromStr8Pool(DN_Str8 string, DN_Pool *pool) +DN_API DN_Str8 DN_Str8FromStr8PoolCallSite(DN_Str8 string, DN_Pool *pool, DN_CallSite call_site) { - DN_Str8 result = DN_Str8FromStr8Allocator(string, DN_AllocatorFromPool(pool)); + DN_Str8 result = DN_Str8FromStr8AllocatorCallSite(string, DN_AllocatorFromPool(pool), call_site); return result; } -DN_API DN_Str8 DN_Str8FmtVAllocator(DN_Allocator allocator, DN_FMT_ATTRIB char const *fmt, va_list args) +DN_API DN_Str8 DN_Str8FmtVAllocatorCallSite(DN_Allocator allocator, DN_FMT_ATTRIB char const *fmt, va_list args, DN_CallSite call_site) { DN_USize count = DN_FmtVCount(fmt, args); - DN_Str8 result = DN_Str8AllocAllocator(count, DN_ZMem_No, allocator); + DN_Str8 result = DN_Str8AllocAllocatorCallSite(count, DN_ZMem_No, allocator, call_site); if (result.data) { DN_USize written = 0; DN_FmtVAppend(result.data, &written, result.count + 1, fmt, args); @@ -3007,41 +3219,41 @@ DN_API DN_Str8 DN_Str8FmtVAllocator(DN_Allocator allocator, DN_FMT_ATTRIB char c return result; } -DN_API DN_Str8 DN_Str8FmtVArena(DN_Arena *arena, DN_FMT_ATTRIB char const *fmt, va_list args) +DN_API DN_Str8 DN_Str8FmtVArenaCallSite(DN_Arena *arena, DN_FMT_ATTRIB char const *fmt, va_list args, DN_CallSite call_site) { - DN_Str8 result = DN_Str8FmtVAllocator(DN_AllocatorFromArena(arena), fmt, args); + DN_Str8 result = DN_Str8FmtVAllocatorCallSite(DN_AllocatorFromArena(arena), fmt, args, call_site); return result; } -DN_API DN_Str8 DN_Str8FmtAllocator(DN_Allocator allocator, DN_FMT_ATTRIB char const *fmt, ...) +DN_API DN_Str8 DN_Str8FmtAllocatorCallSite(DN_Allocator allocator, DN_CallSite call_site, DN_FMT_ATTRIB char const *fmt, ...) { va_list va; va_start(va, fmt); - DN_Str8 result = DN_Str8FmtVAllocator(allocator, fmt, va); + DN_Str8 result = DN_Str8FmtVAllocatorCallSite(allocator, fmt, va, call_site); va_end(va); return result; } -DN_API DN_Str8 DN_Str8FmtArena(DN_Arena *arena, DN_FMT_ATTRIB char const *fmt, ...) +DN_API DN_Str8 DN_Str8FmtArenaCallSite(DN_Arena *arena, DN_CallSite call_site, DN_FMT_ATTRIB char const *fmt, ...) { va_list va; va_start(va, fmt); - DN_Str8 result = DN_Str8FmtVArena(arena, fmt, va); + DN_Str8 result = DN_Str8FmtVArenaCallSite(arena, fmt, va, call_site); va_end(va); return result; } -DN_API DN_Str8 DN_Str8FmtVPool(DN_Pool *pool, DN_FMT_ATTRIB char const *fmt, va_list args) +DN_API DN_Str8 DN_Str8FmtVPoolCallSite(DN_Pool *pool, DN_FMT_ATTRIB char const *fmt, va_list args, DN_CallSite call_site) { - DN_Str8 result = DN_Str8FmtVAllocator(DN_AllocatorFromPool(pool), fmt, args); + DN_Str8 result = DN_Str8FmtVAllocatorCallSite(DN_AllocatorFromPool(pool), fmt, args, call_site); return result; } -DN_API DN_Str8 DN_Str8FmtPool(DN_Pool *pool, DN_FMT_ATTRIB char const *fmt, ...) +DN_API DN_Str8 DN_Str8FmtPoolCallSite(DN_Pool *pool, DN_CallSite call_site, DN_FMT_ATTRIB char const *fmt, ...) { va_list args; va_start(args, fmt); - DN_Str8 result = DN_Str8FmtVPool(pool, fmt, args); + DN_Str8 result = DN_Str8FmtVPoolCallSite(pool, fmt, args, call_site); va_end(args); return result; } @@ -3277,37 +3489,39 @@ DN_API DN_Str8x32 DN_Str8x32FromU64(DN_U64 val, char seperator) return result; } - -DN_API bool DN_Str8Is(DN_Str8 string, DN_Str8IsFlags flags) +DN_API DN_Str8IsResult DN_Str8Is(DN_Str8 string, DN_Str8IsFlags flags) { - bool result = string.count; - if (!result) + DN_Str8IsResult result = {}; + if (string.count == 0) return result; - if (result && (flags & DN_Str8IsFlags_Digits)) { - for (DN_USize index = 0; result && index < string.count; index++) - result = string.data[index] >= '0' && string.data[index] <= '9'; + result.success = true; + if (result.success && (flags & DN_Str8IsFlags_Digits)) { + for (DN_USize index = 0; result.success && index < string.count; index++) + result.success = string.data[index] >= '0' && string.data[index] <= '9'; } - if (result && (flags & DN_Str8IsFlags_Hex)) { + if (result.success && (flags & DN_Str8IsFlags_Hex)) { DN_Str8 trimmed = DN_Str8TrimPrefix(string, DN_Str8Lit("0x"), DN_Str8EqCase_Insensitive); - for (DN_USize index = 0; result && index < trimmed.count; index++) { - char ch = trimmed.data[index]; - result = (ch >= '0' && ch <= '9') || (ch >= 'a' && ch <= 'f') || (ch >= 'A' && ch <= 'F'); + for (DN_USize index = 0; result.success && index < trimmed.count; index++) { + char ch = trimmed.data[index]; + result.success = (ch >= '0' && ch <= '9') || (ch >= 'a' && ch <= 'f') || (ch >= 'A' && ch <= 'F'); } + if (result.success) + result.hex = trimmed; } - if (result && (flags & DN_Str8IsFlags_Lowercase)) { - for (DN_USize index = 0; result && index < string.count; index++) { + if (result.success && (flags & DN_Str8IsFlags_Lowercase)) { + for (DN_USize index = 0; result.success && index < string.count; index++) { if (string.data[index] >= 'A' && string.data[index] <= 'Z') - result = false; + result.success = false; } } - if (result && (flags & DN_Str8IsFlags_Uppercase)) { - for (DN_USize index = 0; result && index < string.count; index++) { + if (result.success && (flags & DN_Str8IsFlags_Uppercase)) { + for (DN_USize index = 0; result.success && index < string.count; index++) { if (string.data[index] >= 'a' && string.data[index] <= 'z') - result = false; + result.success = false; } } return result; @@ -3786,7 +4000,14 @@ DN_API DN_Str8 DN_Str8FileDirectoryFromPath(DN_Str8 path) { DN_Str8 seperators[] = {DN_Str8Lit("/"), DN_Str8Lit("\\")}; DN_Str8BSplitResult split = DN_Str8BSplitLastArray(path, seperators, DN_ArrayCountU(seperators)); - DN_Str8 result = split.rhs.count == 0 ? DN_Str8Lit(".") : split.lhs; + DN_Str8 result = DN_Str8Lit("."); + if (split.rhs.count) { + DN_Str8BSplitResult dot_split = DN_Str8BSplitLast(split.rhs, DN_Str8Lit(".")); + if (dot_split.rhs.count == 0) // E.g. no dot file extension, assume `path` just specifies a path + result = path; + else + result = split.lhs; + } return result; } @@ -5046,17 +5267,17 @@ DN_API bool DN_PathPop(DN_Path *path) return true; } -DN_API DN_Str8 DN_Str8FromPath(DN_Path const *path, DN_Str8 path_seperator, DN_Allocator allocator) +DN_API DN_Str8Path DN_Str8PathFromPath(DN_Path const *path, DN_Str8 path_seperator, DN_Allocator allocator) { - DN_Str8 result = {}; + DN_Str8Path result = {}; if (!path || path->links_size <= 0) return result; // NOTE: Each link except the last one needs the path seperator appended to it, '/' or '\\' DN_USize string_size = (path->has_prefix_path_seperator ? path_seperator.count : 0) + path->string_size + ((path->links_size - 1) * path_seperator.count); - result = DN_Str8AllocAllocator(string_size, DN_ZMem_No, allocator); - if (result.data) { - char *dest = result.data; + result.value = DN_Str8AllocAllocator(string_size, DN_ZMem_No, allocator); + if (result.value.data) { + char *dest = result.value.data; if (path->has_prefix_path_seperator) { DN_Memcpy(dest, path_seperator.data, path_seperator.count); dest += path_seperator.count; @@ -5072,25 +5293,29 @@ DN_API DN_Str8 DN_Str8FromPath(DN_Path const *path, DN_Str8 path_seperator, DN_A dest += path_seperator.count; } } - } - result.data[string_size] = 0; + result.value.data[string_size] = 0; + result.file_name = DN_Str8FileNameFromPath(result.value); + result.file_ext = DN_Str8FileExtension(result.file_name); + result.file_name_no_ext = DN_Str8TrimSuffixSensitive(DN_Str8TrimSuffixSensitive(result.file_name, result.file_ext), DN_Str8Lit(".")); + result.directory = DN_Str8FileDirectoryFromPath(result.value); + } return result; } -DN_API DN_Str8 DN_Str8FmtVPathArena(DN_Str8 path_seperator, DN_Arena *arena, DN_FMT_ATTRIB char const *fmt, va_list args) +DN_API DN_Str8Path DN_Str8PathFmtVArena(DN_Str8 path_seperator, DN_Arena *arena, char const *fmt, va_list args) { DN_TcScratch scratch = DN_TcScratchBeginArena(&arena, 1); DN_Str8 path = DN_Str8FmtVArena(arena, fmt, args); DN_Path fs_path = {}; DN_PathAddRef(&fs_path, path, &scratch.arena); DN_Allocator allocator = DN_AllocatorFromArena(arena); - DN_Str8 result = DN_Str8FromPath(&fs_path, path_seperator, allocator); + DN_Str8Path result = DN_Str8PathFromPath(&fs_path, path_seperator, allocator); DN_TcScratchEnd(&scratch); return result; } -DN_API DN_Str8 DN_Str8FmtPathArena(DN_Str8 path_seperator, DN_Arena *arena, DN_FMT_ATTRIB char const *fmt, ...) +DN_API DN_Str8Path DN_Str8PathFmtArena(DN_Str8 path_seperator, DN_Arena *arena, DN_FMT_ATTRIB char const *fmt, ...) { DN_TcScratch scratch = DN_TcScratchBeginArena(&arena, 1); va_list args; @@ -5102,46 +5327,46 @@ DN_API DN_Str8 DN_Str8FmtPathArena(DN_Str8 path_seperator, DN_Arena *arena, DN_F DN_PathAddRef(&fs_path, path, &scratch.arena); DN_Allocator allocator = DN_AllocatorFromArena(arena); - DN_Str8 result = DN_Str8FromPath(&fs_path, path_seperator, allocator); + DN_Str8Path result = DN_Str8PathFromPath(&fs_path, path_seperator, allocator); DN_TcScratchEnd(&scratch); return result; } -DN_API DN_Str8 DN_Str8FmtVPathPool(DN_Str8 path_seperator, DN_Pool *pool, DN_FMT_ATTRIB char const *fmt, va_list args) +DN_API DN_Str8Path DN_Str8PathFmtVPool(DN_Str8 path_seperator, DN_Pool *pool, char const *fmt, va_list args) { DN_TcScratch scratch = DN_TcScratchBeginArena(&pool->arena, 1); DN_Str8 path = DN_Str8FmtVPool(pool, fmt, args); DN_Path fs_path = {}; DN_PathAddRef(&fs_path, path, &scratch.arena); DN_Allocator allocator = DN_AllocatorFromPool(pool); - DN_Str8 result = DN_Str8FromPath(&fs_path, path_seperator, allocator); + DN_Str8Path result = DN_Str8PathFromPath(&fs_path, path_seperator, allocator); DN_TcScratchEnd(&scratch); return result; } -DN_API DN_Str8 DN_Str8FmtPathPool(DN_Str8 path_seperator, DN_Pool *pool, DN_FMT_ATTRIB char const *fmt, ...) +DN_API DN_Str8Path DN_Str8PathFmtPool(DN_Str8 path_seperator, DN_Pool *pool, DN_FMT_ATTRIB char const *fmt, ...) { va_list args; va_start(args, fmt); - DN_Str8 result = DN_Str8FmtVPathPool(path_seperator, pool, fmt, args); + DN_Str8Path result = DN_Str8PathFmtVPool(path_seperator, pool, fmt, args); va_end(args); return result; } -DN_API DN_Str8 DN_Str8FmtOsPathPool(DN_Pool *pool, DN_FMT_ATTRIB char const *fmt, ...) +DN_API DN_Str8Path DN_Str8PathFmtOsPool(DN_Pool *pool, DN_FMT_ATTRIB char const *fmt, ...) { va_list args; va_start(args, fmt); - DN_Str8 result = DN_Str8FmtVPathPool(DN_OsPathSeperatorStr8, pool, fmt, args); + DN_Str8Path result = DN_Str8PathFmtVPool(DN_OsPathSeperatorStr8, pool, fmt, args); va_end(args); return result; } -DN_API DN_Str8 DN_Str8FmtOsPathArena(DN_Arena *arena, DN_FMT_ATTRIB char const *fmt, ...) +DN_API DN_Str8Path DN_Str8PathFmtOsArena(DN_Arena *arena, DN_FMT_ATTRIB char const *fmt, ...) { va_list args; va_start(args, fmt); - DN_Str8 result = DN_Str8FmtVPathArena(DN_OsPathSeperatorStr8, arena, fmt, args); + DN_Str8Path result = DN_Str8PathFmtVArena(DN_OsPathSeperatorStr8, arena, fmt, args); va_end(args); return result; } @@ -5855,7 +6080,7 @@ DN_API DN_ProfilerZone DN_ProfilerBeginZone(DN_Profiler *profiler, DN_Str8 name, #endif result.profiler = profiler; - result.begin_tsc = profiler->tsc_now ? profiler->tsc_now() : DN_CPUGetTsc(); + result.begin_tsc = profiler->tsc_now ? profiler->tsc_now() : DN_CpuTscNow(); result.anchor_index = anchor_index; result.parent_zone = profiler->parent_zone; result.elapsed_tsc_at_zone_start = anchor->tsc_inclusive; @@ -5874,7 +6099,7 @@ DN_API void DN_ProfilerEndZone(DN_ProfilerZone zone) DN_ProfilerAnchorArray array = DN_ProfilerFrameAnchors(profiler); DN_ProfilerAnchor *anchor = array.data + zone.anchor_index; - DN_U64 tsc_now = profiler->tsc_now ? profiler->tsc_now() : DN_CPUGetTsc(); + DN_U64 tsc_now = profiler->tsc_now ? profiler->tsc_now() : DN_CpuTscNow(); DN_U64 elapsed_tsc = tsc_now - zone.begin_tsc; // NOTE: We snap the elapsed Tsc at the zone start and overwrite every time we end zones. If we @@ -5950,6 +6175,7 @@ DN_API void DN_ProfilerFmtToStdout(DN_Profiler *profiler) if (!profiler || profiler->frame_index == 0) return; + #if DN_WITH_OS DN_USize frame_index = profiler->frame_index - 1; DN_ProfilerAnchor *anchors = profiler->anchors + (frame_index * profiler->anchors_per_frame); for (DN_USize index = 1; index < profiler->anchors_per_frame; index++) { @@ -5959,6 +6185,7 @@ DN_API void DN_ProfilerFmtToStdout(DN_Profiler *profiler) DN_Str8 msg = DN_Str8FromPtr(buffer, fmt_len); DN_OS_PrintOutLnF("%.*s", DN_Str8PrintFmt(msg)); } + #endif } DN_API DN_F64 DN_ProfilerSecFromTsc(DN_Profiler *profiler, DN_U64 duration_tsc) @@ -6158,7 +6385,7 @@ DN_API DN_Profiler2Zone DN_Profiler2ZoneBegin(DN_Profiler2 *profiler, DN_Str8 na DN_U32 marker_index = frame->count - 1; DN_Profiler2Marker *marker = result.marker; marker->call_site = call_site; - marker->tsc_begin = profiler->tsc_now ? profiler->tsc_now() : DN_CPUGetTsc(); + marker->tsc_begin = profiler->tsc_now ? profiler->tsc_now() : DN_CpuTscNow(); marker->parent_index = profiler->active_parent_index; marker->name = name; @@ -6194,7 +6421,7 @@ DN_API void DN_Profiler2ZoneEnd(DN_Profiler2Zone *zone) // NOTE: Record the end timestamp DN_Profiler2* profiler = zone->profiler; - zone->marker->tsc_end = profiler->tsc_now ? profiler->tsc_now() : DN_CPUGetTsc(); + zone->marker->tsc_end = profiler->tsc_now ? profiler->tsc_now() : DN_CpuTscNow(); // NOTE: Calculate the total time consumed into the parent if (profiler->frame_begin_zone.marker != zone->marker) { @@ -6324,65 +6551,111 @@ static void DN_QSortInsertion_(void *array, DN_USize array_size, DN_USize elem_s DN_TcScratchEnd(&scratch); } +// NOTE: Three-way partition of [lo, hi) around a pivot (the middle element): [lo, *out_lt) < pivot, +// [*out_lt, *out_gt) == pivot, [*out_gt, hi) > pivot. Handling the equal band explicitly keeps the +// sort well behaved for arrays with many duplicate keys +static void DN_QSortPartition3_(void *array, DN_USize lo, DN_USize hi, DN_USize elem_size, void *user_context, DN_QSortCompareFunc *compare, DN_USize *out_lt, DN_USize *out_gt) +{ + + char temp_buffer[512]; + bool use_buffer = elem_size <= DN_ArrayCountU(temp_buffer); + DN_TcScratch scratch = {}; + char *pivot = {}; + if (use_buffer) { + pivot = temp_buffer; + } else { + scratch = DN_TcScratchBeginArena(nullptr, 0); + pivot = DN_ArenaNewArray(&scratch.arena, char, elem_size, DN_ZMem_No); + } + + DN_USize pivot_index = lo + ((hi - lo) / 2); + DN_Memcpy(pivot, DN_Cast(char *) array + (pivot_index * elem_size), elem_size); + + DN_USize lt = lo; + DN_USize gt = hi; + DN_USize index = lo; + while (index < gt) { + char *elem = DN_Cast(char *) array + (index * elem_size); + if (compare(elem, pivot, user_context)) { + // NOTE: elem < pivot + DN_QSortSwapElems_(array, elem_size, lt, index); + lt++; + index++; + } else if (compare(pivot, elem, user_context)) { + // NOTE: elem > pivot + gt--; + DN_QSortSwapElems_(array, elem_size, index, gt); + } else { + // NOTE: elem == pivot + index++; + } + } + + if (!use_buffer) + DN_TcScratchEnd(&scratch); + + *out_lt = lt; + *out_gt = gt; +} + DN_API void DN_QSort_(void *array, DN_USize array_size, DN_USize elem_size, void *user_context, DN_QSortCompareFunc *compare) { if (!array || array_size <= 1 || elem_size == 0 || !compare) return; - // NOTE: Insertion Sort, under 24->32 is an optimal amount DN_U8 *array_u8 = DN_Cast(DN_U8 *)array; DN_USize const QSORT_THRESHOLD = 24; - if (array_size < QSORT_THRESHOLD) { - DN_QSortInsertion_(array, array_size, elem_size, user_context, compare); - return; - } - // NOTE: Quick sort, under 24->32 is an optimal amount - DN_USize last_index = array_size - 1; - DN_USize pivot_index = array_size / 2; - DN_USize partition_index = 0; - DN_USize start_index = 0; + // NOTE: Non-recursive quick sort. An explicit stack of [lo, hi) ranges is used; we always push the + // smaller partition and continue with the larger one, which bounds the stack depth to O(log n) (64 + // entries cover any `n` up to 2^64). Ranges at or below the threshold are finished with insertion + // sort. The three-way partition keeps duplicate-heavy arrays shallow. + DN_USize stack[64][2]; + DN_USize stack_count = 0; + DN_USize lo = 0; + DN_USize hi = array_size; - // Swap pivot with last index, so pivot is always at the end of the array. - // This makes logic much simpler. - DN_QSortSwapElems_(array, elem_size, last_index, pivot_index); - pivot_index = last_index; + for (;;) { + while (hi - lo > QSORT_THRESHOLD) { + DN_USize lt = 0; + DN_USize gt = 0; + DN_QSortPartition3_(array, lo, hi, elem_size, user_context, compare, <, >); - // 4^, 8, 7, 5, 2, 3, 6 - if (compare(array_u8 + (start_index * elem_size), array_u8 + (pivot_index * elem_size), user_context)) - partition_index++; - start_index++; - - // 4, |8, 7, 5^, 2, 3, 6* - // 4, 5, |7, 8, 2^, 3, 6* - // 4, 5, 2, |8, 7, ^3, 6* - // 4, 5, 2, 3, |7, 8, ^6* - for (DN_USize index = start_index; index < last_index; index++) { - if (compare(array_u8 + (index * elem_size), array_u8 + (pivot_index * elem_size), user_context)) { - DN_QSortSwapElems_(array, elem_size, partition_index, index); - partition_index++; + // NOTE: [lo, lt) < pivot, [lt, gt) == pivot, [gt, hi) > pivot. Push the smaller side so the + // stack grows at most logarithmically. + DN_USize lt_pivot_count = lt - lo; + DN_USize gt_pivot_count = hi - gt; + if (lt_pivot_count < gt_pivot_count) { + if (lt_pivot_count > 1) { + DN_Assert(stack_count < DN_ArrayCountU(stack)); + stack[stack_count][0] = lo; + stack[stack_count][1] = lt; + stack_count++; + } + lo = gt; + } else { + if (gt_pivot_count > 1) { + DN_Assert(stack_count < DN_ArrayCountU(stack)); + stack[stack_count][0] = gt; + stack[stack_count][1] = hi; + stack_count++; + } + hi = lt; + } } + + if (hi - lo > 1) + DN_QSortInsertion_(array_u8 + (lo * elem_size), hi - lo, elem_size, user_context, compare); + + if (stack_count == 0) + break; + + stack_count--; + lo = stack[stack_count][0]; + hi = stack[stack_count][1]; } - - // Move pivot to right of partition - // 4, 5, 2, 3, |6, 8, ^7* - DN_QSortSwapElems_(array, elem_size, partition_index, pivot_index); - DN_QSort_(array_u8, partition_index, elem_size, user_context, compare); - - // Skip the value at partion index since that is guaranteed to be sorted. - // 4, 5, 2, 3, (x), 8, 7 - DN_USize one_after_partition_index = partition_index + 1; - DN_QSort_(array_u8 + (one_after_partition_index * elem_size), (array_size - one_after_partition_index), elem_size, user_context, compare); } -#if defined(__cplusplus) -template -DN_API void DN_QSort(T *array, DN_USize array_size, void *user_context, DN_QSortCompareFunc *compare) -{ - DN_QSort_(array, array_size, sizeof(T), user_context, compare); -} -#endif - DN_API bool DN_QSortCompareStr8NaturalAsc(void const* lhs, void const *rhs, void *user_context) { DN_Str8EqCase eq_case = *DN_Cast(DN_Str8EqCase *) user_context; @@ -7095,6 +7368,229 @@ DN_API DN_LogTypeParam DN_LogTypeParamFromType(DN_LogType type) return result; } +#if DN_WITH_OS +DN_API DN_StackTrace DN_StackTraceFromAllocator(DN_Allocator allocator, DN_U16 limit) +{ + DN_StackTrace result = {}; +#if defined(DN_OS_WIN32) + if (!allocator.context) + return result; + + static DN_TicketMutex mutex = {}; + DN_TicketMutexBegin(&mutex); + + HANDLE thread = GetCurrentThread(); + result.process = GetCurrentProcess(); + + DN_OSW32Core *w32 = DN_OS_W32GetCore(); + if (!w32->sym_initialised) { + w32->sym_initialised = true; + SymSetOptions(SYMOPT_LOAD_LINES); + if (!SymInitialize(result.process, nullptr /*UserSearchPath*/, true /*fInvadeProcess*/)) { + DN_TcScratch scratch = DN_TcScratchBeginAllocator(&allocator, 1); + DN_OSW32Error error = DN_OS_W32LastError(&scratch.arena); + DN_LogErrorF("SymInitialize failed, stack trace can not be generated (%lu): %.*s\n", error.code, DN_Str8PrintFmt(error.msg)); + DN_TcScratchEnd(&scratch); + } + } + + CONTEXT context; + RtlCaptureContext(&context); + + STACKFRAME64 frame = {}; + frame.AddrPC.Offset = context.Rip; + frame.AddrPC.Mode = AddrModeFlat; + frame.AddrFrame.Offset = context.Rbp; + frame.AddrFrame.Mode = AddrModeFlat; + frame.AddrStack.Offset = context.Rsp; + frame.AddrStack.Mode = AddrModeFlat; + + DN_U64 raw_frames[256] = {}; + DN_USize raw_frames_count = 0; + while (raw_frames_count < limit) { + if (!StackWalk64(IMAGE_FILE_MACHINE_AMD64, + result.process, + thread, + &frame, + &context, + nullptr /*ReadMemoryRoutine*/, + SymFunctionTableAccess64, + SymGetModuleBase64, + nullptr /*TranslateAddress*/)) + break; + + // NOTE: It might be useful one day to use frame.AddrReturn.Offset. + // If AddrPC.Offset == AddrReturn.Offset then we can detect recursion. + DN_LArrayAppend(raw_frames, &raw_frames_count, frame.AddrPC.Offset); + } + DN_TicketMutexEnd(&mutex); + + result.base_addr = DN_Cast(DN_U64 *)DN_AllocatorAlloc(allocator, raw_frames_count * sizeof(DN_U64), alignof(DN_U64), DN_ZMem_No); + DN_Assert(result.base_addr); + + result.size = DN_Cast(DN_U16) raw_frames_count; + DN_Memcpy(result.base_addr, raw_frames, raw_frames_count * sizeof(raw_frames[0])); +#else + (void)limit; + (void)allocator; +#endif + return result; +} + +DN_API DN_StackTrace DN_StackTraceFromArena(DN_Arena *arena, DN_U16 limit) +{ + DN_Allocator allocator = DN_AllocatorFromArena(arena); + DN_StackTrace result = DN_StackTraceFromAllocator(allocator, limit); + return result; +} + +DN_API bool DN_StackTraceIterate(DN_StackTraceIterator *it, DN_StackTrace const *trace) +{ + bool result = false; + if (!it || !trace || !trace->base_addr || !trace->process) + return result; + + if (it->index >= trace->size) + return false; + + result = true; + it->raw_frame.process = trace->process; + it->raw_frame.base_addr = trace->base_addr[it->index++]; + return result; +} + +static void DN_StackTraceAddToStr8Builder_(DN_StackTrace const *trace, DN_Str8Builder *builder, DN_USize skip) +{ + DN_StackTraceRawFrame raw_frame = {}; + raw_frame.process = trace->process; + for (DN_USize index = skip; index < trace->size; index++) { + raw_frame.base_addr = trace->base_addr[index]; + DN_StackTraceFrame frame = DN_StackTraceFrameFromRawFrame(builder->arena, raw_frame); + DN_Str8BuilderAppendF(builder, "%.*s(%zu): %.*s%s", DN_Str8PrintFmt(frame.file_name), frame.line_number, DN_Str8PrintFmt(frame.function_name), (DN_Cast(int) index == trace->size - 1) ? "" : "\n"); + } +} + +DN_API DN_Str8 DN_Str8FromStackTraceAllocator(DN_Allocator allocator, DN_StackTrace const *trace, DN_U16 skip) +{ + DN_Str8 result = {}; + if (!trace) + return result; + + DN_TcScratch scratch = DN_TcScratchBeginAllocator(&allocator, 1); + DN_Str8Builder builder = DN_Str8BuilderFromArena(&scratch.arena); + DN_StackTraceAddToStr8Builder_(trace, &builder, skip); + result = DN_Str8FromStr8BuilderAllocator(&builder, allocator); + DN_TcScratchEnd(&scratch); + return result; +} + +DN_API DN_Str8 DN_Str8FromStackTraceArena(DN_Arena *arena, DN_StackTrace const *trace, DN_U16 skip) +{ + DN_Str8 result = {}; + if (!trace || !arena) + return result; + + DN_TcScratch scratch = DN_TcScratchBeginArena(&arena, 1); + DN_Str8Builder builder = DN_Str8BuilderFromArena(&scratch.arena); + DN_StackTraceAddToStr8Builder_(trace, &builder, skip); + result = DN_Str8FromStr8BuilderArena(&builder, arena); + DN_TcScratchEnd(&scratch); + return result; +} + +DN_API DN_Str8 DN_Str8FromStackTraceNowAllocator(DN_Allocator allocator, DN_U16 limit, DN_U16 skip) +{ + DN_TcScratch scratch = DN_TcScratchBeginArena(DN_Cast(DN_Arena **) & allocator.context, 1); + DN_StackTrace walk = DN_StackTraceFromArena(&scratch.arena, limit); + DN_Str8 result = DN_Str8FromStackTraceAllocator(allocator, &walk, skip); + DN_TcScratchEnd(&scratch); + return result; +} + +DN_API DN_Str8 DN_Str8FromStackTraceNowArena(DN_Arena *arena, DN_U16 limit, DN_U16 skip) +{ + DN_Str8 result = DN_Str8FromStackTraceNowAllocator(DN_AllocatorFromArena(arena), limit, skip); + return result; +} + +DN_API DN_StackTraceFrameSlice DN_StackTraceGetFrames(DN_Arena *arena, DN_U16 limit) +{ + DN_StackTraceFrameSlice result = {}; + if (!arena) + return result; + + DN_TcScratch scratch = DN_TcScratchBeginArena(&arena, 1); + DN_StackTrace walk = DN_StackTraceFromArena(&scratch.arena, limit); + if (walk.size) { + if (DN_PArrayPrepareArena(result.data, 0, &result.count, arena, walk.size)) { + DN_USize slice_index = 0; + for (DN_StackTraceIterator it = {}; DN_StackTraceIterate(&it, &walk);) + result.data[slice_index++] = DN_StackTraceFrameFromRawFrame(arena, it.raw_frame); + } + } + DN_TcScratchEnd(&scratch); + return result; +} + +DN_API DN_StackTraceFrame DN_StackTraceFrameFromRawFrame(DN_Arena *arena, DN_StackTraceRawFrame raw_frame) +{ +#if defined(DN_OS_WIN32) + // NOTE: Get line+filename + IMAGEHLP_LINEW64 line; + line.SizeOfStruct = sizeof(line); + DWORD line_displacement = 0; + if (!SymGetLineFromAddrW64(raw_frame.process, raw_frame.base_addr, &line_displacement, &line)) + line = {}; + + // NOTE: Get function name + alignas(SYMBOL_INFOW) char buffer[sizeof(SYMBOL_INFOW) + (MAX_SYM_NAME * sizeof(wchar_t))] = {}; + SYMBOL_INFOW *symbol = DN_Cast(SYMBOL_INFOW *) buffer; + symbol->SizeOfStruct = sizeof(*symbol); + symbol->MaxNameLen = sizeof(buffer) - sizeof(*symbol); + + uint64_t symbol_displacement = 0; // Offset to the beginning of the symbol to the address + SymFromAddrW(raw_frame.process, raw_frame.base_addr, &symbol_displacement, symbol); + + // NOTE: Construct result + DN_Str16 file_name16 = DN_Str16FromPtr(line.FileName, DN_CStr16Count(line.FileName)); + DN_Str16 function_name16 = DN_Str16FromPtr(symbol->Name, symbol->NameLen); + + DN_StackTraceFrame result = {}; + result.address = raw_frame.base_addr; + result.line_number = line.LineNumber; + result.file_name = DN_OS_W32Str16ToStr8(arena, file_name16); + result.function_name = DN_OS_W32Str16ToStr8(arena, function_name16); + + if (result.function_name.count == 0) + result.function_name = DN_Str8Lit(""); + if (result.file_name.count == 0) + result.file_name = DN_Str8Lit(""); +#else + DN_StackTraceFrame result = {}; +#endif + return result; +} + +DN_API void DN_StackTracePrint(DN_U16 limit) +{ + DN_TcScratch scratch = DN_TcScratchBeginArena(nullptr, 0); + DN_StackTraceFrameSlice stack_trace = DN_StackTraceGetFrames(&scratch.arena, limit); + for (DN_ForItSize(it, DN_StackTraceFrame, stack_trace.data, stack_trace.count)) { + DN_StackTraceFrame frame = *it.data; + DN_OS_PrintErrLnF("%.*s(%I64u): %.*s", DN_Str8PrintFmt(frame.file_name), frame.line_number, DN_Str8PrintFmt(frame.function_name)); + } + DN_TcScratchEnd(&scratch); +} + +DN_API void DN_StackTraceReloadSymbols() +{ +#if defined(DN_OS_WIN32) + HANDLE process = GetCurrentProcess(); + SymRefreshModuleList(process); +#endif +} +#endif // DN_WITH_OS (for DN_StackTrace which gets compiled out completely) + DN_API DN_F32 DN_F32Lerp(DN_F32 a, DN_F32 t, DN_F32 b) { DN_F32 result = a + ((b - a) * t); @@ -8865,15 +9361,6 @@ struct DN_ArrayFindEqMemcmpContext_ void const *find; }; -DN_API void *DN_SliceAllocArena(void **data, DN_USize *slice_size_field, DN_USize count, DN_USize elem_size, DN_U8 align, DN_ZMem zmem, DN_Arena *arena) -{ - void *result = *data; - *data = DN_ArenaAlloc(arena, count * elem_size, align, zmem); - if (*data) - *slice_size_field = count; - return result; -} - DN_API DN_ArrayFindResult DN_ArrayFind(void *data, DN_USize count, DN_USize elem_size, void const *find, DN_ArrayFindEqFunc *eq_func) { DN_ArrayFindResult result = {}; @@ -9034,18 +9521,10 @@ DN_API void *DN_ArrayMakeArrayAssert(void *data, DN_USize *count, DN_USize max, return result; } -DN_API void *DN_ArrayMakeArrayArena(void **data, DN_USize *count, DN_USize *max, DN_USize elem_size, DN_Arena *arena, DN_USize make_count, DN_ZMem z_mem) +DN_API void *DN_ArrayMakeArrayAllocator(void **data, DN_USize *count, DN_USize *max, DN_USize elem_size, DN_Allocator allocator, DN_USize make_count, DN_ZMem z_mem) { void *result = nullptr; - if (DN_ArrayPrepareArena(data, *count, max, elem_size, arena, make_count)) - result = DN_ArrayMakeArray(*data, count, *max, elem_size, make_count, z_mem); - return result; -} - -DN_API void *DN_ArrayMakeArrayPool(void **data, DN_USize *count, DN_USize *max, DN_USize elem_size, DN_Pool *pool, DN_USize make_count, DN_ZMem z_mem) -{ - void *result = nullptr; - if (DN_ArrayPreparePool(data, *count, max, elem_size, pool, make_count)) + if (DN_ArrayPrepareAllocator(data, *count, max, elem_size, allocator, make_count)) result = DN_ArrayMakeArray(*data, count, *max, elem_size, make_count, z_mem); return result; } @@ -9067,18 +9546,10 @@ DN_API void *DN_ArrayAddArray(void *data, DN_USize *count, DN_USize max, DN_USiz return result; } -DN_API void *DN_ArrayAddArrayArena(void **data, DN_USize *count, DN_USize *max, DN_USize elem_size, DN_Arena *arena, void const *elems, DN_USize elems_count, DN_AddType add) +DN_API void *DN_ArrayAddArrayAllocator(void **data, DN_USize *count, DN_USize *max, DN_USize elem_size, DN_Allocator allocator, void const *elems, DN_USize elems_count, DN_AddType add) { void *result = nullptr; - if (DN_ArrayPrepareArena(data, *count, max, elem_size, arena, elems_count)) - result = DN_ArrayAddArray(*data, count, *max, elem_size, elems, elems_count, add); - return result; -} - -DN_API void *DN_ArrayAddArrayPool(void **data, DN_USize *count, DN_USize *max, DN_USize elem_size, DN_Pool *pool, void const *elems, DN_USize elems_count, DN_AddType add) -{ - void *result = nullptr; - if (DN_ArrayPreparePool(data, *count, max, elem_size, pool, elems_count)) + if (DN_ArrayPrepareAllocator(data, *count, max, elem_size, allocator, elems_count)) result = DN_ArrayAddArray(*data, count, *max, elem_size, elems, elems_count, add); return result; } @@ -9090,7 +9561,7 @@ DN_API void *DN_ArrayAddArrayAssert(void *data, DN_USize *count, DN_USize max, D return result; } -static bool DN_ArrayResizeAllocator_(void **data, DN_USize *count, DN_USize *max, DN_USize elem_size, DN_Allocator allocator, DN_USize new_max) +DN_API bool DN_ArrayResizeAllocator(void **data, DN_USize *count, DN_USize *max, DN_USize elem_size, DN_Allocator allocator, DN_USize new_max) { bool result = true; if (!max || new_max != *max) { @@ -9099,8 +9570,7 @@ static bool DN_ArrayResizeAllocator_(void **data, DN_USize *count, DN_USize *max if (buffer) { DN_USize bytes_to_copy = elem_size * DN_Min(*count, new_max); DN_Memcpy(buffer, *data, bytes_to_copy); - if (allocator.type == DN_AllocatorType_Pool) - DN_PoolDealloc(DN_Cast(DN_Pool *)allocator.context, *data); + DN_AllocatorDealloc(allocator, *data, (max ? *max : 0) * elem_size); *data = buffer; *count = DN_Min(*count, new_max); if (max) @@ -9113,88 +9583,38 @@ static bool DN_ArrayResizeAllocator_(void **data, DN_USize *count, DN_USize *max return result; } -DN_API bool DN_ArrayResizeArena(void **data, DN_USize *count, DN_USize *max, DN_USize elem_size, DN_Arena *arena, DN_USize new_max) -{ - DN_Allocator allocator = DN_AllocatorFromArena(arena); - bool result = DN_ArrayResizeAllocator_(data, count, max, elem_size, allocator, new_max); - return result; -} - -DN_API bool DN_ArrayResizePool(void **data, DN_USize *count, DN_USize *max, DN_USize elem_size, DN_Pool *pool, DN_USize new_max) -{ - DN_Allocator allocator = DN_AllocatorFromPool(pool); - bool result = DN_ArrayResizeAllocator_(data, count, max, elem_size, allocator, new_max); - return result; -} - -DN_API bool DN_ArrayReservePool(void **data, DN_USize *max, DN_USize elem_size, DN_Pool *pool, DN_USize new_max) +DN_API bool DN_ArrayReserveAllocator(void **data, DN_USize *max, DN_USize elem_size, DN_Allocator allocator, DN_USize new_max) { bool result = true; if (!max || new_max > *max) { DN_USize count = 0; - result = DN_ArrayResizePool(data, &count, max, elem_size, pool, new_max); + result = DN_ArrayResizeAllocator(data, &count, max, elem_size, allocator, new_max); } return result; } -DN_API bool DN_ArrayReserveArena(void **data, DN_USize *max, DN_USize elem_size, DN_Arena *arena, DN_USize new_max) -{ - bool result = true; - if (!max || new_max > *max) { - DN_USize count = 0; - result = DN_ArrayResizeArena(data, &count, max, elem_size, arena, new_max); - } - return result; -} - -DN_API bool DN_ArrayPreparePool(void **data, DN_USize count, DN_USize *max, DN_USize elem_size, DN_Pool *pool, DN_USize add_count) +DN_API bool DN_ArrayPrepareAllocator(void **data, DN_USize count, DN_USize *max, DN_USize elem_size, DN_Allocator allocator, DN_USize add_count) { bool result = true; DN_USize new_count = count + add_count; if (new_count > *max) { DN_USize new_max = DN_Max(DN_Max(*max * 2, new_count), 8); - result = DN_ArrayResizePool(data, &count, max, elem_size, pool, new_max); + result = DN_ArrayResizeAllocator(data, &count, max, elem_size, allocator, new_max); } return result; } -DN_API bool DN_ArrayPrepareArena(void **data, DN_USize count, DN_USize *max, DN_USize elem_size, DN_Arena *arena, DN_USize add_count) -{ - bool result = true; - DN_USize new_count = count + add_count; - if (new_count > *max) { - DN_USize new_max = DN_Max(DN_Max(*max * 2, new_count), 8); - result = DN_ArrayResizeArena(data, &count, max, elem_size, arena, new_max); - } - return result; -} - -DN_API DN_USize DN_ArrayCopyPtrArena(void **data, void const *src, DN_USize count, DN_USize elem_size, DN_Arena *arena) +DN_API DN_USize DN_ArrayCopyPtrAllocator(void **data, void const *src, DN_USize count, DN_USize elem_size, DN_Allocator allocator) { DN_USize result = 0; - if (DN_ArrayReserveArena(data, /*max=*/ &result, elem_size, arena, /*new_max=*/ count)) + if (DN_ArrayReserveAllocator(data, /*max=*/ &result, elem_size, allocator, /*new_max=*/ count)) DN_Memcpy(*data, src, elem_size * count); return result; } -DN_API DN_USize DN_ArrayCopyPtrArenaAssert(void **data, void const *src, DN_USize count, DN_USize elem_size, DN_Arena *arena, DN_CallSite call_site) +DN_API DN_USize DN_ArrayCopyPtrAllocatorAssert(void **data, void const *src, DN_USize count, DN_USize elem_size, DN_Allocator allocator, DN_CallSite call_site) { - DN_USize result = DN_ArrayCopyPtrArena(data, src, count, elem_size, arena); - DN_AssertCallSiteF(result == count, call_site, "Array copy failed, failed to allocate: %zu items", count); - return result; -} - -DN_API DN_USize DN_ArrayCopyPtrPool(void **data, void const *src, DN_USize count, DN_USize elem_size, DN_Pool *pool) -{ - DN_USize result = 0; - if (DN_ArrayReservePool(data, /*max=*/ &result, elem_size, pool, /*new_max=*/ count)) - DN_Memcpy(*data, src, elem_size * count); - return result; -} - -DN_API DN_USize DN_ArrayCopyPtrPoolAssert(void **data, void const *src, DN_USize count, DN_USize elem_size, DN_Pool *pool, DN_CallSite call_site) -{ - DN_USize result = DN_ArrayCopyPtrPool(data, src, count, elem_size, pool); + DN_USize result = DN_ArrayCopyPtrAllocator(data, src, count, elem_size, allocator); DN_AssertCallSiteF(result == count, call_site, "Array copy failed, failed to allocate: %zu items", count); return result; } @@ -9272,7 +9692,7 @@ DN_API bool DN_HTableKeyEqFuncStr8Eq(void const *lhs, void const *rhs, DN_USize) return result; } -DN_API DN_HTableInitArgs DN_HTableInitArgsDefault_(void** kvs, DN_USize size_of_kv, DN_USize offset_of_hash, DN_USize size_of_key, DN_USize offset_of_key, DN_USize size_of_value, DN_USize offset_of_value) +DN_API DN_HTableInitArgs DN_HTableInitArgsDefaultRaw(void** kvs, DN_USize size_of_kv, DN_USize offset_of_hash, DN_USize size_of_key, DN_USize offset_of_key, DN_USize size_of_value, DN_USize offset_of_value) { DN_HTableInitArgs result = {}; DN_AssertF((*kvs) == 0, "The key-value pointer must be null as the hash table will allocate the objects and keep the pointer in sync with the table for you: %p", *kvs); @@ -9290,7 +9710,7 @@ DN_API DN_HTableInitArgs DN_HTableInitArgsDefault_(void** kvs, DN_USize size_of_ return result; } -DN_API DN_HTable DN_HTableInit_(DN_HTableInitArgs args) +static DN_HTable DN_HTableInit_(DN_HTableInitArgs args) { DN_HTable result = {}; result.load_factor01 = args.load_factor; @@ -9306,17 +9726,19 @@ DN_API DN_HTable DN_HTableInit_(DN_HTableInitArgs args) return result; } -DN_API DN_HTableInitResult DN_HTableInitHeap(DN_HTableInitArgs args, DN_Heap heap) +DN_API DN_HTableInitResult DN_HTableInitHeap(DN_HTableInitArgs args, DN_Heap *heap) { DN_HTableInitResult result = {}; result.table = DN_HTableInit_(args); result.table.heap = heap; result.table.flags |= DN_HTableFlags_UsingHeap; result.success = DN_HTableResize(&result.table, args.max); + if (!result.success) + result.table = {}; return result; } -DN_API DN_HTable DN_HTableInitHeapAssert(DN_HTableInitArgs args, DN_Heap heap) +DN_API DN_HTable DN_HTableInitHeapAssert(DN_HTableInitArgs args, DN_Heap *heap) { DN_HTableInitResult init = DN_HTableInitHeap(args, heap); DN_HTable result = init.table; @@ -9324,7 +9746,7 @@ DN_API DN_HTable DN_HTableInitHeapAssert(DN_HTableInitArgs args, DN_Heap heap) return result; } -DN_API DN_HTableInitResult DN_HTableInitPool(DN_HTableInitArgs args, DN_Pool pool, DN_HTableDeallocPoolOnDeinit dealloc_pool) +DN_API DN_HTableInitResult DN_HTableInitPool(DN_HTableInitArgs args, DN_Pool *pool, DN_HTableDeallocPoolOnDeinit dealloc_pool) { DN_HTableInitResult result = {}; result.table = DN_HTableInit_(args); @@ -9337,7 +9759,7 @@ DN_API DN_HTableInitResult DN_HTableInitPool(DN_HTableInitArgs args, DN_Pool poo return result; } -DN_API DN_HTable DN_HTableInitPoolAssert(DN_HTableInitArgs args, DN_Pool pool, DN_HTableDeallocPoolOnDeinit dealloc_pool) +DN_API DN_HTable DN_HTableInitPoolAssert(DN_HTableInitArgs args, DN_Pool *pool, DN_HTableDeallocPoolOnDeinit dealloc_pool) { DN_HTableInitResult init = DN_HTableInitPool(args, pool, dealloc_pool); DN_HTable result = init.table; @@ -9348,11 +9770,11 @@ DN_API DN_HTable DN_HTableInitPoolAssert(DN_HTableInitArgs args, DN_Pool pool, D DN_API void DN_HTableDeinit(DN_HTable *table) { if ((table->flags & DN_HTableFlags_UsingHeap)) { - DN_HeapDealloc(&table->heap, *table->kvs, table->max * table->size_of_kv); + DN_HeapDealloc(table->heap, *table->kvs, table->max * table->size_of_kv); } else { - DN_PoolDealloc(&table->pool, *table->kvs); + DN_PoolDealloc(table->pool, *table->kvs); if (table->flags & DN_HTableFlags_DeallocPoolOnDeinit) - DN_ArenaDeinit(table->pool.arena); + DN_ArenaDeinit(table->pool->arena); } *table->kvs = nullptr; *table = {}; @@ -9439,9 +9861,9 @@ DN_API bool DN_HTableResize(DN_HTable *table, DN_USize new_max) void* new_kvs = {}; DN_USize new_kvs_size = new_max * table->size_of_kv; if (table->flags & DN_HTableFlags_UsingHeap) { - new_kvs = DN_HeapAllocCallSite(&table->heap, /*reserve*/ new_kvs_size, /*commit*/ new_kvs_size, DN_HeapAllocFlag_Nil, DN_CallSiteNowNamed("DN HTable Resize")); + new_kvs = DN_HeapAllocCallSite(table->heap, /*reserve*/ new_kvs_size, /*commit*/ new_kvs_size, DN_HeapAllocFlag_Nil, DN_CallSiteNowNamed("DN HTable Resize")); } else { - new_kvs = DN_PoolAlloc(&table->pool, new_max * table->size_of_kv); + new_kvs = DN_PoolAlloc(table->pool, new_max * table->size_of_kv); } if (new_kvs) { @@ -9459,9 +9881,9 @@ DN_API bool DN_HTableResize(DN_HTable *table, DN_USize new_max) if (old_kvs) { if (table->flags & DN_HTableFlags_UsingHeap) - DN_HeapDealloc(&table->heap, old_kvs, old_max * table->size_of_kv); + DN_HeapDealloc(table->heap, old_kvs, old_max * table->size_of_kv); else - DN_PoolDealloc(&table->pool, old_kvs); + DN_PoolDealloc(table->pool, old_kvs); } } @@ -10095,14 +10517,18 @@ DN_API void DN_TestGroupBeginF(DN_TestCore *test, char const *fmt, ...) // NOTE: Mark as active test->curr_group = group; + #if DN_WITH_OS group->ts_begin = DN_OS_PerfCounterNow(); + #endif } DN_API void DN_TestGroupEnd(DN_TestCore *test) { DN_TestGroup *group = test->curr_group; DN_AssertF(group, "Test group must be started before attempting to end it"); + #if DN_WITH_OS group->ts_end = DN_OS_PerfCounterNow(); + #endif test->curr_group = nullptr; } @@ -10124,7 +10550,9 @@ DN_API void DN_TestBeginF(DN_TestCore *test, char const *fmt, ...) // NOTE: Mark as active group->curr_entry = entry; + #if DN_WITH_OS entry->ts_begin = DN_OS_PerfCounterNow(); + #endif test->total_count++; } @@ -10135,7 +10563,9 @@ DN_API void DN_TestEnd(DN_TestCore *test) DN_TestEntry *entry = group->curr_entry; DN_AssertF(entry, "Test must be started before attempting to end a test in group (%.*s)", DN_Str8PrintFmt(group->name)); + #if DN_WITH_OS entry->ts_end = DN_OS_PerfCounterNow(); + #endif if (entry->failed) test->total_failed++; else @@ -10187,7 +10617,10 @@ DN_API DN_Str8 DN_Str8FromTestCore(DN_TestCore const *test, DN_Arena *arena, DN_ outcome_str8 = DN_Str8FmtAnsiColourV3F32Rgb255Arena(DN_AnsiColourMode_Fg, good_colour, &scratch.arena, "%.*s", DN_Str8PrintFmt(outcome_str8)); } - DN_F64 elapsed_ms = DN_OS_PerfCounterMs(entry->ts_begin, entry->ts_end); + DN_F64 elapsed_ms = 0; + #if DN_WITH_OS + DN_OS_PerfCounterMs(entry->ts_begin, entry->ts_end); + #endif DN_Str8BuilderAppendF(&builder, "%.*s %.*s (%.3fms)\n", DN_Str8PrintFmt(test_prefix), DN_Str8PrintFmt(outcome_str8), elapsed_ms); // NOTE: Output the test diagnostics, populated on failure @@ -10227,12 +10660,11 @@ DN_API DN_Str8 DN_Str8FromTestCore(DN_TestCore const *test, DN_Arena *arena, DN_ } } - DN_F64 elapsed_ms = DN_OS_PerfCounterMs(group->ts_begin, group->ts_end); - DN_MSVC_WARNING_PUSH - DN_MSVC_WARNING_DISABLE(6067) // _Param_(3) in call to 'DN_Str8BuilderAppendF' must be the address of a string. Actual type: 'const unsigned __int64'. - DN_MSVC_WARNING_DISABLE(6271) // Extra argument passed to 'DN_Str8BuilderAppendF'. + DN_F64 elapsed_ms = 0; + #if DN_WITH_OS + DN_OS_PerfCounterMs(group->ts_begin, group->ts_end); + #endif DN_Str8 group_prefix = DN_Str8FmtArena(&scratch.arena, "%'zu/%'zu test%s", group_successes, group->entries_count, group_successes > 1 ? "s" :""); - DN_MSVC_WARNING_POP if (flags & DN_Str8FromTestCoreFlags_Colour) { if (group_failures == 0) group_prefix = DN_Str8FmtAnsiColourV3F32Rgb255Arena(DN_AnsiColourMode_Fg, good_colour, &scratch.arena, "%.*s", DN_Str8PrintFmt(group_prefix)); @@ -10653,38 +11085,38 @@ DN_API DN_TestCore DN_TestSuite(DN_Arena *arena_) { for (DN_TestScopeF(&result, "[CPU] Query CPUID")) { DN_RefImplCPUReport ref_cpu_report = DN_RefImplCPUReport_Init(); - DN_CPUReport cpu_report = DN_CPUGetReport(); + DN_CpuReport cpu_report = DN_CpuGetReport(); - DN_TestVerifyExpr(&result, DN_CPUHasFeature(&cpu_report, DN_CPUFeature_3DNow) == ref_cpu_report._3DNOW()); - DN_TestVerifyExpr(&result, DN_CPUHasFeature(&cpu_report, DN_CPUFeature_3DNowExt) == ref_cpu_report._3DNOWEXT()); - DN_TestVerifyExpr(&result, DN_CPUHasFeature(&cpu_report, DN_CPUFeature_ABM) == ref_cpu_report.ABM()); - DN_TestVerifyExpr(&result, DN_CPUHasFeature(&cpu_report, DN_CPUFeature_AES) == ref_cpu_report.AES()); - DN_TestVerifyExpr(&result, DN_CPUHasFeature(&cpu_report, DN_CPUFeature_AVX) == ref_cpu_report.AVX()); - DN_TestVerifyExpr(&result, DN_CPUHasFeature(&cpu_report, DN_CPUFeature_AVX2) == ref_cpu_report.AVX2()); - DN_TestVerifyExpr(&result, DN_CPUHasFeature(&cpu_report, DN_CPUFeature_AVX512CD) == ref_cpu_report.AVX512CD()); - DN_TestVerifyExpr(&result, DN_CPUHasFeature(&cpu_report, DN_CPUFeature_AVX512ER) == ref_cpu_report.AVX512ER()); - DN_TestVerifyExpr(&result, DN_CPUHasFeature(&cpu_report, DN_CPUFeature_AVX512F) == ref_cpu_report.AVX512F()); - DN_TestVerifyExpr(&result, DN_CPUHasFeature(&cpu_report, DN_CPUFeature_AVX512PF) == ref_cpu_report.AVX512PF()); - DN_TestVerifyExpr(&result, DN_CPUHasFeature(&cpu_report, DN_CPUFeature_CMPXCHG16B) == ref_cpu_report.CMPXCHG16B()); - DN_TestVerifyExpr(&result, DN_CPUHasFeature(&cpu_report, DN_CPUFeature_F16C) == ref_cpu_report.F16C()); - DN_TestVerifyExpr(&result, DN_CPUHasFeature(&cpu_report, DN_CPUFeature_FMA) == ref_cpu_report.FMA()); - DN_TestVerifyExpr(&result, DN_CPUHasFeature(&cpu_report, DN_CPUFeature_MMX) == ref_cpu_report.MMX()); - DN_TestVerifyExpr(&result, DN_CPUHasFeature(&cpu_report, DN_CPUFeature_MmxExt) == ref_cpu_report.MMXEXT()); - DN_TestVerifyExpr(&result, DN_CPUHasFeature(&cpu_report, DN_CPUFeature_MONITOR) == ref_cpu_report.MONITOR()); - DN_TestVerifyExpr(&result, DN_CPUHasFeature(&cpu_report, DN_CPUFeature_MOVBE) == ref_cpu_report.MOVBE()); - DN_TestVerifyExpr(&result, DN_CPUHasFeature(&cpu_report, DN_CPUFeature_PCLMULQDQ) == ref_cpu_report.PCLMULQDQ()); - DN_TestVerifyExpr(&result, DN_CPUHasFeature(&cpu_report, DN_CPUFeature_POPCNT) == ref_cpu_report.POPCNT()); - DN_TestVerifyExpr(&result, DN_CPUHasFeature(&cpu_report, DN_CPUFeature_RDRAND) == ref_cpu_report.RDRAND()); - DN_TestVerifyExpr(&result, DN_CPUHasFeature(&cpu_report, DN_CPUFeature_RDSEED) == ref_cpu_report.RDSEED()); - DN_TestVerifyExpr(&result, DN_CPUHasFeature(&cpu_report, DN_CPUFeature_RDTscP) == ref_cpu_report.RDTscP()); - DN_TestVerifyExpr(&result, DN_CPUHasFeature(&cpu_report, DN_CPUFeature_SHA) == ref_cpu_report.SHA()); - DN_TestVerifyExpr(&result, DN_CPUHasFeature(&cpu_report, DN_CPUFeature_SSE) == ref_cpu_report.SSE()); - DN_TestVerifyExpr(&result, DN_CPUHasFeature(&cpu_report, DN_CPUFeature_SSE2) == ref_cpu_report.SSE2()); - DN_TestVerifyExpr(&result, DN_CPUHasFeature(&cpu_report, DN_CPUFeature_SSE3) == ref_cpu_report.SSE3()); - DN_TestVerifyExpr(&result, DN_CPUHasFeature(&cpu_report, DN_CPUFeature_SSE41) == ref_cpu_report.SSE41()); - DN_TestVerifyExpr(&result, DN_CPUHasFeature(&cpu_report, DN_CPUFeature_SSE42) == ref_cpu_report.SSE42()); - DN_TestVerifyExpr(&result, DN_CPUHasFeature(&cpu_report, DN_CPUFeature_SSE4A) == ref_cpu_report.SSE4a()); - DN_TestVerifyExpr(&result, DN_CPUHasFeature(&cpu_report, DN_CPUFeature_SSSE3) == ref_cpu_report.SSSE3()); + DN_TestVerifyExpr(&result, DN_CpuHasFeature(&cpu_report, DN_CpuFeature_3DNow) == ref_cpu_report._3DNOW()); + DN_TestVerifyExpr(&result, DN_CpuHasFeature(&cpu_report, DN_CpuFeature_3DNowExt) == ref_cpu_report._3DNOWEXT()); + DN_TestVerifyExpr(&result, DN_CpuHasFeature(&cpu_report, DN_CpuFeature_ABM) == ref_cpu_report.ABM()); + DN_TestVerifyExpr(&result, DN_CpuHasFeature(&cpu_report, DN_CpuFeature_AES) == ref_cpu_report.AES()); + DN_TestVerifyExpr(&result, DN_CpuHasFeature(&cpu_report, DN_CpuFeature_AVX) == ref_cpu_report.AVX()); + DN_TestVerifyExpr(&result, DN_CpuHasFeature(&cpu_report, DN_CpuFeature_AVX2) == ref_cpu_report.AVX2()); + DN_TestVerifyExpr(&result, DN_CpuHasFeature(&cpu_report, DN_CpuFeature_AVX512CD) == ref_cpu_report.AVX512CD()); + DN_TestVerifyExpr(&result, DN_CpuHasFeature(&cpu_report, DN_CpuFeature_AVX512ER) == ref_cpu_report.AVX512ER()); + DN_TestVerifyExpr(&result, DN_CpuHasFeature(&cpu_report, DN_CpuFeature_AVX512F) == ref_cpu_report.AVX512F()); + DN_TestVerifyExpr(&result, DN_CpuHasFeature(&cpu_report, DN_CpuFeature_AVX512PF) == ref_cpu_report.AVX512PF()); + DN_TestVerifyExpr(&result, DN_CpuHasFeature(&cpu_report, DN_CpuFeature_CMPXCHG16B) == ref_cpu_report.CMPXCHG16B()); + DN_TestVerifyExpr(&result, DN_CpuHasFeature(&cpu_report, DN_CpuFeature_F16C) == ref_cpu_report.F16C()); + DN_TestVerifyExpr(&result, DN_CpuHasFeature(&cpu_report, DN_CpuFeature_FMA) == ref_cpu_report.FMA()); + DN_TestVerifyExpr(&result, DN_CpuHasFeature(&cpu_report, DN_CpuFeature_MMX) == ref_cpu_report.MMX()); + DN_TestVerifyExpr(&result, DN_CpuHasFeature(&cpu_report, DN_CpuFeature_MmxExt) == ref_cpu_report.MMXEXT()); + DN_TestVerifyExpr(&result, DN_CpuHasFeature(&cpu_report, DN_CpuFeature_MONITOR) == ref_cpu_report.MONITOR()); + DN_TestVerifyExpr(&result, DN_CpuHasFeature(&cpu_report, DN_CpuFeature_MOVBE) == ref_cpu_report.MOVBE()); + DN_TestVerifyExpr(&result, DN_CpuHasFeature(&cpu_report, DN_CpuFeature_PCLMULQDQ) == ref_cpu_report.PCLMULQDQ()); + DN_TestVerifyExpr(&result, DN_CpuHasFeature(&cpu_report, DN_CpuFeature_POPCNT) == ref_cpu_report.POPCNT()); + DN_TestVerifyExpr(&result, DN_CpuHasFeature(&cpu_report, DN_CpuFeature_RDRAND) == ref_cpu_report.RDRAND()); + DN_TestVerifyExpr(&result, DN_CpuHasFeature(&cpu_report, DN_CpuFeature_RDSEED) == ref_cpu_report.RDSEED()); + DN_TestVerifyExpr(&result, DN_CpuHasFeature(&cpu_report, DN_CpuFeature_RDTscP) == ref_cpu_report.RDTscP()); + DN_TestVerifyExpr(&result, DN_CpuHasFeature(&cpu_report, DN_CpuFeature_SHA) == ref_cpu_report.SHA()); + DN_TestVerifyExpr(&result, DN_CpuHasFeature(&cpu_report, DN_CpuFeature_SSE) == ref_cpu_report.SSE()); + DN_TestVerifyExpr(&result, DN_CpuHasFeature(&cpu_report, DN_CpuFeature_SSE2) == ref_cpu_report.SSE2()); + DN_TestVerifyExpr(&result, DN_CpuHasFeature(&cpu_report, DN_CpuFeature_SSE3) == ref_cpu_report.SSE3()); + DN_TestVerifyExpr(&result, DN_CpuHasFeature(&cpu_report, DN_CpuFeature_SSE41) == ref_cpu_report.SSE41()); + DN_TestVerifyExpr(&result, DN_CpuHasFeature(&cpu_report, DN_CpuFeature_SSE42) == ref_cpu_report.SSE42()); + DN_TestVerifyExpr(&result, DN_CpuHasFeature(&cpu_report, DN_CpuFeature_SSE4A) == ref_cpu_report.SSE4a()); + DN_TestVerifyExpr(&result, DN_CpuHasFeature(&cpu_report, DN_CpuFeature_SSSE3) == ref_cpu_report.SSSE3()); } } #endif // defined(DN_PLATFORM_WIN32) && defined(DN_COMPILER_MSVC) @@ -10746,7 +11178,7 @@ DN_API DN_TestCore DN_TestSuite(DN_Arena *arena_) } for (DN_TestScopeF(&result, "[Intrinsics] CPUGetTsc compile check")) { - DN_CPUGetTsc(); + DN_CpuTscNow(); } for (DN_TestScopeF(&result, "[Intrinsics] CompilerReadBarrierAndCPUReadFence compile check")) { @@ -10765,9 +11197,9 @@ DN_API DN_TestCore DN_TestSuite(DN_Arena *arena_) for (DN_TestScopeF(&result, "[Arena] Reused memory is zeroed out")) { uint8_t alignment = 1; DN_USize alloc_size = DN_Kilobytes(128); - DN_MemList mem = DN_MemListFromHeap(0, 0, DN_MemFlags_Nil, DN_OS_HeapInitVirtual(), "Reused memory"); - DN_Arena arena = DN_ArenaFromMemList(&mem); - DN_DEFER { DN_MemListDeinit(&mem); }; + DN_MemList* mem = DN_MemListFromHeap(0, 0, DN_MemFlags_Nil, DN_OS_HeapInitVirtual(), "Reused memory"); + DN_Arena arena = DN_ArenaFromMemList(mem); + DN_DEFER { DN_MemListDeinit(mem); }; uintptr_t first_ptr_address = 0; { @@ -10787,9 +11219,9 @@ DN_API DN_TestCore DN_TestSuite(DN_Arena *arena_) } for (DN_TestScopeF(&result, "[Arena] Grows naturally, 1mb + 4mb")) { - DN_MemList mem = DN_MemListFromHeap(DN_Megabytes(2), DN_Megabytes(2), DN_MemFlags_Nil, DN_OS_HeapInitVirtual(), "Grows naturally"); - DN_Arena arena = DN_ArenaFromMemList(&mem); - DN_DEFER { DN_MemListDeinit(&mem); }; + DN_MemList* mem = DN_MemListFromHeap(DN_Megabytes(2), DN_Megabytes(2), DN_MemFlags_Nil, DN_OS_HeapInitVirtual(), "Grows naturally"); + DN_Arena arena = DN_ArenaFromMemList(mem); + DN_DEFER { DN_MemListDeinit(mem); }; char *ptr_1mb = DN_ArenaNewArray(&arena, char, DN_Megabytes(1), DN_ZMem_Yes); char *ptr_4mb = DN_ArenaNewArray(&arena, char, DN_Megabytes(4), DN_ZMem_Yes); @@ -10809,9 +11241,9 @@ DN_API DN_TestCore DN_TestSuite(DN_Arena *arena_) } for (DN_TestScopeF(&result, "[Arena] Grows naturally, 1mb, temp memory 4mb")) { - DN_MemList mem = DN_MemListFromHeap(DN_Megabytes(2), DN_Megabytes(2), DN_MemFlags_Nil, DN_OS_HeapInitVirtual(), "Grows naturally"); - DN_Arena arena = DN_ArenaFromMemList(&mem); - DN_DEFER { DN_MemListDeinit(&mem); }; + DN_MemList* mem = DN_MemListFromHeap(DN_Megabytes(2), DN_Megabytes(2), DN_MemFlags_Nil, DN_OS_HeapInitVirtual(), "Grows naturally"); + DN_Arena arena = DN_ArenaFromMemList(mem); + DN_DEFER { DN_MemListDeinit(mem); }; char *ptr_1mb = DN_Cast(char *) DN_ArenaAlloc(&arena, DN_Megabytes(1), 1, DN_ZMem_Yes); DN_TestVerifyExpr(&result, ptr_1mb != nullptr); @@ -11519,16 +11951,16 @@ DN_API DN_TestCore DN_TestSuite(DN_Arena *arena_) char arena_base[512]; for (DN_TestScopeF(&result, "[Strings] Format from arena")) { - DN_MemList mem = DN_MemListFromBuffer(arena_base, sizeof(arena_base), DN_MemFlags_Nil); - DN_Arena arena = DN_ArenaFromMemList(&mem); + DN_MemList* mem = DN_MemListFromBuffer(arena_base, sizeof(arena_base), DN_MemFlags_Nil); + DN_Arena arena = DN_ArenaFromMemList(mem); DN_Str8 str8 = DN_Str8FmtArena(&arena, "Foo Bar %d", 5); DN_Str8 expect = DN_Str8Lit("Foo Bar 5"); DN_TestVerifyStr8EqF(&result, str8, expect, "str8=%.*s", DN_Str8PrintFmt(str8), DN_Str8PrintFmt(expect)); } for (DN_TestScopeF(&result, "[Strings] Format from pool")) { - DN_MemList mem = DN_MemListFromBuffer(arena_base, sizeof(arena_base), DN_MemFlags_Nil); - DN_Arena arena = DN_ArenaFromMemList(&mem); + DN_MemList* mem = DN_MemListFromBuffer(arena_base, sizeof(arena_base), DN_MemFlags_Nil); + DN_Arena arena = DN_ArenaFromMemList(mem); DN_Pool pool = DN_PoolFromArena(&arena, 0); DN_Str8 str8 = DN_Str8FmtPool(&pool, "Foo Bar %d", 5); DN_Str8 expect = DN_Str8Lit("Foo Bar 5"); @@ -11599,29 +12031,29 @@ DN_API DN_TestCore DN_TestSuite(DN_Arena *arena_) } for (DN_TestScopeF(&result, "[Strings] Is all digits fails on non-digit string")) { - DN_B32 str_result = DN_Str8Is(DN_Str8Lit("@123string"), DN_Str8IsFlags_Digits); - DN_TestVerifyExpr(&result, str_result == false); + DN_Str8IsResult str_result = DN_Str8Is(DN_Str8Lit("@123string"), DN_Str8IsFlags_Digits); + DN_TestVerifyExpr(&result, !str_result.success); } for (DN_TestScopeF(&result, "[Strings] Is all digits fails on nullptr")) { - DN_B32 str_result = DN_Str8Is(DN_Str8FromPtr(nullptr, 0), DN_Str8IsFlags_Digits); - DN_TestVerifyExpr(&result, str_result == false); + DN_Str8IsResult str_result = DN_Str8Is(DN_Str8FromPtr(nullptr, 0), DN_Str8IsFlags_Digits); + DN_TestVerifyExpr(&result, !str_result.success); } for (DN_TestScopeF(&result, "[Strings] Is all digits fails on string w/ 0 size")) { - char const buf[] = "@123string"; - DN_B32 str_result = DN_Str8Is(DN_Str8FromPtr(buf, 0), DN_Str8IsFlags_Digits); - DN_TestVerifyExpr(&result, !str_result); + char const buf[] = "@123string"; + DN_Str8IsResult str_result = DN_Str8Is(DN_Str8FromPtr(buf, 0), DN_Str8IsFlags_Digits); + DN_TestVerifyExpr(&result, !str_result.success); } for (DN_TestScopeF(&result, "[Strings] Is all digits success")) { - DN_B32 str_result = DN_Str8Is(DN_Str8Lit("23"), DN_Str8IsFlags_Digits); - DN_TestVerifyExpr(&result, DN_Cast(bool) str_result == true); + DN_Str8IsResult str_result = DN_Str8Is(DN_Str8Lit("23"), DN_Str8IsFlags_Digits); + DN_TestVerifyExpr(&result, str_result.success); } for (DN_TestScopeF(&result, "[Strings] Is all digits fails on whitespace")) { - DN_B32 str_result = DN_Str8Is(DN_Str8Lit("23 "), DN_Str8IsFlags_Digits); - DN_TestVerifyExpr(&result, DN_Cast(bool) str_result == false); + DN_Str8IsResult str_result = DN_Str8Is(DN_Str8Lit("23 "), DN_Str8IsFlags_Digits); + DN_TestVerifyExpr(&result, !str_result.success); } // NOTE: DN_Str8BSplit @@ -12062,23 +12494,20 @@ DN_API DN_MemDebuggerSnapshot DN_MemDebuggerSnapshotMake(DN_MemDebugger *debugge if (!debugger) return result; + // NOTE: Exclude the snapshot arena from the memory debugger for the entire snapshot. The snapshot + // allocates its working memory from this arena while holding the debugger's mutexes, so tracking + // those allocations (or their commit growth) would re-enter those mutexes and dead-lock. + DN_HeapFlags arena_flags_copy = arena->mem->heap.flags; + if (arena->mem->flags & DN_MemFlags_Heap) + arena->mem->heap.flags |= DN_HeapFlags_ExcludeFromMemDebugger; + DN_TicketMutexBegin(&debugger->alloc_table_mutex); { DN_USize count_req = debugger->alloc_table.count; - // NOTE: Exclude this allocation from the memory debugger otherwise that will call into the - // memory debugger which engages the `alloc_table_mutex` it self causing a dead-lock. We restore - // the flag, if it was set after the fact. - DN_HeapFlags flags_copy = arena->mem->heap.flags; - { - if (arena->mem->flags & DN_MemFlags_Heap) - arena->mem->heap.flags &= ~DN_HeapFlags_ExcludeFromMemDebugger; - - // NOTE: Allocate memory - result.count = 0; - result.data = DN_ArenaNewArrayZ(arena, DN_MemDebuggerSnapshotPtrData, count_req); - } - arena->mem->heap.flags = flags_copy; + // NOTE: Allocate memory (this arena is excluded for the whole snapshot, see above) + result.count = 0; + result.data = DN_ArenaNewArrayZ(arena, DN_MemDebuggerSnapshotPtrData, count_req); // NOTE: Snapshot the allocation table if (result.data) { @@ -12090,25 +12519,135 @@ DN_API DN_MemDebuggerSnapshot DN_MemDebuggerSnapshotMake(DN_MemDebugger *debugge DN_MemDebuggerPtrData const *alloc = &kv->value; if (alloc->flags & DN_MemDebuggerPtrFlag_Freed) { result.freed_count++; - result.freed_bytes += alloc->size; + DN_CArrayCopy(result.freed_bytes, alloc->freed_bytes); } else { DN_MemDebuggerSnapshotPtrData *data = DN_PArrayMakeZ(result.data, &result.count, count_req); data->ptr = alloc->ptr; - data->size = alloc->size; data->flags = alloc->flags; - // NOTE: The strings in the call site are in the data-segment so shallow copy is fine - data->call_site = alloc->call_site; - data->stack_trace = DN_Str8FromStr8Arena(alloc->stack_trace, arena); - result.active_bytes += data->size; + DN_CArrayCopy(data->bytes, alloc->bytes); + + // NOTE: The strings in the call site are in the data-segment so shallow copy is fine, + // unless the heap-alloc flags are set, indicating that this is not the case. The debugger + // "owns" the memory and at any arbitrary point it can decide to free it, so we need to + // take ownership. + data->call_site = alloc->call_site; + if (debugger->flags & DN_MemDebuggerFlags_HeapAllocCallSiteStrings) { + data->call_site.name = DN_Str8FromStr8Arena(data->call_site.name, arena); + data->call_site.file = DN_Str8FromStr8Arena(data->call_site.file, arena); + data->call_site.function = DN_Str8FromStr8Arena(data->call_site.function, arena); + } + + data->stack_trace = DN_Str8FromStr8Arena(alloc->stack_trace, arena); + for (DN_ForIndexU(type, DN_MemDebuggerAllocType_Count)) + result.active_bytes[type] += data->bytes[type]; } } } } DN_TicketMutexEnd(&debugger->alloc_table_mutex); + + // NOTE: Snapshot the memory list registry. Read the count, allocate outside the registry lock, then + // fill under the lock so registry mutations cannot race with the copy. + DN_USize mem_list_count = 0; + DN_TicketMutexBegin(&debugger->mem_list_mutex); + mem_list_count = debugger->mem_list_table.count; + DN_TicketMutexEnd(&debugger->mem_list_mutex); + + result.mem_lists = DN_ArenaNewArrayZ(arena, DN_MemDebuggerMemListSnapshot, mem_list_count); + result.mem_lists_count = 0; + if (result.mem_lists) { + DN_TicketMutexBegin(&debugger->mem_list_mutex); + for (DN_ForItSize(it, DN_MemDebuggerMemListKV, debugger->mem_list_kvs, debugger->mem_list_table.max)) { + DN_MemDebuggerMemListKV *kv = it.data; + if (!DN_HTableHashIsValue(kv->hash)) + continue; + DN_MemDebuggerMemListSnapshot *dst = DN_PArrayMakeZ(result.mem_lists, &result.mem_lists_count, mem_list_count); + if (!dst) + break; + DN_MemList const *live = kv->key; + dst->mem_list = *live; + // NOTE: Wasted is the reserved-but-unused space of every block except the current (tail) block, + // which the bump allocator can never reclaim. Computed here while the blocks are still live. + dst->wasted = live->curr + ? (live->stats.info.reserve - live->stats.info.used) - (live->curr->reserve - live->curr->used) + : 0; + + // NOTE: Snapshot the block chain (tail → head) while the blocks are still live. + DN_USize block_count = 0; + for (DN_MemBlock const *block = live->curr; block; block = block->prev) + block_count++; + dst->blocks = DN_ArenaNewArrayZ(arena, DN_MemStats, block_count); + dst->blocks_count = 0; + for (DN_MemBlock const *block = live->curr; block; block = block->prev) { + DN_MemStats *block_stats = &dst->blocks[dst->blocks_count++]; + block_stats->info.used = block->used; + block_stats->info.commit = block->commit; + block_stats->info.reserve = block->reserve; + block_stats->info.blocks = 1; + } + + // NOTE: Snapshot the memory list's live allocations, sorted by alloc_size descending. + DN_MemDebuggerMemList *mem_list_entry = &kv->value; + DN_USize alloc_count = 0; + DN_TicketMutexBegin(&mem_list_entry->alloc_mutex); + alloc_count = mem_list_entry->allocs_count; + DN_TicketMutexEnd(&mem_list_entry->alloc_mutex); + + dst->allocs = DN_ArenaNewArrayZ(arena, DN_MemDebuggerMemListAlloc, alloc_count); + dst->allocs_count = 0; + if (dst->allocs) { + DN_TicketMutexBegin(&mem_list_entry->alloc_mutex); + for (DN_ForItSize(alloc_it, DN_MemDebuggerMemListAlloc, mem_list_entry->allocs, mem_list_entry->allocs_count)) { + DN_MemDebuggerMemListAlloc const *alloc_src = alloc_it.data; + DN_MemDebuggerMemListAlloc *dst_alloc = DN_PArrayMakeZ(dst->allocs, &dst->allocs_count, alloc_count); + if (!dst_alloc) + break; + *dst_alloc = *alloc_src; + if (debugger->flags & DN_MemDebuggerFlags_HeapAllocCallSiteStrings) { + dst_alloc->call_site.name = DN_Str8FromStr8Arena(dst_alloc->call_site.name, arena); + dst_alloc->call_site.file = DN_Str8FromStr8Arena(dst_alloc->call_site.file, arena); + dst_alloc->call_site.function = DN_Str8FromStr8Arena(dst_alloc->call_site.function, arena); + } + } + DN_TicketMutexEnd(&mem_list_entry->alloc_mutex); + DN_QSort(dst->allocs, dst->allocs_count, nullptr, DN_MemDebuggerMemListAllocQSortCompareAllocSizeGT); + } + + if (debugger->flags & DN_MemDebuggerFlags_HeapAllocCallSiteStrings) + dst->mem_list.label = DN_Str8FromStr8Arena(dst->mem_list.label, arena); + } + DN_TicketMutexEnd(&debugger->mem_list_mutex); + } + + // NOTE: Restore the arena's flags and re-sync its blocks' commit (their growth was excluded for the + // whole snapshot). + arena->mem->heap.flags = arena_flags_copy; + + DN_TicketMutexBegin(&debugger->alloc_table_mutex); + for (DN_MemBlock *block = arena->mem->curr; block; block = block->prev) + DN_MemDebuggerCommitUpdateLocked_(debugger, block); + DN_TicketMutexEnd(&debugger->alloc_table_mutex); + return result; } -bool DN_MemDebuggerSnapshotPtrDataQSortComparePtrLT(void const *lhs, void const *rhs, void*) +DN_API bool DN_MemDebuggerMemListSnapshotQSortCompareCommitGT(void const *lhs, void const *rhs, void *) +{ + DN_MemDebuggerMemListSnapshot const *lhs_it = *DN_Cast(DN_MemDebuggerMemListSnapshot const * const *) lhs; + DN_MemDebuggerMemListSnapshot const *rhs_it = *DN_Cast(DN_MemDebuggerMemListSnapshot const * const *) rhs; + bool result = lhs_it->mem_list.stats.info.commit > rhs_it->mem_list.stats.info.commit; + return result; +} + +DN_API bool DN_MemDebuggerMemListAllocQSortCompareAllocSizeGT(void const *lhs, void const *rhs, void *) +{ + DN_MemDebuggerMemListAlloc const *lhs_it = DN_Cast(DN_MemDebuggerMemListAlloc *) lhs; + DN_MemDebuggerMemListAlloc const *rhs_it = DN_Cast(DN_MemDebuggerMemListAlloc *) rhs; + bool result = lhs_it->alloc_size > rhs_it->alloc_size; + return result; +} + +DN_API bool DN_MemDebuggerSnapshotPtrDataQSortComparePtrLT(void const *lhs, void const *rhs, void*) { DN_MemDebuggerSnapshotPtrData const *lhs_it = DN_Cast(DN_MemDebuggerSnapshotPtrData *) lhs; DN_MemDebuggerSnapshotPtrData const *rhs_it = DN_Cast(DN_MemDebuggerSnapshotPtrData *) rhs; @@ -12116,22 +12655,40 @@ bool DN_MemDebuggerSnapshotPtrDataQSortComparePtrLT(void const *lhs, void const return result; } -DN_API void DN_MemDebuggerAlloc_(DN_MemDebugger *debugger, void *ptr, DN_USize size, bool leak_permitted, DN_CallSite call_site) +DN_API bool DN_MemDebuggerSnapshotPtrDataQSortCompareBytesLT(void const *lhs, void const *rhs, void *user_context) +{ + DN_MemDebuggerSnapshotPtrData const *lhs_it = *DN_Cast(DN_MemDebuggerSnapshotPtrData * const *) lhs; + DN_MemDebuggerSnapshotPtrData const *rhs_it = *DN_Cast(DN_MemDebuggerSnapshotPtrData * const *) rhs; + DN_MemDebuggerAllocType type = *DN_Cast(DN_MemDebuggerAllocType *) user_context; + bool result = lhs_it->bytes[type] < rhs_it->bytes[type]; + return result; +} + +DN_API bool DN_MemDebuggerSnapshotPtrDataQSortCompareBytesGT(void const *lhs, void const *rhs, void *user_context) +{ + DN_MemDebuggerSnapshotPtrData const *lhs_it = *DN_Cast(DN_MemDebuggerSnapshotPtrData * const *) lhs; + DN_MemDebuggerSnapshotPtrData const *rhs_it = *DN_Cast(DN_MemDebuggerSnapshotPtrData * const *) rhs; + DN_MemDebuggerAllocType type = *DN_Cast(DN_MemDebuggerAllocType *) user_context; + bool result = lhs_it->bytes[type] > rhs_it->bytes[type]; + return result; +} + +DN_API void DN_MemDebuggerAlloc_(DN_MemDebugger *debugger, void *ptr, DN_USize reserve, DN_USize commit, bool leak_permitted, DN_CallSite call_site) { if (!ptr) return; DN_TicketMutexBegin(&debugger->alloc_table_mutex); - DN_Str8 stack_trace = DN_Str8FromStackTraceNowHeap(128, 3 /*skip*/); + DN_Str8 stack_trace = DN_OS_Str8FromStackTraceNowHeap(128, 3 /*skip*/); DN_HTable* alloc_table = &debugger->alloc_table; DN_UPtr uptr = DN_Cast(DN_UPtr)ptr; DN_HTableAddResult alloc_entry = DN_HTableMake(alloc_table, &uptr); DN_MemDebuggerPtrData* alloc = DN_Cast(DN_MemDebuggerPtrData *)alloc_entry.slot.value; if (alloc_entry.existed) { if ((alloc->flags & DN_MemDebuggerPtrFlag_Freed) == 0) { - DN_Str8x32 alloc_size = DN_Str8x32FromByteCountU64Auto(alloc->size); - DN_Str8x32 new_alloc_size = DN_Str8x32FromByteCountU64Auto(size); + DN_Str8x32 alloc_size = DN_Str8x32FromByteCountU64Auto(alloc->bytes[DN_MemDebuggerAllocType_Commit]); + DN_Str8x32 new_alloc_size = DN_Str8x32FromByteCountU64Auto(commit); DN_AssertAlwaysF( alloc->flags & DN_MemDebuggerPtrFlag_Freed, "This pointer is already in the leak tracker, however it has not been freed yet. This " @@ -12157,18 +12714,40 @@ DN_API void DN_MemDebuggerAlloc_(DN_MemDebugger *debugger, void *ptr, DN_USize s debugger->alloc_table_bytes_allocated_for_stack_traces -= alloc->stack_trace.count; debugger->alloc_table_bytes_allocated_for_stack_traces -= alloc->freed_stack_trace.count; - DN_OS_MemDealloc(alloc->stack_trace.data); - DN_OS_MemDealloc(alloc->freed_stack_trace.data); + // NOTE: Strings inside the callsite are c-string literals stored in the data segment. So no deep + // copy is needed. But if you are dynamically loading and unloading libraries at runtime then + // these c-strings can become pointers to wiped memory once unloaded. The user can specify a flag + // to heap allocate these strings. + if (debugger->flags & DN_MemDebuggerFlags_HeapAllocCallSiteStrings) { + if (alloc->call_site.name.count) + DN_HeapDealloc(&debugger->heap, alloc->call_site.name.data, alloc->call_site.name.count + 1); + if (alloc->call_site.file.count) + DN_HeapDealloc(&debugger->heap, alloc->call_site.file.data, alloc->call_site.file.count + 1); + if (alloc->call_site.function.count) + DN_HeapDealloc(&debugger->heap, alloc->call_site.function.data, alloc->call_site.function.count + 1); + } + + if (alloc->stack_trace.count) + DN_HeapDealloc(&debugger->heap, alloc->stack_trace.data, alloc->stack_trace.count + 1); + if (alloc->freed_stack_trace.count) + DN_HeapDealloc(&debugger->heap, alloc->freed_stack_trace.data, alloc->freed_stack_trace.count + 1); *alloc = {}; } - alloc->ptr = ptr; - alloc->size = size; - alloc->stack_trace = stack_trace; - // NOTE: Strings inside the callsite are c-string literals stored in the data segment. So no deep - // copy is needed. - // TODO: Except, if we do DLL reloading, that's going to unload the string. - alloc->call_site = call_site; + alloc->ptr = ptr; + alloc->bytes[DN_MemDebuggerAllocType_Reserve] = reserve; + alloc->bytes[DN_MemDebuggerAllocType_Commit] = commit; + alloc->stack_trace = stack_trace; + + alloc->call_site = call_site; + + if (debugger->flags & DN_MemDebuggerFlags_HeapAllocCallSiteStrings) { + DN_Allocator heap_allocator = DN_AllocatorFromHeap(&debugger->heap); + alloc->call_site.name = DN_Str8FromStr8Allocator(alloc->call_site.name, heap_allocator); + alloc->call_site.file = DN_Str8FromStr8Allocator(alloc->call_site.file, heap_allocator); + alloc->call_site.function = DN_Str8FromStr8Allocator(alloc->call_site.function, heap_allocator); + } + alloc->flags |= leak_permitted ? DN_MemDebuggerPtrFlag_LeakPermitted : 0; debugger->alloc_table_bytes_allocated_for_stack_traces += alloc->stack_trace.count; DN_TicketMutexEnd(&debugger->alloc_table_mutex); @@ -12181,7 +12760,7 @@ DN_API void DN_MemDebuggerDealloc_(DN_MemDebugger *debugger, void *ptr) DN_TicketMutexBegin(&debugger->alloc_table_mutex); - DN_Str8 stack_trace = DN_Str8FromStackTraceNowHeap(128, 3 /*skip*/); + DN_Str8 stack_trace = DN_OS_Str8FromStackTraceNowHeap(128, 3 /*skip*/); DN_HTable* alloc_table = &debugger->alloc_table; DN_UPtr uptr = DN_Cast(DN_UPtr)ptr; DN_MemDebuggerPtrData* alloc = DN_Cast(DN_MemDebuggerPtrData *)DN_HTableValueFromFind(alloc_table, &uptr); @@ -12192,7 +12771,7 @@ DN_API void DN_MemDebuggerDealloc_(DN_MemDebugger *debugger, void *ptr) ptr); if (alloc->flags & DN_MemDebuggerPtrFlag_Freed) { - DN_Str8x32 freed_size = DN_Str8x32FromByteCountU64Auto(alloc->freed_size); + DN_Str8x32 freed_size = DN_Str8x32FromByteCountU64Auto(alloc->freed_bytes[DN_MemDebuggerAllocType_Commit]); DN_AssertAlwaysF((alloc->flags & DN_MemDebuggerPtrFlag_Freed) == 0, "Double free detected, pointer to free was already marked " "as freed. Either the pointer was reallocated but not " @@ -12218,6 +12797,8 @@ DN_API void DN_MemDebuggerDealloc_(DN_MemDebugger *debugger, void *ptr) DN_Assert(alloc->freed_stack_trace.count == 0); alloc->flags |= DN_MemDebuggerPtrFlag_Freed; + for (DN_ForIndexU(type, DN_MemDebuggerAllocType_Count)) + alloc->freed_bytes[type] = alloc->bytes[type]; alloc->freed_stack_trace = stack_trace; debugger->alloc_table_bytes_allocated_for_stack_traces += alloc->freed_stack_trace.count; DN_TicketMutexEnd(&debugger->alloc_table_mutex); @@ -12236,14 +12817,16 @@ DN_API void DN_MemDebuggerDump_(DN_MemDebugger *debugger) bool alloc_leaked = (alloc->flags & DN_MemDebuggerPtrFlag_Freed) == 0; bool leak_permitted = (alloc->flags & DN_MemDebuggerPtrFlag_LeakPermitted); if (alloc_leaked && !leak_permitted) { - leaked_bytes += alloc->size; + leaked_bytes += alloc->bytes[DN_MemDebuggerAllocType_Reserve]; leak_count++; - DN_Str8x32 alloc_size = DN_Str8x32FromByteCountU64Auto(alloc->size); + DN_Str8x32 reserve_size = DN_Str8x32FromByteCountU64Auto(alloc->bytes[DN_MemDebuggerAllocType_Reserve]); + DN_Str8x32 commit_size = DN_Str8x32FromByteCountU64Auto(alloc->bytes[DN_MemDebuggerAllocType_Commit]); DN_LogWarningF( - "Pointer (0x%p) leaked %.*s at:\n" + "Pointer (0x%p) leaked %.*s (commit: %.*s) at:\n" "%.*s", alloc->ptr, - DN_Str8PrintFmt(alloc_size), + DN_Str8PrintFmt(reserve_size), + DN_Str8PrintFmt(commit_size), DN_Str8PrintFmt(alloc->stack_trace)); } } @@ -12260,6 +12843,19 @@ DN_API void DN_MemDebuggerDump_(DN_MemDebugger *debugger) #include // getpagesize #endif +DN_API DN_Str8 DN_OS_Str8FromStackTraceNowHeap(DN_U16 limit, DN_U16 skip) +{ + DN_Heap heap = DN_OS_HeapInitBasic(); + heap.flags |= DN_HeapFlags_ExcludeFromMemDebugger; + DN_Arena arena = DN_ArenaFromHeap(DN_Kilobytes(64), DN_Kilobytes(64), DN_MemFlags_Nil, heap, "DN Stack Trace Arena"); + DN_Str8Builder builder = DN_Str8BuilderFromArena(&arena); + DN_StackTrace walk = DN_StackTraceFromArena(&arena, limit); + DN_StackTraceAddToStr8Builder_(&walk, &builder, skip); + DN_Str8 result = DN_OS_Str8FromStr8BuilderHeap(&builder); + DN_ArenaDeinit(&arena); + return result; +} + DN_API DN_Str8 DN_OS_Str8FromStr8BuilderHeap(DN_Str8Builder const *builder) { DN_Str8 result = DN_ZeroInit; @@ -12306,7 +12902,7 @@ static void DN_OS_LoggerSetFilePathNoMutex_(DN_OSLogger *logger, DN_Pool *pool, logger->file_path = {}; } DN_OS_FileClose(&logger->file); - logger->file_path = DN_Str8FmtOsPathPool(pool, "%.*s", DN_Str8PrintFmt(file_path)); + logger->file_path = DN_Str8PathFmtOsPool(pool, "%.*s", DN_Str8PrintFmt(file_path)).value; // NOTE: Clear the sticky file error flag if it was set logger->flags &= ~DN_OSLoggerFlags_FileError; @@ -12329,7 +12925,7 @@ static void DN_OS_DoLogFileSetupAndRotation_(DN_OSLogger *logger) // NOTE: Set a default file path to log to if it's not been set yet if (logger->file_path.count == 0) { DN_Str8 exe_dir = DN_OS_ExeDir(&scratch.arena); - DN_Str8 default_file_path = DN_Str8FmtOsPathArena(&scratch.arena, "%.*s/dn.log", DN_Str8PrintFmt(exe_dir)); + DN_Str8 default_file_path = DN_Str8PathFmtOsArena(&scratch.arena, "%.*s/dn.log", DN_Str8PrintFmt(exe_dir)).value; DN_OS_LoggerSetFilePathNoMutex_(logger, DN_TcMainPool(), default_file_path); } @@ -12565,7 +13161,7 @@ DN_API DN_Str8 DN_OS_ExeDir(DN_Arena *arena) return result; } -DN_API void DN_OS_OpenUrl(DN_Str8 url) +DN_API void DN_OS_OpenInDefaultApp(DN_Str8 url) { #if defined(DN_PLATFORM_WIN32) DN_TcScratch scratch = DN_TcScratchBeginArena(nullptr, 0); @@ -12578,6 +13174,16 @@ DN_API void DN_OS_OpenUrl(DN_Str8 url) #endif } +DN_API bool DN_OS_OnceEveryS(DN_U64 *tsc, DN_U64 interval_s) +{ + DN_U64 now = DN_OS_PerfCounterNow(); + DN_F64 delta_s = DN_OS_PerfCounterS(*tsc, now); + bool result = *tsc == 0 || delta_s >= DN_Cast(DN_F64)interval_s; + if (result) + *tsc = now; + return result; +} + // NOTE: Counters DN_API DN_F64 DN_OS_PerfCounterS(uint64_t begin, uint64_t end) { @@ -12647,19 +13253,19 @@ DN_API DN_F64 DN_OS_TimerNs(DN_OSTimer timer) return result; } -DN_API uint64_t DN_OS_EstimateTscPerSecond(uint64_t duration_ms_to_gauge_tsc_frequency) +DN_API DN_U64 DN_OS_EstimateTscPerSecond(DN_U64 duration_ms_to_gauge_tsc_frequency) { - uint64_t os_frequency = DN_OS_PerfCounterFrequency(); - uint64_t os_target_elapsed = duration_ms_to_gauge_tsc_frequency * os_frequency / 1000ULL; - uint64_t tsc_begin = DN_CPUGetTsc(); - uint64_t result = 0; + DN_U64 os_frequency = DN_OS_PerfCounterFrequency(); + DN_U64 os_target_elapsed = duration_ms_to_gauge_tsc_frequency * os_frequency / 1000ULL; + DN_U64 tsc_begin = DN_CpuTscNow(); + DN_U64 result = 0; if (tsc_begin) { - uint64_t os_elapsed = 0; + DN_U64 os_elapsed = 0; for (uint64_t os_begin = DN_OS_PerfCounterNow(); os_elapsed < os_target_elapsed;) os_elapsed = DN_OS_PerfCounterNow() - os_begin; - uint64_t tsc_end = DN_CPUGetTsc(); - uint64_t tsc_elapsed = tsc_end - tsc_begin; - result = tsc_elapsed / os_elapsed * os_frequency; + DN_U64 tsc_end = DN_CpuTscNow(); + DN_U64 tsc_elapsed = tsc_end - tsc_begin; + result = tsc_elapsed / os_elapsed * os_frequency; } return result; } @@ -12764,16 +13370,27 @@ DN_API DN_Str8 DN_OS_FileReadAll(DN_Allocator allocator, DN_Str8 path, DN_ErrSin } // NOTE: Allocate - DN_Arena temp_arena = {}; - if (allocator.type == DN_AllocatorType_Arena) { - DN_Arena *arena = DN_Cast(DN_Arena *) allocator.context; - temp_arena = DN_ArenaTempBeginFromArena(arena); - result = DN_Str8AllocArena(path_info.size, DN_ZMem_No, &temp_arena); - } else { - DN_Pool *pool = DN_Cast(DN_Pool *) allocator.context; - result = DN_Str8AllocPool(path_info.size, pool); + DN_Arena temp_arena = {}; + DN_MemListTemp temp_mem_list = {}; + DN_Allocator sub_allocator = {}; + switch (allocator.type) { + case DN_AllocatorType_Arena: { + temp_arena = DN_ArenaTempBeginFromArena(DN_Cast(DN_Arena *)allocator.context); + sub_allocator = DN_AllocatorFromArena(&temp_arena); + } break; + + case DN_AllocatorType_MemList: { + temp_mem_list = DN_MemListTempBegin(DN_Cast(DN_MemList *)allocator.context); + sub_allocator = DN_AllocatorFromMemList(temp_mem_list.mem); + } break; + + case DN_AllocatorType_Heap: /*FALLTHRU*/ + case DN_AllocatorType_Pool: { + sub_allocator = allocator; + } break; } + result = DN_Str8AllocAllocator(path_info.size, DN_ZMem_No, sub_allocator); if (!result.data) { DN_Str8x32 bytes_str = DN_Str8x32FromByteCountU64Auto(path_info.size); DN_ErrSinkAppendF(err, 1 /*err_code*/, "Failed to allocate %.*s for reading file '%.*s'", DN_Str8PrintFmt(bytes_str), DN_Str8PrintFmt(path)); @@ -12785,13 +13402,21 @@ DN_API DN_Str8 DN_OS_FileReadAll(DN_Allocator allocator, DN_Str8 path, DN_ErrSin DN_OSFileRead read = DN_OS_FileRead(&file, result.data, result.count, err); bool failed = file.error || !read.success; - if (allocator.type == DN_AllocatorType_Arena) { - DN_ArenaTempEnd(&temp_arena, failed ? DN_ArenaReset_Yes : DN_ArenaReset_No); - } else { - if (failed) { - DN_Pool *pool = DN_Cast(DN_Pool *) allocator.context; - DN_PoolDealloc(pool, result.data); - } + switch (allocator.type) { + case DN_AllocatorType_Arena: { + DN_ArenaTempEnd(&temp_arena, failed ? DN_ArenaReset_Yes : DN_ArenaReset_No); + } break; + + case DN_AllocatorType_MemList: { + if (failed) + DN_MemListTempEnd(temp_mem_list); + } break; + + case DN_AllocatorType_Heap: /*FALLTHRU*/ + case DN_AllocatorType_Pool: { + if (failed) + DN_AllocatorDealloc(sub_allocator, result.data, result.count + 1); + } break; } if (failed) @@ -12803,18 +13428,14 @@ DN_API DN_Str8 DN_OS_FileReadAll(DN_Allocator allocator, DN_Str8 path, DN_ErrSin DN_API DN_Str8 DN_OS_FileReadAllArena(DN_Arena *arena, DN_Str8 path, DN_ErrSink *err) { - DN_Allocator allocator = {}; - allocator.type = DN_AllocatorType_Arena; - allocator.context = arena; + DN_Allocator allocator = DN_AllocatorFromArena(arena); DN_Str8 result = DN_OS_FileReadAll(allocator, path, err); return result; } DN_API DN_Str8 DN_OS_FileReadAllPool(DN_Pool *pool, DN_Str8 path, DN_ErrSink *err) { - DN_Allocator allocator = {}; - allocator.type = DN_AllocatorType_Pool; - allocator.context = pool; + DN_Allocator allocator = DN_AllocatorFromPool(pool); DN_Str8 result = DN_OS_FileReadAll(allocator, path, err); return result; } @@ -12901,6 +13522,66 @@ DN_API bool DN_OS_PathIsOlderThan(DN_Str8 path, DN_Str8 check_against) return result; } +DN_API DN_OSPathResult DN_OS_PathRelativeTo(DN_Arena *arena, DN_Str8 from, DN_Str8 to) +{ + DN_OSPathResult result = {}; +#if defined(DN_OS_WIN32) + DN_TcScratch scratch = DN_TcScratchBeginArena(&arena, 1); + DN_Str16 from16 = DN_OS_W32Str8ToStr16(&scratch.arena, from); + DN_Str16 to16 = DN_OS_W32Str8ToStr16(&scratch.arena, to); + + DN_OSPathInfo from_info = DN_OS_PathInfo(from); + DN_OSPathInfo to_info = DN_OS_PathInfo(to); + DWORD from_attribute = from_info.type == DN_OSPathInfoType_Directory ? FILE_ATTRIBUTE_DIRECTORY : 0; + DWORD to_attribute = to_info.type == DN_OSPathInfoType_Directory ? FILE_ATTRIBUTE_DIRECTORY : 0; + + wchar_t relative_path[1024]; + relative_path[0] = 0; + + result.success = PathRelativePathToW(relative_path, from16.data, from_attribute, to16.data, to_attribute); + if (result.success) + result.path = DN_OS_W32Str16ToStr8(arena, DN_Str16FromPtr(relative_path, DN_CStr16Count(relative_path))); + DN_TcScratchEnd(&scratch); +#else + DN_AssertInvalidCodePathF("Unimplemented"); +#endif + return result; +} + +DN_API bool DN_OS_PathIsRelative(DN_Str8 path) +{ + bool result = false; +#if defined(DN_OS_WIN32) + DN_TcScratch scratch = DN_TcScratchBeginArena(nullptr, 0); + DN_Str16 path16 = DN_OS_W32Str8ToStr16(&scratch.arena, path); + result = PathIsRelativeW(path16.data); + DN_TcScratchEnd(&scratch); +#else + DN_AssertInvalidCodePathF("Unimplemented"); +#endif + return result; +} + +DN_API bool DN_OS_PathWatchFileHasChanged(DN_OSPathWatchFile *watch, DN_Str8 path, DN_OSPathWatchFileAcceptChange accept) +{ + DN_OSPathInfo info = DN_OS_PathInfo(path); + bool write_dirtied = watch->prev.last_write_time_in_s != info.last_write_time_in_s; + bool size_dirtied = watch->prev.size != info.size; + bool result = write_dirtied || size_dirtied; + if (result) { + if (accept == DN_OSPathWatchFileAcceptChange_Yes) + watch->prev = info; + else + watch->candidate = info; + } + return result; +} + +DN_API void DN_OS_PathWatchFileAcceptChange(DN_OSPathWatchFile *watch) +{ + watch->prev = watch->candidate; +} + DN_API DN_OSExecArgs DN_OS_ExecArgsDefault() { DN_OSExecArgs result = {}; @@ -12997,6 +13678,7 @@ DN_API void DN_OS_WindowCustomTitlebarSet(DN_OSWindow *window, bool custom_title DwmExtendFrameIntoClientArea(w32_window->hwnd, &margins); } } + #elif defined(DN_PLATFORM_EMSCRIPTEN) #else DN_AssertInvalidCodePath; #endif @@ -13541,249 +14223,6 @@ DN_API void DN_OS_PrintLnFVStyle(DN_OSPrintDest dest, DN_LogStyle style, DN_FMT_ DN_OS_Print(dest, DN_Str8Lit("\n")); } -DN_API DN_StackTrace DN_StackTraceFromAllocator(DN_Allocator allocator, DN_U16 limit) -{ - DN_StackTrace result = {}; -#if defined(DN_OS_WIN32) - if (!allocator.context) - return result; - - static DN_TicketMutex mutex = {}; - DN_TicketMutexBegin(&mutex); - - HANDLE thread = GetCurrentThread(); - result.process = GetCurrentProcess(); - - DN_OSW32Core *w32 = DN_OS_W32GetCore(); - if (!w32->sym_initialised) { - w32->sym_initialised = true; - SymSetOptions(SYMOPT_LOAD_LINES); - if (!SymInitialize(result.process, nullptr /*UserSearchPath*/, true /*fInvadeProcess*/)) { - DN_TcScratch scratch = DN_TcScratchBeginAllocator(&allocator, 1); - DN_OSW32Error error = DN_OS_W32LastError(&scratch.arena); - DN_LogErrorF("SymInitialize failed, stack trace can not be generated (%lu): %.*s\n", error.code, DN_Str8PrintFmt(error.msg)); - DN_TcScratchEnd(&scratch); - } - } - - CONTEXT context; - RtlCaptureContext(&context); - - STACKFRAME64 frame = {}; - frame.AddrPC.Offset = context.Rip; - frame.AddrPC.Mode = AddrModeFlat; - frame.AddrFrame.Offset = context.Rbp; - frame.AddrFrame.Mode = AddrModeFlat; - frame.AddrStack.Offset = context.Rsp; - frame.AddrStack.Mode = AddrModeFlat; - - DN_U64 raw_frames[256] = {}; - DN_USize raw_frames_count = 0; - while (raw_frames_count < limit) { - if (!StackWalk64(IMAGE_FILE_MACHINE_AMD64, - result.process, - thread, - &frame, - &context, - nullptr /*ReadMemoryRoutine*/, - SymFunctionTableAccess64, - SymGetModuleBase64, - nullptr /*TranslateAddress*/)) - break; - - // NOTE: It might be useful one day to use frame.AddrReturn.Offset. - // If AddrPC.Offset == AddrReturn.Offset then we can detect recursion. - DN_LArrayAppend(raw_frames, &raw_frames_count, frame.AddrPC.Offset); - } - DN_TicketMutexEnd(&mutex); - - result.base_addr = DN_Cast(DN_U64 *)DN_AllocatorAlloc(allocator, raw_frames_count * sizeof(DN_U64), alignof(DN_U64), DN_ZMem_No); - DN_Assert(result.base_addr); - - result.size = DN_Cast(DN_U16) raw_frames_count; - DN_Memcpy(result.base_addr, raw_frames, raw_frames_count * sizeof(raw_frames[0])); -#else - (void)limit; - (void)allocator; -#endif - return result; -} - - -DN_API DN_StackTrace DN_StackTraceFromArena(DN_Arena *arena, DN_U16 limit) -{ - DN_Allocator allocator = DN_AllocatorFromArena(arena); - DN_StackTrace result = DN_StackTraceFromAllocator(allocator, limit); - return result; -} - -static void DN_StackTraceAddToStr8Builder_(DN_StackTrace const *trace, DN_Str8Builder *builder, DN_USize skip) -{ - DN_StackTraceRawFrame raw_frame = {}; - raw_frame.process = trace->process; - for (DN_USize index = skip; index < trace->size; index++) { - raw_frame.base_addr = trace->base_addr[index]; - DN_StackTraceFrame frame = DN_StackTraceRawFrameToFrame(builder->arena, raw_frame); - DN_Str8BuilderAppendF(builder, "%.*s(%zu): %.*s%s", DN_Str8PrintFmt(frame.file_name), frame.line_number, DN_Str8PrintFmt(frame.function_name), (DN_Cast(int) index == trace->size - 1) ? "" : "\n"); - } -} - -DN_API bool DN_StackTraceIterate(DN_StackTraceIterator *it, DN_StackTrace const *trace) -{ - bool result = false; - if (!it || !trace || !trace->base_addr || !trace->process) - return result; - - if (it->index >= trace->size) - return false; - - result = true; - it->raw_frame.process = trace->process; - it->raw_frame.base_addr = trace->base_addr[it->index++]; - return result; -} - -DN_API DN_Str8 DN_Str8FromStackTraceAllocator(DN_Allocator allocator, DN_StackTrace const *trace, DN_U16 skip) -{ - DN_Str8 result = {}; - if (!trace) - return result; - - DN_TcScratch scratch = DN_TcScratchBeginAllocator(&allocator, 1); - DN_Str8Builder builder = DN_Str8BuilderFromArena(&scratch.arena); - DN_StackTraceAddToStr8Builder_(trace, &builder, skip); - result = DN_Str8FromStr8BuilderAllocator(&builder, allocator); - DN_TcScratchEnd(&scratch); - return result; -} - -DN_API DN_Str8 DN_Str8FromStackTraceArena(DN_Arena *arena, DN_StackTrace const *trace, DN_U16 skip) -{ - DN_Str8 result = {}; - if (!trace || !arena) - return result; - - DN_TcScratch scratch = DN_TcScratchBeginArena(&arena, 1); - DN_Str8Builder builder = DN_Str8BuilderFromArena(&scratch.arena); - DN_StackTraceAddToStr8Builder_(trace, &builder, skip); - result = DN_Str8FromStr8BuilderArena(&builder, arena); - DN_TcScratchEnd(&scratch); - return result; -} - -DN_API DN_Str8 DN_Str8FromStackTraceNowAllocator(DN_Allocator allocator, DN_U16 limit, DN_U16 skip) -{ - DN_TcScratch scratch = DN_TcScratchBeginArena(DN_Cast(DN_Arena **) & allocator.context, 1); - DN_StackTrace walk = DN_StackTraceFromArena(&scratch.arena, limit); - DN_Str8 result = DN_Str8FromStackTraceAllocator(allocator, &walk, skip); - DN_TcScratchEnd(&scratch); - return result; -} - -DN_API DN_Str8 DN_Str8FromStackTraceNowArena(DN_Arena *arena, DN_U16 limit, DN_U16 skip) -{ - DN_Str8 result = DN_Str8FromStackTraceNowAllocator(DN_AllocatorFromArena(arena), limit, skip); - return result; -} - -DN_API DN_Str8 DN_Str8FromStackTraceNowHeap(DN_U16 limit, DN_U16 skip) -{ - DN_Heap heap = DN_OS_HeapInitBasic(); - heap.flags |= DN_HeapFlags_ExcludeFromMemDebugger; - DN_Arena arena = DN_ArenaFromHeap(DN_Kilobytes(64), DN_Kilobytes(64), DN_MemFlags_Nil, heap, "DN Stack Trace Arena"); - DN_Str8Builder builder = DN_Str8BuilderFromArena(&arena); - DN_StackTrace walk = DN_StackTraceFromArena(&arena, limit); - DN_StackTraceAddToStr8Builder_(&walk, &builder, skip); - DN_Str8 result = DN_OS_Str8FromStr8BuilderHeap(&builder); - DN_ArenaDeinit(&arena); - return result; -} - -DN_API DN_StackTraceFrameSlice DN_StackTraceGetFrames(DN_Arena *arena, DN_U16 limit) -{ - DN_StackTraceFrameSlice result = {}; - if (!arena) - return result; - - DN_TcScratch scratch = DN_TcScratchBeginArena(&arena, 1); - DN_StackTrace walk = DN_StackTraceFromArena(&scratch.arena, limit); - if (walk.size) { - if (DN_ISliceAllocArena(&result, walk.size, DN_ZMem_No, arena)) { - DN_USize slice_index = 0; - for (DN_StackTraceIterator it = {}; DN_StackTraceIterate(&it, &walk);) - result.data[slice_index++] = DN_StackTraceRawFrameToFrame(arena, it.raw_frame); - } - } - DN_TcScratchEnd(&scratch); - return result; -} - -DN_API DN_StackTraceFrame DN_StackTraceRawFrameToFrame(DN_Arena *arena, DN_StackTraceRawFrame raw_frame) -{ -#if defined(DN_OS_WIN32) - // NOTE: Get line+filename - - // TODO: Why does zero-initialising this with `line = {};` cause - // SymGetLineFromAddr64 function to fail once we are at - // __scrt_commain_main_seh and hit BaseThreadInitThunk frame? The - // line and file number are still valid in the result which we use, so, - // we silently ignore this error. - IMAGEHLP_LINEW64 line; - line.SizeOfStruct = sizeof(line); - DWORD line_displacement = 0; - if (!SymGetLineFromAddrW64(raw_frame.process, raw_frame.base_addr, &line_displacement, &line)) - line = {}; - - // NOTE: Get function name - - alignas(SYMBOL_INFOW) char buffer[sizeof(SYMBOL_INFOW) + (MAX_SYM_NAME * sizeof(wchar_t))] = {}; - SYMBOL_INFOW *symbol = DN_Cast(SYMBOL_INFOW *) buffer; - symbol->SizeOfStruct = sizeof(*symbol); - symbol->MaxNameLen = sizeof(buffer) - sizeof(*symbol); - - uint64_t symbol_displacement = 0; // Offset to the beginning of the symbol to the address - SymFromAddrW(raw_frame.process, raw_frame.base_addr, &symbol_displacement, symbol); - - // NOTE: Construct result - - DN_Str16 file_name16 = DN_Str16FromPtr(line.FileName, DN_CStr16Count(line.FileName)); - DN_Str16 function_name16 = DN_Str16FromPtr(symbol->Name, symbol->NameLen); - - DN_StackTraceFrame result = {}; - result.address = raw_frame.base_addr; - result.line_number = line.LineNumber; - result.file_name = DN_OS_W32Str16ToStr8(arena, file_name16); - result.function_name = DN_OS_W32Str16ToStr8(arena, function_name16); - - if (result.function_name.count == 0) - result.function_name = DN_Str8Lit(""); - if (result.file_name.count == 0) - result.file_name = DN_Str8Lit(""); -#else - DN_StackTraceFrame result = {}; -#endif - return result; -} - -DN_API void DN_StackTracePrint(DN_U16 limit) -{ - DN_TcScratch scratch = DN_TcScratchBeginArena(nullptr, 0); - DN_StackTraceFrameSlice stack_trace = DN_StackTraceGetFrames(&scratch.arena, limit); - for (DN_ForItSize(it, DN_StackTraceFrame, stack_trace.data, stack_trace.count)) { - DN_StackTraceFrame frame = *it.data; - DN_OS_PrintErrLnF("%.*s(%I64u): %.*s", DN_Str8PrintFmt(frame.file_name), frame.line_number, DN_Str8PrintFmt(frame.function_name)); - } - DN_TcScratchEnd(&scratch); -} - -DN_API void DN_StackTraceReloadSymbols() -{ -#if defined(DN_OS_WIN32) - HANDLE process = GetCurrentProcess(); - SymRefreshModuleList(process); -#endif -} - #if defined(DN_PLATFORM_POSIX) || defined(DN_PLATFORM_EMSCRIPTEN) // DN: Single header generator commented out => #include "OS/dn_os_posix.cpp" #define DN_OS_POSIX_CPP @@ -13797,6 +14236,8 @@ DN_API void DN_StackTraceReloadSymbols() #include // readdir, opendir, closedir #include #include +#include // realpath +#include // sysconf, readlink // NOTE: DN_OSMem static DN_U32 DN_OS_MemConvertPageToOSFlags_(DN_U32 protect) @@ -14029,6 +14470,23 @@ DN_API DN_OSDiskSpace DN_OS_DiskSpace(DN_Str8 path) return result; } +DN_API DN_OSMemoryInfo DN_OS_MemoryInfo() +{ + DN_OSMemoryInfo result = {}; +#if defined(DN_PLATFORM_POSIX) + long page_size = sysconf(_SC_PAGESIZE); + long pages = sysconf(_SC_PHYS_PAGES); + long avail_pages = sysconf(_SC_AVPHYS_PAGES); + if (page_size > 0 && pages > 0) { + result.success = true; + result.total_phys = DN_Cast(DN_U64) pages * DN_Cast(DN_U64) page_size; + if (avail_pages > 0) + result.avail_phys = DN_Cast(DN_U64) avail_pages * DN_Cast(DN_U64) page_size; + } +#endif + return result; +} + DN_API DN_Str8 DN_OS_ExePath(DN_Arena *arena) { DN_Str8 result = {}; @@ -14385,6 +14843,23 @@ DN_API bool DN_OS_PathDelete(DN_Str8 path) return result; } +DN_API DN_OSPathResult DN_OS_PathCanonicalise(DN_Arena *arena, DN_Str8 path, DN_ErrSink *error) +{ + DN_OSPathResult result = {}; + DN_TcScratch scratch = DN_TcScratchBeginArena(&arena, 1); + DN_Str8 path_cstr = DN_Str8FromStr8Arena(path, &scratch.arena); // Ensure null-terminated + char *resolved = realpath(path_cstr.data, NULL); + if (resolved != NULL) { + result.success = true; + result.path = DN_Str8FromCStr8Arena(resolved, arena); + free(resolved); // realpath allocates with malloc + } else { + DN_ErrSinkAppendF(error, errno, "Failed to canonicalise path: %s", strerror(errno)); + } + DN_TcScratchEnd(&scratch); + return result; +} + DN_API bool DN_OS_PathIsFile(DN_Str8 path) { bool result = false; @@ -15065,14 +15540,20 @@ DN_API void DN_OS_ConditionVariableBroadcast(DN_OSConditionVariable *cv) DN_API DN_OSWindowMinimise DN_OS_WindowIsMinimised(DN_OSWindow *window) { (void)window; + #if defined(DN_PLATFORM_EMSCRIPTEN) + #else DN_AssertInvalidCodePath; + #endif return DN_OSWindowMinimise_No; } DN_API DN_OSWindowMaximise DN_OS_WindowIsMaximised(DN_OSWindow *window) { (void)window; + #if defined(DN_PLATFORM_EMSCRIPTEN) + #else DN_AssertInvalidCodePath; + #endif return DN_OSWindowMaximise_No; } @@ -15080,32 +15561,47 @@ DN_API void DN_OS_WindowSetTitle(DN_OSWindow *window, DN_Str8 title) { (void)window; (void)title; + #if defined(DN_PLATFORM_EMSCRIPTEN) + #else DN_AssertInvalidCodePath; + #endif } DN_API void DN_OS_WindowShow(DN_OSWindow *window, DN_OSWindowShow show) { (void)window; (void)show; + #if defined(DN_PLATFORM_EMSCRIPTEN) + #else DN_AssertInvalidCodePath; + #endif } DN_API void DN_OS_WindowBringToFront(DN_OSWindow *window) { (void)window; + #if defined(DN_PLATFORM_EMSCRIPTEN) + #else DN_AssertInvalidCodePath; + #endif } DN_API void DN_OS_WindowFocus(DN_OSWindow *window) { (void)window; + #if defined(DN_PLATFORM_EMSCRIPTEN) + #else DN_AssertInvalidCodePath; + #endif } DN_API bool DN_OS_WindowIsFocused(DN_OSWindow *window) { (void)window; + #if defined(DN_PLATFORM_EMSCRIPTEN) + #else DN_AssertInvalidCodePath; + #endif return false; } @@ -15288,7 +15784,8 @@ DN_API DN_OSPosixProcSelfStatus DN_OS_PosixProcSelfStatus() // #include // #endif -// NOTE: DN_Mem +//////////////////////////////////////////////////////////////////////////////////////////////////// +// NOTE: DN OS layer implementation static DN_U32 DN_OS_MemConvertPageToOSFlags_(DN_U32 protect) { DN_Assert((protect & ~DN_MemPage_All) == 0); @@ -15514,6 +16011,21 @@ DN_API DN_OSDiskSpace DN_OS_DiskSpace(DN_Str8 path) return result; } +DN_API DN_OSMemoryInfo DN_OS_MemoryInfo() +{ + DN_OSMemoryInfo result = {}; + MEMORYSTATUSEX status = {}; + status.dwLength = sizeof(status); + if (GlobalMemoryStatusEx(&status)) { + result.success = true; + result.total_phys = status.ullTotalPhys; + result.avail_phys = status.ullAvailPhys; + result.total_virtual = status.ullTotalVirtual; + result.avail_virtual = status.ullAvailVirtual; + } + return result; +} + DN_API bool DN_OS_SetEnvVar(DN_Str8 name, DN_Str8 value) { DN_TcScratch scratch = DN_TcScratchBeginArena(nullptr, 0); @@ -15530,7 +16042,7 @@ DN_API DN_Str8 DN_OS_ExePath(DN_Arena *arena) if (!arena) return result; DN_TcScratch scratch = DN_TcScratchBeginArena(&arena, 1); - DN_Str16 exe_dir16 = DN_OS_W32EXEPathW(&scratch.arena); + DN_Str16 exe_dir16 = DN_OS_W32ExePathW(&scratch.arena); result = DN_OS_W32Str16ToStr8(arena, exe_dir16); DN_TcScratchEnd(&scratch); return result; @@ -15819,6 +16331,25 @@ DN_API bool DN_OS_PathDelete(DN_Str8 path) return result; } +DN_API DN_OSPathResult DN_OS_PathCanonicalise(DN_Arena *arena, DN_Str8 path, DN_ErrSink *error) +{ + DN_OSPathResult result = {}; + DN_TcScratch scratch = DN_TcScratchBeginArena(&arena, 1); + DN_Str16 path16 = DN_OS_W32Str8ToStr16(&scratch.arena, path); + + wchar_t out_path[1024]; + HRESULT convert_result = PathCchCanonicalizeEx(out_path, DN_ArrayCountU(out_path), path16.data, PATHCCH_ALLOW_LONG_PATHS); + if (convert_result == S_OK) { + result.success = true; + result.path = DN_OS_W32Str16ToStr8(arena, DN_Str16FromPtr(out_path, DN_CStr16Count(out_path))); + } else { + DN_OSW32Error win_error = DN_OS_W32LastError(&scratch.arena); + DN_ErrSinkAppendF(error, win_error.code, "Failed to canonicalise path. %.*s", DN_Str8PrintFmt(win_error.msg)); + } + DN_TcScratchEnd(&scratch); + return result; +} + DN_API bool DN_OS_PathIsFile(DN_Str8 path) { bool result = false; @@ -15931,9 +16462,9 @@ DN_API bool DN_OS_PathIterateDir(DN_Str8 path, DN_OSDirIterator *it) // add those characters in this branch, so overwrite the null // character, add the glob and re-null terminate the buffer. if (needs_asterisks) - adjusted_path = DN_Str8FmtOsPathArena(&scratch.arena, "%.*s*", DN_Str8PrintFmt(path)); + adjusted_path = DN_Str8PathFmtOsArena(&scratch.arena, "%.*s*", DN_Str8PrintFmt(path)).value; else - adjusted_path = DN_Str8FmtOsPathArena(&scratch.arena, "%.*s/*", DN_Str8PrintFmt(path)); + adjusted_path = DN_Str8PathFmtOsArena(&scratch.arena, "%.*s/*", DN_Str8PrintFmt(path)).value; } path16 = DN_OS_W32Str8ToStr16(&scratch.arena, adjusted_path); @@ -16340,44 +16871,6 @@ DN_API DN_OSExecAsyncHandle DN_OS_ExecAsync(DN_Str8Slice cmd_line, DN_OSExecArgs return result; } -DN_API void DN_OS_W32Init(DN_OSW32Core *w32) -{ - InitializeCriticalSection(&w32->sync_primitive_free_list_mutex); - QueryPerformanceFrequency(&w32->qpc_frequency); - - // NOTE: DPI - HMODULE user32 = LoadLibraryA("user32.dll"); - if (user32) { - w32->get_dpi_for_window = (DN_OSW32GetDpiForWindowFunc* )GetProcAddress(user32, "GetDpiForWindow"); - w32->get_dpi_for_monitor = (DN_OSW32GetDpiForMonitorFunc * )GetProcAddress(user32, "GetDpiForMonitor"); - w32->get_system_metrics_for_dpi = (DN_OSW32GetSystemMetricsForDpiFunc *)GetProcAddress(user32, "GetSystemMetricsForDpi"); - FreeLibrary(user32); - } - - // NOTE: SetThreadDesc - HMODULE kernel32 = LoadLibraryA("kernel32.dll"); - if (kernel32) { - w32->set_thread_description = DN_Cast(DN_OSW32SetThreadDescriptionFunc *) GetProcAddress(kernel32, "SetThreadDescription"); - FreeLibrary(kernel32); - } - - // NOTE: win32 bcrypt - wchar_t const BCRYPT_ALGORITHM[] = L"RNG"; - long /*NTSTATUS*/ init_status = BCryptOpenAlgorithmProvider(&w32->bcrypt_rng_handle, BCRYPT_ALGORITHM, nullptr /*implementation*/, 0 /*flags*/); - if (w32->bcrypt_rng_handle && init_status == 0) - w32->bcrypt_init_success = true; - else - DN_LogErrorF("Failed to initialise Windows secure random number generator, error: %d", init_status); -} - -DN_API DN_OSW32Core *DN_OS_W32GetCore() -{ - DN_Core *dn = DN_Get(); - DN_Assert(dn && dn->os_init); - DN_OSW32Core *result = DN_Cast(DN_OSW32Core *)dn->os.platform_context; - return result; -} - static DN_OSW32SyncPrimitive *DN_OS_U64ToW32SyncPrimitive_(DN_U64 u64) { DN_OSW32SyncPrimitive *result = nullptr; @@ -16423,7 +16916,6 @@ static void DN_OS_W32DeallocSyncPrimitive_(DN_OSW32SyncPrimitive *primitive) } } -// NOTE: DN_OSSemaphore DN_API DN_OSSemaphore DN_OS_SemaphoreInit(DN_U32 initial_count) { DN_OSSemaphore result = {}; @@ -16472,7 +16964,6 @@ DN_API DN_OSSemaphoreWaitResult DN_OS_SemaphoreWait(DN_OSSemaphore *semaphore, D return result; } -// NOTE: DN_OSBarrier DN_API DN_OSBarrier DN_OS_BarrierInit(DN_U32 thread_count) { DN_OSBarrier result = {}; @@ -16543,7 +17034,6 @@ DN_API void DN_OS_MutexUnlock(DN_OSMutex *mutex) } } -// NOTE: DN_OSConditionVariable //////////////////////////////////////////////////////////////////// DN_API DN_OSConditionVariable DN_OS_ConditionVariableInit() { DN_OSW32SyncPrimitive *primitive = DN_OS_W32AllocSyncPrimitive_(); @@ -16727,6 +17217,69 @@ DN_API DN_U32 DN_OS_ThreadID() return result; } +//////////////////////////////////////////////////////////////////////////////////////////////////// +// NOTE: DN Win32 book-keeping +DN_API void DN_OS_W32Init(DN_OSW32Core *w32) +{ + InitializeCriticalSection(&w32->sync_primitive_free_list_mutex); + QueryPerformanceFrequency(&w32->qpc_frequency); + + // NOTE: DPI + HMODULE user32 = LoadLibraryA("user32.dll"); + if (user32) { + w32->get_dpi_for_window = (DN_OSW32GetDpiForWindowFunc* )GetProcAddress(user32, "GetDpiForWindow"); + w32->get_dpi_for_monitor = (DN_OSW32GetDpiForMonitorFunc * )GetProcAddress(user32, "GetDpiForMonitor"); + w32->get_system_metrics_for_dpi = (DN_OSW32GetSystemMetricsForDpiFunc *)GetProcAddress(user32, "GetSystemMetricsForDpi"); + FreeLibrary(user32); + } + + // NOTE: SetThreadDesc + HMODULE kernel32 = LoadLibraryA("kernel32.dll"); + if (kernel32) { + w32->set_thread_description = DN_Cast(DN_OSW32SetThreadDescriptionFunc *) GetProcAddress(kernel32, "SetThreadDescription"); + FreeLibrary(kernel32); + } + + // NOTE: win32 bcrypt + wchar_t const BCRYPT_ALGORITHM[] = L"RNG"; + long /*NTSTATUS*/ init_status = BCryptOpenAlgorithmProvider(&w32->bcrypt_rng_handle, BCRYPT_ALGORITHM, nullptr /*implementation*/, 0 /*flags*/); + if (w32->bcrypt_rng_handle && init_status == 0) + w32->bcrypt_init_success = true; + else + DN_LogErrorF("Failed to initialise Windows secure random number generator, error: %d", init_status); +} + +DN_API DN_OSW32Core *DN_OS_W32GetCore() +{ + DN_Core *dn = DN_Get(); + DN_Assert(dn && dn->os_init); + DN_OSW32Core *result = DN_Cast(DN_OSW32Core *)dn->os.platform_context; + return result; +} + +DN_API DN_OSW32Window* DN_OS_W32WindowFromHwndMaybeAlloc(DN_OSW32Core *w32, HWND hwnd, DN_Arena *arena) +{ + DN_OSW32Window *result = nullptr; + for (DN_OSW32Window *check = w32->windows; !result && check; check = check->next) { + if (check->hwnd == hwnd) + result = check; + } + + if (!result && arena) { + result = DN_ArenaNewZ(arena, DN_OSW32Window); + if (result) { + result->hwnd = hwnd; + if (w32->windows) + w32->windows->next = result; + result->next = w32->windows; + w32->windows = result; + } + } + return result; +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// +// NOTE: Process management DN_API void DN_OS_W32ThreadSetName(DN_Str8 name) { // NOTE: SetThreadDescription is only available in @@ -16758,7 +17311,7 @@ DN_API void DN_OS_W32ThreadSetName(DN_Str8 name) // TODO: Review warning 6320 DN_MSVC_WARNING_PUSH - DN_MSVC_WARNING_DISABLE(6320) // Exception-filter expression is the constant EXCEPTION_EXECUTE_HANDLER. This might mask exceptions that were not intended to be handled + DN_MSVC_WARNING_DISABLE(6320) // Exception-filter expression is the constant EXCEPTION_ExeCUTE_HANDLER. This might mask exceptions that were not intended to be handled DN_MSVC_WARNING_DISABLE(6322) // Empty _except block __try { RaiseException(0x406D1388, 0, sizeof(info) / sizeof(void *), (const ULONG_PTR *)&info); @@ -16769,27 +17322,6 @@ DN_API void DN_OS_W32ThreadSetName(DN_Str8 name) DN_TcScratchEnd(&scratch); } -DN_API DN_OSW32Window* DN_OS_W32WindowFromHwndMaybeAlloc(DN_OSW32Core *w32, HWND hwnd, DN_Arena *arena) -{ - DN_OSW32Window *result = nullptr; - for (DN_OSW32Window *check = w32->windows; !result && check; check = check->next) { - if (check->hwnd == hwnd) - result = check; - } - - if (!result && arena) { - result = DN_ArenaNewZ(arena, DN_OSW32Window); - if (result) { - result->hwnd = hwnd; - if (w32->windows) - w32->windows->next = result; - result->next = w32->windows; - w32->windows = result; - } - } - return result; -} - DN_API LRESULT __stdcall DN_OS_W32WindowProcCustomTitlebar(HWND hwnd, UINT msg, WPARAM w_param, LPARAM l_param) { DN_OSW32Core *w32 = DN_OS_W32GetCore(); @@ -16923,6 +17455,81 @@ DN_API LRESULT __stdcall DN_OS_W32WindowProcCustomTitlebar(HWND hwnd, UINT msg, return result; } +DN_API void DN_OS_W32MakeProcessDPIAware() +{ + typedef bool SetProcessDpiAwareProc(void); + typedef bool SetProcessDpiAwarenessProc(DPI_AWARENESS); + typedef bool SetProcessDpiAwarenessContextProc(void * /*DPI_AWARENESS_CONTEXT*/); + + // NOTE(doyle): Taken from cmuratori/refterm snippet on DPI awareness. It + // appears we can make this robust by just loading user32.dll and using + // GetProcAddress on the DPI function. If it's not there, we're on an old + // version of windows, so we can call an older version of the API. + void *lib_handle = LoadLibraryA("user32.dll"); + if (!lib_handle) + return; + + if (auto *set_process_dpi_awareness_context = DN_Cast(SetProcessDpiAwarenessContextProc *) GetProcAddress(DN_Cast(HMODULE) lib_handle, "SetProcessDpiAwarenessContext")) + set_process_dpi_awareness_context(DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2); + else if (auto *set_process_dpi_awareness = DN_Cast(SetProcessDpiAwarenessProc *) GetProcAddress(DN_Cast(HMODULE) lib_handle, "SetProcessDpiAwareness")) + set_process_dpi_awareness(DPI_AWARENESS_PER_MONITOR_AWARE); + else if (auto *set_process_dpi_aware = DN_Cast(SetProcessDpiAwareProc *) GetProcAddress(DN_Cast(HMODULE) lib_handle, "SetProcessDpiAware")) + set_process_dpi_aware(); +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// +// NOTE: DLL +DN_API void DN_OS_W32DllUnload(DN_OSW32DllCore *dll) +{ + if (dll) { + if (dll->handle) { + FreeLibrary(DN_Cast(HMODULE) dll->handle); + dll->handle = nullptr; + } + + for (DN_ForItSize(it, DN_OSW32DllFunction, dll->functions, dll->functions_count)) + it.data->func_ptr = nullptr; + } +} + +DN_API DN_OSW32DllLoadFunctionsResult DN_OS_W32DllLoadFunctions(DN_OSW32DllCore *dll, DN_Str8 dll_path) +{ + DN_OSW32DllLoadFunctionsResult result = DN_OSW32DllLoadFunctionsResult_LoadLibraryFailed; + HMODULE handle = LoadLibraryA(dll_path.data); + if (handle) { + bool all_good = true; + + // NOTE: Validate that all the functions can be loaded from the DLL + for (DN_ForItSize(it, DN_OSW32DllFunction, dll->functions, dll->functions_count)) { + DN_Str8 func_name = it.data->name; + DN_AssertF(func_name.count && func_name.data[func_name.count] == 0, "Function name must be set and null-terminated"); + void *func_ptr = GetProcAddress(handle, func_name.data); + all_good &= (func_ptr != nullptr); + } + + // NOTE: If all functions can be loaded, then mutate the user's `dll` struct + if (all_good) { + result = DN_OSW32DllLoadFunctionsResult_Ok; + for (DN_ForItSize(it, DN_OSW32DllFunction, dll->functions, dll->functions_count)) { + DN_Str8 func_name = it.data->name; + it.data->func_ptr = GetProcAddress(handle, func_name.data); + } + + // NOTE: Cleanup the old handle + if (dll->handle) + FreeLibrary(DN_Cast(HMODULE) dll->handle); + dll->handle = handle; + DN_StackTraceReloadSymbols(); + } else { + FreeLibrary(handle); + result = DN_OSW32DllLoadFunctionsResult_FunctionMissing; + } + } + return result; +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// +// NOTE: Errors DN_API DN_Str16 DN_OS_W32ErrorCodeToMsg16Alloc(DN_U32 error_code) { DWORD flags = FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS; @@ -16985,28 +17592,8 @@ DN_API DN_OSW32Error DN_OS_W32LastErrorAlloc() return result; } -DN_API void DN_OS_W32MakeProcessDPIAware() -{ - typedef bool SetProcessDpiAwareProc(void); - typedef bool SetProcessDpiAwarenessProc(DPI_AWARENESS); - typedef bool SetProcessDpiAwarenessContextProc(void * /*DPI_AWARENESS_CONTEXT*/); - - // NOTE(doyle): Taken from cmuratori/refterm snippet on DPI awareness. It - // appears we can make this robust by just loading user32.dll and using - // GetProcAddress on the DPI function. If it's not there, we're on an old - // version of windows, so we can call an older version of the API. - void *lib_handle = LoadLibraryA("user32.dll"); - if (!lib_handle) - return; - - if (auto *set_process_dpi_awareness_context = DN_Cast(SetProcessDpiAwarenessContextProc *) GetProcAddress(DN_Cast(HMODULE) lib_handle, "SetProcessDpiAwarenessContext")) - set_process_dpi_awareness_context(DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2); - else if (auto *set_process_dpi_awareness = DN_Cast(SetProcessDpiAwarenessProc *) GetProcAddress(DN_Cast(HMODULE) lib_handle, "SetProcessDpiAwareness")) - set_process_dpi_awareness(DPI_AWARENESS_PER_MONITOR_AWARE); - else if (auto *set_process_dpi_aware = DN_Cast(SetProcessDpiAwareProc *) GetProcAddress(DN_Cast(HMODULE) lib_handle, "SetProcessDpiAware")) - set_process_dpi_aware(); -} - +//////////////////////////////////////////////////////////////////////////////////////////////////// +// NOTE: Windows Str8 <-> Str16 DN_API DN_Str16 DN_OS_W32Str8ToStr16(DN_Arena *arena, DN_Str8 src) { DN_Str16 result = {}; @@ -17128,8 +17715,9 @@ DN_API DN_Str8 DN_OS_W32Str16ToStr8FromHeap(DN_Str16 src) return result; } -// NOTE: Windows Executable Directory ////////////////////////////////////////// -DN_API DN_Str16 DN_OS_W32EXEPathW(DN_Arena *arena) +//////////////////////////////////////////////////////////////////////////////////////////////////// +// NOTE: Path navigation +DN_API DN_Str16 DN_OS_W32ExePathW(DN_Arena *arena) { DN_TcScratch scratch = DN_TcScratchBeginArena(&arena, 1); DN_Str16 result = {}; @@ -17280,20 +17868,19 @@ DN_API bool DN_OS_W32DirWIterate(DN_Str16 path, DN_OSW32FolderIteratorW *it) #endif #endif // DN_WITH_OS -#if DN_WITH_NET DN_Str8 DN_NET_Str8FromResponseState(DN_NETResponseState state) { DN_Str8 result = {}; switch (state) { - case DN_NETResponseState_Nil: result = DN_Str8Lit("Nil"); break; - case DN_NETResponseState_Error: result = DN_Str8Lit("Error"); break; - case DN_NETResponseState_HTTP: result = DN_Str8Lit("HTTP"); break; - case DN_NETResponseState_WSOpen: result = DN_Str8Lit("WS Open"); break; - case DN_NETResponseState_WSText: result = DN_Str8Lit("WS Text"); break; - case DN_NETResponseState_WSBinary: result = DN_Str8Lit("WS Binary"); break; - case DN_NETResponseState_WSClose: result = DN_Str8Lit("WS Close"); break; - case DN_NETResponseState_WSPing: result = DN_Str8Lit("WS Ping"); break; - case DN_NETResponseState_WSPong: result = DN_Str8Lit("WS Pong"); break; + case DN_NETResponseState_Nil: result = DN_Str8Lit("Nil"); break; + case DN_NETResponseState_Error: result = DN_Str8Lit("Error"); break; + case DN_NETResponseState_HTTP: result = DN_Str8Lit("HTTP"); break; + case DN_NETResponseState_WSOpen: result = DN_Str8Lit("WS Open"); break; + case DN_NETResponseState_WSText: result = DN_Str8Lit("WS Text"); break; + case DN_NETResponseState_WSBinary: result = DN_Str8Lit("WS Binary"); break; + case DN_NETResponseState_WSClose: result = DN_Str8Lit("WS Close"); break; + case DN_NETResponseState_WSPing: result = DN_Str8Lit("WS Ping"); break; + case DN_NETResponseState_WSPong: result = DN_Str8Lit("WS Pong"); break; } return result; } @@ -17317,6 +17904,12 @@ DN_NETRequestHandle DN_NET_HandleFromRequest(DN_NETRequest *request) return result; } +bool DN_NET_HandleEq(DN_NETRequestHandle lhs, DN_NETRequestHandle rhs) +{ + bool result = lhs.gen == rhs.gen && lhs.handle == rhs.handle; + return result; +} + bool DN_NET_ResponseHasFailed(DN_NETResponse const* resp) { bool result = false; @@ -17361,12 +17954,13 @@ DN_Str8 DN_NET_Str8DiagnosticFromResponse(DN_NETResponse const* resp, DN_Arena * return result; } +#if DN_WITH_NET void DN_NET_BaseInit(DN_NETCore *net, char *base, DN_U64 base_size) { net->base = base; net->base_size = base_size; net->mem = DN_MemListFromBuffer(net->base, net->base_size, DN_MemFlags_Nil); - net->arena = DN_ArenaFromMemList(&net->mem); + net->arena = DN_ArenaFromMemList(net->mem); net->completion_sem = DN_OS_SemaphoreInit(0); } @@ -17375,7 +17969,7 @@ DN_NETRequestHandle DN_NET_SetupRequest(DN_NETRequest *request, DN_Str8 url, DN_ // NOTE: Setup request DN_Assert(request); if (request) { - if (request->mem.curr) + if (request->mem && request->mem->curr) DN_AssertF(request->arena.mem == nullptr, "DN_NET_RequestRecycle should be called on the request before putting it into the " "free-list and reusing it. This is so that we centralise the one place that we " @@ -17383,7 +17977,7 @@ DN_NETRequestHandle DN_NET_SetupRequest(DN_NETRequest *request, DN_Str8 url, DN_ else request->mem = DN_MemListFromHeap(DN_Megabytes(1), DN_Kilobytes(1), DN_MemFlags_Nil, DN_OS_HeapInitVirtual(), "DN NET Request MemList"); - request->arena = DN_ArenaTempBeginFromMemList(&request->mem); + request->arena = DN_ArenaTempBeginFromMemList(request->mem); request->type = type; request->gen = DN_Max(request->gen + 1, 1); request->url = DN_Str8FromStr8Arena(url, &request->arena); @@ -17423,7 +18017,7 @@ void DN_NET_RequestRecycle(DN_NETRequest *request) resetter.start_response_arena = request->start_response_arena; resetter.gen = request->gen + 1; DN_Memcpy(resetter.context, request->context, sizeof(resetter.context)); - *request = resetter; + *request = resetter; // NOTE: Deallocate the memory used in the request. Note we have to end the start response arena // first to satisfy the UAF checker which requires that the temporary memory arenas are ended in @@ -17508,9 +18102,12 @@ static void DN_NET_CurlMarkRequestDone_(DN_NETCore *net, DN_NETRequest *request) DN_DoublyLLAppend(curl->response_list, request); curl->response_count++; + + // NOTE: Signal the global completion semaphore (net->completion_sem) and the per-request + // completion semaphore (request->completion_sem). + DN_OS_SemaphoreIncrement(&net->completion_sem, 1); + DN_OS_SemaphoreIncrement(&request->completion_sem, 1); } - DN_OS_SemaphoreIncrement(&net->completion_sem, 1); - DN_OS_SemaphoreIncrement(&request->completion_sem, 1); } static DN_USize DN_NET_CurlHTTPCallback_(char *payload, DN_USize size, DN_USize count, void *user_data) @@ -17903,11 +18500,11 @@ static DN_NETRequestHandle DN_NET_CurlDoRequest_(DN_NETCore *net, DN_Str8 url, D } if (req) { - DN_AssertF(req->mem.curr->used == DN_ARENA_HEADER_SIZE, + DN_AssertF(req->mem->curr->used == DN_ARENA_HEADER_SIZE, "A reused request from the free-list should have its memory reset essentially to " "zero. If this isn't the case then we're leaking memory and have forgotten to " "reset the arena before putting the request back into the free list. Request has " - "used %s.", DN_Str8x32FromByteCountU64Auto(req->mem.curr->used).data); + "used %s.", DN_Str8x32FromByteCountU64Auto(req->mem->curr->used).data); } else{ // NOTE: None in the free list so allocate one DN_OS_MutexLock(&curl_core->list_mutex); diff --git a/Single-Header/dn_single_header.h b/Single-Header/dn_single_header.h index 8cab5b4..17ce984 100644 --- a/Single-Header/dn_single_header.h +++ b/Single-Header/dn_single_header.h @@ -1,4 +1,4 @@ -// Generated by the DN single header generator 2026-10-03 22:35:58 +// Generated by the DN single header generator 2026-10-19 12:20:47 #if !defined(DN_H) #define DN_H @@ -115,15 +115,6 @@ // translation unit and will automatically disable the in-built replacement header in which case // this does not need to be defined. -// Freestanding -// TODO: This is not really supported or dealt with properly. Re-review it -// The base layer can be used without an OS implementation by defining DN_FREESTANDING like: -// -// #define DN_FREESTANDING -// -// This means functionality that relies on the OS like printing, memory allocation, stack traces -// and so forth are disabled. - // ASAN Arena Poisoning // When compiled with address sanitizer (.e.g -fsanitize=address) you can optionally enable // memory region poisoning on the inbuilt arena's to catch in certain scenarios, use-after-free @@ -302,14 +293,14 @@ #define DN_GCC_WARNING_POP #endif -// NOTE: Host OS identification +// NOTE: Host OS identification (the OS we're running on) #if defined(_WIN32) #define DN_OS_WIN32 #elif defined(__gnu_linux__) || defined(__linux__) #define DN_OS_UNIX #endif -// NOTE: Platform identification +// NOTE: Platform identification (the OS we're targeting) #if !defined(DN_PLATFORM_EMSCRIPTEN) && \ !defined(DN_PLATFORM_POSIX) && \ !defined(DN_PLATFORM_ARM64) && \ @@ -514,7 +505,7 @@ #define DN_AssertAlwaysCallSiteF(expr, call_site, fmt, ...) \ do { \ if (!(expr)) { \ - DN_Str8 trace_ = DN_Str8FromStackTraceNowHeap(128 /*limit*/, 3 /*skip*/); \ + DN_Str8 trace_ = DN_OS_Str8FromStackTraceNowHeap(128 /*limit*/, 3 /*skip*/); \ DN_LogTypeParam log_type_ = DN_LogTypeParamFromType(DN_LogType_Error); \ DN_LogPrintF(log_type_, call_site, DN_LogFlags_Nil, "Assertion triggered [" #expr "]. " fmt "\nTrace:\n%.*s", ## __VA_ARGS__, DN_Str8PrintFmt(trace_)); \ DN_DebugBreak; \ @@ -539,12 +530,15 @@ #define DN_Verify(expr) DN_VerifyF(expr, 0) #define DN_VerifyWarning(expr) DN_VerifyWarningF(expr, 0) +// NOTE: Static checks (validate expressions at compile time using pre-processor tricks) #define DN_StaticAssert(expr) \ DN_GCC_WARNING_PUSH \ DN_GCC_WARNING_DISABLE(-Wunused-local-typedefs) \ typedef char DN_TokenCombine(static_assert_dummy__, __LINE__)[(expr) ? 1 : -1]; \ DN_GCC_WARNING_POP +#define DN_StaticTypeEq(lhs, rhs) (void)(1 ? lhs : rhs) + #if defined(__aarch64__) || defined(_M_X64) || defined(__x86_64__) || defined(__x86_64) #define DN_64_BIT #else @@ -737,7 +731,7 @@ typedef DN_I32 DN_B32; #define DN_CountLeadingZerosU64(value) __lzcnt64(value) #define DN_CountLeadingZerosU32(value) __lzcnt(value) - #define DN_CPUGetTsc() __rdtsc() + #define DN_CpuTscNow() __rdtsc() #define DN_CompilerReadBarrierAndCPUReadFence _ReadBarrier(); _mm_lfence() #define DN_CompilerWriteBarrierAndCPUWriteFence _WriteBarrier(); _mm_sfence() #elif defined(DN_COMPILER_GCC) || defined(DN_COMPILER_CLANG) @@ -762,9 +756,9 @@ typedef DN_I32 DN_B32; #define DN_CountLeadingZerosU32(value) __builtin_clzl(value) #if defined(DN_COMPILER_GCC) - #define DN_CPUGetTsc() __rdtsc() + #define DN_CpuTscNow() __rdtsc() #else - #define DN_CPUGetTsc() __builtin_readcyclecounter() + #define DN_CpuTscNow() __builtin_readcyclecounter() #endif #if defined(DN_PLATFORM_EMSCRIPTEN) @@ -850,8 +844,8 @@ struct DN_Str16Slice DN_USize count; }; -typedef struct DN_CPURegisters DN_CPURegisters; -struct DN_CPURegisters +typedef struct DN_CpuRegisters DN_CpuRegisters; +struct DN_CpuRegisters { int eax; int ebx; @@ -859,98 +853,98 @@ struct DN_CPURegisters int edx; }; -union DN_CPUIDResult +union DN_CpuIDResult { - DN_CPURegisters reg; + DN_CpuRegisters reg; int values[4]; }; -typedef struct DN_CPUIDArgs DN_CPUIDArgs; -struct DN_CPUIDArgs { int eax; int ecx; }; +typedef struct DN_CpuIDArgs DN_CpuIDArgs; +struct DN_CpuIDArgs { int eax; int ecx; }; -#define DN_CPU_FEAT_XMACRO \ - DN_CPU_FEAT_XENTRY(3DNow) \ - DN_CPU_FEAT_XENTRY(3DNowExt) \ - DN_CPU_FEAT_XENTRY(ABM) \ - DN_CPU_FEAT_XENTRY(AES) \ - DN_CPU_FEAT_XENTRY(AVX) \ - DN_CPU_FEAT_XENTRY(AVX2) \ - DN_CPU_FEAT_XENTRY(AVX512F) \ - DN_CPU_FEAT_XENTRY(AVX512DQ) \ - DN_CPU_FEAT_XENTRY(AVX512IFMA) \ - DN_CPU_FEAT_XENTRY(AVX512PF) \ - DN_CPU_FEAT_XENTRY(AVX512ER) \ - DN_CPU_FEAT_XENTRY(AVX512CD) \ - DN_CPU_FEAT_XENTRY(AVX512BW) \ - DN_CPU_FEAT_XENTRY(AVX512VL) \ - DN_CPU_FEAT_XENTRY(AVX512VBMI) \ - DN_CPU_FEAT_XENTRY(AVX512VBMI2) \ - DN_CPU_FEAT_XENTRY(AVX512VNNI) \ - DN_CPU_FEAT_XENTRY(AVX512BITALG) \ - DN_CPU_FEAT_XENTRY(AVX512VPOPCNTDQ) \ - DN_CPU_FEAT_XENTRY(AVX5124VNNIW) \ - DN_CPU_FEAT_XENTRY(AVX5124FMAPS) \ - DN_CPU_FEAT_XENTRY(AVX512VP2INTERSECT) \ - DN_CPU_FEAT_XENTRY(AVX512FP16) \ - DN_CPU_FEAT_XENTRY(CLZERO) \ - DN_CPU_FEAT_XENTRY(CMPXCHG8B) \ - DN_CPU_FEAT_XENTRY(CMPXCHG16B) \ - DN_CPU_FEAT_XENTRY(F16C) \ - DN_CPU_FEAT_XENTRY(FMA) \ - DN_CPU_FEAT_XENTRY(FMA4) \ - DN_CPU_FEAT_XENTRY(FP128) \ - DN_CPU_FEAT_XENTRY(FP256) \ - DN_CPU_FEAT_XENTRY(FPU) \ - DN_CPU_FEAT_XENTRY(MMX) \ - DN_CPU_FEAT_XENTRY(MONITOR) \ - DN_CPU_FEAT_XENTRY(MOVBE) \ - DN_CPU_FEAT_XENTRY(MOVU) \ - DN_CPU_FEAT_XENTRY(MmxExt) \ - DN_CPU_FEAT_XENTRY(PCLMULQDQ) \ - DN_CPU_FEAT_XENTRY(POPCNT) \ - DN_CPU_FEAT_XENTRY(RDRAND) \ - DN_CPU_FEAT_XENTRY(RDSEED) \ - DN_CPU_FEAT_XENTRY(RDTscP) \ - DN_CPU_FEAT_XENTRY(SHA) \ - DN_CPU_FEAT_XENTRY(SSE) \ - DN_CPU_FEAT_XENTRY(SSE2) \ - DN_CPU_FEAT_XENTRY(SSE3) \ - DN_CPU_FEAT_XENTRY(SSE41) \ - DN_CPU_FEAT_XENTRY(SSE42) \ - DN_CPU_FEAT_XENTRY(SSE4A) \ - DN_CPU_FEAT_XENTRY(SSSE3) \ - DN_CPU_FEAT_XENTRY(Tsc) \ - DN_CPU_FEAT_XENTRY(TscInvariant) \ - DN_CPU_FEAT_XENTRY(VAES) \ - DN_CPU_FEAT_XENTRY(VPCMULQDQ) +#define DN_Cpu_FEAT_XMACRO \ + DN_Cpu_FEAT_XENTRY(3DNow) \ + DN_Cpu_FEAT_XENTRY(3DNowExt) \ + DN_Cpu_FEAT_XENTRY(ABM) \ + DN_Cpu_FEAT_XENTRY(AES) \ + DN_Cpu_FEAT_XENTRY(AVX) \ + DN_Cpu_FEAT_XENTRY(AVX2) \ + DN_Cpu_FEAT_XENTRY(AVX512F) \ + DN_Cpu_FEAT_XENTRY(AVX512DQ) \ + DN_Cpu_FEAT_XENTRY(AVX512IFMA) \ + DN_Cpu_FEAT_XENTRY(AVX512PF) \ + DN_Cpu_FEAT_XENTRY(AVX512ER) \ + DN_Cpu_FEAT_XENTRY(AVX512CD) \ + DN_Cpu_FEAT_XENTRY(AVX512BW) \ + DN_Cpu_FEAT_XENTRY(AVX512VL) \ + DN_Cpu_FEAT_XENTRY(AVX512VBMI) \ + DN_Cpu_FEAT_XENTRY(AVX512VBMI2) \ + DN_Cpu_FEAT_XENTRY(AVX512VNNI) \ + DN_Cpu_FEAT_XENTRY(AVX512BITALG) \ + DN_Cpu_FEAT_XENTRY(AVX512VPOPCNTDQ) \ + DN_Cpu_FEAT_XENTRY(AVX5124VNNIW) \ + DN_Cpu_FEAT_XENTRY(AVX5124FMAPS) \ + DN_Cpu_FEAT_XENTRY(AVX512VP2INTERSECT) \ + DN_Cpu_FEAT_XENTRY(AVX512FP16) \ + DN_Cpu_FEAT_XENTRY(CLZERO) \ + DN_Cpu_FEAT_XENTRY(CMPXCHG8B) \ + DN_Cpu_FEAT_XENTRY(CMPXCHG16B) \ + DN_Cpu_FEAT_XENTRY(F16C) \ + DN_Cpu_FEAT_XENTRY(FMA) \ + DN_Cpu_FEAT_XENTRY(FMA4) \ + DN_Cpu_FEAT_XENTRY(FP128) \ + DN_Cpu_FEAT_XENTRY(FP256) \ + DN_Cpu_FEAT_XENTRY(FPU) \ + DN_Cpu_FEAT_XENTRY(MMX) \ + DN_Cpu_FEAT_XENTRY(MONITOR) \ + DN_Cpu_FEAT_XENTRY(MOVBE) \ + DN_Cpu_FEAT_XENTRY(MOVU) \ + DN_Cpu_FEAT_XENTRY(MmxExt) \ + DN_Cpu_FEAT_XENTRY(PCLMULQDQ) \ + DN_Cpu_FEAT_XENTRY(POPCNT) \ + DN_Cpu_FEAT_XENTRY(RDRAND) \ + DN_Cpu_FEAT_XENTRY(RDSEED) \ + DN_Cpu_FEAT_XENTRY(RDTscP) \ + DN_Cpu_FEAT_XENTRY(SHA) \ + DN_Cpu_FEAT_XENTRY(SSE) \ + DN_Cpu_FEAT_XENTRY(SSE2) \ + DN_Cpu_FEAT_XENTRY(SSE3) \ + DN_Cpu_FEAT_XENTRY(SSE41) \ + DN_Cpu_FEAT_XENTRY(SSE42) \ + DN_Cpu_FEAT_XENTRY(SSE4A) \ + DN_Cpu_FEAT_XENTRY(SSSE3) \ + DN_Cpu_FEAT_XENTRY(Tsc) \ + DN_Cpu_FEAT_XENTRY(TscInvariant) \ + DN_Cpu_FEAT_XENTRY(VAES) \ + DN_Cpu_FEAT_XENTRY(VPCMULQDQ) -typedef enum DN_CPUFeature { - #define DN_CPU_FEAT_XENTRY(label) DN_CPUFeature_##label, - DN_CPU_FEAT_XMACRO - #undef DN_CPU_FEAT_XENTRY - DN_CPUFeature_Count, -} DN_CPUFeature; +typedef enum DN_CpuFeature { + #define DN_Cpu_FEAT_XENTRY(label) DN_CpuFeature_##label, + DN_Cpu_FEAT_XMACRO + #undef DN_Cpu_FEAT_XENTRY + DN_CpuFeature_Count, +} DN_CpuFeature; -typedef struct DN_CPUFeatureDecl DN_CPUFeatureDecl; -struct DN_CPUFeatureDecl +typedef struct DN_CpuFeatureDecl DN_CpuFeatureDecl; +struct DN_CpuFeatureDecl { - DN_CPUFeature value; + DN_CpuFeature value; DN_Str8 label; }; -typedef struct DN_CPUFeatureQuery DN_CPUFeatureQuery; -struct DN_CPUFeatureQuery +typedef struct DN_CpuFeatureQuery DN_CpuFeatureQuery; +struct DN_CpuFeatureQuery { - DN_CPUFeature feature; + DN_CpuFeature feature; bool available; }; -typedef struct DN_CPUReport DN_CPUReport; -struct DN_CPUReport +typedef struct DN_CpuReport DN_CpuReport; +struct DN_CpuReport { char vendor[4 /*bytes*/ * 3 /*EDX, ECX, EBX*/ + 1 /*null*/]; char brand[48]; - DN_U64 features[(DN_CPUFeature_Count / (sizeof(DN_U64) * 8)) + 1]; + DN_U64 features[(DN_CpuFeature_Count / (sizeof(DN_U64) * 8)) + 1]; }; typedef struct DN_TicketMutex DN_TicketMutex; @@ -1289,10 +1283,6 @@ struct DN_MemList DN_MemStats stats; DN_Str8 label; - #if DN_MEM_DEBUGGER - DN_USize mem_debugger_id; - #endif - #if DN_ARENA_TEMP_MEM_UAF_GUARD DN_U32 uaf_guard_next_id; DN_U32 uaf_guard_active_id; @@ -1314,6 +1304,7 @@ typedef enum DN_AllocatorType { DN_AllocatorType_MemList, DN_AllocatorType_Arena, DN_AllocatorType_Pool, + DN_AllocatorType_Heap, } DN_AllocatorType; typedef struct DN_Allocator DN_Allocator; @@ -1351,7 +1342,13 @@ struct DN_Arena #endif }; -DN_USize const DN_ARENA_HEADER_SIZE = DN_AlignUpPowerOfTwo(sizeof(DN_Arena), 64); +// NOTE: The memory list is stored inside the block header, immediately after the DN_MemBlock. Keeping +// the DN_MemBlock at the allocation base means freeing the block is trivial (the block pointer is the +// allocation pointer). The header grows to fit the memory list, and the static assert guarantees the +// list sits below the used watermark so resetting the list can never scrub it. +#define DN_MEM_LIST_OFFSET DN_AlignUpPowerOfTwo(sizeof(DN_MemBlock), alignof(DN_MemList)) +DN_USize const DN_ARENA_HEADER_SIZE = DN_AlignUpPowerOfTwo(DN_Max(sizeof(DN_Arena), DN_MEM_LIST_OFFSET + sizeof(DN_MemList)), 64); +DN_StaticAssert(DN_MEM_LIST_OFFSET + sizeof(DN_MemList) <= DN_ARENA_HEADER_SIZE); #if !defined(DN_POOL_DEFAULT_ALIGN) #define DN_POOL_DEFAULT_ALIGN 16 @@ -1464,6 +1461,14 @@ enum DN_Str8IsFlags_ DN_Str8IsFlags_Uppercase = 1 << 3, // String is all uppercase characters (case-ness is only checked for ASCII, non-ASCII is permitted always) }; +struct DN_Str8IsResult +{ + bool success; + // Set if `flags` was set to hex mode and `success` is true. Set to the slice of the input + // `string` without the 0x prefix if it had one. + DN_Str8 hex; +}; + typedef struct DN_Str8BSplitResult DN_Str8BSplitResult; struct DN_Str8BSplitResult { @@ -1551,6 +1556,24 @@ struct DN_Str8Builder DN_USize count; // The number of links in the linked list of strings }; +struct DN_Str8Path +{ + DN_Str8 value; // Full path that was fed into the function producing this struct + DN_Str8 file_name; // Slice into `value` containing the string proceeding the last path-separator (`/` or `\\`) and includes the file extension + DN_Str8 file_name_no_ext; // `file_name` but with `file_ext` truncated from it for convenience + DN_Str8 file_ext; // Slice into `value` containing the string proceeding the last `.` in the string + + // Full directory path, calculated as a slice into `value` containing the string preceeding the + // last path-seperator (`/` or `\\`). If the file portion of the string from this calculation does + // _not_ have a `.` file extension, it assumes the entire path passed in is a directory. This is + // not bullet proof but these APIs producing this struct do not use OS primitives. + // + // So for example if you have a file called "text_file" and you passed in "C:\folder\text_file" as + // the path, `directory` resolves to "C:\folder\text_file" because it can't determine that + // "text_file" is a file without asking the OS. + DN_Str8 directory; +}; + #if !defined(DN_OsPathSeperator) #if defined(DN_PLATFORM_WIN32) #define DN_OsPathSeperator "\\" @@ -2159,18 +2182,18 @@ struct DN_HTable DN_HTableHashFunc* hash_func; DN_HTableKeyEqFunc* key_eq_func; - DN_HTableFlags flags; - DN_Heap heap; - DN_Pool pool; + DN_HTableFlags flags; + DN_Heap* heap; + DN_Pool* pool; // NOTE: Metadata for handling genericism (in C that means type-erasure) - void** kvs; - DN_USize offset_of_hash; - DN_USize size_of_kv; - DN_USize offset_of_key; - DN_USize size_of_key; - DN_USize offset_of_value; - DN_USize size_of_value; + void** kvs; + DN_USize offset_of_hash; + DN_USize size_of_kv; + DN_USize offset_of_key; + DN_USize size_of_key; + DN_USize offset_of_value; + DN_USize size_of_value; }; typedef struct DN_HTableInitArgs DN_HTableInitArgs; @@ -2242,16 +2265,23 @@ enum DN_MemDebuggerPtrFlag DN_MemDebuggerPtrFlag_LeakPermitted = 1 << 1, }; +enum DN_MemDebuggerAllocType +{ + DN_MemDebuggerAllocType_Reserve, + DN_MemDebuggerAllocType_Commit, + DN_MemDebuggerAllocType_Count, +}; + typedef struct DN_MemDebuggerPtrData DN_MemDebuggerPtrData; struct DN_MemDebuggerPtrData { DN_CallSite call_site; - DN_U16 flags; // Bit flags from `DN_MemDebuggerPtrFlag` - void* ptr; // Pointer to the allocation being tracked - DN_USize size; // Size of the allocation - DN_USize freed_size; // Store the size of the allocation when it is freed - DN_Str8 stack_trace; // Stack trace at the point of allocation - DN_Str8 freed_stack_trace; // Stack trace of where the allocation was freed + DN_U16 flags; // Bit flags from `DN_MemDebuggerPtrFlag` + void* ptr; // Pointer to the allocation being tracked + DN_USize bytes[DN_MemDebuggerAllocType_Count]; // Size of the allocation indexed by `DN_MemDebuggerAllocType` + DN_USize freed_bytes[DN_MemDebuggerAllocType_Count]; // Size of the allocation when it was freed, indexed by `DN_MemDebuggerAllocType` + DN_Str8 stack_trace; // Stack trace at the point of allocation + DN_Str8 freed_stack_trace; // Stack trace of where the allocation was freed }; typedef struct DN_MemDebuggerKV DN_MemDebuggerKV; @@ -2262,33 +2292,107 @@ struct DN_MemDebuggerKV DN_MemDebuggerPtrData value; }; +typedef struct DN_MemDebuggerMemListAlloc DN_MemDebuggerMemListAlloc; +struct DN_MemDebuggerMemListAlloc +{ + void* ptr; // Allocation pointer + DN_U64 size; // Requested size + DN_U64 alloc_size; // Bytes consumed in the block (includes alignment padding) + DN_U64 position; // Absolute (0-based) memory list position of the allocation pointer + DN_U8 align; // Requested alignment + DN_CallSite call_site; +}; + +typedef struct DN_MemDebuggerMemList DN_MemDebuggerMemList; +struct DN_MemDebuggerMemList +{ + DN_MemList* mem_list; + DN_MemDebuggerMemListAlloc* allocs; // Append-only, ascending memory list position order + DN_USize allocs_count; + DN_USize allocs_max; + DN_TicketMutex alloc_mutex; +}; + +typedef struct DN_MemDebuggerMemListKV DN_MemDebuggerMemListKV; +struct DN_MemDebuggerMemListKV +{ + DN_HTableHashType hash; + DN_MemList* key; + DN_MemDebuggerMemList value; +}; + typedef struct DN_MemDebuggerSnapshotPtrData DN_MemDebuggerSnapshotPtrData; struct DN_MemDebuggerSnapshotPtrData { void* ptr; - DN_USize size; + DN_USize bytes[DN_MemDebuggerAllocType_Count]; // Size of the allocation indexed by `DN_MemDebuggerAllocType` DN_U16 flags; DN_CallSite call_site; DN_Str8 stack_trace; }; +typedef struct DN_MemDebuggerMemListSnapshot DN_MemDebuggerMemListSnapshot; +struct DN_MemDebuggerMemListSnapshot +{ + DN_MemList mem_list; // Copy of the live memory list + DN_U64 wasted; // Stranded reserved bytes, captured at snapshot time + DN_MemStats* blocks; // Live block stats (chain order: tail -> head) + DN_USize blocks_count; + DN_MemDebuggerMemListAlloc* allocs; // Live allocations, sorted by alloc_size descending + DN_USize allocs_count; +}; + typedef struct DN_MemDebuggerSnapshot DN_MemDebuggerSnapshot; struct DN_MemDebuggerSnapshot { DN_MemDebuggerSnapshotPtrData *data; DN_USize count; - DN_U64 active_bytes; + DN_U64 active_bytes[DN_MemDebuggerAllocType_Count]; DN_U64 freed_count; - DN_U64 freed_bytes; + DN_U64 freed_bytes[DN_MemDebuggerAllocType_Count]; + DN_MemDebuggerMemListSnapshot* mem_lists; // Snapshot copies of the live memory lists + DN_USize mem_lists_count; }; +typedef enum DN_MemDebuggerFlags { + DN_MemDebuggerFlags_Nil = 0, + + // NOTE: When recording an allocation into the debugger we have the choice of either keeping a + // shallow reference to the strings inside the callsite such as `call_site.name` and + // `call_site.function`. For 99% of use-cases this is probably what you want because this avoids a + // heap allocation because typically, the idea behind these strings is that they are specified in + // the .rodata of the binary and hence have program lifetime. + // + // Filenames and functions are derived from the preprocessor macro __FILE_, __FUNC__ as per + // `DN_CallSiteNow`. The callsite name is specified manually by the caller in the + // `DN_CallSiteNowNamed` macro and it's heavily encouraged that these are also constant C-strings + // so that they get placed into the .rodata section of the binary and thus have program lifetime. + // + // If you can't guarantee the lifetime of these strings then you want to set this flag so that + // the mem-debugger ensures that it holds it own copy of the string by heap allocating a copy. + // This incurs a performance penalty ontop of the penalty of having to instrument all the + // allocation calls. + // + // You also definitely want this flag if you dynamically loading and unloading libraries in your + // application. Using these macros in dynamically loaded libraries will give the memory debugger + // pointers from an .rodata that belong to the dynamic library's address space. Once these + // libraries get unloaded then these pointers become garbage memory and point into nothing-ness. + DN_MemDebuggerFlags_HeapAllocCallSiteStrings = 1 << 0, +} DN_MemDebuggerFlags; + typedef struct DN_MemDebugger DN_MemDebugger; struct DN_MemDebugger { - DN_MemDebuggerKV *alloc_table_kvs; - DN_HTable alloc_table; - DN_TicketMutex alloc_table_mutex; - DN_U64 alloc_table_bytes_allocated_for_stack_traces; + DN_U16 flags; + DN_Heap heap; + DN_MemDebuggerKV* alloc_table_kvs; + DN_HTable alloc_table; + DN_TicketMutex alloc_table_mutex; + DN_U64 alloc_table_bytes_allocated_for_stack_traces; + + DN_MemDebuggerMemListKV* mem_list_kvs; + DN_HTable mem_list_table; + DN_TicketMutex mem_list_mutex; }; typedef DN_USize DN_InitFlags; @@ -2298,10 +2402,11 @@ enum DN_InitFlags_ // NOTE: Query the OS for information and enable functionality that requires the OS (like virtual // memory APIs, mutexes, secure RNG) as well as per-thread persistent and scratch allocators. - DN_InitFlags_OS = (1 << 0), - DN_InitFlags_LogLibFeatures = (1 << 2), - DN_InitFlags_LogCPUFeatures = (1 << 3) | DN_InitFlags_OS, - DN_InitFlags_LogAllFeatures = DN_InitFlags_LogLibFeatures | DN_InitFlags_LogCPUFeatures, + DN_InitFlags_OS = (1 << 0), + DN_InitFlags_LogLibFeatures = (1 << 2), + DN_InitFlags_LogCPUFeatures = (1 << 3) | DN_InitFlags_OS, + DN_InitFlags_LogAllFeatures = DN_InitFlags_LogLibFeatures | DN_InitFlags_LogCPUFeatures, + DN_InitFlags_MemDebuggerHeapAllocCallSiteStrings = (1 << 4), }; typedef enum DN_BinPackMode { @@ -4372,8 +4477,13 @@ DN_MSVC_WARNING_POP #include // sendfile #endif #endif +#endif // DN_WITH_OS -extern DN_CPUFeatureDecl g_dn_cpu_feature_decl[DN_CPUFeature_Count]; +// NOTE: DN_OS structures are not compiled out so that any code that might embed these structures +// and are going across API boundaries that don't use the OS primitives can still compile. Our OS +// structures are designed to only use inbuilt integral types and hence avoids relying on any data +// structures from the host OS's includes themselves. +extern DN_CpuFeatureDecl g_dn_cpu_feature_decl[DN_CpuFeature_Count]; typedef struct DN_OSTimer DN_OSTimer; struct DN_OSTimer /// Record time between two time-points using the OS's performance counter. @@ -4411,6 +4521,27 @@ struct DN_OSPathInfo DN_U64 size; }; +typedef struct DN_OSPathResult DN_OSPathResult; +struct DN_OSPathResult +{ + bool success; + DN_Str8 path; +}; + +enum DN_OSPathWatchFileAcceptChange +{ + DN_OSPathWatchFileAcceptChange_No, + DN_OSPathWatchFileAcceptChange_Yes, +}; + +typedef struct DN_OSPathWatchFile DN_OSPathWatchFile; +struct DN_OSPathWatchFile +{ + bool change_accepted; + DN_OSPathInfo candidate; + DN_OSPathInfo prev; +}; + typedef struct DN_OSDirIterator DN_OSDirIterator; struct DN_OSDirIterator { @@ -4419,7 +4550,6 @@ struct DN_OSDirIterator char buffer[512]; }; -// NOTE: R/W Stream API typedef struct DN_OSFileRead DN_OSFileRead; struct DN_OSFileRead { @@ -4525,18 +4655,19 @@ struct DN_OSConditionVariable DN_U64 handle; }; +typedef struct DN_OSWindow DN_OSWindow; struct DN_OSWindow { DN_UPtr handle; }; -enum DN_OSWindowShow +typedef enum DN_OSWindowShow { DN_OSWindowShow_Nil, DN_OSWindowShow_Restore, DN_OSWindowShow_Minimise, DN_OSWindowShow_Maximise, -}; +} DN_OSWindowShow; enum DN_OSWindowMaximise { @@ -4642,7 +4773,7 @@ struct DN_OSLogger typedef struct DN_OSCore DN_OSCore; struct DN_OSCore { - DN_CPUReport cpu_report; + DN_CpuReport cpu_report; DN_OSLogger logger; // NOTE: OS @@ -4659,7 +4790,7 @@ struct DN_OSCore DN_U64 mem_allocs_total; DN_U64 mem_allocs_frame; // Total OS heap allocs since the last 'DN_Core_FrameBegin' was invoked - DN_MemList mem; + DN_MemList* mem; DN_Arena arena; void* platform_context; }; @@ -4672,6 +4803,16 @@ struct DN_OSDiskSpace DN_U64 size; }; +typedef struct DN_OSMemoryInfo DN_OSMemoryInfo; +struct DN_OSMemoryInfo +{ + bool success; + DN_U64 total_phys; // Total usable physical memory (RAM) in bytes + DN_U64 avail_phys; // Physical memory currently available in bytes + DN_U64 total_virtual; // Total virtual memory in bytes + DN_U64 avail_virtual; // Virtual memory currently available in bytes +}; + typedef enum DN_OSAsyncPriority { DN_OSAsyncPriority_Low, DN_OSAsyncPriority_High, @@ -4715,7 +4856,6 @@ struct DN_OSAsyncTask DN_OSAsyncWork work; DN_OSSemaphore completion_sem; }; -#endif // #if DN_WITH_OS typedef struct DN_Core DN_Core; struct DN_Core @@ -4731,9 +4871,7 @@ struct DN_Core void* print_func_context; bool os_init; - #if DN_WITH_OS DN_OSCore os; - #endif }; // NOTE: Library initialisation @@ -4756,155 +4894,150 @@ struct DN_Core // For convenience you can opt into some sane defaults for the `DN_TcInitArgs` which customises // how thread-local storage is setup with `DN_TcInitArgsDefault()` which produces a // `DN_TcInitArgs` object you can pass in by value. -DN_API void DN_Init (DN_Core *dn, DN_InitFlags flags, DN_TcInitArgs args); -DN_API void DN_Set (DN_Core *dn); -DN_API DN_Core* DN_Get (); -DN_API void DN_BeginFrame (); +DN_API void DN_Init (DN_Core *dn, DN_InitFlags flags, DN_TcInitArgs args); +DN_API void DN_Set (DN_Core *dn); +DN_API DN_Core* DN_Get (); +DN_API void DN_BeginFrame (); -DN_API bool DN_VerifyArgsF (DN_VerifyType type, bool expr, DN_CallSite call_site, DN_Str8 expr_str8, char const *fmt, ...); -DN_API bool DN_VerifyArgs (DN_VerifyType type, bool expr, DN_CallSite call_site, DN_Str8 expr_str8); +DN_API bool DN_VerifyArgsF (DN_VerifyType type, bool expr, DN_CallSite call_site, DN_Str8 expr_str8, char const *fmt, ...); +DN_API bool DN_VerifyArgs (DN_VerifyType type, bool expr, DN_CallSite call_site, DN_Str8 expr_str8); -#define DN_Sprintf(...) STB_SPRINTF_DECORATE(sprintf)(__VA_ARGS__) -#define DN_Snprintf(...) STB_SPRINTF_DECORATE(snprintf)(__VA_ARGS__) -#define DN_Vsprintf(...) STB_SPRINTF_DECORATE(vsprintf)(__VA_ARGS__) -#define DN_Vsnprintf(...) STB_SPRINTF_DECORATE(vsnprintf)(__VA_ARGS__) +#define DN_Sprintf(...) STB_SPRINTF_DECORATE(sprintf)(__VA_ARGS__) +#define DN_Snprintf(...) STB_SPRINTF_DECORATE(snprintf)(__VA_ARGS__) +#define DN_Vsprintf(...) STB_SPRINTF_DECORATE(vsprintf)(__VA_ARGS__) +#define DN_Vsnprintf(...) STB_SPRINTF_DECORATE(vsnprintf)(__VA_ARGS__) -DN_API bool DN_MemStartsWith (void const *lhs, DN_USize lhs_count, void const *rhs, DN_USize rhs_count); -DN_API bool DN_MemEq (void const *lhs, DN_USize lhs_count, void const *rhs, DN_USize rhs_count); -DN_API bool DN_MemEqUnsafe (void const *lhs, void const *rhs, DN_USize count); -#if defined(__cplusplus) -template T* DN_MemCopyObjT (T *dest, T const *src, DN_USize count); -#define DN_MemCopyObj(dest, src, count) DN_MemCopyObjT(dest, src, count) -#else -#define DN_MemCopyObj(dest, src, count) DN_Memcpy(dest, src, sizeof(*src) * count) -#endif +DN_API bool DN_MemStartsWith (void const *lhs, DN_USize lhs_count, void const *rhs, DN_USize rhs_count); +DN_API bool DN_MemEq (void const *lhs, DN_USize lhs_count, void const *rhs, DN_USize rhs_count); +DN_API bool DN_MemEqUnsafe (void const *lhs, void const *rhs, DN_USize count); -DN_API DN_U64 DN_AtomicSetValue64 (DN_U64 volatile *target, DN_U64 value); -DN_API DN_U32 DN_AtomicSetValue32 (DN_U32 volatile *target, DN_U32 value); -DN_API DN_USize DN_AlignUpPowerOfTwoUSize (DN_USize val); -DN_API DN_U64 DN_AlignUpPowerOfTwoU64 (DN_U64 val); -DN_API DN_U32 DN_AlignUpPowerOfTwoU32 (DN_U32 val); +DN_API DN_U64 DN_AtomicSetValue64 (DN_U64 volatile *target, DN_U64 value); +DN_API DN_U32 DN_AtomicSetValue32 (DN_U32 volatile *target, DN_U32 value); +DN_API DN_USize DN_AlignUpPowerOfTwoUSize (DN_USize val); +DN_API DN_U64 DN_AlignUpPowerOfTwoU64 (DN_U64 val); +DN_API DN_U32 DN_AlignUpPowerOfTwoU32 (DN_U32 val); -DN_API void DN_ByteSwapU64Ptr (DN_U8* dest, DN_U64 src); -#define DN_ByteSwap64(val) ( \ - ((((DN_U64)(val) >> 56) & 0xFF) << 0) | \ - ((((DN_U64)(val) >> 48) & 0xFF) << 8) | \ - ((((DN_U64)(val) >> 40) & 0xFF) << 16) | \ - ((((DN_U64)(val) >> 32) & 0xFF) << 24) | \ - ((((DN_U64)(val) >> 24) & 0xFF) << 32) | \ - ((((DN_U64)(val) >> 16) & 0xFF) << 40) | \ - ((((DN_U64)(val) >> 8) & 0xFF) << 48) | \ - ((((DN_U64)(val) >> 0) & 0xFF) << 56) \ - ) -#define DN_ByteSwap32(val) ( \ - ((((DN_U32)(val) >> 24) & 0xFF) << 0) | \ - ((((DN_U32)(val) >> 16) & 0xFF) << 8) | \ - ((((DN_U32)(val) >> 8) & 0xFF) << 16) | \ - ((((DN_U32)(val) >> 0) & 0xFF) << 24) \ - ) -#define DN_ByteSwap24(val) ( \ - ((((DN_U32)(val) >> 16) & 0xFF) << 0) | \ - ((((DN_U32)(val) >> 8) & 0xFF) << 8) | \ - ((((DN_U32)(val) >> 0) & 0xFF) << 16) \ - ) -#define DN_ByteSwap16(val) ( \ - ((((DN_U16)(val) >> 8) & 0xFF) << 0) | \ - ((((DN_U16)(val) >> 0) & 0xFF) << 8) \ - ) +DN_API void DN_ByteSwapU64Ptr (DN_U8* dest, DN_U64 src); +#define DN_ByteSwap64(val) ( \ + ((((DN_U64)(val) >> 56) & 0xFF) << 0) | \ + ((((DN_U64)(val) >> 48) & 0xFF) << 8) | \ + ((((DN_U64)(val) >> 40) & 0xFF) << 16) | \ + ((((DN_U64)(val) >> 32) & 0xFF) << 24) | \ + ((((DN_U64)(val) >> 24) & 0xFF) << 32) | \ + ((((DN_U64)(val) >> 16) & 0xFF) << 40) | \ + ((((DN_U64)(val) >> 8) & 0xFF) << 48) | \ + ((((DN_U64)(val) >> 0) & 0xFF) << 56) \ + ) +#define DN_ByteSwap32(val) ( \ + ((((DN_U32)(val) >> 24) & 0xFF) << 0) | \ + ((((DN_U32)(val) >> 16) & 0xFF) << 8) | \ + ((((DN_U32)(val) >> 8) & 0xFF) << 16) | \ + ((((DN_U32)(val) >> 0) & 0xFF) << 24) \ + ) +#define DN_ByteSwap24(val) ( \ + ((((DN_U32)(val) >> 16) & 0xFF) << 0) | \ + ((((DN_U32)(val) >> 8) & 0xFF) << 8) | \ + ((((DN_U32)(val) >> 0) & 0xFF) << 16) \ + ) +#define DN_ByteSwap16(val) ( \ + ((((DN_U16)(val) >> 8) & 0xFF) << 0) | \ + ((((DN_U16)(val) >> 0) & 0xFF) << 8) \ + ) #if defined(DN_64_BIT) - #define DN_ByteSwapUSize(val) DN_ByteSwap64(val) + #define DN_ByteSwapUSize(val) DN_ByteSwap64(val) #else - #define DN_ByteSwapUSize(val) DN_ByteSwap32(val) + #define DN_ByteSwapUSize(val) DN_ByteSwap32(val) #endif -DN_API DN_CPUIDResult DN_CPUID (DN_CPUIDArgs args); -DN_API DN_USize DN_CPUHasFeatureArray (DN_CPUReport const *report, DN_CPUFeatureQuery *features, DN_USize features_size); -DN_API bool DN_CPUHasFeature (DN_CPUReport const *report, DN_CPUFeature feature); -DN_API bool DN_CPUHasAllFeatures (DN_CPUReport const *report, DN_CPUFeature const *features, DN_USize features_size); -DN_API void DN_CPUSetFeature (DN_CPUReport *report, DN_CPUFeature feature); -DN_API DN_CPUReport DN_CPUGetReport (); +DN_API DN_CpuIDResult DN_CpuID (DN_CpuIDArgs args); +DN_API DN_USize DN_CpuHasFeatureArray (DN_CpuReport const *report, DN_CpuFeatureQuery *features, DN_USize features_size); +DN_API bool DN_CpuHasFeature (DN_CpuReport const *report, DN_CpuFeature feature); +DN_API bool DN_CpuHasAllFeatures (DN_CpuReport const *report, DN_CpuFeature const *features, DN_USize features_size); +DN_API void DN_CpuSetFeature (DN_CpuReport *report, DN_CpuFeature feature); +DN_API DN_CpuReport DN_CpuGetReport (); +DN_API DN_U64 DN_CpuTscNowFunctionWrapper (); -DN_API void DN_TicketMutexBegin (DN_TicketMutex *mutex); -DN_API void DN_TicketMutexEnd (DN_TicketMutex *mutex); -DN_API DN_UInt DN_TicketMutexMakeTicket (DN_TicketMutex *mutex); -DN_API void DN_TicketMutexBeginTicket (DN_TicketMutex const *mutex, DN_UInt ticket); -DN_API bool DN_TicketMutexCanLock (DN_TicketMutex const *mutex, DN_UInt ticket); +DN_API void DN_TicketMutexBegin (DN_TicketMutex *mutex); +DN_API void DN_TicketMutexEnd (DN_TicketMutex *mutex); +DN_API DN_UInt DN_TicketMutexMakeTicket (DN_TicketMutex *mutex); +DN_API void DN_TicketMutexBeginTicket (DN_TicketMutex const *mutex, DN_UInt ticket); +DN_API bool DN_TicketMutexCanLock (DN_TicketMutex const *mutex, DN_UInt ticket); -DN_API void DN_BitUnsetInplace (DN_USize *flags, DN_USize bitfield); -DN_API void DN_BitSetInplace (DN_USize *flags, DN_USize bitfield); -DN_API bool DN_BitIsSet (DN_USize bits, DN_USize bits_to_set); -DN_API bool DN_BitIsNotSet (DN_USize bits, DN_USize bits_to_check); -DN_API bool DN_BitIsAny (DN_USize bits, DN_USize bits_to_check); -#define DN_BitClearNextLsb(value) (value) & ((value) - 1) +DN_API void DN_BitUnsetInplace (DN_USize *flags, DN_USize bitfield); +DN_API void DN_BitSetInplace (DN_USize *flags, DN_USize bitfield); +DN_API bool DN_BitIsSet (DN_USize bits, DN_USize bits_to_set); +DN_API bool DN_BitIsNotSet (DN_USize bits, DN_USize bits_to_check); +DN_API bool DN_BitIsAny (DN_USize bits, DN_USize bits_to_check); +#define DN_BitClearNextLsb(value) (value) & ((value) - 1) -DN_API DN_I64 DN_SafeAddI64 (DN_I64 a, DN_I64 b); -DN_API DN_I64 DN_SafeMulI64 (DN_I64 a, DN_I64 b); +DN_API DN_I64 DN_SafeAddI64 (DN_I64 a, DN_I64 b); +DN_API DN_I64 DN_SafeMulI64 (DN_I64 a, DN_I64 b); -DN_API DN_U64 DN_SafeAddU64 (DN_U64 a, DN_U64 b); -DN_API DN_U64 DN_SafeMulU64 (DN_U64 a, DN_U64 b); +DN_API DN_U64 DN_SafeAddU64 (DN_U64 a, DN_U64 b); +DN_API DN_U64 DN_SafeMulU64 (DN_U64 a, DN_U64 b); -DN_API DN_U64 DN_SafeSubU64 (DN_U64 a, DN_U64 b); -DN_API DN_U32 DN_SafeSubU32 (DN_U32 a, DN_U32 b); +DN_API DN_U64 DN_SafeSubU64 (DN_U64 a, DN_U64 b); +DN_API DN_U32 DN_SafeSubU32 (DN_U32 a, DN_U32 b); -DN_API int DN_SaturateCastUSizeToInt (DN_USize val); -DN_API DN_I8 DN_SaturateCastUSizeToI8 (DN_USize val); -DN_API DN_I16 DN_SaturateCastUSizeToI16 (DN_USize val); -DN_API DN_I32 DN_SaturateCastUSizeToI32 (DN_USize val); -DN_API DN_I64 DN_SaturateCastUSizeToI64 (DN_USize val); +DN_API int DN_SaturateCastUSizeToInt (DN_USize val); +DN_API DN_I8 DN_SaturateCastUSizeToI8 (DN_USize val); +DN_API DN_I16 DN_SaturateCastUSizeToI16 (DN_USize val); +DN_API DN_I32 DN_SaturateCastUSizeToI32 (DN_USize val); +DN_API DN_I64 DN_SaturateCastUSizeToI64 (DN_USize val); -DN_API int DN_SaturateCastU64ToInt (DN_U64 val); -DN_API DN_I8 DN_SaturateCastU8ToI8 (DN_U64 val); -DN_API DN_I16 DN_SaturateCastU16ToI16 (DN_U64 val); -DN_API DN_I32 DN_SaturateCastU32ToI32 (DN_U64 val); -DN_API DN_I64 DN_SaturateCastU64ToI64 (DN_U64 val); -DN_API DN_UInt DN_SaturateCastU64ToUInt (DN_U64 val); -DN_API DN_U8 DN_SaturateCastU64ToU8 (DN_U64 val); -DN_API DN_U16 DN_SaturateCastU64ToU16 (DN_U64 val); -DN_API DN_U32 DN_SaturateCastU64ToU32 (DN_U64 val); +DN_API int DN_SaturateCastU64ToInt (DN_U64 val); +DN_API DN_I8 DN_SaturateCastU8ToI8 (DN_U64 val); +DN_API DN_I16 DN_SaturateCastU16ToI16 (DN_U64 val); +DN_API DN_I32 DN_SaturateCastU32ToI32 (DN_U64 val); +DN_API DN_I64 DN_SaturateCastU64ToI64 (DN_U64 val); +DN_API DN_UInt DN_SaturateCastU64ToUInt (DN_U64 val); +DN_API DN_U8 DN_SaturateCastU64ToU8 (DN_U64 val); +DN_API DN_U16 DN_SaturateCastU64ToU16 (DN_U64 val); +DN_API DN_U32 DN_SaturateCastU64ToU32 (DN_U64 val); -DN_API DN_U8 DN_SaturateCastUSizeToU8 (DN_USize val); -DN_API DN_U16 DN_SaturateCastUSizeToU16 (DN_USize val); -DN_API DN_U32 DN_SaturateCastUSizeToU32 (DN_USize val); -DN_API DN_U64 DN_SaturateCastUSizeToU64 (DN_USize val); +DN_API DN_U8 DN_SaturateCastUSizeToU8 (DN_USize val); +DN_API DN_U16 DN_SaturateCastUSizeToU16 (DN_USize val); +DN_API DN_U32 DN_SaturateCastUSizeToU32 (DN_USize val); +DN_API DN_U64 DN_SaturateCastUSizeToU64 (DN_USize val); -DN_API int DN_SaturateCastISizeToInt (DN_ISize val); -DN_API DN_I8 DN_SaturateCastISizeToI8 (DN_ISize val); -DN_API DN_I16 DN_SaturateCastISizeToI16 (DN_ISize val); -DN_API DN_I32 DN_SaturateCastISizeToI32 (DN_ISize val); -DN_API DN_I64 DN_SaturateCastISizeToI64 (DN_ISize val); +DN_API int DN_SaturateCastISizeToInt (DN_ISize val); +DN_API DN_I8 DN_SaturateCastISizeToI8 (DN_ISize val); +DN_API DN_I16 DN_SaturateCastISizeToI16 (DN_ISize val); +DN_API DN_I32 DN_SaturateCastISizeToI32 (DN_ISize val); +DN_API DN_I64 DN_SaturateCastISizeToI64 (DN_ISize val); -DN_API DN_UInt DN_SaturateCastISizeToUInt (DN_ISize val); -DN_API DN_U8 DN_SaturateCastISizeToU8 (DN_ISize val); -DN_API DN_U16 DN_SaturateCastISizeToU16 (DN_ISize val); -DN_API DN_U32 DN_SaturateCastISizeToU32 (DN_ISize val); -DN_API DN_U64 DN_SaturateCastISizeToU64 (DN_ISize val); +DN_API DN_UInt DN_SaturateCastISizeToUInt (DN_ISize val); +DN_API DN_U8 DN_SaturateCastISizeToU8 (DN_ISize val); +DN_API DN_U16 DN_SaturateCastISizeToU16 (DN_ISize val); +DN_API DN_U32 DN_SaturateCastISizeToU32 (DN_ISize val); +DN_API DN_U64 DN_SaturateCastISizeToU64 (DN_ISize val); -DN_API DN_ISize DN_SaturateCastI64ToISize (DN_I64 val); -DN_API DN_I8 DN_SaturateCastI64ToI8 (DN_I64 val); -DN_API DN_I16 DN_SaturateCastI64ToI16 (DN_I64 val); -DN_API DN_I32 DN_SaturateCastI64ToI32 (DN_I64 val); +DN_API DN_ISize DN_SaturateCastI64ToISize (DN_I64 val); +DN_API DN_I8 DN_SaturateCastI64ToI8 (DN_I64 val); +DN_API DN_I16 DN_SaturateCastI64ToI16 (DN_I64 val); +DN_API DN_I32 DN_SaturateCastI64ToI32 (DN_I64 val); -DN_API DN_UInt DN_SaturateCastI64ToUInt (DN_I64 val); -DN_API DN_USize DN_SaturateCastI64ToUSize (DN_I64 val); -DN_API DN_U8 DN_SaturateCastI64ToU8 (DN_I64 val); -DN_API DN_U16 DN_SaturateCastI64ToU16 (DN_I64 val); -DN_API DN_U32 DN_SaturateCastI64ToU32 (DN_I64 val); -DN_API DN_U64 DN_SaturateCastI64ToU64 (DN_I64 val); +DN_API DN_UInt DN_SaturateCastI64ToUInt (DN_I64 val); +DN_API DN_USize DN_SaturateCastI64ToUSize (DN_I64 val); +DN_API DN_U8 DN_SaturateCastI64ToU8 (DN_I64 val); +DN_API DN_U16 DN_SaturateCastI64ToU16 (DN_I64 val); +DN_API DN_U32 DN_SaturateCastI64ToU32 (DN_I64 val); +DN_API DN_U64 DN_SaturateCastI64ToU64 (DN_I64 val); -DN_API DN_I8 DN_SaturateCastIntToI8 (int val); -DN_API DN_I16 DN_SaturateCastIntToI16 (int val); -DN_API DN_U8 DN_SaturateCastIntToU8 (int val); -DN_API DN_U16 DN_SaturateCastIntToU16 (int val); -DN_API DN_U32 DN_SaturateCastIntToU32 (int val); -DN_API DN_U64 DN_SaturateCastIntToU64 (int val); +DN_API DN_I8 DN_SaturateCastIntToI8 (int val); +DN_API DN_I16 DN_SaturateCastIntToI16 (int val); +DN_API DN_U8 DN_SaturateCastIntToU8 (int val); +DN_API DN_U16 DN_SaturateCastIntToU16 (int val); +DN_API DN_U32 DN_SaturateCastIntToU32 (int val); +DN_API DN_U64 DN_SaturateCastIntToU64 (int val); -DN_API void DN_ASanPoisonMemoryRegion (void const volatile *ptr, DN_USize size); -DN_API void DN_ASanUnpoisonMemoryRegion (void const volatile *ptr, DN_USize size); +DN_API void DN_ASanPoisonMemoryRegion (void const volatile *ptr, DN_USize size); +DN_API void DN_ASanUnpoisonMemoryRegion (void const volatile *ptr, DN_USize size); -DN_API DN_F32 DN_EpsilonClampF32 (DN_F32 value, DN_F32 target, DN_F32 epsilon); +DN_API DN_F32 DN_EpsilonClampF32 (DN_F32 value, DN_F32 target, DN_F32 epsilon); -DN_API DN_MemStats DN_MemStatsSum (DN_MemStats lhs, DN_MemStats rhs); -DN_API DN_MemStats DN_MemStatsSumArray (DN_MemStats const *array, DN_USize count); +DN_API DN_MemStats DN_MemStatsSum (DN_MemStats lhs, DN_MemStats rhs); +DN_API DN_MemStats DN_MemStatsSumArray (DN_MemStats const *array, DN_USize count); // NOTE: Heap // Overview @@ -4927,12 +5060,11 @@ DN_API DN_MemStats DN_MemStatsSumArray // address space to reserve for the application from the OS. `commit` is the amount of memory in // pages that the OS will give your application. -#define DN_MemMetadataInit(name_cstr) DN_Literal(DN_MemMetadata){DN_CallSiteNow, DN_Str8Lit(name_cstr)} -DN_API DN_Heap DN_HeapInitBasic (DN_HeapBasicAllocFunc *basic_alloc, DN_HeapBasicDeallocFunc *basic_dealloc); -DN_API DN_Heap DN_HeapInitVirtual (DN_U32 page_size, DN_HeapVirtualReserveFunc *virtual_reserve, DN_HeapVirtualCommitFunc *virtual_commit, DN_HeapVirtualReleaseFunc *virtual_release); -DN_API void* DN_HeapAllocCallSite (DN_Heap *heap, DN_USize reserve, DN_USize commit, DN_HeapAllocFlag flags, DN_CallSite call_site); -#define DN_HeapAlloc(heap, reserve, commit, flags, name_cstr) DN_HeapAllocMetadata(heap, reserve, commit, flags, DN_MemMetadataInit(name_cstr)); -DN_API void DN_HeapDealloc (DN_Heap *heap, void *ptr, DN_USize size); +DN_API DN_Heap DN_HeapInitBasic (DN_HeapBasicAllocFunc *basic_alloc, DN_HeapBasicDeallocFunc *basic_dealloc); +DN_API DN_Heap DN_HeapInitVirtual (DN_U32 page_size, DN_HeapVirtualReserveFunc *virtual_reserve, DN_HeapVirtualCommitFunc *virtual_commit, DN_HeapVirtualReleaseFunc *virtual_release); +DN_API void* DN_HeapAllocCallSite (DN_Heap *heap, DN_USize reserve, DN_USize commit, DN_HeapAllocFlag flags, DN_CallSite call_site); +#define DN_HeapAlloc(heap, reserve, commit, flags, name_cstr) DN_HeapAllocCallSite(heap, reserve, commit, flags, DN_CallSiteNowNamed(name_cstr)); +DN_API void DN_HeapDealloc (DN_Heap *heap, void *ptr, DN_USize size); // NOTE: MemList // Overview @@ -4943,34 +5075,50 @@ DN_API void DN_HeapDealloc // // In general for 99% of use-cases you want an `Arena` and if some API is not exposed on the // `Arena` to then use the `MemList` API on the embedded `mem_list` backing the Arena. -DN_API DN_MemList DN_MemListFromBuffer (void *buffer, DN_USize size, DN_MemFlags flags); -DN_API DN_MemList DN_MemListFromHeapCallSite (DN_U64 reserve, DN_U64 commit, DN_MemFlags flags, DN_Heap heap, DN_CallSite call_site); -#define DN_MemListFromHeap(reserve, commit, flags, heap, name_cstr) DN_MemListFromHeapCallSite(reserve, commit, flags, heap, DN_CallSiteNowNamed(name_cstr)) -DN_API void DN_MemListDeinit (DN_MemList *mem); -DN_API bool DN_MemListCommit (DN_MemList *mem, DN_U64 size); -DN_API bool DN_MemListCommitTo (DN_MemList *mem, DN_U64 pos); -DN_API bool DN_MemListGrow (DN_MemList *mem, DN_U64 reserve, DN_U64 commit); -DN_API void * DN_MemListAlloc (DN_MemList *mem, DN_U64 size, DN_U8 align, DN_ZMem zmem); -DN_API void * DN_MemListAllocContiguous (DN_MemList *mem, DN_U64 size, DN_U8 align, DN_ZMem zmem); -DN_API void * DN_MemListCopy (DN_MemList *mem, void const *data, DN_U64 size, uint8_t align); -DN_API void DN_MemListPopTo (DN_MemList *mem, DN_U64 init_used); -DN_API void DN_MemListPop (DN_MemList *mem, DN_U64 amount); -DN_API DN_U64 DN_MemListPos (DN_MemList const *mem); -DN_API void DN_MemListClear (DN_MemList *mem); -DN_API bool DN_MemListOwnsPtr (DN_MemList const *mem, void const *ptr); -DN_API DN_Str8x64 DN_MemListInfoStr8x64 (DN_MemListInfo info); -DN_API DN_MemListTemp DN_MemListTempBegin (DN_MemList *mem); -DN_API void DN_MemListTempEnd (DN_MemListTemp mem); -#define DN_MemListNew(arena, T, zmem) (T *)DN_MemListAlloc(arena, sizeof(T), alignof(T), zmem) -#define DN_MemListNewZ(arena, T) (T *)DN_MemListAlloc(arena, sizeof(T), alignof(T), DN_ZMem_Yes) -#define DN_MemListNewContiguous(arena, T, zmem) (T *)DN_MemListAllocContiguous(arena, sizeof(T), alignof(T), zmem) -#define DN_MemListNewContiguousZ(arena, T) (T *)DN_MemListAllocContiguous(arena, sizeof(T), alignof(T), DN_ZMem_Yes) -#define DN_MemListNewArray(arena, T, count, zmem) (T *)DN_MemListAlloc(arena, sizeof(T) * (count), alignof(T), zmem) -#define DN_MemListNewArrayZ(arena, T, count) (T *)DN_MemListAlloc(arena, sizeof(T) * (count), alignof(T), DN_ZMem_Yes) -#define DN_MemListNewArrayNoZ(arena, T, count) (T *)DN_MemListAlloc(arena, sizeof(T) * (count), alignof(T), DN_ZMem_No) -#define DN_MemListNewCopy(arena, T, src) (T *)DN_MemListCopy(arena, (src), sizeof(T), alignof(T)) -#define DN_MemListNewArrayCopy(arena, T, src, count) (T *)DN_MemListCopy(arena, (src), sizeof(T) * (count), alignof(T)) - +DN_API DN_MemList* DN_MemListFromBufferCallSite (void *buffer, DN_USize size, DN_MemFlags flags, DN_CallSite call_site); +#define DN_MemListFromBuffer(buffer, size, flags) DN_MemListFromBufferCallSite(buffer, size, flags, DN_CallSiteNow) +#define DN_MemListFromBufferNamed(buffer, size, flags, name_cstr) DN_MemListFromBufferCallSite(buffer, size, flags, DN_CallSiteNowNamed(name_cstr)) +DN_API DN_MemList* DN_MemListFromHeapCallSite (DN_U64 reserve, DN_U64 commit, DN_MemFlags flags, DN_Heap heap, DN_CallSite call_site); +#define DN_MemListFromHeap(reserve, commit, flags, heap, name_cstr) DN_MemListFromHeapCallSite(reserve, commit, flags, heap, DN_CallSiteNowNamed(name_cstr)) +DN_API void DN_MemListDeinit (DN_MemList *mem); +DN_API bool DN_MemListCommit (DN_MemList *mem, DN_U64 size); +DN_API bool DN_MemListCommitTo (DN_MemList *mem, DN_U64 pos); +#define DN_MemListGrow(mem, reserve, commit) DN_MemListGrowCallSite(mem, reserve, commit, DN_CallSiteNow) +DN_API bool DN_MemListGrowCallSite (DN_MemList *mem, DN_U64 reserve, DN_U64 commit, DN_CallSite call_site); +#define DN_MemListAlloc(mem, size, align, zmem) DN_MemListAllocCallSite(mem, size, align, zmem, DN_CallSiteNow) +DN_API void * DN_MemListAllocCallSite (DN_MemList *mem, DN_U64 size, DN_U8 align, DN_ZMem zmem, DN_CallSite call_site); +#define DN_MemListAllocContiguous(mem, size, align, zmem) DN_MemListAllocContiguousCallSite(mem, size, align, zmem, DN_CallSiteNow) +#define DN_MemListAllocContiguousNamed(mem, size, align, zmem, name_cstr) DN_MemListAllocContiguousCallSite(mem, size, align, zmem, DN_CallSiteNowNamed(name_cstr)) +DN_API void * DN_MemListAllocContiguousCallSite (DN_MemList *mem, DN_U64 size, DN_U8 align, DN_ZMem zmem, DN_CallSite call_site); +#define DN_MemListCopy(mem, data, size, align) DN_MemListCopyCallSite(mem, data, size, align, DN_CallSiteNow) +#define DN_MemListCopyNamed(mem, data, size, align, name_cstr) DN_MemListCopyCallSite(mem, data, size, align, DN_CallSiteNowNamed(name_cstr)) +DN_API void * DN_MemListCopyCallSite (DN_MemList *mem, void const *data, DN_U64 size, uint8_t align, DN_CallSite call_site); +DN_API void DN_MemListPopTo (DN_MemList *mem, DN_U64 init_used); +DN_API void DN_MemListPop (DN_MemList *mem, DN_U64 amount); +DN_API DN_U64 DN_MemListPos (DN_MemList const *mem); +DN_API void DN_MemListClear (DN_MemList *mem); +DN_API bool DN_MemListOwnsPtr (DN_MemList const *mem, void const *ptr); +DN_API DN_Str8x64 DN_MemListInfoStr8x64 (DN_MemListInfo info); +DN_API DN_MemListTemp DN_MemListTempBegin (DN_MemList *mem); +DN_API void DN_MemListTempEnd (DN_MemListTemp mem); +#define DN_MemListNew(arena, T, zmem) (T *)DN_MemListAlloc(arena, sizeof(T), alignof(T), zmem) +#define DN_MemListNewArray(arena, T, count, zmem) (T *)DN_MemListAlloc(arena, sizeof(T) * (count), alignof(T), zmem) +#define DN_MemListNewArrayCopy(arena, T, src, count) (T *)DN_MemListCopy(arena, (src), sizeof(T) * (count), alignof(T)) +#define DN_MemListNewArrayCopyNamed(arena, T, src, count, name_cstr) (T *)DN_MemListCopyCallSite(arena, (src), sizeof(T) * (count), alignof(T), DN_CallSiteNowNamed(name_cstr)) +#define DN_MemListNewArrayNamed(arena, T, count, zmem, name_cstr) (T *)DN_MemListAllocCallSite(arena, sizeof(T) * (count), alignof(T), zmem, DN_CallSiteNowNamed(name_cstr)) +#define DN_MemListNewArrayNoZ(arena, T, count) (T *)DN_MemListAlloc(arena, sizeof(T) * (count), alignof(T), DN_ZMem_No) +#define DN_MemListNewArrayNoZNamed(arena, T, count, name_cstr) (T *)DN_MemListAllocCallSite(arena, sizeof(T) * (count), alignof(T), DN_ZMem_No, DN_CallSiteNowNamed(name_cstr)) +#define DN_MemListNewArrayZ(arena, T, count) (T *)DN_MemListAlloc(arena, sizeof(T) * (count), alignof(T), DN_ZMem_Yes) +#define DN_MemListNewArrayZNamed(arena, T, count, name_cstr) (T *)DN_MemListAllocCallSite(arena, sizeof(T) * (count), alignof(T), DN_ZMem_Yes, DN_CallSiteNowNamed(name_cstr)) +#define DN_MemListNewContiguous(arena, T, zmem) (T *)DN_MemListAllocContiguous(arena, sizeof(T), alignof(T), zmem) +#define DN_MemListNewContiguousNamed(arena, T, zmem, name_cstr) (T *)DN_MemListAllocContiguousCallSite(arena, sizeof(T), alignof(T), zmem, DN_CallSiteNowNamed(name_cstr)) +#define DN_MemListNewContiguousZ(arena, T) (T *)DN_MemListAllocContiguous(arena, sizeof(T), alignof(T), DN_ZMem_Yes) +#define DN_MemListNewContiguousZNamed(arena, T, name_cstr) (T *)DN_MemListAllocContiguousCallSite(arena, sizeof(T), alignof(T), DN_ZMem_Yes, DN_CallSiteNowNamed(name_cstr)) +#define DN_MemListNewCopy(arena, T, src) (T *)DN_MemListCopy(arena, (src), sizeof(T), alignof(T)) +#define DN_MemListNewCopyNamed(arena, T, src, name_cstr) (T *)DN_MemListCopyCallSite(arena, (src), sizeof(T), alignof(T), DN_CallSiteNowNamed(name_cstr)) +#define DN_MemListNewNamed(arena, T, zmem, name_cstr) (T *)DN_MemListAllocCallSite(arena, sizeof(T), alignof(T), zmem, DN_CallSiteNowNamed(name_cstr)) +#define DN_MemListNewZ(arena, T) (T *)DN_MemListAlloc(arena, sizeof(T), alignof(T), DN_ZMem_Yes) +#define DN_MemListNewZNamed(arena, T, name_cstr) (T *)DN_MemListAllocCallSite(arena, sizeof(T), alignof(T), DN_ZMem_Yes, DN_CallSiteNowNamed(name_cstr)) // NOTE: Arena // Overview // `Arena`'s in this codebase are thin-layers over `MemList` but additionally provide @@ -5015,371 +5163,444 @@ DN_API void DN_MemListTempEnd DN_ArenaTempEnd(&temp); DN_ArenaDeinit(&arena); // Frees the memory */ -DN_API DN_Arena DN_ArenaFromMemList (DN_MemList *mem); -DN_API DN_Arena DN_ArenaFromHeapCallSite (DN_U64 reserve, DN_U64 commit, DN_MemFlags flags, DN_Heap heap, DN_CallSite call_site); -#define DN_ArenaFromHeap(reserve, commit, flags, heap, name_cstr) DN_ArenaFromHeapCallSite(reserve, commit, flags, heap, DN_CallSiteNowNamed(name_cstr)) -DN_API DN_Arena DN_ArenaTempBeginFromMemList (DN_MemList *mem); -DN_API DN_Arena DN_ArenaTempBeginFromArena (DN_Arena *arena); -DN_API void DN_ArenaTempEnd (DN_Arena *arena, DN_ArenaReset reset); -DN_API void* DN_ArenaAlloc (DN_Arena *arena, DN_U64 size, DN_U8 align, DN_ZMem z_mem); -DN_API void* DN_ArenaAllocContiguous (DN_Arena *arena, DN_U64 size, DN_U8 align, DN_ZMem z_arena); -DN_API void* DN_ArenaCopy (DN_Arena *arena, void const *data, DN_U64 size, DN_U8 align); -DN_API void DN_ArenaDeinit (DN_Arena *arena); -DN_API bool DN_ArenaOwnsPtr (DN_Arena const *arena, void *ptr); +DN_API DN_Arena DN_ArenaFromMemList (DN_MemList *mem); +DN_API DN_Arena DN_ArenaFromHeapCallSite (DN_U64 reserve, DN_U64 commit, DN_MemFlags flags, DN_Heap heap, DN_CallSite call_site); +#define DN_ArenaFromHeap(reserve, commit, flags, heap, name_cstr) DN_ArenaFromHeapCallSite(reserve, commit, flags, heap, DN_CallSiteNowNamed(name_cstr)) +DN_API DN_Arena DN_ArenaTempBeginFromMemList (DN_MemList *mem); +DN_API DN_Arena DN_ArenaTempBeginFromArena (DN_Arena *arena); +DN_API void DN_ArenaTempEnd (DN_Arena *arena, DN_ArenaReset reset); +DN_API void* DN_ArenaAllocCallSite (DN_Arena *arena, DN_U64 size, DN_U8 align, DN_ZMem z_mem, DN_CallSite call_site); +#define DN_ArenaAlloc(arena, size, align, z_mem) DN_ArenaAllocCallSite(arena, size, align, z_mem, DN_CallSiteNow) +#define DN_ArenaAllocNamed(arena, size, align, z_mem, name_cstr) DN_ArenaAllocCallSite(arena, size, align, z_mem, DN_CallSiteNowNamed(name_cstr)) +DN_API void* DN_ArenaAllocContiguousCallSite (DN_Arena *arena, DN_U64 size, DN_U8 align, DN_ZMem z_arena, DN_CallSite call_site); +#define DN_ArenaAllocContiguous(arena, size, align, z_arena) DN_ArenaAllocContiguousCallSite(arena, size, align, z_arena, DN_CallSiteNow) +#define DN_ArenaAllocContiguousNamed(arena, size, align, z_arena, name_cstr) DN_ArenaAllocContiguousCallSite(arena, size, align, z_arena, DN_CallSiteNowNamed(name_cstr)) +DN_API void DN_ArenaClear (DN_Arena *arena); +DN_API void* DN_ArenaCopyCallSite (DN_Arena *arena, void const *data, DN_U64 size, DN_U8 align, DN_CallSite call_site); +#define DN_ArenaCopy(arena, data, size, align) DN_ArenaCopyCallSite(arena, data, size, align, DN_CallSiteNow) +#define DN_ArenaCopyNamed(arena, data, size, align, name_cstr) DN_ArenaCopyCallSite(arena, data, size, align, DN_CallSiteNowNamed(name_cstr)) +DN_API void DN_ArenaDeinit (DN_Arena *arena); +DN_API bool DN_ArenaOwnsPtr (DN_Arena const *arena, void *ptr); -#define DN_ArenaNew(arena, T, zmem) (T *)DN_ArenaAlloc(arena, sizeof(T), alignof(T), zmem) -#define DN_ArenaNewZ(arena, T) (T *)DN_ArenaAlloc(arena, sizeof(T), alignof(T), DN_ZMem_Yes) -#define DN_ArenaNewContiguous(arena, T, zmem) (T *)DN_ArenaAllocContiguous(arena, sizeof(T), alignof(T), zmem) -#define DN_ArenaNewContiguousZ(arena, T) (T *)DN_ArenaAllocContiguous(arena, sizeof(T), alignof(T), DN_ZMem_Yes) -#define DN_ArenaNewArray(arena, T, count, zmem) (T *)DN_ArenaAlloc(arena, sizeof(T) * (count), alignof(T), zmem) -#define DN_ArenaNewArrayZ(arena, T, count) (T *)DN_ArenaAlloc(arena, sizeof(T) * (count), alignof(T), DN_ZMem_Yes) -#define DN_ArenaNewArrayNoZ(arena, T, count) (T *)DN_ArenaAlloc(arena, sizeof(T) * (count), alignof(T), DN_ZMem_No) -#define DN_ArenaNewCopy(arena, T, src) (T *)DN_ArenaCopy(arena, (src), sizeof(T), alignof(T)) -#define DN_ArenaNewArrayCopy(arena, T, src, count) (T *)DN_ArenaCopy(arena, (src), sizeof(T) * (count), alignof(T)) +#define DN_ArenaNew(arena, T, zmem) (T *)DN_ArenaAlloc(arena, sizeof(T), alignof(T), zmem) +#define DN_ArenaNewArray(arena, T, count, zmem) (T *)DN_ArenaAlloc(arena, sizeof(T) * (count), alignof(T), zmem) +#define DN_ArenaNewArrayCopy(arena, T, src, count) (T *)DN_ArenaCopy(arena, (src), sizeof(T) * (count), alignof(T)) +#define DN_ArenaNewArrayCopyNamed(arena, T, src, count, name_cstr) (T *)DN_ArenaCopyCallSite(arena, (src), sizeof(T) * (count), alignof(T), DN_CallSiteNowNamed(name_cstr)) +#define DN_ArenaNewArrayNamed(arena, T, count, zmem, name_cstr) (T *)DN_ArenaAllocCallSite(arena, sizeof(T) * (count), alignof(T), zmem, DN_CallSiteNowNamed(name_cstr)) +#define DN_ArenaNewArrayNoZ(arena, T, count) (T *)DN_ArenaAlloc(arena, sizeof(T) * (count), alignof(T), DN_ZMem_No) +#define DN_ArenaNewArrayNoZNamed(arena, T, count, name_cstr) (T *)DN_ArenaAllocCallSite(arena, sizeof(T) * (count), alignof(T), DN_ZMem_No, DN_CallSiteNowNamed(name_cstr)) +#define DN_ArenaNewArrayZ(arena, T, count) (T *)DN_ArenaAlloc(arena, sizeof(T) * (count), alignof(T), DN_ZMem_Yes) +#define DN_ArenaNewArrayZNamed(arena, T, count, name_cstr) (T *)DN_ArenaAllocCallSite(arena, sizeof(T) * (count), alignof(T), DN_ZMem_Yes, DN_CallSiteNowNamed(name_cstr)) +#define DN_ArenaNewContiguous(arena, T, zmem) (T *)DN_ArenaAllocContiguous(arena, sizeof(T), alignof(T), zmem) +#define DN_ArenaNewContiguousNamed(arena, T, zmem, name_cstr) (T *)DN_ArenaAllocContiguousCallSite(arena, sizeof(T), alignof(T), zmem, DN_CallSiteNowNamed(name_cstr)) +#define DN_ArenaNewContiguousZ(arena, T) (T *)DN_ArenaAllocContiguous(arena, sizeof(T), alignof(T), DN_ZMem_Yes) +#define DN_ArenaNewContiguousZNamed(arena, T, name_cstr) (T *)DN_ArenaAllocContiguousCallSite(arena, sizeof(T), alignof(T), DN_ZMem_Yes, DN_CallSiteNowNamed(name_cstr)) +#define DN_ArenaNewCopy(arena, T, src) (T *)DN_ArenaCopy(arena, (src), sizeof(T), alignof(T)) +#define DN_ArenaNewCopyNamed(arena, T, src, name_cstr) (T *)DN_ArenaCopyCallSite(arena, (src), sizeof(T), alignof(T), DN_CallSiteNowNamed(name_cstr)) +#define DN_ArenaNewNamed(arena, T, zmem, name_cstr) (T *)DN_ArenaAllocCallSite(arena, sizeof(T), alignof(T), zmem, DN_CallSiteNowNamed(name_cstr)) +#define DN_ArenaNewZ(arena, T) (T *)DN_ArenaAlloc(arena, sizeof(T), alignof(T), DN_ZMem_Yes) +#define DN_ArenaNewZNamed(arena, T, name_cstr) (T *)DN_ArenaAllocCallSite(arena, sizeof(T), alignof(T), DN_ZMem_Yes, DN_CallSiteNowNamed(name_cstr)) -DN_API DN_Pool DN_PoolFromArena (DN_Arena *arena, DN_U8 align); -DN_API bool DN_PoolIsValid (DN_Pool const *pool); -DN_API void * DN_PoolAlloc (DN_Pool *pool, DN_USize size); -DN_API void DN_PoolDealloc (DN_Pool *pool, void *ptr); -DN_API void * DN_PoolCopy (DN_Pool *pool, void const *data, DN_U64 size, uint8_t align); -#define DN_PoolNew(pool, T) (T *)DN_PoolAlloc(pool, sizeof(T)) -#define DN_PoolNewArray(pool, T, count) (T *)DN_PoolAlloc(pool, count * sizeof(T)) -#define DN_PoolNewCopy(pool, T, src) (T *)DN_PoolCopy (pool, (src), sizeof(T), alignof(T)) -#define DN_PoolNewArrayCopy(pool, T, src, count) (T *)DN_PoolCopy (pool, (src), sizeof(T) * (count), alignof(T)) +DN_API DN_Pool DN_PoolFromArena (DN_Arena *arena, DN_U8 align); +DN_API bool DN_PoolIsValid (DN_Pool const *pool); +DN_API void * DN_PoolAllocCallSite (DN_Pool *pool, DN_USize size, DN_CallSite call_site); +#define DN_PoolAlloc(pool, size) DN_PoolAllocCallSite(pool, size, DN_CallSiteNow) +#define DN_PoolAllocNamed(pool, size, name_cstr) DN_PoolAllocCallSite(pool, size, DN_CallSiteNowNamed(name_cstr)) +DN_API void DN_PoolDealloc (DN_Pool *pool, void *ptr); +DN_API void * DN_PoolCopyCallSite (DN_Pool *pool, void const *data, DN_U64 size, uint8_t align, DN_CallSite call_site); +#define DN_PoolCopy(pool, data, size, align) DN_PoolCopyCallSite(pool, data, size, align, DN_CallSiteNow) +#define DN_PoolCopyNamed(pool, data, size, align, name_cstr) DN_PoolCopyCallSite(pool, data, size, align, DN_CallSiteNowNamed(name_cstr)) +#define DN_PoolNew(pool, T) (T *)DN_PoolAlloc(pool, sizeof(T)) +#define DN_PoolNewArray(pool, T, count) (T *)DN_PoolAlloc(pool, count * sizeof(T)) +#define DN_PoolNewArrayCopy(pool, T, src, count) (T *)DN_PoolCopy (pool, (src), sizeof(T) * (count), alignof(T)) +#define DN_PoolNewArrayCopyNamed(pool, T, src, count, name_cstr) (T *)DN_PoolCopyCallSite(pool, (src), sizeof(T) * (count), alignof(T), DN_CallSiteNowNamed(name_cstr)) +#define DN_PoolNewArrayNamed(pool, T, count, name_cstr) (T *)DN_PoolAllocCallSite(pool, count * sizeof(T), DN_CallSiteNowNamed(name_cstr)) +#define DN_PoolNewCopy(pool, T, src) (T *)DN_PoolCopy (pool, (src), sizeof(T), alignof(T)) +#define DN_PoolNewCopyNamed(pool, T, src, name_cstr) (T *)DN_PoolCopyCallSite(pool, (src), sizeof(T), alignof(T), DN_CallSiteNowNamed(name_cstr)) +#define DN_PoolNewNamed(pool, T, name_cstr) (T *)DN_PoolAllocCallSite(pool, sizeof(T), DN_CallSiteNowNamed(name_cstr)) -DN_API DN_ErrSink* DN_ErrSinkBegin_ (DN_ErrSink *err, DN_ErrSinkMode mode, DN_CallSite call_site); -#define DN_ErrSinkBegin(err, mode) DN_ErrSinkBegin_(err, mode, DN_CallSiteNow) -#define DN_ErrSinkBeginDefault(err) DN_ErrSinkBegin(err, DN_ErrSinkMode_Nil) -DN_API bool DN_ErrSinkHasError (DN_ErrSink *err); -DN_API DN_ErrSinkMsg* DN_ErrSinkEnd (DN_Arena *arena, DN_ErrSink *err); -DN_API DN_Str8 DN_ErrSinkEndStr8 (DN_Arena *arena, DN_ErrSink *err); -DN_API void DN_ErrSinkEndIgnore (DN_ErrSink *err); -DN_API bool DN_ErrSinkEndLogError_ (DN_ErrSink *err, DN_CallSite call_site, DN_Str8 msg); -#define DN_ErrSinkEndLogError(err, err_msg) DN_ErrSinkEndLogError_(err, DN_CallSiteNow, err_msg) -DN_API bool DN_ErrSinkEndLogErrorFV_ (DN_ErrSink *err, DN_CallSite call_site, DN_FMT_ATTRIB char const *fmt, va_list args); -#define DN_ErrSinkEndLogErrorFV(err, fmt, args) DN_ErrSinkEndLogErrorFV_(err, DN_CallSiteNow, fmt, args) -DN_API bool DN_ErrSinkEndLogErrorF_ (DN_ErrSink *err, DN_CallSite call_site, DN_FMT_ATTRIB char const *fmt, ...); -#define DN_ErrSinkEndLogErrorF(err, fmt, ...) DN_ErrSinkEndLogErrorF_(err, DN_CallSiteNow, fmt, ##__VA_ARGS__) -DN_API void DN_ErrSinkEndExitIfErrorF_ (DN_ErrSink *err, DN_CallSite call_site, DN_U32 exit_val, DN_FMT_ATTRIB char const *fmt, ...); -#define DN_ErrSinkEndExitIfErrorF(err, exit_val, fmt, ...) DN_ErrSinkEndExitIfErrorF_(err, DN_CallSiteNow, exit_val, fmt, ##__VA_ARGS__) -DN_API void DN_ErrSinkEndExitIfErrorFV_ (DN_ErrSink *err, DN_CallSite call_site, DN_U32 exit_val, DN_FMT_ATTRIB char const *fmt, va_list args); -#define DN_ErrSinkEndExitIfErrorFV(err, exit_val, fmt, args) DN_ErrSinkEndExitIfErrorFV_(err, DN_CallSiteNow, exit_val, fmt, args) -DN_API void DN_ErrSinkAppendFV_ (DN_ErrSink *err, DN_U32 error_code, DN_CallSite call_site, DN_FMT_ATTRIB char const *fmt, va_list args); -#define DN_ErrSinkAppendFV(error, error_code, fmt, args) DN_ErrSinkAppendFV_(error, error_code, DN_CallSiteNow, fmt, args) -DN_API void DN_ErrSinkAppendF_ (DN_ErrSink *err, DN_U32 error_code, DN_CallSite call_site, DN_FMT_ATTRIB char const *fmt, ...); -#define DN_ErrSinkAppendF(error, error_code, fmt, ...) DN_ErrSinkAppendF_(error, error_code, DN_CallSiteNow, fmt, ##__VA_ARGS__) +DN_API DN_ErrSink* DN_ErrSinkBegin_ (DN_ErrSink *err, DN_ErrSinkMode mode, DN_CallSite call_site); +#define DN_ErrSinkBegin(err, mode) DN_ErrSinkBegin_(err, mode, DN_CallSiteNow) +#define DN_ErrSinkBeginDefault(err) DN_ErrSinkBegin(err, DN_ErrSinkMode_Nil) +DN_API bool DN_ErrSinkHasError (DN_ErrSink *err); +DN_API DN_ErrSinkMsg* DN_ErrSinkEnd (DN_Arena *arena, DN_ErrSink *err); +DN_API DN_Str8 DN_ErrSinkEndStr8 (DN_Arena *arena, DN_ErrSink *err); +DN_API void DN_ErrSinkEndIgnore (DN_ErrSink *err); +DN_API bool DN_ErrSinkEndLogError_ (DN_ErrSink *err, DN_CallSite call_site, DN_Str8 msg); +#define DN_ErrSinkEndLogError(err, err_msg) DN_ErrSinkEndLogError_(err, DN_CallSiteNow, err_msg) +DN_API bool DN_ErrSinkEndLogErrorFV_ (DN_ErrSink *err, DN_CallSite call_site, DN_FMT_ATTRIB char const *fmt, va_list args); +#define DN_ErrSinkEndLogErrorFV(err, fmt, args) DN_ErrSinkEndLogErrorFV_(err, DN_CallSiteNow, fmt, args) +DN_API bool DN_ErrSinkEndLogErrorF_ (DN_ErrSink *err, DN_CallSite call_site, DN_FMT_ATTRIB char const *fmt, ...); +#define DN_ErrSinkEndLogErrorF(err, fmt, ...) DN_ErrSinkEndLogErrorF_(err, DN_CallSiteNow, fmt, ##__VA_ARGS__) +DN_API void DN_ErrSinkEndExitIfErrorF_ (DN_ErrSink *err, DN_CallSite call_site, DN_U32 exit_val, DN_FMT_ATTRIB char const *fmt, ...); +#define DN_ErrSinkEndExitIfErrorF(err, exit_val, fmt, ...) DN_ErrSinkEndExitIfErrorF_(err, DN_CallSiteNow, exit_val, fmt, ##__VA_ARGS__) +DN_API void DN_ErrSinkEndExitIfErrorFV_ (DN_ErrSink *err, DN_CallSite call_site, DN_U32 exit_val, DN_FMT_ATTRIB char const *fmt, va_list args); +#define DN_ErrSinkEndExitIfErrorFV(err, exit_val, fmt, args) DN_ErrSinkEndExitIfErrorFV_(err, DN_CallSiteNow, exit_val, fmt, args) +DN_API void DN_ErrSinkAppendFV_ (DN_ErrSink *err, DN_U32 error_code, DN_CallSite call_site, DN_FMT_ATTRIB char const *fmt, va_list args); +#define DN_ErrSinkAppendFV(error, error_code, fmt, args) DN_ErrSinkAppendFV_(error, error_code, DN_CallSiteNow, fmt, args) +DN_API void DN_ErrSinkAppendF_ (DN_ErrSink *err, DN_U32 error_code, DN_CallSite call_site, DN_FMT_ATTRIB char const *fmt, ...); +#define DN_ErrSinkAppendF(error, error_code, fmt, ...) DN_ErrSinkAppendF_(error, error_code, DN_CallSiteNow, fmt, ##__VA_ARGS__) -DN_API DN_TcInitArgs DN_TcInitArgsDefault (); -DN_API void DN_TcInit (DN_TcCore *tc, DN_U64 thread_id, DN_Arena *main_arena, DN_Arena *temp_arenas, DN_USize temp_arenas_count, DN_Arena *err_sink_arena); -DN_API void DN_TcInitFromHeap (DN_TcCore *tc, DN_U64 thread_id, DN_TcInitArgs args, DN_Heap heap); -DN_API void DN_TcDeinit (DN_TcCore *tc, DN_TcDeinitArenas deinit_arenas); -DN_API void DN_TcEquip (DN_TcCore *tc); -DN_API DN_TcCore* DN_TcGet (); -DN_API DN_Arena* DN_TcMainArena (); -DN_API DN_Pool* DN_TcMainPool (); -DN_API DN_Arena DN_TcTempArenaFromAllocator (DN_Allocator *conflicts, DN_USize count); -DN_API DN_Arena DN_TcTempArenaFromArena (DN_Arena **conflicts, DN_USize count); -DN_API DN_TcScratch DN_TcScratchBeginAllocator (DN_Allocator *conflicts, DN_USize count); -DN_API DN_TcScratch DN_TcScratchBeginArena (DN_Arena **conflicts, DN_USize count); -DN_API void DN_TcScratchEnd (DN_TcScratch *scratch); -DN_API void DN_TcSetFrameArena (DN_Arena *arena); -DN_API DN_Arena* DN_TcFrameArena (); -DN_API DN_ErrSink* DN_TcErrSink (); -#define DN_TcErrSinkBegin(mode) DN_ErrSinkBegin(DN_TcErrSink(), mode) -#define DN_TcErrSinkBeginDefault() DN_ErrSinkBeginDefault(DN_TcErrSink()) +DN_API DN_TcInitArgs DN_TcInitArgsDefault (); +DN_API void DN_TcInit (DN_TcCore *tc, DN_U64 thread_id, DN_Arena *main_arena, DN_Arena *temp_arenas, DN_USize temp_arenas_count, DN_Arena *err_sink_arena); +DN_API void DN_TcInitFromHeap (DN_TcCore *tc, DN_U64 thread_id, DN_TcInitArgs args, DN_Heap heap); +DN_API void DN_TcDeinit (DN_TcCore *tc, DN_TcDeinitArenas deinit_arenas); +DN_API void DN_TcEquip (DN_TcCore *tc); +DN_API DN_TcCore* DN_TcGet (); +DN_API DN_Arena* DN_TcMainArena (); +DN_API DN_Pool* DN_TcMainPool (); +DN_API DN_Arena DN_TcTempArenaFromAllocator (DN_Allocator *conflicts, DN_USize count); +DN_API DN_Arena DN_TcTempArenaFromArena (DN_Arena **conflicts, DN_USize count); +DN_API DN_TcScratch DN_TcScratchBeginAllocator (DN_Allocator *conflicts, DN_USize count); +DN_API DN_TcScratch DN_TcScratchBeginArena (DN_Arena **conflicts, DN_USize count); +DN_API void DN_TcScratchEnd (DN_TcScratch *scratch); +DN_API void DN_TcSetFrameArena (DN_Arena *arena); +DN_API DN_Arena* DN_TcFrameArena (); +DN_API DN_ErrSink* DN_TcErrSink (); +#define DN_TcErrSinkBegin(mode) DN_ErrSinkBegin(DN_TcErrSink(), mode) +#define DN_TcErrSinkBeginDefault() DN_ErrSinkBeginDefault(DN_TcErrSink()) -DN_API bool DN_CharIsAlphabet (char ch); -DN_API bool DN_CharIsDigit (char ch); -DN_API bool DN_CharIsAlphaNum (char ch); -DN_API bool DN_CharIsWhitespace (char ch); -DN_API bool DN_CharIsHex (char ch); -DN_API char DN_CharToLower (char ch); -DN_API char DN_CharToUpper (char ch); +DN_API bool DN_CharIsAlphabet (char ch); +DN_API bool DN_CharIsDigit (char ch); +DN_API bool DN_CharIsAlphaNum (char ch); +DN_API bool DN_CharIsWhitespace (char ch); +DN_API bool DN_CharIsHex (char ch); +DN_API char DN_CharToLower (char ch); +DN_API char DN_CharToUpper (char ch); -DN_API DN_U64FromResult DN_U64FromStr8Delimiters (DN_Str8 string, DN_Str8 const *delimiters, DN_USize delimiters_count); -DN_API DN_U64FromResult DN_U64FromStr8Delimiter (DN_Str8 string, DN_Str8 delimiter); -DN_API DN_U64FromResult DN_U64FromStr8 (DN_Str8 string); -DN_API DN_U64FromResult DN_U64FromPtrDelimiter (void const *data, DN_USize size, DN_Str8 delimiter); -DN_API DN_U64FromResult DN_U64FromPtr (void const *data, DN_USize size); -DN_API DN_U64 DN_U64FromPtrUnsafeDelimiter (void const *data, DN_USize size, DN_Str8 delimiter); -DN_API DN_U64 DN_U64FromPtrUnsafe (void const *data, DN_USize size); -DN_API DN_U64FromResult DN_U64FromHexPtr (void const *hex, DN_USize hex_count); -DN_API DN_U64 DN_U64FromHexPtrUnsafe (void const *hex, DN_USize hex_count); -DN_API DN_U64FromResult DN_U64FromHexStr8 (DN_Str8 hex); -DN_API DN_U64 DN_U64FromHexStr8Unsafe (DN_Str8 hex); -DN_API DN_U64 DN_U64FromU8x32HiBEUnsafe (DN_U8x32 const *val); // Get U64 stored in big-endian at the high bytes [24:32) -DN_API DN_U64FromResult DN_U64FromU8x32HiBE (DN_U8x32 const *val); // Checks [0:24) bytes aren't set before getting the U64 -DN_API DN_USize DN_USizeFromU8x32HiBEUnsafe (DN_U8x32 const *val); // Get USize stored in big-endian at the high bytes [32 - sizeof USize:32) -DN_API DN_USizeFromResult DN_USizeFromU8x32HiBE (DN_U8x32 const *val); // Checks [0:sizeof USize) bytes aren't set before getting the U64 -DN_API DN_U32FromResult DN_U32FromHexStr8 (DN_Str8 hex); -DN_API DN_U32FromResult DN_U32FromStr8Delimiters (DN_Str8 string, DN_Str8 const *delimiters, DN_USize delimiters_count); -DN_API DN_U32FromResult DN_U32FromStr8Delimiter (DN_Str8 string, DN_Str8 delimiter); -DN_API DN_U32FromResult DN_U32FromPtr (void const *data, DN_USize size); -DN_API DN_I64FromResult DN_I64FromStr8Delimiters (DN_Str8 string, DN_Str8 const *delimiters, DN_USize delimiters_count); -DN_API DN_I64FromResult DN_I64FromStr8Delimiter (DN_Str8 string, DN_Str8 delimiter); -DN_API DN_I64FromResult DN_I64FromStr8 (DN_Str8 string); -DN_API DN_I64FromResult DN_I64FromPtr (void const *data, DN_USize size); -DN_API DN_I64 DN_I64FromPtrUnsafe (void const *data, DN_USize size); +DN_API DN_U64FromResult DN_U64FromStr8Delimiters (DN_Str8 string, DN_Str8 const *delimiters, DN_USize delimiters_count); +DN_API DN_U64FromResult DN_U64FromStr8Delimiter (DN_Str8 string, DN_Str8 delimiter); +DN_API DN_U64FromResult DN_U64FromStr8 (DN_Str8 string); +DN_API DN_U64FromResult DN_U64FromPtrDelimiter (void const *data, DN_USize size, DN_Str8 delimiter); +DN_API DN_U64FromResult DN_U64FromPtr (void const *data, DN_USize size); +DN_API DN_U64 DN_U64FromPtrUnsafeDelimiter (void const *data, DN_USize size, DN_Str8 delimiter); +DN_API DN_U64 DN_U64FromPtrUnsafe (void const *data, DN_USize size); +DN_API DN_U64FromResult DN_U64FromHexPtr (void const *hex, DN_USize hex_count); +DN_API DN_U64 DN_U64FromHexPtrUnsafe (void const *hex, DN_USize hex_count); +DN_API DN_U64FromResult DN_U64FromHexStr8 (DN_Str8 hex); +DN_API DN_U64 DN_U64FromHexStr8Unsafe (DN_Str8 hex); +DN_API DN_U64 DN_U64FromU8x32HiBEUnsafe (DN_U8x32 const *val); // Get U64 stored in big-endian at the high bytes [24:32) +DN_API DN_U64FromResult DN_U64FromU8x32HiBE (DN_U8x32 const *val); // Checks [0:24) bytes aren't set before getting the U64 +DN_API DN_USize DN_USizeFromU8x32HiBEUnsafe (DN_U8x32 const *val); // Get USize stored in big-endian at the high bytes [32 - sizeof USize:32) +DN_API DN_USizeFromResult DN_USizeFromU8x32HiBE (DN_U8x32 const *val); // Checks [0:sizeof USize) bytes aren't set before getting the U64 +DN_API DN_U32FromResult DN_U32FromHexStr8 (DN_Str8 hex); +DN_API DN_U32FromResult DN_U32FromStr8Delimiters (DN_Str8 string, DN_Str8 const *delimiters, DN_USize delimiters_count); +DN_API DN_U32FromResult DN_U32FromStr8Delimiter (DN_Str8 string, DN_Str8 delimiter); +DN_API DN_U32FromResult DN_U32FromPtr (void const *data, DN_USize size); +DN_API DN_I64FromResult DN_I64FromStr8Delimiters (DN_Str8 string, DN_Str8 const *delimiters, DN_USize delimiters_count); +DN_API DN_I64FromResult DN_I64FromStr8Delimiter (DN_Str8 string, DN_Str8 delimiter); +DN_API DN_I64FromResult DN_I64FromStr8 (DN_Str8 string); +DN_API DN_I64FromResult DN_I64FromPtr (void const *data, DN_USize size); +DN_API DN_I64 DN_I64FromPtrUnsafe (void const *data, DN_USize size); -DN_API bool DN_U8x32Eq (DN_U8x32 const *lhs, DN_U8x32 const *rhs); -DN_API DN_U8x32 DN_U8x32FromBytesLeftPadZ (DN_U8 const *ptr, DN_USize size); -DN_API DN_U8x32 DN_U8x32FromHexUnsafe (DN_Str8 hex_32b); -DN_API DN_U8x32FromResult DN_U8x32FromHex (DN_Str8 hex_32b); -DN_API DN_U8x32FromResult DN_U8x32FromDecimalStr8 (DN_Str8 decimal); // Write decimal string (e.g. "12345") as big-endian 256-bit value +DN_API bool DN_U8x32Eq (DN_U8x32 const *lhs, DN_U8x32 const *rhs); +DN_API DN_U8x32 DN_U8x32FromBytesLeftPadZ (DN_U8 const *ptr, DN_USize size); +DN_API DN_U8x32 DN_U8x32FromHexUnsafe (DN_Str8 hex_32b); +DN_API DN_U8x32FromResult DN_U8x32FromHex (DN_Str8 hex_32b); +DN_API DN_U8x32FromResult DN_U8x32FromDecimalStr8 (DN_Str8 decimal); // Write decimal string (e.g. "12345") as big-endian 256-bit value -DN_API DN_Allocator DN_AllocatorFromMemList (DN_MemList *mem); -DN_API DN_Allocator DN_AllocatorFromArena (DN_Arena *arena); -DN_API DN_Allocator DN_AllocatorFromPool (DN_Pool *pool); -DN_API void* DN_AllocatorAlloc (DN_Allocator allocator, DN_USize count, DN_U8 align, DN_ZMem z_mem); -#define DN_AllocatorNew(allocator, T, zmem) (T *)DN_AllocatorAlloc(allocator, sizeof(T), alignof(T), zmem) -#define DN_AllocatorNewZ(allocator, T) (T *)DN_AllocatorAlloc(allocator, sizeof(T), alignof(T), DN_ZMem_Yes) -#define DN_AllocatorNewNoZ(allocator, T) (T *)DN_AllocatorAlloc(allocator, sizeof(T), alignof(T), DN_ZMem_No) -#define DN_AllocatorNewArray(allocator, T, count, zmem) (T *)DN_AllocatorAlloc(allocator, sizeof(T) * (count), alignof(T), zmem) -#define DN_AllocatorNewArrayZ(allocator, T, count) (T *)DN_AllocatorAlloc(allocator, sizeof(T) * (count), alignof(T), DN_ZMem_Yes) -#define DN_AllocatorNewArrayNoZ(allocator, T, count) (T *)DN_AllocatorAlloc(allocator, sizeof(T) * (count), alignof(T), DN_ZMem_No) +DN_API DN_Allocator DN_AllocatorFromMemList (DN_MemList *mem); +DN_API DN_Allocator DN_AllocatorFromArena (DN_Arena *arena); +DN_API DN_Allocator DN_AllocatorFromPool (DN_Pool *pool); +DN_API DN_Allocator DN_AllocatorFromHeap (DN_Heap *heap); +DN_API void* DN_AllocatorAllocCallSite (DN_Allocator allocator, DN_USize size, DN_U8 align, DN_ZMem z_mem, DN_CallSite call_site); +#define DN_AllocatorAlloc(allocator, count, align, z_mem) DN_AllocatorAllocCallSite(allocator, count, align, z_mem, DN_CallSiteNow) +#define DN_AllocatorAllocNamed(allocator, count, align, z_mem, name_cstr) DN_AllocatorAllocCallSite(allocator, count, align, z_mem, DN_CallSiteNowNamed(name_cstr)) +DN_API void DN_AllocatorDealloc (DN_Allocator allocator, void *ptr, DN_USize size); +#define DN_AllocatorNew(allocator, T, zmem) (T *)DN_AllocatorAlloc(allocator, sizeof(T), alignof(T), zmem) +#define DN_AllocatorNewZ(allocator, T) (T *)DN_AllocatorAlloc(allocator, sizeof(T), alignof(T), DN_ZMem_Yes) +#define DN_AllocatorNewNoZ(allocator, T) (T *)DN_AllocatorAlloc(allocator, sizeof(T), alignof(T), DN_ZMem_No) +#define DN_AllocatorNewArray(allocator, T, count, zmem) (T *)DN_AllocatorAlloc(allocator, sizeof(T) * (count), alignof(T), zmem) +#define DN_AllocatorNewArrayZ(allocator, T, count) (T *)DN_AllocatorAlloc(allocator, sizeof(T) * (count), alignof(T), DN_ZMem_Yes) +#define DN_AllocatorNewArrayNoZ(allocator, T, count) (T *)DN_AllocatorAlloc(allocator, sizeof(T) * (count), alignof(T), DN_ZMem_No) +#define DN_AllocatorNewNamed(allocator, T, zmem, name_cstr) (T *)DN_AllocatorAllocCallSite(allocator, sizeof(T), alignof(T), zmem, DN_CallSiteNowNamed(name_cstr)) +#define DN_AllocatorNewZNamed(allocator, T, name_cstr) (T *)DN_AllocatorAllocCallSite(allocator, sizeof(T), alignof(T), DN_ZMem_Yes, DN_CallSiteNowNamed(name_cstr)) +#define DN_AllocatorNewNoZNamed(allocator, T, name_cstr) (T *)DN_AllocatorAllocCallSite(allocator, sizeof(T), alignof(T), DN_ZMem_No, DN_CallSiteNowNamed(name_cstr)) +#define DN_AllocatorNewArrayNamed(allocator, T, count, zmem, name_cstr) (T *)DN_AllocatorAllocCallSite(allocator, sizeof(T) * (count), alignof(T), zmem, DN_CallSiteNowNamed(name_cstr)) +#define DN_AllocatorNewArrayZNamed(allocator, T, count, name_cstr) (T *)DN_AllocatorAllocCallSite(allocator, sizeof(T) * (count), alignof(T), DN_ZMem_Yes, DN_CallSiteNowNamed(name_cstr)) +#define DN_AllocatorNewArrayNoZNamed(allocator, T, count, name_cstr) (T *)DN_AllocatorAllocCallSite(allocator, sizeof(T) * (count), alignof(T), DN_ZMem_No, DN_CallSiteNowNamed(name_cstr)) -DN_API DN_USize DN_FmtVCount (DN_FMT_ATTRIB char const *fmt, va_list args); -DN_API DN_USize DN_FmtCount (DN_FMT_ATTRIB char const *fmt, ...); -DN_API DN_FmtAppendResult DN_FmtVAppend (char *buf, DN_USize *buf_size, DN_USize buf_max, char const *fmt, va_list args); -DN_API DN_FmtAppendResult DN_FmtAppend (char *buf, DN_USize *buf_size, DN_USize buf_max, char const *fmt, ...); -DN_API DN_FmtAppendResult DN_FmtAppendTruncate (char *buf, DN_USize *buf_size, DN_USize buf_max, DN_Str8 truncator, char const *fmt, ...); -DN_API DN_USize DN_CStr8Count (char const *src); -DN_API DN_USize DN_CStr16Count (wchar_t const *src); +DN_API DN_USize DN_FmtVCount (DN_FMT_ATTRIB char const *fmt, va_list args); +DN_API DN_USize DN_FmtCount (DN_FMT_ATTRIB char const *fmt, ...); +DN_API DN_FmtAppendResult DN_FmtVAppend (char *buf, DN_USize *buf_size, DN_USize buf_max, char const *fmt, va_list args); +DN_API DN_FmtAppendResult DN_FmtAppend (char *buf, DN_USize *buf_size, DN_USize buf_max, char const *fmt, ...); +DN_API DN_FmtAppendResult DN_FmtAppendTruncate (char *buf, DN_USize *buf_size, DN_USize buf_max, DN_Str8 truncator, char const *fmt, ...); +DN_API DN_USize DN_CStr8Count (char const *src); +DN_API DN_USize DN_CStr16Count (wchar_t const *src); -#define DN_Str16Lit(string) DN_Str16{(wchar_t *)(string), sizeof(string)/sizeof(string[0]) - 1} -#define DN_Str16FromPtr(data, count) DN_Literal(DN_Str16){(wchar_t *)(data), (DN_USize)(count)} +// NOTE: Strings +// API +// DN_Str8Is +// Identify if the string satisfies one or more of the types indicated by `flags` such as +// whether or not the string contains valid hex, is all uppercase, all digits and so forth. +// Flags can be combined to check more than one condition at once. If more than one flag is set +// all conditions must be met for the returned value to be successful. +// +// An empty `string` is considered a failure and the returned `success` value is false. +#define DN_Str16Lit(string) DN_Str16{(wchar_t *)(string), sizeof(string)/sizeof(string[0]) - 1} +#define DN_Str16FromPtr(data, count) DN_Literal(DN_Str16){(wchar_t *)(data), (DN_USize)(count)} -#define DN_Str8Lit(c_str) DN_Literal(DN_Str8){(char *)(c_str), sizeof(c_str) - 1} -#define DN_Str8PrintFmt(string) (int)((string).count), (string).data +#define DN_Str8Lit(c_str) DN_Literal(DN_Str8){(char *)(c_str), sizeof(c_str) - 1} +#define DN_Str8PrintFmt(string) (int)((string).count), (string).data -#define DN_Str8FromPtr(data, count) DN_Literal(DN_Str8){(char *)(data), (DN_USize)(count)} -#define DN_Str8FromStruct(ptr) DN_Str8FromPtr((ptr)->data, (ptr)->count) -#define DN_Str8FromLitArray(c_array) DN_Str8FromPtr(c_array, DN_ArrayCountU(c_array)) -DN_API DN_Str8 DN_Str8AllocAllocator (DN_USize count, DN_ZMem z_mem, DN_Allocator allocator); -DN_API DN_Str8 DN_Str8AllocArena (DN_USize count, DN_ZMem z_mem, DN_Arena *arena); -DN_API DN_Str8 DN_Str8AllocPool (DN_USize count, DN_Pool *pool); +#define DN_Str8FromPtr(data, count) DN_Literal(DN_Str8){(char *)(data), (DN_USize)(count)} +#define DN_Str8FromStruct(ptr) DN_Str8FromPtr((ptr)->data, (ptr)->count) +#define DN_Str8FromLitArray(c_array) DN_Str8FromPtr(c_array, DN_ArrayCountU(c_array)) +DN_API DN_Str8 DN_Str8AllocAllocatorCallSite (DN_USize count, DN_ZMem z_mem, DN_Allocator allocator, DN_CallSite call_site); +#define DN_Str8AllocAllocator(count, z_mem, allocator) DN_Str8AllocAllocatorCallSite(count, z_mem, allocator, DN_CallSiteNow) +#define DN_Str8AllocAllocatorNamed(count, z_mem, allocator, name_cstr) DN_Str8AllocAllocatorCallSite(count, z_mem, allocator, DN_CallSiteNowNamed(name_cstr)) +DN_API DN_Str8 DN_Str8AllocArenaCallSite (DN_USize count, DN_ZMem z_mem, DN_Arena *arena, DN_CallSite call_site); +#define DN_Str8AllocArena(count, z_mem, arena) DN_Str8AllocArenaCallSite(count, z_mem, arena, DN_CallSiteNow) +#define DN_Str8AllocArenaNamed(count, z_mem, arena, name_cstr) DN_Str8AllocArenaCallSite(count, z_mem, arena, DN_CallSiteNowNamed(name_cstr)) +DN_API DN_Str8 DN_Str8AllocPoolCallSite (DN_USize count, DN_Pool *pool, DN_CallSite call_site); +#define DN_Str8AllocPool(count, pool) DN_Str8AllocPoolCallSite(count, pool, DN_CallSiteNow) +#define DN_Str8AllocPoolNamed(count, pool, name_cstr) DN_Str8AllocPoolCallSite(count, pool, DN_CallSiteNowNamed(name_cstr)) -DN_API DN_Str8 DN_Str8FromCStr8 (char const *src); -DN_API DN_Str8 DN_Str8FromCStr8Arena (char const *src, DN_Arena *arena); -DN_API DN_Str8 DN_Str8FromPtrArena (void const *data, DN_USize count, DN_Arena *arena); -DN_API DN_Str8 DN_Str8FromPtrPool (void const *data, DN_USize count, DN_Pool *pool); -DN_API DN_Str8 DN_Str8FromStr8Allocator (DN_Str8 string, DN_Allocator allocator); -DN_API DN_Str8 DN_Str8FromStr8Arena (DN_Str8 string, DN_Arena *arena); -DN_API DN_Str8 DN_Str8FromStr8Pool (DN_Str8 string, DN_Pool *pool); -DN_API DN_Str8 DN_Str8FmtVAllocator (DN_Allocator allocator, DN_FMT_ATTRIB char const *fmt, va_list args); -DN_API DN_Str8 DN_Str8FmtVArena (DN_Arena *arena, DN_FMT_ATTRIB char const *fmt, va_list args); -DN_API DN_Str8 DN_Str8FmtAllocator (DN_Allocator allocator, DN_FMT_ATTRIB char const *fmt, ...); -DN_API DN_Str8 DN_Str8FmtArena (DN_Arena *arena, DN_FMT_ATTRIB char const *fmt, ...); -DN_API DN_Str8 DN_Str8FmtVPool (DN_Pool *pool, DN_FMT_ATTRIB char const *fmt, va_list args); -DN_API DN_Str8 DN_Str8FmtPool (DN_Pool *pool, DN_FMT_ATTRIB char const *fmt, ...); +DN_API DN_Str8 DN_Str8FromCStr8 (char const *src); +DN_API DN_Str8 DN_Str8FromCStr8ArenaCallSite (char const *src, DN_Arena *arena, DN_CallSite call_site); +#define DN_Str8FromCStr8Arena(src, arena) DN_Str8FromCStr8ArenaCallSite(src, arena, DN_CallSiteNow) +#define DN_Str8FromCStr8ArenaNamed(src, arena, name_cstr) DN_Str8FromCStr8ArenaCallSite(src, arena, DN_CallSiteNowNamed(name_cstr)) +DN_API DN_Str8 DN_Str8FromPtrArenaCallSite (void const *data, DN_USize count, DN_Arena *arena, DN_CallSite call_site); +#define DN_Str8FromPtrArena(data, count, arena) DN_Str8FromPtrArenaCallSite(data, count, arena, DN_CallSiteNow) +#define DN_Str8FromPtrArenaNamed(data, count, arena, name_cstr) DN_Str8FromPtrArenaCallSite(data, count, arena, DN_CallSiteNowNamed(name_cstr)) +DN_API DN_Str8 DN_Str8FromPtrPoolCallSite (void const *data, DN_USize count, DN_Pool *pool, DN_CallSite call_site); +#define DN_Str8FromPtrPool(data, count, pool) DN_Str8FromPtrPoolCallSite(data, count, pool, DN_CallSiteNow) +#define DN_Str8FromPtrPoolNamed(data, count, pool, name_cstr) DN_Str8FromPtrPoolCallSite(data, count, pool, DN_CallSiteNowNamed(name_cstr)) +DN_API DN_Str8 DN_Str8FromStr8AllocatorCallSite (DN_Str8 string, DN_Allocator allocator, DN_CallSite call_site); +#define DN_Str8FromStr8Allocator(string, allocator) DN_Str8FromStr8AllocatorCallSite(string, allocator, DN_CallSiteNow) +#define DN_Str8FromStr8AllocatorNamed(string, allocator, name_cstr) DN_Str8FromStr8AllocatorCallSite(string, allocator, DN_CallSiteNowNamed(name_cstr)) +DN_API DN_Str8 DN_Str8FromStr8ArenaCallSite (DN_Str8 string, DN_Arena *arena, DN_CallSite call_site); +#define DN_Str8FromStr8Arena(string, arena) DN_Str8FromStr8ArenaCallSite(string, arena, DN_CallSiteNow) +#define DN_Str8FromStr8ArenaNamed(string, arena, name_cstr) DN_Str8FromStr8ArenaCallSite(string, arena, DN_CallSiteNowNamed(name_cstr)) +DN_API DN_Str8 DN_Str8FromStr8PoolCallSite (DN_Str8 string, DN_Pool *pool, DN_CallSite call_site); +#define DN_Str8FromStr8Pool(string, pool) DN_Str8FromStr8PoolCallSite(string, pool, DN_CallSiteNow) +#define DN_Str8FromStr8PoolNamed(string, pool, name_cstr) DN_Str8FromStr8PoolCallSite(string, pool, DN_CallSiteNowNamed(name_cstr)) +DN_API DN_Str8 DN_Str8FmtVAllocatorCallSite (DN_Allocator allocator, DN_FMT_ATTRIB char const *fmt, va_list args, DN_CallSite call_site); +#define DN_Str8FmtVAllocator(allocator, fmt, args) DN_Str8FmtVAllocatorCallSite(allocator, fmt, args, DN_CallSiteNow) +#define DN_Str8FmtVAllocatorNamed(allocator, fmt, args, name_cstr) DN_Str8FmtVAllocatorCallSite(allocator, fmt, args, DN_CallSiteNowNamed(name_cstr)) +DN_API DN_Str8 DN_Str8FmtVArenaCallSite (DN_Arena *arena, DN_FMT_ATTRIB char const *fmt, va_list args, DN_CallSite call_site); +#define DN_Str8FmtVArena(arena, fmt, args) DN_Str8FmtVArenaCallSite(arena, fmt, args, DN_CallSiteNow) +#define DN_Str8FmtVArenaNamed(arena, fmt, args, name_cstr) DN_Str8FmtVArenaCallSite(arena, fmt, args, DN_CallSiteNowNamed(name_cstr)) +DN_API DN_Str8 DN_Str8FmtAllocatorCallSite (DN_Allocator allocator, DN_CallSite call_site, DN_FMT_ATTRIB char const *fmt, ...); +#define DN_Str8FmtAllocator(allocator, fmt, ...) DN_Str8FmtAllocatorCallSite(allocator, DN_CallSiteNow, fmt, ## __VA_ARGS__) +#define DN_Str8FmtAllocatorNamed(allocator, name_cstr, fmt, ...) DN_Str8FmtAllocatorCallSite(allocator, DN_CallSiteNowNamed(name_cstr), fmt, ## __VA_ARGS__) +DN_API DN_Str8 DN_Str8FmtArenaCallSite (DN_Arena *arena, DN_CallSite call_site, DN_FMT_ATTRIB char const *fmt, ...); +#define DN_Str8FmtArena(arena, fmt, ...) DN_Str8FmtArenaCallSite(arena, DN_CallSiteNow, fmt, ## __VA_ARGS__) +#define DN_Str8FmtArenaNamed(arena, name_cstr, fmt, ...) DN_Str8FmtArenaCallSite(arena, DN_CallSiteNowNamed(name_cstr), fmt, ## __VA_ARGS__) +DN_API DN_Str8 DN_Str8FmtVPoolCallSite (DN_Pool *pool, DN_FMT_ATTRIB char const *fmt, va_list args, DN_CallSite call_site); +#define DN_Str8FmtVPool(pool, fmt, args) DN_Str8FmtVPoolCallSite(pool, fmt, args, DN_CallSiteNow) +#define DN_Str8FmtVPoolNamed(pool, fmt, args, name_cstr) DN_Str8FmtVPoolCallSite(pool, fmt, args, DN_CallSiteNowNamed(name_cstr)) +DN_API DN_Str8 DN_Str8FmtPoolCallSite (DN_Pool *pool, DN_CallSite call_site, DN_FMT_ATTRIB char const *fmt, ...); +#define DN_Str8FmtPool(pool, fmt, ...) DN_Str8FmtPoolCallSite(pool, DN_CallSiteNow, fmt, ## __VA_ARGS__) +#define DN_Str8FmtPoolNamed(pool, name_cstr, fmt, ...) DN_Str8FmtPoolCallSite(pool, DN_CallSiteNowNamed(name_cstr), fmt, ## __VA_ARGS__) -DN_API DN_Str8x16 DN_Str8x16FromFmt (DN_FMT_ATTRIB char const *fmt, ...); -DN_API DN_Str8x16 DN_Str8x16FromFmtV (DN_FMT_ATTRIB char const *fmt, va_list args); -DN_API DN_Str8x32 DN_Str8x32FromFmt (DN_FMT_ATTRIB char const *fmt, ...); -DN_API DN_Str8x32 DN_Str8x32FromFmtV (DN_FMT_ATTRIB char const *fmt, va_list args); -DN_API DN_Str8x64 DN_Str8x64FromFmt (DN_FMT_ATTRIB char const *fmt, ...); -DN_API DN_Str8x64 DN_Str8x64FromFmtV (DN_FMT_ATTRIB char const *fmt, va_list args); -DN_API DN_Str8x128 DN_Str8x128FromFmt (DN_FMT_ATTRIB char const *fmt, ...); -DN_API DN_Str8x256 DN_Str8x256FromFmtV (DN_FMT_ATTRIB char const *fmt, va_list args); -DN_API DN_Str8x256 DN_Str8x256FromFmt (DN_FMT_ATTRIB char const *fmt, ...); -DN_API DN_Str8x256 DN_Str8x256FromFmtV (DN_FMT_ATTRIB char const *fmt, va_list args); -DN_API DN_Str8x512 DN_Str8x512FromFmt (DN_FMT_ATTRIB char const *fmt, ...); -DN_API DN_Str8x512 DN_Str8x512FromFmtV (DN_FMT_ATTRIB char const *fmt, va_list args); -DN_API DN_Str8x1024 DN_Str8x1024FromFmt (DN_FMT_ATTRIB char const *fmt, ...); -DN_API DN_Str8x1024 DN_Str8x1024FromFmtV (DN_FMT_ATTRIB char const *fmt, va_list args); -DN_API void DN_Str8x16AppendFmt (DN_Str8x16 *str, DN_FMT_ATTRIB char const *fmt, ...); -DN_API void DN_Str8x16AppendFmtV (DN_Str8x16 *str, DN_FMT_ATTRIB char const *fmt, va_list args); -DN_API void DN_Str8x32AppendFmt (DN_Str8x32 *str, DN_FMT_ATTRIB char const *fmt, ...); -DN_API void DN_Str8x32AppendFmtV (DN_Str8x32 *str, DN_FMT_ATTRIB char const *fmt, va_list args); -DN_API void DN_Str8x64AppendFmt (DN_Str8x64 *str, DN_FMT_ATTRIB char const *fmt, ...); -DN_API void DN_Str8x64AppendFmtV (DN_Str8x64 *str, DN_FMT_ATTRIB char const *fmt, va_list args); -DN_API void DN_Str8x128AppendFmt (DN_Str8x128 *str, DN_FMT_ATTRIB char const *fmt, ...); -DN_API void DN_Str8x128AppendFmtV (DN_Str8x128 *str, DN_FMT_ATTRIB char const *fmt, va_list args); -DN_API void DN_Str8x256AppendFmt (DN_Str8x256 *str, DN_FMT_ATTRIB char const *fmt, ...); -DN_API void DN_Str8x256AppendFmtV (DN_Str8x256 *str, DN_FMT_ATTRIB char const *fmt, va_list args); -DN_API void DN_Str8x512AppendFmt (DN_Str8x512 *str, DN_FMT_ATTRIB char const *fmt, ...); -DN_API void DN_Str8x512AppendFmtV (DN_Str8x512 *str, DN_FMT_ATTRIB char const *fmt, va_list args); -DN_API void DN_Str8x1024AppendFmt (DN_Str8x1024 *str, DN_FMT_ATTRIB char const *fmt, ...); -DN_API void DN_Str8x1024AppendFmtV (DN_Str8x1024 *str, DN_FMT_ATTRIB char const *fmt, va_list args); +DN_API DN_Str8x16 DN_Str8x16FromFmt (DN_FMT_ATTRIB char const *fmt, ...); +DN_API DN_Str8x16 DN_Str8x16FromFmtV (DN_FMT_ATTRIB char const *fmt, va_list args); +DN_API DN_Str8x32 DN_Str8x32FromFmt (DN_FMT_ATTRIB char const *fmt, ...); +DN_API DN_Str8x32 DN_Str8x32FromFmtV (DN_FMT_ATTRIB char const *fmt, va_list args); +DN_API DN_Str8x64 DN_Str8x64FromFmt (DN_FMT_ATTRIB char const *fmt, ...); +DN_API DN_Str8x64 DN_Str8x64FromFmtV (DN_FMT_ATTRIB char const *fmt, va_list args); +DN_API DN_Str8x128 DN_Str8x128FromFmt (DN_FMT_ATTRIB char const *fmt, ...); +DN_API DN_Str8x256 DN_Str8x256FromFmtV (DN_FMT_ATTRIB char const *fmt, va_list args); +DN_API DN_Str8x256 DN_Str8x256FromFmt (DN_FMT_ATTRIB char const *fmt, ...); +DN_API DN_Str8x256 DN_Str8x256FromFmtV (DN_FMT_ATTRIB char const *fmt, va_list args); +DN_API DN_Str8x512 DN_Str8x512FromFmt (DN_FMT_ATTRIB char const *fmt, ...); +DN_API DN_Str8x512 DN_Str8x512FromFmtV (DN_FMT_ATTRIB char const *fmt, va_list args); +DN_API DN_Str8x1024 DN_Str8x1024FromFmt (DN_FMT_ATTRIB char const *fmt, ...); +DN_API DN_Str8x1024 DN_Str8x1024FromFmtV (DN_FMT_ATTRIB char const *fmt, va_list args); +DN_API void DN_Str8x16AppendFmt (DN_Str8x16 *str, DN_FMT_ATTRIB char const *fmt, ...); +DN_API void DN_Str8x16AppendFmtV (DN_Str8x16 *str, DN_FMT_ATTRIB char const *fmt, va_list args); +DN_API void DN_Str8x32AppendFmt (DN_Str8x32 *str, DN_FMT_ATTRIB char const *fmt, ...); +DN_API void DN_Str8x32AppendFmtV (DN_Str8x32 *str, DN_FMT_ATTRIB char const *fmt, va_list args); +DN_API void DN_Str8x64AppendFmt (DN_Str8x64 *str, DN_FMT_ATTRIB char const *fmt, ...); +DN_API void DN_Str8x64AppendFmtV (DN_Str8x64 *str, DN_FMT_ATTRIB char const *fmt, va_list args); +DN_API void DN_Str8x128AppendFmt (DN_Str8x128 *str, DN_FMT_ATTRIB char const *fmt, ...); +DN_API void DN_Str8x128AppendFmtV (DN_Str8x128 *str, DN_FMT_ATTRIB char const *fmt, va_list args); +DN_API void DN_Str8x256AppendFmt (DN_Str8x256 *str, DN_FMT_ATTRIB char const *fmt, ...); +DN_API void DN_Str8x256AppendFmtV (DN_Str8x256 *str, DN_FMT_ATTRIB char const *fmt, va_list args); +DN_API void DN_Str8x512AppendFmt (DN_Str8x512 *str, DN_FMT_ATTRIB char const *fmt, ...); +DN_API void DN_Str8x512AppendFmtV (DN_Str8x512 *str, DN_FMT_ATTRIB char const *fmt, va_list args); +DN_API void DN_Str8x1024AppendFmt (DN_Str8x1024 *str, DN_FMT_ATTRIB char const *fmt, ...); +DN_API void DN_Str8x1024AppendFmtV (DN_Str8x1024 *str, DN_FMT_ATTRIB char const *fmt, va_list args); -DN_API DN_Str8x32 DN_Str8x32FromU64 (DN_U64 val, char seperator); -DN_API bool DN_Str8Is (DN_Str8 string, DN_Str8IsFlags flags); -DN_API char * DN_Str8End (DN_Str8 string); -DN_API DN_Str8 DN_Str8Subset (DN_Str8 string, DN_USize offset, DN_USize count); -DN_API DN_Str8 DN_Str8Advance (DN_Str8 string, DN_USize amount); -DN_API DN_Str8 DN_Str8NextLine (DN_Str8 string); -DN_API DN_Str8BSplitResult DN_Str8BSplitArray (DN_Str8 string, DN_Str8 const *find, DN_USize find_size); -DN_API DN_Str8BSplitResult DN_Str8BSplit (DN_Str8 string, DN_Str8 find); -DN_API DN_Str8BSplitResult DN_Str8BSplitLastArray (DN_Str8 string, DN_Str8 const *find, DN_USize find_size); -DN_API DN_Str8BSplitResult DN_Str8BSplitLast (DN_Str8 string, DN_Str8 find); -DN_API DN_USize DN_Str8Split (DN_Str8 string, DN_Str8 delimiter, DN_Str8 *splits, DN_USize splits_count, DN_Str8SplitFlags mode); -DN_API DN_Str8SplitResult DN_Str8SplitArena (DN_Str8 string, DN_Str8 delimiter, DN_Str8SplitFlags mode, DN_Arena *arena); -DN_API DN_Str8FindResult DN_Str8FindStr8Array (DN_Str8 string, DN_Str8 const *find, DN_USize find_size, DN_Str8EqCase eq_case); -DN_API DN_Str8FindResult DN_Str8FindStr8 (DN_Str8 string, DN_Str8 find, DN_Str8EqCase eq_case); -DN_API DN_Str8FindResult DN_Str8Find (DN_Str8 string, DN_Str8FindFlag flags); -DN_API DN_Str8 DN_Str8Segment (DN_Arena *arena, DN_Str8 src, DN_USize segment_size, char segment_char); -DN_API DN_Str8 DN_Str8ReverseSegment (DN_Arena *arena, DN_Str8 src, DN_USize segment_size, char segment_char); -DN_API bool DN_Str8Eq (DN_Str8 lhs, DN_Str8 rhs, DN_Str8EqCase eq_case); -DN_API bool DN_Str8EqSensitive (DN_Str8 lhs, DN_Str8 rhs); -DN_API bool DN_Str8EqInsensitive (DN_Str8 lhs, DN_Str8 rhs); -DN_API bool DN_Str8StartsWith (DN_Str8 string, DN_Str8 prefix, DN_Str8EqCase eq_case); -DN_API bool DN_Str8StartsWithSensitive (DN_Str8 string, DN_Str8 prefix); -DN_API bool DN_Str8StartsWithInsensitive (DN_Str8 string, DN_Str8 prefix); -DN_API bool DN_Str8EndsWith (DN_Str8 string, DN_Str8 prefix, DN_Str8EqCase eq_case); -DN_API bool DN_Str8EndsWithSensitive (DN_Str8 string, DN_Str8 prefix); -DN_API bool DN_Str8EndsWithInsensitive (DN_Str8 string, DN_Str8 prefix); -DN_API bool DN_Str8HasChar (DN_Str8 string, char ch); +DN_API DN_Str8x32 DN_Str8x32FromU64 (DN_U64 val, char seperator); +DN_API DN_Str8IsResult DN_Str8Is (DN_Str8 string, DN_Str8IsFlags flags); +DN_API char * DN_Str8End (DN_Str8 string); +DN_API DN_Str8 DN_Str8Subset (DN_Str8 string, DN_USize offset, DN_USize count); +DN_API DN_Str8 DN_Str8Advance (DN_Str8 string, DN_USize amount); +DN_API DN_Str8 DN_Str8NextLine (DN_Str8 string); +DN_API DN_Str8BSplitResult DN_Str8BSplitArray (DN_Str8 string, DN_Str8 const *find, DN_USize find_size); +DN_API DN_Str8BSplitResult DN_Str8BSplit (DN_Str8 string, DN_Str8 find); +DN_API DN_Str8BSplitResult DN_Str8BSplitLastArray (DN_Str8 string, DN_Str8 const *find, DN_USize find_size); +DN_API DN_Str8BSplitResult DN_Str8BSplitLast (DN_Str8 string, DN_Str8 find); +DN_API DN_USize DN_Str8Split (DN_Str8 string, DN_Str8 delimiter, DN_Str8 *splits, DN_USize splits_count, DN_Str8SplitFlags mode); +DN_API DN_Str8SplitResult DN_Str8SplitArena (DN_Str8 string, DN_Str8 delimiter, DN_Str8SplitFlags mode, DN_Arena *arena); +DN_API DN_Str8FindResult DN_Str8FindStr8Array (DN_Str8 string, DN_Str8 const *find, DN_USize find_size, DN_Str8EqCase eq_case); +DN_API DN_Str8FindResult DN_Str8FindStr8 (DN_Str8 string, DN_Str8 find, DN_Str8EqCase eq_case); +DN_API DN_Str8FindResult DN_Str8Find (DN_Str8 string, DN_Str8FindFlag flags); +DN_API DN_Str8 DN_Str8Segment (DN_Arena *arena, DN_Str8 src, DN_USize segment_size, char segment_char); +DN_API DN_Str8 DN_Str8ReverseSegment (DN_Arena *arena, DN_Str8 src, DN_USize segment_size, char segment_char); +DN_API bool DN_Str8Eq (DN_Str8 lhs, DN_Str8 rhs, DN_Str8EqCase eq_case); +DN_API bool DN_Str8EqSensitive (DN_Str8 lhs, DN_Str8 rhs); +DN_API bool DN_Str8EqInsensitive (DN_Str8 lhs, DN_Str8 rhs); +DN_API bool DN_Str8StartsWith (DN_Str8 string, DN_Str8 prefix, DN_Str8EqCase eq_case); +DN_API bool DN_Str8StartsWithSensitive (DN_Str8 string, DN_Str8 prefix); +DN_API bool DN_Str8StartsWithInsensitive (DN_Str8 string, DN_Str8 prefix); +DN_API bool DN_Str8EndsWith (DN_Str8 string, DN_Str8 prefix, DN_Str8EqCase eq_case); +DN_API bool DN_Str8EndsWithSensitive (DN_Str8 string, DN_Str8 prefix); +DN_API bool DN_Str8EndsWithInsensitive (DN_Str8 string, DN_Str8 prefix); +DN_API bool DN_Str8HasChar (DN_Str8 string, char ch); -DN_API DN_Str8 DN_Str8TrimPrefix (DN_Str8 string, DN_Str8 prefix, DN_Str8EqCase eq_case); -DN_API DN_Str8 DN_Str8TrimPrefixSensitive (DN_Str8 string, DN_Str8 prefix); -DN_API DN_Str8 DN_Str8TrimPrefixInsensitive (DN_Str8 string, DN_Str8 prefix); -DN_API DN_Str8 DN_Str8TrimHexPrefix (DN_Str8 string); -DN_API DN_Str8 DN_Str8TrimSuffix (DN_Str8 string, DN_Str8 suffix, DN_Str8EqCase eq_case); -DN_API DN_Str8 DN_Str8TrimSuffixSensitive (DN_Str8 string, DN_Str8 suffix); -DN_API DN_Str8 DN_Str8TrimSuffixInsensitive (DN_Str8 string, DN_Str8 suffix); -DN_API DN_Str8 DN_Str8TrimAround (DN_Str8 string, DN_Str8 trim_string, DN_Str8EqCase eq_case); -DN_API DN_Str8 DN_Str8TrimAroundSensitive (DN_Str8 string, DN_Str8 trim_string); -DN_API DN_Str8 DN_Str8TrimAroundInsensitive (DN_Str8 string, DN_Str8 trim_string); -DN_API DN_Str8 DN_Str8TrimHeadWhitespace (DN_Str8 string); -DN_API DN_Str8 DN_Str8TrimTailWhitespace (DN_Str8 string); -DN_API DN_Str8 DN_Str8TrimWhitespaceAround (DN_Str8 string); -DN_API DN_Str8 DN_Str8TrimByteOrderMark (DN_Str8 string); +DN_API DN_Str8 DN_Str8TrimPrefix (DN_Str8 string, DN_Str8 prefix, DN_Str8EqCase eq_case); +DN_API DN_Str8 DN_Str8TrimPrefixSensitive (DN_Str8 string, DN_Str8 prefix); +DN_API DN_Str8 DN_Str8TrimPrefixInsensitive (DN_Str8 string, DN_Str8 prefix); +DN_API DN_Str8 DN_Str8TrimHexPrefix (DN_Str8 string); +DN_API DN_Str8 DN_Str8TrimSuffix (DN_Str8 string, DN_Str8 suffix, DN_Str8EqCase eq_case); +DN_API DN_Str8 DN_Str8TrimSuffixSensitive (DN_Str8 string, DN_Str8 suffix); +DN_API DN_Str8 DN_Str8TrimSuffixInsensitive (DN_Str8 string, DN_Str8 suffix); +DN_API DN_Str8 DN_Str8TrimAround (DN_Str8 string, DN_Str8 trim_string, DN_Str8EqCase eq_case); +DN_API DN_Str8 DN_Str8TrimAroundSensitive (DN_Str8 string, DN_Str8 trim_string); +DN_API DN_Str8 DN_Str8TrimAroundInsensitive (DN_Str8 string, DN_Str8 trim_string); +DN_API DN_Str8 DN_Str8TrimHeadWhitespace (DN_Str8 string); +DN_API DN_Str8 DN_Str8TrimTailWhitespace (DN_Str8 string); +DN_API DN_Str8 DN_Str8TrimWhitespaceAround (DN_Str8 string); +DN_API DN_Str8 DN_Str8TrimByteOrderMark (DN_Str8 string); -DN_API DN_Str8 DN_Str8FileNameFromPath (DN_Str8 path); -DN_API DN_Str8 DN_Str8FileNameNoExtension (DN_Str8 path); -DN_API DN_Str8 DN_Str8FilePathNoExtension (DN_Str8 path); -DN_API DN_Str8 DN_Str8FileExtension (DN_Str8 path); -DN_API DN_Str8 DN_Str8FileDirectoryFromPath (DN_Str8 path); -DN_API DN_Str8 DN_Str8AppendF (DN_Arena *arena, DN_Str8 string, char const *fmt, ...); -DN_API DN_Str8 DN_Str8AppendFV (DN_Arena *arena, DN_Str8 string, char const *fmt, va_list args); -DN_API DN_Str8 DN_Str8FillF (DN_Arena *arena, DN_USize count, char const *fmt, ...); -DN_API DN_Str8 DN_Str8FillFV (DN_Arena *arena, DN_USize count, char const *fmt, va_list args); -DN_API void DN_Str8Remove (DN_Str8 *string, DN_USize offset, DN_USize count); -DN_API DN_Str8 DN_Str8TruncateArena (DN_Str8 string, DN_USize max_count, DN_Str8 truncator, DN_Arena *arena); -DN_API DN_Str8TruncResult DN_Str8TruncMiddlePtr (DN_Str8 str8, DN_USize side_size, DN_Str8 truncator, char *dest, DN_USize dest_max); -DN_API DN_Str8TruncResult DN_Str8TruncMiddle (DN_Str8 str8, DN_USize side_size, DN_Str8 truncator, DN_Arena *arena); -DN_API DN_Str8 DN_Str8Lower (DN_Str8 string, DN_Arena *arena); -DN_API DN_Str8 DN_Str8Upper (DN_Str8 string, DN_Arena *arena); -DN_API DN_Str8 DN_Str8Replace (DN_Str8 string, DN_Str8 find, DN_Str8 replace, DN_USize start_index, DN_Arena *arena, DN_Str8EqCase eq_case); -DN_API DN_Str8 DN_Str8ReplaceSensitive (DN_Str8 string, DN_Str8 find, DN_Str8 replace, DN_USize start_index, DN_Arena *arena); -DN_API DN_Str8 DN_Str8ReplaceInsensitive (DN_Str8 string, DN_Str8 find, DN_Str8 replace, DN_USize start_index, DN_Arena *arena); -DN_API DN_Str8 DN_Str8PadNewLinesAllocator (DN_Str8 string, DN_Str8 pad_string, DN_Allocator allocator); -DN_API DN_Str8 DN_Str8PadNewLinesArena (DN_Str8 string, DN_Str8 pad_string, DN_Arena *arena); -DN_API DN_Str8 DN_Str8LineBreakAllocator (DN_Str8 src, DN_USize desired_width, DN_Str8 delimiter, DN_Str8LineBreakMode mode, DN_Allocator allocator); -DN_API DN_Str8 DN_Str8LineBreakArena (DN_Str8 src, DN_USize desired_width, DN_Str8 delimiter, DN_Str8LineBreakMode mode, DN_Arena *arena); -DN_API DN_Str8 DN_Str8Table (DN_Str8 const* rows, DN_USize num_rows, DN_USize num_cols, DN_Str8TableFlags flags, DN_Arena *arena); +DN_API DN_Str8 DN_Str8FileNameFromPath (DN_Str8 path); +DN_API DN_Str8 DN_Str8FileNameNoExtension (DN_Str8 path); +DN_API DN_Str8 DN_Str8FilePathNoExtension (DN_Str8 path); +DN_API DN_Str8 DN_Str8FileExtension (DN_Str8 path); +DN_API DN_Str8 DN_Str8FileDirectoryFromPath (DN_Str8 path); +DN_API DN_Str8 DN_Str8AppendF (DN_Arena *arena, DN_Str8 string, char const *fmt, ...); +DN_API DN_Str8 DN_Str8AppendFV (DN_Arena *arena, DN_Str8 string, char const *fmt, va_list args); +DN_API DN_Str8 DN_Str8FillF (DN_Arena *arena, DN_USize count, char const *fmt, ...); +DN_API DN_Str8 DN_Str8FillFV (DN_Arena *arena, DN_USize count, char const *fmt, va_list args); +DN_API void DN_Str8Remove (DN_Str8 *string, DN_USize offset, DN_USize count); +DN_API DN_Str8 DN_Str8TruncateArena (DN_Str8 string, DN_USize max_count, DN_Str8 truncator, DN_Arena *arena); +DN_API DN_Str8TruncResult DN_Str8TruncMiddlePtr (DN_Str8 str8, DN_USize side_size, DN_Str8 truncator, char *dest, DN_USize dest_max); +DN_API DN_Str8TruncResult DN_Str8TruncMiddle (DN_Str8 str8, DN_USize side_size, DN_Str8 truncator, DN_Arena *arena); +DN_API DN_Str8 DN_Str8Lower (DN_Str8 string, DN_Arena *arena); +DN_API DN_Str8 DN_Str8Upper (DN_Str8 string, DN_Arena *arena); +DN_API DN_Str8 DN_Str8Replace (DN_Str8 string, DN_Str8 find, DN_Str8 replace, DN_USize start_index, DN_Arena *arena, DN_Str8EqCase eq_case); +DN_API DN_Str8 DN_Str8ReplaceSensitive (DN_Str8 string, DN_Str8 find, DN_Str8 replace, DN_USize start_index, DN_Arena *arena); +DN_API DN_Str8 DN_Str8ReplaceInsensitive (DN_Str8 string, DN_Str8 find, DN_Str8 replace, DN_USize start_index, DN_Arena *arena); +DN_API DN_Str8 DN_Str8PadNewLinesAllocator (DN_Str8 string, DN_Str8 pad_string, DN_Allocator allocator); +DN_API DN_Str8 DN_Str8PadNewLinesArena (DN_Str8 string, DN_Str8 pad_string, DN_Arena *arena); +DN_API DN_Str8 DN_Str8LineBreakAllocator (DN_Str8 src, DN_USize desired_width, DN_Str8 delimiter, DN_Str8LineBreakMode mode, DN_Allocator allocator); +DN_API DN_Str8 DN_Str8LineBreakArena (DN_Str8 src, DN_USize desired_width, DN_Str8 delimiter, DN_Str8LineBreakMode mode, DN_Arena *arena); +DN_API DN_Str8 DN_Str8Table (DN_Str8 const* rows, DN_USize num_rows, DN_USize num_cols, DN_Str8TableFlags flags, DN_Arena *arena); #if DN_WITH_STR8_AVX512F -DN_API DN_Str8FindResult DN_Str8FindStr8AVX512F (DN_Str8 string, DN_Str8 find); -DN_API DN_Str8FindResult DN_Str8FindLastStr8AVX512F (DN_Str8 string, DN_Str8 find); -DN_API DN_Str8BSplitResult DN_Str8BSplitAVX512F (DN_Str8 string, DN_Str8 find); -DN_API DN_Str8BSplitResult DN_Str8BSplitLastAVX512F (DN_Str8 string, DN_Str8 find); -DN_API DN_USize DN_Str8SplitAVX512F (DN_Str8 string, DN_Str8 delimiter, DN_Str8 *splits, DN_USize splits_count, DN_Str8SplitFlags flags); -DN_API DN_Str8Slice DN_Str8SplitAllocAVX512F (DN_Arena *arena, DN_Str8 string, DN_Str8 delimiter, DN_Str8SplitFlags flags); +DN_API DN_Str8FindResult DN_Str8FindStr8AVX512F (DN_Str8 string, DN_Str8 find); +DN_API DN_Str8FindResult DN_Str8FindLastStr8AVX512F (DN_Str8 string, DN_Str8 find); +DN_API DN_Str8BSplitResult DN_Str8BSplitAVX512F (DN_Str8 string, DN_Str8 find); +DN_API DN_Str8BSplitResult DN_Str8BSplitLastAVX512F (DN_Str8 string, DN_Str8 find); +DN_API DN_USize DN_Str8SplitAVX512F (DN_Str8 string, DN_Str8 delimiter, DN_Str8 *splits, DN_USize splits_count, DN_Str8SplitFlags flags); +DN_API DN_Str8Slice DN_Str8SplitAllocAVX512F (DN_Arena *arena, DN_Str8 string, DN_Str8 delimiter, DN_Str8SplitFlags flags); #endif -DN_API DN_Str8 DN_Str8SliceRender (DN_Str8Slice array, DN_Str8 seperator, DN_Arena *arena); -DN_API DN_Str8 DN_Str8RenderSpaceSep (DN_Str8Slice array, DN_Arena *arena); -DN_API int DN_Str8CompareNatural (DN_Str8 lhs, DN_Str8 rhs, DN_Str8EqCase eq_case); -DN_API int DN_Str8CompareLexicographic (DN_Str8 lhs, DN_Str8 rhs, DN_Str8EqCase eq_case); +DN_API DN_Str8 DN_Str8SliceRender (DN_Str8Slice array, DN_Str8 seperator, DN_Arena *arena); +DN_API DN_Str8 DN_Str8RenderSpaceSep (DN_Str8Slice array, DN_Arena *arena); +DN_API int DN_Str8CompareNatural (DN_Str8 lhs, DN_Str8 rhs, DN_Str8EqCase eq_case); +DN_API int DN_Str8CompareLexicographic (DN_Str8 lhs, DN_Str8 rhs, DN_Str8EqCase eq_case); -DN_API bool DN_Str16Eq (DN_Str16 lhs, DN_Str16 rhs); -DN_API DN_Str16 DN_Str16SliceRender (DN_Str16Slice array, DN_Str16 seperator, DN_Arena *arena); -DN_API DN_Str16 DN_Str16RenderSpaceSep (DN_Str16Slice array, DN_Arena *arena); +DN_API bool DN_Str16Eq (DN_Str16 lhs, DN_Str16 rhs); +DN_API DN_Str16 DN_Str16SliceRender (DN_Str16Slice array, DN_Str16 seperator, DN_Arena *arena); +DN_API DN_Str16 DN_Str16RenderSpaceSep (DN_Str16Slice array, DN_Arena *arena); -DN_API DN_Str8Builder DN_Str8BuilderFromArena (DN_Arena *arena); -DN_API DN_Str8Builder DN_Str8BuilderFromStr8PtrRef (DN_Arena *arena, DN_Str8 const *strings, DN_USize count); -DN_API DN_Str8Builder DN_Str8BuilderFromStr8PtrCopy (DN_Arena *arena, DN_Str8 const *strings, DN_USize count); -DN_API DN_Str8Builder DN_Str8BuilderFromBuilder (DN_Arena *arena, DN_Str8Builder const *builder); -DN_API bool DN_Str8BuilderAddArrayRef (DN_Str8Builder *builder, DN_Str8 const *strings, DN_USize count, DN_AddType add); -DN_API bool DN_Str8BuilderAddArrayCopy (DN_Str8Builder *builder, DN_Str8 const *strings, DN_USize count, DN_AddType add); -DN_API bool DN_Str8BuilderAddFV (DN_Str8Builder *builder, DN_AddType add, DN_FMT_ATTRIB char const *fmt, va_list args); -#define DN_Str8BuilderAppendArrayRef(builder, strings, size) DN_Str8BuilderAddArrayRef(builder, strings, size, DN_AddType_Append) -#define DN_Str8BuilderAppendArrayCopy(builder, strings, size) DN_Str8BuilderAddArrayCopy(builder, strings, size, DN_AddType_Append) -#define DN_Str8BuilderAppendSliceRef(builder, slice) DN_Str8BuilderAddArrayRef(builder, slice.data, slice.count, DN_AddType_Append) -#define DN_Str8BuilderAppendSliceCopy(builder, slice) DN_Str8BuilderAddArrayCopy(builder, slice.data, slice.count, DN_AddType_Append) -DN_API bool DN_Str8BuilderAppendRef (DN_Str8Builder *builder, DN_Str8 string); -DN_API bool DN_Str8BuilderAppendCopy (DN_Str8Builder *builder, DN_Str8 string); -#define DN_Str8BuilderAppendFV(builder, fmt, args) DN_Str8BuilderAddFV(builder, DN_AddType_Append, fmt, args) -DN_API bool DN_Str8BuilderAppendF (DN_Str8Builder *builder, DN_FMT_ATTRIB char const *fmt, ...); -DN_API bool DN_Str8BuilderAppendBytesRef (DN_Str8Builder *builder, void const *ptr, DN_USize count); -DN_API bool DN_Str8BuilderAppendBytesCopy (DN_Str8Builder *builder, void const *ptr, DN_USize count); -DN_API bool DN_Str8BuilderAppendBuilderRef (DN_Str8Builder *dest, DN_Str8Builder const *src); -DN_API bool DN_Str8BuilderAppendBuilderCopy (DN_Str8Builder *dest, DN_Str8Builder const *src); -#define DN_Str8BuilderPrependArrayRef(builder, strings, size) DN_Str8BuilderAddArrayRef(builder, strings, size, DN_AddType_Prepend) -#define DN_Str8BuilderPrependArrayCopy(builder, strings, size) DN_Str8BuilderAddArrayCopy(builder, strings, size, DN_AddType_Prepend) -#define DN_Str8BuilderPrependSliceRef(builder, slice) DN_Str8BuilderAddArrayRef(builder, slice.data, slice.count, DN_AddType_Prepend) -#define DN_Str8BuilderPrependSliceCopy(builder, slice) DN_Str8BuilderAddArrayCopy(builder, slice.data, slice.count, DN_AddType_Prepend) -DN_API bool DN_Str8BuilderPrependRef (DN_Str8Builder *builder, DN_Str8 string); -DN_API bool DN_Str8BuilderPrependCopy (DN_Str8Builder *builder, DN_Str8 string); -#define DN_Str8BuilderPrependFV(builder, fmt, args) DN_Str8BuilderAddFV(builder, DN_AddType_Prepend, fmt, args) -DN_API bool DN_Str8BuilderPrependF (DN_Str8Builder *builder, DN_FMT_ATTRIB char const *fmt, ...); -DN_API bool DN_Str8BuilderErase (DN_Str8Builder *builder, DN_Str8 string); -DN_API DN_Str8 DN_Str8FromStr8BuilderAllocator (DN_Str8Builder const *builder, DN_Allocator allocator); -DN_API DN_Str8 DN_Str8FromStr8BuilderArena (DN_Str8Builder const *builder, DN_Arena *arena); -DN_API DN_Str8 DN_Str8FromStr8BuilderDelimitAllocator (DN_Str8Builder const *builder, DN_Str8 delimiter, DN_Allocator allocator); -DN_API DN_Str8 DN_Str8FromStr8BuilderDelimitArena (DN_Str8Builder const *builder, DN_Str8 delimiter, DN_Arena *arena); +DN_API DN_Str8Builder DN_Str8BuilderFromArena (DN_Arena *arena); +DN_API DN_Str8Builder DN_Str8BuilderFromStr8PtrRef (DN_Arena *arena, DN_Str8 const *strings, DN_USize count); +DN_API DN_Str8Builder DN_Str8BuilderFromStr8PtrCopy (DN_Arena *arena, DN_Str8 const *strings, DN_USize count); +DN_API DN_Str8Builder DN_Str8BuilderFromBuilder (DN_Arena *arena, DN_Str8Builder const *builder); +DN_API bool DN_Str8BuilderAddArrayRef (DN_Str8Builder *builder, DN_Str8 const *strings, DN_USize count, DN_AddType add); +DN_API bool DN_Str8BuilderAddArrayCopy (DN_Str8Builder *builder, DN_Str8 const *strings, DN_USize count, DN_AddType add); +DN_API bool DN_Str8BuilderAddFV (DN_Str8Builder *builder, DN_AddType add, DN_FMT_ATTRIB char const *fmt, va_list args); +#define DN_Str8BuilderAppendArrayRef(builder, strings, size) DN_Str8BuilderAddArrayRef(builder, strings, size, DN_AddType_Append) +#define DN_Str8BuilderAppendArrayCopy(builder, strings, size) DN_Str8BuilderAddArrayCopy(builder, strings, size, DN_AddType_Append) +#define DN_Str8BuilderAppendSliceRef(builder, slice) DN_Str8BuilderAddArrayRef(builder, slice.data, slice.count, DN_AddType_Append) +#define DN_Str8BuilderAppendSliceCopy(builder, slice) DN_Str8BuilderAddArrayCopy(builder, slice.data, slice.count, DN_AddType_Append) +DN_API bool DN_Str8BuilderAppendRef (DN_Str8Builder *builder, DN_Str8 string); +DN_API bool DN_Str8BuilderAppendCopy (DN_Str8Builder *builder, DN_Str8 string); +#define DN_Str8BuilderAppendFV(builder, fmt, args) DN_Str8BuilderAddFV(builder, DN_AddType_Append, fmt, args) +DN_API bool DN_Str8BuilderAppendF (DN_Str8Builder *builder, DN_FMT_ATTRIB char const *fmt, ...); +DN_API bool DN_Str8BuilderAppendBytesRef (DN_Str8Builder *builder, void const *ptr, DN_USize count); +DN_API bool DN_Str8BuilderAppendBytesCopy (DN_Str8Builder *builder, void const *ptr, DN_USize count); +DN_API bool DN_Str8BuilderAppendBuilderRef (DN_Str8Builder *dest, DN_Str8Builder const *src); +DN_API bool DN_Str8BuilderAppendBuilderCopy (DN_Str8Builder *dest, DN_Str8Builder const *src); +#define DN_Str8BuilderPrependArrayRef(builder, strings, size) DN_Str8BuilderAddArrayRef(builder, strings, size, DN_AddType_Prepend) +#define DN_Str8BuilderPrependArrayCopy(builder, strings, size) DN_Str8BuilderAddArrayCopy(builder, strings, size, DN_AddType_Prepend) +#define DN_Str8BuilderPrependSliceRef(builder, slice) DN_Str8BuilderAddArrayRef(builder, slice.data, slice.count, DN_AddType_Prepend) +#define DN_Str8BuilderPrependSliceCopy(builder, slice) DN_Str8BuilderAddArrayCopy(builder, slice.data, slice.count, DN_AddType_Prepend) +DN_API bool DN_Str8BuilderPrependRef (DN_Str8Builder *builder, DN_Str8 string); +DN_API bool DN_Str8BuilderPrependCopy (DN_Str8Builder *builder, DN_Str8 string); +#define DN_Str8BuilderPrependFV(builder, fmt, args) DN_Str8BuilderAddFV(builder, DN_AddType_Prepend, fmt, args) +DN_API bool DN_Str8BuilderPrependF (DN_Str8Builder *builder, DN_FMT_ATTRIB char const *fmt, ...); +DN_API bool DN_Str8BuilderErase (DN_Str8Builder *builder, DN_Str8 string); +DN_API DN_Str8 DN_Str8FromStr8BuilderAllocator (DN_Str8Builder const *builder, DN_Allocator allocator); +DN_API DN_Str8 DN_Str8FromStr8BuilderArena (DN_Str8Builder const *builder, DN_Arena *arena); +DN_API DN_Str8 DN_Str8FromStr8BuilderDelimitAllocator (DN_Str8Builder const *builder, DN_Str8 delimiter, DN_Allocator allocator); +DN_API DN_Str8 DN_Str8FromStr8BuilderDelimitArena (DN_Str8Builder const *builder, DN_Str8 delimiter, DN_Arena *arena); -DN_API bool DN_PathAddRef (DN_Path *path, DN_Str8 add, DN_Arena *arena); -DN_API bool DN_PathAdd (DN_Path *path, DN_Str8 add, DN_Arena *arena); -DN_API bool DN_PathAddF (DN_Path *path, DN_FMT_ATTRIB char const *fmt, ...); -DN_API bool DN_PathPop (DN_Path *path); -DN_API DN_Str8 DN_Str8FromPath (DN_Path const *path, DN_Str8 path_seperator, DN_Allocator allocator); -DN_API DN_Str8 DN_Str8FmtPathVArena (DN_Str8 path_seperator, DN_Arena *arena, char const *fmt, va_list args); -DN_API DN_Str8 DN_Str8FmtPathArena (DN_Str8 path_seperator, DN_Arena *arena, DN_FMT_ATTRIB char const *fmt, ...); -DN_API DN_Str8 DN_Str8FmtPathVPool (DN_Str8 path_seperator, DN_Pool *pool, char const *fmt, va_list args); -DN_API DN_Str8 DN_Str8FmtPathPool (DN_Str8 path_seperator, DN_Pool *pool, DN_FMT_ATTRIB char const *fmt, ...); -DN_API DN_Str8 DN_Str8FmtOsPathArena (DN_Arena *arena, DN_FMT_ATTRIB char const *fmt, ...); -DN_API DN_Str8 DN_Str8FmtOsPathPool (DN_Pool *pool, DN_FMT_ATTRIB char const *fmt, ...); +DN_API bool DN_PathAddRef (DN_Path *path, DN_Str8 add, DN_Arena *arena); +DN_API bool DN_PathAdd (DN_Path *path, DN_Str8 add, DN_Arena *arena); +DN_API bool DN_PathAddF (DN_Path *path, DN_FMT_ATTRIB char const *fmt, ...); +DN_API bool DN_PathPop (DN_Path *path); +DN_API DN_Str8Path DN_Str8PathFromPath (DN_Path const *path, DN_Str8 path_seperator, DN_Allocator allocator); +DN_API DN_Str8Path DN_Str8PathFmtVArena (DN_Str8 path_seperator, DN_Arena *arena, char const *fmt, va_list args); +DN_API DN_Str8Path DN_Str8PathFmtArena (DN_Str8 path_seperator, DN_Arena *arena, DN_FMT_ATTRIB char const *fmt, ...); +DN_API DN_Str8Path DN_Str8PathFmtVPool (DN_Str8 path_seperator, DN_Pool *pool, char const *fmt, va_list args); +DN_API DN_Str8Path DN_Str8PathFmtPool (DN_Str8 path_seperator, DN_Pool *pool, DN_FMT_ATTRIB char const *fmt, ...); +DN_API DN_Str8Path DN_Str8PathFmtOsArena (DN_Arena *arena, DN_FMT_ATTRIB char const *fmt, ...); +DN_API DN_Str8Path DN_Str8PathFmtOsPool (DN_Pool *pool, DN_FMT_ATTRIB char const *fmt, ...); -DN_API DN_USize DN_Utf8FromUtf32 (DN_U8 utf8[4], DN_U32 codepoint); -DN_API bool DN_Utf32IsAlphabet (DN_U32 codepoint); -DN_API bool DN_Utf32IsDigit (DN_U32 codepoint); -DN_API bool DN_Utf32IsAlphaNum (DN_U32 codepoint); -DN_API bool DN_Utf32IsWhitespace (DN_U32 codepoint); -DN_API bool DN_Utf32IsHex (DN_U32 codepoint); -DN_API bool DN_Utf32IsWordCharacter (DN_U32 codepoint); -DN_API DN_U32 DN_Utf32ToLower (DN_U32 codepoint); -DN_API DN_U32 DN_Utf32ToUpper (DN_U32 codepoint); -DN_API DN_USize DN_Utf32FromUtf16 (DN_U16 utf16[2], DN_U32 codepoint); -DN_API DN_Utf32FromResult DN_Utf32FromUtf8Stream (DN_Str8 stream); -DN_API bool DN_Utf32FromUtf8Iterate (DN_Utf32FromUtf8Iterator *it, DN_Utf32IterateDir dir, DN_Str8 utf8); -DN_API DN_USize DN_Utf32CodepointCountFromUtf8 (DN_Str8 str, DN_CodepointCountFlags flags); +DN_API DN_USize DN_Utf8FromUtf32 (DN_U8 utf8[4], DN_U32 codepoint); +DN_API bool DN_Utf32IsAlphabet (DN_U32 codepoint); +DN_API bool DN_Utf32IsDigit (DN_U32 codepoint); +DN_API bool DN_Utf32IsAlphaNum (DN_U32 codepoint); +DN_API bool DN_Utf32IsWhitespace (DN_U32 codepoint); +DN_API bool DN_Utf32IsHex (DN_U32 codepoint); +DN_API bool DN_Utf32IsWordCharacter (DN_U32 codepoint); +DN_API DN_U32 DN_Utf32ToLower (DN_U32 codepoint); +DN_API DN_U32 DN_Utf32ToUpper (DN_U32 codepoint); +DN_API DN_USize DN_Utf32FromUtf16 (DN_U16 utf16[2], DN_U32 codepoint); +DN_API DN_Utf32FromResult DN_Utf32FromUtf8Stream (DN_Str8 stream); +DN_API bool DN_Utf32FromUtf8Iterate (DN_Utf32FromUtf8Iterator *it, DN_Utf32IterateDir dir, DN_Str8 utf8); +DN_API DN_USize DN_Utf32CodepointCountFromUtf8 (DN_Str8 str, DN_CodepointCountFlags flags); -DN_API DN_U8 DN_U8FromHexNibble (char hex); -DN_API DN_NibbleFromU8Result DN_NibbleFromU8 (DN_U8 u8); +DN_API DN_U8 DN_U8FromHexNibble (char hex); +DN_API DN_NibbleFromU8Result DN_NibbleFromU8 (DN_U8 u8); -DN_API DN_USize DN_PtrBytesFromStr8Hex (DN_Str8 hex, void *dest, DN_USize dest_count); -DN_API DN_USize DN_PtrBytesFromPtrHex (char const *hex, DN_USize hex_count, void *dest, DN_USize dest_count); -DN_API DN_Str8 DN_Str8BytesFromStr8HexArena (DN_Str8 hex, DN_Arena *arena); -DN_API DN_Str8 DN_Str8BytesFromPtrHexArena (char const *hex, DN_USize hex_count, DN_Arena *arena); -DN_API DN_Str8 DN_Str8BytesFromPtrHexPool (char const *hex, DN_USize hex_count, DN_Pool *pool); -DN_API DN_U8x16 DN_U8x16FromPtrHex32 (char const *hex, DN_USize hex_count); -DN_API DN_U8x32 DN_U8x32FromPtrHex64 (char const *hex, DN_USize hex_count); +DN_API DN_USize DN_PtrBytesFromStr8Hex (DN_Str8 hex, void *dest, DN_USize dest_count); +DN_API DN_USize DN_PtrBytesFromPtrHex (char const *hex, DN_USize hex_count, void *dest, DN_USize dest_count); +DN_API DN_Str8 DN_Str8BytesFromStr8HexArena (DN_Str8 hex, DN_Arena *arena); +DN_API DN_Str8 DN_Str8BytesFromPtrHexArena (char const *hex, DN_USize hex_count, DN_Arena *arena); +DN_API DN_Str8 DN_Str8BytesFromPtrHexPool (char const *hex, DN_USize hex_count, DN_Pool *pool); +DN_API DN_U8x16 DN_U8x16FromPtrHex32 (char const *hex, DN_USize hex_count); +DN_API DN_U8x32 DN_U8x32FromPtrHex64 (char const *hex, DN_USize hex_count); -DN_API DN_HexU64 DN_HexU64FromU64 (DN_U64 value, DN_HexFromU64Type type); -DN_API DN_USize DN_PtrHexFromPtrBytes (void const *bytes, DN_USize bytes_count, void *hex, DN_USize hex_count, DN_TrimLeadingZero trim_leading_z); -DN_API DN_USize DN_PtrHexFromStr8Bytes (DN_Str8 bytes, void *hex, DN_USize hex_count, DN_TrimLeadingZero trim_leading_z); -DN_API DN_Str8 DN_Str8HexFromPtrBytesArena (void const *bytes, DN_USize bytes_count, DN_Arena *arena, DN_TrimLeadingZero trim_leading_z); -DN_API DN_Str8 DN_Str8HexFromStr8BytesArena (DN_Str8 bytes, DN_Arena *arena, DN_TrimLeadingZero trim_leading_z); -DN_API DN_Hex32 DN_Hex32FromPtrBytes16 (void const *bytes, DN_USize bytes_count, DN_TrimLeadingZero trim_leading_z); -DN_API DN_Hex64 DN_Hex64FromPtrBytes32 (void const *bytes, DN_USize bytes_count, DN_TrimLeadingZero trim_leading_z); -DN_API DN_Hex64 DN_Hex64FromU8x32 (DN_U8x32 const *value, DN_TrimLeadingZero trim_leading_z); -DN_API DN_Hex128 DN_Hex128FromPtrBytes64 (void const *bytes, DN_USize bytes_count, DN_TrimLeadingZero trim_leading_z); +DN_API DN_HexU64 DN_HexU64FromU64 (DN_U64 value, DN_HexFromU64Type type); +DN_API DN_USize DN_PtrHexFromPtrBytes (void const *bytes, DN_USize bytes_count, void *hex, DN_USize hex_count, DN_TrimLeadingZero trim_leading_z); +DN_API DN_USize DN_PtrHexFromStr8Bytes (DN_Str8 bytes, void *hex, DN_USize hex_count, DN_TrimLeadingZero trim_leading_z); +DN_API DN_Str8 DN_Str8HexFromPtrBytesArena (void const *bytes, DN_USize bytes_count, DN_Arena *arena, DN_TrimLeadingZero trim_leading_z); +DN_API DN_Str8 DN_Str8HexFromStr8BytesArena (DN_Str8 bytes, DN_Arena *arena, DN_TrimLeadingZero trim_leading_z); +DN_API DN_Hex32 DN_Hex32FromPtrBytes16 (void const *bytes, DN_USize bytes_count, DN_TrimLeadingZero trim_leading_z); +DN_API DN_Hex64 DN_Hex64FromPtrBytes32 (void const *bytes, DN_USize bytes_count, DN_TrimLeadingZero trim_leading_z); +DN_API DN_Hex64 DN_Hex64FromU8x32 (DN_U8x32 const *value, DN_TrimLeadingZero trim_leading_z); +DN_API DN_Hex128 DN_Hex128FromPtrBytes64 (void const *bytes, DN_USize bytes_count, DN_TrimLeadingZero trim_leading_z); -DN_API DN_Str8x128 DN_AgeStr8FromMsU64 (DN_U64 duration_ms, DN_AgeUnit units); -DN_API DN_Str8x128 DN_AgeStr8FromSecU64 (DN_U64 duration_ms, DN_AgeUnit units); -DN_API DN_Str8x128 DN_AgeStr8FromSecF64 (DN_F64 sec, DN_AgeUnit units); +DN_API DN_Str8x128 DN_AgeStr8FromMsU64 (DN_U64 duration_ms, DN_AgeUnit units); +DN_API DN_Str8x128 DN_AgeStr8FromSecU64 (DN_U64 duration_ms, DN_AgeUnit units); +DN_API DN_Str8x128 DN_AgeStr8FromSecF64 (DN_F64 sec, DN_AgeUnit units); -DN_API int DN_IsLeapYear (int year); -DN_API bool DN_DateIsValid (DN_Date date); -DN_API DN_Date DN_DateFromUnixTimeMs (DN_USize unix_ts_ms); -DN_API DN_U64 DN_UnixTimeMsFromDate (DN_Date date); +DN_API int DN_IsLeapYear (int year); +DN_API bool DN_DateIsValid (DN_Date date); +DN_API DN_Date DN_DateFromUnixTimeMs (DN_USize unix_ts_ms); +DN_API DN_U64 DN_UnixTimeMsFromDate (DN_Date date); -DN_API DN_Str8 DN_Str8FromByteType (DN_ByteType type); -DN_API DN_ByteCount DN_ByteCountFromU64 (DN_U64 byte_count, DN_ByteType type); -DN_API DN_Str8x32 DN_Str8x32FromByteCountU64 (DN_U64 byte_count, DN_ByteType type); -#define DN_Str8x32FromByteCountU64Auto(bytes) DN_Str8x32FromByteCountU64(bytes, DN_ByteType_Auto) +DN_API DN_Str8 DN_Str8FromByteType (DN_ByteType type); +DN_API DN_ByteCount DN_ByteCountFromU64 (DN_U64 byte_count, DN_ByteType type); +DN_API DN_Str8x32 DN_Str8x32FromByteCountU64 (DN_U64 byte_count, DN_ByteType type); +#define DN_Str8x32FromByteCountU64Auto(bytes) DN_Str8x32FromByteCountU64(bytes, DN_ByteType_Auto) // NOTE: Profiler // Overview @@ -5409,8 +5630,8 @@ DN_API DN_Str8x32 DN_Str8x32FromByteCountU64 // API // DN_ProfilerInit // You can set `tsc_now` to NULL to use the default timer mechanic which relies on -// DN_CPUGetTsc() which essentially uses __rdtsc. `tsc_frequency` must however always be -// provided, for, DN_CPUGetTsc() you can use `DN_OS_EstimateTscPerSecond()` to calculate the +// DN_CpuTscNow() which essentially uses __rdtsc. `tsc_frequency` must however always be +// provided, for, DN_CpuTscNow() you can use `DN_OS_EstimateTscPerSecond()` to calculate the // frequency of `__rdtsc`. // DN_ProfilerNewFrame // Always call `DN_ProfilerNewFrame` at-least once using the `Zone` family of functions as it @@ -5455,12 +5676,7 @@ DN_API DN_V2USize DN_Profiler2MarkerOffsetFromFrame DN_API DN_Profiler2Marker* DN_Profiler2MarkerFromFrameIndex (DN_Profiler2 *profiler, DN_Profiler2Frame *frame, DN_U32 index); DN_API void DN_QSort_ (void *array, DN_USize array_size, DN_USize elem_size, void *user_context, DN_QSortCompareFunc *compare); -#if defined(__cplusplus) -template void DN_QSortT (T *array, DN_USize array_size, void *user_context, DN_QSortCompareFunc *compare); -#define DN_QSort(array, array_size, user_context, compare) DN_QSortT(array, array_size, user_context, compare) -#else #define DN_QSort(array, array_size, user_context, compare) DN_QSort_(array, array_size, sizeof(*array), user_context, compare) -#endif DN_API bool DN_QSortCompareStr8NaturalAsc (void const* lhs, void const *rhs, void *user_context); DN_API bool DN_QSortCompareStr8NaturalDesc (void const* lhs, void const *rhs, void *user_context); @@ -5542,32 +5758,30 @@ DN_API DN_LogTypeParam DN_LogTypeParamFromType // NOTE: OS primitives that the OS layer can provide for the base layer but is optional. -#if defined(DN_FREESTANDING) -#define DN_StackTraceFromArena(...) {} -#define DN_StackTraceFromAllocator(...) {} -#define DN_StackTraceIterate(...) false -#define DN_Str8FromStackTraceAllocator(...) DN_Str8Lit("N/A") -#define DN_Str8FromStackTraceArena(...) DN_Str8Lit("N/A") -#define DN_Str8FromStackTraceNowAllocator(...) DN_Str8Lit("N/A") -#define DN_Str8FromStackTraceNowArena(...) DN_Str8Lit("N/A") -#define DN_Str8FromStackTraceNowHeap(...) DN_Str8Lit("N/A") -#define DN_StackTraceGetFrames(...) -#define DN_StackTraceRawFrameToFrame(...) -#define DN_StackTracePrint(...) -#define DN_StackTraceReloadSymbols(...) +#if DN_WITH_OS +DN_API DN_StackTrace DN_StackTraceFromAllocator (DN_Allocator allocator, DN_U16 limit); +DN_API DN_StackTrace DN_StackTraceFromArena (DN_Arena *arena, DN_U16 limit); +DN_API bool DN_StackTraceIterate (DN_StackTraceIterator *it, DN_StackTrace const *walk); +DN_API DN_Str8 DN_Str8FromStackTraceAllocator (DN_Allocator allocator, DN_StackTrace const *walk, DN_U16 skip); +DN_API DN_Str8 DN_Str8FromStackTraceArena (DN_Arena *arena, DN_StackTrace const *walk, DN_U16 skip); +DN_API DN_Str8 DN_Str8FromStackTraceNowAllocator (DN_Arena *arena, DN_U16 limit, DN_U16 skip); +DN_API DN_Str8 DN_Str8FromStackTraceNowArena (DN_Arena *arena, DN_U16 limit, DN_U16 skip); +DN_API DN_StackTraceFrameSlice DN_StackTraceGetFrames (DN_Arena *arena, DN_U16 limit); +DN_API DN_StackTraceFrame DN_StackTraceFrameFromRawFrame (DN_Arena *arena, DN_StackTraceRawFrame raw_frame); +DN_API void DN_StackTracePrint (DN_U16 limit); +DN_API void DN_StackTraceReloadSymbols (); #else -DN_API DN_StackTrace DN_StackTraceFromArena (DN_Arena *arena, DN_U16 limit); -DN_API DN_StackTrace DN_StackTraceFromAllocator (DN_Allocator allocator, DN_U16 limit); -DN_API bool DN_StackTraceIterate (DN_StackTraceIterator *it, DN_StackTrace const *walk); -DN_API DN_Str8 DN_Str8FromStackTraceAllocator (DN_Allocator allocator, DN_StackTrace const *walk, DN_U16 skip); -DN_API DN_Str8 DN_Str8FromStackTraceArena (DN_Arena *arena, DN_StackTrace const *walk, DN_U16 skip); -DN_API DN_Str8 DN_Str8FromStackTraceNowAllocator (DN_Arena *arena, DN_U16 limit, DN_U16 skip); -DN_API DN_Str8 DN_Str8FromStackTraceNowArena (DN_Arena *arena, DN_U16 limit, DN_U16 skip); -DN_API DN_Str8 DN_Str8FromStackTraceNowHeap (DN_U16 limit, DN_U16 skip); -DN_API DN_StackTraceFrameSlice DN_StackTraceGetFrames (DN_Arena *arena, DN_U16 limit); -DN_API DN_StackTraceFrame DN_StackTraceRawFrameToFrame (DN_Arena *arena, DN_StackTraceRawFrame raw_frame); -DN_API void DN_StackTracePrint (DN_U16 limit); -DN_API void DN_StackTraceReloadSymbols (); +#define DN_StackTraceFromAllocator(...) {} +#define DN_StackTraceFromArena(...) {} +#define DN_StackTraceIterate(...) false +#define DN_Str8FromStackTraceAllocator(...) {} +#define DN_Str8FromStackTraceArena(...) {} +#define DN_Str8FromStackTraceNowAllocator(...) {} +#define DN_Str8FromStackTraceNowArena(...) {} +#define DN_StackTraceGetFrames(...) {} +#define DN_StackTraceFrameFromRawFrame(...) {} +#define DN_StackTracePrint(...) +#define DN_StackTraceReloadSymbols(...) #endif DN_API DN_F32 DN_F32Lerp (DN_F32 a, DN_F32 t, DN_F32 b); @@ -5761,6 +5975,9 @@ DN_API DN_V3F32 DN_V3F32Normalise #define DN_V4F32FromRgba255ToRgba01(r, g, b, a) DN_Literal(DN_V4F32){{r / 255.f, g / 255.f, b / 255.f, a / 255.f}} #define DN_V4F32FromRgb255ToRgba01(r, g, b) DN_Literal(DN_V4F32){{r / 255.f, g / 255.f, b / 255.f, 1.f}} +#define DN_V4F32Zero DN_V4F32From1N(0) +#define DN_V4F32One DN_V4F32From1N(1) + DN_API DN_V4F32 DN_V4F32Lerp (DN_V4F32 lhs, DN_F32 t01, DN_V4F32 rhs); DN_API bool DN_V4F32Rgba01IsValid (DN_V4F32 rgba01); DN_API DN_V4F32 DN_V4F32FromRgbU32ToRgba01 (DN_U32 u32); @@ -6215,129 +6432,160 @@ DN_API DN_RaycastV2 DN_RaycastLineIntersectV2 // MyStruct *item = DN_IArrayMake(&my_array, DN_ZMem_No); // #if defined(__cplusplus) - #define DN_PArrayFind(ptr, size, ptr_find, eq_func) DN_TArrayFind(ptr, size, ptr_find, eq_func) - #define DN_PArrayFindMemEq(ptr, size, ptr_find) DN_TArrayFindMemEq(ptr, size, ptr_find) - #define DN_PArrayResizePool(ptr, ptr_size, ptr_max, pool, new_max) DN_TArrayResizePool(&(ptr), ptr_size, ptr_max, pool, new_max) - #define DN_PArrayResizeArena(ptr, ptr_size, ptr_max, arena, new_max) DN_TArrayResizeArena(&(ptr), ptr_size, ptr_max, arena, new_max) - #define DN_PArrayReservePool(ptr, ptr_max, pool, new_max) DN_TArrayReservePool(&(ptr), ptr_max, pool, new_max) - #define DN_PArrayReserveArena(ptr, ptr_max, arena, new_max) DN_TArrayReserveArena(&(ptr), ptr_max, arena, new_max) - #define DN_PArrayPreparePool(ptr, size, ptr_max, pool, add_count) DN_TArrayPreparePool(&(ptr), size, ptr_max, pool, add_count) - #define DN_PArrayPrepareArena(ptr, size, ptr_max, arena, add_count) DN_TArrayPrepareArena(&(ptr), size, ptr_max, arena, add_count) - #define DN_PArrayCopyPtrPool(dest, src, count_, pool) DN_TArrayCopyPtrPool(&(dest), src, count_, pool) - #define DN_PArrayCopyPtrPoolAssert(dest, src, count_, pool) DN_TArrayCopyPtrPoolAssert(&(dest), src, count_, pool, DN_CallSiteNow) - #define DN_PArrayCopyPtrArena(dest, src, count_, arena) DN_TArrayCopyPtrArena(&(dest), src, count_, arena) - #define DN_PArrayCopyPtrArenaAssert(dest, src, count_, arena) DN_TArrayCopyPtrArenaAssert(&(dest), src, count_, arena, DN_CallSiteNow) + #define DN_PArrayFind(ptr, size, ptr_find, eq_func) DN_TArrayFind(ptr, size, ptr_find, eq_func) + #define DN_PArrayFindMemEq(ptr, size, ptr_find) DN_TArrayFindMemEq(ptr, size, ptr_find) + #define DN_PArrayResizePool(ptr, ptr_size, ptr_max, pool, new_max) DN_TArrayResizeAllocator(&(ptr), ptr_size, ptr_max, DN_AllocatorFromPool(pool), new_max) + #define DN_PArrayResizeArena(ptr, ptr_size, ptr_max, arena, new_max) DN_TArrayResizeAllocator(&(ptr), ptr_size, ptr_max, DN_AllocatorFromArena(arena), new_max) + #define DN_PArrayReservePool(ptr, ptr_max, pool, new_max) DN_TArrayReserveAllocator(&(ptr), ptr_max, DN_AllocatorFromPool(pool), new_max) + #define DN_PArrayReserveArena(ptr, ptr_max, arena, new_max) DN_TArrayReserveAllocator(&(ptr), ptr_max, DN_AllocatorFromArena(arena), new_max) + #define DN_PArrayPreparePool(ptr, size, ptr_max, pool, add_count) DN_TArrayPrepareAllocator(&(ptr), size, ptr_max, DN_AllocatorFromPool(pool), add_count) + #define DN_PArrayPrepareArena(ptr, size, ptr_max, arena, add_count) DN_TArrayPrepareAllocator(&(ptr), size, ptr_max, DN_AllocatorFromArena(arena), add_count) + #define DN_PArrayCopyPtrPool(dest, src, count_, pool) DN_TArrayCopyPtrAllocator(&(dest), src, count_, DN_AllocatorFromPool(pool)) + #define DN_PArrayCopyPtrPoolAssert(dest, src, count_, pool) DN_TArrayCopyPtrAllocatorAssert(&(dest), src, count_, DN_AllocatorFromPool(pool), DN_CallSiteNow) + #define DN_PArrayCopyPtrArena(dest, src, count_, arena) DN_TArrayCopyPtrAllocator(&(dest), src, count_, DN_AllocatorFromArena(arena)) + #define DN_PArrayCopyPtrArenaAssert(dest, src, count_, arena) DN_TArrayCopyPtrAllocatorAssert(&(dest), src, count_, DN_AllocatorFromArena(arena), DN_CallSiteNow) - #define DN_PArrayMakeArray(ptr, ptr_size, max, count, z_mem) DN_TArrayMakeArray(ptr, ptr_size, max, count, z_mem) - #define DN_PArrayMakeArrayZ(ptr, ptr_size, max, count) DN_TArrayMakeArray(ptr, ptr_size, max, count, DN_ZMem_Yes) - #define DN_PArrayMakeArrayNoZ(ptr, ptr_size, max, count) DN_TArrayMakeArray(ptr, ptr_size, max, count, DN_ZMem_No) - #define DN_PArrayMakeArrayAssert(ptr, ptr_size, max, count, z_mem) DN_TArrayMakeArrayAssert(ptr, ptr_size, max, count, z_mem, DN_CallSiteNow) - #define DN_PArrayMakeArrayAssertZ(ptr, ptr_size, max, count) DN_TArrayMakeArrayAssert(ptr, ptr_size, max, count, DN_ZMem_Yes, DN_CallSiteNow) - #define DN_PArrayMakeArrayAssertNoZ(ptr, ptr_size, max, count) DN_TArrayMakeArrayAssert(ptr, ptr_size, max, count, DN_ZMem_No, DN_CallSiteNow) - #define DN_PArrayMakeArrayArena(ptr, ptr_size, ptr_max, arena, count, z_mem) DN_TArrayMakeArrayArena(&(ptr), ptr_size, ptr_max, arena, count, z_mem) - #define DN_PArrayMakeArrayArenaZ(ptr, ptr_size, ptr_max, arena, count) DN_TArrayMakeArrayArena(&(ptr), ptr_size, ptr_max, arena, count, DN_ZMem_Yes) - #define DN_PArrayMakeArrayArenaNoZ(ptr, ptr_size, ptr_max, arena, count) DN_TArrayMakeArrayArena(&(ptr), ptr_size, ptr_max, arena, count, DN_ZMem_No) - #define DN_PArrayMakeArrayPool(ptr, ptr_size, ptr_max, pool, count, z_mem) DN_TArrayMakeArrayPool(&(ptr), ptr_size, ptr_max, pool, count, z_mem) - #define DN_PArrayMakeArrayPoolZ(ptr, ptr_size, ptr_max, pool, count) DN_TArrayMakeArrayPool(&(ptr), ptr_size, ptr_max, pool, count, DN_ZMem_Yes) - #define DN_PArrayMakeArrayPoolNoZ(ptr, ptr_size, ptr_max, pool, count) DN_TArrayMakeArrayPool(&(ptr), ptr_size, ptr_max, pool, count, DN_ZMem_No) + #define DN_PArrayMakeArray(ptr, ptr_size, max, count, z_mem) DN_TArrayMakeArray(ptr, ptr_size, max, count, z_mem) + #define DN_PArrayMakeArrayZ(ptr, ptr_size, max, count) DN_TArrayMakeArray(ptr, ptr_size, max, count, DN_ZMem_Yes) + #define DN_PArrayMakeArrayNoZ(ptr, ptr_size, max, count) DN_TArrayMakeArray(ptr, ptr_size, max, count, DN_ZMem_No) + #define DN_PArrayMakeArrayAssert(ptr, ptr_size, max, count, z_mem) DN_TArrayMakeArrayAssert(ptr, ptr_size, max, count, z_mem, DN_CallSiteNow) + #define DN_PArrayMakeArrayAssertZ(ptr, ptr_size, max, count) DN_TArrayMakeArrayAssert(ptr, ptr_size, max, count, DN_ZMem_Yes, DN_CallSiteNow) + #define DN_PArrayMakeArrayAssertNoZ(ptr, ptr_size, max, count) DN_TArrayMakeArrayAssert(ptr, ptr_size, max, count, DN_ZMem_No, DN_CallSiteNow) + #define DN_PArrayMakeArrayArena(ptr, ptr_size, ptr_max, arena, count, z_mem) DN_TArrayMakeArrayAllocator(&(ptr), ptr_size, ptr_max, DN_AllocatorFromArena(arena), count, z_mem) + #define DN_PArrayMakeArrayArenaZ(ptr, ptr_size, ptr_max, arena, count) DN_TArrayMakeArrayAllocator(&(ptr), ptr_size, ptr_max, DN_AllocatorFromArena(arena), count, DN_ZMem_Yes) + #define DN_PArrayMakeArrayArenaNoZ(ptr, ptr_size, ptr_max, arena, count) DN_TArrayMakeArrayAllocator(&(ptr), ptr_size, ptr_max, DN_AllocatorFromArena(arena), count, DN_ZMem_No) + #define DN_PArrayMakeArrayPool(ptr, ptr_size, ptr_max, pool, count, z_mem) DN_TArrayMakeArrayAllocator(&(ptr), ptr_size, ptr_max, DN_AllocatorFromPool(pool), count, z_mem) + #define DN_PArrayMakeArrayPoolZ(ptr, ptr_size, ptr_max, pool, count) DN_TArrayMakeArrayAllocator(&(ptr), ptr_size, ptr_max, DN_AllocatorFromPool(pool), count, DN_ZMem_Yes) + #define DN_PArrayMakeArrayPoolNoZ(ptr, ptr_size, ptr_max, pool, count) DN_TArrayMakeArrayAllocator(&(ptr), ptr_size, ptr_max, DN_AllocatorFromPool(pool), count, DN_ZMem_No) - #define DN_PArrayMake(ptr, ptr_size, max, z_mem) DN_TArrayMakeArray(ptr, ptr_size, max, 1, z_mem) - #define DN_PArrayMakeZ(ptr, ptr_size, max) DN_TArrayMakeArray(ptr, ptr_size, max, 1, DN_ZMem_Yes) - #define DN_PArrayMakeNoZ(ptr, ptr_size, max) DN_TArrayMakeArray(ptr, ptr_size, max, 1, DN_ZMem_No) - #define DN_PArrayMakeAssert(ptr, ptr_size, max, z_mem) DN_TArrayMakeArrayAssert(ptr, ptr_size, max, 1, z_mem, DN_CallSiteNow) - #define DN_PArrayMakeAssertZ(ptr, ptr_size, max) DN_TArrayMakeArrayAssert(ptr, ptr_size, max, 1, DN_ZMem_Yes, DN_CallSiteNow) - #define DN_PArrayMakeAssertNoZ(ptr, ptr_size, max) DN_TArrayMakeArrayAssert(ptr, ptr_size, max, 1, DN_ZMem_No, DN_CallSiteNow) - #define DN_PArrayMakeArena(ptr, ptr_size, ptr_max, arena, z_mem) DN_TArrayMakeArrayArena(&(ptr), ptr_size, ptr_max, arena, 1, z_mem) - #define DN_PArrayMakeArenaZ(ptr, ptr_size, ptr_max, arena) DN_TArrayMakeArrayArena(&(ptr), ptr_size, ptr_max, arena, 1, DN_ZMem_Yes) - #define DN_PArrayMakeArenaNoZ(ptr, ptr_size, ptr_max, arena) DN_TArrayMakeArrayArena(&(ptr), ptr_size, ptr_max, arena, 1, DN_ZMem_No) - #define DN_PArrayMakePool(ptr, ptr_size, ptr_max, pool, z_mem) DN_TArrayMakeArrayPool(&(ptr), ptr_size, ptr_max, pool, 1, z_mem) - #define DN_PArrayMakePoolZ(ptr, ptr_size, ptr_max, pool) DN_TArrayMakeArrayPool(&(ptr), ptr_size, ptr_max, pool, 1, DN_ZMem_Yes) - #define DN_PArrayMakePoolNoZ(ptr, ptr_size, ptr_max, pool) DN_TArrayMakeArrayPool(&(ptr), ptr_size, ptr_max, pool, 1, DN_ZMem_No) + #define DN_PArrayMake(ptr, ptr_size, max, z_mem) DN_TArrayMakeArray(ptr, ptr_size, max, 1, z_mem) + #define DN_PArrayMakeZ(ptr, ptr_size, max) DN_TArrayMakeArray(ptr, ptr_size, max, 1, DN_ZMem_Yes) + #define DN_PArrayMakeNoZ(ptr, ptr_size, max) DN_TArrayMakeArray(ptr, ptr_size, max, 1, DN_ZMem_No) + #define DN_PArrayMakeAssert(ptr, ptr_size, max, z_mem) DN_TArrayMakeArrayAssert(ptr, ptr_size, max, 1, z_mem, DN_CallSiteNow) + #define DN_PArrayMakeAssertZ(ptr, ptr_size, max) DN_TArrayMakeArrayAssert(ptr, ptr_size, max, 1, DN_ZMem_Yes, DN_CallSiteNow) + #define DN_PArrayMakeAssertNoZ(ptr, ptr_size, max) DN_TArrayMakeArrayAssert(ptr, ptr_size, max, 1, DN_ZMem_No, DN_CallSiteNow) + #define DN_PArrayMakeArena(ptr, ptr_size, ptr_max, arena, z_mem) DN_TArrayMakeArrayAllocator(&(ptr), ptr_size, ptr_max, DN_AllocatorFromArena(arena), 1, z_mem) + #define DN_PArrayMakeArenaZ(ptr, ptr_size, ptr_max, arena) DN_TArrayMakeArrayAllocator(&(ptr), ptr_size, ptr_max, DN_AllocatorFromArena(arena), 1, DN_ZMem_Yes) + #define DN_PArrayMakeArenaNoZ(ptr, ptr_size, ptr_max, arena) DN_TArrayMakeArrayAllocator(&(ptr), ptr_size, ptr_max, DN_AllocatorFromArena(arena), 1, DN_ZMem_No) + #define DN_PArrayMakePool(ptr, ptr_size, ptr_max, pool, z_mem) DN_TArrayMakeArrayAllocator(&(ptr), ptr_size, ptr_max, DN_AllocatorFromPool(pool), 1, z_mem) + #define DN_PArrayMakePoolZ(ptr, ptr_size, ptr_max, pool) DN_TArrayMakeArrayAllocator(&(ptr), ptr_size, ptr_max, DN_AllocatorFromPool(pool), 1, DN_ZMem_Yes) + #define DN_PArrayMakePoolNoZ(ptr, ptr_size, ptr_max, pool) DN_TArrayMakeArrayAllocator(&(ptr), ptr_size, ptr_max, DN_AllocatorFromPool(pool), 1, DN_ZMem_No) - #define DN_PArrayAddArray(ptr, ptr_size, max, items, count, add) DN_TArrayAddArray(ptr, ptr_size, max, items, count, add) - #define DN_PArrayAddArrayArena(ptr, ptr_size, ptr_max, arena, items, count, add) DN_TArrayAddArrayArena(&(ptr), ptr_size, ptr_max, arena, items, count, add) - #define DN_PArrayAddArrayPool(ptr, ptr_size, ptr_max, pool, items, count, add) DN_TArrayAddArrayPool(&(ptr), ptr_size, ptr_max, pool, items, count, add) - #define DN_PArrayAdd(ptr, ptr_size, max, item, add) DN_TArrayAddArray(ptr, ptr_size, max, &item, 1, add) - #define DN_PArrayAddArena(ptr, ptr_size, ptr_max, arena, item, add) DN_TArrayAddArrayArena(&(ptr), ptr_size, ptr_max, arena, &item, 1, add) - #define DN_PArrayAddPool(ptr, ptr_size, ptr_max, pool, item, add) DN_TArrayAddArrayPool(&(ptr), ptr_size, ptr_max, pool, &item, 1, add) - #define DN_PArrayAppendArray(ptr, ptr_size, max, items, count) DN_TArrayAddArray(ptr, ptr_size, max, items, count, DN_AddType_Append) - #define DN_PArrayAppend(ptr, ptr_size, max, item) DN_TArrayAddArray(ptr, ptr_size, max, &item, 1, DN_AddType_Append) - #define DN_PArrayAppendArena(ptr, ptr_size, ptr_max, arena, item) DN_TArrayAddArrayArena(&(ptr), ptr_size, ptr_max, arena, &item, 1, DN_AddType_Append) - #define DN_PArrayAppendPool(ptr, ptr_size, ptr_max, pool, item) DN_TArrayAddArrayPool(&(ptr), ptr_size, ptr_max, pool, &item, 1, DN_AddType_Append) - #define DN_PArrayAppendAssert(ptr, ptr_size, max, item) DN_TArrayAddArrayAssert(ptr, ptr_size, max, &item, 1, DN_AddType_Append, DN_CallSiteNow) - #define DN_PArrayPrependArray(ptr, ptr_size, max, items, count) DN_TArrayAddArray(ptr, ptr_size, max, items, count, DN_AddType_Prepend) - #define DN_PArrayPrepend(ptr, ptr_size, max, item) DN_TArrayAddArray(ptr, ptr_size, max, &item, 1, DN_AddType_Prepend) - #define DN_PArrayPrependArena(ptr, ptr_size, ptr_max, arena, item) DN_TArrayAddArrayArena(&(ptr), ptr_size, ptr_max, arena, &item, 1, DN_AddType_Prepend) - #define DN_PArrayPrependPool(ptr, ptr_size, ptr_max, pool, item) DN_TArrayAddArrayPool(&(ptr), ptr_size, ptr_max, pool, &item, 1, DN_AddType_Prepend) + #define DN_PArrayAddArray(ptr, ptr_size, max, items, count, add) DN_TArrayAddArray(ptr, ptr_size, max, items, count, add) + #define DN_PArrayAddArrayArena(ptr, ptr_size, ptr_max, arena, items, count, add) DN_TArrayAddArrayAllocator(&(ptr), ptr_size, ptr_max, DN_AllocatorFromArena(arena), items, count, add) + #define DN_PArrayAddArrayPool(ptr, ptr_size, ptr_max, pool, items, count, add) DN_TArrayAddArrayAllocator(&(ptr), ptr_size, ptr_max, DN_AllocatorFromPool(pool), items, count, add) + #define DN_PArrayAdd(ptr, ptr_size, max, item, add) DN_TArrayAddArray(ptr, ptr_size, max, &item, 1, add) + #define DN_PArrayAddArena(ptr, ptr_size, ptr_max, arena, item, add) DN_TArrayAddArrayAllocator(&(ptr), ptr_size, ptr_max, DN_AllocatorFromArena(arena), &item, 1, add) + #define DN_PArrayAddPool(ptr, ptr_size, ptr_max, pool, item, add) DN_TArrayAddArrayAllocator(&(ptr), ptr_size, ptr_max, DN_AllocatorFromPool(pool), &item, 1, add) + #define DN_PArrayAppendArray(ptr, ptr_size, max, items, count) DN_TArrayAddArray(ptr, ptr_size, max, items, count, DN_AddType_Append) + #define DN_PArrayAppend(ptr, ptr_size, max, item) DN_TArrayAddArray(ptr, ptr_size, max, &item, 1, DN_AddType_Append) + #define DN_PArrayAppendArena(ptr, ptr_size, ptr_max, arena, item) DN_TArrayAddArrayAllocator(&(ptr), ptr_size, ptr_max, DN_AllocatorFromArena(arena), &item, 1, DN_AddType_Append) + #define DN_PArrayAppendPool(ptr, ptr_size, ptr_max, pool, item) DN_TArrayAddArrayAllocator(&(ptr), ptr_size, ptr_max, DN_AllocatorFromPool(pool), &item, 1, DN_AddType_Append) + #define DN_PArrayAppendAssert(ptr, ptr_size, max, item) DN_TArrayAddArrayAssert(ptr, ptr_size, max, &item, 1, DN_AddType_Append, DN_CallSiteNow) + #define DN_PArrayPrependArray(ptr, ptr_size, max, items, count) DN_TArrayAddArray(ptr, ptr_size, max, items, count, DN_AddType_Prepend) + #define DN_PArrayPrepend(ptr, ptr_size, max, item) DN_TArrayAddArray(ptr, ptr_size, max, &item, 1, DN_AddType_Prepend) + #define DN_PArrayPrependArena(ptr, ptr_size, ptr_max, arena, item) DN_TArrayAddArrayAllocator(&(ptr), ptr_size, ptr_max, DN_AllocatorFromArena(arena), &item, 1, DN_AddType_Prepend) + #define DN_PArrayPrependPool(ptr, ptr_size, ptr_max, pool, item) DN_TArrayAddArrayAllocator(&(ptr), ptr_size, ptr_max, DN_AllocatorFromPool(pool), &item, 1, DN_AddType_Prepend) - #define DN_PArrayEraseRange(ptr, ptr_size, begin_index, count, erase) DN_TArrayEraseRange(ptr, ptr_size, begin_index, count, erase) - #define DN_PArrayErase(ptr, ptr_size, index, erase) DN_TArrayEraseRange(ptr, ptr_size, index, 1, erase) - #define DN_PArrayInsertArray(ptr, ptr_size, max, index, items, count) DN_TArrayInsertArray(ptr, ptr_size, max, index, items, count) - #define DN_PArrayInsert(ptr, ptr_size, max, index, item) DN_TArrayInsertArray(ptr, ptr_size, max, index, &item, 1) - #define DN_PArrayPopFront(ptr, ptr_size, max, count) DN_TArrayPopFront(ptr, ptr_size, count) - #define DN_PArrayPopBack(ptr, ptr_size, max, count) DN_TArrayPopBack(ptr, ptr_size, count) + #define DN_PArrayEraseRange(ptr, ptr_size, begin_index, count, erase) DN_TArrayEraseRange(ptr, ptr_size, begin_index, count, erase) + #define DN_PArrayErase(ptr, ptr_size, index, erase) DN_TArrayEraseRange(ptr, ptr_size, index, 1, erase) + #define DN_PArrayInsertArray(ptr, ptr_size, max, index, items, count) DN_TArrayInsertArray(ptr, ptr_size, max, index, items, count) + #define DN_PArrayInsert(ptr, ptr_size, max, index, item) DN_TArrayInsertArray(ptr, ptr_size, max, index, &item, 1) + #define DN_PArrayPopFront(ptr, ptr_size, max, count) DN_TArrayPopFront(ptr, ptr_size, count) + #define DN_PArrayPopBack(ptr, ptr_size, max, count) DN_TArrayPopBack(ptr, ptr_size, count) + + #define DN_PArrayResizeHeap(ptr, ptr_size, ptr_max, heap, new_max) DN_TArrayResizeAllocator(&(ptr), ptr_size, ptr_max, DN_AllocatorFromHeap(heap), new_max) + #define DN_PArrayReserveHeap(ptr, ptr_max, heap, new_max) DN_TArrayReserveAllocator(&(ptr), ptr_max, DN_AllocatorFromHeap(heap), new_max) + #define DN_PArrayPrepareHeap(ptr, size, ptr_max, heap, add_count) DN_TArrayPrepareAllocator(&(ptr), size, ptr_max, DN_AllocatorFromHeap(heap), add_count) + #define DN_PArrayCopyPtrHeap(dest, src, count_, heap) DN_TArrayCopyPtrAllocator(&(dest), src, count_, DN_AllocatorFromHeap(heap)) + #define DN_PArrayCopyPtrHeapAssert(dest, src, count_, heap) DN_TArrayCopyPtrAllocatorAssert(&(dest), src, count_, DN_AllocatorFromHeap(heap), DN_CallSiteNow) + #define DN_PArrayMakeArrayHeap(ptr, ptr_size, ptr_max, heap, count, z_mem) DN_TArrayMakeArrayAllocator(&(ptr), ptr_size, ptr_max, DN_AllocatorFromHeap(heap), count, z_mem) + #define DN_PArrayMakeArrayHeapZ(ptr, ptr_size, ptr_max, heap, count) DN_TArrayMakeArrayAllocator(&(ptr), ptr_size, ptr_max, DN_AllocatorFromHeap(heap), count, DN_ZMem_Yes) + #define DN_PArrayMakeArrayHeapNoZ(ptr, ptr_size, ptr_max, heap, count) DN_TArrayMakeArrayAllocator(&(ptr), ptr_size, ptr_max, DN_AllocatorFromHeap(heap), count, DN_ZMem_No) + #define DN_PArrayMakeHeap(ptr, ptr_size, ptr_max, heap, z_mem) DN_TArrayMakeArrayAllocator(&(ptr), ptr_size, ptr_max, DN_AllocatorFromHeap(heap), 1, z_mem) + #define DN_PArrayMakeHeapZ(ptr, ptr_size, ptr_max, heap) DN_TArrayMakeArrayAllocator(&(ptr), ptr_size, ptr_max, DN_AllocatorFromHeap(heap), 1, DN_ZMem_Yes) + #define DN_PArrayMakeHeapNoZ(ptr, ptr_size, ptr_max, heap) DN_TArrayMakeArrayAllocator(&(ptr), ptr_size, ptr_max, DN_AllocatorFromHeap(heap), 1, DN_ZMem_No) + #define DN_PArrayAddArrayHeap(ptr, ptr_size, ptr_max, heap, items, count, add) DN_TArrayAddArrayAllocator(&(ptr), ptr_size, ptr_max, DN_AllocatorFromHeap(heap), items, count, add) + #define DN_PArrayAddHeap(ptr, ptr_size, ptr_max, heap, item, add) DN_TArrayAddArrayAllocator(&(ptr), ptr_size, ptr_max, DN_AllocatorFromHeap(heap), &item, 1, add) + #define DN_PArrayAppendHeap(ptr, ptr_size, ptr_max, heap, item) DN_TArrayAddArrayAllocator(&(ptr), ptr_size, ptr_max, DN_AllocatorFromHeap(heap), &item, 1, DN_AddType_Append) + #define DN_PArrayPrependHeap(ptr, ptr_size, ptr_max, heap, item) DN_TArrayAddArrayAllocator(&(ptr), ptr_size, ptr_max, DN_AllocatorFromHeap(heap), &item, 1, DN_AddType_Prepend) #else - #define DN_PArrayFind(ptr, size, ptr_find, eq_func) DN_ArrayFind(ptr, size, sizeof(*(ptr)), ptr_find, eq_func) - #define DN_PArrayFindMemEq(ptr, size, ptr_find) DN_ArrayFindMemEq(ptr, size, sizeof(*(ptr)), ptr_find) - #define DN_PArrayResizePool(ptr, ptr_size, ptr_max, pool, new_max) DN_ArrayResizePool((void **)&(ptr), ptr_size, ptr_max, sizeof((ptr)[0]), pool, new_max) - #define DN_PArrayResizeArena(ptr, ptr_size, ptr_max, arena, new_max) DN_ArrayResizeArena((void **)&(ptr), ptr_size, ptr_max, sizeof((ptr)[0]), arena, new_max) - #define DN_PArrayReservePool(ptr, ptr_max, pool, new_max) DN_ArrayReservePool((void **)&(ptr), ptr_max, sizeof((ptr)[0]), pool, new_max) - #define DN_PArrayReserveArena(ptr, ptr_max, arena, new_max) DN_ArrayReserveArena((void **)&(ptr), ptr_max, sizeof((ptr)[0]), arena, new_max) - #define DN_PArrayPreparePool(ptr, size, ptr_max, pool, add_count) DN_ArrayPreparePool((void **)(ptr), size, ptr_max, sizeof((*ptr)[0]), pool, add_count) - #define DN_PArrayPrepareArena(ptr, size, ptr_max, arena, add_count) DN_ArrayPrepareArena((void **)(ptr), size, ptr_max, sizeof((*ptr)[0]), arena, add_count) - #define DN_PArrayCopyPtrPool(ptr_array, src, count_, pool) DN_ArrayCopyPtrPool(ptr_array, src, count_, sizeof((*ptr)[0]), pool) - #define DN_PArrayCopyPtrPoolAssert(ptr_array, src, count_, pool) DN_ArrayCopyPtrPool(ptr_array, src, count_, sizeof((*ptr)[0]), pool, DN_CallSiteNow) - #define DN_PArrayCopyPtrArena(ptr_array, src, count_, arena) DN_ArrayCopyPtrArena(ptr_array, src, count_, sizeof((*ptr)[0]), arena) - #define DN_PArrayCopyPtrArenaAssert(ptr_array, src, count_, arena) DN_ArrayCopyPtrArena(ptr_array, src, count_, sizeof((*ptr)[0]), arena, DN_CallSiteNow) + #define DN_PArrayFind(ptr, size, ptr_find, eq_func) DN_ArrayFind(ptr, size, sizeof(*(ptr)), ptr_find, eq_func) + #define DN_PArrayFindMemEq(ptr, size, ptr_find) DN_ArrayFindMemEq(ptr, size, sizeof(*(ptr)), ptr_find) + #define DN_PArrayResizePool(ptr, ptr_size, ptr_max, pool, new_max) DN_ArrayResizeAllocator((void **)&(ptr), ptr_size, ptr_max, sizeof((ptr)[0]), DN_AllocatorFromPool(pool), new_max) + #define DN_PArrayResizeArena(ptr, ptr_size, ptr_max, arena, new_max) DN_ArrayResizeAllocator((void **)&(ptr), ptr_size, ptr_max, sizeof((ptr)[0]), DN_AllocatorFromArena(arena), new_max) + #define DN_PArrayReservePool(ptr, ptr_max, pool, new_max) DN_ArrayReserveAllocator((void **)&(ptr), ptr_max, sizeof((ptr)[0]), DN_AllocatorFromPool(pool), new_max) + #define DN_PArrayReserveArena(ptr, ptr_max, arena, new_max) DN_ArrayReserveAllocator((void **)&(ptr), ptr_max, sizeof((ptr)[0]), DN_AllocatorFromArena(arena), new_max) + #define DN_PArrayPreparePool(ptr, size, ptr_max, pool, add_count) DN_ArrayPrepareAllocator((void **)(ptr), size, ptr_max, sizeof((*ptr)[0]), DN_AllocatorFromPool(pool), add_count) + #define DN_PArrayPrepareArena(ptr, size, ptr_max, arena, add_count) DN_ArrayPrepareAllocator((void **)(ptr), size, ptr_max, sizeof((*ptr)[0]), DN_AllocatorFromArena(arena), add_count) + #define DN_PArrayCopyPtrPool(ptr_array, src, count_, pool) DN_ArrayCopyPtrAllocator(ptr_array, src, count_, sizeof((*ptr)[0]), DN_AllocatorFromPool(pool)) + #define DN_PArrayCopyPtrPoolAssert(ptr_array, src, count_, pool) DN_ArrayCopyPtrAllocatorAssert(ptr_array, src, count_, sizeof((*ptr)[0]), DN_AllocatorFromPool(pool), DN_CallSiteNow) + #define DN_PArrayCopyPtrArena(ptr_array, src, count_, arena) DN_ArrayCopyPtrAllocator(ptr_array, src, count_, sizeof((*ptr)[0]), DN_AllocatorFromArena(arena)) + #define DN_PArrayCopyPtrArenaAssert(ptr_array, src, count_, arena) DN_ArrayCopyPtrAllocatorAssert(ptr_array, src, count_, sizeof((*ptr)[0]), DN_AllocatorFromArena(arena), DN_CallSiteNow) + #define DN_PArrayResizeHeap(ptr, ptr_size, ptr_max, heap, new_max) DN_ArrayResizeAllocator((void **)&(ptr), ptr_size, ptr_max, sizeof((ptr)[0]), DN_AllocatorFromHeap(heap), new_max) + #define DN_PArrayReserveHeap(ptr, ptr_max, heap, new_max) DN_ArrayReserveAllocator((void **)&(ptr), ptr_max, sizeof((ptr)[0]), DN_AllocatorFromHeap(heap), new_max) + #define DN_PArrayPrepareHeap(ptr, size, ptr_max, heap, add_count) DN_ArrayPrepareAllocator((void **)(ptr), size, ptr_max, sizeof((*ptr)[0]), DN_AllocatorFromHeap(heap), add_count) + #define DN_PArrayCopyPtrHeap(ptr_array, src, count_, heap) DN_ArrayCopyPtrAllocator(ptr_array, src, count_, sizeof((*ptr)[0]), DN_AllocatorFromHeap(heap)) + #define DN_PArrayCopyPtrHeapAssert(ptr_array, src, count_, heap) DN_ArrayCopyPtrAllocatorAssert(ptr_array, src, count_, sizeof((*ptr)[0]), DN_AllocatorFromHeap(heap), DN_CallSiteNow) - #define DN_PArrayMakeArray(ptr, ptr_size, max, count, z_mem) (DN_CppDeclType(&(ptr)[0]))DN_ArrayMakeArray(ptr, ptr_size, max, sizeof((ptr)[0]), count, z_mem) - #define DN_PArrayMakeArrayZ(ptr, ptr_size, max, count) (DN_CppDeclType(&(ptr)[0]))DN_ArrayMakeArray(ptr, ptr_size, max, sizeof((ptr)[0]), count, DN_ZMem_Yes) - #define DN_PArrayMakeArrayNoZ(ptr, ptr_size, max, count) (DN_CppDeclType(&(ptr)[0]))DN_ArrayMakeArray(ptr, ptr_size, max, sizeof((ptr)[0]), count, DN_ZMem_No) - #define DN_PArrayMakeArrayAssert(ptr, ptr_size, max, count, z_mem) (DN_CppDeclType(&(ptr)[0]))DN_ArrayMakeArrayAssert(ptr, ptr_size, max, sizeof((ptr)[0]), count, z_mem, DN_CallSiteNow) - #define DN_PArrayMakeArrayAssertZ(ptr, ptr_size, max, count) (DN_CppDeclType(&(ptr)[0]))DN_ArrayMakeArrayAssert(ptr, ptr_size, max, sizeof((ptr)[0]), count, DN_ZMem_Yes, DN_CallSiteNow) - #define DN_PArrayMakeArrayAssertNoZ(ptr, ptr_size, max, count) (DN_CppDeclType(&(ptr)[0]))DN_ArrayMakeArrayAssert(ptr, ptr_size, max, sizeof((ptr)[0]), count, DN_ZMem_No, DN_CallSiteNow) - #define DN_PArrayMakeArrayArena(ptr, ptr_size, max, arena, count, z_mem) (DN_CppDeclType(&(ptr)[0]))DN_ArrayMakeArrayArena((void **)&(ptr), ptr_size, max, sizeof((ptr)[0]), arena, count, z_mem) - #define DN_PArrayMakeArrayArenaZ(ptr, ptr_size, max, arena, count) (DN_CppDeclType(&(ptr)[0]))DN_ArrayMakeArrayArena((void **)&(ptr), ptr_size, max, sizeof((ptr)[0]), arena, count, DN_ZMem_Yes) - #define DN_PArrayMakeArrayArenaNoZ(ptr, ptr_size, max, arena, count) (DN_CppDeclType(&(ptr)[0]))DN_ArrayMakeArrayArena((void **)&(ptr), ptr_size, max, sizeof((ptr)[0]), arena, count, DN_ZMem_No) - #define DN_PArrayMakeArrayPool(ptr, ptr_size, max, pool, count, z_mem) (DN_CppDeclType(&(ptr)[0]))DN_ArrayMakeArrayPool((void **)&(ptr), ptr_size, max, sizeof((ptr)[0]), pool, count, z_mem) - #define DN_PArrayMakeArrayPoolZ(ptr, ptr_size, max, pool, count) (DN_CppDeclType(&(ptr)[0]))DN_ArrayMakeArrayPool((void **)&(ptr), ptr_size, max, sizeof((ptr)[0]), pool, count, DN_ZMem_Yes) - #define DN_PArrayMakeArrayPoolNoZ(ptr, ptr_size, max, pool, count) (DN_CppDeclType(&(ptr)[0]))DN_ArrayMakeArrayPool((void **)&(ptr), ptr_size, max, sizeof((ptr)[0]), pool, count, DN_ZMem_No) + #define DN_PArrayMakeArray(ptr, ptr_size, max, count, z_mem) (DN_CppDeclType(&(ptr)[0]))DN_ArrayMakeArray(ptr, ptr_size, max, sizeof((ptr)[0]), count, z_mem) + #define DN_PArrayMakeArrayZ(ptr, ptr_size, max, count) (DN_CppDeclType(&(ptr)[0]))DN_ArrayMakeArray(ptr, ptr_size, max, sizeof((ptr)[0]), count, DN_ZMem_Yes) + #define DN_PArrayMakeArrayNoZ(ptr, ptr_size, max, count) (DN_CppDeclType(&(ptr)[0]))DN_ArrayMakeArray(ptr, ptr_size, max, sizeof((ptr)[0]), count, DN_ZMem_No) + #define DN_PArrayMakeArrayAssert(ptr, ptr_size, max, count, z_mem) (DN_CppDeclType(&(ptr)[0]))DN_ArrayMakeArrayAssert(ptr, ptr_size, max, sizeof((ptr)[0]), count, z_mem, DN_CallSiteNow) + #define DN_PArrayMakeArrayAssertZ(ptr, ptr_size, max, count) (DN_CppDeclType(&(ptr)[0]))DN_ArrayMakeArrayAssert(ptr, ptr_size, max, sizeof((ptr)[0]), count, DN_ZMem_Yes, DN_CallSiteNow) + #define DN_PArrayMakeArrayAssertNoZ(ptr, ptr_size, max, count) (DN_CppDeclType(&(ptr)[0]))DN_ArrayMakeArrayAssert(ptr, ptr_size, max, sizeof((ptr)[0]), count, DN_ZMem_No, DN_CallSiteNow) + #define DN_PArrayMakeArrayArena(ptr, ptr_size, max, arena, count, z_mem) (DN_CppDeclType(&(ptr)[0]))DN_ArrayMakeArrayAllocator((void **)&(ptr), ptr_size, max, sizeof((ptr)[0]), DN_AllocatorFromArena(arena), count, z_mem) + #define DN_PArrayMakeArrayArenaZ(ptr, ptr_size, max, arena, count) (DN_CppDeclType(&(ptr)[0]))DN_ArrayMakeArrayAllocator((void **)&(ptr), ptr_size, max, sizeof((ptr)[0]), DN_AllocatorFromArena(arena), count, DN_ZMem_Yes) + #define DN_PArrayMakeArrayArenaNoZ(ptr, ptr_size, max, arena, count) (DN_CppDeclType(&(ptr)[0]))DN_ArrayMakeArrayAllocator((void **)&(ptr), ptr_size, max, sizeof((ptr)[0]), DN_AllocatorFromArena(arena), count, DN_ZMem_No) + #define DN_PArrayMakeArrayPool(ptr, ptr_size, max, pool, count, z_mem) (DN_CppDeclType(&(ptr)[0]))DN_ArrayMakeArrayAllocator((void **)&(ptr), ptr_size, max, sizeof((ptr)[0]), DN_AllocatorFromPool(pool), count, z_mem) + #define DN_PArrayMakeArrayPoolZ(ptr, ptr_size, max, pool, count) (DN_CppDeclType(&(ptr)[0]))DN_ArrayMakeArrayAllocator((void **)&(ptr), ptr_size, max, sizeof((ptr)[0]), DN_AllocatorFromPool(pool), count, DN_ZMem_Yes) + #define DN_PArrayMakeArrayPoolNoZ(ptr, ptr_size, max, pool, count) (DN_CppDeclType(&(ptr)[0]))DN_ArrayMakeArrayAllocator((void **)&(ptr), ptr_size, max, sizeof((ptr)[0]), DN_AllocatorFromPool(pool), count, DN_ZMem_No) + #define DN_PArrayMakeArrayHeap(ptr, ptr_size, max, heap, count, z_mem) (DN_CppDeclType(&(ptr)[0]))DN_ArrayMakeArrayAllocator((void **)&(ptr), ptr_size, max, sizeof((ptr)[0]), DN_AllocatorFromHeap(heap), count, z_mem) + #define DN_PArrayMakeArrayHeapZ(ptr, ptr_size, max, heap, count) (DN_CppDeclType(&(ptr)[0]))DN_ArrayMakeArrayAllocator((void **)&(ptr), ptr_size, max, sizeof((ptr)[0]), DN_AllocatorFromHeap(heap), count, DN_ZMem_Yes) + #define DN_PArrayMakeArrayHeapNoZ(ptr, ptr_size, max, heap, count) (DN_CppDeclType(&(ptr)[0]))DN_ArrayMakeArrayAllocator((void **)&(ptr), ptr_size, max, sizeof((ptr)[0]), DN_AllocatorFromHeap(heap), count, DN_ZMem_No) - #define DN_PArrayMake(ptr, ptr_size, max, z_mem) (DN_CppDeclType(&(ptr)[0]))DN_ArrayMakeArray(ptr, ptr_size, max, sizeof((ptr)[0]), 1, z_mem) - #define DN_PArrayMakeZ(ptr, ptr_size, max) (DN_CppDeclType(&(ptr)[0]))DN_ArrayMakeArray(ptr, ptr_size, max, sizeof((ptr)[0]), 1, DN_ZMem_Yes) - #define DN_PArrayMakeNoZ(ptr, ptr_size, max) (DN_CppDeclType(&(ptr)[0]))DN_ArrayMakeArray(ptr, ptr_size, max, sizeof((ptr)[0]), 1, DN_ZMem_No) - #define DN_PArrayMakeAssert(ptr, ptr_size, max, z_mem) (DN_CppDeclType(&(ptr)[0]))DN_ArrayMakeArrayAssert(ptr, ptr_size, max, sizeof((ptr)[0]), 1, z_mem, DN_CallSiteNow) - #define DN_PArrayMakeAssertZ(ptr, ptr_size, max) (DN_CppDeclType(&(ptr)[0]))DN_ArrayMakeArrayAssert(ptr, ptr_size, max, sizeof((ptr)[0]), 1, DN_ZMem_Yes, DN_CallSiteNow) - #define DN_PArrayMakeAssertNoZ(ptr, ptr_size, max) (DN_CppDeclType(&(ptr)[0]))DN_ArrayMakeArrayAssert(ptr, ptr_size, max, sizeof((ptr)[0]), 1, DN_ZMem_No, DN_CallSiteNow) - #define DN_PArrayMakeArena(ptr, ptr_size, max, arena, z_mem) (DN_CppDeclType(&(ptr)[0]))DN_ArrayMakeArrayArena((void **)&(ptr), ptr_size, max, sizeof((ptr)[0]), arena, 1, z_mem) - #define DN_PArrayMakeArenaZ(ptr, ptr_size, max, arena) (DN_CppDeclType(&(ptr)[0]))DN_ArrayMakeArrayArena((void **)&(ptr), ptr_size, max, sizeof((ptr)[0]), arena, 1, DN_ZMem_Yes) - #define DN_PArrayMakeArenaNoZ(ptr, ptr_size, max, arena) (DN_CppDeclType(&(ptr)[0]))DN_ArrayMakeArrayArena((void **)&(ptr), ptr_size, max, sizeof((ptr)[0]), arena, 1, DN_ZMem_No) - #define DN_PArrayMakePool(ptr, ptr_size, max, pool, z_mem) (DN_CppDeclType(&(ptr)[0]))DN_ArrayMakeArrayPool((void **)&(ptr), ptr_size, max, sizeof((ptr)[0]), pool, 1, z_mem) - #define DN_PArrayMakePoolZ(ptr, ptr_size, max, pool) (DN_CppDeclType(&(ptr)[0]))DN_ArrayMakeArrayPool((void **)&(ptr), ptr_size, max, sizeof((ptr)[0]), pool, 1, DN_ZMem_Yes) - #define DN_PArrayMakePoolNoZ(ptr, ptr_size, max, pool) (DN_CppDeclType(&(ptr)[0]))DN_ArrayMakeArrayPool((void **)&(ptr), ptr_size, max, sizeof((ptr)[0]), pool, 1, DN_ZMem_No) + #define DN_PArrayMake(ptr, ptr_size, max, z_mem) (DN_CppDeclType(&(ptr)[0]))DN_ArrayMakeArray(ptr, ptr_size, max, sizeof((ptr)[0]), 1, z_mem) + #define DN_PArrayMakeZ(ptr, ptr_size, max) (DN_CppDeclType(&(ptr)[0]))DN_ArrayMakeArray(ptr, ptr_size, max, sizeof((ptr)[0]), 1, DN_ZMem_Yes) + #define DN_PArrayMakeNoZ(ptr, ptr_size, max) (DN_CppDeclType(&(ptr)[0]))DN_ArrayMakeArray(ptr, ptr_size, max, sizeof((ptr)[0]), 1, DN_ZMem_No) + #define DN_PArrayMakeAssert(ptr, ptr_size, max, z_mem) (DN_CppDeclType(&(ptr)[0]))DN_ArrayMakeArrayAssert(ptr, ptr_size, max, sizeof((ptr)[0]), 1, z_mem, DN_CallSiteNow) + #define DN_PArrayMakeAssertZ(ptr, ptr_size, max) (DN_CppDeclType(&(ptr)[0]))DN_ArrayMakeArrayAssert(ptr, ptr_size, max, sizeof((ptr)[0]), 1, DN_ZMem_Yes, DN_CallSiteNow) + #define DN_PArrayMakeAssertNoZ(ptr, ptr_size, max) (DN_CppDeclType(&(ptr)[0]))DN_ArrayMakeArrayAssert(ptr, ptr_size, max, sizeof((ptr)[0]), 1, DN_ZMem_No, DN_CallSiteNow) + #define DN_PArrayMakeArena(ptr, ptr_size, max, arena, z_mem) (DN_CppDeclType(&(ptr)[0]))DN_ArrayMakeArrayAllocator((void **)&(ptr), ptr_size, max, sizeof((ptr)[0]), DN_AllocatorFromArena(arena), 1, z_mem) + #define DN_PArrayMakeArenaZ(ptr, ptr_size, max, arena) (DN_CppDeclType(&(ptr)[0]))DN_ArrayMakeArrayAllocator((void **)&(ptr), ptr_size, max, sizeof((ptr)[0]), DN_AllocatorFromArena(arena), 1, DN_ZMem_Yes) + #define DN_PArrayMakeArenaNoZ(ptr, ptr_size, max, arena) (DN_CppDeclType(&(ptr)[0]))DN_ArrayMakeArrayAllocator((void **)&(ptr), ptr_size, max, sizeof((ptr)[0]), DN_AllocatorFromArena(arena), 1, DN_ZMem_No) + #define DN_PArrayMakePool(ptr, ptr_size, max, pool, z_mem) (DN_CppDeclType(&(ptr)[0]))DN_ArrayMakeArrayAllocator((void **)&(ptr), ptr_size, max, sizeof((ptr)[0]), DN_AllocatorFromPool(pool), 1, z_mem) + #define DN_PArrayMakePoolZ(ptr, ptr_size, max, pool) (DN_CppDeclType(&(ptr)[0]))DN_ArrayMakeArrayAllocator((void **)&(ptr), ptr_size, max, sizeof((ptr)[0]), DN_AllocatorFromPool(pool), 1, DN_ZMem_Yes) + #define DN_PArrayMakePoolNoZ(ptr, ptr_size, max, pool) (DN_CppDeclType(&(ptr)[0]))DN_ArrayMakeArrayAllocator((void **)&(ptr), ptr_size, max, sizeof((ptr)[0]), DN_AllocatorFromPool(pool), 1, DN_ZMem_No) + #define DN_PArrayMakeHeap(ptr, ptr_size, max, heap, z_mem) (DN_CppDeclType(&(ptr)[0]))DN_ArrayMakeArrayAllocator((void **)&(ptr), ptr_size, max, sizeof((ptr)[0]), DN_AllocatorFromHeap(heap), 1, z_mem) + #define DN_PArrayMakeHeapZ(ptr, ptr_size, max, heap) (DN_CppDeclType(&(ptr)[0]))DN_ArrayMakeArrayAllocator((void **)&(ptr), ptr_size, max, sizeof((ptr)[0]), DN_AllocatorFromHeap(heap), 1, DN_ZMem_Yes) + #define DN_PArrayMakeHeapNoZ(ptr, ptr_size, max, heap) (DN_CppDeclType(&(ptr)[0]))DN_ArrayMakeArrayAllocator((void **)&(ptr), ptr_size, max, sizeof((ptr)[0]), DN_AllocatorFromHeap(heap), 1, DN_ZMem_No) - #define DN_PArrayAddArray(ptr, ptr_size, max, items, count, add) (DN_CppDeclType(&(ptr)[0]))DN_ArrayAddArray(ptr, ptr_size, max, sizeof((ptr)[0]), items, count, add) - #define DN_PArrayAddArrayArena(ptr, ptr_size, max, arena, items, count, add) (DN_CppDeclType(&(ptr)[0]))DN_ArrayAddArrayArena((void **)&(ptr), ptr_size, max, sizeof((ptr)[0]), arena, items, count, add) - #define DN_PArrayAddArrayPool(ptr, ptr_size, max, pool, items, count, add) (DN_CppDeclType(&(ptr)[0]))DN_ArrayAddArrayPool((void **)&(ptr), ptr_size, max, sizeof((ptr)[0]), pool, items, count, add) - #define DN_PArrayAdd(ptr, ptr_size, max, item, add) (DN_CppDeclType(&(ptr)[0]))DN_ArrayAddArray(ptr, ptr_size, max, sizeof((ptr)[0]), &item, 1, add) - #define DN_PArrayAddArena(ptr, ptr_size, max, arena, item, add) (DN_CppDeclType(&(ptr)[0]))DN_ArrayAddArrayArena((void **)&(ptr), ptr_size, max, sizeof((ptr)[0]), arena, &item, 1, add) - #define DN_PArrayAddPool(ptr, ptr_size, max, pool, item, add) (DN_CppDeclType(&(ptr)[0]))DN_ArrayAddArrayPool((void **)&(ptr), ptr_size, max, sizeof((ptr)[0]), pool, &item, 1, add) - #define DN_PArrayAppendArray(ptr, ptr_size, max, items, count) (DN_CppDeclType(&(ptr)[0]))DN_ArrayAddArray(ptr, ptr_size, max, sizeof((ptr)[0]), items, count, DN_AddType_Append) - #define DN_PArrayAppend(ptr, ptr_size, max, item) (DN_CppDeclType(&(ptr)[0]))DN_ArrayAddArray(ptr, ptr_size, max, sizeof((ptr)[0]), &item, 1, DN_AddType_Append) - #define DN_PArrayAppendArena(ptr, ptr_size, max, arena, item) (DN_CppDeclType(&(ptr)[0]))DN_ArrayAddArrayArena((void **)&(ptr), ptr_size, max, sizeof((ptr)[0]), arena, &item, 1, DN_AddType_Append) - #define DN_PArrayAppendPool(ptr, ptr_size, max, pool, item) (DN_CppDeclType(&(ptr)[0]))DN_ArrayAddArrayPool((void **)&(ptr), ptr_size, max, sizeof((ptr)[0]), pool, &item, 1, DN_AddType_Append) - #define DN_PArrayAppendAssert(ptr, ptr_size, max, item) (DN_CppDeclType(&(ptr)[0]))DN_ArrayAddArrayAssert(ptr, ptr_size, max, sizeof((ptr)[0]), &item, 1, DN_AddType_Append, DN_CallSiteNow) - #define DN_PArrayPrependArray(ptr, ptr_size, max, items, count) (DN_CppDeclType(&(ptr)[0]))DN_ArrayAddArray(ptr, ptr_size, max, sizeof((ptr)[0]), items, count, DN_AddType_Prepend) - #define DN_PArrayPrepend(ptr, ptr_size, max, item) (DN_CppDeclType(&(ptr)[0]))DN_ArrayAddArray(ptr, ptr_size, max, sizeof((ptr)[0]), &item, 1, DN_AddType_Prepend) - #define DN_PArrayPrependArena(ptr, ptr_size, max, arena, item) (DN_CppDeclType(&(ptr)[0]))DN_ArrayAddArrayArena((void **)&(ptr), ptr_size, max, sizeof((ptr)[0]), arena, &item, 1, DN_AddType_Prepend) - #define DN_PArrayPrependPool(ptr, ptr_size, max, pool, item) (DN_CppDeclType(&(ptr)[0]))DN_ArrayAddArrayPool((void **)&(ptr), ptr_size, max, sizeof((ptr)[0]), pool, &item, 1, DN_AddType_Prepend) + #define DN_PArrayAddArray(ptr, ptr_size, max, items, count, add) (DN_CppDeclType(&(ptr)[0]))DN_ArrayAddArray(ptr, ptr_size, max, sizeof((ptr)[0]), items, count, add) + #define DN_PArrayAddArrayArena(ptr, ptr_size, max, arena, items, count, add) (DN_CppDeclType(&(ptr)[0]))DN_ArrayAddArrayAllocator((void **)&(ptr), ptr_size, max, sizeof((ptr)[0]), DN_AllocatorFromArena(arena), items, count, add) + #define DN_PArrayAddArrayPool(ptr, ptr_size, max, pool, items, count, add) (DN_CppDeclType(&(ptr)[0]))DN_ArrayAddArrayAllocator((void **)&(ptr), ptr_size, max, sizeof((ptr)[0]), DN_AllocatorFromPool(pool), items, count, add) + #define DN_PArrayAddArrayHeap(ptr, ptr_size, max, heap, items, count, add) (DN_CppDeclType(&(ptr)[0]))DN_ArrayAddArrayAllocator((void **)&(ptr), ptr_size, max, sizeof((ptr)[0]), DN_AllocatorFromHeap(heap), items, count, add) + #define DN_PArrayAdd(ptr, ptr_size, max, item, add) (DN_CppDeclType(&(ptr)[0]))DN_ArrayAddArray(ptr, ptr_size, max, sizeof((ptr)[0]), &item, 1, add) + #define DN_PArrayAddArena(ptr, ptr_size, max, arena, item, add) (DN_CppDeclType(&(ptr)[0]))DN_ArrayAddArrayAllocator((void **)&(ptr), ptr_size, max, sizeof((ptr)[0]), DN_AllocatorFromArena(arena), &item, 1, add) + #define DN_PArrayAddPool(ptr, ptr_size, max, pool, item, add) (DN_CppDeclType(&(ptr)[0]))DN_ArrayAddArrayAllocator((void **)&(ptr), ptr_size, max, sizeof((ptr)[0]), DN_AllocatorFromPool(pool), &item, 1, add) + #define DN_PArrayAddHeap(ptr, ptr_size, max, heap, item, add) (DN_CppDeclType(&(ptr)[0]))DN_ArrayAddArrayAllocator((void **)&(ptr), ptr_size, max, sizeof((ptr)[0]), DN_AllocatorFromHeap(heap), &item, 1, add) + #define DN_PArrayAppendArray(ptr, ptr_size, max, items, count) (DN_CppDeclType(&(ptr)[0]))DN_ArrayAddArray(ptr, ptr_size, max, sizeof((ptr)[0]), items, count, DN_AddType_Append) + #define DN_PArrayAppend(ptr, ptr_size, max, item) (DN_CppDeclType(&(ptr)[0]))DN_ArrayAddArray(ptr, ptr_size, max, sizeof((ptr)[0]), &item, 1, DN_AddType_Append) + #define DN_PArrayAppendArena(ptr, ptr_size, max, arena, item) (DN_CppDeclType(&(ptr)[0]))DN_ArrayAddArrayAllocator((void **)&(ptr), ptr_size, max, sizeof((ptr)[0]), DN_AllocatorFromArena(arena), &item, 1, DN_AddType_Append) + #define DN_PArrayAppendPool(ptr, ptr_size, max, pool, item) (DN_CppDeclType(&(ptr)[0]))DN_ArrayAddArrayAllocator((void **)&(ptr), ptr_size, max, sizeof((ptr)[0]), DN_AllocatorFromPool(pool), &item, 1, DN_AddType_Append) + #define DN_PArrayAppendHeap(ptr, ptr_size, max, heap, item) (DN_CppDeclType(&(ptr)[0]))DN_ArrayAddArrayAllocator((void **)&(ptr), ptr_size, max, sizeof((ptr)[0]), DN_AllocatorFromHeap(heap), &item, 1, DN_AddType_Append) + #define DN_PArrayAppendAssert(ptr, ptr_size, max, item) (DN_CppDeclType(&(ptr)[0]))DN_ArrayAddArrayAssert(ptr, ptr_size, max, sizeof((ptr)[0]), &item, 1, DN_AddType_Append, DN_CallSiteNow) + #define DN_PArrayPrependArray(ptr, ptr_size, max, items, count) (DN_CppDeclType(&(ptr)[0]))DN_ArrayAddArray(ptr, ptr_size, max, sizeof((ptr)[0]), items, count, DN_AddType_Prepend) + #define DN_PArrayPrepend(ptr, ptr_size, max, item) (DN_CppDeclType(&(ptr)[0]))DN_ArrayAddArray(ptr, ptr_size, max, sizeof((ptr)[0]), &item, 1, DN_AddType_Prepend) + #define DN_PArrayPrependArena(ptr, ptr_size, max, arena, item) (DN_CppDeclType(&(ptr)[0]))DN_ArrayAddArrayAllocator((void **)&(ptr), ptr_size, max, sizeof((ptr)[0]), DN_AllocatorFromArena(arena), &item, 1, DN_AddType_Prepend) + #define DN_PArrayPrependPool(ptr, ptr_size, max, pool, item) (DN_CppDeclType(&(ptr)[0]))DN_ArrayAddArrayAllocator((void **)&(ptr), ptr_size, max, sizeof((ptr)[0]), DN_AllocatorFromPool(pool), &item, 1, DN_AddType_Prepend) + #define DN_PArrayPrependHeap(ptr, ptr_size, max, heap, item) (DN_CppDeclType(&(ptr)[0]))DN_ArrayAddArrayAllocator((void **)&(ptr), ptr_size, max, sizeof((ptr)[0]), DN_AllocatorFromHeap(heap), &item, 1, DN_AddType_Prepend) - #define DN_PArrayEraseRange(ptr, ptr_size, begin_index, count, erase) DN_ArrayEraseRange(ptr, ptr_size, sizeof((ptr)[0]), begin_index, count, erase) - #define DN_PArrayErase(ptr, ptr_size, index, erase) DN_ArrayEraseRange(ptr, ptr_size, sizeof((ptr)[0]), index, 1, erase) - #define DN_PArrayInsertArray(ptr, ptr_size, max, index, items, count) (DN_CppDeclType(&(ptr)[0]))DN_ArrayInsertArray(ptr, ptr_size, max, sizeof((ptr)[0]), index, items, count) - #define DN_PArrayInsert(ptr, ptr_size, max, index, item) (DN_CppDeclType(&(ptr)[0]))DN_ArrayInsertArray(ptr, ptr_size, max, sizeof((ptr)[0]), index, &item, 1) - #define DN_PArrayPopFront(ptr, ptr_size, max, count) (DN_CppDeclType(&(ptr)[0]))DN_ArrayPopFront(ptr, ptr_size, sizeof((ptr)[0]), count) - #define DN_PArrayPopBack(ptr, ptr_size, max, count) (DN_CppDeclType(&(ptr)[0]))DN_ArrayPopBack(ptr, ptr_size, sizeof((ptr)[0]), count) + #define DN_PArrayEraseRange(ptr, ptr_size, begin_index, count, erase) DN_ArrayEraseRange(ptr, ptr_size, sizeof((ptr)[0]), begin_index, count, erase) + #define DN_PArrayErase(ptr, ptr_size, index, erase) DN_ArrayEraseRange(ptr, ptr_size, sizeof((ptr)[0]), index, 1, erase) + #define DN_PArrayInsertArray(ptr, ptr_size, max, index, items, count) (DN_CppDeclType(&(ptr)[0]))DN_ArrayInsertArray(ptr, ptr_size, max, sizeof((ptr)[0]), index, items, count) + #define DN_PArrayInsert(ptr, ptr_size, max, index, item) (DN_CppDeclType(&(ptr)[0]))DN_ArrayInsertArray(ptr, ptr_size, max, sizeof((ptr)[0]), index, &item, 1) + #define DN_PArrayPopFront(ptr, ptr_size, max, count) (DN_CppDeclType(&(ptr)[0]))DN_ArrayPopFront(ptr, ptr_size, sizeof((ptr)[0]), count) + #define DN_PArrayPopBack(ptr, ptr_size, max, count) (DN_CppDeclType(&(ptr)[0]))DN_ArrayPopBack(ptr, ptr_size, sizeof((ptr)[0]), count) #endif #define DN_LArrayFind(c_array, size, ptr_find, eq_func) DN_PArrayFind(c_array, size, ptr_find, eq_func) @@ -6375,14 +6623,19 @@ DN_API DN_RaycastV2 DN_RaycastLineIntersectV2 #define DN_IArrayFindMemEq(ptr_array, ptr_find) DN_PArrayFindMemEq((ptr_array)->data, (ptr_array)->count, ptr_find) #define DN_IArrayResizePool(ptr_array, pool, new_max) DN_PArrayResizePool((ptr_array)->data, &(ptr_array)->count, &(ptr_array)->max, pool, new_max) #define DN_IArrayResizeArena(ptr_array, arena, new_max) DN_PArrayResizeArena((ptr_array)->data, &(ptr_array)->count, &(ptr_array)->max, arena, new_max) +#define DN_IArrayResizeHeap(ptr_array, heap, new_max) DN_PArrayResizeHeap((ptr_array)->data, &(ptr_array)->count, &(ptr_array)->max, heap, new_max) #define DN_IArrayReservePool(ptr_array, pool, new_max) DN_PArrayReservePool((ptr_array)->data, &(ptr_array)->max, pool, new_max) #define DN_IArrayReserveArena(ptr_array, arena, new_max) DN_PArrayReserveArena((ptr_array)->data, &(ptr_array)->max, arena, new_max) +#define DN_IArrayReserveHeap(ptr_array, heap, new_max) DN_PArrayReserveHeap((ptr_array)->data, &(ptr_array)->max, heap, new_max) #define DN_IArrayPreparePool(ptr_array, pool, add_count) DN_PArrayPreparePool(&(ptr_array)->data, (ptr_array)->count, &(ptr_array)->max, pool, add_count) #define DN_IArrayPrepareArena(ptr_array, arena, add_count) DN_PArrayPrepareArena(&(ptr_array)->data, (ptr_array)->count, &(ptr_array)->max, arena, add_count) -#define DN_IArrayCopyPtrPool(ptr_array, src, count_, pool) (ptr_array)->max = (ptr_array)->count = DN_PArrayCopyPtrPool((ptr_array), src, count_, pool) -#define DN_IArrayCopyPtrPoolAssert(ptr_array, src, count_, pool) (ptr_array)->max = (ptr_array)->count = DN_PArrayCopyPtrPoolAssert((ptr_array), src, count_, pool) -#define DN_IArrayCopyPtrArena(ptr_array, src, count_, arena) (ptr_array)->max = (ptr_array)->count = DN_PArrayCopyPtrArena((ptr_array), src, count_, arena) -#define DN_IArrayCopyPtrArenaAssert(ptr_array, src, count_, arena) (ptr_array)->max = (ptr_array)->count = DN_PArrayCopyPtrArenaAssert((ptr_array), src, count_, arena) +#define DN_IArrayPrepareHeap(ptr_array, heap, add_count) DN_PArrayPrepareHeap(&(ptr_array)->data, (ptr_array)->count, &(ptr_array)->max, heap, add_count) +#define DN_IArrayCopyPtrPool(ptr_array, src, count_, pool) (ptr_array)->max = (ptr_array)->count = DN_PArrayCopyPtrPool((ptr_array)->data, src, count_, pool) +#define DN_IArrayCopyPtrPoolAssert(ptr_array, src, count_, pool) (ptr_array)->max = (ptr_array)->count = DN_PArrayCopyPtrPoolAssert((ptr_array)->data, src, count_, pool) +#define DN_IArrayCopyPtrArena(ptr_array, src, count_, arena) (ptr_array)->max = (ptr_array)->count = DN_PArrayCopyPtrArena((ptr_array)->data, src, count_, arena) +#define DN_IArrayCopyPtrArenaAssert(ptr_array, src, count_, arena) (ptr_array)->max = (ptr_array)->count = DN_PArrayCopyPtrArenaAssert((ptr_array)->data, src, count_, arena) +#define DN_IArrayCopyPtrHeap(ptr_array, src, count_, heap) (ptr_array)->max = (ptr_array)->count = DN_PArrayCopyPtrHeap((ptr_array)->data, src, count_, heap) +#define DN_IArrayCopyPtrHeapAssert(ptr_array, src, count_, heap) (ptr_array)->max = (ptr_array)->count = DN_PArrayCopyPtrHeapAssert((ptr_array)->data, src, count_, heap) #define DN_IArrayMakeArray(ptr_array, count_, z_mem) DN_PArrayMakeArray((ptr_array)->data, &(ptr_array)->count, (ptr_array)->max, count_, z_mem) #define DN_IArrayMakeArrayZ(ptr_array, count_) DN_PArrayMakeArrayZ((ptr_array)->data, &(ptr_array)->count, (ptr_array)->max, count_) @@ -6396,6 +6649,9 @@ DN_API DN_RaycastV2 DN_RaycastLineIntersectV2 #define DN_IArrayMakeArrayPool(ptr_array, pool, count_, z_mem) DN_PArrayMakeArrayPool((ptr_array)->data, &(ptr_array)->count, &(ptr_array)->max, pool, count_, z_mem) #define DN_IArrayMakeArrayPoolZ(ptr_array, pool, count_) DN_PArrayMakeArrayPoolZ((ptr_array)->data, &(ptr_array)->count, &(ptr_array)->max, pool, count_) #define DN_IArrayMakeArrayPoolNoZ(ptr_array, pool, count_) DN_PArrayMakeArrayPoolNoZ((ptr_array)->data, &(ptr_array)->count, &(ptr_array)->max, pool, count_) +#define DN_IArrayMakeArrayHeap(ptr_array, heap, count_, z_mem) DN_PArrayMakeArrayHeap((ptr_array)->data, &(ptr_array)->count, &(ptr_array)->max, heap, count_, z_mem) +#define DN_IArrayMakeArrayHeapZ(ptr_array, heap, count_) DN_PArrayMakeArrayHeapZ((ptr_array)->data, &(ptr_array)->count, &(ptr_array)->max, heap, count_) +#define DN_IArrayMakeArrayHeapNoZ(ptr_array, heap, count_) DN_PArrayMakeArrayHeapNoZ((ptr_array)->data, &(ptr_array)->count, &(ptr_array)->max, heap, count_) #define DN_IArrayMake(ptr_array, z_mem) DN_PArrayMake((ptr_array)->data, &(ptr_array)->count, (ptr_array)->max, z_mem) #define DN_IArrayMakeZ(ptr_array) DN_PArrayMakeZ((ptr_array)->data, &(ptr_array)->count, (ptr_array)->max) @@ -6409,23 +6665,29 @@ DN_API DN_RaycastV2 DN_RaycastLineIntersectV2 #define DN_IArrayMakePool(ptr_array, pool, z_mem) DN_PArrayMakePool((ptr_array)->data, &(ptr_array)->count, &(ptr_array)->max, pool, z_mem) #define DN_IArrayMakePoolZ(ptr_array, pool) DN_PArrayMakePoolZ((ptr_array)->data, &(ptr_array)->count, &(ptr_array)->max, pool) #define DN_IArrayMakePoolNoZ(ptr_array, pool) DN_PArrayMakePoolNoZ((ptr_array)->data, &(ptr_array)->count, &(ptr_array)->max, pool) -#define DN_IArrayMakeNoZ(ptr_array) DN_PArrayMakeNoZ((ptr_array)->data, &(ptr_array)->count, (ptr_array)->max) +#define DN_IArrayMakeHeap(ptr_array, heap, z_mem) DN_PArrayMakeHeap((ptr_array)->data, &(ptr_array)->count, &(ptr_array)->max, heap, z_mem) +#define DN_IArrayMakeHeapZ(ptr_array, heap) DN_PArrayMakeHeapZ((ptr_array)->data, &(ptr_array)->count, &(ptr_array)->max, heap) +#define DN_IArrayMakeHeapNoZ(ptr_array, heap) DN_PArrayMakeHeapNoZ((ptr_array)->data, &(ptr_array)->count, &(ptr_array)->max, heap) #define DN_IArrayAddArray(ptr_array, items, count_, add) DN_PArrayAddArray((ptr_array)->data, &(ptr_array)->count, (ptr_array)->max, items, count_, add) #define DN_IArrayAddArrayArena(ptr_array, arena, items, count_, add) DN_PArrayAddArrayArena((ptr_array)->data, &(ptr_array)->count, &(ptr_array)->max, arena, items, count_, add) #define DN_IArrayAddArrayPool(ptr_array, pool, items, count_, add) DN_PArrayAddArrayPool((ptr_array)->data, &(ptr_array)->count, &(ptr_array)->max, pool, items, count_, add) +#define DN_IArrayAddArrayHeap(ptr_array, heap, items, count_, add) DN_PArrayAddArrayHeap((ptr_array)->data, &(ptr_array)->count, &(ptr_array)->max, heap, items, count_, add) #define DN_IArrayAdd(ptr_array, item, add) DN_PArrayAdd((ptr_array)->data, &(ptr_array)->count, (ptr_array)->max, item, add) #define DN_IArrayAddArena(ptr_array, arena, item, add) DN_PArrayAddArena((ptr_array)->data, &(ptr_array)->count, &(ptr_array)->max, arena, item, add) #define DN_IArrayAddPool(ptr_array, pool, item, add) DN_PArrayAddPool((ptr_array)->data, &(ptr_array)->count, &(ptr_array)->max, pool, item, add) +#define DN_IArrayAddHeap(ptr_array, heap, item, add) DN_PArrayAddHeap((ptr_array)->data, &(ptr_array)->count, &(ptr_array)->max, heap, item, add) #define DN_IArrayAppendArray(ptr_array, items, count_) DN_PArrayAppendArray((ptr_array)->data, &(ptr_array)->count, (ptr_array)->max, items, count_) #define DN_IArrayAppend(ptr_array, item) DN_PArrayAppend((ptr_array)->data, &(ptr_array)->count, (ptr_array)->max, item) #define DN_IArrayAppendArena(ptr_array, arena, item) DN_PArrayAppendArena((ptr_array)->data, &(ptr_array)->count, &(ptr_array)->max, arena, item) #define DN_IArrayAppendPool(ptr_array, pool, item) DN_PArrayAppendPool((ptr_array)->data, &(ptr_array)->count, &(ptr_array)->max, pool, item) +#define DN_IArrayAppendHeap(ptr_array, heap, item) DN_PArrayAppendHeap((ptr_array)->data, &(ptr_array)->count, &(ptr_array)->max, heap, item) #define DN_IArrayAppendAssert(ptr_array, item) DN_PArrayAppendAssert((ptr_array)->data, &(ptr_array)->count, (ptr_array)->max, item) #define DN_IArrayPrependArray(ptr_array, items, count_) DN_PArrayPrependArray((ptr_array)->data, &(ptr_array)->count, (ptr_array)->max, items, count_) #define DN_IArrayPrepend(ptr_array, item) DN_PArrayPrepend((ptr_array)->data, &(ptr_array)->count, (ptr_array)->max, item) #define DN_IArrayPrependArena(ptr_array, arena, item) DN_PArrayPrependArena((ptr_array)->data, &(ptr_array)->count, &(ptr_array)->max, arena, item) #define DN_IArrayPrependPool(ptr_array, pool, item) DN_PArrayPrependPool((ptr_array)->data, &(ptr_array)->count, &(ptr_array)->max, pool, item) +#define DN_IArrayPrependHeap(ptr_array, heap, item) DN_PArrayPrependHeap((ptr_array)->data, &(ptr_array)->count, &(ptr_array)->max, heap, item) #define DN_IArrayEraseRange(ptr_array, begin_index, count_, erase) DN_PArrayEraseRange((ptr_array)->data, &(ptr_array)->count, begin_index, count_, erase) #define DN_IArrayErase(ptr_array, index, erase) DN_PArrayErase((ptr_array)->data, &(ptr_array)->count, index, erase) #define DN_IArrayInsertArray(ptr_array, index, items, count_) DN_PArrayInsertArray((ptr_array)->data, &(ptr_array)->count, (ptr_array)->max, index, items, count_) @@ -6433,17 +6695,13 @@ DN_API DN_RaycastV2 DN_RaycastLineIntersectV2 #define DN_IArrayPopFront(ptr_array, count_) DN_PArrayPopFront((ptr_array)->data, &(ptr_array)->count, (ptr_array)->max, count_) #define DN_IArrayPopBack(ptr_array, count_) DN_PArrayPopBack((ptr_array)->data, &(ptr_array)->count, (ptr_array)->max, count_) -// NOTE: Slices -// -// Fixed size container allocated up front that have a `T *data` and `DN_USize count` elements. -// -// API -// AllocArena: Allocates the container with the requested `count` elements -// -#define DN_ISliceAllocArena(slice_ptr, count_, zmem, arena) (DN_CppDeclType(&((slice_ptr)->data[0])))DN_SliceAllocArena((void **)&((slice_ptr)->data), &((slice_ptr)->count), count_, sizeof((slice_ptr)->data[0]), alignof(DN_CppDeclType((slice_ptr)->data[0])), zmem, arena) - - -DN_API void* DN_SliceAllocArena (void **data, DN_USize *slice_size_field, DN_USize count, DN_USize elem_size, DN_U8 align, DN_ZMem zmem, DN_Arena *arena); +#define DN_CArraySet(dest_array, src_item) for (DN_USize index = 0; index < DN_ArrayCountU(dest_array); index++) { (dest_array)[index] = (src_item); } +#define DN_CArrayZero(dest_array) DN_Memset(dest_array, 0, sizeof(dest_array[0]) * DN_ArrayCountU(dest_array)) +#define DN_CArrayCopy(dest_array, src_array) do { \ + DN_StaticTypeEq((dest_array)[0], (src_array)[0]); \ + DN_StaticAssert(DN_ArrayCountU(dest_array) == DN_ArrayCountU(src_array)); \ + DN_Memcpy((dest_array), (src_array), sizeof((dest_array)[0]) * DN_ArrayCountU(dest_array)); \ + } while (0) DN_API DN_ArrayFindResult DN_ArrayFind (void *data, DN_USize count, DN_USize elem_size, void const *find, DN_ArrayFindEqFunc *eq_func); DN_API DN_ArrayFindResult DN_ArrayFindMemEq (void *data, DN_USize count, DN_USize elem_size, void const *find); @@ -6453,22 +6711,15 @@ DN_API void* DN_ArrayPopBack (void * DN_API DN_ArrayEraseResult DN_ArrayEraseRange (void *data, DN_USize *count, DN_USize elem_size, DN_USize begin_index, DN_ISize erase_count, DN_ArrayErase erase); DN_API void* DN_ArrayMakeArray (void *data, DN_USize *count, DN_USize max, DN_USize elem_size, DN_USize make_count, DN_ZMem z_mem); DN_API void* DN_ArrayMakeArrayAssert (void *data, DN_USize *count, DN_USize max, DN_USize elem_size, DN_USize make_count, DN_ZMem z_mem, DN_CallSite call_site); -DN_API void* DN_ArrayMakeArrayArena (void **data, DN_USize *count, DN_USize *max, DN_USize elem_size, DN_Arena *arena, DN_USize make_count, DN_ZMem z_mem); -DN_API void* DN_ArrayMakeArrayPool (void **data, DN_USize *count, DN_USize *max, DN_USize elem_size, DN_Pool *pool, DN_USize make_count, DN_ZMem z_mem); +DN_API void* DN_ArrayMakeArrayAllocator (void **data, DN_USize *count, DN_USize *max, DN_USize elem_size, DN_Allocator allocator, DN_USize make_count, DN_ZMem z_mem); DN_API void* DN_ArrayAddArray (void *data, DN_USize *count, DN_USize max, DN_USize elem_size, void const *elems, DN_USize elems_count, DN_AddType add); DN_API void* DN_ArrayAddArrayAssert (void *data, DN_USize *count, DN_USize max, DN_USize elem_size, void const *elems, DN_USize elems_count, DN_AddType add, DN_CallSite call_site); -DN_API void* DN_ArrayAddArrayArena (void **data, DN_USize *count, DN_USize *max, DN_USize elem_size, void const *elems, DN_USize elems_count, DN_Arena *arena, DN_AddType add); -DN_API void* DN_ArrayAddArrayPool (void **data, DN_USize *count, DN_USize *max, DN_USize elem_size, void const *elems, DN_USize elems_count, DN_Pool *pool, DN_AddType add); -DN_API bool DN_ArrayResizePool (void **data, DN_USize *count, DN_USize *max, DN_USize elem_size, DN_Pool *pool, DN_USize new_max); -DN_API bool DN_ArrayResizeArena (void **data, DN_USize *count, DN_USize *max, DN_USize elem_size, DN_Arena *arena, DN_USize new_max); -DN_API bool DN_ArrayReservePool (void **data, DN_USize *max, DN_USize elem_size, DN_Pool *pool, DN_USize new_max); -DN_API bool DN_ArrayReserveArena (void **data, DN_USize *max, DN_USize elem_size, DN_Arena *arena, DN_USize new_max); -DN_API bool DN_ArrayPreparePool (void **data, DN_USize count, DN_USize *max, DN_USize elem_size, DN_Pool *pool, DN_USize add_count); -DN_API bool DN_ArrayPrepareArena (void **data, DN_USize count, DN_USize *max, DN_USize elem_size, DN_Arena *arena, DN_USize add_count); -DN_API DN_USize DN_ArrayCopyPtrArena (void **data, void const *src, DN_USize count, DN_USize elem_size, DN_Arena *arena); -DN_API DN_USize DN_ArrayCopyPtrArenaAssert (void **data, void const *src, DN_USize count, DN_USize elem_size, DN_Arena *arena, DN_CallSite call_site); -DN_API DN_USize DN_ArrayCopyPtrPool (void **data, void const *src, DN_USize count, DN_USize elem_size, DN_Pool *pool); -DN_API DN_USize DN_ArrayCopyPtrPoolAssert (void **data, void const *src, DN_USize count, DN_USize elem_size, DN_Pool *pool, DN_CallSite call_site); +DN_API void* DN_ArrayAddArrayAllocator (void **data, DN_USize *count, DN_USize *max, DN_USize elem_size, DN_Allocator allocator, void const *elems, DN_USize elems_count, DN_AddType add); +DN_API bool DN_ArrayResizeAllocator (void **data, DN_USize *count, DN_USize *max, DN_USize elem_size, DN_Allocator allocator, DN_USize new_max); +DN_API bool DN_ArrayReserveAllocator (void **data, DN_USize *max, DN_USize elem_size, DN_Allocator allocator, DN_USize new_max); +DN_API bool DN_ArrayPrepareAllocator (void **data, DN_USize count, DN_USize *max, DN_USize elem_size, DN_Allocator allocator, DN_USize add_count); +DN_API DN_USize DN_ArrayCopyPtrAllocator (void **data, void const *src, DN_USize count, DN_USize elem_size, DN_Allocator allocator); +DN_API DN_USize DN_ArrayCopyPtrAllocatorAssert (void **data, void const *src, DN_USize count, DN_USize elem_size, DN_Allocator allocator, DN_CallSite call_site); #if defined (__cplusplus) template DN_ArrayFindResult DN_TArrayFind (T *data, DN_USize count, void const *find, DN_ArrayFindEqFunc *eq_func); @@ -6483,32 +6734,15 @@ template T* DN_TArrayMakeArrayAssertZ (T *dat template T* DN_TArrayMakeArrayAssertNoZ (T *data, DN_USize *count, DN_USize max, DN_USize make_count, DN_CallSite call_site); template T* DN_TArrayAddArray (T *data, DN_USize *count, DN_USize max, T const *elems, DN_USize elems_count, DN_AddType add); template T* DN_TArrayAddArrayAssert (T *data, DN_USize *count, DN_USize max, T const *elems, DN_USize elems_count, DN_AddType add, DN_CallSite call_site); -template T* DN_TArrayMakeArrayArena (T **data, DN_USize *count, DN_USize *max, DN_Arena *arena, DN_USize make_count, DN_ZMem z_mem); -template T* DN_TArrayMakeArrayArenaZ (T **data, DN_USize *count, DN_USize *max, DN_Arena *arena, DN_USize make_count); -template T* DN_TArrayMakeArrayArenaNoZ (T **data, DN_USize *count, DN_USize *max, DN_Arena *arena, DN_USize make_count); -template T* DN_TArrayMakeArrayPool (T **data, DN_USize *count, DN_USize *max, DN_Pool *pool, DN_USize make_count, DN_ZMem z_mem); -template T* DN_TArrayMakeArrayPoolZ (T **data, DN_USize *count, DN_USize *max, DN_Pool *pool, DN_USize make_count); -template T* DN_TArrayMakeArrayPoolNoZ (T **data, DN_USize *count, DN_USize *max, DN_Pool *pool, DN_USize make_count); -template T* DN_TArrayAddArrayArena (T **data, DN_USize *count, DN_USize *max, DN_Arena *arena, T const *elems, DN_USize elems_count, DN_AddType add); -template T* DN_TArrayAddArrayPool (T **data, DN_USize *count, DN_USize *max, DN_Pool *pool, T const *elems, DN_USize elems_count, DN_AddType add); -template T* DN_TArrayMakeArena (T **data, DN_USize *count, DN_USize *max, DN_Arena *arena, DN_ZMem z_mem); -template T* DN_TArrayMakeArenaZ (T **data, DN_USize *count, DN_USize *max, DN_Arena *arena); -template T* DN_TArrayMakeArenaNoZ (T **data, DN_USize *count, DN_USize *max, DN_Arena *arena); -template T* DN_TArrayMakePool (T **data, DN_USize *count, DN_USize *max, DN_Pool *pool, DN_ZMem z_mem); -template T* DN_TArrayMakePoolZ (T **data, DN_USize *count, DN_USize *max, DN_Pool *pool); -template T* DN_TArrayMakePoolNoZ (T **data, DN_USize *count, DN_USize *max, DN_Pool *pool); -template T* DN_TArrayAddArena (T **data, DN_USize *count, DN_USize *max, DN_Arena *arena, T const *elems, DN_USize elems_count, DN_AddType add); -template T* DN_TArrayAddPool (T **data, DN_USize *count, DN_USize *max, DN_Pool *pool, T const *elems, DN_USize elems_count, DN_AddType add); -template bool DN_TArrayResizePool (T **data, DN_USize *count, DN_USize *max, DN_Pool *pool, DN_USize new_max); -template bool DN_TArrayResizeArena (T **data, DN_USize *count, DN_USize *max, DN_Arena *arena, DN_USize new_max); -template bool DN_TArrayReservePool (T **data, DN_USize *max, DN_Pool *pool, DN_USize new_max); -template bool DN_TArrayReserveArena (T **data, DN_USize *max, DN_Pool *pool, DN_USize new_max); -template bool DN_TArrayPreparePool (T **data, DN_USize count, DN_USize *max, DN_Pool *pool, DN_USize add_count); -template bool DN_TArrayPrepareArena (T **data, DN_USize count, DN_USize *max, DN_Arena *pool, DN_USize add_count); -template DN_USize DN_TArrayCopyPtrArena (T **data, T const *src, DN_USize count, DN_Arena *arena); -template DN_USize DN_TArrayCopyPtrArenaAssert (T **data, T const *src, DN_USize count, DN_Arena *arena, DN_CallSite call_site); -template DN_USize DN_TArrayCopyPtrPool (T **data, T const *src, DN_USize count, DN_Pool *pool); -template DN_USize DN_TArrayCopyPtrPoolAssert (T **data, T const *src, DN_USize count, DN_Pool *pool, DN_CallSite call_site); +template T* DN_TArrayMakeArrayAllocator (T **data, DN_USize *count, DN_USize *max, DN_Allocator allocator, DN_USize make_count, DN_ZMem z_mem); +template T* DN_TArrayMakeArrayAllocatorZ (T **data, DN_USize *count, DN_USize *max, DN_Allocator allocator, DN_USize make_count); +template T* DN_TArrayMakeArrayAllocatorNoZ (T **data, DN_USize *count, DN_USize *max, DN_Allocator allocator, DN_USize make_count); +template T* DN_TArrayAddArrayAllocator (T **data, DN_USize *count, DN_USize *max, DN_Allocator allocator, T const *elems, DN_USize elems_count, DN_AddType add); +template bool DN_TArrayResizeAllocator (T **data, DN_USize *count, DN_USize *max, DN_Allocator allocator, DN_USize new_max); +template bool DN_TArrayReserveAllocator (T **data, DN_USize *max, DN_Allocator allocator, DN_USize new_max); +template bool DN_TArrayPrepareAllocator (T **data, DN_USize count, DN_USize *max, DN_Allocator allocator, DN_USize add_count); +template DN_USize DN_TArrayCopyPtrAllocator (T **data, T const *src, DN_USize count, DN_Allocator allocator); +template DN_USize DN_TArrayCopyPtrAllocatorAssert(T **data, T const *src, DN_USize count, DN_Allocator allocator, DN_CallSite call_site); #endif DN_API bool DN_RingHasSpace (DN_Ring const *ring, DN_U64 size); @@ -6599,12 +6833,12 @@ DN_API DN_U32 DN_HTableHashFuncMurmur3KeyStr8 (void const* key, DN_API bool DN_HTableKeyEqFuncMemcmp (void const* lhs, void const* rhs, DN_USize size); DN_API bool DN_HTableKeyEqFuncStr8Eq (void const* lhs, void const* rhs, DN_USize size); -#define DN_HTableInitArgsDefault(KeyValueT, kvs_ptr, HashField, KeyField, ValueField) DN_HTableInitArgsDefault_(DN_Cast(void **)&kvs_ptr, sizeof(*kvs_ptr), offsetof(KeyValueT, HashField), sizeof(kvs_ptr->KeyField), offsetof(KeyValueT, KeyField), sizeof(kvs_ptr->ValueField), offsetof(KeyValueT, ValueField)) -DN_API DN_HTableInitArgs DN_HTableInitArgsDefault_ (void** kvs, DN_USize size_of_kvs, DN_USize offset_of_hash, DN_USize size_of_key, DN_USize offset_of_key, DN_USize size_of_value, DN_USize offset_of_value); -DN_API DN_HTableInitResult DN_HTableInitHeap (DN_HTableInitArgs args, DN_Heap heap); -DN_API DN_HTable DN_HTableInitHeapAssert (DN_HTableInitArgs args, DN_Heap heap); -DN_API DN_HTableInitResult DN_HTableInitPool (DN_HTableInitArgs args, DN_Pool pool, DN_HTableDeallocPoolOnDeinit dealloc_pool); -DN_API DN_HTable DN_HTableInitPoolAssert (DN_HTableInitArgs args, DN_Pool pool, DN_HTableDeallocPoolOnDeinit dealloc_pool); +#define DN_HTableInitArgsDefault(KeyValueT, kvs_ptr, HashField, KeyField, ValueField) DN_HTableInitArgsDefaultRaw(DN_Cast(void **)&kvs_ptr, sizeof(*kvs_ptr), offsetof(KeyValueT, HashField), sizeof(kvs_ptr->KeyField), offsetof(KeyValueT, KeyField), sizeof(kvs_ptr->ValueField), offsetof(KeyValueT, ValueField)) +DN_API DN_HTableInitArgs DN_HTableInitArgsDefaultRaw (void** kvs, DN_USize size_of_kvs, DN_USize offset_of_hash, DN_USize size_of_key, DN_USize offset_of_key, DN_USize size_of_value, DN_USize offset_of_value); +DN_API DN_HTableInitResult DN_HTableInitHeap (DN_HTableInitArgs args, DN_Heap *heap); +DN_API DN_HTable DN_HTableInitHeapAssert (DN_HTableInitArgs args, DN_Heap *heap); +DN_API DN_HTableInitResult DN_HTableInitPool (DN_HTableInitArgs args, DN_Pool *pool, DN_HTableDeallocPoolOnDeinit dealloc_pool); +DN_API DN_HTable DN_HTableInitPoolAssert (DN_HTableInitArgs args, DN_Pool *pool, DN_HTableDeallocPoolOnDeinit dealloc_pool); DN_API void DN_HTableDeinit (DN_HTable* table); DN_API DN_HTableLookupResult DN_HTableLookup (DN_HTable const* table, void const* key, DN_HTableAllowTombstone allow_tombstone); @@ -6779,25 +7013,36 @@ DN_API DN_TestCore DN_TestSuite DN_API DN_MemDebuggerSnapshot DN_MemDebuggerSnapshotMake (DN_MemDebugger *debugger, DN_Arena *arena); DN_API bool DN_MemDebuggerSnapshotPtrDataQSortComparePtrLT (void const *lhs, void const *rhs, void*); -DN_API void DN_MemDebuggerAlloc_ (DN_MemDebugger *debugger, void *ptr, DN_USize size, bool alloc_can_leak, DN_CallSite call_site); +DN_API bool DN_MemDebuggerSnapshotPtrDataQSortCompareBytesLT (void const *lhs, void const *rhs, void *user_context); +DN_API bool DN_MemDebuggerSnapshotPtrDataQSortCompareBytesGT (void const *lhs, void const *rhs, void *user_context); +DN_API bool DN_MemDebuggerMemListSnapshotQSortCompareCommitGT (void const *lhs, void const *rhs, void *user_context); +DN_API bool DN_MemDebuggerMemListAllocQSortCompareAllocSizeGT (void const *lhs, void const *rhs, void *user_context); +DN_API void DN_MemDebuggerAlloc_ (DN_MemDebugger *debugger, void *ptr, DN_USize reserve, DN_USize commit, bool alloc_can_leak, DN_CallSite call_site); DN_API void DN_MemDebuggerDealloc_ (DN_MemDebugger *debugger, void *ptr); DN_API void DN_MemDebuggerDump_ (DN_MemDebugger *debugger); -#if defined(DN_MEM_DEBUGGER) -#define DN_MemDebuggerAlloc(debugger, ptr, size, alloc_can_leak, call_site) DN_MemDebuggerAlloc_(debugger, ptr, size, alloc_can_leak, call_site) -#define DN_MemDebuggerDealloc(debugger, ptr) DN_MemDebuggerDealloc_(debugger, ptr) -#define DN_MemDebuggerDump(debugger) DN_MemDebuggerDump_(debugger) +#if DN_MEM_DEBUGGER +#define DN_MemDebuggerAlloc(debugger, ptr, reserve, commit, alloc_can_leak, call_site) DN_MemDebuggerAlloc_(debugger, ptr, reserve, commit, alloc_can_leak, call_site) +#define DN_MemDebuggerDealloc(debugger, ptr) DN_MemDebuggerDealloc_(debugger, ptr) +#define DN_MemDebuggerDump(debugger) DN_MemDebuggerDump_(debugger) #else -#define DN_MemDebuggerAlloc(debugger, ptr, size, alloc_can_leak, call_site) do { (void)ptr; (void)size; (void)alloc_can_leak; } while (0) -#define DN_MemDebuggerDealloc(debugger, ptr) do { (void)ptr; } while (0) -#define DN_MemDebuggerDump(debugger) do { } while (0) +#define DN_MemDebuggerAlloc(debugger, ptr, reserve, commit, alloc_can_leak, call_site) do { (void)ptr; (void)reserve; (void)commit; (void)alloc_can_leak; } while (0) +#define DN_MemDebuggerDealloc(debugger, ptr) do { (void)ptr; } while (0) +#define DN_MemDebuggerDump(debugger) do { } while (0) #endif #if DN_WITH_OS -DN_API DN_Str8 DN_OS_Str8FromStr8BuilderHeap (DN_Str8Builder const *builder); -DN_API void DN_OS_LogPrintFV (DN_LogTypeParam type, void *user_data, DN_CallSite call_site, DN_LogFlags flags, DN_FMT_ATTRIB char const *fmt, va_list args); -DN_API void DN_OS_LogPrintF (DN_LogTypeParam type, void *user_data, DN_CallSite call_site, DN_LogFlags flags, DN_FMT_ATTRIB char const *fmt, ...); -DN_API void DN_OS_SetLogPrintFuncToOS (); +DN_API DN_Str8 DN_OS_Str8FromStackTraceNowHeap (DN_U16 limit, DN_U16 skip); +#else +#define DN_OS_Str8FromStackTraceNowHeap(...) {} +#endif + +#if DN_WITH_OS +DN_API DN_Str8 DN_OS_Str8FromStr8BuilderHeap (DN_Str8Builder const *builder); + +DN_API void DN_OS_LogPrintFV (DN_LogTypeParam type, void *user_data, DN_CallSite call_site, DN_LogFlags flags, DN_FMT_ATTRIB char const *fmt, va_list args); +DN_API void DN_OS_LogPrintF (DN_LogTypeParam type, void *user_data, DN_CallSite call_site, DN_LogFlags flags, DN_FMT_ATTRIB char const *fmt, ...); +DN_API void DN_OS_SetLogPrintFuncToOS (); // NOTE: Logger // Overview @@ -6884,24 +7129,27 @@ DN_API DN_U64 DN_OS_DateLocalUnixTimeSFromUnixTimeS DN_API void DN_OS_GenBytesSecure (void *buffer, DN_U32 size); DN_API bool DN_OS_SetEnvVar (DN_Str8 name, DN_Str8 value); DN_API DN_OSDiskSpace DN_OS_DiskSpace (DN_Str8 path); +DN_API DN_OSMemoryInfo DN_OS_MemoryInfo (); DN_API DN_Str8 DN_OS_ExePath (DN_Arena *arena); DN_API DN_Str8 DN_OS_ExeDir (DN_Arena *arena); -DN_API void DN_OS_OpenUrl (DN_Str8 url); +DN_API void DN_OS_OpenInDefaultApp (DN_Str8 url); DN_API void DN_OS_SleepMs (DN_UInt milliseconds); +DN_API bool DN_OS_OnceEveryS (DN_U64 *tsc, DN_U64 interval_s); DN_API DN_U64 DN_OS_PerfCounterNow (); DN_API DN_U64 DN_OS_PerfCounterFrequency (); -DN_API DN_F64 DN_OS_PerfCounterS (DN_U64 begin, uint64_t end); -DN_API DN_F64 DN_OS_PerfCounterMs (DN_U64 begin, uint64_t end); -DN_API DN_F64 DN_OS_PerfCounterUs (DN_U64 begin, uint64_t end); -DN_API DN_F64 DN_OS_PerfCounterNs (DN_U64 begin, uint64_t end); +DN_API DN_F64 DN_OS_PerfCounterS (DN_U64 begin, DN_U64 end); +DN_API DN_F64 DN_OS_PerfCounterMs (DN_U64 begin, DN_U64 end); +DN_API DN_F64 DN_OS_PerfCounterUs (DN_U64 begin, DN_U64 end); +DN_API DN_F64 DN_OS_PerfCounterNs (DN_U64 begin, DN_U64 end); + DN_API DN_OSTimer DN_OS_TimerBegin (); DN_API void DN_OS_TimerEnd (DN_OSTimer *timer); DN_API DN_F64 DN_OS_TimerS (DN_OSTimer timer); DN_API DN_F64 DN_OS_TimerMs (DN_OSTimer timer); DN_API DN_F64 DN_OS_TimerUs (DN_OSTimer timer); DN_API DN_F64 DN_OS_TimerNs (DN_OSTimer timer); -DN_API DN_U64 DN_OS_EstimateTscPerSecond (uint64_t duration_ms_to_gauge_tsc_frequency); +DN_API DN_U64 DN_OS_EstimateTscPerSecond (DN_U64 duration_ms_to_gauge_tsc_frequency); // NOTE: OS File // Overview @@ -6966,12 +7214,18 @@ DN_API bool DN_OS_FileWriteAllSafeF (D DN_API DN_Str8 DN_OS_Str8FromPathInfoType (DN_OSPathInfoType type); DN_API DN_OSPathInfo DN_OS_PathInfo (DN_Str8 path); +DN_API bool DN_OS_PathInfoFileHasChanged (DN_OSPathInfo lhs, DN_OSPathInfo rhs); DN_API bool DN_OS_PathIsOlderThan (DN_Str8 file, DN_Str8 check_against); -DN_API bool DN_OS_PathDelete (DN_Str8 path); +DN_API DN_OSPathResult DN_OS_PathCanonicalise (DN_Arena *arena, DN_Str8 path, DN_ErrSink *error); +DN_API DN_OSPathResult DN_OS_PathRelativeTo (DN_Arena *arena, DN_Str8 from, DN_Str8 to); +DN_API bool DN_OS_PathIsRelative (DN_Str8 path); DN_API bool DN_OS_PathIsFile (DN_Str8 path); DN_API bool DN_OS_PathIsDir (DN_Str8 path); +DN_API bool DN_OS_PathDelete (DN_Str8 path); DN_API bool DN_OS_PathMakeDir (DN_Str8 path); DN_API bool DN_OS_PathIterateDir (DN_Str8 path, DN_OSDirIterator *it); +DN_API bool DN_OS_PathWatchFileHasChanged (DN_OSPathWatchFile *watch, DN_Str8 path, DN_OSPathWatchFileAcceptChange accept); +DN_API void DN_OS_PathWatchFileAcceptChange (DN_OSPathWatchFile *watch); DN_API void DN_OS_Exit (int32_t exit_code); DN_API DN_OSExecArgs DN_OS_ExecArgsDefault (); @@ -7197,13 +7451,6 @@ DN_API void DN_OS_PrintLnFVStyle (DN_OSPrintDest dest, DN_LogStyle style, // NOTE: Template implementations #if defined(__cplusplus) -template T *DN_MemCopyObjT(T *dest, T const *src, DN_USize count) -{ - T* result = dest; - DN_Memcpy(dest, src, sizeof(T) * count); - return result; -} - template DN_ArrayFindResult DN_TArrayFind(T *data, DN_USize count, void const *find, DN_ArrayFindEqFunc *eq_func) { @@ -7289,189 +7536,69 @@ T *DN_TArrayAddArrayAssert(T *data, DN_USize *count, DN_USize max, T const *elem } template -T *DN_TArrayMakeArrayArena(T **data, DN_USize *count, DN_USize *max, DN_Arena *arena, DN_USize make_count, DN_ZMem z_mem) +T *DN_TArrayMakeArrayAllocator(T **data, DN_USize *count, DN_USize *max, DN_Allocator allocator, DN_USize make_count, DN_ZMem z_mem) { - T *result = DN_Cast(T *)DN_ArrayMakeArrayArena(DN_Cast(void **)data, count, max, sizeof(**data), arena, make_count, z_mem); + T *result = DN_Cast(T *)DN_ArrayMakeArrayAllocator(DN_Cast(void **)data, count, max, sizeof(**data), allocator, make_count, z_mem); return result; } template -T *DN_TArrayMakeArrayArenaZ(T **data, DN_USize *count, DN_USize *max, DN_Arena *arena, DN_USize make_count) +T *DN_TArrayMakeArrayAllocatorZ(T **data, DN_USize *count, DN_USize *max, DN_Allocator allocator, DN_USize make_count) { - T *result = DN_TArrayMakeArrayArena(data, count, max, arena, make_count, DN_ZMem_Yes); + T *result = DN_TArrayMakeArrayAllocator(data, count, max, allocator, make_count, DN_ZMem_Yes); return result; } template -T *DN_TArrayMakeArrayArenaNoZ(T **data, DN_USize *count, DN_USize *max, DN_Arena *arena, DN_USize make_count) +T *DN_TArrayMakeArrayAllocatorNoZ(T **data, DN_USize *count, DN_USize *max, DN_Allocator allocator, DN_USize make_count) { - T *result = DN_TArrayMakeArrayArena(data, count, max, arena, make_count, DN_ZMem_No); + T *result = DN_TArrayMakeArrayAllocator(data, count, max, allocator, make_count, DN_ZMem_No); return result; } template -T *DN_TArrayMakeArrayPool(T **data, DN_USize *count, DN_USize *max, DN_Pool *pool, DN_USize make_count, DN_ZMem z_mem) +T *DN_TArrayAddArrayAllocator(T **data, DN_USize *count, DN_USize *max, DN_Allocator allocator, T const *elems, DN_USize elems_count, DN_AddType add) { - T *result = DN_Cast(T *)DN_ArrayMakeArrayPool(DN_Cast(void **)data, count, max, sizeof(**data), pool, make_count, z_mem); + T *result = DN_Cast(T *)DN_ArrayAddArrayAllocator(DN_Cast(void **)data, count, max, sizeof(**data), allocator, elems, elems_count, add); return result; } template -T *DN_TArrayMakeArrayPoolZ(T **data, DN_USize *count, DN_USize *max, DN_Pool *pool, DN_USize make_count) +bool DN_TArrayResizeAllocator(T **data, DN_USize *count, DN_USize *max, DN_Allocator allocator, DN_USize new_max) { - T *result = DN_TArrayMakeArrayPool(data, count, max, pool, make_count, DN_ZMem_Yes); + bool result = DN_ArrayResizeAllocator(DN_Cast(void **)data, count, max, sizeof(**data), allocator, new_max); return result; } template -T *DN_TArrayMakeArrayPoolNoZ(T **data, DN_USize *count, DN_USize *max, DN_Pool *pool, DN_USize make_count) +bool DN_TArrayReserveAllocator(T **data, DN_USize *max, DN_Allocator allocator, DN_USize new_max) { - T *result = DN_TArrayMakeArrayPool(data, count, max, pool, make_count, DN_ZMem_No); + bool result = DN_ArrayReserveAllocator(DN_Cast(void **)data, max, sizeof(**data), allocator, new_max); return result; } template -T *DN_TArrayAddArrayArena(T **data, DN_USize *count, DN_USize *max, DN_Arena *arena, T const *elems, DN_USize elems_count, DN_AddType add) +bool DN_TArrayPrepareAllocator(T **data, DN_USize count, DN_USize *max, DN_Allocator allocator, DN_USize add_count) { - T *result = DN_Cast(T *)DN_ArrayAddArrayArena(DN_Cast(void **)data, count, max, sizeof(**data), arena, elems, elems_count, add); + bool result = DN_ArrayPrepareAllocator(DN_Cast(void **)data, count, max, sizeof(**data), allocator, add_count); return result; } template -T *DN_TArrayAddArrayPool(T **data, DN_USize *count, DN_USize *max, DN_Pool *pool, T const *elems, DN_USize elems_count, DN_AddType add) +DN_USize DN_TArrayCopyPtrAllocator(T **data, T const *src, DN_USize count, DN_Allocator allocator) { - T *result = DN_Cast(T *)DN_ArrayAddArrayPool(DN_Cast(void **)data, count, max, sizeof(**data), pool, elems, elems_count, add); + DN_USize result = DN_ArrayCopyPtrAllocator(DN_Cast(void **)data, src, count, sizeof(T), allocator); return result; } template -T *DN_TArrayMakeArena(T **data, DN_USize *count, DN_USize *max, DN_Arena *arena, DN_ZMem z_mem) +DN_USize DN_TArrayCopyPtrAllocatorAssert(T **data, T const *src, DN_USize count, DN_Allocator allocator, DN_CallSite call_site) { - T *result = DN_TArrayMakeArrayArena(data, count, max, arena, 1, z_mem); - return result; -} - -template -T *DN_TArrayMakeArenaZ(T **data, DN_USize *count, DN_USize *max, DN_Arena *arena) -{ - T *result = DN_TArrayMakeArrayArena(data, count, max, arena, 1, DN_ZMem_Yes); - return result; -} - -template -T *DN_TArrayMakeArenaNoZ(T **data, DN_USize *count, DN_USize *max, DN_Arena *arena) -{ - T *result = DN_TArrayMakeArrayArena(data, count, max, arena, 1, DN_ZMem_No); - return result; -} - -template -T *DN_TArrayMakePool(T **data, DN_USize *count, DN_USize *max, DN_Pool *pool, DN_ZMem z_mem) -{ - T *result = DN_TArrayMakeArrayPool(data, count, max, pool, 1, z_mem); - return result; -} - -template -T *DN_TArrayMakePoolZ(T **data, DN_USize *count, DN_USize *max, DN_Pool *pool) -{ - T *result = DN_TArrayMakeArrayPool(data, count, max, pool, 1, DN_ZMem_Yes); - return result; -} - -template -T *DN_TArrayMakePoolNoZ(T **data, DN_USize *count, DN_USize *max, DN_Pool *pool) -{ - T *result = DN_TArrayMakeArrayPool(data, count, max, pool, 1, DN_ZMem_No); - return result; -} - -template -T *DN_TArrayAddArena(T **data, DN_USize *count, DN_USize *max, DN_Arena *arena, T const *elems, DN_USize elems_count, DN_AddType add) -{ - T *result = DN_TArrayAddArrayArena(data, count, max, arena, elems, elems_count, add); - return result; -} - -template -T *DN_TArrayAddPool(T **data, DN_USize *count, DN_USize *max, DN_Pool *pool, T const *elems, DN_USize elems_count, DN_AddType add) -{ - T *result = DN_TArrayAddArrayPool(data, count, max, pool, elems, elems_count, add); - return result; -} - -template -bool DN_TArrayResizePool(T **data, DN_USize *count, DN_USize *max, DN_Pool *pool, DN_USize new_max) -{ - bool result = DN_ArrayResizePool(DN_Cast(void **)data, count, max, sizeof(**data), pool, new_max); - return result; -} - -template -bool DN_TArrayResizeArena(T **data, DN_USize *count, DN_USize *max, DN_Arena *arena, DN_USize new_max) -{ - bool result = DN_ArrayResizeArena(DN_Cast(void **)data, count, max, sizeof(**data), arena, new_max); - return result; -} - -template -bool DN_TArrayReservePool(T **data, DN_USize *max, DN_Pool *pool, DN_USize new_max) -{ - bool result = DN_ArrayReservePool(DN_Cast(void **)data, max, sizeof(**data), pool, new_max); - return result; -} - -template -bool DN_TArrayReserveArena(T **data, DN_USize *max, DN_Arena *arena, DN_USize new_max) -{ - bool result = DN_ArrayReserveArena(DN_Cast(void **)data, max, sizeof(**data), arena, new_max); - return result; -} - -template -bool DN_TArrayPreparePool(T **data, DN_USize count, DN_USize *max, DN_Pool *pool, DN_USize add_count) -{ - bool result = DN_ArrayPreparePool(DN_Cast(void **)data, count, max, sizeof(**data), pool, add_count); - return result; -} - -template -bool DN_TArrayPrepareArena(T **data, DN_USize count, DN_USize *max, DN_Arena *arena, DN_USize add_count) -{ - bool result = DN_ArrayPrepareArena(DN_Cast(void **)data, count, max, sizeof(**data), arena, add_count); - return result; -} - -template -DN_USize DN_TArrayCopyPtrArena(T **data, T const *src, DN_USize count, DN_Arena *arena) -{ - DN_USize result = DN_ArrayCopyPtrArena(DN_Cast(void **)data, src, count, sizeof(T), arena); - return result; -} - -template -DN_USize DN_TArrayCopyPtrArenaAssert(T **data, T const *src, DN_USize count, DN_Arena *arena, DN_CallSite call_site) -{ - DN_USize result = DN_ArrayCopyPtrArenaAssert(DN_Cast(void **)data, src, count, sizeof(T), arena, call_site); - return result; -} - -template -DN_USize DN_TArrayCopyPtrPool(T **data, T const *src, DN_USize count, DN_Pool *pool) -{ - DN_USize result = DN_ArrayCopyPtrPool(DN_Cast(void **)data, src, count, sizeof(T), pool); - return result; -} - -template -DN_USize DN_TArrayCopyPtrPoolAssert(T **data, T const *src, DN_USize count, DN_Pool *pool, DN_CallSite call_site) -{ - DN_USize result = DN_ArrayCopyPtrPoolAssert(DN_Cast(void **)data, src, count, sizeof(T), pool, call_site); + DN_USize result = DN_ArrayCopyPtrAllocatorAssert(DN_Cast(void **)data, src, count, sizeof(T), allocator, call_site); return result; } #endif // defined(__cplusplus) -#if DN_WITH_NET typedef enum DN_NETRequestType { DN_NETRequestType_Nil, DN_NETRequestType_HTTP, @@ -7546,7 +7673,7 @@ struct DN_NETResponse typedef struct DN_NETRequest DN_NETRequest; struct DN_NETRequest { - DN_MemList mem; + DN_MemList* mem; DN_Arena arena; DN_Arena start_response_arena; DN_NETRequestType type; @@ -7586,7 +7713,7 @@ struct DN_NETCore { char *base; DN_U64 base_size; - DN_MemList mem; + DN_MemList* mem; DN_Arena arena; DN_OSSemaphore completion_sem; void *context; @@ -7599,20 +7726,23 @@ struct DN_NETCore // object) in the core struct. On top of this is a asynchronous API provided to the caller along // the lines of, do http/ws followed to dispatch a request followed by a blocking wait for // response function. -// + // API // DN_NET_ResponseHasFailed // After a response has been dispatched via do http/ws the returned handle's status can be // queried using this function. A request has failed if the `state` has returned -// `DN_NETResponseState_Error`, or the returned HTTP status code was `>= 400`. +// `DN_NETResponseState_Error`, or the returned HTTP status code was `>= 400`. You can either +// switch on the `response.state` or use this function to blanket identify failed requests. DN_Str8 DN_NET_Str8FromResponseState (DN_NETResponseState state); DN_NETRequest * DN_NET_RequestFromHandle (DN_NETRequestHandle handle); DN_NETRequestHandle DN_NET_HandleFromRequest (DN_NETRequest *request); +bool DN_NET_HandleEq (DN_NETRequestHandle lhs, DN_NETRequestHandle rhs); bool DN_NET_ResponseHasFailed (DN_NETResponse const* resp); bool DN_NET_ResponseHasSucceeded (DN_NETResponse const* resp); bool DN_NET_ResponseIsReady (DN_NETResponse const* resp); DN_Str8 DN_NET_Str8DiagnosticFromResponse(DN_NETResponse const* resp, DN_Arena *arena); +#if DN_WITH_NET // NOTE: Internal functions for different networking implementations to use void DN_NET_BaseInit (DN_NETCore *net, char *base, DN_U64 base_size); DN_NETRequestHandle DN_NET_SetupRequest (DN_NETRequest *request, DN_Str8 url, DN_Str8 method, DN_NETDoHTTPArgs const *args, DN_NETRequestType type); @@ -7795,6 +7925,7 @@ DN_NETResponse DN_NET_EmcWaitForAnyResponse(DN_NETCore *net, DN_Arena *aren typedef WCHAR * NWPSTR, *LPWSTR, *PWSTR; typedef const WCHAR* LPCWSTR, *PCWSTR; typedef long HRESULT; + typedef ULONGLONG DWORDLONG; // NOTE: VirtualAlloc: Allocation Type #define MEM_RESERVE 0x00002000 @@ -8292,6 +8423,23 @@ DN_NETResponse DN_NET_EmcWaitForAnyResponse(DN_NETCore *net, DN_Arena *aren } PROCESS_MEMORY_COUNTERS; typedef PROCESS_MEMORY_COUNTERS *PPROCESS_MEMORY_COUNTERS; + typedef struct _PROCESS_MEMORY_COUNTERS_EX2 { + DWORD cb; + DWORD PageFaultCount; + SIZE_T PeakWorkingSetSize; + SIZE_T WorkingSetSize; + SIZE_T QuotaPeakPagedPoolUsage; + SIZE_T QuotaPagedPoolUsage; + SIZE_T QuotaPeakNonPagedPoolUsage; + SIZE_T QuotaNonPagedPoolUsage; + SIZE_T PagefileUsage; + SIZE_T PeakPagefileUsage; + SIZE_T PrivateUsage; + SIZE_T PrivateWorkingSetSize; + ULONG64 SharedCommitUsage; + } PROCESS_MEMORY_COUNTERS_EX2; + typedef PROCESS_MEMORY_COUNTERS_EX2 *PPROCESS_MEMORY_COUNTERS_EX2; + extern "C" { __declspec(dllimport) BOOL __stdcall GetProcessMemoryInfo(HANDLE Process, PPROCESS_MEMORY_COUNTERS ppsmemCounters, DWORD cb); @@ -8317,12 +8465,25 @@ DN_NETResponse DN_NET_EmcWaitForAnyResponse(DN_NETCore *net, DN_Arena *aren WORD wProcessorRevision; } SYSTEM_INFO, *LPSYSTEM_INFO; + typedef struct _MEMORYSTATUSEX { + DWORD dwLength; + DWORD dwMemoryLoad; + DWORDLONG ullTotalPhys; + DWORDLONG ullAvailPhys; + DWORDLONG ullTotalPageFile; + DWORDLONG ullAvailPageFile; + DWORDLONG ullTotalVirtual; + DWORDLONG ullAvailVirtual; + DWORDLONG ullAvailExtendedVirtual; + } MEMORYSTATUSEX, *LPMEMORYSTATUSEX; + extern "C" { - __declspec(dllimport) VOID __stdcall GetSystemInfo(SYSTEM_INFO *lpSystemInfo); - __declspec(dllimport) VOID __stdcall GetSystemTime(SYSTEMTIME *lpSystemTime); + __declspec(dllimport) BOOL __stdcall GlobalMemoryStatusEx (LPMEMORYSTATUSEX lpBuffer); + __declspec(dllimport) VOID __stdcall GetSystemInfo (SYSTEM_INFO *lpSystemInfo); + __declspec(dllimport) VOID __stdcall GetSystemTime (SYSTEMTIME *lpSystemTime); __declspec(dllimport) VOID __stdcall GetSystemTimeAsFileTime(FILETIME *lpSystemTimeAsFileTime); - __declspec(dllimport) VOID __stdcall GetLocalTime(SYSTEMTIME *lpSystemTime); + __declspec(dllimport) VOID __stdcall GetLocalTime (SYSTEMTIME *lpSystemTime); } // NOTE: um/timezoneapi.h ////////////////////////////////////////////////////////////////////// @@ -9233,12 +9394,37 @@ DN_NETResponse DN_NET_EmcWaitForAnyResponse(DN_NETCore *net, DN_Arena *aren // #include "dn_os_windows.h" // #endif +typedef enum DN_OSW32DllLoadFunctionsResult +{ + DN_OSW32DllLoadFunctionsResult_Ok, + DN_OSW32DllLoadFunctionsResult_LoadLibraryFailed, + DN_OSW32DllLoadFunctionsResult_FunctionMissing, +} +DN_OSW32DllLoadFunctionsResult; + +typedef struct DN_OSW32DllFunction DN_OSW32DllLoadFunction; +struct DN_OSW32DllFunction +{ + DN_Str8 name; + void *func_ptr; +}; + +typedef struct DN_OSW32DllCore DN_OSW32DllCore; +struct DN_OSW32DllCore +{ + void* handle; + DN_OSW32DllFunction* functions; + DN_USize functions_count; +}; + +typedef struct DN_OSW32Error DN_OSW32Error; struct DN_OSW32Error { unsigned long code; DN_Str8 msg; }; +typedef struct DN_OSW32FolderIteratorW DN_OSW32FolderIteratorW; struct DN_OSW32FolderIteratorW { void *handle; @@ -9246,6 +9432,7 @@ struct DN_OSW32FolderIteratorW wchar_t file_name_buf[512]; }; +typedef struct DN_OSW32Window DN_OSW32Window; struct DN_OSW32Window { HWND hwnd; @@ -9258,14 +9445,16 @@ struct DN_OSW32Window DN_OSW32Window *next; }; -enum DN_OSW32SyncPrimitiveType +typedef enum DN_OSW32SyncPrimitiveType { DN_OSW32SyncPrimitiveType_Semaphore, DN_OSW32SyncPrimitiveType_Mutex, DN_OSW32SyncPrimitiveType_ConditionVariable, DN_OSW32SyncPrimitiveType_Barrier, -}; +} +DN_OSW32SyncPrimitiveType; +typedef struct DN_OSW32SyncPrimitive DN_OSW32SyncPrimitive; struct DN_OSW32SyncPrimitive { union @@ -9286,6 +9475,7 @@ typedef HRESULT DN_OSW32GetDpiForMonitorFunc (HMONITOR hmonitor, MON typedef int DN_OSW32GetSystemMetricsForDpiFunc (int nIndex, UINT dpi); #define DN_OSW32DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2 ((void*)-4) +typedef struct DN_OSW32Core DN_OSW32Core; struct DN_OSW32Core { // NOTE: These functions are dynamically loaded because they might not be present on the user's @@ -9306,32 +9496,46 @@ struct DN_OSW32Core WNDPROC fallback_wnd_proc; }; -DN_API void DN_OS_W32Init (DN_OSW32Core *w32); -DN_API DN_OSW32Core* DN_OS_W32GetCore (); -DN_API void DN_OS_W32ThreadSetName (DN_Str8 name); -DN_API DN_OSW32Window* DN_OS_W32WindowFromHwndMaybeAlloc(DN_OSW32Core *w32, HWND hwnd, DN_Arena *arena); -DN_API LRESULT __stdcall DN_OS_W32WindowProcCustomTitlebar(HWND hwnd, UINT msg, WPARAM w_param, LPARAM l_param); +//////////////////////////////////////////////////////////////////////////////////////////////////// +// NOTE: DN Win32 book-keeping +DN_API void DN_OS_W32Init (DN_OSW32Core *w32); +DN_API DN_OSW32Core* DN_OS_W32GetCore (); +DN_API DN_OSW32Window* DN_OS_W32WindowFromHwndMaybeAlloc(DN_OSW32Core *w32, HWND hwnd, DN_Arena *arena); -DN_API DN_Str16 DN_OS_W32ErrorCodeToMsg16Alloc(DN_U32 error_code); -DN_API DN_OSW32Error DN_OS_W32ErrorCodeToMsg (DN_Arena *arena, DN_U32 error_code); -DN_API DN_OSW32Error DN_OS_W32ErrorCodeToMsgAlloc (DN_U32 error_code); -DN_API DN_OSW32Error DN_OS_W32LastError (DN_Arena *arena); -DN_API DN_OSW32Error DN_OS_W32LastErrorAlloc (); -DN_API void DN_OS_W32MakeProcessDPIAware (); +//////////////////////////////////////////////////////////////////////////////////////////////////// +// NOTE: Process management +DN_API void DN_OS_W32ThreadSetName (DN_Str8 name); +DN_API LRESULT __stdcall DN_OS_W32WindowProcCustomTitlebar(HWND hwnd, UINT msg, WPARAM w_param, LPARAM l_param); +DN_API void DN_OS_W32MakeProcessDPIAware (); +//////////////////////////////////////////////////////////////////////////////////////////////////// +// NOTE: DLL +DN_API void DN_OS_W32DllUnload (DN_OSW32DllCore *dll); +DN_API DN_OSW32DllLoadFunctionsResult DN_OS_W32DllLoadFunctions (DN_OSW32DllCore *dll, DN_Str8 dll_path); + +//////////////////////////////////////////////////////////////////////////////////////////////////// +// NOTE: Errors +DN_API DN_Str16 DN_OS_W32ErrorCodeToMsg16Alloc (DN_U32 error_code); +DN_API DN_OSW32Error DN_OS_W32ErrorCodeToMsg (DN_Arena *arena, DN_U32 error_code); +DN_API DN_OSW32Error DN_OS_W32ErrorCodeToMsgAlloc (DN_U32 error_code); +DN_API DN_OSW32Error DN_OS_W32LastError (DN_Arena *arena); +DN_API DN_OSW32Error DN_OS_W32LastErrorAlloc (); + +//////////////////////////////////////////////////////////////////////////////////////////////////// // NOTE: Windows Str8 <-> Str16 -DN_API DN_Str16 DN_OS_W32Str8ToStr16 (DN_Arena *arena, DN_Str8 src); -DN_API int DN_OS_W32Str8ToStr16Buffer (DN_Str16 src, char *dest, int dest_size); -DN_API DN_Str8 DN_OS_W32Str16ToStr8 (DN_Arena *arena, DN_Str16 src); -DN_API int DN_OS_W32Str16ToStr8Buffer (DN_Str16 src, char *dest, int dest_size); -DN_API DN_Str8 DN_OS_W32Str16ToStr8FromHeap (DN_Str16 src); +DN_API DN_Str16 DN_OS_W32Str8ToStr16 (DN_Arena *arena, DN_Str8 src); +DN_API int DN_OS_W32Str8ToStr16Buffer (DN_Str16 src, char *dest, int dest_size); +DN_API DN_Str8 DN_OS_W32Str16ToStr8 (DN_Arena *arena, DN_Str16 src); +DN_API int DN_OS_W32Str16ToStr8Buffer (DN_Str16 src, char *dest, int dest_size); +DN_API DN_Str8 DN_OS_W32Str16ToStr8FromHeap (DN_Str16 src); +//////////////////////////////////////////////////////////////////////////////////////////////////// // NOTE: Path navigation -DN_API DN_Str16 DN_OS_W32EXEPathW (DN_Arena *arena); -DN_API DN_Str16 DN_OS_W32EXEDirW (DN_Arena *arena); -DN_API DN_Str8 DN_OS_W32WorkingDir (DN_Arena *arena, DN_Str8 suffix); -DN_API DN_Str16 DN_OS_W32WorkingDirW (DN_Arena *arena, DN_Str16 suffix); -DN_API bool DN_OS_W32DirWIterate (DN_Str16 path, DN_OSW32FolderIteratorW *it); +DN_API DN_Str16 DN_OS_W32ExePathW (DN_Arena *arena); +DN_API DN_Str16 DN_OS_W32ExeDirW (DN_Arena *arena); +DN_API DN_Str8 DN_OS_W32WorkingDir (DN_Arena *arena, DN_Str8 suffix); +DN_API DN_Str16 DN_OS_W32WorkingDirW (DN_Arena *arena, DN_Str16 suffix); +DN_API bool DN_OS_W32DirWIterate (DN_Str16 path, DN_OSW32FolderIteratorW *it); #endif // !defined(DN_OS_W32_H) #elif defined(DN_PLATFORM_POSIX) || defined(DN_PLATFORM_EMSCRIPTEN) // DN: Single header generator commented out => #include "OS/dn_os_posix.h" diff --git a/Source/OS/dn_os_posix.cpp b/Source/OS/dn_os_posix.cpp index 36c33fe..33f4108 100644 --- a/Source/OS/dn_os_posix.cpp +++ b/Source/OS/dn_os_posix.cpp @@ -9,6 +9,8 @@ #include // readdir, opendir, closedir #include #include +#include // realpath +#include // sysconf, readlink // NOTE: DN_OSMem static DN_U32 DN_OS_MemConvertPageToOSFlags_(DN_U32 protect) @@ -241,6 +243,23 @@ DN_API DN_OSDiskSpace DN_OS_DiskSpace(DN_Str8 path) return result; } +DN_API DN_OSMemoryInfo DN_OS_MemoryInfo() +{ + DN_OSMemoryInfo result = {}; +#if defined(DN_PLATFORM_POSIX) + long page_size = sysconf(_SC_PAGESIZE); + long pages = sysconf(_SC_PHYS_PAGES); + long avail_pages = sysconf(_SC_AVPHYS_PAGES); + if (page_size > 0 && pages > 0) { + result.success = true; + result.total_phys = DN_Cast(DN_U64) pages * DN_Cast(DN_U64) page_size; + if (avail_pages > 0) + result.avail_phys = DN_Cast(DN_U64) avail_pages * DN_Cast(DN_U64) page_size; + } +#endif + return result; +} + DN_API DN_Str8 DN_OS_ExePath(DN_Arena *arena) { DN_Str8 result = {}; @@ -597,6 +616,23 @@ DN_API bool DN_OS_PathDelete(DN_Str8 path) return result; } +DN_API DN_OSPathResult DN_OS_PathCanonicalise(DN_Arena *arena, DN_Str8 path, DN_ErrSink *error) +{ + DN_OSPathResult result = {}; + DN_TcScratch scratch = DN_TcScratchBeginArena(&arena, 1); + DN_Str8 path_cstr = DN_Str8FromStr8Arena(path, &scratch.arena); // Ensure null-terminated + char *resolved = realpath(path_cstr.data, NULL); + if (resolved != NULL) { + result.success = true; + result.path = DN_Str8FromCStr8Arena(resolved, arena); + free(resolved); // realpath allocates with malloc + } else { + DN_ErrSinkAppendF(error, errno, "Failed to canonicalise path: %s", strerror(errno)); + } + DN_TcScratchEnd(&scratch); + return result; +} + DN_API bool DN_OS_PathIsFile(DN_Str8 path) { bool result = false; @@ -1277,14 +1313,20 @@ DN_API void DN_OS_ConditionVariableBroadcast(DN_OSConditionVariable *cv) DN_API DN_OSWindowMinimise DN_OS_WindowIsMinimised(DN_OSWindow *window) { (void)window; + #if defined(DN_PLATFORM_EMSCRIPTEN) + #else DN_AssertInvalidCodePath; + #endif return DN_OSWindowMinimise_No; } DN_API DN_OSWindowMaximise DN_OS_WindowIsMaximised(DN_OSWindow *window) { (void)window; + #if defined(DN_PLATFORM_EMSCRIPTEN) + #else DN_AssertInvalidCodePath; + #endif return DN_OSWindowMaximise_No; } @@ -1292,32 +1334,47 @@ DN_API void DN_OS_WindowSetTitle(DN_OSWindow *window, DN_Str8 title) { (void)window; (void)title; + #if defined(DN_PLATFORM_EMSCRIPTEN) + #else DN_AssertInvalidCodePath; + #endif } DN_API void DN_OS_WindowShow(DN_OSWindow *window, DN_OSWindowShow show) { (void)window; (void)show; + #if defined(DN_PLATFORM_EMSCRIPTEN) + #else DN_AssertInvalidCodePath; + #endif } DN_API void DN_OS_WindowBringToFront(DN_OSWindow *window) { (void)window; + #if defined(DN_PLATFORM_EMSCRIPTEN) + #else DN_AssertInvalidCodePath; + #endif } DN_API void DN_OS_WindowFocus(DN_OSWindow *window) { (void)window; + #if defined(DN_PLATFORM_EMSCRIPTEN) + #else DN_AssertInvalidCodePath; + #endif } DN_API bool DN_OS_WindowIsFocused(DN_OSWindow *window) { (void)window; + #if defined(DN_PLATFORM_EMSCRIPTEN) + #else DN_AssertInvalidCodePath; + #endif return false; } diff --git a/Source/OS/dn_os_w32.cpp b/Source/OS/dn_os_w32.cpp index f68c383..9f1033d 100644 --- a/Source/OS/dn_os_w32.cpp +++ b/Source/OS/dn_os_w32.cpp @@ -5,7 +5,8 @@ #include #endif -// NOTE: DN_Mem +//////////////////////////////////////////////////////////////////////////////////////////////////// +// NOTE: DN OS layer implementation static DN_U32 DN_OS_MemConvertPageToOSFlags_(DN_U32 protect) { DN_Assert((protect & ~DN_MemPage_All) == 0); @@ -231,6 +232,21 @@ DN_API DN_OSDiskSpace DN_OS_DiskSpace(DN_Str8 path) return result; } +DN_API DN_OSMemoryInfo DN_OS_MemoryInfo() +{ + DN_OSMemoryInfo result = {}; + MEMORYSTATUSEX status = {}; + status.dwLength = sizeof(status); + if (GlobalMemoryStatusEx(&status)) { + result.success = true; + result.total_phys = status.ullTotalPhys; + result.avail_phys = status.ullAvailPhys; + result.total_virtual = status.ullTotalVirtual; + result.avail_virtual = status.ullAvailVirtual; + } + return result; +} + DN_API bool DN_OS_SetEnvVar(DN_Str8 name, DN_Str8 value) { DN_TcScratch scratch = DN_TcScratchBeginArena(nullptr, 0); @@ -247,7 +263,7 @@ DN_API DN_Str8 DN_OS_ExePath(DN_Arena *arena) if (!arena) return result; DN_TcScratch scratch = DN_TcScratchBeginArena(&arena, 1); - DN_Str16 exe_dir16 = DN_OS_W32EXEPathW(&scratch.arena); + DN_Str16 exe_dir16 = DN_OS_W32ExePathW(&scratch.arena); result = DN_OS_W32Str16ToStr8(arena, exe_dir16); DN_TcScratchEnd(&scratch); return result; @@ -536,6 +552,25 @@ DN_API bool DN_OS_PathDelete(DN_Str8 path) return result; } +DN_API DN_OSPathResult DN_OS_PathCanonicalise(DN_Arena *arena, DN_Str8 path, DN_ErrSink *error) +{ + DN_OSPathResult result = {}; + DN_TcScratch scratch = DN_TcScratchBeginArena(&arena, 1); + DN_Str16 path16 = DN_OS_W32Str8ToStr16(&scratch.arena, path); + + wchar_t out_path[1024]; + HRESULT convert_result = PathCchCanonicalizeEx(out_path, DN_ArrayCountU(out_path), path16.data, PATHCCH_ALLOW_LONG_PATHS); + if (convert_result == S_OK) { + result.success = true; + result.path = DN_OS_W32Str16ToStr8(arena, DN_Str16FromPtr(out_path, DN_CStr16Count(out_path))); + } else { + DN_OSW32Error win_error = DN_OS_W32LastError(&scratch.arena); + DN_ErrSinkAppendF(error, win_error.code, "Failed to canonicalise path. %.*s", DN_Str8PrintFmt(win_error.msg)); + } + DN_TcScratchEnd(&scratch); + return result; +} + DN_API bool DN_OS_PathIsFile(DN_Str8 path) { bool result = false; @@ -648,9 +683,9 @@ DN_API bool DN_OS_PathIterateDir(DN_Str8 path, DN_OSDirIterator *it) // add those characters in this branch, so overwrite the null // character, add the glob and re-null terminate the buffer. if (needs_asterisks) - adjusted_path = DN_Str8FmtOsPathArena(&scratch.arena, "%.*s*", DN_Str8PrintFmt(path)); + adjusted_path = DN_Str8PathFmtOsArena(&scratch.arena, "%.*s*", DN_Str8PrintFmt(path)).value; else - adjusted_path = DN_Str8FmtOsPathArena(&scratch.arena, "%.*s/*", DN_Str8PrintFmt(path)); + adjusted_path = DN_Str8PathFmtOsArena(&scratch.arena, "%.*s/*", DN_Str8PrintFmt(path)).value; } path16 = DN_OS_W32Str8ToStr16(&scratch.arena, adjusted_path); @@ -1057,44 +1092,6 @@ DN_API DN_OSExecAsyncHandle DN_OS_ExecAsync(DN_Str8Slice cmd_line, DN_OSExecArgs return result; } -DN_API void DN_OS_W32Init(DN_OSW32Core *w32) -{ - InitializeCriticalSection(&w32->sync_primitive_free_list_mutex); - QueryPerformanceFrequency(&w32->qpc_frequency); - - // NOTE: DPI - HMODULE user32 = LoadLibraryA("user32.dll"); - if (user32) { - w32->get_dpi_for_window = (DN_OSW32GetDpiForWindowFunc* )GetProcAddress(user32, "GetDpiForWindow"); - w32->get_dpi_for_monitor = (DN_OSW32GetDpiForMonitorFunc * )GetProcAddress(user32, "GetDpiForMonitor"); - w32->get_system_metrics_for_dpi = (DN_OSW32GetSystemMetricsForDpiFunc *)GetProcAddress(user32, "GetSystemMetricsForDpi"); - FreeLibrary(user32); - } - - // NOTE: SetThreadDesc - HMODULE kernel32 = LoadLibraryA("kernel32.dll"); - if (kernel32) { - w32->set_thread_description = DN_Cast(DN_OSW32SetThreadDescriptionFunc *) GetProcAddress(kernel32, "SetThreadDescription"); - FreeLibrary(kernel32); - } - - // NOTE: win32 bcrypt - wchar_t const BCRYPT_ALGORITHM[] = L"RNG"; - long /*NTSTATUS*/ init_status = BCryptOpenAlgorithmProvider(&w32->bcrypt_rng_handle, BCRYPT_ALGORITHM, nullptr /*implementation*/, 0 /*flags*/); - if (w32->bcrypt_rng_handle && init_status == 0) - w32->bcrypt_init_success = true; - else - DN_LogErrorF("Failed to initialise Windows secure random number generator, error: %d", init_status); -} - -DN_API DN_OSW32Core *DN_OS_W32GetCore() -{ - DN_Core *dn = DN_Get(); - DN_Assert(dn && dn->os_init); - DN_OSW32Core *result = DN_Cast(DN_OSW32Core *)dn->os.platform_context; - return result; -} - static DN_OSW32SyncPrimitive *DN_OS_U64ToW32SyncPrimitive_(DN_U64 u64) { DN_OSW32SyncPrimitive *result = nullptr; @@ -1140,7 +1137,6 @@ static void DN_OS_W32DeallocSyncPrimitive_(DN_OSW32SyncPrimitive *primitive) } } -// NOTE: DN_OSSemaphore DN_API DN_OSSemaphore DN_OS_SemaphoreInit(DN_U32 initial_count) { DN_OSSemaphore result = {}; @@ -1189,7 +1185,6 @@ DN_API DN_OSSemaphoreWaitResult DN_OS_SemaphoreWait(DN_OSSemaphore *semaphore, D return result; } -// NOTE: DN_OSBarrier DN_API DN_OSBarrier DN_OS_BarrierInit(DN_U32 thread_count) { DN_OSBarrier result = {}; @@ -1260,7 +1255,6 @@ DN_API void DN_OS_MutexUnlock(DN_OSMutex *mutex) } } -// NOTE: DN_OSConditionVariable //////////////////////////////////////////////////////////////////// DN_API DN_OSConditionVariable DN_OS_ConditionVariableInit() { DN_OSW32SyncPrimitive *primitive = DN_OS_W32AllocSyncPrimitive_(); @@ -1444,6 +1438,69 @@ DN_API DN_U32 DN_OS_ThreadID() return result; } +//////////////////////////////////////////////////////////////////////////////////////////////////// +// NOTE: DN Win32 book-keeping +DN_API void DN_OS_W32Init(DN_OSW32Core *w32) +{ + InitializeCriticalSection(&w32->sync_primitive_free_list_mutex); + QueryPerformanceFrequency(&w32->qpc_frequency); + + // NOTE: DPI + HMODULE user32 = LoadLibraryA("user32.dll"); + if (user32) { + w32->get_dpi_for_window = (DN_OSW32GetDpiForWindowFunc* )GetProcAddress(user32, "GetDpiForWindow"); + w32->get_dpi_for_monitor = (DN_OSW32GetDpiForMonitorFunc * )GetProcAddress(user32, "GetDpiForMonitor"); + w32->get_system_metrics_for_dpi = (DN_OSW32GetSystemMetricsForDpiFunc *)GetProcAddress(user32, "GetSystemMetricsForDpi"); + FreeLibrary(user32); + } + + // NOTE: SetThreadDesc + HMODULE kernel32 = LoadLibraryA("kernel32.dll"); + if (kernel32) { + w32->set_thread_description = DN_Cast(DN_OSW32SetThreadDescriptionFunc *) GetProcAddress(kernel32, "SetThreadDescription"); + FreeLibrary(kernel32); + } + + // NOTE: win32 bcrypt + wchar_t const BCRYPT_ALGORITHM[] = L"RNG"; + long /*NTSTATUS*/ init_status = BCryptOpenAlgorithmProvider(&w32->bcrypt_rng_handle, BCRYPT_ALGORITHM, nullptr /*implementation*/, 0 /*flags*/); + if (w32->bcrypt_rng_handle && init_status == 0) + w32->bcrypt_init_success = true; + else + DN_LogErrorF("Failed to initialise Windows secure random number generator, error: %d", init_status); +} + +DN_API DN_OSW32Core *DN_OS_W32GetCore() +{ + DN_Core *dn = DN_Get(); + DN_Assert(dn && dn->os_init); + DN_OSW32Core *result = DN_Cast(DN_OSW32Core *)dn->os.platform_context; + return result; +} + +DN_API DN_OSW32Window* DN_OS_W32WindowFromHwndMaybeAlloc(DN_OSW32Core *w32, HWND hwnd, DN_Arena *arena) +{ + DN_OSW32Window *result = nullptr; + for (DN_OSW32Window *check = w32->windows; !result && check; check = check->next) { + if (check->hwnd == hwnd) + result = check; + } + + if (!result && arena) { + result = DN_ArenaNewZ(arena, DN_OSW32Window); + if (result) { + result->hwnd = hwnd; + if (w32->windows) + w32->windows->next = result; + result->next = w32->windows; + w32->windows = result; + } + } + return result; +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// +// NOTE: Process management DN_API void DN_OS_W32ThreadSetName(DN_Str8 name) { // NOTE: SetThreadDescription is only available in @@ -1475,7 +1532,7 @@ DN_API void DN_OS_W32ThreadSetName(DN_Str8 name) // TODO: Review warning 6320 DN_MSVC_WARNING_PUSH - DN_MSVC_WARNING_DISABLE(6320) // Exception-filter expression is the constant EXCEPTION_EXECUTE_HANDLER. This might mask exceptions that were not intended to be handled + DN_MSVC_WARNING_DISABLE(6320) // Exception-filter expression is the constant EXCEPTION_ExeCUTE_HANDLER. This might mask exceptions that were not intended to be handled DN_MSVC_WARNING_DISABLE(6322) // Empty _except block __try { RaiseException(0x406D1388, 0, sizeof(info) / sizeof(void *), (const ULONG_PTR *)&info); @@ -1486,27 +1543,6 @@ DN_API void DN_OS_W32ThreadSetName(DN_Str8 name) DN_TcScratchEnd(&scratch); } -DN_API DN_OSW32Window* DN_OS_W32WindowFromHwndMaybeAlloc(DN_OSW32Core *w32, HWND hwnd, DN_Arena *arena) -{ - DN_OSW32Window *result = nullptr; - for (DN_OSW32Window *check = w32->windows; !result && check; check = check->next) { - if (check->hwnd == hwnd) - result = check; - } - - if (!result && arena) { - result = DN_ArenaNewZ(arena, DN_OSW32Window); - if (result) { - result->hwnd = hwnd; - if (w32->windows) - w32->windows->next = result; - result->next = w32->windows; - w32->windows = result; - } - } - return result; -} - DN_API LRESULT __stdcall DN_OS_W32WindowProcCustomTitlebar(HWND hwnd, UINT msg, WPARAM w_param, LPARAM l_param) { DN_OSW32Core *w32 = DN_OS_W32GetCore(); @@ -1640,6 +1676,81 @@ DN_API LRESULT __stdcall DN_OS_W32WindowProcCustomTitlebar(HWND hwnd, UINT msg, return result; } +DN_API void DN_OS_W32MakeProcessDPIAware() +{ + typedef bool SetProcessDpiAwareProc(void); + typedef bool SetProcessDpiAwarenessProc(DPI_AWARENESS); + typedef bool SetProcessDpiAwarenessContextProc(void * /*DPI_AWARENESS_CONTEXT*/); + + // NOTE(doyle): Taken from cmuratori/refterm snippet on DPI awareness. It + // appears we can make this robust by just loading user32.dll and using + // GetProcAddress on the DPI function. If it's not there, we're on an old + // version of windows, so we can call an older version of the API. + void *lib_handle = LoadLibraryA("user32.dll"); + if (!lib_handle) + return; + + if (auto *set_process_dpi_awareness_context = DN_Cast(SetProcessDpiAwarenessContextProc *) GetProcAddress(DN_Cast(HMODULE) lib_handle, "SetProcessDpiAwarenessContext")) + set_process_dpi_awareness_context(DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2); + else if (auto *set_process_dpi_awareness = DN_Cast(SetProcessDpiAwarenessProc *) GetProcAddress(DN_Cast(HMODULE) lib_handle, "SetProcessDpiAwareness")) + set_process_dpi_awareness(DPI_AWARENESS_PER_MONITOR_AWARE); + else if (auto *set_process_dpi_aware = DN_Cast(SetProcessDpiAwareProc *) GetProcAddress(DN_Cast(HMODULE) lib_handle, "SetProcessDpiAware")) + set_process_dpi_aware(); +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// +// NOTE: DLL +DN_API void DN_OS_W32DllUnload(DN_OSW32DllCore *dll) +{ + if (dll) { + if (dll->handle) { + FreeLibrary(DN_Cast(HMODULE) dll->handle); + dll->handle = nullptr; + } + + for (DN_ForItSize(it, DN_OSW32DllFunction, dll->functions, dll->functions_count)) + it.data->func_ptr = nullptr; + } +} + +DN_API DN_OSW32DllLoadFunctionsResult DN_OS_W32DllLoadFunctions(DN_OSW32DllCore *dll, DN_Str8 dll_path) +{ + DN_OSW32DllLoadFunctionsResult result = DN_OSW32DllLoadFunctionsResult_LoadLibraryFailed; + HMODULE handle = LoadLibraryA(dll_path.data); + if (handle) { + bool all_good = true; + + // NOTE: Validate that all the functions can be loaded from the DLL + for (DN_ForItSize(it, DN_OSW32DllFunction, dll->functions, dll->functions_count)) { + DN_Str8 func_name = it.data->name; + DN_AssertF(func_name.count && func_name.data[func_name.count] == 0, "Function name must be set and null-terminated"); + void *func_ptr = GetProcAddress(handle, func_name.data); + all_good &= (func_ptr != nullptr); + } + + // NOTE: If all functions can be loaded, then mutate the user's `dll` struct + if (all_good) { + result = DN_OSW32DllLoadFunctionsResult_Ok; + for (DN_ForItSize(it, DN_OSW32DllFunction, dll->functions, dll->functions_count)) { + DN_Str8 func_name = it.data->name; + it.data->func_ptr = GetProcAddress(handle, func_name.data); + } + + // NOTE: Cleanup the old handle + if (dll->handle) + FreeLibrary(DN_Cast(HMODULE) dll->handle); + dll->handle = handle; + DN_StackTraceReloadSymbols(); + } else { + FreeLibrary(handle); + result = DN_OSW32DllLoadFunctionsResult_FunctionMissing; + } + } + return result; +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// +// NOTE: Errors DN_API DN_Str16 DN_OS_W32ErrorCodeToMsg16Alloc(DN_U32 error_code) { DWORD flags = FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS; @@ -1702,28 +1813,8 @@ DN_API DN_OSW32Error DN_OS_W32LastErrorAlloc() return result; } -DN_API void DN_OS_W32MakeProcessDPIAware() -{ - typedef bool SetProcessDpiAwareProc(void); - typedef bool SetProcessDpiAwarenessProc(DPI_AWARENESS); - typedef bool SetProcessDpiAwarenessContextProc(void * /*DPI_AWARENESS_CONTEXT*/); - - // NOTE(doyle): Taken from cmuratori/refterm snippet on DPI awareness. It - // appears we can make this robust by just loading user32.dll and using - // GetProcAddress on the DPI function. If it's not there, we're on an old - // version of windows, so we can call an older version of the API. - void *lib_handle = LoadLibraryA("user32.dll"); - if (!lib_handle) - return; - - if (auto *set_process_dpi_awareness_context = DN_Cast(SetProcessDpiAwarenessContextProc *) GetProcAddress(DN_Cast(HMODULE) lib_handle, "SetProcessDpiAwarenessContext")) - set_process_dpi_awareness_context(DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2); - else if (auto *set_process_dpi_awareness = DN_Cast(SetProcessDpiAwarenessProc *) GetProcAddress(DN_Cast(HMODULE) lib_handle, "SetProcessDpiAwareness")) - set_process_dpi_awareness(DPI_AWARENESS_PER_MONITOR_AWARE); - else if (auto *set_process_dpi_aware = DN_Cast(SetProcessDpiAwareProc *) GetProcAddress(DN_Cast(HMODULE) lib_handle, "SetProcessDpiAware")) - set_process_dpi_aware(); -} - +//////////////////////////////////////////////////////////////////////////////////////////////////// +// NOTE: Windows Str8 <-> Str16 DN_API DN_Str16 DN_OS_W32Str8ToStr16(DN_Arena *arena, DN_Str8 src) { DN_Str16 result = {}; @@ -1845,8 +1936,9 @@ DN_API DN_Str8 DN_OS_W32Str16ToStr8FromHeap(DN_Str16 src) return result; } -// NOTE: Windows Executable Directory ////////////////////////////////////////// -DN_API DN_Str16 DN_OS_W32EXEPathW(DN_Arena *arena) +//////////////////////////////////////////////////////////////////////////////////////////////////// +// NOTE: Path navigation +DN_API DN_Str16 DN_OS_W32ExePathW(DN_Arena *arena) { DN_TcScratch scratch = DN_TcScratchBeginArena(&arena, 1); DN_Str16 result = {}; diff --git a/Source/OS/dn_os_w32.h b/Source/OS/dn_os_w32.h index b012c28..a462ab9 100644 --- a/Source/OS/dn_os_w32.h +++ b/Source/OS/dn_os_w32.h @@ -7,12 +7,37 @@ #include "dn_os_windows.h" #endif +typedef enum DN_OSW32DllLoadFunctionsResult +{ + DN_OSW32DllLoadFunctionsResult_Ok, + DN_OSW32DllLoadFunctionsResult_LoadLibraryFailed, + DN_OSW32DllLoadFunctionsResult_FunctionMissing, +} +DN_OSW32DllLoadFunctionsResult; + +typedef struct DN_OSW32DllFunction DN_OSW32DllLoadFunction; +struct DN_OSW32DllFunction +{ + DN_Str8 name; + void *func_ptr; +}; + +typedef struct DN_OSW32DllCore DN_OSW32DllCore; +struct DN_OSW32DllCore +{ + void* handle; + DN_OSW32DllFunction* functions; + DN_USize functions_count; +}; + +typedef struct DN_OSW32Error DN_OSW32Error; struct DN_OSW32Error { unsigned long code; DN_Str8 msg; }; +typedef struct DN_OSW32FolderIteratorW DN_OSW32FolderIteratorW; struct DN_OSW32FolderIteratorW { void *handle; @@ -20,6 +45,7 @@ struct DN_OSW32FolderIteratorW wchar_t file_name_buf[512]; }; +typedef struct DN_OSW32Window DN_OSW32Window; struct DN_OSW32Window { HWND hwnd; @@ -32,14 +58,16 @@ struct DN_OSW32Window DN_OSW32Window *next; }; -enum DN_OSW32SyncPrimitiveType +typedef enum DN_OSW32SyncPrimitiveType { DN_OSW32SyncPrimitiveType_Semaphore, DN_OSW32SyncPrimitiveType_Mutex, DN_OSW32SyncPrimitiveType_ConditionVariable, DN_OSW32SyncPrimitiveType_Barrier, -}; +} +DN_OSW32SyncPrimitiveType; +typedef struct DN_OSW32SyncPrimitive DN_OSW32SyncPrimitive; struct DN_OSW32SyncPrimitive { union @@ -60,6 +88,7 @@ typedef HRESULT DN_OSW32GetDpiForMonitorFunc (HMONITOR hmonitor, MON typedef int DN_OSW32GetSystemMetricsForDpiFunc (int nIndex, UINT dpi); #define DN_OSW32DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2 ((void*)-4) +typedef struct DN_OSW32Core DN_OSW32Core; struct DN_OSW32Core { // NOTE: These functions are dynamically loaded because they might not be present on the user's @@ -80,30 +109,44 @@ struct DN_OSW32Core WNDPROC fallback_wnd_proc; }; -DN_API void DN_OS_W32Init (DN_OSW32Core *w32); -DN_API DN_OSW32Core* DN_OS_W32GetCore (); -DN_API void DN_OS_W32ThreadSetName (DN_Str8 name); -DN_API DN_OSW32Window* DN_OS_W32WindowFromHwndMaybeAlloc(DN_OSW32Core *w32, HWND hwnd, DN_Arena *arena); -DN_API LRESULT __stdcall DN_OS_W32WindowProcCustomTitlebar(HWND hwnd, UINT msg, WPARAM w_param, LPARAM l_param); +//////////////////////////////////////////////////////////////////////////////////////////////////// +// NOTE: DN Win32 book-keeping +DN_API void DN_OS_W32Init (DN_OSW32Core *w32); +DN_API DN_OSW32Core* DN_OS_W32GetCore (); +DN_API DN_OSW32Window* DN_OS_W32WindowFromHwndMaybeAlloc(DN_OSW32Core *w32, HWND hwnd, DN_Arena *arena); -DN_API DN_Str16 DN_OS_W32ErrorCodeToMsg16Alloc(DN_U32 error_code); -DN_API DN_OSW32Error DN_OS_W32ErrorCodeToMsg (DN_Arena *arena, DN_U32 error_code); -DN_API DN_OSW32Error DN_OS_W32ErrorCodeToMsgAlloc (DN_U32 error_code); -DN_API DN_OSW32Error DN_OS_W32LastError (DN_Arena *arena); -DN_API DN_OSW32Error DN_OS_W32LastErrorAlloc (); -DN_API void DN_OS_W32MakeProcessDPIAware (); +//////////////////////////////////////////////////////////////////////////////////////////////////// +// NOTE: Process management +DN_API void DN_OS_W32ThreadSetName (DN_Str8 name); +DN_API LRESULT __stdcall DN_OS_W32WindowProcCustomTitlebar(HWND hwnd, UINT msg, WPARAM w_param, LPARAM l_param); +DN_API void DN_OS_W32MakeProcessDPIAware (); +//////////////////////////////////////////////////////////////////////////////////////////////////// +// NOTE: DLL +DN_API void DN_OS_W32DllUnload (DN_OSW32DllCore *dll); +DN_API DN_OSW32DllLoadFunctionsResult DN_OS_W32DllLoadFunctions (DN_OSW32DllCore *dll, DN_Str8 dll_path); + +//////////////////////////////////////////////////////////////////////////////////////////////////// +// NOTE: Errors +DN_API DN_Str16 DN_OS_W32ErrorCodeToMsg16Alloc (DN_U32 error_code); +DN_API DN_OSW32Error DN_OS_W32ErrorCodeToMsg (DN_Arena *arena, DN_U32 error_code); +DN_API DN_OSW32Error DN_OS_W32ErrorCodeToMsgAlloc (DN_U32 error_code); +DN_API DN_OSW32Error DN_OS_W32LastError (DN_Arena *arena); +DN_API DN_OSW32Error DN_OS_W32LastErrorAlloc (); + +//////////////////////////////////////////////////////////////////////////////////////////////////// // NOTE: Windows Str8 <-> Str16 -DN_API DN_Str16 DN_OS_W32Str8ToStr16 (DN_Arena *arena, DN_Str8 src); -DN_API int DN_OS_W32Str8ToStr16Buffer (DN_Str16 src, char *dest, int dest_size); -DN_API DN_Str8 DN_OS_W32Str16ToStr8 (DN_Arena *arena, DN_Str16 src); -DN_API int DN_OS_W32Str16ToStr8Buffer (DN_Str16 src, char *dest, int dest_size); -DN_API DN_Str8 DN_OS_W32Str16ToStr8FromHeap (DN_Str16 src); +DN_API DN_Str16 DN_OS_W32Str8ToStr16 (DN_Arena *arena, DN_Str8 src); +DN_API int DN_OS_W32Str8ToStr16Buffer (DN_Str16 src, char *dest, int dest_size); +DN_API DN_Str8 DN_OS_W32Str16ToStr8 (DN_Arena *arena, DN_Str16 src); +DN_API int DN_OS_W32Str16ToStr8Buffer (DN_Str16 src, char *dest, int dest_size); +DN_API DN_Str8 DN_OS_W32Str16ToStr8FromHeap (DN_Str16 src); +//////////////////////////////////////////////////////////////////////////////////////////////////// // NOTE: Path navigation -DN_API DN_Str16 DN_OS_W32EXEPathW (DN_Arena *arena); -DN_API DN_Str16 DN_OS_W32EXEDirW (DN_Arena *arena); -DN_API DN_Str8 DN_OS_W32WorkingDir (DN_Arena *arena, DN_Str8 suffix); -DN_API DN_Str16 DN_OS_W32WorkingDirW (DN_Arena *arena, DN_Str16 suffix); -DN_API bool DN_OS_W32DirWIterate (DN_Str16 path, DN_OSW32FolderIteratorW *it); +DN_API DN_Str16 DN_OS_W32ExePathW (DN_Arena *arena); +DN_API DN_Str16 DN_OS_W32ExeDirW (DN_Arena *arena); +DN_API DN_Str8 DN_OS_W32WorkingDir (DN_Arena *arena, DN_Str8 suffix); +DN_API DN_Str16 DN_OS_W32WorkingDirW (DN_Arena *arena, DN_Str16 suffix); +DN_API bool DN_OS_W32DirWIterate (DN_Str16 path, DN_OSW32FolderIteratorW *it); #endif // !defined(DN_OS_W32_H) diff --git a/Source/OS/dn_os_windows.h b/Source/OS/dn_os_windows.h index 5dee44a..c9415dc 100644 --- a/Source/OS/dn_os_windows.h +++ b/Source/OS/dn_os_windows.h @@ -103,6 +103,7 @@ typedef WCHAR * NWPSTR, *LPWSTR, *PWSTR; typedef const WCHAR* LPCWSTR, *PCWSTR; typedef long HRESULT; + typedef ULONGLONG DWORDLONG; // NOTE: VirtualAlloc: Allocation Type #define MEM_RESERVE 0x00002000 @@ -600,6 +601,23 @@ } PROCESS_MEMORY_COUNTERS; typedef PROCESS_MEMORY_COUNTERS *PPROCESS_MEMORY_COUNTERS; + typedef struct _PROCESS_MEMORY_COUNTERS_EX2 { + DWORD cb; + DWORD PageFaultCount; + SIZE_T PeakWorkingSetSize; + SIZE_T WorkingSetSize; + SIZE_T QuotaPeakPagedPoolUsage; + SIZE_T QuotaPagedPoolUsage; + SIZE_T QuotaPeakNonPagedPoolUsage; + SIZE_T QuotaNonPagedPoolUsage; + SIZE_T PagefileUsage; + SIZE_T PeakPagefileUsage; + SIZE_T PrivateUsage; + SIZE_T PrivateWorkingSetSize; + ULONG64 SharedCommitUsage; + } PROCESS_MEMORY_COUNTERS_EX2; + typedef PROCESS_MEMORY_COUNTERS_EX2 *PPROCESS_MEMORY_COUNTERS_EX2; + extern "C" { __declspec(dllimport) BOOL __stdcall GetProcessMemoryInfo(HANDLE Process, PPROCESS_MEMORY_COUNTERS ppsmemCounters, DWORD cb); @@ -625,12 +643,25 @@ WORD wProcessorRevision; } SYSTEM_INFO, *LPSYSTEM_INFO; + typedef struct _MEMORYSTATUSEX { + DWORD dwLength; + DWORD dwMemoryLoad; + DWORDLONG ullTotalPhys; + DWORDLONG ullAvailPhys; + DWORDLONG ullTotalPageFile; + DWORDLONG ullAvailPageFile; + DWORDLONG ullTotalVirtual; + DWORDLONG ullAvailVirtual; + DWORDLONG ullAvailExtendedVirtual; + } MEMORYSTATUSEX, *LPMEMORYSTATUSEX; + extern "C" { - __declspec(dllimport) VOID __stdcall GetSystemInfo(SYSTEM_INFO *lpSystemInfo); - __declspec(dllimport) VOID __stdcall GetSystemTime(SYSTEMTIME *lpSystemTime); + __declspec(dllimport) BOOL __stdcall GlobalMemoryStatusEx (LPMEMORYSTATUSEX lpBuffer); + __declspec(dllimport) VOID __stdcall GetSystemInfo (SYSTEM_INFO *lpSystemInfo); + __declspec(dllimport) VOID __stdcall GetSystemTime (SYSTEMTIME *lpSystemTime); __declspec(dllimport) VOID __stdcall GetSystemTimeAsFileTime(FILETIME *lpSystemTimeAsFileTime); - __declspec(dllimport) VOID __stdcall GetLocalTime(SYSTEMTIME *lpSystemTime); + __declspec(dllimport) VOID __stdcall GetLocalTime (SYSTEMTIME *lpSystemTime); } // NOTE: um/timezoneapi.h ////////////////////////////////////////////////////////////////////// diff --git a/Source/Standalone/dn_ini.h b/Source/Standalone/dn_ini.h index 9f6c3ef..4c56887 100644 --- a/Source/Standalone/dn_ini.h +++ b/Source/Standalone/dn_ini.h @@ -49,7 +49,7 @@ // NOTE: Calculate the number of bytes required to parse the buffer and make one single // allocation - DN_INICore ini = DN_INI_ParseFromPtr(ini_buffer.data, ini_buffer.count, NULL, 0); + DN_INICore ini = DN_INI_ParseFromPtr(ini_buffer.data, ini_buffer.count, NULL, 0); size_t parse_buffer_size = ini.memory_required; char* parse_buffer = calloc(1, parse_buffer_size); diff --git a/Source/dn.cpp b/Source/dn.cpp index 4ae44e2..2438d15 100644 --- a/Source/dn.cpp +++ b/Source/dn.cpp @@ -20,8 +20,134 @@ enum DN_ArenaUAFCheckReportType_ DN_Core *g_dn_; +#if DN_MEM_DEBUGGER +static void DN_MemDebuggerMemListRegister_(DN_MemList *mem) +{ + DN_Core *dn = g_dn_; + if (!dn || !mem || !dn->mem_debugger.mem_list_table.kvs) + return; + DN_TicketMutexBegin(&dn->mem_debugger.mem_list_mutex); + DN_HTableAddResult add = DN_HTableMake(&dn->mem_debugger.mem_list_table, &mem); + DN_MemDebuggerMemList *entry = DN_Cast(DN_MemDebuggerMemList *) add.slot.value; + if (entry) { + entry->mem_list = mem; + if (!add.existed) { + entry->allocs = nullptr; + entry->allocs_count = 0; + entry->allocs_max = 0; + } + } + DN_TicketMutexEnd(&dn->mem_debugger.mem_list_mutex); +} + +static void DN_MemDebuggerMemListUnregister_(DN_MemList *mem) +{ + DN_Core *dn = g_dn_; + if (!dn || !mem || !dn->mem_debugger.mem_list_table.kvs) + return; + DN_TicketMutexBegin(&dn->mem_debugger.mem_list_mutex); + DN_MemDebuggerMemList *entry = DN_Cast(DN_MemDebuggerMemList *) DN_HTableValueFromFind(&dn->mem_debugger.mem_list_table, &mem); + if (entry && entry->allocs) { + DN_HeapDealloc(&dn->mem_debugger.heap, entry->allocs, entry->allocs_max * sizeof(DN_MemDebuggerMemListAlloc)); + entry->allocs = nullptr; + entry->allocs_count = 0; + entry->allocs_max = 0; + } + DN_HTableDel(&dn->mem_debugger.mem_list_table, &mem); + DN_TicketMutexEnd(&dn->mem_debugger.mem_list_mutex); +} + +static void DN_MemDebuggerMemListAllocTrack_(DN_MemList *mem, void *ptr, DN_U64 size, DN_U64 alloc_size, DN_U8 align, DN_CallSite call_site) +{ + DN_Core *dn = g_dn_; + if (!dn || !mem || !ptr || !dn->mem_debugger.mem_list_table.kvs) + return; + + // NOTE: Excluded heaps are not tracked (e.g. the debugger's own snapshot arena while the snapshot + // holds the alloc table mutex). + if (DN_BitIsSet(mem->heap.flags, DN_HeapFlags_ExcludeFromMemDebugger)) + return; + + DN_TicketMutexBegin(&dn->mem_debugger.mem_list_mutex); + DN_MemDebuggerMemList *entry = DN_Cast(DN_MemDebuggerMemList *) DN_HTableValueFromFind(&dn->mem_debugger.mem_list_table, &mem); + if (entry) { + DN_TicketMutexBegin(&entry->alloc_mutex); + DN_MemDebuggerMemListAlloc alloc = {}; + alloc.ptr = ptr; + alloc.size = size; + alloc.alloc_size = alloc_size; + alloc.position = DN_MemListPos(mem) - size; + alloc.align = align; + alloc.call_site = call_site; + DN_PArrayAppendHeap(entry->allocs, &entry->allocs_count, &entry->allocs_max, &dn->mem_debugger.heap, alloc); + DN_TicketMutexEnd(&entry->alloc_mutex); + } + DN_TicketMutexEnd(&dn->mem_debugger.mem_list_mutex); +} + +static void DN_MemDebuggerMemListAllocsSync_(DN_MemList *mem) +{ + DN_Core *dn = g_dn_; + if (!dn || !mem || !dn->mem_debugger.mem_list_table.kvs) + return; + if (DN_BitIsSet(mem->heap.flags, DN_HeapFlags_ExcludeFromMemDebugger)) + return; + + // NOTE: The tail block's used watermark (absolute list position). Any tracked allocation whose data + // ends above it was freed by the reset and can be dropped. Allocations are appended in ascending + // list-position order, so the freed ones form a suffix that we pop off. No block walk required. + DN_U64 live_end = DN_MemListPos(mem); + + DN_TicketMutexBegin(&dn->mem_debugger.mem_list_mutex); + DN_MemDebuggerMemList *entry = DN_Cast(DN_MemDebuggerMemList *) DN_HTableValueFromFind(&dn->mem_debugger.mem_list_table, &mem); + if (entry) { + DN_TicketMutexBegin(&entry->alloc_mutex); + while (entry->allocs_count && entry->allocs[entry->allocs_count - 1].position + entry->allocs[entry->allocs_count - 1].size > live_end) + entry->allocs_count--; + DN_TicketMutexEnd(&entry->alloc_mutex); + } + DN_TicketMutexEnd(&dn->mem_debugger.mem_list_mutex); +} +#else + #define DN_MemDebuggerMemListRegister_(mem) ((void)(mem)) + #define DN_MemDebuggerMemListUnregister_(mem) ((void)(mem)) + #define DN_MemDebuggerMemListAllocTrack_(mem, ptr, size, alloc_size, align, call_site) ((void)0) + #define DN_MemDebuggerMemListAllocsSync_(mem) ((void)(mem)) +#endif + +#if DN_MEM_DEBUGGER +static void DN_MemDebuggerCommitUpdateLocked_(DN_MemDebugger *debugger, DN_MemBlock *block) +{ + DN_UPtr uptr = DN_Cast(DN_UPtr) block; + DN_MemDebuggerPtrData *alloc = DN_Cast(DN_MemDebuggerPtrData *) DN_HTableValueFromFind(&debugger->alloc_table, &uptr); + if (alloc && (alloc->flags & DN_MemDebuggerPtrFlag_Freed) == 0) + alloc->bytes[DN_MemDebuggerAllocType_Commit] = block->commit; +} + +static void DN_MemDebuggerCommitUpdate_(DN_MemList *mem, DN_MemBlock *block) +{ + DN_Core *dn = g_dn_; + if (!dn || !mem || !block || !dn->mem_debugger.alloc_table.kvs) + return; + + // NOTE: Excluded heaps are not tracked by the debugger, and the snapshot holds the alloc table + // mutex while it allocates from its own (excluded) arena, so skip excluded heaps to avoid a + // re-entrant deadlock. + if (DN_BitIsSet(mem->heap.flags, DN_HeapFlags_ExcludeFromMemDebugger)) + return; + + DN_TicketMutexBegin(&dn->mem_debugger.alloc_table_mutex); + DN_MemDebuggerCommitUpdateLocked_(&dn->mem_debugger, block); + DN_TicketMutexEnd(&dn->mem_debugger.alloc_table_mutex); +} +#else + #define DN_MemDebuggerCommitUpdate_(mem, block) ((void)(mem), (void)(block)) + #define DN_MemDebuggerCommitUpdateLocked_(debugger, block) ((void)(debugger), (void)(block)) +#endif + DN_API void DN_Init(DN_Core *dn, DN_InitFlags flags, DN_TcInitArgs args) { + (void)args; DN_Set(dn); dn->init_flags = flags; @@ -59,7 +185,7 @@ DN_API void DN_Init(DN_Core *dn, DN_InitFlags flags, DN_TcInitArgs args) heap.flags |= DN_HeapFlags_ExcludeFromMemDebugger; os->mem = DN_MemListFromHeap(DN_Megabytes(1), DN_Kilobytes(4), DN_MemFlags_Nil, heap, "DN OS MemList"); - os->arena = DN_ArenaFromMemList(&os->mem); + os->arena = DN_ArenaFromMemList(os->mem); #if defined(DN_PLATFORM_WIN32) os->platform_context = DN_ArenaNew(&os->arena, DN_OSW32Core, DN_ZMem_Yes); @@ -79,32 +205,41 @@ DN_API void DN_Init(DN_Core *dn, DN_InitFlags flags, DN_TcInitArgs args) #if DN_MEM_DEBUGGER // NOTE: Setup the mem debugger table with allocation tracking turned off on because we're // allocating before we've setup the table to track allocations itself (and would otherwise cause an recursive loop). - DN_Heap heap = DN_OS_HeapInitBasic(); - heap.flags |= DN_HeapFlags_ExcludeFromMemDebugger; + dn->mem_debugger.heap = DN_OS_HeapInitBasic(); + dn->mem_debugger.heap.flags |= DN_HeapFlags_ExcludeFromMemDebugger; + if (DN_BitIsSet(flags, DN_InitFlags_MemDebuggerHeapAllocCallSiteStrings)) + dn->mem_debugger.flags |= DN_MemDebuggerFlags_HeapAllocCallSiteStrings; + DN_CallSite alloc_call_site = DN_CallSiteNowNamed("DN Memory Debugger Hash Table"); DN_HTableInitArgs table_args = DN_HTableInitArgsDefault(DN_MemDebuggerKV, dn->mem_debugger.alloc_table_kvs, hash, key, value); - dn->mem_debugger.alloc_table = DN_HTableInitHeapAssert(table_args, heap); + dn->mem_debugger.alloc_table = DN_HTableInitHeapAssert(table_args, &dn->mem_debugger.heap); - // NOTE: Unset the exclusion flag and manually add the pointers we allocator - os->mem.heap.flags &= ~DN_HeapFlags_ExcludeFromMemDebugger; + DN_HTableInitArgs mem_list_table_args = DN_HTableInitArgsDefault(DN_MemDebuggerMemListKV, dn->mem_debugger.mem_list_kvs, hash, key, value); + dn->mem_debugger.mem_list_table = DN_HTableInitHeapAssert(mem_list_table_args, &dn->mem_debugger.heap); + + // NOTE: Unset the exclusion flag and manually add the pointers we allocated + os->mem->heap.flags &= ~DN_HeapFlags_ExcludeFromMemDebugger; for (DN_MemBlock *block = os->arena.mem->curr; block; block = block->prev) - DN_MemDebuggerAlloc(&dn->mem_debugger, block, block->reserve, /*alloc_can_leak=*/true, alloc_call_site); + DN_MemDebuggerAlloc(&dn->mem_debugger, block, block->reserve, block->commit, /*alloc_can_leak=*/true, alloc_call_site); + + // NOTE: The OS mem list was created before the registry existed, register it now + DN_MemDebuggerMemListRegister_(os->mem); #endif } - os->cpu_report = DN_CPUGetReport(); + os->cpu_report = DN_CpuGetReport(); - #define DN_CPU_FEAT_XENTRY(label) g_dn_cpu_feature_decl[DN_CPUFeature_##label] = {DN_CPUFeature_##label, DN_Str8Lit(#label)}; - DN_CPU_FEAT_XMACRO - #undef DN_CPU_FEAT_XENTRY + #define DN_Cpu_FEAT_XENTRY(label) g_dn_cpu_feature_decl[DN_CpuFeature_##label] = {DN_CpuFeature_##label, DN_Str8Lit(#label)}; + DN_Cpu_FEAT_XMACRO + #undef DN_Cpu_FEAT_XENTRY DN_Assert(g_dn_); - #endif // NOTE: Initialise thread context DN_Heap tc_heap = DN_OS_HeapInitDefault(); tc_heap.flags |= DN_HeapFlags_MemDebuggerCanLeakPtr; DN_TcInitFromHeap(&dn->main_tc, DN_OS_ThreadID(), args, tc_heap); DN_TcEquip(&dn->main_tc); + #endif // DN_WITH_OS } // NOTE: Print out init features @@ -172,19 +307,19 @@ DN_API void DN_Init(DN_Core *dn, DN_InitFlags flags, DN_TcInitArgs args) if (DN_BitIsSet(flags, DN_InitFlags_LogCPUFeatures)) { DN_Assert(dn->os_init); #if DN_WITH_OS - DN_CPUReport const *report = &dn->os.cpu_report; + DN_CpuReport const *report = &dn->os.cpu_report; DN_Str8 brand = DN_Str8TrimWhitespaceAround(DN_Str8FromPtr(report->brand, sizeof(report->brand) - 1)); DN_FmtAppendTruncate(buf, &buf_size, sizeof(buf), DN_Str8Lit("..."), " CPU '%.*s' from '%s' detected:\n", DN_Str8PrintFmt(brand), report->vendor); DN_USize longest_feature_name = 0; - for (DN_ForIndexU(feature_index, DN_CPUFeature_Count)) { - DN_CPUFeatureDecl feature_decl = g_dn_cpu_feature_decl[feature_index]; + for (DN_ForIndexU(feature_index, DN_CpuFeature_Count)) { + DN_CpuFeatureDecl feature_decl = g_dn_cpu_feature_decl[feature_index]; longest_feature_name = DN_Max(longest_feature_name, feature_decl.label.count); } - for (DN_ForIndexU(feature_index, DN_CPUFeature_Count)) { - DN_CPUFeatureDecl feature_decl = g_dn_cpu_feature_decl[feature_index]; - bool has_feature = DN_CPUHasFeature(report, feature_decl.value); + for (DN_ForIndexU(feature_index, DN_CpuFeature_Count)) { + DN_CpuFeatureDecl feature_decl = g_dn_cpu_feature_decl[feature_index]; + bool has_feature = DN_CpuHasFeature(report, feature_decl.value); DN_FmtAppendTruncate(buf, &buf_size, sizeof(buf), @@ -205,6 +340,7 @@ DN_API void DN_Init(DN_Core *dn, DN_InitFlags flags, DN_TcInitArgs args) DN_API void DN_Set(DN_Core *dn) { g_dn_ = dn; + DN_TcEquip(&dn->main_tc); } DN_API DN_Core *DN_Get() @@ -294,7 +430,7 @@ DN_API bool DN_MemEqUnsafe(void const *lhs, void const *rhs, DN_USize count) #include #endif -DN_CPUFeatureDecl g_dn_cpu_feature_decl[DN_CPUFeature_Count]; +DN_CpuFeatureDecl g_dn_cpu_feature_decl[DN_CpuFeature_Count]; DN_API DN_U64 DN_AtomicSetValue64(DN_U64 volatile *target, DN_U64 value) { @@ -362,21 +498,21 @@ DN_API void DN_ByteSwapU64Ptr(DN_U8 *dest, DN_U64 src) dest[7] = DN_Cast(DN_U8)(src & 0xFF); } -DN_API DN_CPUIDResult DN_CPUID(DN_CPUIDArgs args) +DN_API DN_CpuIDResult DN_CpuID(DN_CpuIDArgs args) { - DN_CPUIDResult result = {}; + DN_CpuIDResult result = {}; #if defined(DN_SUPPORTS_CPU_ID) __cpuidex(result.values, args.eax, args.ecx); #endif return result; } -DN_API DN_USize DN_CPUHasFeatureArray(DN_CPUReport const *report, DN_CPUFeatureQuery *features, DN_USize features_size) +DN_API DN_USize DN_CpuHasFeatureArray(DN_CpuReport const *report, DN_CpuFeatureQuery *features, DN_USize features_size) { DN_USize result = 0; DN_USize const BITS = sizeof(report->features[0]) * 8; for (DN_ForIndexU(feature_index, features_size)) { - DN_CPUFeatureQuery *query = features + feature_index; + DN_CpuFeatureQuery *query = features + feature_index; DN_USize chunk_index = query->feature / BITS; DN_USize chunk_bit = query->feature % BITS; DN_U64 chunk = report->features[chunk_index]; @@ -387,52 +523,52 @@ DN_API DN_USize DN_CPUHasFeatureArray(DN_CPUReport const *report, DN_CPUFeatureQ return result; } -DN_API bool DN_CPUHasFeature(DN_CPUReport const *report, DN_CPUFeature feature) +DN_API bool DN_CpuHasFeature(DN_CpuReport const *report, DN_CpuFeature feature) { - DN_CPUFeatureQuery query = {}; + DN_CpuFeatureQuery query = {}; query.feature = feature; - bool result = DN_CPUHasFeatureArray(report, &query, 1) == 1; + bool result = DN_CpuHasFeatureArray(report, &query, 1) == 1; return result; } -DN_API bool DN_CPUHasAllFeatures(DN_CPUReport const *report, DN_CPUFeature const *features, DN_USize features_size) +DN_API bool DN_CpuHasAllFeatures(DN_CpuReport const *report, DN_CpuFeature const *features, DN_USize features_size) { bool result = true; for (DN_USize index = 0; result && index < features_size; index++) - result &= DN_CPUHasFeature(report, features[index]); + result &= DN_CpuHasFeature(report, features[index]); return result; } -DN_API void DN_CPUSetFeature(DN_CPUReport *report, DN_CPUFeature feature) +DN_API void DN_CpuSetFeature(DN_CpuReport *report, DN_CpuFeature feature) { - DN_Assert(feature < DN_CPUFeature_Count); + DN_Assert(feature < DN_CpuFeature_Count); DN_USize const BITS = sizeof(report->features[0]) * 8; DN_USize chunk_index = feature / BITS; DN_USize chunk_bit = feature % BITS; report->features[chunk_index] |= (1ULL << chunk_bit); } -DN_API DN_CPUReport DN_CPUGetReport() +DN_API DN_CpuReport DN_CpuGetReport() { - DN_CPUReport result = {}; + DN_CpuReport result = {}; #if defined(DN_SUPPORTS_CPU_ID) - DN_CPUIDResult fn_0000_[500] = {}; - DN_CPUIDResult fn_8000_[500] = {}; + DN_CpuIDResult fn_0000_[500] = {}; + DN_CpuIDResult fn_8000_[500] = {}; int const EXTENDED_FUNC_BASE_EAX = 0x8000'0000; int const REGISTER_SIZE = sizeof(fn_0000_[0].reg.eax); // NOTE: Query standard/extended numbers { - DN_CPUIDArgs args = {}; + DN_CpuIDArgs args = {}; // NOTE: Query standard function (e.g. eax = 0x0) for function count + cpu vendor args = {}; - fn_0000_[0] = DN_CPUID(args); + fn_0000_[0] = DN_CpuID(args); // NOTE: Query extended function (e.g. eax = 0x8000'0000) for function count + cpu vendor args = {}; args.eax = DN_Cast(int) EXTENDED_FUNC_BASE_EAX; - fn_8000_[0] = DN_CPUID(args); + fn_8000_[0] = DN_CpuID(args); } // NOTE: Extract function count @@ -449,15 +585,15 @@ DN_API DN_CPUReport DN_CPUGetReport() DN_Cast(DN_ISize) EXTENDED_FUNC_MAX_EAX - EXTENDED_FUNC_BASE_EAX + 1); for (int eax = 1; eax <= STANDARD_FUNC_MAX_EAX; eax++) { - DN_CPUIDArgs args = {}; + DN_CpuIDArgs args = {}; args.eax = eax; - fn_0000_[eax] = DN_CPUID(args); + fn_0000_[eax] = DN_CpuID(args); } for (int eax = EXTENDED_FUNC_BASE_EAX + 1, index = 1; eax <= EXTENDED_FUNC_MAX_EAX; eax++, index++) { - DN_CPUIDArgs args = {}; + DN_CpuIDArgs args = {}; args.eax = eax; - fn_8000_[index] = DN_CPUID(args); + fn_8000_[index] = DN_CpuID(args); } } @@ -489,77 +625,83 @@ DN_API DN_CPUReport DN_CPUGetReport() } // NOTE: Query CPU features - for (DN_USize ext_index = 0; ext_index < DN_CPUFeature_Count; ext_index++) { + for (DN_USize ext_index = 0; ext_index < DN_CpuFeature_Count; ext_index++) { bool available = false; // NOTE: Mask bits taken from various manuals // - AMD64 Architecture Programmer's Manual, Volumes 1-5 // - https://en.wikipedia.org/wiki/CPUID#Calling_CPUID - switch (DN_Cast(DN_CPUFeature) ext_index) { - case DN_CPUFeature_3DNow: available = (fn_8000_[0x0001].reg.edx & (1 << 31)); break; - case DN_CPUFeature_3DNowExt: available = (fn_8000_[0x0001].reg.edx & (1 << 30)); break; - case DN_CPUFeature_ABM: available = (fn_8000_[0x0001].reg.ecx & (1 << 5)); break; - case DN_CPUFeature_AES: available = (fn_0000_[0x0001].reg.ecx & (1 << 25)); break; - case DN_CPUFeature_AVX: available = (fn_0000_[0x0001].reg.ecx & (1 << 28)); break; - case DN_CPUFeature_AVX2: available = (fn_0000_[0x0007].reg.ebx & (1 << 0)); break; - case DN_CPUFeature_AVX512F: available = (fn_0000_[0x0007].reg.ebx & (1 << 16)); break; - case DN_CPUFeature_AVX512DQ: available = (fn_0000_[0x0007].reg.ebx & (1 << 17)); break; - case DN_CPUFeature_AVX512IFMA: available = (fn_0000_[0x0007].reg.ebx & (1 << 21)); break; - case DN_CPUFeature_AVX512PF: available = (fn_0000_[0x0007].reg.ebx & (1 << 26)); break; - case DN_CPUFeature_AVX512ER: available = (fn_0000_[0x0007].reg.ebx & (1 << 27)); break; - case DN_CPUFeature_AVX512CD: available = (fn_0000_[0x0007].reg.ebx & (1 << 28)); break; - case DN_CPUFeature_AVX512BW: available = (fn_0000_[0x0007].reg.ebx & (1 << 30)); break; - case DN_CPUFeature_AVX512VL: available = (fn_0000_[0x0007].reg.ebx & (1 << 31)); break; - case DN_CPUFeature_AVX512VBMI: available = (fn_0000_[0x0007].reg.ecx & (1 << 1)); break; - case DN_CPUFeature_AVX512VBMI2: available = (fn_0000_[0x0007].reg.ecx & (1 << 6)); break; - case DN_CPUFeature_AVX512VNNI: available = (fn_0000_[0x0007].reg.ecx & (1 << 11)); break; - case DN_CPUFeature_AVX512BITALG: available = (fn_0000_[0x0007].reg.ecx & (1 << 12)); break; - case DN_CPUFeature_AVX512VPOPCNTDQ: available = (fn_0000_[0x0007].reg.ecx & (1 << 14)); break; - case DN_CPUFeature_AVX5124VNNIW: available = (fn_0000_[0x0007].reg.edx & (1 << 2)); break; - case DN_CPUFeature_AVX5124FMAPS: available = (fn_0000_[0x0007].reg.edx & (1 << 3)); break; - case DN_CPUFeature_AVX512VP2INTERSECT: available = (fn_0000_[0x0007].reg.edx & (1 << 8)); break; - case DN_CPUFeature_AVX512FP16: available = (fn_0000_[0x0007].reg.edx & (1 << 23)); break; - case DN_CPUFeature_CLZERO: available = (fn_8000_[0x0008].reg.ebx & (1 << 0)); break; - case DN_CPUFeature_CMPXCHG8B: available = (fn_0000_[0x0001].reg.edx & (1 << 8)); break; - case DN_CPUFeature_CMPXCHG16B: available = (fn_0000_[0x0001].reg.ecx & (1 << 13)); break; - case DN_CPUFeature_F16C: available = (fn_0000_[0x0001].reg.ecx & (1 << 29)); break; - case DN_CPUFeature_FMA: available = (fn_0000_[0x0001].reg.ecx & (1 << 12)); break; - case DN_CPUFeature_FMA4: available = (fn_8000_[0x0001].reg.ecx & (1 << 16)); break; - case DN_CPUFeature_FP128: available = (fn_8000_[0x001A].reg.eax & (1 << 0)); break; - case DN_CPUFeature_FP256: available = (fn_8000_[0x001A].reg.eax & (1 << 2)); break; - case DN_CPUFeature_FPU: available = (fn_0000_[0x0001].reg.edx & (1 << 0)); break; - case DN_CPUFeature_MMX: available = (fn_0000_[0x0001].reg.edx & (1 << 23)); break; - case DN_CPUFeature_MONITOR: available = (fn_0000_[0x0001].reg.ecx & (1 << 3)); break; - case DN_CPUFeature_MOVBE: available = (fn_0000_[0x0001].reg.ecx & (1 << 22)); break; - case DN_CPUFeature_MOVU: available = (fn_8000_[0x001A].reg.eax & (1 << 1)); break; - case DN_CPUFeature_MmxExt: available = (fn_8000_[0x0001].reg.edx & (1 << 22)); break; - case DN_CPUFeature_PCLMULQDQ: available = (fn_0000_[0x0001].reg.ecx & (1 << 1)); break; - case DN_CPUFeature_POPCNT: available = (fn_0000_[0x0001].reg.ecx & (1 << 23)); break; - case DN_CPUFeature_RDRAND: available = (fn_0000_[0x0001].reg.ecx & (1 << 30)); break; - case DN_CPUFeature_RDSEED: available = (fn_0000_[0x0007].reg.ebx & (1 << 18)); break; - case DN_CPUFeature_RDTscP: available = (fn_8000_[0x0001].reg.edx & (1 << 27)); break; - case DN_CPUFeature_SHA: available = (fn_0000_[0x0007].reg.ebx & (1 << 29)); break; - case DN_CPUFeature_SSE: available = (fn_0000_[0x0001].reg.edx & (1 << 25)); break; - case DN_CPUFeature_SSE2: available = (fn_0000_[0x0001].reg.edx & (1 << 26)); break; - case DN_CPUFeature_SSE3: available = (fn_0000_[0x0001].reg.ecx & (1 << 0)); break; - case DN_CPUFeature_SSE41: available = (fn_0000_[0x0001].reg.ecx & (1 << 19)); break; - case DN_CPUFeature_SSE42: available = (fn_0000_[0x0001].reg.ecx & (1 << 20)); break; - case DN_CPUFeature_SSE4A: available = (fn_8000_[0x0001].reg.ecx & (1 << 6)); break; - case DN_CPUFeature_SSSE3: available = (fn_0000_[0x0001].reg.ecx & (1 << 9)); break; - case DN_CPUFeature_Tsc: available = (fn_0000_[0x0001].reg.edx & (1 << 4)); break; - case DN_CPUFeature_TscInvariant: available = (fn_8000_[0x0007].reg.edx & (1 << 8)); break; - case DN_CPUFeature_VAES: available = (fn_0000_[0x0007].reg.ecx & (1 << 9)); break; - case DN_CPUFeature_VPCMULQDQ: available = (fn_0000_[0x0007].reg.ecx & (1 << 10)); break; - case DN_CPUFeature_Count: DN_AssertInvalidCodePath; break; + switch (DN_Cast(DN_CpuFeature) ext_index) { + case DN_CpuFeature_3DNow: available = (fn_8000_[0x0001].reg.edx & (1 << 31)); break; + case DN_CpuFeature_3DNowExt: available = (fn_8000_[0x0001].reg.edx & (1 << 30)); break; + case DN_CpuFeature_ABM: available = (fn_8000_[0x0001].reg.ecx & (1 << 5)); break; + case DN_CpuFeature_AES: available = (fn_0000_[0x0001].reg.ecx & (1 << 25)); break; + case DN_CpuFeature_AVX: available = (fn_0000_[0x0001].reg.ecx & (1 << 28)); break; + case DN_CpuFeature_AVX2: available = (fn_0000_[0x0007].reg.ebx & (1 << 0)); break; + case DN_CpuFeature_AVX512F: available = (fn_0000_[0x0007].reg.ebx & (1 << 16)); break; + case DN_CpuFeature_AVX512DQ: available = (fn_0000_[0x0007].reg.ebx & (1 << 17)); break; + case DN_CpuFeature_AVX512IFMA: available = (fn_0000_[0x0007].reg.ebx & (1 << 21)); break; + case DN_CpuFeature_AVX512PF: available = (fn_0000_[0x0007].reg.ebx & (1 << 26)); break; + case DN_CpuFeature_AVX512ER: available = (fn_0000_[0x0007].reg.ebx & (1 << 27)); break; + case DN_CpuFeature_AVX512CD: available = (fn_0000_[0x0007].reg.ebx & (1 << 28)); break; + case DN_CpuFeature_AVX512BW: available = (fn_0000_[0x0007].reg.ebx & (1 << 30)); break; + case DN_CpuFeature_AVX512VL: available = (fn_0000_[0x0007].reg.ebx & (1 << 31)); break; + case DN_CpuFeature_AVX512VBMI: available = (fn_0000_[0x0007].reg.ecx & (1 << 1)); break; + case DN_CpuFeature_AVX512VBMI2: available = (fn_0000_[0x0007].reg.ecx & (1 << 6)); break; + case DN_CpuFeature_AVX512VNNI: available = (fn_0000_[0x0007].reg.ecx & (1 << 11)); break; + case DN_CpuFeature_AVX512BITALG: available = (fn_0000_[0x0007].reg.ecx & (1 << 12)); break; + case DN_CpuFeature_AVX512VPOPCNTDQ: available = (fn_0000_[0x0007].reg.ecx & (1 << 14)); break; + case DN_CpuFeature_AVX5124VNNIW: available = (fn_0000_[0x0007].reg.edx & (1 << 2)); break; + case DN_CpuFeature_AVX5124FMAPS: available = (fn_0000_[0x0007].reg.edx & (1 << 3)); break; + case DN_CpuFeature_AVX512VP2INTERSECT: available = (fn_0000_[0x0007].reg.edx & (1 << 8)); break; + case DN_CpuFeature_AVX512FP16: available = (fn_0000_[0x0007].reg.edx & (1 << 23)); break; + case DN_CpuFeature_CLZERO: available = (fn_8000_[0x0008].reg.ebx & (1 << 0)); break; + case DN_CpuFeature_CMPXCHG8B: available = (fn_0000_[0x0001].reg.edx & (1 << 8)); break; + case DN_CpuFeature_CMPXCHG16B: available = (fn_0000_[0x0001].reg.ecx & (1 << 13)); break; + case DN_CpuFeature_F16C: available = (fn_0000_[0x0001].reg.ecx & (1 << 29)); break; + case DN_CpuFeature_FMA: available = (fn_0000_[0x0001].reg.ecx & (1 << 12)); break; + case DN_CpuFeature_FMA4: available = (fn_8000_[0x0001].reg.ecx & (1 << 16)); break; + case DN_CpuFeature_FP128: available = (fn_8000_[0x001A].reg.eax & (1 << 0)); break; + case DN_CpuFeature_FP256: available = (fn_8000_[0x001A].reg.eax & (1 << 2)); break; + case DN_CpuFeature_FPU: available = (fn_0000_[0x0001].reg.edx & (1 << 0)); break; + case DN_CpuFeature_MMX: available = (fn_0000_[0x0001].reg.edx & (1 << 23)); break; + case DN_CpuFeature_MONITOR: available = (fn_0000_[0x0001].reg.ecx & (1 << 3)); break; + case DN_CpuFeature_MOVBE: available = (fn_0000_[0x0001].reg.ecx & (1 << 22)); break; + case DN_CpuFeature_MOVU: available = (fn_8000_[0x001A].reg.eax & (1 << 1)); break; + case DN_CpuFeature_MmxExt: available = (fn_8000_[0x0001].reg.edx & (1 << 22)); break; + case DN_CpuFeature_PCLMULQDQ: available = (fn_0000_[0x0001].reg.ecx & (1 << 1)); break; + case DN_CpuFeature_POPCNT: available = (fn_0000_[0x0001].reg.ecx & (1 << 23)); break; + case DN_CpuFeature_RDRAND: available = (fn_0000_[0x0001].reg.ecx & (1 << 30)); break; + case DN_CpuFeature_RDSEED: available = (fn_0000_[0x0007].reg.ebx & (1 << 18)); break; + case DN_CpuFeature_RDTscP: available = (fn_8000_[0x0001].reg.edx & (1 << 27)); break; + case DN_CpuFeature_SHA: available = (fn_0000_[0x0007].reg.ebx & (1 << 29)); break; + case DN_CpuFeature_SSE: available = (fn_0000_[0x0001].reg.edx & (1 << 25)); break; + case DN_CpuFeature_SSE2: available = (fn_0000_[0x0001].reg.edx & (1 << 26)); break; + case DN_CpuFeature_SSE3: available = (fn_0000_[0x0001].reg.ecx & (1 << 0)); break; + case DN_CpuFeature_SSE41: available = (fn_0000_[0x0001].reg.ecx & (1 << 19)); break; + case DN_CpuFeature_SSE42: available = (fn_0000_[0x0001].reg.ecx & (1 << 20)); break; + case DN_CpuFeature_SSE4A: available = (fn_8000_[0x0001].reg.ecx & (1 << 6)); break; + case DN_CpuFeature_SSSE3: available = (fn_0000_[0x0001].reg.ecx & (1 << 9)); break; + case DN_CpuFeature_Tsc: available = (fn_0000_[0x0001].reg.edx & (1 << 4)); break; + case DN_CpuFeature_TscInvariant: available = (fn_8000_[0x0007].reg.edx & (1 << 8)); break; + case DN_CpuFeature_VAES: available = (fn_0000_[0x0007].reg.ecx & (1 << 9)); break; + case DN_CpuFeature_VPCMULQDQ: available = (fn_0000_[0x0007].reg.ecx & (1 << 10)); break; + case DN_CpuFeature_Count: DN_AssertInvalidCodePath; break; } if (available) - DN_CPUSetFeature(&result, DN_Cast(DN_CPUFeature) ext_index); + DN_CpuSetFeature(&result, DN_Cast(DN_CpuFeature) ext_index); } #endif // DN_SUPPORTS_CPU_ID return result; } +DN_API DN_U64 DN_CpuTscNowFunctionWrapper() +{ + DN_U64 result = DN_CpuTscNow(); + return result; +} + DN_API void DN_TicketMutexBegin(DN_TicketMutex *mutex) { DN_UInt ticket = DN_AtomicAddU32(&mutex->ticket, 1); @@ -1091,7 +1233,7 @@ static DN_MemBlock *DN_MemBlockFromHeap_(DN_U64 reserve, DN_U64 commit, DN_Heap real_reserve = DN_ARENA_RESERVE_SIZE; DN_AssertF(real_reserve > DN_ARENA_HEADER_SIZE, "%I64u > %I64u", real_reserve, DN_ARENA_HEADER_SIZE); - result = DN_Cast(DN_MemBlock *) DN_HeapAllocCallSite(&heap, real_reserve, 0, DN_HeapAllocFlag_Nil, call_site); + result = DN_Cast(DN_MemBlock *) DN_HeapAllocCallSite(&heap, real_reserve, real_reserve, DN_HeapAllocFlag_Nil, call_site); if (!result) return result; @@ -1210,32 +1352,34 @@ DN_API DN_Heap DN_HeapInitVirtual(DN_U32 page_size, DN_HeapVirtualReserveFunc *v DN_API void *DN_HeapAllocCallSite(DN_Heap *heap, DN_USize reserve, DN_USize commit, DN_HeapAllocFlag flags, DN_CallSite call_site) { void *result = nullptr; - switch (heap->type) { - case DN_HeapType_Nil: - break; + if (heap) { + switch (heap->type) { + case DN_HeapType_Nil: + break; - case DN_HeapType_Basic: { - result = heap->basic_alloc(reserve); - } break; - case DN_HeapType_Virtual: { - DN_MemCommit mem_commit = reserve == commit ? DN_MemCommit_Yes : DN_MemCommit_No; - result = DN_Cast(DN_MemBlock *) heap->virtual_reserve(reserve, mem_commit, DN_MemPage_ReadWrite); - if (result) { - bool commit_success = true; - if (mem_commit == DN_MemCommit_No && commit > 0) { - // NOTE: If mem-commit is yes, then the entire block of memory that was reserved is - // committed in the same syscall as the allocation itself as an optimisation. If - // mem-commit is no, which is this branch, then we commit just the range that the user - // requested in `commit`. - commit_success = heap->virtual_commit(result, commit, DN_MemPage_ReadWrite); - } + case DN_HeapType_Basic: { + result = heap->basic_alloc(reserve); + } break; + case DN_HeapType_Virtual: { + DN_MemCommit mem_commit = reserve == commit ? DN_MemCommit_Yes : DN_MemCommit_No; + result = DN_Cast(DN_MemBlock *) heap->virtual_reserve(reserve, mem_commit, DN_MemPage_ReadWrite); + if (result) { + bool commit_success = true; + if (mem_commit == DN_MemCommit_No && commit > 0) { + // NOTE: If mem-commit is yes, then the entire block of memory that was reserved is + // committed in the same syscall as the allocation itself as an optimisation. If + // mem-commit is no, which is this branch, then we commit just the range that the user + // requested in `commit`. + commit_success = heap->virtual_commit(result, commit, DN_MemPage_ReadWrite); + } - if (!commit_success) { - heap->virtual_release(result, reserve); - result = nullptr; + if (!commit_success) { + heap->virtual_release(result, reserve); + result = nullptr; + } } - } - } break; + } break; + } } if (result) { @@ -1245,7 +1389,7 @@ DN_API void *DN_HeapAllocCallSite(DN_Heap *heap, DN_USize reserve, DN_USize comm DN_BitIsNotSet(heap->flags, DN_HeapFlags_ExcludeFromMemDebugger)) { (void)call_site; bool ptr_can_leak = flags & DN_HeapAllocFlag_MemDebuggerCanLeakPtr || heap->flags & DN_HeapFlags_MemDebuggerCanLeakPtr; - DN_MemDebuggerAlloc(&g_dn_->mem_debugger, result, reserve, ptr_can_leak, call_site); + DN_MemDebuggerAlloc(&g_dn_->mem_debugger, result, reserve, commit, ptr_can_leak, call_site); } } return result; @@ -1265,7 +1409,7 @@ DN_API void DN_HeapDealloc(DN_Heap *heap, void *ptr, DN_USize size) heap->virtual_release(ptr, size); } -DN_API DN_MemList DN_MemListFromBuffer(void *buffer, DN_USize size, DN_MemFlags flags) +DN_API DN_MemList* DN_MemListFromBufferCallSite(void *buffer, DN_USize size, DN_MemFlags flags, DN_CallSite call_site) { DN_Assert(buffer); DN_AssertF(DN_ARENA_HEADER_SIZE < size, "Buffer (%zu bytes) too small, need atleast %zu bytes to store arena metadata", size, DN_ARENA_HEADER_SIZE); @@ -1273,27 +1417,41 @@ DN_API DN_MemList DN_MemListFromBuffer(void *buffer, DN_USize size, DN_MemFlags // NOTE: Init block DN_MemBlock *block = DN_Cast(DN_MemBlock *) buffer; + block->prev = nullptr; block->commit = size; block->reserve = size; block->used = DN_ARENA_HEADER_SIZE; + block->reserve_sum = 0; if (block && DN_ArenaHasPoison_(flags)) DN_ASanPoisonMemoryRegion(DN_Cast(char *) block + DN_ARENA_HEADER_SIZE, block->commit - DN_ARENA_HEADER_SIZE); - DN_MemList result = {}; - result.flags = flags | DN_MemFlags_NoGrow | DN_MemFlags_UserBuffer; - result.curr = block; - DN_MemListOnNewBlock_(&result, result.curr); - return result; + // NOTE: The memory list lives in the block header, immediately after the block + DN_MemList *mem = DN_Cast(DN_MemList *) (DN_Cast(char *) block + DN_MEM_LIST_OFFSET); + *mem = {}; + mem->flags = flags | DN_MemFlags_NoGrow | DN_MemFlags_UserBuffer; + mem->curr = block; + mem->label = call_site.name; + DN_MemListOnNewBlock_(mem, block); + DN_MemDebuggerMemListRegister_(mem); + return mem; } -DN_API DN_MemList DN_MemListFromHeapCallSite(DN_U64 reserve, DN_U64 commit, DN_MemFlags flags, DN_Heap heap, DN_CallSite call_site) +DN_API DN_MemList* DN_MemListFromHeapCallSite(DN_U64 reserve, DN_U64 commit, DN_MemFlags flags, DN_Heap heap, DN_CallSite call_site) { - DN_MemList result = {}; - result.heap = heap; - result.flags |= flags | DN_MemFlags_Heap; - result.curr = DN_MemBlockFromHeapFlags_(reserve, commit, flags, heap, call_site); - DN_MemListOnNewBlock_(&result, result.curr); - return result; + DN_MemBlock *block = DN_MemBlockFromHeapFlags_(reserve, commit, flags, heap, call_site); + if (!block) + return nullptr; + + // NOTE: The memory list lives in the block header, immediately after the block + DN_MemList *mem = DN_Cast(DN_MemList *) (DN_Cast(char *) block + DN_MEM_LIST_OFFSET); + *mem = {}; + mem->heap = heap; + mem->flags = flags | DN_MemFlags_Heap; + mem->curr = block; + mem->label = call_site.name; + DN_MemListOnNewBlock_(mem, block); + DN_MemDebuggerMemListRegister_(mem); + return mem; } static void DN_MemBlockDeinit_(DN_MemList *mem, DN_MemBlock *block) @@ -1301,19 +1459,37 @@ static void DN_MemBlockDeinit_(DN_MemList *mem, DN_MemBlock *block) DN_USize release_size = block->reserve; if (DN_ArenaHasPoison_(mem->flags)) DN_ASanUnpoisonMemoryRegion(block, block->commit); + // NOTE: The DN_MemBlock stays at the allocation base (the memory list is stored in the header + // after it), so the block pointer can be freed directly. if (mem->flags & DN_MemFlags_Heap) DN_HeapDealloc(&mem->heap, block, release_size); } DN_API void DN_MemListDeinit(DN_MemList *mem) { - bool mem_allocated_from_itself = DN_MemListOwnsPtr(mem, mem); - for (DN_MemBlock *block = mem ? mem->curr : nullptr; block;) { + if (!mem) + return; + + DN_MemDebuggerMemListUnregister_(mem); + + // NOTE: The memory list is embedded in the first block's header (see DN_MEM_LIST_OFFSET), so it + // must not be zeroed after the blocks have been freed. + bool mem_in_block_header = false; + for (DN_MemBlock *block = mem->curr; block && !mem_in_block_header; block = block->prev) { + char *begin = (char *)block; + char *end = begin + DN_ARENA_HEADER_SIZE; + char *ptr = (char *)mem; + mem_in_block_header = ptr >= begin && ptr < end; + } + if (!mem_in_block_header) + mem_in_block_header = DN_MemListOwnsPtr(mem, mem); + + for (DN_MemBlock *block = mem->curr; block;) { DN_MemBlock *block_to_free = block; block = block->prev; DN_MemBlockDeinit_(mem, block_to_free); } - if (mem && !mem_allocated_from_itself) + if (!mem_in_block_header) *mem = {}; } @@ -1346,6 +1522,7 @@ DN_API bool DN_MemListCommitTo(DN_MemList *mem, DN_U64 pos) DN_ASanPoisonMemoryRegion(commit_ptr, commit_size); curr->commit = end_commit; + DN_MemDebuggerCommitUpdate_(mem, curr); return true; } @@ -1358,13 +1535,13 @@ DN_API bool DN_MemListCommit(DN_MemList *mem, DN_U64 size) return result; } -DN_API bool DN_MemListGrow(DN_MemList *mem, DN_U64 reserve, DN_U64 commit) +DN_API bool DN_MemListGrowCallSite(DN_MemList *mem, DN_U64 reserve, DN_U64 commit, DN_CallSite call_site) { if (mem->flags & (DN_MemFlags_NoGrow | DN_MemFlags_UserBuffer)) return false; bool result = false; - DN_MemBlock *new_block = DN_MemBlockFromHeapFlags_(reserve, commit, mem->flags, mem->heap, DN_CallSiteNowNamed("DN MemList Grow")); + DN_MemBlock *new_block = DN_MemBlockFromHeapFlags_(reserve, commit, mem->flags, mem->heap, call_site); if (new_block) { result = true; new_block->prev = mem->curr; @@ -1375,13 +1552,13 @@ DN_API bool DN_MemListGrow(DN_MemList *mem, DN_U64 reserve, DN_U64 commit) return result; } -DN_API void *DN_MemListAlloc(DN_MemList *mem, DN_U64 size, DN_U8 align, DN_ZMem z_mem) +DN_API void *DN_MemListAllocCallSite(DN_MemList *mem, DN_U64 size, DN_U8 align, DN_ZMem z_mem, DN_CallSite call_site) { if (!mem) return nullptr; if (!mem->curr) { - mem->curr = DN_MemBlockFromHeapFlags_(DN_ARENA_RESERVE_SIZE, DN_ARENA_COMMIT_SIZE, mem->flags, mem->heap, DN_CallSiteNowNamed("DN MemList Lazy Bootstrap")); + mem->curr = DN_MemBlockFromHeapFlags_(DN_ARENA_RESERVE_SIZE, DN_ARENA_COMMIT_SIZE, mem->flags, mem->heap, call_site); DN_MemListOnNewBlock_(mem, mem->curr); } @@ -1401,7 +1578,7 @@ DN_API void *DN_MemListAlloc(DN_MemList *mem, DN_U64 size, DN_U8 align, DN_ZMem return nullptr; DN_USize new_reserve = DN_Max(DN_ARENA_HEADER_SIZE + alloc_size, DN_ARENA_RESERVE_SIZE); DN_USize new_commit = DN_Max(DN_ARENA_HEADER_SIZE + alloc_size, DN_ARENA_COMMIT_SIZE); - if (!DN_MemListGrow(mem, new_reserve, new_commit)) + if (!DN_MemListGrowCallSite(mem, new_reserve, new_commit, call_site)) return nullptr; goto try_alloc_again; } @@ -1420,12 +1597,14 @@ DN_API void *DN_MemListAlloc(DN_MemList *mem, DN_U64 size, DN_U8 align, DN_ZMem curr->commit = end_commit; mem->stats.info.commit += commit_size; mem->stats.hwm.commit = DN_Max(mem->stats.hwm.commit, mem->stats.info.commit); + DN_MemDebuggerCommitUpdate_(mem, curr); } void *result = DN_Cast(char *) curr + offset_pos; curr->used += alloc_size; mem->stats.info.used += alloc_size; mem->stats.hwm.used = DN_Max(mem->stats.hwm.used, mem->stats.info.used); + DN_MemDebuggerMemListAllocTrack_(mem, result, size, alloc_size, align, call_site); if (poison && DN_BitIsNotSet(mem->flags, DN_MemFlags_SimAlloc)) DN_ASanUnpoisonMemoryRegion(result, size); @@ -1440,20 +1619,20 @@ DN_API void *DN_MemListAlloc(DN_MemList *mem, DN_U64 size, DN_U8 align, DN_ZMem return result; } -DN_API void *DN_MemListAllocContiguous(DN_MemList *mem, DN_U64 size, DN_U8 align, DN_ZMem z_mem) +DN_API void *DN_MemListAllocContiguousCallSite(DN_MemList *mem, DN_U64 size, DN_U8 align, DN_ZMem z_mem, DN_CallSite call_site) { DN_MemFlags prev_flags = mem->flags; mem->flags |= (DN_MemFlags_NoGrow | DN_MemFlags_NoPoison); - void *memory = DN_MemListAlloc(mem, size, align, z_mem); + void *memory = DN_MemListAllocCallSite(mem, size, align, z_mem, call_site); mem->flags = prev_flags; return memory; } -DN_API void *DN_MemListCopy(DN_MemList *mem, void const *data, DN_U64 size, DN_U8 align) +DN_API void *DN_MemListCopyCallSite(DN_MemList *mem, void const *data, DN_U64 size, DN_U8 align, DN_CallSite call_site) { if (!mem || !data || size == 0) return nullptr; - void *result = DN_MemListAlloc(mem, size, align, DN_ZMem_No); + void *result = DN_MemListAllocCallSite(mem, size, align, DN_ZMem_No, call_site); if (result) DN_Memcpy(result, data, size); return result; @@ -1464,7 +1643,9 @@ DN_API void DN_MemListPopTo(DN_MemList *mem, DN_U64 init_used) if (!mem || !mem->curr) return; - // NOTE: Free any memory blocks until we get back to the starting block + // NOTE: Free any memory blocks until we get back to the starting block. The floor is always the + // header: the DN_MemList itself lives inside the block header (see DN_MEM_LIST_OFFSET) so it is + // never scrubbed by a reset. DN_U64 used = DN_Max(DN_ARENA_HEADER_SIZE, init_used); DN_MemBlock *curr = mem->curr; while (curr->reserve_sum >= used) { @@ -1520,6 +1701,8 @@ DN_API void DN_MemListPopTo(DN_MemList *mem, DN_U64 init_used) DN_USize poison_size = ((char *)curr + curr->commit) - poison_ptr; DN_ASanPoisonMemoryRegion(poison_ptr, poison_size); } + + DN_MemDebuggerMemListAllocsSync_(mem); } DN_API void DN_MemListPop(DN_MemList *mem, DN_U64 amount) @@ -1685,10 +1868,9 @@ DN_API DN_Arena DN_ArenaFromMemList(DN_MemList *mem) DN_API DN_Arena DN_ArenaFromHeapCallSite(DN_U64 reserve, DN_U64 commit, DN_MemFlags flags, DN_Heap heap, DN_CallSite call_site) { - DN_MemList mem = DN_MemListFromHeapCallSite(reserve, commit, flags, heap, call_site); - DN_Arena result = {}; - result.flags |= DN_ArenaFlags_OwnsMemList; - result.mem = DN_MemListNewCopy(&mem, DN_MemList, &mem); + DN_Arena result = {}; + result.flags |= DN_ArenaFlags_OwnsMemList; + result.mem = DN_MemListFromHeapCallSite(reserve, commit, flags, heap, call_site); return result; } @@ -1757,27 +1939,33 @@ DN_API void DN_ArenaTempEnd(DN_Arena *arena, DN_ArenaReset reset) #endif } -DN_API void *DN_ArenaAlloc(DN_Arena *arena, DN_U64 size, DN_U8 align, DN_ZMem z_mem) +DN_API void *DN_ArenaAllocCallSite(DN_Arena *arena, DN_U64 size, DN_U8 align, DN_ZMem z_mem, DN_CallSite call_site) { DN_ArenaUAFCheck_(arena, DN_ArenaUAFCheckReportType_AllocViolation); - void *result = DN_MemListAlloc(arena->mem, size, align, z_mem); + void *result = DN_MemListAllocCallSite(arena->mem, size, align, z_mem, call_site); return result; } -DN_API void *DN_ArenaAllocContiguous(DN_Arena *arena, DN_U64 size, DN_U8 align, DN_ZMem z_mem) +DN_API void *DN_ArenaAllocContiguousCallSite(DN_Arena *arena, DN_U64 size, DN_U8 align, DN_ZMem z_mem, DN_CallSite call_site) { DN_ArenaUAFCheck_(arena, DN_ArenaUAFCheckReportType_AllocViolation); - void *result = DN_MemListAllocContiguous(arena->mem, size, align, z_mem); + void *result = DN_MemListAllocContiguousCallSite(arena->mem, size, align, z_mem, call_site); return result; } -DN_API void *DN_ArenaCopy(DN_Arena *arena, void const *data, DN_U64 size, DN_U8 align) +DN_API void *DN_ArenaCopyCallSite(DN_Arena *arena, void const *data, DN_U64 size, DN_U8 align, DN_CallSite call_site) { DN_ArenaUAFCheck_(arena, DN_ArenaUAFCheckReportType_AllocViolation); - void *result = DN_MemListCopy(arena->mem, data, size, align); + void *result = DN_MemListCopyCallSite(arena->mem, data, size, align, call_site); return result; } +DN_API void DN_ArenaClear(DN_Arena *arena) +{ + DN_ArenaUAFCheck_(arena, DN_ArenaUAFCheckReportType_AllocViolation); + DN_MemListPopTo(arena->mem, 0); +} + DN_API void DN_ArenaDeinit(DN_Arena *arena) { if (arena->flags & DN_ArenaFlags_OwnsMemList) @@ -1806,7 +1994,7 @@ DN_API bool DN_PoolIsValid(DN_Pool const *pool) return result; } -DN_API void *DN_PoolAlloc(DN_Pool *pool, DN_USize size) +DN_API void *DN_PoolAllocCallSite(DN_Pool *pool, DN_USize size, DN_CallSite call_site) { void *result = nullptr; if (!DN_PoolIsValid(pool)) @@ -1841,7 +2029,7 @@ DN_API void *DN_PoolAlloc(DN_Pool *pool, DN_USize size) DN_Memset(slot->data, 0, size); DN_Assert(DN_IsPowerOfTwoAligned(slot->data, pool->align)); } else { - void *bytes = DN_ArenaAlloc(pool->arena, slot_size_in_bytes, alignof(DN_PoolSlot), DN_ZMem_Yes); + void *bytes = DN_ArenaAllocCallSite(pool->arena, slot_size_in_bytes, alignof(DN_PoolSlot), DN_ZMem_Yes, call_site); slot = DN_Cast(DN_PoolSlot *) bytes; // NOTE: The raw pointer is round up to the next 'pool->align'-ed @@ -2103,7 +2291,11 @@ DN_API void DN_ErrSinkEndExitIfErrorFV_(DN_ErrSink *err, DN_CallSite call_site, { if (DN_ErrSinkEndLogErrorFV_(err, call_site, fmt, args)) { DN_DebugBreak; + #if DN_WITH_OS DN_OS_Exit(exit_val); + #else + DN_AssertInvalidCodePathF("Exiting with exit code: %u", exit_val); + #endif } } @@ -2171,22 +2363,19 @@ DN_API DN_TcInitArgs DN_TcInitArgsDefault() DN_API void DN_TcInitFromHeap(DN_TcCore *tc, DN_U64 thread_id, DN_TcInitArgs args, DN_Heap heap) { DN_Assert(args.temp_count <= DN_ArrayCountU(tc->temp_arenas)); - DN_MemList main_mem_stack = DN_MemListFromHeap(args.main_reserve, args.main_commit, DN_MemFlags_Nil, heap, "DN Thread Context Main MemList"); - DN_MemList *main_mem = DN_MemListNewCopy(&main_mem_stack, DN_MemList, &main_mem_stack); - DN_Arena *main_arena = DN_MemListNewZ(main_mem, DN_Arena); - *main_arena = DN_ArenaFromMemList(main_mem); + DN_MemList *main_mem = DN_MemListFromHeap(args.main_reserve, args.main_commit, DN_MemFlags_Nil, heap, "DN Thread Context Main MemList"); + DN_Arena *main_arena = DN_MemListNewZ(main_mem, DN_Arena); + *main_arena = DN_ArenaFromMemList(main_mem); DN_Arena *temp_arenas = DN_MemListNewArrayZ(main_mem, DN_Arena, args.temp_count); for (DN_ForIndexU(index, args.temp_count)) { - DN_MemList temp_mem_stack = DN_MemListFromHeap(args.temp_reserve, args.temp_commit, DN_MemFlags_Nil, heap, "DN Thread Context Temp MemList"); - DN_MemList *temp_mem = DN_MemListNewCopy(main_mem, DN_MemList, &temp_mem_stack); - temp_arenas[index] = DN_ArenaFromMemList(temp_mem); + DN_MemList *temp_mem = DN_MemListFromHeap(args.temp_reserve, args.temp_commit, DN_MemFlags_Nil, heap, "DN Thread Context Temp MemList"); + temp_arenas[index] = DN_ArenaFromMemList(temp_mem); } - DN_MemList err_sink_mem_stack = DN_MemListFromHeap(args.err_sink_reserve, args.err_sink_commit, DN_MemFlags_Nil, heap, "DN ThreadContext Err MemList"); - DN_MemList *err_sink_mem = DN_MemListNewCopy(main_mem, DN_MemList, &err_sink_mem_stack); - DN_Arena *err_sink_arena = DN_MemListNewZ(main_mem, DN_Arena); - *err_sink_arena = DN_ArenaFromMemList(err_sink_mem); + DN_MemList *err_sink_mem = DN_MemListFromHeap(args.err_sink_reserve, args.err_sink_commit, DN_MemFlags_Nil, heap, "DN ThreadContext Err MemList"); + DN_Arena *err_sink_arena = DN_MemListNewZ(main_mem, DN_Arena); + *err_sink_arena = DN_ArenaFromMemList(err_sink_mem); DN_TcInit(tc, thread_id, main_arena, temp_arenas, args.temp_count, err_sink_arena); } @@ -2248,6 +2437,8 @@ DN_API DN_Arena DN_TcTempArenaAllocator(DN_Allocator *conflicts, DN_USize count) mem_list = arena->mem; } break; + case DN_AllocatorType_Heap: break; + case DN_AllocatorType_Pool: { DN_Pool *pool = DN_Cast(DN_Pool *) allocator->context; mem_list = pool->arena ? pool->arena->mem : nullptr; @@ -2366,7 +2557,7 @@ DN_API DN_ErrSink *DN_TcErrSink() return result; } -DN_API void *DN_PoolCopy(DN_Pool *pool, void const *data, DN_U64 size, DN_U8 align) +DN_API void *DN_PoolCopyCallSite(DN_Pool *pool, void const *data, DN_U64 size, DN_U8 align, DN_CallSite call_site) { if (!pool || !data || size == 0) return nullptr; @@ -2375,7 +2566,7 @@ DN_API void *DN_PoolCopy(DN_Pool *pool, void const *data, DN_U64 size, DN_U8 ali // about this until we crash because of misalignment. DN_Assert(pool->align >= align); - void *result = DN_PoolAlloc(pool, size); + void *result = DN_PoolAllocCallSite(pool, size, call_site); if (result) DN_Memcpy(result, data, size); return result; @@ -2835,19 +3026,40 @@ DN_API DN_Allocator DN_AllocatorFromPool(DN_Pool *pool) return result; } -DN_API void *DN_AllocatorAlloc(DN_Allocator allocator, DN_USize size, DN_U8 align, DN_ZMem z_mem) +DN_API DN_Allocator DN_AllocatorFromHeap(DN_Heap *heap) +{ + DN_Allocator result = {}; + result.type = DN_AllocatorType_Heap; + result.context = heap; + return result; +} + +DN_API void *DN_AllocatorAllocCallSite(DN_Allocator allocator, DN_USize size, DN_U8 align, DN_ZMem z_mem, DN_CallSite call_site) { void *result = nullptr; if (allocator.context) { switch (allocator.type) { - case DN_AllocatorType_Arena: result = DN_ArenaAlloc (DN_Cast(DN_Arena *) allocator.context, size + 1, align, z_mem); break; - case DN_AllocatorType_Pool: result = DN_PoolAlloc (DN_Cast(DN_Pool *) allocator.context, size + 1); break; - case DN_AllocatorType_MemList: result = DN_MemListAlloc(DN_Cast(DN_MemList *) allocator.context, size + 1, align, z_mem); break; + case DN_AllocatorType_Heap: result = DN_HeapAllocCallSite (DN_Cast(DN_Heap *) allocator.context, size, size, DN_HeapAllocFlag_Nil, call_site); break; + case DN_AllocatorType_Arena: result = DN_ArenaAllocCallSite (DN_Cast(DN_Arena *) allocator.context, size, align, z_mem, call_site); break; + case DN_AllocatorType_Pool: result = DN_PoolAllocCallSite (DN_Cast(DN_Pool *) allocator.context, size, call_site); break; + case DN_AllocatorType_MemList: result = DN_MemListAllocCallSite (DN_Cast(DN_MemList *) allocator.context, size, align, z_mem, call_site); break; } } return result; } +DN_API void DN_AllocatorDealloc(DN_Allocator allocator, void *ptr, DN_USize size) +{ + if (allocator.context) { + switch (allocator.type) { + case DN_AllocatorType_Heap: DN_HeapDealloc(DN_Cast(DN_Heap *)allocator.context, ptr, size); break; + case DN_AllocatorType_Arena: break; + case DN_AllocatorType_Pool: DN_PoolDealloc(DN_Cast(DN_Pool *)allocator.context, ptr); break; + case DN_AllocatorType_MemList: break; + } + } +} + DN_API DN_FmtAppendResult DN_FmtVAppend(char *buf, DN_USize *buf_size, DN_USize buf_max, char const *fmt, va_list args) { DN_FmtAppendResult result = {}; @@ -2916,10 +3128,10 @@ DN_API DN_USize DN_CStr16Count(wchar_t const *src) return result; } -DN_API DN_Str8 DN_Str8AllocAllocator(DN_USize count, DN_ZMem z_mem, DN_Allocator allocator) +DN_API DN_Str8 DN_Str8AllocAllocatorCallSite(DN_USize count, DN_ZMem z_mem, DN_Allocator allocator, DN_CallSite call_site) { DN_Str8 result = {}; - result.data = DN_Cast(char *) DN_AllocatorAlloc(allocator, count + 1, alignof(char), z_mem); + result.data = DN_Cast(char *) DN_AllocatorAllocCallSite(allocator, count + 1, alignof(char), z_mem, call_site); if (result.data) { result.count = count; result.data[result.count] = 0; @@ -2927,15 +3139,15 @@ DN_API DN_Str8 DN_Str8AllocAllocator(DN_USize count, DN_ZMem z_mem, DN_Allocator return result; } -DN_API DN_Str8 DN_Str8AllocArena(DN_USize count, DN_ZMem z_mem, DN_Arena *arena) +DN_API DN_Str8 DN_Str8AllocArenaCallSite(DN_USize count, DN_ZMem z_mem, DN_Arena *arena, DN_CallSite call_site) { - DN_Str8 result = DN_Str8AllocAllocator(count, z_mem, DN_AllocatorFromArena(arena)); + DN_Str8 result = DN_Str8AllocAllocatorCallSite(count, z_mem, DN_AllocatorFromArena(arena), call_site); return result; } -DN_API DN_Str8 DN_Str8AllocPool(DN_USize count, DN_Pool *pool) +DN_API DN_Str8 DN_Str8AllocPoolCallSite(DN_USize count, DN_Pool *pool, DN_CallSite call_site) { - DN_Str8 result = DN_Str8AllocAllocator(count, DN_ZMem_No, DN_AllocatorFromPool(pool)); + DN_Str8 result = DN_Str8AllocAllocatorCallSite(count, DN_ZMem_No, DN_AllocatorFromPool(pool), call_site); return result; } @@ -2946,33 +3158,33 @@ DN_API DN_Str8 DN_Str8FromCStr8(char const *src) return result; } -DN_API DN_Str8 DN_Str8FromCStr8Arena(char const *src, DN_Arena *arena) +DN_API DN_Str8 DN_Str8FromCStr8ArenaCallSite(char const *src, DN_Arena *arena, DN_CallSite call_site) { DN_Str8 shallow = DN_Str8FromCStr8(src); - DN_Str8 result = DN_Str8FromStr8Arena(shallow, arena); + DN_Str8 result = DN_Str8FromStr8ArenaCallSite(shallow, arena, call_site); return result; } -DN_API DN_Str8 DN_Str8FromPtrArena(void const *data, DN_USize count, DN_Arena *arena) +DN_API DN_Str8 DN_Str8FromPtrArenaCallSite(void const *data, DN_USize count, DN_Arena *arena, DN_CallSite call_site) { - DN_Str8 result = DN_Str8AllocArena(count, DN_ZMem_No, arena); + DN_Str8 result = DN_Str8AllocArenaCallSite(count, DN_ZMem_No, arena, call_site); if (result.count) DN_Memcpy(result.data, data, count); return result; } -DN_API DN_Str8 DN_Str8FromPtrPool(void const *data, DN_USize count, DN_Pool *pool) +DN_API DN_Str8 DN_Str8FromPtrPoolCallSite(void const *data, DN_USize count, DN_Pool *pool, DN_CallSite call_site) { - DN_Str8 result = DN_Str8AllocPool(count, pool); + DN_Str8 result = DN_Str8AllocPoolCallSite(count, pool, call_site); if (result.count) DN_Memcpy(result.data, data, count); return result; } -DN_API DN_Str8 DN_Str8FromStr8Allocator(DN_Str8 string, DN_Allocator allocator) +DN_API DN_Str8 DN_Str8FromStr8AllocatorCallSite(DN_Str8 string, DN_Allocator allocator, DN_CallSite call_site) { DN_Str8 result = {}; - result.data = DN_Cast(char *) DN_AllocatorAlloc(allocator, string.count + 1, alignof(char), DN_ZMem_No); + result.data = DN_Cast(char *) DN_AllocatorAllocCallSite(allocator, string.count + 1, alignof(char), DN_ZMem_No, call_site); if (result.data) { DN_Memcpy(result.data, string.data, string.count); result.data[string.count] = 0; @@ -2981,22 +3193,22 @@ DN_API DN_Str8 DN_Str8FromStr8Allocator(DN_Str8 string, DN_Allocator allocator) return result; } -DN_API DN_Str8 DN_Str8FromStr8Arena(DN_Str8 string, DN_Arena *arena) +DN_API DN_Str8 DN_Str8FromStr8ArenaCallSite(DN_Str8 string, DN_Arena *arena, DN_CallSite call_site) { - DN_Str8 result = DN_Str8FromStr8Allocator(string, DN_AllocatorFromArena(arena)); + DN_Str8 result = DN_Str8FromStr8AllocatorCallSite(string, DN_AllocatorFromArena(arena), call_site); return result; } -DN_API DN_Str8 DN_Str8FromStr8Pool(DN_Str8 string, DN_Pool *pool) +DN_API DN_Str8 DN_Str8FromStr8PoolCallSite(DN_Str8 string, DN_Pool *pool, DN_CallSite call_site) { - DN_Str8 result = DN_Str8FromStr8Allocator(string, DN_AllocatorFromPool(pool)); + DN_Str8 result = DN_Str8FromStr8AllocatorCallSite(string, DN_AllocatorFromPool(pool), call_site); return result; } -DN_API DN_Str8 DN_Str8FmtVAllocator(DN_Allocator allocator, DN_FMT_ATTRIB char const *fmt, va_list args) +DN_API DN_Str8 DN_Str8FmtVAllocatorCallSite(DN_Allocator allocator, DN_FMT_ATTRIB char const *fmt, va_list args, DN_CallSite call_site) { DN_USize count = DN_FmtVCount(fmt, args); - DN_Str8 result = DN_Str8AllocAllocator(count, DN_ZMem_No, allocator); + DN_Str8 result = DN_Str8AllocAllocatorCallSite(count, DN_ZMem_No, allocator, call_site); if (result.data) { DN_USize written = 0; DN_FmtVAppend(result.data, &written, result.count + 1, fmt, args); @@ -3005,41 +3217,41 @@ DN_API DN_Str8 DN_Str8FmtVAllocator(DN_Allocator allocator, DN_FMT_ATTRIB char c return result; } -DN_API DN_Str8 DN_Str8FmtVArena(DN_Arena *arena, DN_FMT_ATTRIB char const *fmt, va_list args) +DN_API DN_Str8 DN_Str8FmtVArenaCallSite(DN_Arena *arena, DN_FMT_ATTRIB char const *fmt, va_list args, DN_CallSite call_site) { - DN_Str8 result = DN_Str8FmtVAllocator(DN_AllocatorFromArena(arena), fmt, args); + DN_Str8 result = DN_Str8FmtVAllocatorCallSite(DN_AllocatorFromArena(arena), fmt, args, call_site); return result; } -DN_API DN_Str8 DN_Str8FmtAllocator(DN_Allocator allocator, DN_FMT_ATTRIB char const *fmt, ...) +DN_API DN_Str8 DN_Str8FmtAllocatorCallSite(DN_Allocator allocator, DN_CallSite call_site, DN_FMT_ATTRIB char const *fmt, ...) { va_list va; va_start(va, fmt); - DN_Str8 result = DN_Str8FmtVAllocator(allocator, fmt, va); + DN_Str8 result = DN_Str8FmtVAllocatorCallSite(allocator, fmt, va, call_site); va_end(va); return result; } -DN_API DN_Str8 DN_Str8FmtArena(DN_Arena *arena, DN_FMT_ATTRIB char const *fmt, ...) +DN_API DN_Str8 DN_Str8FmtArenaCallSite(DN_Arena *arena, DN_CallSite call_site, DN_FMT_ATTRIB char const *fmt, ...) { va_list va; va_start(va, fmt); - DN_Str8 result = DN_Str8FmtVArena(arena, fmt, va); + DN_Str8 result = DN_Str8FmtVArenaCallSite(arena, fmt, va, call_site); va_end(va); return result; } -DN_API DN_Str8 DN_Str8FmtVPool(DN_Pool *pool, DN_FMT_ATTRIB char const *fmt, va_list args) +DN_API DN_Str8 DN_Str8FmtVPoolCallSite(DN_Pool *pool, DN_FMT_ATTRIB char const *fmt, va_list args, DN_CallSite call_site) { - DN_Str8 result = DN_Str8FmtVAllocator(DN_AllocatorFromPool(pool), fmt, args); + DN_Str8 result = DN_Str8FmtVAllocatorCallSite(DN_AllocatorFromPool(pool), fmt, args, call_site); return result; } -DN_API DN_Str8 DN_Str8FmtPool(DN_Pool *pool, DN_FMT_ATTRIB char const *fmt, ...) +DN_API DN_Str8 DN_Str8FmtPoolCallSite(DN_Pool *pool, DN_CallSite call_site, DN_FMT_ATTRIB char const *fmt, ...) { va_list args; va_start(args, fmt); - DN_Str8 result = DN_Str8FmtVPool(pool, fmt, args); + DN_Str8 result = DN_Str8FmtVPoolCallSite(pool, fmt, args, call_site); va_end(args); return result; } @@ -3275,37 +3487,39 @@ DN_API DN_Str8x32 DN_Str8x32FromU64(DN_U64 val, char seperator) return result; } - -DN_API bool DN_Str8Is(DN_Str8 string, DN_Str8IsFlags flags) +DN_API DN_Str8IsResult DN_Str8Is(DN_Str8 string, DN_Str8IsFlags flags) { - bool result = string.count; - if (!result) + DN_Str8IsResult result = {}; + if (string.count == 0) return result; - if (result && (flags & DN_Str8IsFlags_Digits)) { - for (DN_USize index = 0; result && index < string.count; index++) - result = string.data[index] >= '0' && string.data[index] <= '9'; + result.success = true; + if (result.success && (flags & DN_Str8IsFlags_Digits)) { + for (DN_USize index = 0; result.success && index < string.count; index++) + result.success = string.data[index] >= '0' && string.data[index] <= '9'; } - if (result && (flags & DN_Str8IsFlags_Hex)) { + if (result.success && (flags & DN_Str8IsFlags_Hex)) { DN_Str8 trimmed = DN_Str8TrimPrefix(string, DN_Str8Lit("0x"), DN_Str8EqCase_Insensitive); - for (DN_USize index = 0; result && index < trimmed.count; index++) { - char ch = trimmed.data[index]; - result = (ch >= '0' && ch <= '9') || (ch >= 'a' && ch <= 'f') || (ch >= 'A' && ch <= 'F'); + for (DN_USize index = 0; result.success && index < trimmed.count; index++) { + char ch = trimmed.data[index]; + result.success = (ch >= '0' && ch <= '9') || (ch >= 'a' && ch <= 'f') || (ch >= 'A' && ch <= 'F'); } + if (result.success) + result.hex = trimmed; } - if (result && (flags & DN_Str8IsFlags_Lowercase)) { - for (DN_USize index = 0; result && index < string.count; index++) { + if (result.success && (flags & DN_Str8IsFlags_Lowercase)) { + for (DN_USize index = 0; result.success && index < string.count; index++) { if (string.data[index] >= 'A' && string.data[index] <= 'Z') - result = false; + result.success = false; } } - if (result && (flags & DN_Str8IsFlags_Uppercase)) { - for (DN_USize index = 0; result && index < string.count; index++) { + if (result.success && (flags & DN_Str8IsFlags_Uppercase)) { + for (DN_USize index = 0; result.success && index < string.count; index++) { if (string.data[index] >= 'a' && string.data[index] <= 'z') - result = false; + result.success = false; } } return result; @@ -3784,7 +3998,14 @@ DN_API DN_Str8 DN_Str8FileDirectoryFromPath(DN_Str8 path) { DN_Str8 seperators[] = {DN_Str8Lit("/"), DN_Str8Lit("\\")}; DN_Str8BSplitResult split = DN_Str8BSplitLastArray(path, seperators, DN_ArrayCountU(seperators)); - DN_Str8 result = split.rhs.count == 0 ? DN_Str8Lit(".") : split.lhs; + DN_Str8 result = DN_Str8Lit("."); + if (split.rhs.count) { + DN_Str8BSplitResult dot_split = DN_Str8BSplitLast(split.rhs, DN_Str8Lit(".")); + if (dot_split.rhs.count == 0) // E.g. no dot file extension, assume `path` just specifies a path + result = path; + else + result = split.lhs; + } return result; } @@ -5044,17 +5265,17 @@ DN_API bool DN_PathPop(DN_Path *path) return true; } -DN_API DN_Str8 DN_Str8FromPath(DN_Path const *path, DN_Str8 path_seperator, DN_Allocator allocator) +DN_API DN_Str8Path DN_Str8PathFromPath(DN_Path const *path, DN_Str8 path_seperator, DN_Allocator allocator) { - DN_Str8 result = {}; + DN_Str8Path result = {}; if (!path || path->links_size <= 0) return result; // NOTE: Each link except the last one needs the path seperator appended to it, '/' or '\\' DN_USize string_size = (path->has_prefix_path_seperator ? path_seperator.count : 0) + path->string_size + ((path->links_size - 1) * path_seperator.count); - result = DN_Str8AllocAllocator(string_size, DN_ZMem_No, allocator); - if (result.data) { - char *dest = result.data; + result.value = DN_Str8AllocAllocator(string_size, DN_ZMem_No, allocator); + if (result.value.data) { + char *dest = result.value.data; if (path->has_prefix_path_seperator) { DN_Memcpy(dest, path_seperator.data, path_seperator.count); dest += path_seperator.count; @@ -5070,25 +5291,29 @@ DN_API DN_Str8 DN_Str8FromPath(DN_Path const *path, DN_Str8 path_seperator, DN_A dest += path_seperator.count; } } - } - result.data[string_size] = 0; + result.value.data[string_size] = 0; + result.file_name = DN_Str8FileNameFromPath(result.value); + result.file_ext = DN_Str8FileExtension(result.file_name); + result.file_name_no_ext = DN_Str8TrimSuffixSensitive(DN_Str8TrimSuffixSensitive(result.file_name, result.file_ext), DN_Str8Lit(".")); + result.directory = DN_Str8FileDirectoryFromPath(result.value); + } return result; } -DN_API DN_Str8 DN_Str8FmtVPathArena(DN_Str8 path_seperator, DN_Arena *arena, DN_FMT_ATTRIB char const *fmt, va_list args) +DN_API DN_Str8Path DN_Str8PathFmtVArena(DN_Str8 path_seperator, DN_Arena *arena, char const *fmt, va_list args) { DN_TcScratch scratch = DN_TcScratchBeginArena(&arena, 1); DN_Str8 path = DN_Str8FmtVArena(arena, fmt, args); DN_Path fs_path = {}; DN_PathAddRef(&fs_path, path, &scratch.arena); DN_Allocator allocator = DN_AllocatorFromArena(arena); - DN_Str8 result = DN_Str8FromPath(&fs_path, path_seperator, allocator); + DN_Str8Path result = DN_Str8PathFromPath(&fs_path, path_seperator, allocator); DN_TcScratchEnd(&scratch); return result; } -DN_API DN_Str8 DN_Str8FmtPathArena(DN_Str8 path_seperator, DN_Arena *arena, DN_FMT_ATTRIB char const *fmt, ...) +DN_API DN_Str8Path DN_Str8PathFmtArena(DN_Str8 path_seperator, DN_Arena *arena, DN_FMT_ATTRIB char const *fmt, ...) { DN_TcScratch scratch = DN_TcScratchBeginArena(&arena, 1); va_list args; @@ -5100,46 +5325,46 @@ DN_API DN_Str8 DN_Str8FmtPathArena(DN_Str8 path_seperator, DN_Arena *arena, DN_F DN_PathAddRef(&fs_path, path, &scratch.arena); DN_Allocator allocator = DN_AllocatorFromArena(arena); - DN_Str8 result = DN_Str8FromPath(&fs_path, path_seperator, allocator); + DN_Str8Path result = DN_Str8PathFromPath(&fs_path, path_seperator, allocator); DN_TcScratchEnd(&scratch); return result; } -DN_API DN_Str8 DN_Str8FmtVPathPool(DN_Str8 path_seperator, DN_Pool *pool, DN_FMT_ATTRIB char const *fmt, va_list args) +DN_API DN_Str8Path DN_Str8PathFmtVPool(DN_Str8 path_seperator, DN_Pool *pool, char const *fmt, va_list args) { DN_TcScratch scratch = DN_TcScratchBeginArena(&pool->arena, 1); DN_Str8 path = DN_Str8FmtVPool(pool, fmt, args); DN_Path fs_path = {}; DN_PathAddRef(&fs_path, path, &scratch.arena); DN_Allocator allocator = DN_AllocatorFromPool(pool); - DN_Str8 result = DN_Str8FromPath(&fs_path, path_seperator, allocator); + DN_Str8Path result = DN_Str8PathFromPath(&fs_path, path_seperator, allocator); DN_TcScratchEnd(&scratch); return result; } -DN_API DN_Str8 DN_Str8FmtPathPool(DN_Str8 path_seperator, DN_Pool *pool, DN_FMT_ATTRIB char const *fmt, ...) +DN_API DN_Str8Path DN_Str8PathFmtPool(DN_Str8 path_seperator, DN_Pool *pool, DN_FMT_ATTRIB char const *fmt, ...) { va_list args; va_start(args, fmt); - DN_Str8 result = DN_Str8FmtVPathPool(path_seperator, pool, fmt, args); + DN_Str8Path result = DN_Str8PathFmtVPool(path_seperator, pool, fmt, args); va_end(args); return result; } -DN_API DN_Str8 DN_Str8FmtOsPathPool(DN_Pool *pool, DN_FMT_ATTRIB char const *fmt, ...) +DN_API DN_Str8Path DN_Str8PathFmtOsPool(DN_Pool *pool, DN_FMT_ATTRIB char const *fmt, ...) { va_list args; va_start(args, fmt); - DN_Str8 result = DN_Str8FmtVPathPool(DN_OsPathSeperatorStr8, pool, fmt, args); + DN_Str8Path result = DN_Str8PathFmtVPool(DN_OsPathSeperatorStr8, pool, fmt, args); va_end(args); return result; } -DN_API DN_Str8 DN_Str8FmtOsPathArena(DN_Arena *arena, DN_FMT_ATTRIB char const *fmt, ...) +DN_API DN_Str8Path DN_Str8PathFmtOsArena(DN_Arena *arena, DN_FMT_ATTRIB char const *fmt, ...) { va_list args; va_start(args, fmt); - DN_Str8 result = DN_Str8FmtVPathArena(DN_OsPathSeperatorStr8, arena, fmt, args); + DN_Str8Path result = DN_Str8PathFmtVArena(DN_OsPathSeperatorStr8, arena, fmt, args); va_end(args); return result; } @@ -5853,7 +6078,7 @@ DN_API DN_ProfilerZone DN_ProfilerBeginZone(DN_Profiler *profiler, DN_Str8 name, #endif result.profiler = profiler; - result.begin_tsc = profiler->tsc_now ? profiler->tsc_now() : DN_CPUGetTsc(); + result.begin_tsc = profiler->tsc_now ? profiler->tsc_now() : DN_CpuTscNow(); result.anchor_index = anchor_index; result.parent_zone = profiler->parent_zone; result.elapsed_tsc_at_zone_start = anchor->tsc_inclusive; @@ -5872,7 +6097,7 @@ DN_API void DN_ProfilerEndZone(DN_ProfilerZone zone) DN_ProfilerAnchorArray array = DN_ProfilerFrameAnchors(profiler); DN_ProfilerAnchor *anchor = array.data + zone.anchor_index; - DN_U64 tsc_now = profiler->tsc_now ? profiler->tsc_now() : DN_CPUGetTsc(); + DN_U64 tsc_now = profiler->tsc_now ? profiler->tsc_now() : DN_CpuTscNow(); DN_U64 elapsed_tsc = tsc_now - zone.begin_tsc; // NOTE: We snap the elapsed Tsc at the zone start and overwrite every time we end zones. If we @@ -5948,6 +6173,7 @@ DN_API void DN_ProfilerFmtToStdout(DN_Profiler *profiler) if (!profiler || profiler->frame_index == 0) return; + #if DN_WITH_OS DN_USize frame_index = profiler->frame_index - 1; DN_ProfilerAnchor *anchors = profiler->anchors + (frame_index * profiler->anchors_per_frame); for (DN_USize index = 1; index < profiler->anchors_per_frame; index++) { @@ -5957,6 +6183,7 @@ DN_API void DN_ProfilerFmtToStdout(DN_Profiler *profiler) DN_Str8 msg = DN_Str8FromPtr(buffer, fmt_len); DN_OS_PrintOutLnF("%.*s", DN_Str8PrintFmt(msg)); } + #endif } DN_API DN_F64 DN_ProfilerSecFromTsc(DN_Profiler *profiler, DN_U64 duration_tsc) @@ -6156,7 +6383,7 @@ DN_API DN_Profiler2Zone DN_Profiler2ZoneBegin(DN_Profiler2 *profiler, DN_Str8 na DN_U32 marker_index = frame->count - 1; DN_Profiler2Marker *marker = result.marker; marker->call_site = call_site; - marker->tsc_begin = profiler->tsc_now ? profiler->tsc_now() : DN_CPUGetTsc(); + marker->tsc_begin = profiler->tsc_now ? profiler->tsc_now() : DN_CpuTscNow(); marker->parent_index = profiler->active_parent_index; marker->name = name; @@ -6192,7 +6419,7 @@ DN_API void DN_Profiler2ZoneEnd(DN_Profiler2Zone *zone) // NOTE: Record the end timestamp DN_Profiler2* profiler = zone->profiler; - zone->marker->tsc_end = profiler->tsc_now ? profiler->tsc_now() : DN_CPUGetTsc(); + zone->marker->tsc_end = profiler->tsc_now ? profiler->tsc_now() : DN_CpuTscNow(); // NOTE: Calculate the total time consumed into the parent if (profiler->frame_begin_zone.marker != zone->marker) { @@ -6322,65 +6549,111 @@ static void DN_QSortInsertion_(void *array, DN_USize array_size, DN_USize elem_s DN_TcScratchEnd(&scratch); } +// NOTE: Three-way partition of [lo, hi) around a pivot (the middle element): [lo, *out_lt) < pivot, +// [*out_lt, *out_gt) == pivot, [*out_gt, hi) > pivot. Handling the equal band explicitly keeps the +// sort well behaved for arrays with many duplicate keys +static void DN_QSortPartition3_(void *array, DN_USize lo, DN_USize hi, DN_USize elem_size, void *user_context, DN_QSortCompareFunc *compare, DN_USize *out_lt, DN_USize *out_gt) +{ + + char temp_buffer[512]; + bool use_buffer = elem_size <= DN_ArrayCountU(temp_buffer); + DN_TcScratch scratch = {}; + char *pivot = {}; + if (use_buffer) { + pivot = temp_buffer; + } else { + scratch = DN_TcScratchBeginArena(nullptr, 0); + pivot = DN_ArenaNewArray(&scratch.arena, char, elem_size, DN_ZMem_No); + } + + DN_USize pivot_index = lo + ((hi - lo) / 2); + DN_Memcpy(pivot, DN_Cast(char *) array + (pivot_index * elem_size), elem_size); + + DN_USize lt = lo; + DN_USize gt = hi; + DN_USize index = lo; + while (index < gt) { + char *elem = DN_Cast(char *) array + (index * elem_size); + if (compare(elem, pivot, user_context)) { + // NOTE: elem < pivot + DN_QSortSwapElems_(array, elem_size, lt, index); + lt++; + index++; + } else if (compare(pivot, elem, user_context)) { + // NOTE: elem > pivot + gt--; + DN_QSortSwapElems_(array, elem_size, index, gt); + } else { + // NOTE: elem == pivot + index++; + } + } + + if (!use_buffer) + DN_TcScratchEnd(&scratch); + + *out_lt = lt; + *out_gt = gt; +} + DN_API void DN_QSort_(void *array, DN_USize array_size, DN_USize elem_size, void *user_context, DN_QSortCompareFunc *compare) { if (!array || array_size <= 1 || elem_size == 0 || !compare) return; - // NOTE: Insertion Sort, under 24->32 is an optimal amount DN_U8 *array_u8 = DN_Cast(DN_U8 *)array; DN_USize const QSORT_THRESHOLD = 24; - if (array_size < QSORT_THRESHOLD) { - DN_QSortInsertion_(array, array_size, elem_size, user_context, compare); - return; - } - // NOTE: Quick sort, under 24->32 is an optimal amount - DN_USize last_index = array_size - 1; - DN_USize pivot_index = array_size / 2; - DN_USize partition_index = 0; - DN_USize start_index = 0; + // NOTE: Non-recursive quick sort. An explicit stack of [lo, hi) ranges is used; we always push the + // smaller partition and continue with the larger one, which bounds the stack depth to O(log n) (64 + // entries cover any `n` up to 2^64). Ranges at or below the threshold are finished with insertion + // sort. The three-way partition keeps duplicate-heavy arrays shallow. + DN_USize stack[64][2]; + DN_USize stack_count = 0; + DN_USize lo = 0; + DN_USize hi = array_size; - // Swap pivot with last index, so pivot is always at the end of the array. - // This makes logic much simpler. - DN_QSortSwapElems_(array, elem_size, last_index, pivot_index); - pivot_index = last_index; + for (;;) { + while (hi - lo > QSORT_THRESHOLD) { + DN_USize lt = 0; + DN_USize gt = 0; + DN_QSortPartition3_(array, lo, hi, elem_size, user_context, compare, <, >); - // 4^, 8, 7, 5, 2, 3, 6 - if (compare(array_u8 + (start_index * elem_size), array_u8 + (pivot_index * elem_size), user_context)) - partition_index++; - start_index++; - - // 4, |8, 7, 5^, 2, 3, 6* - // 4, 5, |7, 8, 2^, 3, 6* - // 4, 5, 2, |8, 7, ^3, 6* - // 4, 5, 2, 3, |7, 8, ^6* - for (DN_USize index = start_index; index < last_index; index++) { - if (compare(array_u8 + (index * elem_size), array_u8 + (pivot_index * elem_size), user_context)) { - DN_QSortSwapElems_(array, elem_size, partition_index, index); - partition_index++; + // NOTE: [lo, lt) < pivot, [lt, gt) == pivot, [gt, hi) > pivot. Push the smaller side so the + // stack grows at most logarithmically. + DN_USize lt_pivot_count = lt - lo; + DN_USize gt_pivot_count = hi - gt; + if (lt_pivot_count < gt_pivot_count) { + if (lt_pivot_count > 1) { + DN_Assert(stack_count < DN_ArrayCountU(stack)); + stack[stack_count][0] = lo; + stack[stack_count][1] = lt; + stack_count++; + } + lo = gt; + } else { + if (gt_pivot_count > 1) { + DN_Assert(stack_count < DN_ArrayCountU(stack)); + stack[stack_count][0] = gt; + stack[stack_count][1] = hi; + stack_count++; + } + hi = lt; + } } + + if (hi - lo > 1) + DN_QSortInsertion_(array_u8 + (lo * elem_size), hi - lo, elem_size, user_context, compare); + + if (stack_count == 0) + break; + + stack_count--; + lo = stack[stack_count][0]; + hi = stack[stack_count][1]; } - - // Move pivot to right of partition - // 4, 5, 2, 3, |6, 8, ^7* - DN_QSortSwapElems_(array, elem_size, partition_index, pivot_index); - DN_QSort_(array_u8, partition_index, elem_size, user_context, compare); - - // Skip the value at partion index since that is guaranteed to be sorted. - // 4, 5, 2, 3, (x), 8, 7 - DN_USize one_after_partition_index = partition_index + 1; - DN_QSort_(array_u8 + (one_after_partition_index * elem_size), (array_size - one_after_partition_index), elem_size, user_context, compare); } -#if defined(__cplusplus) -template -DN_API void DN_QSort(T *array, DN_USize array_size, void *user_context, DN_QSortCompareFunc *compare) -{ - DN_QSort_(array, array_size, sizeof(T), user_context, compare); -} -#endif - DN_API bool DN_QSortCompareStr8NaturalAsc(void const* lhs, void const *rhs, void *user_context) { DN_Str8EqCase eq_case = *DN_Cast(DN_Str8EqCase *) user_context; @@ -7093,6 +7366,229 @@ DN_API DN_LogTypeParam DN_LogTypeParamFromType(DN_LogType type) return result; } +#if DN_WITH_OS +DN_API DN_StackTrace DN_StackTraceFromAllocator(DN_Allocator allocator, DN_U16 limit) +{ + DN_StackTrace result = {}; +#if defined(DN_OS_WIN32) + if (!allocator.context) + return result; + + static DN_TicketMutex mutex = {}; + DN_TicketMutexBegin(&mutex); + + HANDLE thread = GetCurrentThread(); + result.process = GetCurrentProcess(); + + DN_OSW32Core *w32 = DN_OS_W32GetCore(); + if (!w32->sym_initialised) { + w32->sym_initialised = true; + SymSetOptions(SYMOPT_LOAD_LINES); + if (!SymInitialize(result.process, nullptr /*UserSearchPath*/, true /*fInvadeProcess*/)) { + DN_TcScratch scratch = DN_TcScratchBeginAllocator(&allocator, 1); + DN_OSW32Error error = DN_OS_W32LastError(&scratch.arena); + DN_LogErrorF("SymInitialize failed, stack trace can not be generated (%lu): %.*s\n", error.code, DN_Str8PrintFmt(error.msg)); + DN_TcScratchEnd(&scratch); + } + } + + CONTEXT context; + RtlCaptureContext(&context); + + STACKFRAME64 frame = {}; + frame.AddrPC.Offset = context.Rip; + frame.AddrPC.Mode = AddrModeFlat; + frame.AddrFrame.Offset = context.Rbp; + frame.AddrFrame.Mode = AddrModeFlat; + frame.AddrStack.Offset = context.Rsp; + frame.AddrStack.Mode = AddrModeFlat; + + DN_U64 raw_frames[256] = {}; + DN_USize raw_frames_count = 0; + while (raw_frames_count < limit) { + if (!StackWalk64(IMAGE_FILE_MACHINE_AMD64, + result.process, + thread, + &frame, + &context, + nullptr /*ReadMemoryRoutine*/, + SymFunctionTableAccess64, + SymGetModuleBase64, + nullptr /*TranslateAddress*/)) + break; + + // NOTE: It might be useful one day to use frame.AddrReturn.Offset. + // If AddrPC.Offset == AddrReturn.Offset then we can detect recursion. + DN_LArrayAppend(raw_frames, &raw_frames_count, frame.AddrPC.Offset); + } + DN_TicketMutexEnd(&mutex); + + result.base_addr = DN_Cast(DN_U64 *)DN_AllocatorAlloc(allocator, raw_frames_count * sizeof(DN_U64), alignof(DN_U64), DN_ZMem_No); + DN_Assert(result.base_addr); + + result.size = DN_Cast(DN_U16) raw_frames_count; + DN_Memcpy(result.base_addr, raw_frames, raw_frames_count * sizeof(raw_frames[0])); +#else + (void)limit; + (void)allocator; +#endif + return result; +} + +DN_API DN_StackTrace DN_StackTraceFromArena(DN_Arena *arena, DN_U16 limit) +{ + DN_Allocator allocator = DN_AllocatorFromArena(arena); + DN_StackTrace result = DN_StackTraceFromAllocator(allocator, limit); + return result; +} + +DN_API bool DN_StackTraceIterate(DN_StackTraceIterator *it, DN_StackTrace const *trace) +{ + bool result = false; + if (!it || !trace || !trace->base_addr || !trace->process) + return result; + + if (it->index >= trace->size) + return false; + + result = true; + it->raw_frame.process = trace->process; + it->raw_frame.base_addr = trace->base_addr[it->index++]; + return result; +} + +static void DN_StackTraceAddToStr8Builder_(DN_StackTrace const *trace, DN_Str8Builder *builder, DN_USize skip) +{ + DN_StackTraceRawFrame raw_frame = {}; + raw_frame.process = trace->process; + for (DN_USize index = skip; index < trace->size; index++) { + raw_frame.base_addr = trace->base_addr[index]; + DN_StackTraceFrame frame = DN_StackTraceFrameFromRawFrame(builder->arena, raw_frame); + DN_Str8BuilderAppendF(builder, "%.*s(%zu): %.*s%s", DN_Str8PrintFmt(frame.file_name), frame.line_number, DN_Str8PrintFmt(frame.function_name), (DN_Cast(int) index == trace->size - 1) ? "" : "\n"); + } +} + +DN_API DN_Str8 DN_Str8FromStackTraceAllocator(DN_Allocator allocator, DN_StackTrace const *trace, DN_U16 skip) +{ + DN_Str8 result = {}; + if (!trace) + return result; + + DN_TcScratch scratch = DN_TcScratchBeginAllocator(&allocator, 1); + DN_Str8Builder builder = DN_Str8BuilderFromArena(&scratch.arena); + DN_StackTraceAddToStr8Builder_(trace, &builder, skip); + result = DN_Str8FromStr8BuilderAllocator(&builder, allocator); + DN_TcScratchEnd(&scratch); + return result; +} + +DN_API DN_Str8 DN_Str8FromStackTraceArena(DN_Arena *arena, DN_StackTrace const *trace, DN_U16 skip) +{ + DN_Str8 result = {}; + if (!trace || !arena) + return result; + + DN_TcScratch scratch = DN_TcScratchBeginArena(&arena, 1); + DN_Str8Builder builder = DN_Str8BuilderFromArena(&scratch.arena); + DN_StackTraceAddToStr8Builder_(trace, &builder, skip); + result = DN_Str8FromStr8BuilderArena(&builder, arena); + DN_TcScratchEnd(&scratch); + return result; +} + +DN_API DN_Str8 DN_Str8FromStackTraceNowAllocator(DN_Allocator allocator, DN_U16 limit, DN_U16 skip) +{ + DN_TcScratch scratch = DN_TcScratchBeginArena(DN_Cast(DN_Arena **) & allocator.context, 1); + DN_StackTrace walk = DN_StackTraceFromArena(&scratch.arena, limit); + DN_Str8 result = DN_Str8FromStackTraceAllocator(allocator, &walk, skip); + DN_TcScratchEnd(&scratch); + return result; +} + +DN_API DN_Str8 DN_Str8FromStackTraceNowArena(DN_Arena *arena, DN_U16 limit, DN_U16 skip) +{ + DN_Str8 result = DN_Str8FromStackTraceNowAllocator(DN_AllocatorFromArena(arena), limit, skip); + return result; +} + +DN_API DN_StackTraceFrameSlice DN_StackTraceGetFrames(DN_Arena *arena, DN_U16 limit) +{ + DN_StackTraceFrameSlice result = {}; + if (!arena) + return result; + + DN_TcScratch scratch = DN_TcScratchBeginArena(&arena, 1); + DN_StackTrace walk = DN_StackTraceFromArena(&scratch.arena, limit); + if (walk.size) { + if (DN_PArrayPrepareArena(result.data, 0, &result.count, arena, walk.size)) { + DN_USize slice_index = 0; + for (DN_StackTraceIterator it = {}; DN_StackTraceIterate(&it, &walk);) + result.data[slice_index++] = DN_StackTraceFrameFromRawFrame(arena, it.raw_frame); + } + } + DN_TcScratchEnd(&scratch); + return result; +} + +DN_API DN_StackTraceFrame DN_StackTraceFrameFromRawFrame(DN_Arena *arena, DN_StackTraceRawFrame raw_frame) +{ +#if defined(DN_OS_WIN32) + // NOTE: Get line+filename + IMAGEHLP_LINEW64 line; + line.SizeOfStruct = sizeof(line); + DWORD line_displacement = 0; + if (!SymGetLineFromAddrW64(raw_frame.process, raw_frame.base_addr, &line_displacement, &line)) + line = {}; + + // NOTE: Get function name + alignas(SYMBOL_INFOW) char buffer[sizeof(SYMBOL_INFOW) + (MAX_SYM_NAME * sizeof(wchar_t))] = {}; + SYMBOL_INFOW *symbol = DN_Cast(SYMBOL_INFOW *) buffer; + symbol->SizeOfStruct = sizeof(*symbol); + symbol->MaxNameLen = sizeof(buffer) - sizeof(*symbol); + + uint64_t symbol_displacement = 0; // Offset to the beginning of the symbol to the address + SymFromAddrW(raw_frame.process, raw_frame.base_addr, &symbol_displacement, symbol); + + // NOTE: Construct result + DN_Str16 file_name16 = DN_Str16FromPtr(line.FileName, DN_CStr16Count(line.FileName)); + DN_Str16 function_name16 = DN_Str16FromPtr(symbol->Name, symbol->NameLen); + + DN_StackTraceFrame result = {}; + result.address = raw_frame.base_addr; + result.line_number = line.LineNumber; + result.file_name = DN_OS_W32Str16ToStr8(arena, file_name16); + result.function_name = DN_OS_W32Str16ToStr8(arena, function_name16); + + if (result.function_name.count == 0) + result.function_name = DN_Str8Lit(""); + if (result.file_name.count == 0) + result.file_name = DN_Str8Lit(""); +#else + DN_StackTraceFrame result = {}; +#endif + return result; +} + +DN_API void DN_StackTracePrint(DN_U16 limit) +{ + DN_TcScratch scratch = DN_TcScratchBeginArena(nullptr, 0); + DN_StackTraceFrameSlice stack_trace = DN_StackTraceGetFrames(&scratch.arena, limit); + for (DN_ForItSize(it, DN_StackTraceFrame, stack_trace.data, stack_trace.count)) { + DN_StackTraceFrame frame = *it.data; + DN_OS_PrintErrLnF("%.*s(%I64u): %.*s", DN_Str8PrintFmt(frame.file_name), frame.line_number, DN_Str8PrintFmt(frame.function_name)); + } + DN_TcScratchEnd(&scratch); +} + +DN_API void DN_StackTraceReloadSymbols() +{ +#if defined(DN_OS_WIN32) + HANDLE process = GetCurrentProcess(); + SymRefreshModuleList(process); +#endif +} +#endif // DN_WITH_OS (for DN_StackTrace which gets compiled out completely) + DN_API DN_F32 DN_F32Lerp(DN_F32 a, DN_F32 t, DN_F32 b) { DN_F32 result = a + ((b - a) * t); @@ -8863,15 +9359,6 @@ struct DN_ArrayFindEqMemcmpContext_ void const *find; }; -DN_API void *DN_SliceAllocArena(void **data, DN_USize *slice_size_field, DN_USize count, DN_USize elem_size, DN_U8 align, DN_ZMem zmem, DN_Arena *arena) -{ - void *result = *data; - *data = DN_ArenaAlloc(arena, count * elem_size, align, zmem); - if (*data) - *slice_size_field = count; - return result; -} - DN_API DN_ArrayFindResult DN_ArrayFind(void *data, DN_USize count, DN_USize elem_size, void const *find, DN_ArrayFindEqFunc *eq_func) { DN_ArrayFindResult result = {}; @@ -9032,18 +9519,10 @@ DN_API void *DN_ArrayMakeArrayAssert(void *data, DN_USize *count, DN_USize max, return result; } -DN_API void *DN_ArrayMakeArrayArena(void **data, DN_USize *count, DN_USize *max, DN_USize elem_size, DN_Arena *arena, DN_USize make_count, DN_ZMem z_mem) +DN_API void *DN_ArrayMakeArrayAllocator(void **data, DN_USize *count, DN_USize *max, DN_USize elem_size, DN_Allocator allocator, DN_USize make_count, DN_ZMem z_mem) { void *result = nullptr; - if (DN_ArrayPrepareArena(data, *count, max, elem_size, arena, make_count)) - result = DN_ArrayMakeArray(*data, count, *max, elem_size, make_count, z_mem); - return result; -} - -DN_API void *DN_ArrayMakeArrayPool(void **data, DN_USize *count, DN_USize *max, DN_USize elem_size, DN_Pool *pool, DN_USize make_count, DN_ZMem z_mem) -{ - void *result = nullptr; - if (DN_ArrayPreparePool(data, *count, max, elem_size, pool, make_count)) + if (DN_ArrayPrepareAllocator(data, *count, max, elem_size, allocator, make_count)) result = DN_ArrayMakeArray(*data, count, *max, elem_size, make_count, z_mem); return result; } @@ -9065,18 +9544,10 @@ DN_API void *DN_ArrayAddArray(void *data, DN_USize *count, DN_USize max, DN_USiz return result; } -DN_API void *DN_ArrayAddArrayArena(void **data, DN_USize *count, DN_USize *max, DN_USize elem_size, DN_Arena *arena, void const *elems, DN_USize elems_count, DN_AddType add) +DN_API void *DN_ArrayAddArrayAllocator(void **data, DN_USize *count, DN_USize *max, DN_USize elem_size, DN_Allocator allocator, void const *elems, DN_USize elems_count, DN_AddType add) { void *result = nullptr; - if (DN_ArrayPrepareArena(data, *count, max, elem_size, arena, elems_count)) - result = DN_ArrayAddArray(*data, count, *max, elem_size, elems, elems_count, add); - return result; -} - -DN_API void *DN_ArrayAddArrayPool(void **data, DN_USize *count, DN_USize *max, DN_USize elem_size, DN_Pool *pool, void const *elems, DN_USize elems_count, DN_AddType add) -{ - void *result = nullptr; - if (DN_ArrayPreparePool(data, *count, max, elem_size, pool, elems_count)) + if (DN_ArrayPrepareAllocator(data, *count, max, elem_size, allocator, elems_count)) result = DN_ArrayAddArray(*data, count, *max, elem_size, elems, elems_count, add); return result; } @@ -9088,7 +9559,7 @@ DN_API void *DN_ArrayAddArrayAssert(void *data, DN_USize *count, DN_USize max, D return result; } -static bool DN_ArrayResizeAllocator_(void **data, DN_USize *count, DN_USize *max, DN_USize elem_size, DN_Allocator allocator, DN_USize new_max) +DN_API bool DN_ArrayResizeAllocator(void **data, DN_USize *count, DN_USize *max, DN_USize elem_size, DN_Allocator allocator, DN_USize new_max) { bool result = true; if (!max || new_max != *max) { @@ -9097,8 +9568,7 @@ static bool DN_ArrayResizeAllocator_(void **data, DN_USize *count, DN_USize *max if (buffer) { DN_USize bytes_to_copy = elem_size * DN_Min(*count, new_max); DN_Memcpy(buffer, *data, bytes_to_copy); - if (allocator.type == DN_AllocatorType_Pool) - DN_PoolDealloc(DN_Cast(DN_Pool *)allocator.context, *data); + DN_AllocatorDealloc(allocator, *data, (max ? *max : 0) * elem_size); *data = buffer; *count = DN_Min(*count, new_max); if (max) @@ -9111,88 +9581,38 @@ static bool DN_ArrayResizeAllocator_(void **data, DN_USize *count, DN_USize *max return result; } -DN_API bool DN_ArrayResizeArena(void **data, DN_USize *count, DN_USize *max, DN_USize elem_size, DN_Arena *arena, DN_USize new_max) -{ - DN_Allocator allocator = DN_AllocatorFromArena(arena); - bool result = DN_ArrayResizeAllocator_(data, count, max, elem_size, allocator, new_max); - return result; -} - -DN_API bool DN_ArrayResizePool(void **data, DN_USize *count, DN_USize *max, DN_USize elem_size, DN_Pool *pool, DN_USize new_max) -{ - DN_Allocator allocator = DN_AllocatorFromPool(pool); - bool result = DN_ArrayResizeAllocator_(data, count, max, elem_size, allocator, new_max); - return result; -} - -DN_API bool DN_ArrayReservePool(void **data, DN_USize *max, DN_USize elem_size, DN_Pool *pool, DN_USize new_max) +DN_API bool DN_ArrayReserveAllocator(void **data, DN_USize *max, DN_USize elem_size, DN_Allocator allocator, DN_USize new_max) { bool result = true; if (!max || new_max > *max) { DN_USize count = 0; - result = DN_ArrayResizePool(data, &count, max, elem_size, pool, new_max); + result = DN_ArrayResizeAllocator(data, &count, max, elem_size, allocator, new_max); } return result; } -DN_API bool DN_ArrayReserveArena(void **data, DN_USize *max, DN_USize elem_size, DN_Arena *arena, DN_USize new_max) -{ - bool result = true; - if (!max || new_max > *max) { - DN_USize count = 0; - result = DN_ArrayResizeArena(data, &count, max, elem_size, arena, new_max); - } - return result; -} - -DN_API bool DN_ArrayPreparePool(void **data, DN_USize count, DN_USize *max, DN_USize elem_size, DN_Pool *pool, DN_USize add_count) +DN_API bool DN_ArrayPrepareAllocator(void **data, DN_USize count, DN_USize *max, DN_USize elem_size, DN_Allocator allocator, DN_USize add_count) { bool result = true; DN_USize new_count = count + add_count; if (new_count > *max) { DN_USize new_max = DN_Max(DN_Max(*max * 2, new_count), 8); - result = DN_ArrayResizePool(data, &count, max, elem_size, pool, new_max); + result = DN_ArrayResizeAllocator(data, &count, max, elem_size, allocator, new_max); } return result; } -DN_API bool DN_ArrayPrepareArena(void **data, DN_USize count, DN_USize *max, DN_USize elem_size, DN_Arena *arena, DN_USize add_count) -{ - bool result = true; - DN_USize new_count = count + add_count; - if (new_count > *max) { - DN_USize new_max = DN_Max(DN_Max(*max * 2, new_count), 8); - result = DN_ArrayResizeArena(data, &count, max, elem_size, arena, new_max); - } - return result; -} - -DN_API DN_USize DN_ArrayCopyPtrArena(void **data, void const *src, DN_USize count, DN_USize elem_size, DN_Arena *arena) +DN_API DN_USize DN_ArrayCopyPtrAllocator(void **data, void const *src, DN_USize count, DN_USize elem_size, DN_Allocator allocator) { DN_USize result = 0; - if (DN_ArrayReserveArena(data, /*max=*/ &result, elem_size, arena, /*new_max=*/ count)) + if (DN_ArrayReserveAllocator(data, /*max=*/ &result, elem_size, allocator, /*new_max=*/ count)) DN_Memcpy(*data, src, elem_size * count); return result; } -DN_API DN_USize DN_ArrayCopyPtrArenaAssert(void **data, void const *src, DN_USize count, DN_USize elem_size, DN_Arena *arena, DN_CallSite call_site) +DN_API DN_USize DN_ArrayCopyPtrAllocatorAssert(void **data, void const *src, DN_USize count, DN_USize elem_size, DN_Allocator allocator, DN_CallSite call_site) { - DN_USize result = DN_ArrayCopyPtrArena(data, src, count, elem_size, arena); - DN_AssertCallSiteF(result == count, call_site, "Array copy failed, failed to allocate: %zu items", count); - return result; -} - -DN_API DN_USize DN_ArrayCopyPtrPool(void **data, void const *src, DN_USize count, DN_USize elem_size, DN_Pool *pool) -{ - DN_USize result = 0; - if (DN_ArrayReservePool(data, /*max=*/ &result, elem_size, pool, /*new_max=*/ count)) - DN_Memcpy(*data, src, elem_size * count); - return result; -} - -DN_API DN_USize DN_ArrayCopyPtrPoolAssert(void **data, void const *src, DN_USize count, DN_USize elem_size, DN_Pool *pool, DN_CallSite call_site) -{ - DN_USize result = DN_ArrayCopyPtrPool(data, src, count, elem_size, pool); + DN_USize result = DN_ArrayCopyPtrAllocator(data, src, count, elem_size, allocator); DN_AssertCallSiteF(result == count, call_site, "Array copy failed, failed to allocate: %zu items", count); return result; } @@ -9270,7 +9690,7 @@ DN_API bool DN_HTableKeyEqFuncStr8Eq(void const *lhs, void const *rhs, DN_USize) return result; } -DN_API DN_HTableInitArgs DN_HTableInitArgsDefault_(void** kvs, DN_USize size_of_kv, DN_USize offset_of_hash, DN_USize size_of_key, DN_USize offset_of_key, DN_USize size_of_value, DN_USize offset_of_value) +DN_API DN_HTableInitArgs DN_HTableInitArgsDefaultRaw(void** kvs, DN_USize size_of_kv, DN_USize offset_of_hash, DN_USize size_of_key, DN_USize offset_of_key, DN_USize size_of_value, DN_USize offset_of_value) { DN_HTableInitArgs result = {}; DN_AssertF((*kvs) == 0, "The key-value pointer must be null as the hash table will allocate the objects and keep the pointer in sync with the table for you: %p", *kvs); @@ -9288,7 +9708,7 @@ DN_API DN_HTableInitArgs DN_HTableInitArgsDefault_(void** kvs, DN_USize size_of_ return result; } -DN_API DN_HTable DN_HTableInit_(DN_HTableInitArgs args) +static DN_HTable DN_HTableInit_(DN_HTableInitArgs args) { DN_HTable result = {}; result.load_factor01 = args.load_factor; @@ -9304,17 +9724,19 @@ DN_API DN_HTable DN_HTableInit_(DN_HTableInitArgs args) return result; } -DN_API DN_HTableInitResult DN_HTableInitHeap(DN_HTableInitArgs args, DN_Heap heap) +DN_API DN_HTableInitResult DN_HTableInitHeap(DN_HTableInitArgs args, DN_Heap *heap) { DN_HTableInitResult result = {}; result.table = DN_HTableInit_(args); result.table.heap = heap; result.table.flags |= DN_HTableFlags_UsingHeap; result.success = DN_HTableResize(&result.table, args.max); + if (!result.success) + result.table = {}; return result; } -DN_API DN_HTable DN_HTableInitHeapAssert(DN_HTableInitArgs args, DN_Heap heap) +DN_API DN_HTable DN_HTableInitHeapAssert(DN_HTableInitArgs args, DN_Heap *heap) { DN_HTableInitResult init = DN_HTableInitHeap(args, heap); DN_HTable result = init.table; @@ -9322,7 +9744,7 @@ DN_API DN_HTable DN_HTableInitHeapAssert(DN_HTableInitArgs args, DN_Heap heap) return result; } -DN_API DN_HTableInitResult DN_HTableInitPool(DN_HTableInitArgs args, DN_Pool pool, DN_HTableDeallocPoolOnDeinit dealloc_pool) +DN_API DN_HTableInitResult DN_HTableInitPool(DN_HTableInitArgs args, DN_Pool *pool, DN_HTableDeallocPoolOnDeinit dealloc_pool) { DN_HTableInitResult result = {}; result.table = DN_HTableInit_(args); @@ -9335,7 +9757,7 @@ DN_API DN_HTableInitResult DN_HTableInitPool(DN_HTableInitArgs args, DN_Pool poo return result; } -DN_API DN_HTable DN_HTableInitPoolAssert(DN_HTableInitArgs args, DN_Pool pool, DN_HTableDeallocPoolOnDeinit dealloc_pool) +DN_API DN_HTable DN_HTableInitPoolAssert(DN_HTableInitArgs args, DN_Pool *pool, DN_HTableDeallocPoolOnDeinit dealloc_pool) { DN_HTableInitResult init = DN_HTableInitPool(args, pool, dealloc_pool); DN_HTable result = init.table; @@ -9346,11 +9768,11 @@ DN_API DN_HTable DN_HTableInitPoolAssert(DN_HTableInitArgs args, DN_Pool pool, D DN_API void DN_HTableDeinit(DN_HTable *table) { if ((table->flags & DN_HTableFlags_UsingHeap)) { - DN_HeapDealloc(&table->heap, *table->kvs, table->max * table->size_of_kv); + DN_HeapDealloc(table->heap, *table->kvs, table->max * table->size_of_kv); } else { - DN_PoolDealloc(&table->pool, *table->kvs); + DN_PoolDealloc(table->pool, *table->kvs); if (table->flags & DN_HTableFlags_DeallocPoolOnDeinit) - DN_ArenaDeinit(table->pool.arena); + DN_ArenaDeinit(table->pool->arena); } *table->kvs = nullptr; *table = {}; @@ -9437,9 +9859,9 @@ DN_API bool DN_HTableResize(DN_HTable *table, DN_USize new_max) void* new_kvs = {}; DN_USize new_kvs_size = new_max * table->size_of_kv; if (table->flags & DN_HTableFlags_UsingHeap) { - new_kvs = DN_HeapAllocCallSite(&table->heap, /*reserve*/ new_kvs_size, /*commit*/ new_kvs_size, DN_HeapAllocFlag_Nil, DN_CallSiteNowNamed("DN HTable Resize")); + new_kvs = DN_HeapAllocCallSite(table->heap, /*reserve*/ new_kvs_size, /*commit*/ new_kvs_size, DN_HeapAllocFlag_Nil, DN_CallSiteNowNamed("DN HTable Resize")); } else { - new_kvs = DN_PoolAlloc(&table->pool, new_max * table->size_of_kv); + new_kvs = DN_PoolAlloc(table->pool, new_max * table->size_of_kv); } if (new_kvs) { @@ -9457,9 +9879,9 @@ DN_API bool DN_HTableResize(DN_HTable *table, DN_USize new_max) if (old_kvs) { if (table->flags & DN_HTableFlags_UsingHeap) - DN_HeapDealloc(&table->heap, old_kvs, old_max * table->size_of_kv); + DN_HeapDealloc(table->heap, old_kvs, old_max * table->size_of_kv); else - DN_PoolDealloc(&table->pool, old_kvs); + DN_PoolDealloc(table->pool, old_kvs); } } @@ -10093,14 +10515,18 @@ DN_API void DN_TestGroupBeginF(DN_TestCore *test, char const *fmt, ...) // NOTE: Mark as active test->curr_group = group; + #if DN_WITH_OS group->ts_begin = DN_OS_PerfCounterNow(); + #endif } DN_API void DN_TestGroupEnd(DN_TestCore *test) { DN_TestGroup *group = test->curr_group; DN_AssertF(group, "Test group must be started before attempting to end it"); + #if DN_WITH_OS group->ts_end = DN_OS_PerfCounterNow(); + #endif test->curr_group = nullptr; } @@ -10122,7 +10548,9 @@ DN_API void DN_TestBeginF(DN_TestCore *test, char const *fmt, ...) // NOTE: Mark as active group->curr_entry = entry; + #if DN_WITH_OS entry->ts_begin = DN_OS_PerfCounterNow(); + #endif test->total_count++; } @@ -10133,7 +10561,9 @@ DN_API void DN_TestEnd(DN_TestCore *test) DN_TestEntry *entry = group->curr_entry; DN_AssertF(entry, "Test must be started before attempting to end a test in group (%.*s)", DN_Str8PrintFmt(group->name)); + #if DN_WITH_OS entry->ts_end = DN_OS_PerfCounterNow(); + #endif if (entry->failed) test->total_failed++; else @@ -10185,7 +10615,10 @@ DN_API DN_Str8 DN_Str8FromTestCore(DN_TestCore const *test, DN_Arena *arena, DN_ outcome_str8 = DN_Str8FmtAnsiColourV3F32Rgb255Arena(DN_AnsiColourMode_Fg, good_colour, &scratch.arena, "%.*s", DN_Str8PrintFmt(outcome_str8)); } - DN_F64 elapsed_ms = DN_OS_PerfCounterMs(entry->ts_begin, entry->ts_end); + DN_F64 elapsed_ms = 0; + #if DN_WITH_OS + DN_OS_PerfCounterMs(entry->ts_begin, entry->ts_end); + #endif DN_Str8BuilderAppendF(&builder, "%.*s %.*s (%.3fms)\n", DN_Str8PrintFmt(test_prefix), DN_Str8PrintFmt(outcome_str8), elapsed_ms); // NOTE: Output the test diagnostics, populated on failure @@ -10225,12 +10658,11 @@ DN_API DN_Str8 DN_Str8FromTestCore(DN_TestCore const *test, DN_Arena *arena, DN_ } } - DN_F64 elapsed_ms = DN_OS_PerfCounterMs(group->ts_begin, group->ts_end); - DN_MSVC_WARNING_PUSH - DN_MSVC_WARNING_DISABLE(6067) // _Param_(3) in call to 'DN_Str8BuilderAppendF' must be the address of a string. Actual type: 'const unsigned __int64'. - DN_MSVC_WARNING_DISABLE(6271) // Extra argument passed to 'DN_Str8BuilderAppendF'. + DN_F64 elapsed_ms = 0; + #if DN_WITH_OS + DN_OS_PerfCounterMs(group->ts_begin, group->ts_end); + #endif DN_Str8 group_prefix = DN_Str8FmtArena(&scratch.arena, "%'zu/%'zu test%s", group_successes, group->entries_count, group_successes > 1 ? "s" :""); - DN_MSVC_WARNING_POP if (flags & DN_Str8FromTestCoreFlags_Colour) { if (group_failures == 0) group_prefix = DN_Str8FmtAnsiColourV3F32Rgb255Arena(DN_AnsiColourMode_Fg, good_colour, &scratch.arena, "%.*s", DN_Str8PrintFmt(group_prefix)); @@ -10651,38 +11083,38 @@ DN_API DN_TestCore DN_TestSuite(DN_Arena *arena_) { for (DN_TestScopeF(&result, "[CPU] Query CPUID")) { DN_RefImplCPUReport ref_cpu_report = DN_RefImplCPUReport_Init(); - DN_CPUReport cpu_report = DN_CPUGetReport(); + DN_CpuReport cpu_report = DN_CpuGetReport(); - DN_TestVerifyExpr(&result, DN_CPUHasFeature(&cpu_report, DN_CPUFeature_3DNow) == ref_cpu_report._3DNOW()); - DN_TestVerifyExpr(&result, DN_CPUHasFeature(&cpu_report, DN_CPUFeature_3DNowExt) == ref_cpu_report._3DNOWEXT()); - DN_TestVerifyExpr(&result, DN_CPUHasFeature(&cpu_report, DN_CPUFeature_ABM) == ref_cpu_report.ABM()); - DN_TestVerifyExpr(&result, DN_CPUHasFeature(&cpu_report, DN_CPUFeature_AES) == ref_cpu_report.AES()); - DN_TestVerifyExpr(&result, DN_CPUHasFeature(&cpu_report, DN_CPUFeature_AVX) == ref_cpu_report.AVX()); - DN_TestVerifyExpr(&result, DN_CPUHasFeature(&cpu_report, DN_CPUFeature_AVX2) == ref_cpu_report.AVX2()); - DN_TestVerifyExpr(&result, DN_CPUHasFeature(&cpu_report, DN_CPUFeature_AVX512CD) == ref_cpu_report.AVX512CD()); - DN_TestVerifyExpr(&result, DN_CPUHasFeature(&cpu_report, DN_CPUFeature_AVX512ER) == ref_cpu_report.AVX512ER()); - DN_TestVerifyExpr(&result, DN_CPUHasFeature(&cpu_report, DN_CPUFeature_AVX512F) == ref_cpu_report.AVX512F()); - DN_TestVerifyExpr(&result, DN_CPUHasFeature(&cpu_report, DN_CPUFeature_AVX512PF) == ref_cpu_report.AVX512PF()); - DN_TestVerifyExpr(&result, DN_CPUHasFeature(&cpu_report, DN_CPUFeature_CMPXCHG16B) == ref_cpu_report.CMPXCHG16B()); - DN_TestVerifyExpr(&result, DN_CPUHasFeature(&cpu_report, DN_CPUFeature_F16C) == ref_cpu_report.F16C()); - DN_TestVerifyExpr(&result, DN_CPUHasFeature(&cpu_report, DN_CPUFeature_FMA) == ref_cpu_report.FMA()); - DN_TestVerifyExpr(&result, DN_CPUHasFeature(&cpu_report, DN_CPUFeature_MMX) == ref_cpu_report.MMX()); - DN_TestVerifyExpr(&result, DN_CPUHasFeature(&cpu_report, DN_CPUFeature_MmxExt) == ref_cpu_report.MMXEXT()); - DN_TestVerifyExpr(&result, DN_CPUHasFeature(&cpu_report, DN_CPUFeature_MONITOR) == ref_cpu_report.MONITOR()); - DN_TestVerifyExpr(&result, DN_CPUHasFeature(&cpu_report, DN_CPUFeature_MOVBE) == ref_cpu_report.MOVBE()); - DN_TestVerifyExpr(&result, DN_CPUHasFeature(&cpu_report, DN_CPUFeature_PCLMULQDQ) == ref_cpu_report.PCLMULQDQ()); - DN_TestVerifyExpr(&result, DN_CPUHasFeature(&cpu_report, DN_CPUFeature_POPCNT) == ref_cpu_report.POPCNT()); - DN_TestVerifyExpr(&result, DN_CPUHasFeature(&cpu_report, DN_CPUFeature_RDRAND) == ref_cpu_report.RDRAND()); - DN_TestVerifyExpr(&result, DN_CPUHasFeature(&cpu_report, DN_CPUFeature_RDSEED) == ref_cpu_report.RDSEED()); - DN_TestVerifyExpr(&result, DN_CPUHasFeature(&cpu_report, DN_CPUFeature_RDTscP) == ref_cpu_report.RDTscP()); - DN_TestVerifyExpr(&result, DN_CPUHasFeature(&cpu_report, DN_CPUFeature_SHA) == ref_cpu_report.SHA()); - DN_TestVerifyExpr(&result, DN_CPUHasFeature(&cpu_report, DN_CPUFeature_SSE) == ref_cpu_report.SSE()); - DN_TestVerifyExpr(&result, DN_CPUHasFeature(&cpu_report, DN_CPUFeature_SSE2) == ref_cpu_report.SSE2()); - DN_TestVerifyExpr(&result, DN_CPUHasFeature(&cpu_report, DN_CPUFeature_SSE3) == ref_cpu_report.SSE3()); - DN_TestVerifyExpr(&result, DN_CPUHasFeature(&cpu_report, DN_CPUFeature_SSE41) == ref_cpu_report.SSE41()); - DN_TestVerifyExpr(&result, DN_CPUHasFeature(&cpu_report, DN_CPUFeature_SSE42) == ref_cpu_report.SSE42()); - DN_TestVerifyExpr(&result, DN_CPUHasFeature(&cpu_report, DN_CPUFeature_SSE4A) == ref_cpu_report.SSE4a()); - DN_TestVerifyExpr(&result, DN_CPUHasFeature(&cpu_report, DN_CPUFeature_SSSE3) == ref_cpu_report.SSSE3()); + DN_TestVerifyExpr(&result, DN_CpuHasFeature(&cpu_report, DN_CpuFeature_3DNow) == ref_cpu_report._3DNOW()); + DN_TestVerifyExpr(&result, DN_CpuHasFeature(&cpu_report, DN_CpuFeature_3DNowExt) == ref_cpu_report._3DNOWEXT()); + DN_TestVerifyExpr(&result, DN_CpuHasFeature(&cpu_report, DN_CpuFeature_ABM) == ref_cpu_report.ABM()); + DN_TestVerifyExpr(&result, DN_CpuHasFeature(&cpu_report, DN_CpuFeature_AES) == ref_cpu_report.AES()); + DN_TestVerifyExpr(&result, DN_CpuHasFeature(&cpu_report, DN_CpuFeature_AVX) == ref_cpu_report.AVX()); + DN_TestVerifyExpr(&result, DN_CpuHasFeature(&cpu_report, DN_CpuFeature_AVX2) == ref_cpu_report.AVX2()); + DN_TestVerifyExpr(&result, DN_CpuHasFeature(&cpu_report, DN_CpuFeature_AVX512CD) == ref_cpu_report.AVX512CD()); + DN_TestVerifyExpr(&result, DN_CpuHasFeature(&cpu_report, DN_CpuFeature_AVX512ER) == ref_cpu_report.AVX512ER()); + DN_TestVerifyExpr(&result, DN_CpuHasFeature(&cpu_report, DN_CpuFeature_AVX512F) == ref_cpu_report.AVX512F()); + DN_TestVerifyExpr(&result, DN_CpuHasFeature(&cpu_report, DN_CpuFeature_AVX512PF) == ref_cpu_report.AVX512PF()); + DN_TestVerifyExpr(&result, DN_CpuHasFeature(&cpu_report, DN_CpuFeature_CMPXCHG16B) == ref_cpu_report.CMPXCHG16B()); + DN_TestVerifyExpr(&result, DN_CpuHasFeature(&cpu_report, DN_CpuFeature_F16C) == ref_cpu_report.F16C()); + DN_TestVerifyExpr(&result, DN_CpuHasFeature(&cpu_report, DN_CpuFeature_FMA) == ref_cpu_report.FMA()); + DN_TestVerifyExpr(&result, DN_CpuHasFeature(&cpu_report, DN_CpuFeature_MMX) == ref_cpu_report.MMX()); + DN_TestVerifyExpr(&result, DN_CpuHasFeature(&cpu_report, DN_CpuFeature_MmxExt) == ref_cpu_report.MMXEXT()); + DN_TestVerifyExpr(&result, DN_CpuHasFeature(&cpu_report, DN_CpuFeature_MONITOR) == ref_cpu_report.MONITOR()); + DN_TestVerifyExpr(&result, DN_CpuHasFeature(&cpu_report, DN_CpuFeature_MOVBE) == ref_cpu_report.MOVBE()); + DN_TestVerifyExpr(&result, DN_CpuHasFeature(&cpu_report, DN_CpuFeature_PCLMULQDQ) == ref_cpu_report.PCLMULQDQ()); + DN_TestVerifyExpr(&result, DN_CpuHasFeature(&cpu_report, DN_CpuFeature_POPCNT) == ref_cpu_report.POPCNT()); + DN_TestVerifyExpr(&result, DN_CpuHasFeature(&cpu_report, DN_CpuFeature_RDRAND) == ref_cpu_report.RDRAND()); + DN_TestVerifyExpr(&result, DN_CpuHasFeature(&cpu_report, DN_CpuFeature_RDSEED) == ref_cpu_report.RDSEED()); + DN_TestVerifyExpr(&result, DN_CpuHasFeature(&cpu_report, DN_CpuFeature_RDTscP) == ref_cpu_report.RDTscP()); + DN_TestVerifyExpr(&result, DN_CpuHasFeature(&cpu_report, DN_CpuFeature_SHA) == ref_cpu_report.SHA()); + DN_TestVerifyExpr(&result, DN_CpuHasFeature(&cpu_report, DN_CpuFeature_SSE) == ref_cpu_report.SSE()); + DN_TestVerifyExpr(&result, DN_CpuHasFeature(&cpu_report, DN_CpuFeature_SSE2) == ref_cpu_report.SSE2()); + DN_TestVerifyExpr(&result, DN_CpuHasFeature(&cpu_report, DN_CpuFeature_SSE3) == ref_cpu_report.SSE3()); + DN_TestVerifyExpr(&result, DN_CpuHasFeature(&cpu_report, DN_CpuFeature_SSE41) == ref_cpu_report.SSE41()); + DN_TestVerifyExpr(&result, DN_CpuHasFeature(&cpu_report, DN_CpuFeature_SSE42) == ref_cpu_report.SSE42()); + DN_TestVerifyExpr(&result, DN_CpuHasFeature(&cpu_report, DN_CpuFeature_SSE4A) == ref_cpu_report.SSE4a()); + DN_TestVerifyExpr(&result, DN_CpuHasFeature(&cpu_report, DN_CpuFeature_SSSE3) == ref_cpu_report.SSSE3()); } } #endif // defined(DN_PLATFORM_WIN32) && defined(DN_COMPILER_MSVC) @@ -10744,7 +11176,7 @@ DN_API DN_TestCore DN_TestSuite(DN_Arena *arena_) } for (DN_TestScopeF(&result, "[Intrinsics] CPUGetTsc compile check")) { - DN_CPUGetTsc(); + DN_CpuTscNow(); } for (DN_TestScopeF(&result, "[Intrinsics] CompilerReadBarrierAndCPUReadFence compile check")) { @@ -10763,9 +11195,9 @@ DN_API DN_TestCore DN_TestSuite(DN_Arena *arena_) for (DN_TestScopeF(&result, "[Arena] Reused memory is zeroed out")) { uint8_t alignment = 1; DN_USize alloc_size = DN_Kilobytes(128); - DN_MemList mem = DN_MemListFromHeap(0, 0, DN_MemFlags_Nil, DN_OS_HeapInitVirtual(), "Reused memory"); - DN_Arena arena = DN_ArenaFromMemList(&mem); - DN_DEFER { DN_MemListDeinit(&mem); }; + DN_MemList* mem = DN_MemListFromHeap(0, 0, DN_MemFlags_Nil, DN_OS_HeapInitVirtual(), "Reused memory"); + DN_Arena arena = DN_ArenaFromMemList(mem); + DN_DEFER { DN_MemListDeinit(mem); }; uintptr_t first_ptr_address = 0; { @@ -10785,9 +11217,9 @@ DN_API DN_TestCore DN_TestSuite(DN_Arena *arena_) } for (DN_TestScopeF(&result, "[Arena] Grows naturally, 1mb + 4mb")) { - DN_MemList mem = DN_MemListFromHeap(DN_Megabytes(2), DN_Megabytes(2), DN_MemFlags_Nil, DN_OS_HeapInitVirtual(), "Grows naturally"); - DN_Arena arena = DN_ArenaFromMemList(&mem); - DN_DEFER { DN_MemListDeinit(&mem); }; + DN_MemList* mem = DN_MemListFromHeap(DN_Megabytes(2), DN_Megabytes(2), DN_MemFlags_Nil, DN_OS_HeapInitVirtual(), "Grows naturally"); + DN_Arena arena = DN_ArenaFromMemList(mem); + DN_DEFER { DN_MemListDeinit(mem); }; char *ptr_1mb = DN_ArenaNewArray(&arena, char, DN_Megabytes(1), DN_ZMem_Yes); char *ptr_4mb = DN_ArenaNewArray(&arena, char, DN_Megabytes(4), DN_ZMem_Yes); @@ -10807,9 +11239,9 @@ DN_API DN_TestCore DN_TestSuite(DN_Arena *arena_) } for (DN_TestScopeF(&result, "[Arena] Grows naturally, 1mb, temp memory 4mb")) { - DN_MemList mem = DN_MemListFromHeap(DN_Megabytes(2), DN_Megabytes(2), DN_MemFlags_Nil, DN_OS_HeapInitVirtual(), "Grows naturally"); - DN_Arena arena = DN_ArenaFromMemList(&mem); - DN_DEFER { DN_MemListDeinit(&mem); }; + DN_MemList* mem = DN_MemListFromHeap(DN_Megabytes(2), DN_Megabytes(2), DN_MemFlags_Nil, DN_OS_HeapInitVirtual(), "Grows naturally"); + DN_Arena arena = DN_ArenaFromMemList(mem); + DN_DEFER { DN_MemListDeinit(mem); }; char *ptr_1mb = DN_Cast(char *) DN_ArenaAlloc(&arena, DN_Megabytes(1), 1, DN_ZMem_Yes); DN_TestVerifyExpr(&result, ptr_1mb != nullptr); @@ -11517,16 +11949,16 @@ DN_API DN_TestCore DN_TestSuite(DN_Arena *arena_) char arena_base[512]; for (DN_TestScopeF(&result, "[Strings] Format from arena")) { - DN_MemList mem = DN_MemListFromBuffer(arena_base, sizeof(arena_base), DN_MemFlags_Nil); - DN_Arena arena = DN_ArenaFromMemList(&mem); + DN_MemList* mem = DN_MemListFromBuffer(arena_base, sizeof(arena_base), DN_MemFlags_Nil); + DN_Arena arena = DN_ArenaFromMemList(mem); DN_Str8 str8 = DN_Str8FmtArena(&arena, "Foo Bar %d", 5); DN_Str8 expect = DN_Str8Lit("Foo Bar 5"); DN_TestVerifyStr8EqF(&result, str8, expect, "str8=%.*s", DN_Str8PrintFmt(str8), DN_Str8PrintFmt(expect)); } for (DN_TestScopeF(&result, "[Strings] Format from pool")) { - DN_MemList mem = DN_MemListFromBuffer(arena_base, sizeof(arena_base), DN_MemFlags_Nil); - DN_Arena arena = DN_ArenaFromMemList(&mem); + DN_MemList* mem = DN_MemListFromBuffer(arena_base, sizeof(arena_base), DN_MemFlags_Nil); + DN_Arena arena = DN_ArenaFromMemList(mem); DN_Pool pool = DN_PoolFromArena(&arena, 0); DN_Str8 str8 = DN_Str8FmtPool(&pool, "Foo Bar %d", 5); DN_Str8 expect = DN_Str8Lit("Foo Bar 5"); @@ -11597,29 +12029,29 @@ DN_API DN_TestCore DN_TestSuite(DN_Arena *arena_) } for (DN_TestScopeF(&result, "[Strings] Is all digits fails on non-digit string")) { - DN_B32 str_result = DN_Str8Is(DN_Str8Lit("@123string"), DN_Str8IsFlags_Digits); - DN_TestVerifyExpr(&result, str_result == false); + DN_Str8IsResult str_result = DN_Str8Is(DN_Str8Lit("@123string"), DN_Str8IsFlags_Digits); + DN_TestVerifyExpr(&result, !str_result.success); } for (DN_TestScopeF(&result, "[Strings] Is all digits fails on nullptr")) { - DN_B32 str_result = DN_Str8Is(DN_Str8FromPtr(nullptr, 0), DN_Str8IsFlags_Digits); - DN_TestVerifyExpr(&result, str_result == false); + DN_Str8IsResult str_result = DN_Str8Is(DN_Str8FromPtr(nullptr, 0), DN_Str8IsFlags_Digits); + DN_TestVerifyExpr(&result, !str_result.success); } for (DN_TestScopeF(&result, "[Strings] Is all digits fails on string w/ 0 size")) { - char const buf[] = "@123string"; - DN_B32 str_result = DN_Str8Is(DN_Str8FromPtr(buf, 0), DN_Str8IsFlags_Digits); - DN_TestVerifyExpr(&result, !str_result); + char const buf[] = "@123string"; + DN_Str8IsResult str_result = DN_Str8Is(DN_Str8FromPtr(buf, 0), DN_Str8IsFlags_Digits); + DN_TestVerifyExpr(&result, !str_result.success); } for (DN_TestScopeF(&result, "[Strings] Is all digits success")) { - DN_B32 str_result = DN_Str8Is(DN_Str8Lit("23"), DN_Str8IsFlags_Digits); - DN_TestVerifyExpr(&result, DN_Cast(bool) str_result == true); + DN_Str8IsResult str_result = DN_Str8Is(DN_Str8Lit("23"), DN_Str8IsFlags_Digits); + DN_TestVerifyExpr(&result, str_result.success); } for (DN_TestScopeF(&result, "[Strings] Is all digits fails on whitespace")) { - DN_B32 str_result = DN_Str8Is(DN_Str8Lit("23 "), DN_Str8IsFlags_Digits); - DN_TestVerifyExpr(&result, DN_Cast(bool) str_result == false); + DN_Str8IsResult str_result = DN_Str8Is(DN_Str8Lit("23 "), DN_Str8IsFlags_Digits); + DN_TestVerifyExpr(&result, !str_result.success); } // NOTE: DN_Str8BSplit @@ -12060,23 +12492,20 @@ DN_API DN_MemDebuggerSnapshot DN_MemDebuggerSnapshotMake(DN_MemDebugger *debugge if (!debugger) return result; + // NOTE: Exclude the snapshot arena from the memory debugger for the entire snapshot. The snapshot + // allocates its working memory from this arena while holding the debugger's mutexes, so tracking + // those allocations (or their commit growth) would re-enter those mutexes and dead-lock. + DN_HeapFlags arena_flags_copy = arena->mem->heap.flags; + if (arena->mem->flags & DN_MemFlags_Heap) + arena->mem->heap.flags |= DN_HeapFlags_ExcludeFromMemDebugger; + DN_TicketMutexBegin(&debugger->alloc_table_mutex); { DN_USize count_req = debugger->alloc_table.count; - // NOTE: Exclude this allocation from the memory debugger otherwise that will call into the - // memory debugger which engages the `alloc_table_mutex` it self causing a dead-lock. We restore - // the flag, if it was set after the fact. - DN_HeapFlags flags_copy = arena->mem->heap.flags; - { - if (arena->mem->flags & DN_MemFlags_Heap) - arena->mem->heap.flags &= ~DN_HeapFlags_ExcludeFromMemDebugger; - - // NOTE: Allocate memory - result.count = 0; - result.data = DN_ArenaNewArrayZ(arena, DN_MemDebuggerSnapshotPtrData, count_req); - } - arena->mem->heap.flags = flags_copy; + // NOTE: Allocate memory (this arena is excluded for the whole snapshot, see above) + result.count = 0; + result.data = DN_ArenaNewArrayZ(arena, DN_MemDebuggerSnapshotPtrData, count_req); // NOTE: Snapshot the allocation table if (result.data) { @@ -12088,25 +12517,135 @@ DN_API DN_MemDebuggerSnapshot DN_MemDebuggerSnapshotMake(DN_MemDebugger *debugge DN_MemDebuggerPtrData const *alloc = &kv->value; if (alloc->flags & DN_MemDebuggerPtrFlag_Freed) { result.freed_count++; - result.freed_bytes += alloc->size; + DN_CArrayCopy(result.freed_bytes, alloc->freed_bytes); } else { DN_MemDebuggerSnapshotPtrData *data = DN_PArrayMakeZ(result.data, &result.count, count_req); data->ptr = alloc->ptr; - data->size = alloc->size; data->flags = alloc->flags; - // NOTE: The strings in the call site are in the data-segment so shallow copy is fine - data->call_site = alloc->call_site; - data->stack_trace = DN_Str8FromStr8Arena(alloc->stack_trace, arena); - result.active_bytes += data->size; + DN_CArrayCopy(data->bytes, alloc->bytes); + + // NOTE: The strings in the call site are in the data-segment so shallow copy is fine, + // unless the heap-alloc flags are set, indicating that this is not the case. The debugger + // "owns" the memory and at any arbitrary point it can decide to free it, so we need to + // take ownership. + data->call_site = alloc->call_site; + if (debugger->flags & DN_MemDebuggerFlags_HeapAllocCallSiteStrings) { + data->call_site.name = DN_Str8FromStr8Arena(data->call_site.name, arena); + data->call_site.file = DN_Str8FromStr8Arena(data->call_site.file, arena); + data->call_site.function = DN_Str8FromStr8Arena(data->call_site.function, arena); + } + + data->stack_trace = DN_Str8FromStr8Arena(alloc->stack_trace, arena); + for (DN_ForIndexU(type, DN_MemDebuggerAllocType_Count)) + result.active_bytes[type] += data->bytes[type]; } } } } DN_TicketMutexEnd(&debugger->alloc_table_mutex); + + // NOTE: Snapshot the memory list registry. Read the count, allocate outside the registry lock, then + // fill under the lock so registry mutations cannot race with the copy. + DN_USize mem_list_count = 0; + DN_TicketMutexBegin(&debugger->mem_list_mutex); + mem_list_count = debugger->mem_list_table.count; + DN_TicketMutexEnd(&debugger->mem_list_mutex); + + result.mem_lists = DN_ArenaNewArrayZ(arena, DN_MemDebuggerMemListSnapshot, mem_list_count); + result.mem_lists_count = 0; + if (result.mem_lists) { + DN_TicketMutexBegin(&debugger->mem_list_mutex); + for (DN_ForItSize(it, DN_MemDebuggerMemListKV, debugger->mem_list_kvs, debugger->mem_list_table.max)) { + DN_MemDebuggerMemListKV *kv = it.data; + if (!DN_HTableHashIsValue(kv->hash)) + continue; + DN_MemDebuggerMemListSnapshot *dst = DN_PArrayMakeZ(result.mem_lists, &result.mem_lists_count, mem_list_count); + if (!dst) + break; + DN_MemList const *live = kv->key; + dst->mem_list = *live; + // NOTE: Wasted is the reserved-but-unused space of every block except the current (tail) block, + // which the bump allocator can never reclaim. Computed here while the blocks are still live. + dst->wasted = live->curr + ? (live->stats.info.reserve - live->stats.info.used) - (live->curr->reserve - live->curr->used) + : 0; + + // NOTE: Snapshot the block chain (tail → head) while the blocks are still live. + DN_USize block_count = 0; + for (DN_MemBlock const *block = live->curr; block; block = block->prev) + block_count++; + dst->blocks = DN_ArenaNewArrayZ(arena, DN_MemStats, block_count); + dst->blocks_count = 0; + for (DN_MemBlock const *block = live->curr; block; block = block->prev) { + DN_MemStats *block_stats = &dst->blocks[dst->blocks_count++]; + block_stats->info.used = block->used; + block_stats->info.commit = block->commit; + block_stats->info.reserve = block->reserve; + block_stats->info.blocks = 1; + } + + // NOTE: Snapshot the memory list's live allocations, sorted by alloc_size descending. + DN_MemDebuggerMemList *mem_list_entry = &kv->value; + DN_USize alloc_count = 0; + DN_TicketMutexBegin(&mem_list_entry->alloc_mutex); + alloc_count = mem_list_entry->allocs_count; + DN_TicketMutexEnd(&mem_list_entry->alloc_mutex); + + dst->allocs = DN_ArenaNewArrayZ(arena, DN_MemDebuggerMemListAlloc, alloc_count); + dst->allocs_count = 0; + if (dst->allocs) { + DN_TicketMutexBegin(&mem_list_entry->alloc_mutex); + for (DN_ForItSize(alloc_it, DN_MemDebuggerMemListAlloc, mem_list_entry->allocs, mem_list_entry->allocs_count)) { + DN_MemDebuggerMemListAlloc const *alloc_src = alloc_it.data; + DN_MemDebuggerMemListAlloc *dst_alloc = DN_PArrayMakeZ(dst->allocs, &dst->allocs_count, alloc_count); + if (!dst_alloc) + break; + *dst_alloc = *alloc_src; + if (debugger->flags & DN_MemDebuggerFlags_HeapAllocCallSiteStrings) { + dst_alloc->call_site.name = DN_Str8FromStr8Arena(dst_alloc->call_site.name, arena); + dst_alloc->call_site.file = DN_Str8FromStr8Arena(dst_alloc->call_site.file, arena); + dst_alloc->call_site.function = DN_Str8FromStr8Arena(dst_alloc->call_site.function, arena); + } + } + DN_TicketMutexEnd(&mem_list_entry->alloc_mutex); + DN_QSort(dst->allocs, dst->allocs_count, nullptr, DN_MemDebuggerMemListAllocQSortCompareAllocSizeGT); + } + + if (debugger->flags & DN_MemDebuggerFlags_HeapAllocCallSiteStrings) + dst->mem_list.label = DN_Str8FromStr8Arena(dst->mem_list.label, arena); + } + DN_TicketMutexEnd(&debugger->mem_list_mutex); + } + + // NOTE: Restore the arena's flags and re-sync its blocks' commit (their growth was excluded for the + // whole snapshot). + arena->mem->heap.flags = arena_flags_copy; + + DN_TicketMutexBegin(&debugger->alloc_table_mutex); + for (DN_MemBlock *block = arena->mem->curr; block; block = block->prev) + DN_MemDebuggerCommitUpdateLocked_(debugger, block); + DN_TicketMutexEnd(&debugger->alloc_table_mutex); + return result; } -bool DN_MemDebuggerSnapshotPtrDataQSortComparePtrLT(void const *lhs, void const *rhs, void*) +DN_API bool DN_MemDebuggerMemListSnapshotQSortCompareCommitGT(void const *lhs, void const *rhs, void *) +{ + DN_MemDebuggerMemListSnapshot const *lhs_it = *DN_Cast(DN_MemDebuggerMemListSnapshot const * const *) lhs; + DN_MemDebuggerMemListSnapshot const *rhs_it = *DN_Cast(DN_MemDebuggerMemListSnapshot const * const *) rhs; + bool result = lhs_it->mem_list.stats.info.commit > rhs_it->mem_list.stats.info.commit; + return result; +} + +DN_API bool DN_MemDebuggerMemListAllocQSortCompareAllocSizeGT(void const *lhs, void const *rhs, void *) +{ + DN_MemDebuggerMemListAlloc const *lhs_it = DN_Cast(DN_MemDebuggerMemListAlloc *) lhs; + DN_MemDebuggerMemListAlloc const *rhs_it = DN_Cast(DN_MemDebuggerMemListAlloc *) rhs; + bool result = lhs_it->alloc_size > rhs_it->alloc_size; + return result; +} + +DN_API bool DN_MemDebuggerSnapshotPtrDataQSortComparePtrLT(void const *lhs, void const *rhs, void*) { DN_MemDebuggerSnapshotPtrData const *lhs_it = DN_Cast(DN_MemDebuggerSnapshotPtrData *) lhs; DN_MemDebuggerSnapshotPtrData const *rhs_it = DN_Cast(DN_MemDebuggerSnapshotPtrData *) rhs; @@ -12114,22 +12653,40 @@ bool DN_MemDebuggerSnapshotPtrDataQSortComparePtrLT(void const *lhs, void const return result; } -DN_API void DN_MemDebuggerAlloc_(DN_MemDebugger *debugger, void *ptr, DN_USize size, bool leak_permitted, DN_CallSite call_site) +DN_API bool DN_MemDebuggerSnapshotPtrDataQSortCompareBytesLT(void const *lhs, void const *rhs, void *user_context) +{ + DN_MemDebuggerSnapshotPtrData const *lhs_it = *DN_Cast(DN_MemDebuggerSnapshotPtrData * const *) lhs; + DN_MemDebuggerSnapshotPtrData const *rhs_it = *DN_Cast(DN_MemDebuggerSnapshotPtrData * const *) rhs; + DN_MemDebuggerAllocType type = *DN_Cast(DN_MemDebuggerAllocType *) user_context; + bool result = lhs_it->bytes[type] < rhs_it->bytes[type]; + return result; +} + +DN_API bool DN_MemDebuggerSnapshotPtrDataQSortCompareBytesGT(void const *lhs, void const *rhs, void *user_context) +{ + DN_MemDebuggerSnapshotPtrData const *lhs_it = *DN_Cast(DN_MemDebuggerSnapshotPtrData * const *) lhs; + DN_MemDebuggerSnapshotPtrData const *rhs_it = *DN_Cast(DN_MemDebuggerSnapshotPtrData * const *) rhs; + DN_MemDebuggerAllocType type = *DN_Cast(DN_MemDebuggerAllocType *) user_context; + bool result = lhs_it->bytes[type] > rhs_it->bytes[type]; + return result; +} + +DN_API void DN_MemDebuggerAlloc_(DN_MemDebugger *debugger, void *ptr, DN_USize reserve, DN_USize commit, bool leak_permitted, DN_CallSite call_site) { if (!ptr) return; DN_TicketMutexBegin(&debugger->alloc_table_mutex); - DN_Str8 stack_trace = DN_Str8FromStackTraceNowHeap(128, 3 /*skip*/); + DN_Str8 stack_trace = DN_OS_Str8FromStackTraceNowHeap(128, 3 /*skip*/); DN_HTable* alloc_table = &debugger->alloc_table; DN_UPtr uptr = DN_Cast(DN_UPtr)ptr; DN_HTableAddResult alloc_entry = DN_HTableMake(alloc_table, &uptr); DN_MemDebuggerPtrData* alloc = DN_Cast(DN_MemDebuggerPtrData *)alloc_entry.slot.value; if (alloc_entry.existed) { if ((alloc->flags & DN_MemDebuggerPtrFlag_Freed) == 0) { - DN_Str8x32 alloc_size = DN_Str8x32FromByteCountU64Auto(alloc->size); - DN_Str8x32 new_alloc_size = DN_Str8x32FromByteCountU64Auto(size); + DN_Str8x32 alloc_size = DN_Str8x32FromByteCountU64Auto(alloc->bytes[DN_MemDebuggerAllocType_Commit]); + DN_Str8x32 new_alloc_size = DN_Str8x32FromByteCountU64Auto(commit); DN_AssertAlwaysF( alloc->flags & DN_MemDebuggerPtrFlag_Freed, "This pointer is already in the leak tracker, however it has not been freed yet. This " @@ -12155,18 +12712,40 @@ DN_API void DN_MemDebuggerAlloc_(DN_MemDebugger *debugger, void *ptr, DN_USize s debugger->alloc_table_bytes_allocated_for_stack_traces -= alloc->stack_trace.count; debugger->alloc_table_bytes_allocated_for_stack_traces -= alloc->freed_stack_trace.count; - DN_OS_MemDealloc(alloc->stack_trace.data); - DN_OS_MemDealloc(alloc->freed_stack_trace.data); + // NOTE: Strings inside the callsite are c-string literals stored in the data segment. So no deep + // copy is needed. But if you are dynamically loading and unloading libraries at runtime then + // these c-strings can become pointers to wiped memory once unloaded. The user can specify a flag + // to heap allocate these strings. + if (debugger->flags & DN_MemDebuggerFlags_HeapAllocCallSiteStrings) { + if (alloc->call_site.name.count) + DN_HeapDealloc(&debugger->heap, alloc->call_site.name.data, alloc->call_site.name.count + 1); + if (alloc->call_site.file.count) + DN_HeapDealloc(&debugger->heap, alloc->call_site.file.data, alloc->call_site.file.count + 1); + if (alloc->call_site.function.count) + DN_HeapDealloc(&debugger->heap, alloc->call_site.function.data, alloc->call_site.function.count + 1); + } + + if (alloc->stack_trace.count) + DN_HeapDealloc(&debugger->heap, alloc->stack_trace.data, alloc->stack_trace.count + 1); + if (alloc->freed_stack_trace.count) + DN_HeapDealloc(&debugger->heap, alloc->freed_stack_trace.data, alloc->freed_stack_trace.count + 1); *alloc = {}; } - alloc->ptr = ptr; - alloc->size = size; - alloc->stack_trace = stack_trace; - // NOTE: Strings inside the callsite are c-string literals stored in the data segment. So no deep - // copy is needed. - // TODO: Except, if we do DLL reloading, that's going to unload the string. - alloc->call_site = call_site; + alloc->ptr = ptr; + alloc->bytes[DN_MemDebuggerAllocType_Reserve] = reserve; + alloc->bytes[DN_MemDebuggerAllocType_Commit] = commit; + alloc->stack_trace = stack_trace; + + alloc->call_site = call_site; + + if (debugger->flags & DN_MemDebuggerFlags_HeapAllocCallSiteStrings) { + DN_Allocator heap_allocator = DN_AllocatorFromHeap(&debugger->heap); + alloc->call_site.name = DN_Str8FromStr8Allocator(alloc->call_site.name, heap_allocator); + alloc->call_site.file = DN_Str8FromStr8Allocator(alloc->call_site.file, heap_allocator); + alloc->call_site.function = DN_Str8FromStr8Allocator(alloc->call_site.function, heap_allocator); + } + alloc->flags |= leak_permitted ? DN_MemDebuggerPtrFlag_LeakPermitted : 0; debugger->alloc_table_bytes_allocated_for_stack_traces += alloc->stack_trace.count; DN_TicketMutexEnd(&debugger->alloc_table_mutex); @@ -12179,7 +12758,7 @@ DN_API void DN_MemDebuggerDealloc_(DN_MemDebugger *debugger, void *ptr) DN_TicketMutexBegin(&debugger->alloc_table_mutex); - DN_Str8 stack_trace = DN_Str8FromStackTraceNowHeap(128, 3 /*skip*/); + DN_Str8 stack_trace = DN_OS_Str8FromStackTraceNowHeap(128, 3 /*skip*/); DN_HTable* alloc_table = &debugger->alloc_table; DN_UPtr uptr = DN_Cast(DN_UPtr)ptr; DN_MemDebuggerPtrData* alloc = DN_Cast(DN_MemDebuggerPtrData *)DN_HTableValueFromFind(alloc_table, &uptr); @@ -12190,7 +12769,7 @@ DN_API void DN_MemDebuggerDealloc_(DN_MemDebugger *debugger, void *ptr) ptr); if (alloc->flags & DN_MemDebuggerPtrFlag_Freed) { - DN_Str8x32 freed_size = DN_Str8x32FromByteCountU64Auto(alloc->freed_size); + DN_Str8x32 freed_size = DN_Str8x32FromByteCountU64Auto(alloc->freed_bytes[DN_MemDebuggerAllocType_Commit]); DN_AssertAlwaysF((alloc->flags & DN_MemDebuggerPtrFlag_Freed) == 0, "Double free detected, pointer to free was already marked " "as freed. Either the pointer was reallocated but not " @@ -12216,6 +12795,8 @@ DN_API void DN_MemDebuggerDealloc_(DN_MemDebugger *debugger, void *ptr) DN_Assert(alloc->freed_stack_trace.count == 0); alloc->flags |= DN_MemDebuggerPtrFlag_Freed; + for (DN_ForIndexU(type, DN_MemDebuggerAllocType_Count)) + alloc->freed_bytes[type] = alloc->bytes[type]; alloc->freed_stack_trace = stack_trace; debugger->alloc_table_bytes_allocated_for_stack_traces += alloc->freed_stack_trace.count; DN_TicketMutexEnd(&debugger->alloc_table_mutex); @@ -12234,14 +12815,16 @@ DN_API void DN_MemDebuggerDump_(DN_MemDebugger *debugger) bool alloc_leaked = (alloc->flags & DN_MemDebuggerPtrFlag_Freed) == 0; bool leak_permitted = (alloc->flags & DN_MemDebuggerPtrFlag_LeakPermitted); if (alloc_leaked && !leak_permitted) { - leaked_bytes += alloc->size; + leaked_bytes += alloc->bytes[DN_MemDebuggerAllocType_Reserve]; leak_count++; - DN_Str8x32 alloc_size = DN_Str8x32FromByteCountU64Auto(alloc->size); + DN_Str8x32 reserve_size = DN_Str8x32FromByteCountU64Auto(alloc->bytes[DN_MemDebuggerAllocType_Reserve]); + DN_Str8x32 commit_size = DN_Str8x32FromByteCountU64Auto(alloc->bytes[DN_MemDebuggerAllocType_Commit]); DN_LogWarningF( - "Pointer (0x%p) leaked %.*s at:\n" + "Pointer (0x%p) leaked %.*s (commit: %.*s) at:\n" "%.*s", alloc->ptr, - DN_Str8PrintFmt(alloc_size), + DN_Str8PrintFmt(reserve_size), + DN_Str8PrintFmt(commit_size), DN_Str8PrintFmt(alloc->stack_trace)); } } @@ -12258,6 +12841,19 @@ DN_API void DN_MemDebuggerDump_(DN_MemDebugger *debugger) #include // getpagesize #endif +DN_API DN_Str8 DN_OS_Str8FromStackTraceNowHeap(DN_U16 limit, DN_U16 skip) +{ + DN_Heap heap = DN_OS_HeapInitBasic(); + heap.flags |= DN_HeapFlags_ExcludeFromMemDebugger; + DN_Arena arena = DN_ArenaFromHeap(DN_Kilobytes(64), DN_Kilobytes(64), DN_MemFlags_Nil, heap, "DN Stack Trace Arena"); + DN_Str8Builder builder = DN_Str8BuilderFromArena(&arena); + DN_StackTrace walk = DN_StackTraceFromArena(&arena, limit); + DN_StackTraceAddToStr8Builder_(&walk, &builder, skip); + DN_Str8 result = DN_OS_Str8FromStr8BuilderHeap(&builder); + DN_ArenaDeinit(&arena); + return result; +} + DN_API DN_Str8 DN_OS_Str8FromStr8BuilderHeap(DN_Str8Builder const *builder) { DN_Str8 result = DN_ZeroInit; @@ -12304,7 +12900,7 @@ static void DN_OS_LoggerSetFilePathNoMutex_(DN_OSLogger *logger, DN_Pool *pool, logger->file_path = {}; } DN_OS_FileClose(&logger->file); - logger->file_path = DN_Str8FmtOsPathPool(pool, "%.*s", DN_Str8PrintFmt(file_path)); + logger->file_path = DN_Str8PathFmtOsPool(pool, "%.*s", DN_Str8PrintFmt(file_path)).value; // NOTE: Clear the sticky file error flag if it was set logger->flags &= ~DN_OSLoggerFlags_FileError; @@ -12327,7 +12923,7 @@ static void DN_OS_DoLogFileSetupAndRotation_(DN_OSLogger *logger) // NOTE: Set a default file path to log to if it's not been set yet if (logger->file_path.count == 0) { DN_Str8 exe_dir = DN_OS_ExeDir(&scratch.arena); - DN_Str8 default_file_path = DN_Str8FmtOsPathArena(&scratch.arena, "%.*s/dn.log", DN_Str8PrintFmt(exe_dir)); + DN_Str8 default_file_path = DN_Str8PathFmtOsArena(&scratch.arena, "%.*s/dn.log", DN_Str8PrintFmt(exe_dir)).value; DN_OS_LoggerSetFilePathNoMutex_(logger, DN_TcMainPool(), default_file_path); } @@ -12563,7 +13159,7 @@ DN_API DN_Str8 DN_OS_ExeDir(DN_Arena *arena) return result; } -DN_API void DN_OS_OpenUrl(DN_Str8 url) +DN_API void DN_OS_OpenInDefaultApp(DN_Str8 url) { #if defined(DN_PLATFORM_WIN32) DN_TcScratch scratch = DN_TcScratchBeginArena(nullptr, 0); @@ -12576,6 +13172,16 @@ DN_API void DN_OS_OpenUrl(DN_Str8 url) #endif } +DN_API bool DN_OS_OnceEveryS(DN_U64 *tsc, DN_U64 interval_s) +{ + DN_U64 now = DN_OS_PerfCounterNow(); + DN_F64 delta_s = DN_OS_PerfCounterS(*tsc, now); + bool result = *tsc == 0 || delta_s >= DN_Cast(DN_F64)interval_s; + if (result) + *tsc = now; + return result; +} + // NOTE: Counters DN_API DN_F64 DN_OS_PerfCounterS(uint64_t begin, uint64_t end) { @@ -12645,19 +13251,19 @@ DN_API DN_F64 DN_OS_TimerNs(DN_OSTimer timer) return result; } -DN_API uint64_t DN_OS_EstimateTscPerSecond(uint64_t duration_ms_to_gauge_tsc_frequency) +DN_API DN_U64 DN_OS_EstimateTscPerSecond(DN_U64 duration_ms_to_gauge_tsc_frequency) { - uint64_t os_frequency = DN_OS_PerfCounterFrequency(); - uint64_t os_target_elapsed = duration_ms_to_gauge_tsc_frequency * os_frequency / 1000ULL; - uint64_t tsc_begin = DN_CPUGetTsc(); - uint64_t result = 0; + DN_U64 os_frequency = DN_OS_PerfCounterFrequency(); + DN_U64 os_target_elapsed = duration_ms_to_gauge_tsc_frequency * os_frequency / 1000ULL; + DN_U64 tsc_begin = DN_CpuTscNow(); + DN_U64 result = 0; if (tsc_begin) { - uint64_t os_elapsed = 0; + DN_U64 os_elapsed = 0; for (uint64_t os_begin = DN_OS_PerfCounterNow(); os_elapsed < os_target_elapsed;) os_elapsed = DN_OS_PerfCounterNow() - os_begin; - uint64_t tsc_end = DN_CPUGetTsc(); - uint64_t tsc_elapsed = tsc_end - tsc_begin; - result = tsc_elapsed / os_elapsed * os_frequency; + DN_U64 tsc_end = DN_CpuTscNow(); + DN_U64 tsc_elapsed = tsc_end - tsc_begin; + result = tsc_elapsed / os_elapsed * os_frequency; } return result; } @@ -12762,16 +13368,27 @@ DN_API DN_Str8 DN_OS_FileReadAll(DN_Allocator allocator, DN_Str8 path, DN_ErrSin } // NOTE: Allocate - DN_Arena temp_arena = {}; - if (allocator.type == DN_AllocatorType_Arena) { - DN_Arena *arena = DN_Cast(DN_Arena *) allocator.context; - temp_arena = DN_ArenaTempBeginFromArena(arena); - result = DN_Str8AllocArena(path_info.size, DN_ZMem_No, &temp_arena); - } else { - DN_Pool *pool = DN_Cast(DN_Pool *) allocator.context; - result = DN_Str8AllocPool(path_info.size, pool); + DN_Arena temp_arena = {}; + DN_MemListTemp temp_mem_list = {}; + DN_Allocator sub_allocator = {}; + switch (allocator.type) { + case DN_AllocatorType_Arena: { + temp_arena = DN_ArenaTempBeginFromArena(DN_Cast(DN_Arena *)allocator.context); + sub_allocator = DN_AllocatorFromArena(&temp_arena); + } break; + + case DN_AllocatorType_MemList: { + temp_mem_list = DN_MemListTempBegin(DN_Cast(DN_MemList *)allocator.context); + sub_allocator = DN_AllocatorFromMemList(temp_mem_list.mem); + } break; + + case DN_AllocatorType_Heap: /*FALLTHRU*/ + case DN_AllocatorType_Pool: { + sub_allocator = allocator; + } break; } + result = DN_Str8AllocAllocator(path_info.size, DN_ZMem_No, sub_allocator); if (!result.data) { DN_Str8x32 bytes_str = DN_Str8x32FromByteCountU64Auto(path_info.size); DN_ErrSinkAppendF(err, 1 /*err_code*/, "Failed to allocate %.*s for reading file '%.*s'", DN_Str8PrintFmt(bytes_str), DN_Str8PrintFmt(path)); @@ -12783,13 +13400,21 @@ DN_API DN_Str8 DN_OS_FileReadAll(DN_Allocator allocator, DN_Str8 path, DN_ErrSin DN_OSFileRead read = DN_OS_FileRead(&file, result.data, result.count, err); bool failed = file.error || !read.success; - if (allocator.type == DN_AllocatorType_Arena) { - DN_ArenaTempEnd(&temp_arena, failed ? DN_ArenaReset_Yes : DN_ArenaReset_No); - } else { - if (failed) { - DN_Pool *pool = DN_Cast(DN_Pool *) allocator.context; - DN_PoolDealloc(pool, result.data); - } + switch (allocator.type) { + case DN_AllocatorType_Arena: { + DN_ArenaTempEnd(&temp_arena, failed ? DN_ArenaReset_Yes : DN_ArenaReset_No); + } break; + + case DN_AllocatorType_MemList: { + if (failed) + DN_MemListTempEnd(temp_mem_list); + } break; + + case DN_AllocatorType_Heap: /*FALLTHRU*/ + case DN_AllocatorType_Pool: { + if (failed) + DN_AllocatorDealloc(sub_allocator, result.data, result.count + 1); + } break; } if (failed) @@ -12801,18 +13426,14 @@ DN_API DN_Str8 DN_OS_FileReadAll(DN_Allocator allocator, DN_Str8 path, DN_ErrSin DN_API DN_Str8 DN_OS_FileReadAllArena(DN_Arena *arena, DN_Str8 path, DN_ErrSink *err) { - DN_Allocator allocator = {}; - allocator.type = DN_AllocatorType_Arena; - allocator.context = arena; + DN_Allocator allocator = DN_AllocatorFromArena(arena); DN_Str8 result = DN_OS_FileReadAll(allocator, path, err); return result; } DN_API DN_Str8 DN_OS_FileReadAllPool(DN_Pool *pool, DN_Str8 path, DN_ErrSink *err) { - DN_Allocator allocator = {}; - allocator.type = DN_AllocatorType_Pool; - allocator.context = pool; + DN_Allocator allocator = DN_AllocatorFromPool(pool); DN_Str8 result = DN_OS_FileReadAll(allocator, path, err); return result; } @@ -12899,6 +13520,66 @@ DN_API bool DN_OS_PathIsOlderThan(DN_Str8 path, DN_Str8 check_against) return result; } +DN_API DN_OSPathResult DN_OS_PathRelativeTo(DN_Arena *arena, DN_Str8 from, DN_Str8 to) +{ + DN_OSPathResult result = {}; +#if defined(DN_OS_WIN32) + DN_TcScratch scratch = DN_TcScratchBeginArena(&arena, 1); + DN_Str16 from16 = DN_OS_W32Str8ToStr16(&scratch.arena, from); + DN_Str16 to16 = DN_OS_W32Str8ToStr16(&scratch.arena, to); + + DN_OSPathInfo from_info = DN_OS_PathInfo(from); + DN_OSPathInfo to_info = DN_OS_PathInfo(to); + DWORD from_attribute = from_info.type == DN_OSPathInfoType_Directory ? FILE_ATTRIBUTE_DIRECTORY : 0; + DWORD to_attribute = to_info.type == DN_OSPathInfoType_Directory ? FILE_ATTRIBUTE_DIRECTORY : 0; + + wchar_t relative_path[1024]; + relative_path[0] = 0; + + result.success = PathRelativePathToW(relative_path, from16.data, from_attribute, to16.data, to_attribute); + if (result.success) + result.path = DN_OS_W32Str16ToStr8(arena, DN_Str16FromPtr(relative_path, DN_CStr16Count(relative_path))); + DN_TcScratchEnd(&scratch); +#else + DN_AssertInvalidCodePathF("Unimplemented"); +#endif + return result; +} + +DN_API bool DN_OS_PathIsRelative(DN_Str8 path) +{ + bool result = false; +#if defined(DN_OS_WIN32) + DN_TcScratch scratch = DN_TcScratchBeginArena(nullptr, 0); + DN_Str16 path16 = DN_OS_W32Str8ToStr16(&scratch.arena, path); + result = PathIsRelativeW(path16.data); + DN_TcScratchEnd(&scratch); +#else + DN_AssertInvalidCodePathF("Unimplemented"); +#endif + return result; +} + +DN_API bool DN_OS_PathWatchFileHasChanged(DN_OSPathWatchFile *watch, DN_Str8 path, DN_OSPathWatchFileAcceptChange accept) +{ + DN_OSPathInfo info = DN_OS_PathInfo(path); + bool write_dirtied = watch->prev.last_write_time_in_s != info.last_write_time_in_s; + bool size_dirtied = watch->prev.size != info.size; + bool result = write_dirtied || size_dirtied; + if (result) { + if (accept == DN_OSPathWatchFileAcceptChange_Yes) + watch->prev = info; + else + watch->candidate = info; + } + return result; +} + +DN_API void DN_OS_PathWatchFileAcceptChange(DN_OSPathWatchFile *watch) +{ + watch->prev = watch->candidate; +} + DN_API DN_OSExecArgs DN_OS_ExecArgsDefault() { DN_OSExecArgs result = {}; @@ -12995,6 +13676,7 @@ DN_API void DN_OS_WindowCustomTitlebarSet(DN_OSWindow *window, bool custom_title DwmExtendFrameIntoClientArea(w32_window->hwnd, &margins); } } + #elif defined(DN_PLATFORM_EMSCRIPTEN) #else DN_AssertInvalidCodePath; #endif @@ -13539,249 +14221,6 @@ DN_API void DN_OS_PrintLnFVStyle(DN_OSPrintDest dest, DN_LogStyle style, DN_FMT_ DN_OS_Print(dest, DN_Str8Lit("\n")); } -DN_API DN_StackTrace DN_StackTraceFromAllocator(DN_Allocator allocator, DN_U16 limit) -{ - DN_StackTrace result = {}; -#if defined(DN_OS_WIN32) - if (!allocator.context) - return result; - - static DN_TicketMutex mutex = {}; - DN_TicketMutexBegin(&mutex); - - HANDLE thread = GetCurrentThread(); - result.process = GetCurrentProcess(); - - DN_OSW32Core *w32 = DN_OS_W32GetCore(); - if (!w32->sym_initialised) { - w32->sym_initialised = true; - SymSetOptions(SYMOPT_LOAD_LINES); - if (!SymInitialize(result.process, nullptr /*UserSearchPath*/, true /*fInvadeProcess*/)) { - DN_TcScratch scratch = DN_TcScratchBeginAllocator(&allocator, 1); - DN_OSW32Error error = DN_OS_W32LastError(&scratch.arena); - DN_LogErrorF("SymInitialize failed, stack trace can not be generated (%lu): %.*s\n", error.code, DN_Str8PrintFmt(error.msg)); - DN_TcScratchEnd(&scratch); - } - } - - CONTEXT context; - RtlCaptureContext(&context); - - STACKFRAME64 frame = {}; - frame.AddrPC.Offset = context.Rip; - frame.AddrPC.Mode = AddrModeFlat; - frame.AddrFrame.Offset = context.Rbp; - frame.AddrFrame.Mode = AddrModeFlat; - frame.AddrStack.Offset = context.Rsp; - frame.AddrStack.Mode = AddrModeFlat; - - DN_U64 raw_frames[256] = {}; - DN_USize raw_frames_count = 0; - while (raw_frames_count < limit) { - if (!StackWalk64(IMAGE_FILE_MACHINE_AMD64, - result.process, - thread, - &frame, - &context, - nullptr /*ReadMemoryRoutine*/, - SymFunctionTableAccess64, - SymGetModuleBase64, - nullptr /*TranslateAddress*/)) - break; - - // NOTE: It might be useful one day to use frame.AddrReturn.Offset. - // If AddrPC.Offset == AddrReturn.Offset then we can detect recursion. - DN_LArrayAppend(raw_frames, &raw_frames_count, frame.AddrPC.Offset); - } - DN_TicketMutexEnd(&mutex); - - result.base_addr = DN_Cast(DN_U64 *)DN_AllocatorAlloc(allocator, raw_frames_count * sizeof(DN_U64), alignof(DN_U64), DN_ZMem_No); - DN_Assert(result.base_addr); - - result.size = DN_Cast(DN_U16) raw_frames_count; - DN_Memcpy(result.base_addr, raw_frames, raw_frames_count * sizeof(raw_frames[0])); -#else - (void)limit; - (void)allocator; -#endif - return result; -} - - -DN_API DN_StackTrace DN_StackTraceFromArena(DN_Arena *arena, DN_U16 limit) -{ - DN_Allocator allocator = DN_AllocatorFromArena(arena); - DN_StackTrace result = DN_StackTraceFromAllocator(allocator, limit); - return result; -} - -static void DN_StackTraceAddToStr8Builder_(DN_StackTrace const *trace, DN_Str8Builder *builder, DN_USize skip) -{ - DN_StackTraceRawFrame raw_frame = {}; - raw_frame.process = trace->process; - for (DN_USize index = skip; index < trace->size; index++) { - raw_frame.base_addr = trace->base_addr[index]; - DN_StackTraceFrame frame = DN_StackTraceRawFrameToFrame(builder->arena, raw_frame); - DN_Str8BuilderAppendF(builder, "%.*s(%zu): %.*s%s", DN_Str8PrintFmt(frame.file_name), frame.line_number, DN_Str8PrintFmt(frame.function_name), (DN_Cast(int) index == trace->size - 1) ? "" : "\n"); - } -} - -DN_API bool DN_StackTraceIterate(DN_StackTraceIterator *it, DN_StackTrace const *trace) -{ - bool result = false; - if (!it || !trace || !trace->base_addr || !trace->process) - return result; - - if (it->index >= trace->size) - return false; - - result = true; - it->raw_frame.process = trace->process; - it->raw_frame.base_addr = trace->base_addr[it->index++]; - return result; -} - -DN_API DN_Str8 DN_Str8FromStackTraceAllocator(DN_Allocator allocator, DN_StackTrace const *trace, DN_U16 skip) -{ - DN_Str8 result = {}; - if (!trace) - return result; - - DN_TcScratch scratch = DN_TcScratchBeginAllocator(&allocator, 1); - DN_Str8Builder builder = DN_Str8BuilderFromArena(&scratch.arena); - DN_StackTraceAddToStr8Builder_(trace, &builder, skip); - result = DN_Str8FromStr8BuilderAllocator(&builder, allocator); - DN_TcScratchEnd(&scratch); - return result; -} - -DN_API DN_Str8 DN_Str8FromStackTraceArena(DN_Arena *arena, DN_StackTrace const *trace, DN_U16 skip) -{ - DN_Str8 result = {}; - if (!trace || !arena) - return result; - - DN_TcScratch scratch = DN_TcScratchBeginArena(&arena, 1); - DN_Str8Builder builder = DN_Str8BuilderFromArena(&scratch.arena); - DN_StackTraceAddToStr8Builder_(trace, &builder, skip); - result = DN_Str8FromStr8BuilderArena(&builder, arena); - DN_TcScratchEnd(&scratch); - return result; -} - -DN_API DN_Str8 DN_Str8FromStackTraceNowAllocator(DN_Allocator allocator, DN_U16 limit, DN_U16 skip) -{ - DN_TcScratch scratch = DN_TcScratchBeginArena(DN_Cast(DN_Arena **) & allocator.context, 1); - DN_StackTrace walk = DN_StackTraceFromArena(&scratch.arena, limit); - DN_Str8 result = DN_Str8FromStackTraceAllocator(allocator, &walk, skip); - DN_TcScratchEnd(&scratch); - return result; -} - -DN_API DN_Str8 DN_Str8FromStackTraceNowArena(DN_Arena *arena, DN_U16 limit, DN_U16 skip) -{ - DN_Str8 result = DN_Str8FromStackTraceNowAllocator(DN_AllocatorFromArena(arena), limit, skip); - return result; -} - -DN_API DN_Str8 DN_Str8FromStackTraceNowHeap(DN_U16 limit, DN_U16 skip) -{ - DN_Heap heap = DN_OS_HeapInitBasic(); - heap.flags |= DN_HeapFlags_ExcludeFromMemDebugger; - DN_Arena arena = DN_ArenaFromHeap(DN_Kilobytes(64), DN_Kilobytes(64), DN_MemFlags_Nil, heap, "DN Stack Trace Arena"); - DN_Str8Builder builder = DN_Str8BuilderFromArena(&arena); - DN_StackTrace walk = DN_StackTraceFromArena(&arena, limit); - DN_StackTraceAddToStr8Builder_(&walk, &builder, skip); - DN_Str8 result = DN_OS_Str8FromStr8BuilderHeap(&builder); - DN_ArenaDeinit(&arena); - return result; -} - -DN_API DN_StackTraceFrameSlice DN_StackTraceGetFrames(DN_Arena *arena, DN_U16 limit) -{ - DN_StackTraceFrameSlice result = {}; - if (!arena) - return result; - - DN_TcScratch scratch = DN_TcScratchBeginArena(&arena, 1); - DN_StackTrace walk = DN_StackTraceFromArena(&scratch.arena, limit); - if (walk.size) { - if (DN_ISliceAllocArena(&result, walk.size, DN_ZMem_No, arena)) { - DN_USize slice_index = 0; - for (DN_StackTraceIterator it = {}; DN_StackTraceIterate(&it, &walk);) - result.data[slice_index++] = DN_StackTraceRawFrameToFrame(arena, it.raw_frame); - } - } - DN_TcScratchEnd(&scratch); - return result; -} - -DN_API DN_StackTraceFrame DN_StackTraceRawFrameToFrame(DN_Arena *arena, DN_StackTraceRawFrame raw_frame) -{ -#if defined(DN_OS_WIN32) - // NOTE: Get line+filename - - // TODO: Why does zero-initialising this with `line = {};` cause - // SymGetLineFromAddr64 function to fail once we are at - // __scrt_commain_main_seh and hit BaseThreadInitThunk frame? The - // line and file number are still valid in the result which we use, so, - // we silently ignore this error. - IMAGEHLP_LINEW64 line; - line.SizeOfStruct = sizeof(line); - DWORD line_displacement = 0; - if (!SymGetLineFromAddrW64(raw_frame.process, raw_frame.base_addr, &line_displacement, &line)) - line = {}; - - // NOTE: Get function name - - alignas(SYMBOL_INFOW) char buffer[sizeof(SYMBOL_INFOW) + (MAX_SYM_NAME * sizeof(wchar_t))] = {}; - SYMBOL_INFOW *symbol = DN_Cast(SYMBOL_INFOW *) buffer; - symbol->SizeOfStruct = sizeof(*symbol); - symbol->MaxNameLen = sizeof(buffer) - sizeof(*symbol); - - uint64_t symbol_displacement = 0; // Offset to the beginning of the symbol to the address - SymFromAddrW(raw_frame.process, raw_frame.base_addr, &symbol_displacement, symbol); - - // NOTE: Construct result - - DN_Str16 file_name16 = DN_Str16FromPtr(line.FileName, DN_CStr16Count(line.FileName)); - DN_Str16 function_name16 = DN_Str16FromPtr(symbol->Name, symbol->NameLen); - - DN_StackTraceFrame result = {}; - result.address = raw_frame.base_addr; - result.line_number = line.LineNumber; - result.file_name = DN_OS_W32Str16ToStr8(arena, file_name16); - result.function_name = DN_OS_W32Str16ToStr8(arena, function_name16); - - if (result.function_name.count == 0) - result.function_name = DN_Str8Lit(""); - if (result.file_name.count == 0) - result.file_name = DN_Str8Lit(""); -#else - DN_StackTraceFrame result = {}; -#endif - return result; -} - -DN_API void DN_StackTracePrint(DN_U16 limit) -{ - DN_TcScratch scratch = DN_TcScratchBeginArena(nullptr, 0); - DN_StackTraceFrameSlice stack_trace = DN_StackTraceGetFrames(&scratch.arena, limit); - for (DN_ForItSize(it, DN_StackTraceFrame, stack_trace.data, stack_trace.count)) { - DN_StackTraceFrame frame = *it.data; - DN_OS_PrintErrLnF("%.*s(%I64u): %.*s", DN_Str8PrintFmt(frame.file_name), frame.line_number, DN_Str8PrintFmt(frame.function_name)); - } - DN_TcScratchEnd(&scratch); -} - -DN_API void DN_StackTraceReloadSymbols() -{ -#if defined(DN_OS_WIN32) - HANDLE process = GetCurrentProcess(); - SymRefreshModuleList(process); -#endif -} - #if defined(DN_PLATFORM_POSIX) || defined(DN_PLATFORM_EMSCRIPTEN) #include "OS/dn_os_posix.cpp" #elif defined(DN_PLATFORM_WIN32) @@ -13791,20 +14230,19 @@ DN_API void DN_StackTraceReloadSymbols() #endif #endif // DN_WITH_OS -#if DN_WITH_NET DN_Str8 DN_NET_Str8FromResponseState(DN_NETResponseState state) { DN_Str8 result = {}; switch (state) { - case DN_NETResponseState_Nil: result = DN_Str8Lit("Nil"); break; - case DN_NETResponseState_Error: result = DN_Str8Lit("Error"); break; - case DN_NETResponseState_HTTP: result = DN_Str8Lit("HTTP"); break; - case DN_NETResponseState_WSOpen: result = DN_Str8Lit("WS Open"); break; - case DN_NETResponseState_WSText: result = DN_Str8Lit("WS Text"); break; - case DN_NETResponseState_WSBinary: result = DN_Str8Lit("WS Binary"); break; - case DN_NETResponseState_WSClose: result = DN_Str8Lit("WS Close"); break; - case DN_NETResponseState_WSPing: result = DN_Str8Lit("WS Ping"); break; - case DN_NETResponseState_WSPong: result = DN_Str8Lit("WS Pong"); break; + case DN_NETResponseState_Nil: result = DN_Str8Lit("Nil"); break; + case DN_NETResponseState_Error: result = DN_Str8Lit("Error"); break; + case DN_NETResponseState_HTTP: result = DN_Str8Lit("HTTP"); break; + case DN_NETResponseState_WSOpen: result = DN_Str8Lit("WS Open"); break; + case DN_NETResponseState_WSText: result = DN_Str8Lit("WS Text"); break; + case DN_NETResponseState_WSBinary: result = DN_Str8Lit("WS Binary"); break; + case DN_NETResponseState_WSClose: result = DN_Str8Lit("WS Close"); break; + case DN_NETResponseState_WSPing: result = DN_Str8Lit("WS Ping"); break; + case DN_NETResponseState_WSPong: result = DN_Str8Lit("WS Pong"); break; } return result; } @@ -13828,6 +14266,12 @@ DN_NETRequestHandle DN_NET_HandleFromRequest(DN_NETRequest *request) return result; } +bool DN_NET_HandleEq(DN_NETRequestHandle lhs, DN_NETRequestHandle rhs) +{ + bool result = lhs.gen == rhs.gen && lhs.handle == rhs.handle; + return result; +} + bool DN_NET_ResponseHasFailed(DN_NETResponse const* resp) { bool result = false; @@ -13872,12 +14316,13 @@ DN_Str8 DN_NET_Str8DiagnosticFromResponse(DN_NETResponse const* resp, DN_Arena * return result; } +#if DN_WITH_NET void DN_NET_BaseInit(DN_NETCore *net, char *base, DN_U64 base_size) { net->base = base; net->base_size = base_size; net->mem = DN_MemListFromBuffer(net->base, net->base_size, DN_MemFlags_Nil); - net->arena = DN_ArenaFromMemList(&net->mem); + net->arena = DN_ArenaFromMemList(net->mem); net->completion_sem = DN_OS_SemaphoreInit(0); } @@ -13886,7 +14331,7 @@ DN_NETRequestHandle DN_NET_SetupRequest(DN_NETRequest *request, DN_Str8 url, DN_ // NOTE: Setup request DN_Assert(request); if (request) { - if (request->mem.curr) + if (request->mem && request->mem->curr) DN_AssertF(request->arena.mem == nullptr, "DN_NET_RequestRecycle should be called on the request before putting it into the " "free-list and reusing it. This is so that we centralise the one place that we " @@ -13894,7 +14339,7 @@ DN_NETRequestHandle DN_NET_SetupRequest(DN_NETRequest *request, DN_Str8 url, DN_ else request->mem = DN_MemListFromHeap(DN_Megabytes(1), DN_Kilobytes(1), DN_MemFlags_Nil, DN_OS_HeapInitVirtual(), "DN NET Request MemList"); - request->arena = DN_ArenaTempBeginFromMemList(&request->mem); + request->arena = DN_ArenaTempBeginFromMemList(request->mem); request->type = type; request->gen = DN_Max(request->gen + 1, 1); request->url = DN_Str8FromStr8Arena(url, &request->arena); @@ -13934,7 +14379,7 @@ void DN_NET_RequestRecycle(DN_NETRequest *request) resetter.start_response_arena = request->start_response_arena; resetter.gen = request->gen + 1; DN_Memcpy(resetter.context, request->context, sizeof(resetter.context)); - *request = resetter; + *request = resetter; // NOTE: Deallocate the memory used in the request. Note we have to end the start response arena // first to satisfy the UAF checker which requires that the temporary memory arenas are ended in @@ -14019,9 +14464,12 @@ static void DN_NET_CurlMarkRequestDone_(DN_NETCore *net, DN_NETRequest *request) DN_DoublyLLAppend(curl->response_list, request); curl->response_count++; + + // NOTE: Signal the global completion semaphore (net->completion_sem) and the per-request + // completion semaphore (request->completion_sem). + DN_OS_SemaphoreIncrement(&net->completion_sem, 1); + DN_OS_SemaphoreIncrement(&request->completion_sem, 1); } - DN_OS_SemaphoreIncrement(&net->completion_sem, 1); - DN_OS_SemaphoreIncrement(&request->completion_sem, 1); } static DN_USize DN_NET_CurlHTTPCallback_(char *payload, DN_USize size, DN_USize count, void *user_data) @@ -14414,11 +14862,11 @@ static DN_NETRequestHandle DN_NET_CurlDoRequest_(DN_NETCore *net, DN_Str8 url, D } if (req) { - DN_AssertF(req->mem.curr->used == DN_ARENA_HEADER_SIZE, + DN_AssertF(req->mem->curr->used == DN_ARENA_HEADER_SIZE, "A reused request from the free-list should have its memory reset essentially to " "zero. If this isn't the case then we're leaking memory and have forgotten to " "reset the arena before putting the request back into the free list. Request has " - "used %s.", DN_Str8x32FromByteCountU64Auto(req->mem.curr->used).data); + "used %s.", DN_Str8x32FromByteCountU64Auto(req->mem->curr->used).data); } else{ // NOTE: None in the free list so allocate one DN_OS_MutexLock(&curl_core->list_mutex); diff --git a/Source/dn.h b/Source/dn.h index f709480..fd17ad3 100644 --- a/Source/dn.h +++ b/Source/dn.h @@ -113,15 +113,6 @@ // translation unit and will automatically disable the in-built replacement header in which case // this does not need to be defined. -// Freestanding -// TODO: This is not really supported or dealt with properly. Re-review it -// The base layer can be used without an OS implementation by defining DN_FREESTANDING like: -// -// #define DN_FREESTANDING -// -// This means functionality that relies on the OS like printing, memory allocation, stack traces -// and so forth are disabled. - // ASAN Arena Poisoning // When compiled with address sanitizer (.e.g -fsanitize=address) you can optionally enable // memory region poisoning on the inbuilt arena's to catch in certain scenarios, use-after-free @@ -300,14 +291,14 @@ #define DN_GCC_WARNING_POP #endif -// NOTE: Host OS identification +// NOTE: Host OS identification (the OS we're running on) #if defined(_WIN32) #define DN_OS_WIN32 #elif defined(__gnu_linux__) || defined(__linux__) #define DN_OS_UNIX #endif -// NOTE: Platform identification +// NOTE: Platform identification (the OS we're targeting) #if !defined(DN_PLATFORM_EMSCRIPTEN) && \ !defined(DN_PLATFORM_POSIX) && \ !defined(DN_PLATFORM_ARM64) && \ @@ -512,7 +503,7 @@ #define DN_AssertAlwaysCallSiteF(expr, call_site, fmt, ...) \ do { \ if (!(expr)) { \ - DN_Str8 trace_ = DN_Str8FromStackTraceNowHeap(128 /*limit*/, 3 /*skip*/); \ + DN_Str8 trace_ = DN_OS_Str8FromStackTraceNowHeap(128 /*limit*/, 3 /*skip*/); \ DN_LogTypeParam log_type_ = DN_LogTypeParamFromType(DN_LogType_Error); \ DN_LogPrintF(log_type_, call_site, DN_LogFlags_Nil, "Assertion triggered [" #expr "]. " fmt "\nTrace:\n%.*s", ## __VA_ARGS__, DN_Str8PrintFmt(trace_)); \ DN_DebugBreak; \ @@ -537,12 +528,15 @@ #define DN_Verify(expr) DN_VerifyF(expr, 0) #define DN_VerifyWarning(expr) DN_VerifyWarningF(expr, 0) +// NOTE: Static checks (validate expressions at compile time using pre-processor tricks) #define DN_StaticAssert(expr) \ DN_GCC_WARNING_PUSH \ DN_GCC_WARNING_DISABLE(-Wunused-local-typedefs) \ typedef char DN_TokenCombine(static_assert_dummy__, __LINE__)[(expr) ? 1 : -1]; \ DN_GCC_WARNING_POP +#define DN_StaticTypeEq(lhs, rhs) (void)(1 ? lhs : rhs) + #if defined(__aarch64__) || defined(_M_X64) || defined(__x86_64__) || defined(__x86_64) #define DN_64_BIT #else @@ -735,7 +729,7 @@ typedef DN_I32 DN_B32; #define DN_CountLeadingZerosU64(value) __lzcnt64(value) #define DN_CountLeadingZerosU32(value) __lzcnt(value) - #define DN_CPUGetTsc() __rdtsc() + #define DN_CpuTscNow() __rdtsc() #define DN_CompilerReadBarrierAndCPUReadFence _ReadBarrier(); _mm_lfence() #define DN_CompilerWriteBarrierAndCPUWriteFence _WriteBarrier(); _mm_sfence() #elif defined(DN_COMPILER_GCC) || defined(DN_COMPILER_CLANG) @@ -760,9 +754,9 @@ typedef DN_I32 DN_B32; #define DN_CountLeadingZerosU32(value) __builtin_clzl(value) #if defined(DN_COMPILER_GCC) - #define DN_CPUGetTsc() __rdtsc() + #define DN_CpuTscNow() __rdtsc() #else - #define DN_CPUGetTsc() __builtin_readcyclecounter() + #define DN_CpuTscNow() __builtin_readcyclecounter() #endif #if defined(DN_PLATFORM_EMSCRIPTEN) @@ -848,8 +842,8 @@ struct DN_Str16Slice DN_USize count; }; -typedef struct DN_CPURegisters DN_CPURegisters; -struct DN_CPURegisters +typedef struct DN_CpuRegisters DN_CpuRegisters; +struct DN_CpuRegisters { int eax; int ebx; @@ -857,98 +851,98 @@ struct DN_CPURegisters int edx; }; -union DN_CPUIDResult +union DN_CpuIDResult { - DN_CPURegisters reg; + DN_CpuRegisters reg; int values[4]; }; -typedef struct DN_CPUIDArgs DN_CPUIDArgs; -struct DN_CPUIDArgs { int eax; int ecx; }; +typedef struct DN_CpuIDArgs DN_CpuIDArgs; +struct DN_CpuIDArgs { int eax; int ecx; }; -#define DN_CPU_FEAT_XMACRO \ - DN_CPU_FEAT_XENTRY(3DNow) \ - DN_CPU_FEAT_XENTRY(3DNowExt) \ - DN_CPU_FEAT_XENTRY(ABM) \ - DN_CPU_FEAT_XENTRY(AES) \ - DN_CPU_FEAT_XENTRY(AVX) \ - DN_CPU_FEAT_XENTRY(AVX2) \ - DN_CPU_FEAT_XENTRY(AVX512F) \ - DN_CPU_FEAT_XENTRY(AVX512DQ) \ - DN_CPU_FEAT_XENTRY(AVX512IFMA) \ - DN_CPU_FEAT_XENTRY(AVX512PF) \ - DN_CPU_FEAT_XENTRY(AVX512ER) \ - DN_CPU_FEAT_XENTRY(AVX512CD) \ - DN_CPU_FEAT_XENTRY(AVX512BW) \ - DN_CPU_FEAT_XENTRY(AVX512VL) \ - DN_CPU_FEAT_XENTRY(AVX512VBMI) \ - DN_CPU_FEAT_XENTRY(AVX512VBMI2) \ - DN_CPU_FEAT_XENTRY(AVX512VNNI) \ - DN_CPU_FEAT_XENTRY(AVX512BITALG) \ - DN_CPU_FEAT_XENTRY(AVX512VPOPCNTDQ) \ - DN_CPU_FEAT_XENTRY(AVX5124VNNIW) \ - DN_CPU_FEAT_XENTRY(AVX5124FMAPS) \ - DN_CPU_FEAT_XENTRY(AVX512VP2INTERSECT) \ - DN_CPU_FEAT_XENTRY(AVX512FP16) \ - DN_CPU_FEAT_XENTRY(CLZERO) \ - DN_CPU_FEAT_XENTRY(CMPXCHG8B) \ - DN_CPU_FEAT_XENTRY(CMPXCHG16B) \ - DN_CPU_FEAT_XENTRY(F16C) \ - DN_CPU_FEAT_XENTRY(FMA) \ - DN_CPU_FEAT_XENTRY(FMA4) \ - DN_CPU_FEAT_XENTRY(FP128) \ - DN_CPU_FEAT_XENTRY(FP256) \ - DN_CPU_FEAT_XENTRY(FPU) \ - DN_CPU_FEAT_XENTRY(MMX) \ - DN_CPU_FEAT_XENTRY(MONITOR) \ - DN_CPU_FEAT_XENTRY(MOVBE) \ - DN_CPU_FEAT_XENTRY(MOVU) \ - DN_CPU_FEAT_XENTRY(MmxExt) \ - DN_CPU_FEAT_XENTRY(PCLMULQDQ) \ - DN_CPU_FEAT_XENTRY(POPCNT) \ - DN_CPU_FEAT_XENTRY(RDRAND) \ - DN_CPU_FEAT_XENTRY(RDSEED) \ - DN_CPU_FEAT_XENTRY(RDTscP) \ - DN_CPU_FEAT_XENTRY(SHA) \ - DN_CPU_FEAT_XENTRY(SSE) \ - DN_CPU_FEAT_XENTRY(SSE2) \ - DN_CPU_FEAT_XENTRY(SSE3) \ - DN_CPU_FEAT_XENTRY(SSE41) \ - DN_CPU_FEAT_XENTRY(SSE42) \ - DN_CPU_FEAT_XENTRY(SSE4A) \ - DN_CPU_FEAT_XENTRY(SSSE3) \ - DN_CPU_FEAT_XENTRY(Tsc) \ - DN_CPU_FEAT_XENTRY(TscInvariant) \ - DN_CPU_FEAT_XENTRY(VAES) \ - DN_CPU_FEAT_XENTRY(VPCMULQDQ) +#define DN_Cpu_FEAT_XMACRO \ + DN_Cpu_FEAT_XENTRY(3DNow) \ + DN_Cpu_FEAT_XENTRY(3DNowExt) \ + DN_Cpu_FEAT_XENTRY(ABM) \ + DN_Cpu_FEAT_XENTRY(AES) \ + DN_Cpu_FEAT_XENTRY(AVX) \ + DN_Cpu_FEAT_XENTRY(AVX2) \ + DN_Cpu_FEAT_XENTRY(AVX512F) \ + DN_Cpu_FEAT_XENTRY(AVX512DQ) \ + DN_Cpu_FEAT_XENTRY(AVX512IFMA) \ + DN_Cpu_FEAT_XENTRY(AVX512PF) \ + DN_Cpu_FEAT_XENTRY(AVX512ER) \ + DN_Cpu_FEAT_XENTRY(AVX512CD) \ + DN_Cpu_FEAT_XENTRY(AVX512BW) \ + DN_Cpu_FEAT_XENTRY(AVX512VL) \ + DN_Cpu_FEAT_XENTRY(AVX512VBMI) \ + DN_Cpu_FEAT_XENTRY(AVX512VBMI2) \ + DN_Cpu_FEAT_XENTRY(AVX512VNNI) \ + DN_Cpu_FEAT_XENTRY(AVX512BITALG) \ + DN_Cpu_FEAT_XENTRY(AVX512VPOPCNTDQ) \ + DN_Cpu_FEAT_XENTRY(AVX5124VNNIW) \ + DN_Cpu_FEAT_XENTRY(AVX5124FMAPS) \ + DN_Cpu_FEAT_XENTRY(AVX512VP2INTERSECT) \ + DN_Cpu_FEAT_XENTRY(AVX512FP16) \ + DN_Cpu_FEAT_XENTRY(CLZERO) \ + DN_Cpu_FEAT_XENTRY(CMPXCHG8B) \ + DN_Cpu_FEAT_XENTRY(CMPXCHG16B) \ + DN_Cpu_FEAT_XENTRY(F16C) \ + DN_Cpu_FEAT_XENTRY(FMA) \ + DN_Cpu_FEAT_XENTRY(FMA4) \ + DN_Cpu_FEAT_XENTRY(FP128) \ + DN_Cpu_FEAT_XENTRY(FP256) \ + DN_Cpu_FEAT_XENTRY(FPU) \ + DN_Cpu_FEAT_XENTRY(MMX) \ + DN_Cpu_FEAT_XENTRY(MONITOR) \ + DN_Cpu_FEAT_XENTRY(MOVBE) \ + DN_Cpu_FEAT_XENTRY(MOVU) \ + DN_Cpu_FEAT_XENTRY(MmxExt) \ + DN_Cpu_FEAT_XENTRY(PCLMULQDQ) \ + DN_Cpu_FEAT_XENTRY(POPCNT) \ + DN_Cpu_FEAT_XENTRY(RDRAND) \ + DN_Cpu_FEAT_XENTRY(RDSEED) \ + DN_Cpu_FEAT_XENTRY(RDTscP) \ + DN_Cpu_FEAT_XENTRY(SHA) \ + DN_Cpu_FEAT_XENTRY(SSE) \ + DN_Cpu_FEAT_XENTRY(SSE2) \ + DN_Cpu_FEAT_XENTRY(SSE3) \ + DN_Cpu_FEAT_XENTRY(SSE41) \ + DN_Cpu_FEAT_XENTRY(SSE42) \ + DN_Cpu_FEAT_XENTRY(SSE4A) \ + DN_Cpu_FEAT_XENTRY(SSSE3) \ + DN_Cpu_FEAT_XENTRY(Tsc) \ + DN_Cpu_FEAT_XENTRY(TscInvariant) \ + DN_Cpu_FEAT_XENTRY(VAES) \ + DN_Cpu_FEAT_XENTRY(VPCMULQDQ) -typedef enum DN_CPUFeature { - #define DN_CPU_FEAT_XENTRY(label) DN_CPUFeature_##label, - DN_CPU_FEAT_XMACRO - #undef DN_CPU_FEAT_XENTRY - DN_CPUFeature_Count, -} DN_CPUFeature; +typedef enum DN_CpuFeature { + #define DN_Cpu_FEAT_XENTRY(label) DN_CpuFeature_##label, + DN_Cpu_FEAT_XMACRO + #undef DN_Cpu_FEAT_XENTRY + DN_CpuFeature_Count, +} DN_CpuFeature; -typedef struct DN_CPUFeatureDecl DN_CPUFeatureDecl; -struct DN_CPUFeatureDecl +typedef struct DN_CpuFeatureDecl DN_CpuFeatureDecl; +struct DN_CpuFeatureDecl { - DN_CPUFeature value; + DN_CpuFeature value; DN_Str8 label; }; -typedef struct DN_CPUFeatureQuery DN_CPUFeatureQuery; -struct DN_CPUFeatureQuery +typedef struct DN_CpuFeatureQuery DN_CpuFeatureQuery; +struct DN_CpuFeatureQuery { - DN_CPUFeature feature; + DN_CpuFeature feature; bool available; }; -typedef struct DN_CPUReport DN_CPUReport; -struct DN_CPUReport +typedef struct DN_CpuReport DN_CpuReport; +struct DN_CpuReport { char vendor[4 /*bytes*/ * 3 /*EDX, ECX, EBX*/ + 1 /*null*/]; char brand[48]; - DN_U64 features[(DN_CPUFeature_Count / (sizeof(DN_U64) * 8)) + 1]; + DN_U64 features[(DN_CpuFeature_Count / (sizeof(DN_U64) * 8)) + 1]; }; typedef struct DN_TicketMutex DN_TicketMutex; @@ -1287,10 +1281,6 @@ struct DN_MemList DN_MemStats stats; DN_Str8 label; - #if DN_MEM_DEBUGGER - DN_USize mem_debugger_id; - #endif - #if DN_ARENA_TEMP_MEM_UAF_GUARD DN_U32 uaf_guard_next_id; DN_U32 uaf_guard_active_id; @@ -1312,6 +1302,7 @@ typedef enum DN_AllocatorType { DN_AllocatorType_MemList, DN_AllocatorType_Arena, DN_AllocatorType_Pool, + DN_AllocatorType_Heap, } DN_AllocatorType; typedef struct DN_Allocator DN_Allocator; @@ -1349,7 +1340,13 @@ struct DN_Arena #endif }; -DN_USize const DN_ARENA_HEADER_SIZE = DN_AlignUpPowerOfTwo(sizeof(DN_Arena), 64); +// NOTE: The memory list is stored inside the block header, immediately after the DN_MemBlock. Keeping +// the DN_MemBlock at the allocation base means freeing the block is trivial (the block pointer is the +// allocation pointer). The header grows to fit the memory list, and the static assert guarantees the +// list sits below the used watermark so resetting the list can never scrub it. +#define DN_MEM_LIST_OFFSET DN_AlignUpPowerOfTwo(sizeof(DN_MemBlock), alignof(DN_MemList)) +DN_USize const DN_ARENA_HEADER_SIZE = DN_AlignUpPowerOfTwo(DN_Max(sizeof(DN_Arena), DN_MEM_LIST_OFFSET + sizeof(DN_MemList)), 64); +DN_StaticAssert(DN_MEM_LIST_OFFSET + sizeof(DN_MemList) <= DN_ARENA_HEADER_SIZE); #if !defined(DN_POOL_DEFAULT_ALIGN) #define DN_POOL_DEFAULT_ALIGN 16 @@ -1462,6 +1459,14 @@ enum DN_Str8IsFlags_ DN_Str8IsFlags_Uppercase = 1 << 3, // String is all uppercase characters (case-ness is only checked for ASCII, non-ASCII is permitted always) }; +struct DN_Str8IsResult +{ + bool success; + // Set if `flags` was set to hex mode and `success` is true. Set to the slice of the input + // `string` without the 0x prefix if it had one. + DN_Str8 hex; +}; + typedef struct DN_Str8BSplitResult DN_Str8BSplitResult; struct DN_Str8BSplitResult { @@ -1549,6 +1554,24 @@ struct DN_Str8Builder DN_USize count; // The number of links in the linked list of strings }; +struct DN_Str8Path +{ + DN_Str8 value; // Full path that was fed into the function producing this struct + DN_Str8 file_name; // Slice into `value` containing the string proceeding the last path-separator (`/` or `\\`) and includes the file extension + DN_Str8 file_name_no_ext; // `file_name` but with `file_ext` truncated from it for convenience + DN_Str8 file_ext; // Slice into `value` containing the string proceeding the last `.` in the string + + // Full directory path, calculated as a slice into `value` containing the string preceeding the + // last path-seperator (`/` or `\\`). If the file portion of the string from this calculation does + // _not_ have a `.` file extension, it assumes the entire path passed in is a directory. This is + // not bullet proof but these APIs producing this struct do not use OS primitives. + // + // So for example if you have a file called "text_file" and you passed in "C:\folder\text_file" as + // the path, `directory` resolves to "C:\folder\text_file" because it can't determine that + // "text_file" is a file without asking the OS. + DN_Str8 directory; +}; + #if !defined(DN_OsPathSeperator) #if defined(DN_PLATFORM_WIN32) #define DN_OsPathSeperator "\\" @@ -2157,18 +2180,18 @@ struct DN_HTable DN_HTableHashFunc* hash_func; DN_HTableKeyEqFunc* key_eq_func; - DN_HTableFlags flags; - DN_Heap heap; - DN_Pool pool; + DN_HTableFlags flags; + DN_Heap* heap; + DN_Pool* pool; // NOTE: Metadata for handling genericism (in C that means type-erasure) - void** kvs; - DN_USize offset_of_hash; - DN_USize size_of_kv; - DN_USize offset_of_key; - DN_USize size_of_key; - DN_USize offset_of_value; - DN_USize size_of_value; + void** kvs; + DN_USize offset_of_hash; + DN_USize size_of_kv; + DN_USize offset_of_key; + DN_USize size_of_key; + DN_USize offset_of_value; + DN_USize size_of_value; }; typedef struct DN_HTableInitArgs DN_HTableInitArgs; @@ -2240,16 +2263,23 @@ enum DN_MemDebuggerPtrFlag DN_MemDebuggerPtrFlag_LeakPermitted = 1 << 1, }; +enum DN_MemDebuggerAllocType +{ + DN_MemDebuggerAllocType_Reserve, + DN_MemDebuggerAllocType_Commit, + DN_MemDebuggerAllocType_Count, +}; + typedef struct DN_MemDebuggerPtrData DN_MemDebuggerPtrData; struct DN_MemDebuggerPtrData { DN_CallSite call_site; - DN_U16 flags; // Bit flags from `DN_MemDebuggerPtrFlag` - void* ptr; // Pointer to the allocation being tracked - DN_USize size; // Size of the allocation - DN_USize freed_size; // Store the size of the allocation when it is freed - DN_Str8 stack_trace; // Stack trace at the point of allocation - DN_Str8 freed_stack_trace; // Stack trace of where the allocation was freed + DN_U16 flags; // Bit flags from `DN_MemDebuggerPtrFlag` + void* ptr; // Pointer to the allocation being tracked + DN_USize bytes[DN_MemDebuggerAllocType_Count]; // Size of the allocation indexed by `DN_MemDebuggerAllocType` + DN_USize freed_bytes[DN_MemDebuggerAllocType_Count]; // Size of the allocation when it was freed, indexed by `DN_MemDebuggerAllocType` + DN_Str8 stack_trace; // Stack trace at the point of allocation + DN_Str8 freed_stack_trace; // Stack trace of where the allocation was freed }; typedef struct DN_MemDebuggerKV DN_MemDebuggerKV; @@ -2260,33 +2290,107 @@ struct DN_MemDebuggerKV DN_MemDebuggerPtrData value; }; +typedef struct DN_MemDebuggerMemListAlloc DN_MemDebuggerMemListAlloc; +struct DN_MemDebuggerMemListAlloc +{ + void* ptr; // Allocation pointer + DN_U64 size; // Requested size + DN_U64 alloc_size; // Bytes consumed in the block (includes alignment padding) + DN_U64 position; // Absolute (0-based) memory list position of the allocation pointer + DN_U8 align; // Requested alignment + DN_CallSite call_site; +}; + +typedef struct DN_MemDebuggerMemList DN_MemDebuggerMemList; +struct DN_MemDebuggerMemList +{ + DN_MemList* mem_list; + DN_MemDebuggerMemListAlloc* allocs; // Append-only, ascending memory list position order + DN_USize allocs_count; + DN_USize allocs_max; + DN_TicketMutex alloc_mutex; +}; + +typedef struct DN_MemDebuggerMemListKV DN_MemDebuggerMemListKV; +struct DN_MemDebuggerMemListKV +{ + DN_HTableHashType hash; + DN_MemList* key; + DN_MemDebuggerMemList value; +}; + typedef struct DN_MemDebuggerSnapshotPtrData DN_MemDebuggerSnapshotPtrData; struct DN_MemDebuggerSnapshotPtrData { void* ptr; - DN_USize size; + DN_USize bytes[DN_MemDebuggerAllocType_Count]; // Size of the allocation indexed by `DN_MemDebuggerAllocType` DN_U16 flags; DN_CallSite call_site; DN_Str8 stack_trace; }; +typedef struct DN_MemDebuggerMemListSnapshot DN_MemDebuggerMemListSnapshot; +struct DN_MemDebuggerMemListSnapshot +{ + DN_MemList mem_list; // Copy of the live memory list + DN_U64 wasted; // Stranded reserved bytes, captured at snapshot time + DN_MemStats* blocks; // Live block stats (chain order: tail -> head) + DN_USize blocks_count; + DN_MemDebuggerMemListAlloc* allocs; // Live allocations, sorted by alloc_size descending + DN_USize allocs_count; +}; + typedef struct DN_MemDebuggerSnapshot DN_MemDebuggerSnapshot; struct DN_MemDebuggerSnapshot { DN_MemDebuggerSnapshotPtrData *data; DN_USize count; - DN_U64 active_bytes; + DN_U64 active_bytes[DN_MemDebuggerAllocType_Count]; DN_U64 freed_count; - DN_U64 freed_bytes; + DN_U64 freed_bytes[DN_MemDebuggerAllocType_Count]; + DN_MemDebuggerMemListSnapshot* mem_lists; // Snapshot copies of the live memory lists + DN_USize mem_lists_count; }; +typedef enum DN_MemDebuggerFlags { + DN_MemDebuggerFlags_Nil = 0, + + // NOTE: When recording an allocation into the debugger we have the choice of either keeping a + // shallow reference to the strings inside the callsite such as `call_site.name` and + // `call_site.function`. For 99% of use-cases this is probably what you want because this avoids a + // heap allocation because typically, the idea behind these strings is that they are specified in + // the .rodata of the binary and hence have program lifetime. + // + // Filenames and functions are derived from the preprocessor macro __FILE_, __FUNC__ as per + // `DN_CallSiteNow`. The callsite name is specified manually by the caller in the + // `DN_CallSiteNowNamed` macro and it's heavily encouraged that these are also constant C-strings + // so that they get placed into the .rodata section of the binary and thus have program lifetime. + // + // If you can't guarantee the lifetime of these strings then you want to set this flag so that + // the mem-debugger ensures that it holds it own copy of the string by heap allocating a copy. + // This incurs a performance penalty ontop of the penalty of having to instrument all the + // allocation calls. + // + // You also definitely want this flag if you dynamically loading and unloading libraries in your + // application. Using these macros in dynamically loaded libraries will give the memory debugger + // pointers from an .rodata that belong to the dynamic library's address space. Once these + // libraries get unloaded then these pointers become garbage memory and point into nothing-ness. + DN_MemDebuggerFlags_HeapAllocCallSiteStrings = 1 << 0, +} DN_MemDebuggerFlags; + typedef struct DN_MemDebugger DN_MemDebugger; struct DN_MemDebugger { - DN_MemDebuggerKV *alloc_table_kvs; - DN_HTable alloc_table; - DN_TicketMutex alloc_table_mutex; - DN_U64 alloc_table_bytes_allocated_for_stack_traces; + DN_U16 flags; + DN_Heap heap; + DN_MemDebuggerKV* alloc_table_kvs; + DN_HTable alloc_table; + DN_TicketMutex alloc_table_mutex; + DN_U64 alloc_table_bytes_allocated_for_stack_traces; + + DN_MemDebuggerMemListKV* mem_list_kvs; + DN_HTable mem_list_table; + DN_TicketMutex mem_list_mutex; }; typedef DN_USize DN_InitFlags; @@ -2296,10 +2400,11 @@ enum DN_InitFlags_ // NOTE: Query the OS for information and enable functionality that requires the OS (like virtual // memory APIs, mutexes, secure RNG) as well as per-thread persistent and scratch allocators. - DN_InitFlags_OS = (1 << 0), - DN_InitFlags_LogLibFeatures = (1 << 2), - DN_InitFlags_LogCPUFeatures = (1 << 3) | DN_InitFlags_OS, - DN_InitFlags_LogAllFeatures = DN_InitFlags_LogLibFeatures | DN_InitFlags_LogCPUFeatures, + DN_InitFlags_OS = (1 << 0), + DN_InitFlags_LogLibFeatures = (1 << 2), + DN_InitFlags_LogCPUFeatures = (1 << 3) | DN_InitFlags_OS, + DN_InitFlags_LogAllFeatures = DN_InitFlags_LogLibFeatures | DN_InitFlags_LogCPUFeatures, + DN_InitFlags_MemDebuggerHeapAllocCallSiteStrings = (1 << 4), }; typedef enum DN_BinPackMode { @@ -2442,8 +2547,13 @@ DN_MSVC_WARNING_POP #include // sendfile #endif #endif +#endif // DN_WITH_OS -extern DN_CPUFeatureDecl g_dn_cpu_feature_decl[DN_CPUFeature_Count]; +// NOTE: DN_OS structures are not compiled out so that any code that might embed these structures +// and are going across API boundaries that don't use the OS primitives can still compile. Our OS +// structures are designed to only use inbuilt integral types and hence avoids relying on any data +// structures from the host OS's includes themselves. +extern DN_CpuFeatureDecl g_dn_cpu_feature_decl[DN_CpuFeature_Count]; typedef struct DN_OSTimer DN_OSTimer; struct DN_OSTimer /// Record time between two time-points using the OS's performance counter. @@ -2481,6 +2591,27 @@ struct DN_OSPathInfo DN_U64 size; }; +typedef struct DN_OSPathResult DN_OSPathResult; +struct DN_OSPathResult +{ + bool success; + DN_Str8 path; +}; + +enum DN_OSPathWatchFileAcceptChange +{ + DN_OSPathWatchFileAcceptChange_No, + DN_OSPathWatchFileAcceptChange_Yes, +}; + +typedef struct DN_OSPathWatchFile DN_OSPathWatchFile; +struct DN_OSPathWatchFile +{ + bool change_accepted; + DN_OSPathInfo candidate; + DN_OSPathInfo prev; +}; + typedef struct DN_OSDirIterator DN_OSDirIterator; struct DN_OSDirIterator { @@ -2489,7 +2620,6 @@ struct DN_OSDirIterator char buffer[512]; }; -// NOTE: R/W Stream API typedef struct DN_OSFileRead DN_OSFileRead; struct DN_OSFileRead { @@ -2595,18 +2725,19 @@ struct DN_OSConditionVariable DN_U64 handle; }; +typedef struct DN_OSWindow DN_OSWindow; struct DN_OSWindow { DN_UPtr handle; }; -enum DN_OSWindowShow +typedef enum DN_OSWindowShow { DN_OSWindowShow_Nil, DN_OSWindowShow_Restore, DN_OSWindowShow_Minimise, DN_OSWindowShow_Maximise, -}; +} DN_OSWindowShow; enum DN_OSWindowMaximise { @@ -2712,7 +2843,7 @@ struct DN_OSLogger typedef struct DN_OSCore DN_OSCore; struct DN_OSCore { - DN_CPUReport cpu_report; + DN_CpuReport cpu_report; DN_OSLogger logger; // NOTE: OS @@ -2729,7 +2860,7 @@ struct DN_OSCore DN_U64 mem_allocs_total; DN_U64 mem_allocs_frame; // Total OS heap allocs since the last 'DN_Core_FrameBegin' was invoked - DN_MemList mem; + DN_MemList* mem; DN_Arena arena; void* platform_context; }; @@ -2742,6 +2873,16 @@ struct DN_OSDiskSpace DN_U64 size; }; +typedef struct DN_OSMemoryInfo DN_OSMemoryInfo; +struct DN_OSMemoryInfo +{ + bool success; + DN_U64 total_phys; // Total usable physical memory (RAM) in bytes + DN_U64 avail_phys; // Physical memory currently available in bytes + DN_U64 total_virtual; // Total virtual memory in bytes + DN_U64 avail_virtual; // Virtual memory currently available in bytes +}; + typedef enum DN_OSAsyncPriority { DN_OSAsyncPriority_Low, DN_OSAsyncPriority_High, @@ -2785,7 +2926,6 @@ struct DN_OSAsyncTask DN_OSAsyncWork work; DN_OSSemaphore completion_sem; }; -#endif // #if DN_WITH_OS typedef struct DN_Core DN_Core; struct DN_Core @@ -2801,9 +2941,7 @@ struct DN_Core void* print_func_context; bool os_init; - #if DN_WITH_OS DN_OSCore os; - #endif }; // NOTE: Library initialisation @@ -2826,155 +2964,150 @@ struct DN_Core // For convenience you can opt into some sane defaults for the `DN_TcInitArgs` which customises // how thread-local storage is setup with `DN_TcInitArgsDefault()` which produces a // `DN_TcInitArgs` object you can pass in by value. -DN_API void DN_Init (DN_Core *dn, DN_InitFlags flags, DN_TcInitArgs args); -DN_API void DN_Set (DN_Core *dn); -DN_API DN_Core* DN_Get (); -DN_API void DN_BeginFrame (); +DN_API void DN_Init (DN_Core *dn, DN_InitFlags flags, DN_TcInitArgs args); +DN_API void DN_Set (DN_Core *dn); +DN_API DN_Core* DN_Get (); +DN_API void DN_BeginFrame (); -DN_API bool DN_VerifyArgsF (DN_VerifyType type, bool expr, DN_CallSite call_site, DN_Str8 expr_str8, char const *fmt, ...); -DN_API bool DN_VerifyArgs (DN_VerifyType type, bool expr, DN_CallSite call_site, DN_Str8 expr_str8); +DN_API bool DN_VerifyArgsF (DN_VerifyType type, bool expr, DN_CallSite call_site, DN_Str8 expr_str8, char const *fmt, ...); +DN_API bool DN_VerifyArgs (DN_VerifyType type, bool expr, DN_CallSite call_site, DN_Str8 expr_str8); -#define DN_Sprintf(...) STB_SPRINTF_DECORATE(sprintf)(__VA_ARGS__) -#define DN_Snprintf(...) STB_SPRINTF_DECORATE(snprintf)(__VA_ARGS__) -#define DN_Vsprintf(...) STB_SPRINTF_DECORATE(vsprintf)(__VA_ARGS__) -#define DN_Vsnprintf(...) STB_SPRINTF_DECORATE(vsnprintf)(__VA_ARGS__) +#define DN_Sprintf(...) STB_SPRINTF_DECORATE(sprintf)(__VA_ARGS__) +#define DN_Snprintf(...) STB_SPRINTF_DECORATE(snprintf)(__VA_ARGS__) +#define DN_Vsprintf(...) STB_SPRINTF_DECORATE(vsprintf)(__VA_ARGS__) +#define DN_Vsnprintf(...) STB_SPRINTF_DECORATE(vsnprintf)(__VA_ARGS__) -DN_API bool DN_MemStartsWith (void const *lhs, DN_USize lhs_count, void const *rhs, DN_USize rhs_count); -DN_API bool DN_MemEq (void const *lhs, DN_USize lhs_count, void const *rhs, DN_USize rhs_count); -DN_API bool DN_MemEqUnsafe (void const *lhs, void const *rhs, DN_USize count); -#if defined(__cplusplus) -template T* DN_MemCopyObjT (T *dest, T const *src, DN_USize count); -#define DN_MemCopyObj(dest, src, count) DN_MemCopyObjT(dest, src, count) -#else -#define DN_MemCopyObj(dest, src, count) DN_Memcpy(dest, src, sizeof(*src) * count) -#endif +DN_API bool DN_MemStartsWith (void const *lhs, DN_USize lhs_count, void const *rhs, DN_USize rhs_count); +DN_API bool DN_MemEq (void const *lhs, DN_USize lhs_count, void const *rhs, DN_USize rhs_count); +DN_API bool DN_MemEqUnsafe (void const *lhs, void const *rhs, DN_USize count); -DN_API DN_U64 DN_AtomicSetValue64 (DN_U64 volatile *target, DN_U64 value); -DN_API DN_U32 DN_AtomicSetValue32 (DN_U32 volatile *target, DN_U32 value); -DN_API DN_USize DN_AlignUpPowerOfTwoUSize (DN_USize val); -DN_API DN_U64 DN_AlignUpPowerOfTwoU64 (DN_U64 val); -DN_API DN_U32 DN_AlignUpPowerOfTwoU32 (DN_U32 val); +DN_API DN_U64 DN_AtomicSetValue64 (DN_U64 volatile *target, DN_U64 value); +DN_API DN_U32 DN_AtomicSetValue32 (DN_U32 volatile *target, DN_U32 value); +DN_API DN_USize DN_AlignUpPowerOfTwoUSize (DN_USize val); +DN_API DN_U64 DN_AlignUpPowerOfTwoU64 (DN_U64 val); +DN_API DN_U32 DN_AlignUpPowerOfTwoU32 (DN_U32 val); -DN_API void DN_ByteSwapU64Ptr (DN_U8* dest, DN_U64 src); -#define DN_ByteSwap64(val) ( \ - ((((DN_U64)(val) >> 56) & 0xFF) << 0) | \ - ((((DN_U64)(val) >> 48) & 0xFF) << 8) | \ - ((((DN_U64)(val) >> 40) & 0xFF) << 16) | \ - ((((DN_U64)(val) >> 32) & 0xFF) << 24) | \ - ((((DN_U64)(val) >> 24) & 0xFF) << 32) | \ - ((((DN_U64)(val) >> 16) & 0xFF) << 40) | \ - ((((DN_U64)(val) >> 8) & 0xFF) << 48) | \ - ((((DN_U64)(val) >> 0) & 0xFF) << 56) \ - ) -#define DN_ByteSwap32(val) ( \ - ((((DN_U32)(val) >> 24) & 0xFF) << 0) | \ - ((((DN_U32)(val) >> 16) & 0xFF) << 8) | \ - ((((DN_U32)(val) >> 8) & 0xFF) << 16) | \ - ((((DN_U32)(val) >> 0) & 0xFF) << 24) \ - ) -#define DN_ByteSwap24(val) ( \ - ((((DN_U32)(val) >> 16) & 0xFF) << 0) | \ - ((((DN_U32)(val) >> 8) & 0xFF) << 8) | \ - ((((DN_U32)(val) >> 0) & 0xFF) << 16) \ - ) -#define DN_ByteSwap16(val) ( \ - ((((DN_U16)(val) >> 8) & 0xFF) << 0) | \ - ((((DN_U16)(val) >> 0) & 0xFF) << 8) \ - ) +DN_API void DN_ByteSwapU64Ptr (DN_U8* dest, DN_U64 src); +#define DN_ByteSwap64(val) ( \ + ((((DN_U64)(val) >> 56) & 0xFF) << 0) | \ + ((((DN_U64)(val) >> 48) & 0xFF) << 8) | \ + ((((DN_U64)(val) >> 40) & 0xFF) << 16) | \ + ((((DN_U64)(val) >> 32) & 0xFF) << 24) | \ + ((((DN_U64)(val) >> 24) & 0xFF) << 32) | \ + ((((DN_U64)(val) >> 16) & 0xFF) << 40) | \ + ((((DN_U64)(val) >> 8) & 0xFF) << 48) | \ + ((((DN_U64)(val) >> 0) & 0xFF) << 56) \ + ) +#define DN_ByteSwap32(val) ( \ + ((((DN_U32)(val) >> 24) & 0xFF) << 0) | \ + ((((DN_U32)(val) >> 16) & 0xFF) << 8) | \ + ((((DN_U32)(val) >> 8) & 0xFF) << 16) | \ + ((((DN_U32)(val) >> 0) & 0xFF) << 24) \ + ) +#define DN_ByteSwap24(val) ( \ + ((((DN_U32)(val) >> 16) & 0xFF) << 0) | \ + ((((DN_U32)(val) >> 8) & 0xFF) << 8) | \ + ((((DN_U32)(val) >> 0) & 0xFF) << 16) \ + ) +#define DN_ByteSwap16(val) ( \ + ((((DN_U16)(val) >> 8) & 0xFF) << 0) | \ + ((((DN_U16)(val) >> 0) & 0xFF) << 8) \ + ) #if defined(DN_64_BIT) - #define DN_ByteSwapUSize(val) DN_ByteSwap64(val) + #define DN_ByteSwapUSize(val) DN_ByteSwap64(val) #else - #define DN_ByteSwapUSize(val) DN_ByteSwap32(val) + #define DN_ByteSwapUSize(val) DN_ByteSwap32(val) #endif -DN_API DN_CPUIDResult DN_CPUID (DN_CPUIDArgs args); -DN_API DN_USize DN_CPUHasFeatureArray (DN_CPUReport const *report, DN_CPUFeatureQuery *features, DN_USize features_size); -DN_API bool DN_CPUHasFeature (DN_CPUReport const *report, DN_CPUFeature feature); -DN_API bool DN_CPUHasAllFeatures (DN_CPUReport const *report, DN_CPUFeature const *features, DN_USize features_size); -DN_API void DN_CPUSetFeature (DN_CPUReport *report, DN_CPUFeature feature); -DN_API DN_CPUReport DN_CPUGetReport (); +DN_API DN_CpuIDResult DN_CpuID (DN_CpuIDArgs args); +DN_API DN_USize DN_CpuHasFeatureArray (DN_CpuReport const *report, DN_CpuFeatureQuery *features, DN_USize features_size); +DN_API bool DN_CpuHasFeature (DN_CpuReport const *report, DN_CpuFeature feature); +DN_API bool DN_CpuHasAllFeatures (DN_CpuReport const *report, DN_CpuFeature const *features, DN_USize features_size); +DN_API void DN_CpuSetFeature (DN_CpuReport *report, DN_CpuFeature feature); +DN_API DN_CpuReport DN_CpuGetReport (); +DN_API DN_U64 DN_CpuTscNowFunctionWrapper (); -DN_API void DN_TicketMutexBegin (DN_TicketMutex *mutex); -DN_API void DN_TicketMutexEnd (DN_TicketMutex *mutex); -DN_API DN_UInt DN_TicketMutexMakeTicket (DN_TicketMutex *mutex); -DN_API void DN_TicketMutexBeginTicket (DN_TicketMutex const *mutex, DN_UInt ticket); -DN_API bool DN_TicketMutexCanLock (DN_TicketMutex const *mutex, DN_UInt ticket); +DN_API void DN_TicketMutexBegin (DN_TicketMutex *mutex); +DN_API void DN_TicketMutexEnd (DN_TicketMutex *mutex); +DN_API DN_UInt DN_TicketMutexMakeTicket (DN_TicketMutex *mutex); +DN_API void DN_TicketMutexBeginTicket (DN_TicketMutex const *mutex, DN_UInt ticket); +DN_API bool DN_TicketMutexCanLock (DN_TicketMutex const *mutex, DN_UInt ticket); -DN_API void DN_BitUnsetInplace (DN_USize *flags, DN_USize bitfield); -DN_API void DN_BitSetInplace (DN_USize *flags, DN_USize bitfield); -DN_API bool DN_BitIsSet (DN_USize bits, DN_USize bits_to_set); -DN_API bool DN_BitIsNotSet (DN_USize bits, DN_USize bits_to_check); -DN_API bool DN_BitIsAny (DN_USize bits, DN_USize bits_to_check); -#define DN_BitClearNextLsb(value) (value) & ((value) - 1) +DN_API void DN_BitUnsetInplace (DN_USize *flags, DN_USize bitfield); +DN_API void DN_BitSetInplace (DN_USize *flags, DN_USize bitfield); +DN_API bool DN_BitIsSet (DN_USize bits, DN_USize bits_to_set); +DN_API bool DN_BitIsNotSet (DN_USize bits, DN_USize bits_to_check); +DN_API bool DN_BitIsAny (DN_USize bits, DN_USize bits_to_check); +#define DN_BitClearNextLsb(value) (value) & ((value) - 1) -DN_API DN_I64 DN_SafeAddI64 (DN_I64 a, DN_I64 b); -DN_API DN_I64 DN_SafeMulI64 (DN_I64 a, DN_I64 b); +DN_API DN_I64 DN_SafeAddI64 (DN_I64 a, DN_I64 b); +DN_API DN_I64 DN_SafeMulI64 (DN_I64 a, DN_I64 b); -DN_API DN_U64 DN_SafeAddU64 (DN_U64 a, DN_U64 b); -DN_API DN_U64 DN_SafeMulU64 (DN_U64 a, DN_U64 b); +DN_API DN_U64 DN_SafeAddU64 (DN_U64 a, DN_U64 b); +DN_API DN_U64 DN_SafeMulU64 (DN_U64 a, DN_U64 b); -DN_API DN_U64 DN_SafeSubU64 (DN_U64 a, DN_U64 b); -DN_API DN_U32 DN_SafeSubU32 (DN_U32 a, DN_U32 b); +DN_API DN_U64 DN_SafeSubU64 (DN_U64 a, DN_U64 b); +DN_API DN_U32 DN_SafeSubU32 (DN_U32 a, DN_U32 b); -DN_API int DN_SaturateCastUSizeToInt (DN_USize val); -DN_API DN_I8 DN_SaturateCastUSizeToI8 (DN_USize val); -DN_API DN_I16 DN_SaturateCastUSizeToI16 (DN_USize val); -DN_API DN_I32 DN_SaturateCastUSizeToI32 (DN_USize val); -DN_API DN_I64 DN_SaturateCastUSizeToI64 (DN_USize val); +DN_API int DN_SaturateCastUSizeToInt (DN_USize val); +DN_API DN_I8 DN_SaturateCastUSizeToI8 (DN_USize val); +DN_API DN_I16 DN_SaturateCastUSizeToI16 (DN_USize val); +DN_API DN_I32 DN_SaturateCastUSizeToI32 (DN_USize val); +DN_API DN_I64 DN_SaturateCastUSizeToI64 (DN_USize val); -DN_API int DN_SaturateCastU64ToInt (DN_U64 val); -DN_API DN_I8 DN_SaturateCastU8ToI8 (DN_U64 val); -DN_API DN_I16 DN_SaturateCastU16ToI16 (DN_U64 val); -DN_API DN_I32 DN_SaturateCastU32ToI32 (DN_U64 val); -DN_API DN_I64 DN_SaturateCastU64ToI64 (DN_U64 val); -DN_API DN_UInt DN_SaturateCastU64ToUInt (DN_U64 val); -DN_API DN_U8 DN_SaturateCastU64ToU8 (DN_U64 val); -DN_API DN_U16 DN_SaturateCastU64ToU16 (DN_U64 val); -DN_API DN_U32 DN_SaturateCastU64ToU32 (DN_U64 val); +DN_API int DN_SaturateCastU64ToInt (DN_U64 val); +DN_API DN_I8 DN_SaturateCastU8ToI8 (DN_U64 val); +DN_API DN_I16 DN_SaturateCastU16ToI16 (DN_U64 val); +DN_API DN_I32 DN_SaturateCastU32ToI32 (DN_U64 val); +DN_API DN_I64 DN_SaturateCastU64ToI64 (DN_U64 val); +DN_API DN_UInt DN_SaturateCastU64ToUInt (DN_U64 val); +DN_API DN_U8 DN_SaturateCastU64ToU8 (DN_U64 val); +DN_API DN_U16 DN_SaturateCastU64ToU16 (DN_U64 val); +DN_API DN_U32 DN_SaturateCastU64ToU32 (DN_U64 val); -DN_API DN_U8 DN_SaturateCastUSizeToU8 (DN_USize val); -DN_API DN_U16 DN_SaturateCastUSizeToU16 (DN_USize val); -DN_API DN_U32 DN_SaturateCastUSizeToU32 (DN_USize val); -DN_API DN_U64 DN_SaturateCastUSizeToU64 (DN_USize val); +DN_API DN_U8 DN_SaturateCastUSizeToU8 (DN_USize val); +DN_API DN_U16 DN_SaturateCastUSizeToU16 (DN_USize val); +DN_API DN_U32 DN_SaturateCastUSizeToU32 (DN_USize val); +DN_API DN_U64 DN_SaturateCastUSizeToU64 (DN_USize val); -DN_API int DN_SaturateCastISizeToInt (DN_ISize val); -DN_API DN_I8 DN_SaturateCastISizeToI8 (DN_ISize val); -DN_API DN_I16 DN_SaturateCastISizeToI16 (DN_ISize val); -DN_API DN_I32 DN_SaturateCastISizeToI32 (DN_ISize val); -DN_API DN_I64 DN_SaturateCastISizeToI64 (DN_ISize val); +DN_API int DN_SaturateCastISizeToInt (DN_ISize val); +DN_API DN_I8 DN_SaturateCastISizeToI8 (DN_ISize val); +DN_API DN_I16 DN_SaturateCastISizeToI16 (DN_ISize val); +DN_API DN_I32 DN_SaturateCastISizeToI32 (DN_ISize val); +DN_API DN_I64 DN_SaturateCastISizeToI64 (DN_ISize val); -DN_API DN_UInt DN_SaturateCastISizeToUInt (DN_ISize val); -DN_API DN_U8 DN_SaturateCastISizeToU8 (DN_ISize val); -DN_API DN_U16 DN_SaturateCastISizeToU16 (DN_ISize val); -DN_API DN_U32 DN_SaturateCastISizeToU32 (DN_ISize val); -DN_API DN_U64 DN_SaturateCastISizeToU64 (DN_ISize val); +DN_API DN_UInt DN_SaturateCastISizeToUInt (DN_ISize val); +DN_API DN_U8 DN_SaturateCastISizeToU8 (DN_ISize val); +DN_API DN_U16 DN_SaturateCastISizeToU16 (DN_ISize val); +DN_API DN_U32 DN_SaturateCastISizeToU32 (DN_ISize val); +DN_API DN_U64 DN_SaturateCastISizeToU64 (DN_ISize val); -DN_API DN_ISize DN_SaturateCastI64ToISize (DN_I64 val); -DN_API DN_I8 DN_SaturateCastI64ToI8 (DN_I64 val); -DN_API DN_I16 DN_SaturateCastI64ToI16 (DN_I64 val); -DN_API DN_I32 DN_SaturateCastI64ToI32 (DN_I64 val); +DN_API DN_ISize DN_SaturateCastI64ToISize (DN_I64 val); +DN_API DN_I8 DN_SaturateCastI64ToI8 (DN_I64 val); +DN_API DN_I16 DN_SaturateCastI64ToI16 (DN_I64 val); +DN_API DN_I32 DN_SaturateCastI64ToI32 (DN_I64 val); -DN_API DN_UInt DN_SaturateCastI64ToUInt (DN_I64 val); -DN_API DN_USize DN_SaturateCastI64ToUSize (DN_I64 val); -DN_API DN_U8 DN_SaturateCastI64ToU8 (DN_I64 val); -DN_API DN_U16 DN_SaturateCastI64ToU16 (DN_I64 val); -DN_API DN_U32 DN_SaturateCastI64ToU32 (DN_I64 val); -DN_API DN_U64 DN_SaturateCastI64ToU64 (DN_I64 val); +DN_API DN_UInt DN_SaturateCastI64ToUInt (DN_I64 val); +DN_API DN_USize DN_SaturateCastI64ToUSize (DN_I64 val); +DN_API DN_U8 DN_SaturateCastI64ToU8 (DN_I64 val); +DN_API DN_U16 DN_SaturateCastI64ToU16 (DN_I64 val); +DN_API DN_U32 DN_SaturateCastI64ToU32 (DN_I64 val); +DN_API DN_U64 DN_SaturateCastI64ToU64 (DN_I64 val); -DN_API DN_I8 DN_SaturateCastIntToI8 (int val); -DN_API DN_I16 DN_SaturateCastIntToI16 (int val); -DN_API DN_U8 DN_SaturateCastIntToU8 (int val); -DN_API DN_U16 DN_SaturateCastIntToU16 (int val); -DN_API DN_U32 DN_SaturateCastIntToU32 (int val); -DN_API DN_U64 DN_SaturateCastIntToU64 (int val); +DN_API DN_I8 DN_SaturateCastIntToI8 (int val); +DN_API DN_I16 DN_SaturateCastIntToI16 (int val); +DN_API DN_U8 DN_SaturateCastIntToU8 (int val); +DN_API DN_U16 DN_SaturateCastIntToU16 (int val); +DN_API DN_U32 DN_SaturateCastIntToU32 (int val); +DN_API DN_U64 DN_SaturateCastIntToU64 (int val); -DN_API void DN_ASanPoisonMemoryRegion (void const volatile *ptr, DN_USize size); -DN_API void DN_ASanUnpoisonMemoryRegion (void const volatile *ptr, DN_USize size); +DN_API void DN_ASanPoisonMemoryRegion (void const volatile *ptr, DN_USize size); +DN_API void DN_ASanUnpoisonMemoryRegion (void const volatile *ptr, DN_USize size); -DN_API DN_F32 DN_EpsilonClampF32 (DN_F32 value, DN_F32 target, DN_F32 epsilon); +DN_API DN_F32 DN_EpsilonClampF32 (DN_F32 value, DN_F32 target, DN_F32 epsilon); -DN_API DN_MemStats DN_MemStatsSum (DN_MemStats lhs, DN_MemStats rhs); -DN_API DN_MemStats DN_MemStatsSumArray (DN_MemStats const *array, DN_USize count); +DN_API DN_MemStats DN_MemStatsSum (DN_MemStats lhs, DN_MemStats rhs); +DN_API DN_MemStats DN_MemStatsSumArray (DN_MemStats const *array, DN_USize count); // NOTE: Heap // Overview @@ -2997,12 +3130,11 @@ DN_API DN_MemStats DN_MemStatsSumArray // address space to reserve for the application from the OS. `commit` is the amount of memory in // pages that the OS will give your application. -#define DN_MemMetadataInit(name_cstr) DN_Literal(DN_MemMetadata){DN_CallSiteNow, DN_Str8Lit(name_cstr)} -DN_API DN_Heap DN_HeapInitBasic (DN_HeapBasicAllocFunc *basic_alloc, DN_HeapBasicDeallocFunc *basic_dealloc); -DN_API DN_Heap DN_HeapInitVirtual (DN_U32 page_size, DN_HeapVirtualReserveFunc *virtual_reserve, DN_HeapVirtualCommitFunc *virtual_commit, DN_HeapVirtualReleaseFunc *virtual_release); -DN_API void* DN_HeapAllocCallSite (DN_Heap *heap, DN_USize reserve, DN_USize commit, DN_HeapAllocFlag flags, DN_CallSite call_site); -#define DN_HeapAlloc(heap, reserve, commit, flags, name_cstr) DN_HeapAllocMetadata(heap, reserve, commit, flags, DN_MemMetadataInit(name_cstr)); -DN_API void DN_HeapDealloc (DN_Heap *heap, void *ptr, DN_USize size); +DN_API DN_Heap DN_HeapInitBasic (DN_HeapBasicAllocFunc *basic_alloc, DN_HeapBasicDeallocFunc *basic_dealloc); +DN_API DN_Heap DN_HeapInitVirtual (DN_U32 page_size, DN_HeapVirtualReserveFunc *virtual_reserve, DN_HeapVirtualCommitFunc *virtual_commit, DN_HeapVirtualReleaseFunc *virtual_release); +DN_API void* DN_HeapAllocCallSite (DN_Heap *heap, DN_USize reserve, DN_USize commit, DN_HeapAllocFlag flags, DN_CallSite call_site); +#define DN_HeapAlloc(heap, reserve, commit, flags, name_cstr) DN_HeapAllocCallSite(heap, reserve, commit, flags, DN_CallSiteNowNamed(name_cstr)); +DN_API void DN_HeapDealloc (DN_Heap *heap, void *ptr, DN_USize size); // NOTE: MemList // Overview @@ -3013,34 +3145,50 @@ DN_API void DN_HeapDealloc // // In general for 99% of use-cases you want an `Arena` and if some API is not exposed on the // `Arena` to then use the `MemList` API on the embedded `mem_list` backing the Arena. -DN_API DN_MemList DN_MemListFromBuffer (void *buffer, DN_USize size, DN_MemFlags flags); -DN_API DN_MemList DN_MemListFromHeapCallSite (DN_U64 reserve, DN_U64 commit, DN_MemFlags flags, DN_Heap heap, DN_CallSite call_site); -#define DN_MemListFromHeap(reserve, commit, flags, heap, name_cstr) DN_MemListFromHeapCallSite(reserve, commit, flags, heap, DN_CallSiteNowNamed(name_cstr)) -DN_API void DN_MemListDeinit (DN_MemList *mem); -DN_API bool DN_MemListCommit (DN_MemList *mem, DN_U64 size); -DN_API bool DN_MemListCommitTo (DN_MemList *mem, DN_U64 pos); -DN_API bool DN_MemListGrow (DN_MemList *mem, DN_U64 reserve, DN_U64 commit); -DN_API void * DN_MemListAlloc (DN_MemList *mem, DN_U64 size, DN_U8 align, DN_ZMem zmem); -DN_API void * DN_MemListAllocContiguous (DN_MemList *mem, DN_U64 size, DN_U8 align, DN_ZMem zmem); -DN_API void * DN_MemListCopy (DN_MemList *mem, void const *data, DN_U64 size, uint8_t align); -DN_API void DN_MemListPopTo (DN_MemList *mem, DN_U64 init_used); -DN_API void DN_MemListPop (DN_MemList *mem, DN_U64 amount); -DN_API DN_U64 DN_MemListPos (DN_MemList const *mem); -DN_API void DN_MemListClear (DN_MemList *mem); -DN_API bool DN_MemListOwnsPtr (DN_MemList const *mem, void const *ptr); -DN_API DN_Str8x64 DN_MemListInfoStr8x64 (DN_MemListInfo info); -DN_API DN_MemListTemp DN_MemListTempBegin (DN_MemList *mem); -DN_API void DN_MemListTempEnd (DN_MemListTemp mem); -#define DN_MemListNew(arena, T, zmem) (T *)DN_MemListAlloc(arena, sizeof(T), alignof(T), zmem) -#define DN_MemListNewZ(arena, T) (T *)DN_MemListAlloc(arena, sizeof(T), alignof(T), DN_ZMem_Yes) -#define DN_MemListNewContiguous(arena, T, zmem) (T *)DN_MemListAllocContiguous(arena, sizeof(T), alignof(T), zmem) -#define DN_MemListNewContiguousZ(arena, T) (T *)DN_MemListAllocContiguous(arena, sizeof(T), alignof(T), DN_ZMem_Yes) -#define DN_MemListNewArray(arena, T, count, zmem) (T *)DN_MemListAlloc(arena, sizeof(T) * (count), alignof(T), zmem) -#define DN_MemListNewArrayZ(arena, T, count) (T *)DN_MemListAlloc(arena, sizeof(T) * (count), alignof(T), DN_ZMem_Yes) -#define DN_MemListNewArrayNoZ(arena, T, count) (T *)DN_MemListAlloc(arena, sizeof(T) * (count), alignof(T), DN_ZMem_No) -#define DN_MemListNewCopy(arena, T, src) (T *)DN_MemListCopy(arena, (src), sizeof(T), alignof(T)) -#define DN_MemListNewArrayCopy(arena, T, src, count) (T *)DN_MemListCopy(arena, (src), sizeof(T) * (count), alignof(T)) - +DN_API DN_MemList* DN_MemListFromBufferCallSite (void *buffer, DN_USize size, DN_MemFlags flags, DN_CallSite call_site); +#define DN_MemListFromBuffer(buffer, size, flags) DN_MemListFromBufferCallSite(buffer, size, flags, DN_CallSiteNow) +#define DN_MemListFromBufferNamed(buffer, size, flags, name_cstr) DN_MemListFromBufferCallSite(buffer, size, flags, DN_CallSiteNowNamed(name_cstr)) +DN_API DN_MemList* DN_MemListFromHeapCallSite (DN_U64 reserve, DN_U64 commit, DN_MemFlags flags, DN_Heap heap, DN_CallSite call_site); +#define DN_MemListFromHeap(reserve, commit, flags, heap, name_cstr) DN_MemListFromHeapCallSite(reserve, commit, flags, heap, DN_CallSiteNowNamed(name_cstr)) +DN_API void DN_MemListDeinit (DN_MemList *mem); +DN_API bool DN_MemListCommit (DN_MemList *mem, DN_U64 size); +DN_API bool DN_MemListCommitTo (DN_MemList *mem, DN_U64 pos); +#define DN_MemListGrow(mem, reserve, commit) DN_MemListGrowCallSite(mem, reserve, commit, DN_CallSiteNow) +DN_API bool DN_MemListGrowCallSite (DN_MemList *mem, DN_U64 reserve, DN_U64 commit, DN_CallSite call_site); +#define DN_MemListAlloc(mem, size, align, zmem) DN_MemListAllocCallSite(mem, size, align, zmem, DN_CallSiteNow) +DN_API void * DN_MemListAllocCallSite (DN_MemList *mem, DN_U64 size, DN_U8 align, DN_ZMem zmem, DN_CallSite call_site); +#define DN_MemListAllocContiguous(mem, size, align, zmem) DN_MemListAllocContiguousCallSite(mem, size, align, zmem, DN_CallSiteNow) +#define DN_MemListAllocContiguousNamed(mem, size, align, zmem, name_cstr) DN_MemListAllocContiguousCallSite(mem, size, align, zmem, DN_CallSiteNowNamed(name_cstr)) +DN_API void * DN_MemListAllocContiguousCallSite (DN_MemList *mem, DN_U64 size, DN_U8 align, DN_ZMem zmem, DN_CallSite call_site); +#define DN_MemListCopy(mem, data, size, align) DN_MemListCopyCallSite(mem, data, size, align, DN_CallSiteNow) +#define DN_MemListCopyNamed(mem, data, size, align, name_cstr) DN_MemListCopyCallSite(mem, data, size, align, DN_CallSiteNowNamed(name_cstr)) +DN_API void * DN_MemListCopyCallSite (DN_MemList *mem, void const *data, DN_U64 size, uint8_t align, DN_CallSite call_site); +DN_API void DN_MemListPopTo (DN_MemList *mem, DN_U64 init_used); +DN_API void DN_MemListPop (DN_MemList *mem, DN_U64 amount); +DN_API DN_U64 DN_MemListPos (DN_MemList const *mem); +DN_API void DN_MemListClear (DN_MemList *mem); +DN_API bool DN_MemListOwnsPtr (DN_MemList const *mem, void const *ptr); +DN_API DN_Str8x64 DN_MemListInfoStr8x64 (DN_MemListInfo info); +DN_API DN_MemListTemp DN_MemListTempBegin (DN_MemList *mem); +DN_API void DN_MemListTempEnd (DN_MemListTemp mem); +#define DN_MemListNew(arena, T, zmem) (T *)DN_MemListAlloc(arena, sizeof(T), alignof(T), zmem) +#define DN_MemListNewArray(arena, T, count, zmem) (T *)DN_MemListAlloc(arena, sizeof(T) * (count), alignof(T), zmem) +#define DN_MemListNewArrayCopy(arena, T, src, count) (T *)DN_MemListCopy(arena, (src), sizeof(T) * (count), alignof(T)) +#define DN_MemListNewArrayCopyNamed(arena, T, src, count, name_cstr) (T *)DN_MemListCopyCallSite(arena, (src), sizeof(T) * (count), alignof(T), DN_CallSiteNowNamed(name_cstr)) +#define DN_MemListNewArrayNamed(arena, T, count, zmem, name_cstr) (T *)DN_MemListAllocCallSite(arena, sizeof(T) * (count), alignof(T), zmem, DN_CallSiteNowNamed(name_cstr)) +#define DN_MemListNewArrayNoZ(arena, T, count) (T *)DN_MemListAlloc(arena, sizeof(T) * (count), alignof(T), DN_ZMem_No) +#define DN_MemListNewArrayNoZNamed(arena, T, count, name_cstr) (T *)DN_MemListAllocCallSite(arena, sizeof(T) * (count), alignof(T), DN_ZMem_No, DN_CallSiteNowNamed(name_cstr)) +#define DN_MemListNewArrayZ(arena, T, count) (T *)DN_MemListAlloc(arena, sizeof(T) * (count), alignof(T), DN_ZMem_Yes) +#define DN_MemListNewArrayZNamed(arena, T, count, name_cstr) (T *)DN_MemListAllocCallSite(arena, sizeof(T) * (count), alignof(T), DN_ZMem_Yes, DN_CallSiteNowNamed(name_cstr)) +#define DN_MemListNewContiguous(arena, T, zmem) (T *)DN_MemListAllocContiguous(arena, sizeof(T), alignof(T), zmem) +#define DN_MemListNewContiguousNamed(arena, T, zmem, name_cstr) (T *)DN_MemListAllocContiguousCallSite(arena, sizeof(T), alignof(T), zmem, DN_CallSiteNowNamed(name_cstr)) +#define DN_MemListNewContiguousZ(arena, T) (T *)DN_MemListAllocContiguous(arena, sizeof(T), alignof(T), DN_ZMem_Yes) +#define DN_MemListNewContiguousZNamed(arena, T, name_cstr) (T *)DN_MemListAllocContiguousCallSite(arena, sizeof(T), alignof(T), DN_ZMem_Yes, DN_CallSiteNowNamed(name_cstr)) +#define DN_MemListNewCopy(arena, T, src) (T *)DN_MemListCopy(arena, (src), sizeof(T), alignof(T)) +#define DN_MemListNewCopyNamed(arena, T, src, name_cstr) (T *)DN_MemListCopyCallSite(arena, (src), sizeof(T), alignof(T), DN_CallSiteNowNamed(name_cstr)) +#define DN_MemListNewNamed(arena, T, zmem, name_cstr) (T *)DN_MemListAllocCallSite(arena, sizeof(T), alignof(T), zmem, DN_CallSiteNowNamed(name_cstr)) +#define DN_MemListNewZ(arena, T) (T *)DN_MemListAlloc(arena, sizeof(T), alignof(T), DN_ZMem_Yes) +#define DN_MemListNewZNamed(arena, T, name_cstr) (T *)DN_MemListAllocCallSite(arena, sizeof(T), alignof(T), DN_ZMem_Yes, DN_CallSiteNowNamed(name_cstr)) // NOTE: Arena // Overview // `Arena`'s in this codebase are thin-layers over `MemList` but additionally provide @@ -3085,371 +3233,444 @@ DN_API void DN_MemListTempEnd DN_ArenaTempEnd(&temp); DN_ArenaDeinit(&arena); // Frees the memory */ -DN_API DN_Arena DN_ArenaFromMemList (DN_MemList *mem); -DN_API DN_Arena DN_ArenaFromHeapCallSite (DN_U64 reserve, DN_U64 commit, DN_MemFlags flags, DN_Heap heap, DN_CallSite call_site); -#define DN_ArenaFromHeap(reserve, commit, flags, heap, name_cstr) DN_ArenaFromHeapCallSite(reserve, commit, flags, heap, DN_CallSiteNowNamed(name_cstr)) -DN_API DN_Arena DN_ArenaTempBeginFromMemList (DN_MemList *mem); -DN_API DN_Arena DN_ArenaTempBeginFromArena (DN_Arena *arena); -DN_API void DN_ArenaTempEnd (DN_Arena *arena, DN_ArenaReset reset); -DN_API void* DN_ArenaAlloc (DN_Arena *arena, DN_U64 size, DN_U8 align, DN_ZMem z_mem); -DN_API void* DN_ArenaAllocContiguous (DN_Arena *arena, DN_U64 size, DN_U8 align, DN_ZMem z_arena); -DN_API void* DN_ArenaCopy (DN_Arena *arena, void const *data, DN_U64 size, DN_U8 align); -DN_API void DN_ArenaDeinit (DN_Arena *arena); -DN_API bool DN_ArenaOwnsPtr (DN_Arena const *arena, void *ptr); +DN_API DN_Arena DN_ArenaFromMemList (DN_MemList *mem); +DN_API DN_Arena DN_ArenaFromHeapCallSite (DN_U64 reserve, DN_U64 commit, DN_MemFlags flags, DN_Heap heap, DN_CallSite call_site); +#define DN_ArenaFromHeap(reserve, commit, flags, heap, name_cstr) DN_ArenaFromHeapCallSite(reserve, commit, flags, heap, DN_CallSiteNowNamed(name_cstr)) +DN_API DN_Arena DN_ArenaTempBeginFromMemList (DN_MemList *mem); +DN_API DN_Arena DN_ArenaTempBeginFromArena (DN_Arena *arena); +DN_API void DN_ArenaTempEnd (DN_Arena *arena, DN_ArenaReset reset); +DN_API void* DN_ArenaAllocCallSite (DN_Arena *arena, DN_U64 size, DN_U8 align, DN_ZMem z_mem, DN_CallSite call_site); +#define DN_ArenaAlloc(arena, size, align, z_mem) DN_ArenaAllocCallSite(arena, size, align, z_mem, DN_CallSiteNow) +#define DN_ArenaAllocNamed(arena, size, align, z_mem, name_cstr) DN_ArenaAllocCallSite(arena, size, align, z_mem, DN_CallSiteNowNamed(name_cstr)) +DN_API void* DN_ArenaAllocContiguousCallSite (DN_Arena *arena, DN_U64 size, DN_U8 align, DN_ZMem z_arena, DN_CallSite call_site); +#define DN_ArenaAllocContiguous(arena, size, align, z_arena) DN_ArenaAllocContiguousCallSite(arena, size, align, z_arena, DN_CallSiteNow) +#define DN_ArenaAllocContiguousNamed(arena, size, align, z_arena, name_cstr) DN_ArenaAllocContiguousCallSite(arena, size, align, z_arena, DN_CallSiteNowNamed(name_cstr)) +DN_API void DN_ArenaClear (DN_Arena *arena); +DN_API void* DN_ArenaCopyCallSite (DN_Arena *arena, void const *data, DN_U64 size, DN_U8 align, DN_CallSite call_site); +#define DN_ArenaCopy(arena, data, size, align) DN_ArenaCopyCallSite(arena, data, size, align, DN_CallSiteNow) +#define DN_ArenaCopyNamed(arena, data, size, align, name_cstr) DN_ArenaCopyCallSite(arena, data, size, align, DN_CallSiteNowNamed(name_cstr)) +DN_API void DN_ArenaDeinit (DN_Arena *arena); +DN_API bool DN_ArenaOwnsPtr (DN_Arena const *arena, void *ptr); -#define DN_ArenaNew(arena, T, zmem) (T *)DN_ArenaAlloc(arena, sizeof(T), alignof(T), zmem) -#define DN_ArenaNewZ(arena, T) (T *)DN_ArenaAlloc(arena, sizeof(T), alignof(T), DN_ZMem_Yes) -#define DN_ArenaNewContiguous(arena, T, zmem) (T *)DN_ArenaAllocContiguous(arena, sizeof(T), alignof(T), zmem) -#define DN_ArenaNewContiguousZ(arena, T) (T *)DN_ArenaAllocContiguous(arena, sizeof(T), alignof(T), DN_ZMem_Yes) -#define DN_ArenaNewArray(arena, T, count, zmem) (T *)DN_ArenaAlloc(arena, sizeof(T) * (count), alignof(T), zmem) -#define DN_ArenaNewArrayZ(arena, T, count) (T *)DN_ArenaAlloc(arena, sizeof(T) * (count), alignof(T), DN_ZMem_Yes) -#define DN_ArenaNewArrayNoZ(arena, T, count) (T *)DN_ArenaAlloc(arena, sizeof(T) * (count), alignof(T), DN_ZMem_No) -#define DN_ArenaNewCopy(arena, T, src) (T *)DN_ArenaCopy(arena, (src), sizeof(T), alignof(T)) -#define DN_ArenaNewArrayCopy(arena, T, src, count) (T *)DN_ArenaCopy(arena, (src), sizeof(T) * (count), alignof(T)) +#define DN_ArenaNew(arena, T, zmem) (T *)DN_ArenaAlloc(arena, sizeof(T), alignof(T), zmem) +#define DN_ArenaNewArray(arena, T, count, zmem) (T *)DN_ArenaAlloc(arena, sizeof(T) * (count), alignof(T), zmem) +#define DN_ArenaNewArrayCopy(arena, T, src, count) (T *)DN_ArenaCopy(arena, (src), sizeof(T) * (count), alignof(T)) +#define DN_ArenaNewArrayCopyNamed(arena, T, src, count, name_cstr) (T *)DN_ArenaCopyCallSite(arena, (src), sizeof(T) * (count), alignof(T), DN_CallSiteNowNamed(name_cstr)) +#define DN_ArenaNewArrayNamed(arena, T, count, zmem, name_cstr) (T *)DN_ArenaAllocCallSite(arena, sizeof(T) * (count), alignof(T), zmem, DN_CallSiteNowNamed(name_cstr)) +#define DN_ArenaNewArrayNoZ(arena, T, count) (T *)DN_ArenaAlloc(arena, sizeof(T) * (count), alignof(T), DN_ZMem_No) +#define DN_ArenaNewArrayNoZNamed(arena, T, count, name_cstr) (T *)DN_ArenaAllocCallSite(arena, sizeof(T) * (count), alignof(T), DN_ZMem_No, DN_CallSiteNowNamed(name_cstr)) +#define DN_ArenaNewArrayZ(arena, T, count) (T *)DN_ArenaAlloc(arena, sizeof(T) * (count), alignof(T), DN_ZMem_Yes) +#define DN_ArenaNewArrayZNamed(arena, T, count, name_cstr) (T *)DN_ArenaAllocCallSite(arena, sizeof(T) * (count), alignof(T), DN_ZMem_Yes, DN_CallSiteNowNamed(name_cstr)) +#define DN_ArenaNewContiguous(arena, T, zmem) (T *)DN_ArenaAllocContiguous(arena, sizeof(T), alignof(T), zmem) +#define DN_ArenaNewContiguousNamed(arena, T, zmem, name_cstr) (T *)DN_ArenaAllocContiguousCallSite(arena, sizeof(T), alignof(T), zmem, DN_CallSiteNowNamed(name_cstr)) +#define DN_ArenaNewContiguousZ(arena, T) (T *)DN_ArenaAllocContiguous(arena, sizeof(T), alignof(T), DN_ZMem_Yes) +#define DN_ArenaNewContiguousZNamed(arena, T, name_cstr) (T *)DN_ArenaAllocContiguousCallSite(arena, sizeof(T), alignof(T), DN_ZMem_Yes, DN_CallSiteNowNamed(name_cstr)) +#define DN_ArenaNewCopy(arena, T, src) (T *)DN_ArenaCopy(arena, (src), sizeof(T), alignof(T)) +#define DN_ArenaNewCopyNamed(arena, T, src, name_cstr) (T *)DN_ArenaCopyCallSite(arena, (src), sizeof(T), alignof(T), DN_CallSiteNowNamed(name_cstr)) +#define DN_ArenaNewNamed(arena, T, zmem, name_cstr) (T *)DN_ArenaAllocCallSite(arena, sizeof(T), alignof(T), zmem, DN_CallSiteNowNamed(name_cstr)) +#define DN_ArenaNewZ(arena, T) (T *)DN_ArenaAlloc(arena, sizeof(T), alignof(T), DN_ZMem_Yes) +#define DN_ArenaNewZNamed(arena, T, name_cstr) (T *)DN_ArenaAllocCallSite(arena, sizeof(T), alignof(T), DN_ZMem_Yes, DN_CallSiteNowNamed(name_cstr)) -DN_API DN_Pool DN_PoolFromArena (DN_Arena *arena, DN_U8 align); -DN_API bool DN_PoolIsValid (DN_Pool const *pool); -DN_API void * DN_PoolAlloc (DN_Pool *pool, DN_USize size); -DN_API void DN_PoolDealloc (DN_Pool *pool, void *ptr); -DN_API void * DN_PoolCopy (DN_Pool *pool, void const *data, DN_U64 size, uint8_t align); -#define DN_PoolNew(pool, T) (T *)DN_PoolAlloc(pool, sizeof(T)) -#define DN_PoolNewArray(pool, T, count) (T *)DN_PoolAlloc(pool, count * sizeof(T)) -#define DN_PoolNewCopy(pool, T, src) (T *)DN_PoolCopy (pool, (src), sizeof(T), alignof(T)) -#define DN_PoolNewArrayCopy(pool, T, src, count) (T *)DN_PoolCopy (pool, (src), sizeof(T) * (count), alignof(T)) +DN_API DN_Pool DN_PoolFromArena (DN_Arena *arena, DN_U8 align); +DN_API bool DN_PoolIsValid (DN_Pool const *pool); +DN_API void * DN_PoolAllocCallSite (DN_Pool *pool, DN_USize size, DN_CallSite call_site); +#define DN_PoolAlloc(pool, size) DN_PoolAllocCallSite(pool, size, DN_CallSiteNow) +#define DN_PoolAllocNamed(pool, size, name_cstr) DN_PoolAllocCallSite(pool, size, DN_CallSiteNowNamed(name_cstr)) +DN_API void DN_PoolDealloc (DN_Pool *pool, void *ptr); +DN_API void * DN_PoolCopyCallSite (DN_Pool *pool, void const *data, DN_U64 size, uint8_t align, DN_CallSite call_site); +#define DN_PoolCopy(pool, data, size, align) DN_PoolCopyCallSite(pool, data, size, align, DN_CallSiteNow) +#define DN_PoolCopyNamed(pool, data, size, align, name_cstr) DN_PoolCopyCallSite(pool, data, size, align, DN_CallSiteNowNamed(name_cstr)) +#define DN_PoolNew(pool, T) (T *)DN_PoolAlloc(pool, sizeof(T)) +#define DN_PoolNewArray(pool, T, count) (T *)DN_PoolAlloc(pool, count * sizeof(T)) +#define DN_PoolNewArrayCopy(pool, T, src, count) (T *)DN_PoolCopy (pool, (src), sizeof(T) * (count), alignof(T)) +#define DN_PoolNewArrayCopyNamed(pool, T, src, count, name_cstr) (T *)DN_PoolCopyCallSite(pool, (src), sizeof(T) * (count), alignof(T), DN_CallSiteNowNamed(name_cstr)) +#define DN_PoolNewArrayNamed(pool, T, count, name_cstr) (T *)DN_PoolAllocCallSite(pool, count * sizeof(T), DN_CallSiteNowNamed(name_cstr)) +#define DN_PoolNewCopy(pool, T, src) (T *)DN_PoolCopy (pool, (src), sizeof(T), alignof(T)) +#define DN_PoolNewCopyNamed(pool, T, src, name_cstr) (T *)DN_PoolCopyCallSite(pool, (src), sizeof(T), alignof(T), DN_CallSiteNowNamed(name_cstr)) +#define DN_PoolNewNamed(pool, T, name_cstr) (T *)DN_PoolAllocCallSite(pool, sizeof(T), DN_CallSiteNowNamed(name_cstr)) -DN_API DN_ErrSink* DN_ErrSinkBegin_ (DN_ErrSink *err, DN_ErrSinkMode mode, DN_CallSite call_site); -#define DN_ErrSinkBegin(err, mode) DN_ErrSinkBegin_(err, mode, DN_CallSiteNow) -#define DN_ErrSinkBeginDefault(err) DN_ErrSinkBegin(err, DN_ErrSinkMode_Nil) -DN_API bool DN_ErrSinkHasError (DN_ErrSink *err); -DN_API DN_ErrSinkMsg* DN_ErrSinkEnd (DN_Arena *arena, DN_ErrSink *err); -DN_API DN_Str8 DN_ErrSinkEndStr8 (DN_Arena *arena, DN_ErrSink *err); -DN_API void DN_ErrSinkEndIgnore (DN_ErrSink *err); -DN_API bool DN_ErrSinkEndLogError_ (DN_ErrSink *err, DN_CallSite call_site, DN_Str8 msg); -#define DN_ErrSinkEndLogError(err, err_msg) DN_ErrSinkEndLogError_(err, DN_CallSiteNow, err_msg) -DN_API bool DN_ErrSinkEndLogErrorFV_ (DN_ErrSink *err, DN_CallSite call_site, DN_FMT_ATTRIB char const *fmt, va_list args); -#define DN_ErrSinkEndLogErrorFV(err, fmt, args) DN_ErrSinkEndLogErrorFV_(err, DN_CallSiteNow, fmt, args) -DN_API bool DN_ErrSinkEndLogErrorF_ (DN_ErrSink *err, DN_CallSite call_site, DN_FMT_ATTRIB char const *fmt, ...); -#define DN_ErrSinkEndLogErrorF(err, fmt, ...) DN_ErrSinkEndLogErrorF_(err, DN_CallSiteNow, fmt, ##__VA_ARGS__) -DN_API void DN_ErrSinkEndExitIfErrorF_ (DN_ErrSink *err, DN_CallSite call_site, DN_U32 exit_val, DN_FMT_ATTRIB char const *fmt, ...); -#define DN_ErrSinkEndExitIfErrorF(err, exit_val, fmt, ...) DN_ErrSinkEndExitIfErrorF_(err, DN_CallSiteNow, exit_val, fmt, ##__VA_ARGS__) -DN_API void DN_ErrSinkEndExitIfErrorFV_ (DN_ErrSink *err, DN_CallSite call_site, DN_U32 exit_val, DN_FMT_ATTRIB char const *fmt, va_list args); -#define DN_ErrSinkEndExitIfErrorFV(err, exit_val, fmt, args) DN_ErrSinkEndExitIfErrorFV_(err, DN_CallSiteNow, exit_val, fmt, args) -DN_API void DN_ErrSinkAppendFV_ (DN_ErrSink *err, DN_U32 error_code, DN_CallSite call_site, DN_FMT_ATTRIB char const *fmt, va_list args); -#define DN_ErrSinkAppendFV(error, error_code, fmt, args) DN_ErrSinkAppendFV_(error, error_code, DN_CallSiteNow, fmt, args) -DN_API void DN_ErrSinkAppendF_ (DN_ErrSink *err, DN_U32 error_code, DN_CallSite call_site, DN_FMT_ATTRIB char const *fmt, ...); -#define DN_ErrSinkAppendF(error, error_code, fmt, ...) DN_ErrSinkAppendF_(error, error_code, DN_CallSiteNow, fmt, ##__VA_ARGS__) +DN_API DN_ErrSink* DN_ErrSinkBegin_ (DN_ErrSink *err, DN_ErrSinkMode mode, DN_CallSite call_site); +#define DN_ErrSinkBegin(err, mode) DN_ErrSinkBegin_(err, mode, DN_CallSiteNow) +#define DN_ErrSinkBeginDefault(err) DN_ErrSinkBegin(err, DN_ErrSinkMode_Nil) +DN_API bool DN_ErrSinkHasError (DN_ErrSink *err); +DN_API DN_ErrSinkMsg* DN_ErrSinkEnd (DN_Arena *arena, DN_ErrSink *err); +DN_API DN_Str8 DN_ErrSinkEndStr8 (DN_Arena *arena, DN_ErrSink *err); +DN_API void DN_ErrSinkEndIgnore (DN_ErrSink *err); +DN_API bool DN_ErrSinkEndLogError_ (DN_ErrSink *err, DN_CallSite call_site, DN_Str8 msg); +#define DN_ErrSinkEndLogError(err, err_msg) DN_ErrSinkEndLogError_(err, DN_CallSiteNow, err_msg) +DN_API bool DN_ErrSinkEndLogErrorFV_ (DN_ErrSink *err, DN_CallSite call_site, DN_FMT_ATTRIB char const *fmt, va_list args); +#define DN_ErrSinkEndLogErrorFV(err, fmt, args) DN_ErrSinkEndLogErrorFV_(err, DN_CallSiteNow, fmt, args) +DN_API bool DN_ErrSinkEndLogErrorF_ (DN_ErrSink *err, DN_CallSite call_site, DN_FMT_ATTRIB char const *fmt, ...); +#define DN_ErrSinkEndLogErrorF(err, fmt, ...) DN_ErrSinkEndLogErrorF_(err, DN_CallSiteNow, fmt, ##__VA_ARGS__) +DN_API void DN_ErrSinkEndExitIfErrorF_ (DN_ErrSink *err, DN_CallSite call_site, DN_U32 exit_val, DN_FMT_ATTRIB char const *fmt, ...); +#define DN_ErrSinkEndExitIfErrorF(err, exit_val, fmt, ...) DN_ErrSinkEndExitIfErrorF_(err, DN_CallSiteNow, exit_val, fmt, ##__VA_ARGS__) +DN_API void DN_ErrSinkEndExitIfErrorFV_ (DN_ErrSink *err, DN_CallSite call_site, DN_U32 exit_val, DN_FMT_ATTRIB char const *fmt, va_list args); +#define DN_ErrSinkEndExitIfErrorFV(err, exit_val, fmt, args) DN_ErrSinkEndExitIfErrorFV_(err, DN_CallSiteNow, exit_val, fmt, args) +DN_API void DN_ErrSinkAppendFV_ (DN_ErrSink *err, DN_U32 error_code, DN_CallSite call_site, DN_FMT_ATTRIB char const *fmt, va_list args); +#define DN_ErrSinkAppendFV(error, error_code, fmt, args) DN_ErrSinkAppendFV_(error, error_code, DN_CallSiteNow, fmt, args) +DN_API void DN_ErrSinkAppendF_ (DN_ErrSink *err, DN_U32 error_code, DN_CallSite call_site, DN_FMT_ATTRIB char const *fmt, ...); +#define DN_ErrSinkAppendF(error, error_code, fmt, ...) DN_ErrSinkAppendF_(error, error_code, DN_CallSiteNow, fmt, ##__VA_ARGS__) -DN_API DN_TcInitArgs DN_TcInitArgsDefault (); -DN_API void DN_TcInit (DN_TcCore *tc, DN_U64 thread_id, DN_Arena *main_arena, DN_Arena *temp_arenas, DN_USize temp_arenas_count, DN_Arena *err_sink_arena); -DN_API void DN_TcInitFromHeap (DN_TcCore *tc, DN_U64 thread_id, DN_TcInitArgs args, DN_Heap heap); -DN_API void DN_TcDeinit (DN_TcCore *tc, DN_TcDeinitArenas deinit_arenas); -DN_API void DN_TcEquip (DN_TcCore *tc); -DN_API DN_TcCore* DN_TcGet (); -DN_API DN_Arena* DN_TcMainArena (); -DN_API DN_Pool* DN_TcMainPool (); -DN_API DN_Arena DN_TcTempArenaFromAllocator (DN_Allocator *conflicts, DN_USize count); -DN_API DN_Arena DN_TcTempArenaFromArena (DN_Arena **conflicts, DN_USize count); -DN_API DN_TcScratch DN_TcScratchBeginAllocator (DN_Allocator *conflicts, DN_USize count); -DN_API DN_TcScratch DN_TcScratchBeginArena (DN_Arena **conflicts, DN_USize count); -DN_API void DN_TcScratchEnd (DN_TcScratch *scratch); -DN_API void DN_TcSetFrameArena (DN_Arena *arena); -DN_API DN_Arena* DN_TcFrameArena (); -DN_API DN_ErrSink* DN_TcErrSink (); -#define DN_TcErrSinkBegin(mode) DN_ErrSinkBegin(DN_TcErrSink(), mode) -#define DN_TcErrSinkBeginDefault() DN_ErrSinkBeginDefault(DN_TcErrSink()) +DN_API DN_TcInitArgs DN_TcInitArgsDefault (); +DN_API void DN_TcInit (DN_TcCore *tc, DN_U64 thread_id, DN_Arena *main_arena, DN_Arena *temp_arenas, DN_USize temp_arenas_count, DN_Arena *err_sink_arena); +DN_API void DN_TcInitFromHeap (DN_TcCore *tc, DN_U64 thread_id, DN_TcInitArgs args, DN_Heap heap); +DN_API void DN_TcDeinit (DN_TcCore *tc, DN_TcDeinitArenas deinit_arenas); +DN_API void DN_TcEquip (DN_TcCore *tc); +DN_API DN_TcCore* DN_TcGet (); +DN_API DN_Arena* DN_TcMainArena (); +DN_API DN_Pool* DN_TcMainPool (); +DN_API DN_Arena DN_TcTempArenaFromAllocator (DN_Allocator *conflicts, DN_USize count); +DN_API DN_Arena DN_TcTempArenaFromArena (DN_Arena **conflicts, DN_USize count); +DN_API DN_TcScratch DN_TcScratchBeginAllocator (DN_Allocator *conflicts, DN_USize count); +DN_API DN_TcScratch DN_TcScratchBeginArena (DN_Arena **conflicts, DN_USize count); +DN_API void DN_TcScratchEnd (DN_TcScratch *scratch); +DN_API void DN_TcSetFrameArena (DN_Arena *arena); +DN_API DN_Arena* DN_TcFrameArena (); +DN_API DN_ErrSink* DN_TcErrSink (); +#define DN_TcErrSinkBegin(mode) DN_ErrSinkBegin(DN_TcErrSink(), mode) +#define DN_TcErrSinkBeginDefault() DN_ErrSinkBeginDefault(DN_TcErrSink()) -DN_API bool DN_CharIsAlphabet (char ch); -DN_API bool DN_CharIsDigit (char ch); -DN_API bool DN_CharIsAlphaNum (char ch); -DN_API bool DN_CharIsWhitespace (char ch); -DN_API bool DN_CharIsHex (char ch); -DN_API char DN_CharToLower (char ch); -DN_API char DN_CharToUpper (char ch); +DN_API bool DN_CharIsAlphabet (char ch); +DN_API bool DN_CharIsDigit (char ch); +DN_API bool DN_CharIsAlphaNum (char ch); +DN_API bool DN_CharIsWhitespace (char ch); +DN_API bool DN_CharIsHex (char ch); +DN_API char DN_CharToLower (char ch); +DN_API char DN_CharToUpper (char ch); -DN_API DN_U64FromResult DN_U64FromStr8Delimiters (DN_Str8 string, DN_Str8 const *delimiters, DN_USize delimiters_count); -DN_API DN_U64FromResult DN_U64FromStr8Delimiter (DN_Str8 string, DN_Str8 delimiter); -DN_API DN_U64FromResult DN_U64FromStr8 (DN_Str8 string); -DN_API DN_U64FromResult DN_U64FromPtrDelimiter (void const *data, DN_USize size, DN_Str8 delimiter); -DN_API DN_U64FromResult DN_U64FromPtr (void const *data, DN_USize size); -DN_API DN_U64 DN_U64FromPtrUnsafeDelimiter (void const *data, DN_USize size, DN_Str8 delimiter); -DN_API DN_U64 DN_U64FromPtrUnsafe (void const *data, DN_USize size); -DN_API DN_U64FromResult DN_U64FromHexPtr (void const *hex, DN_USize hex_count); -DN_API DN_U64 DN_U64FromHexPtrUnsafe (void const *hex, DN_USize hex_count); -DN_API DN_U64FromResult DN_U64FromHexStr8 (DN_Str8 hex); -DN_API DN_U64 DN_U64FromHexStr8Unsafe (DN_Str8 hex); -DN_API DN_U64 DN_U64FromU8x32HiBEUnsafe (DN_U8x32 const *val); // Get U64 stored in big-endian at the high bytes [24:32) -DN_API DN_U64FromResult DN_U64FromU8x32HiBE (DN_U8x32 const *val); // Checks [0:24) bytes aren't set before getting the U64 -DN_API DN_USize DN_USizeFromU8x32HiBEUnsafe (DN_U8x32 const *val); // Get USize stored in big-endian at the high bytes [32 - sizeof USize:32) -DN_API DN_USizeFromResult DN_USizeFromU8x32HiBE (DN_U8x32 const *val); // Checks [0:sizeof USize) bytes aren't set before getting the U64 -DN_API DN_U32FromResult DN_U32FromHexStr8 (DN_Str8 hex); -DN_API DN_U32FromResult DN_U32FromStr8Delimiters (DN_Str8 string, DN_Str8 const *delimiters, DN_USize delimiters_count); -DN_API DN_U32FromResult DN_U32FromStr8Delimiter (DN_Str8 string, DN_Str8 delimiter); -DN_API DN_U32FromResult DN_U32FromPtr (void const *data, DN_USize size); -DN_API DN_I64FromResult DN_I64FromStr8Delimiters (DN_Str8 string, DN_Str8 const *delimiters, DN_USize delimiters_count); -DN_API DN_I64FromResult DN_I64FromStr8Delimiter (DN_Str8 string, DN_Str8 delimiter); -DN_API DN_I64FromResult DN_I64FromStr8 (DN_Str8 string); -DN_API DN_I64FromResult DN_I64FromPtr (void const *data, DN_USize size); -DN_API DN_I64 DN_I64FromPtrUnsafe (void const *data, DN_USize size); +DN_API DN_U64FromResult DN_U64FromStr8Delimiters (DN_Str8 string, DN_Str8 const *delimiters, DN_USize delimiters_count); +DN_API DN_U64FromResult DN_U64FromStr8Delimiter (DN_Str8 string, DN_Str8 delimiter); +DN_API DN_U64FromResult DN_U64FromStr8 (DN_Str8 string); +DN_API DN_U64FromResult DN_U64FromPtrDelimiter (void const *data, DN_USize size, DN_Str8 delimiter); +DN_API DN_U64FromResult DN_U64FromPtr (void const *data, DN_USize size); +DN_API DN_U64 DN_U64FromPtrUnsafeDelimiter (void const *data, DN_USize size, DN_Str8 delimiter); +DN_API DN_U64 DN_U64FromPtrUnsafe (void const *data, DN_USize size); +DN_API DN_U64FromResult DN_U64FromHexPtr (void const *hex, DN_USize hex_count); +DN_API DN_U64 DN_U64FromHexPtrUnsafe (void const *hex, DN_USize hex_count); +DN_API DN_U64FromResult DN_U64FromHexStr8 (DN_Str8 hex); +DN_API DN_U64 DN_U64FromHexStr8Unsafe (DN_Str8 hex); +DN_API DN_U64 DN_U64FromU8x32HiBEUnsafe (DN_U8x32 const *val); // Get U64 stored in big-endian at the high bytes [24:32) +DN_API DN_U64FromResult DN_U64FromU8x32HiBE (DN_U8x32 const *val); // Checks [0:24) bytes aren't set before getting the U64 +DN_API DN_USize DN_USizeFromU8x32HiBEUnsafe (DN_U8x32 const *val); // Get USize stored in big-endian at the high bytes [32 - sizeof USize:32) +DN_API DN_USizeFromResult DN_USizeFromU8x32HiBE (DN_U8x32 const *val); // Checks [0:sizeof USize) bytes aren't set before getting the U64 +DN_API DN_U32FromResult DN_U32FromHexStr8 (DN_Str8 hex); +DN_API DN_U32FromResult DN_U32FromStr8Delimiters (DN_Str8 string, DN_Str8 const *delimiters, DN_USize delimiters_count); +DN_API DN_U32FromResult DN_U32FromStr8Delimiter (DN_Str8 string, DN_Str8 delimiter); +DN_API DN_U32FromResult DN_U32FromPtr (void const *data, DN_USize size); +DN_API DN_I64FromResult DN_I64FromStr8Delimiters (DN_Str8 string, DN_Str8 const *delimiters, DN_USize delimiters_count); +DN_API DN_I64FromResult DN_I64FromStr8Delimiter (DN_Str8 string, DN_Str8 delimiter); +DN_API DN_I64FromResult DN_I64FromStr8 (DN_Str8 string); +DN_API DN_I64FromResult DN_I64FromPtr (void const *data, DN_USize size); +DN_API DN_I64 DN_I64FromPtrUnsafe (void const *data, DN_USize size); -DN_API bool DN_U8x32Eq (DN_U8x32 const *lhs, DN_U8x32 const *rhs); -DN_API DN_U8x32 DN_U8x32FromBytesLeftPadZ (DN_U8 const *ptr, DN_USize size); -DN_API DN_U8x32 DN_U8x32FromHexUnsafe (DN_Str8 hex_32b); -DN_API DN_U8x32FromResult DN_U8x32FromHex (DN_Str8 hex_32b); -DN_API DN_U8x32FromResult DN_U8x32FromDecimalStr8 (DN_Str8 decimal); // Write decimal string (e.g. "12345") as big-endian 256-bit value +DN_API bool DN_U8x32Eq (DN_U8x32 const *lhs, DN_U8x32 const *rhs); +DN_API DN_U8x32 DN_U8x32FromBytesLeftPadZ (DN_U8 const *ptr, DN_USize size); +DN_API DN_U8x32 DN_U8x32FromHexUnsafe (DN_Str8 hex_32b); +DN_API DN_U8x32FromResult DN_U8x32FromHex (DN_Str8 hex_32b); +DN_API DN_U8x32FromResult DN_U8x32FromDecimalStr8 (DN_Str8 decimal); // Write decimal string (e.g. "12345") as big-endian 256-bit value -DN_API DN_Allocator DN_AllocatorFromMemList (DN_MemList *mem); -DN_API DN_Allocator DN_AllocatorFromArena (DN_Arena *arena); -DN_API DN_Allocator DN_AllocatorFromPool (DN_Pool *pool); -DN_API void* DN_AllocatorAlloc (DN_Allocator allocator, DN_USize count, DN_U8 align, DN_ZMem z_mem); -#define DN_AllocatorNew(allocator, T, zmem) (T *)DN_AllocatorAlloc(allocator, sizeof(T), alignof(T), zmem) -#define DN_AllocatorNewZ(allocator, T) (T *)DN_AllocatorAlloc(allocator, sizeof(T), alignof(T), DN_ZMem_Yes) -#define DN_AllocatorNewNoZ(allocator, T) (T *)DN_AllocatorAlloc(allocator, sizeof(T), alignof(T), DN_ZMem_No) -#define DN_AllocatorNewArray(allocator, T, count, zmem) (T *)DN_AllocatorAlloc(allocator, sizeof(T) * (count), alignof(T), zmem) -#define DN_AllocatorNewArrayZ(allocator, T, count) (T *)DN_AllocatorAlloc(allocator, sizeof(T) * (count), alignof(T), DN_ZMem_Yes) -#define DN_AllocatorNewArrayNoZ(allocator, T, count) (T *)DN_AllocatorAlloc(allocator, sizeof(T) * (count), alignof(T), DN_ZMem_No) +DN_API DN_Allocator DN_AllocatorFromMemList (DN_MemList *mem); +DN_API DN_Allocator DN_AllocatorFromArena (DN_Arena *arena); +DN_API DN_Allocator DN_AllocatorFromPool (DN_Pool *pool); +DN_API DN_Allocator DN_AllocatorFromHeap (DN_Heap *heap); +DN_API void* DN_AllocatorAllocCallSite (DN_Allocator allocator, DN_USize size, DN_U8 align, DN_ZMem z_mem, DN_CallSite call_site); +#define DN_AllocatorAlloc(allocator, count, align, z_mem) DN_AllocatorAllocCallSite(allocator, count, align, z_mem, DN_CallSiteNow) +#define DN_AllocatorAllocNamed(allocator, count, align, z_mem, name_cstr) DN_AllocatorAllocCallSite(allocator, count, align, z_mem, DN_CallSiteNowNamed(name_cstr)) +DN_API void DN_AllocatorDealloc (DN_Allocator allocator, void *ptr, DN_USize size); +#define DN_AllocatorNew(allocator, T, zmem) (T *)DN_AllocatorAlloc(allocator, sizeof(T), alignof(T), zmem) +#define DN_AllocatorNewZ(allocator, T) (T *)DN_AllocatorAlloc(allocator, sizeof(T), alignof(T), DN_ZMem_Yes) +#define DN_AllocatorNewNoZ(allocator, T) (T *)DN_AllocatorAlloc(allocator, sizeof(T), alignof(T), DN_ZMem_No) +#define DN_AllocatorNewArray(allocator, T, count, zmem) (T *)DN_AllocatorAlloc(allocator, sizeof(T) * (count), alignof(T), zmem) +#define DN_AllocatorNewArrayZ(allocator, T, count) (T *)DN_AllocatorAlloc(allocator, sizeof(T) * (count), alignof(T), DN_ZMem_Yes) +#define DN_AllocatorNewArrayNoZ(allocator, T, count) (T *)DN_AllocatorAlloc(allocator, sizeof(T) * (count), alignof(T), DN_ZMem_No) +#define DN_AllocatorNewNamed(allocator, T, zmem, name_cstr) (T *)DN_AllocatorAllocCallSite(allocator, sizeof(T), alignof(T), zmem, DN_CallSiteNowNamed(name_cstr)) +#define DN_AllocatorNewZNamed(allocator, T, name_cstr) (T *)DN_AllocatorAllocCallSite(allocator, sizeof(T), alignof(T), DN_ZMem_Yes, DN_CallSiteNowNamed(name_cstr)) +#define DN_AllocatorNewNoZNamed(allocator, T, name_cstr) (T *)DN_AllocatorAllocCallSite(allocator, sizeof(T), alignof(T), DN_ZMem_No, DN_CallSiteNowNamed(name_cstr)) +#define DN_AllocatorNewArrayNamed(allocator, T, count, zmem, name_cstr) (T *)DN_AllocatorAllocCallSite(allocator, sizeof(T) * (count), alignof(T), zmem, DN_CallSiteNowNamed(name_cstr)) +#define DN_AllocatorNewArrayZNamed(allocator, T, count, name_cstr) (T *)DN_AllocatorAllocCallSite(allocator, sizeof(T) * (count), alignof(T), DN_ZMem_Yes, DN_CallSiteNowNamed(name_cstr)) +#define DN_AllocatorNewArrayNoZNamed(allocator, T, count, name_cstr) (T *)DN_AllocatorAllocCallSite(allocator, sizeof(T) * (count), alignof(T), DN_ZMem_No, DN_CallSiteNowNamed(name_cstr)) -DN_API DN_USize DN_FmtVCount (DN_FMT_ATTRIB char const *fmt, va_list args); -DN_API DN_USize DN_FmtCount (DN_FMT_ATTRIB char const *fmt, ...); -DN_API DN_FmtAppendResult DN_FmtVAppend (char *buf, DN_USize *buf_size, DN_USize buf_max, char const *fmt, va_list args); -DN_API DN_FmtAppendResult DN_FmtAppend (char *buf, DN_USize *buf_size, DN_USize buf_max, char const *fmt, ...); -DN_API DN_FmtAppendResult DN_FmtAppendTruncate (char *buf, DN_USize *buf_size, DN_USize buf_max, DN_Str8 truncator, char const *fmt, ...); -DN_API DN_USize DN_CStr8Count (char const *src); -DN_API DN_USize DN_CStr16Count (wchar_t const *src); +DN_API DN_USize DN_FmtVCount (DN_FMT_ATTRIB char const *fmt, va_list args); +DN_API DN_USize DN_FmtCount (DN_FMT_ATTRIB char const *fmt, ...); +DN_API DN_FmtAppendResult DN_FmtVAppend (char *buf, DN_USize *buf_size, DN_USize buf_max, char const *fmt, va_list args); +DN_API DN_FmtAppendResult DN_FmtAppend (char *buf, DN_USize *buf_size, DN_USize buf_max, char const *fmt, ...); +DN_API DN_FmtAppendResult DN_FmtAppendTruncate (char *buf, DN_USize *buf_size, DN_USize buf_max, DN_Str8 truncator, char const *fmt, ...); +DN_API DN_USize DN_CStr8Count (char const *src); +DN_API DN_USize DN_CStr16Count (wchar_t const *src); -#define DN_Str16Lit(string) DN_Str16{(wchar_t *)(string), sizeof(string)/sizeof(string[0]) - 1} -#define DN_Str16FromPtr(data, count) DN_Literal(DN_Str16){(wchar_t *)(data), (DN_USize)(count)} +// NOTE: Strings +// API +// DN_Str8Is +// Identify if the string satisfies one or more of the types indicated by `flags` such as +// whether or not the string contains valid hex, is all uppercase, all digits and so forth. +// Flags can be combined to check more than one condition at once. If more than one flag is set +// all conditions must be met for the returned value to be successful. +// +// An empty `string` is considered a failure and the returned `success` value is false. +#define DN_Str16Lit(string) DN_Str16{(wchar_t *)(string), sizeof(string)/sizeof(string[0]) - 1} +#define DN_Str16FromPtr(data, count) DN_Literal(DN_Str16){(wchar_t *)(data), (DN_USize)(count)} -#define DN_Str8Lit(c_str) DN_Literal(DN_Str8){(char *)(c_str), sizeof(c_str) - 1} -#define DN_Str8PrintFmt(string) (int)((string).count), (string).data +#define DN_Str8Lit(c_str) DN_Literal(DN_Str8){(char *)(c_str), sizeof(c_str) - 1} +#define DN_Str8PrintFmt(string) (int)((string).count), (string).data -#define DN_Str8FromPtr(data, count) DN_Literal(DN_Str8){(char *)(data), (DN_USize)(count)} -#define DN_Str8FromStruct(ptr) DN_Str8FromPtr((ptr)->data, (ptr)->count) -#define DN_Str8FromLitArray(c_array) DN_Str8FromPtr(c_array, DN_ArrayCountU(c_array)) -DN_API DN_Str8 DN_Str8AllocAllocator (DN_USize count, DN_ZMem z_mem, DN_Allocator allocator); -DN_API DN_Str8 DN_Str8AllocArena (DN_USize count, DN_ZMem z_mem, DN_Arena *arena); -DN_API DN_Str8 DN_Str8AllocPool (DN_USize count, DN_Pool *pool); +#define DN_Str8FromPtr(data, count) DN_Literal(DN_Str8){(char *)(data), (DN_USize)(count)} +#define DN_Str8FromStruct(ptr) DN_Str8FromPtr((ptr)->data, (ptr)->count) +#define DN_Str8FromLitArray(c_array) DN_Str8FromPtr(c_array, DN_ArrayCountU(c_array)) +DN_API DN_Str8 DN_Str8AllocAllocatorCallSite (DN_USize count, DN_ZMem z_mem, DN_Allocator allocator, DN_CallSite call_site); +#define DN_Str8AllocAllocator(count, z_mem, allocator) DN_Str8AllocAllocatorCallSite(count, z_mem, allocator, DN_CallSiteNow) +#define DN_Str8AllocAllocatorNamed(count, z_mem, allocator, name_cstr) DN_Str8AllocAllocatorCallSite(count, z_mem, allocator, DN_CallSiteNowNamed(name_cstr)) +DN_API DN_Str8 DN_Str8AllocArenaCallSite (DN_USize count, DN_ZMem z_mem, DN_Arena *arena, DN_CallSite call_site); +#define DN_Str8AllocArena(count, z_mem, arena) DN_Str8AllocArenaCallSite(count, z_mem, arena, DN_CallSiteNow) +#define DN_Str8AllocArenaNamed(count, z_mem, arena, name_cstr) DN_Str8AllocArenaCallSite(count, z_mem, arena, DN_CallSiteNowNamed(name_cstr)) +DN_API DN_Str8 DN_Str8AllocPoolCallSite (DN_USize count, DN_Pool *pool, DN_CallSite call_site); +#define DN_Str8AllocPool(count, pool) DN_Str8AllocPoolCallSite(count, pool, DN_CallSiteNow) +#define DN_Str8AllocPoolNamed(count, pool, name_cstr) DN_Str8AllocPoolCallSite(count, pool, DN_CallSiteNowNamed(name_cstr)) -DN_API DN_Str8 DN_Str8FromCStr8 (char const *src); -DN_API DN_Str8 DN_Str8FromCStr8Arena (char const *src, DN_Arena *arena); -DN_API DN_Str8 DN_Str8FromPtrArena (void const *data, DN_USize count, DN_Arena *arena); -DN_API DN_Str8 DN_Str8FromPtrPool (void const *data, DN_USize count, DN_Pool *pool); -DN_API DN_Str8 DN_Str8FromStr8Allocator (DN_Str8 string, DN_Allocator allocator); -DN_API DN_Str8 DN_Str8FromStr8Arena (DN_Str8 string, DN_Arena *arena); -DN_API DN_Str8 DN_Str8FromStr8Pool (DN_Str8 string, DN_Pool *pool); -DN_API DN_Str8 DN_Str8FmtVAllocator (DN_Allocator allocator, DN_FMT_ATTRIB char const *fmt, va_list args); -DN_API DN_Str8 DN_Str8FmtVArena (DN_Arena *arena, DN_FMT_ATTRIB char const *fmt, va_list args); -DN_API DN_Str8 DN_Str8FmtAllocator (DN_Allocator allocator, DN_FMT_ATTRIB char const *fmt, ...); -DN_API DN_Str8 DN_Str8FmtArena (DN_Arena *arena, DN_FMT_ATTRIB char const *fmt, ...); -DN_API DN_Str8 DN_Str8FmtVPool (DN_Pool *pool, DN_FMT_ATTRIB char const *fmt, va_list args); -DN_API DN_Str8 DN_Str8FmtPool (DN_Pool *pool, DN_FMT_ATTRIB char const *fmt, ...); +DN_API DN_Str8 DN_Str8FromCStr8 (char const *src); +DN_API DN_Str8 DN_Str8FromCStr8ArenaCallSite (char const *src, DN_Arena *arena, DN_CallSite call_site); +#define DN_Str8FromCStr8Arena(src, arena) DN_Str8FromCStr8ArenaCallSite(src, arena, DN_CallSiteNow) +#define DN_Str8FromCStr8ArenaNamed(src, arena, name_cstr) DN_Str8FromCStr8ArenaCallSite(src, arena, DN_CallSiteNowNamed(name_cstr)) +DN_API DN_Str8 DN_Str8FromPtrArenaCallSite (void const *data, DN_USize count, DN_Arena *arena, DN_CallSite call_site); +#define DN_Str8FromPtrArena(data, count, arena) DN_Str8FromPtrArenaCallSite(data, count, arena, DN_CallSiteNow) +#define DN_Str8FromPtrArenaNamed(data, count, arena, name_cstr) DN_Str8FromPtrArenaCallSite(data, count, arena, DN_CallSiteNowNamed(name_cstr)) +DN_API DN_Str8 DN_Str8FromPtrPoolCallSite (void const *data, DN_USize count, DN_Pool *pool, DN_CallSite call_site); +#define DN_Str8FromPtrPool(data, count, pool) DN_Str8FromPtrPoolCallSite(data, count, pool, DN_CallSiteNow) +#define DN_Str8FromPtrPoolNamed(data, count, pool, name_cstr) DN_Str8FromPtrPoolCallSite(data, count, pool, DN_CallSiteNowNamed(name_cstr)) +DN_API DN_Str8 DN_Str8FromStr8AllocatorCallSite (DN_Str8 string, DN_Allocator allocator, DN_CallSite call_site); +#define DN_Str8FromStr8Allocator(string, allocator) DN_Str8FromStr8AllocatorCallSite(string, allocator, DN_CallSiteNow) +#define DN_Str8FromStr8AllocatorNamed(string, allocator, name_cstr) DN_Str8FromStr8AllocatorCallSite(string, allocator, DN_CallSiteNowNamed(name_cstr)) +DN_API DN_Str8 DN_Str8FromStr8ArenaCallSite (DN_Str8 string, DN_Arena *arena, DN_CallSite call_site); +#define DN_Str8FromStr8Arena(string, arena) DN_Str8FromStr8ArenaCallSite(string, arena, DN_CallSiteNow) +#define DN_Str8FromStr8ArenaNamed(string, arena, name_cstr) DN_Str8FromStr8ArenaCallSite(string, arena, DN_CallSiteNowNamed(name_cstr)) +DN_API DN_Str8 DN_Str8FromStr8PoolCallSite (DN_Str8 string, DN_Pool *pool, DN_CallSite call_site); +#define DN_Str8FromStr8Pool(string, pool) DN_Str8FromStr8PoolCallSite(string, pool, DN_CallSiteNow) +#define DN_Str8FromStr8PoolNamed(string, pool, name_cstr) DN_Str8FromStr8PoolCallSite(string, pool, DN_CallSiteNowNamed(name_cstr)) +DN_API DN_Str8 DN_Str8FmtVAllocatorCallSite (DN_Allocator allocator, DN_FMT_ATTRIB char const *fmt, va_list args, DN_CallSite call_site); +#define DN_Str8FmtVAllocator(allocator, fmt, args) DN_Str8FmtVAllocatorCallSite(allocator, fmt, args, DN_CallSiteNow) +#define DN_Str8FmtVAllocatorNamed(allocator, fmt, args, name_cstr) DN_Str8FmtVAllocatorCallSite(allocator, fmt, args, DN_CallSiteNowNamed(name_cstr)) +DN_API DN_Str8 DN_Str8FmtVArenaCallSite (DN_Arena *arena, DN_FMT_ATTRIB char const *fmt, va_list args, DN_CallSite call_site); +#define DN_Str8FmtVArena(arena, fmt, args) DN_Str8FmtVArenaCallSite(arena, fmt, args, DN_CallSiteNow) +#define DN_Str8FmtVArenaNamed(arena, fmt, args, name_cstr) DN_Str8FmtVArenaCallSite(arena, fmt, args, DN_CallSiteNowNamed(name_cstr)) +DN_API DN_Str8 DN_Str8FmtAllocatorCallSite (DN_Allocator allocator, DN_CallSite call_site, DN_FMT_ATTRIB char const *fmt, ...); +#define DN_Str8FmtAllocator(allocator, fmt, ...) DN_Str8FmtAllocatorCallSite(allocator, DN_CallSiteNow, fmt, ## __VA_ARGS__) +#define DN_Str8FmtAllocatorNamed(allocator, name_cstr, fmt, ...) DN_Str8FmtAllocatorCallSite(allocator, DN_CallSiteNowNamed(name_cstr), fmt, ## __VA_ARGS__) +DN_API DN_Str8 DN_Str8FmtArenaCallSite (DN_Arena *arena, DN_CallSite call_site, DN_FMT_ATTRIB char const *fmt, ...); +#define DN_Str8FmtArena(arena, fmt, ...) DN_Str8FmtArenaCallSite(arena, DN_CallSiteNow, fmt, ## __VA_ARGS__) +#define DN_Str8FmtArenaNamed(arena, name_cstr, fmt, ...) DN_Str8FmtArenaCallSite(arena, DN_CallSiteNowNamed(name_cstr), fmt, ## __VA_ARGS__) +DN_API DN_Str8 DN_Str8FmtVPoolCallSite (DN_Pool *pool, DN_FMT_ATTRIB char const *fmt, va_list args, DN_CallSite call_site); +#define DN_Str8FmtVPool(pool, fmt, args) DN_Str8FmtVPoolCallSite(pool, fmt, args, DN_CallSiteNow) +#define DN_Str8FmtVPoolNamed(pool, fmt, args, name_cstr) DN_Str8FmtVPoolCallSite(pool, fmt, args, DN_CallSiteNowNamed(name_cstr)) +DN_API DN_Str8 DN_Str8FmtPoolCallSite (DN_Pool *pool, DN_CallSite call_site, DN_FMT_ATTRIB char const *fmt, ...); +#define DN_Str8FmtPool(pool, fmt, ...) DN_Str8FmtPoolCallSite(pool, DN_CallSiteNow, fmt, ## __VA_ARGS__) +#define DN_Str8FmtPoolNamed(pool, name_cstr, fmt, ...) DN_Str8FmtPoolCallSite(pool, DN_CallSiteNowNamed(name_cstr), fmt, ## __VA_ARGS__) -DN_API DN_Str8x16 DN_Str8x16FromFmt (DN_FMT_ATTRIB char const *fmt, ...); -DN_API DN_Str8x16 DN_Str8x16FromFmtV (DN_FMT_ATTRIB char const *fmt, va_list args); -DN_API DN_Str8x32 DN_Str8x32FromFmt (DN_FMT_ATTRIB char const *fmt, ...); -DN_API DN_Str8x32 DN_Str8x32FromFmtV (DN_FMT_ATTRIB char const *fmt, va_list args); -DN_API DN_Str8x64 DN_Str8x64FromFmt (DN_FMT_ATTRIB char const *fmt, ...); -DN_API DN_Str8x64 DN_Str8x64FromFmtV (DN_FMT_ATTRIB char const *fmt, va_list args); -DN_API DN_Str8x128 DN_Str8x128FromFmt (DN_FMT_ATTRIB char const *fmt, ...); -DN_API DN_Str8x256 DN_Str8x256FromFmtV (DN_FMT_ATTRIB char const *fmt, va_list args); -DN_API DN_Str8x256 DN_Str8x256FromFmt (DN_FMT_ATTRIB char const *fmt, ...); -DN_API DN_Str8x256 DN_Str8x256FromFmtV (DN_FMT_ATTRIB char const *fmt, va_list args); -DN_API DN_Str8x512 DN_Str8x512FromFmt (DN_FMT_ATTRIB char const *fmt, ...); -DN_API DN_Str8x512 DN_Str8x512FromFmtV (DN_FMT_ATTRIB char const *fmt, va_list args); -DN_API DN_Str8x1024 DN_Str8x1024FromFmt (DN_FMT_ATTRIB char const *fmt, ...); -DN_API DN_Str8x1024 DN_Str8x1024FromFmtV (DN_FMT_ATTRIB char const *fmt, va_list args); -DN_API void DN_Str8x16AppendFmt (DN_Str8x16 *str, DN_FMT_ATTRIB char const *fmt, ...); -DN_API void DN_Str8x16AppendFmtV (DN_Str8x16 *str, DN_FMT_ATTRIB char const *fmt, va_list args); -DN_API void DN_Str8x32AppendFmt (DN_Str8x32 *str, DN_FMT_ATTRIB char const *fmt, ...); -DN_API void DN_Str8x32AppendFmtV (DN_Str8x32 *str, DN_FMT_ATTRIB char const *fmt, va_list args); -DN_API void DN_Str8x64AppendFmt (DN_Str8x64 *str, DN_FMT_ATTRIB char const *fmt, ...); -DN_API void DN_Str8x64AppendFmtV (DN_Str8x64 *str, DN_FMT_ATTRIB char const *fmt, va_list args); -DN_API void DN_Str8x128AppendFmt (DN_Str8x128 *str, DN_FMT_ATTRIB char const *fmt, ...); -DN_API void DN_Str8x128AppendFmtV (DN_Str8x128 *str, DN_FMT_ATTRIB char const *fmt, va_list args); -DN_API void DN_Str8x256AppendFmt (DN_Str8x256 *str, DN_FMT_ATTRIB char const *fmt, ...); -DN_API void DN_Str8x256AppendFmtV (DN_Str8x256 *str, DN_FMT_ATTRIB char const *fmt, va_list args); -DN_API void DN_Str8x512AppendFmt (DN_Str8x512 *str, DN_FMT_ATTRIB char const *fmt, ...); -DN_API void DN_Str8x512AppendFmtV (DN_Str8x512 *str, DN_FMT_ATTRIB char const *fmt, va_list args); -DN_API void DN_Str8x1024AppendFmt (DN_Str8x1024 *str, DN_FMT_ATTRIB char const *fmt, ...); -DN_API void DN_Str8x1024AppendFmtV (DN_Str8x1024 *str, DN_FMT_ATTRIB char const *fmt, va_list args); +DN_API DN_Str8x16 DN_Str8x16FromFmt (DN_FMT_ATTRIB char const *fmt, ...); +DN_API DN_Str8x16 DN_Str8x16FromFmtV (DN_FMT_ATTRIB char const *fmt, va_list args); +DN_API DN_Str8x32 DN_Str8x32FromFmt (DN_FMT_ATTRIB char const *fmt, ...); +DN_API DN_Str8x32 DN_Str8x32FromFmtV (DN_FMT_ATTRIB char const *fmt, va_list args); +DN_API DN_Str8x64 DN_Str8x64FromFmt (DN_FMT_ATTRIB char const *fmt, ...); +DN_API DN_Str8x64 DN_Str8x64FromFmtV (DN_FMT_ATTRIB char const *fmt, va_list args); +DN_API DN_Str8x128 DN_Str8x128FromFmt (DN_FMT_ATTRIB char const *fmt, ...); +DN_API DN_Str8x256 DN_Str8x256FromFmtV (DN_FMT_ATTRIB char const *fmt, va_list args); +DN_API DN_Str8x256 DN_Str8x256FromFmt (DN_FMT_ATTRIB char const *fmt, ...); +DN_API DN_Str8x256 DN_Str8x256FromFmtV (DN_FMT_ATTRIB char const *fmt, va_list args); +DN_API DN_Str8x512 DN_Str8x512FromFmt (DN_FMT_ATTRIB char const *fmt, ...); +DN_API DN_Str8x512 DN_Str8x512FromFmtV (DN_FMT_ATTRIB char const *fmt, va_list args); +DN_API DN_Str8x1024 DN_Str8x1024FromFmt (DN_FMT_ATTRIB char const *fmt, ...); +DN_API DN_Str8x1024 DN_Str8x1024FromFmtV (DN_FMT_ATTRIB char const *fmt, va_list args); +DN_API void DN_Str8x16AppendFmt (DN_Str8x16 *str, DN_FMT_ATTRIB char const *fmt, ...); +DN_API void DN_Str8x16AppendFmtV (DN_Str8x16 *str, DN_FMT_ATTRIB char const *fmt, va_list args); +DN_API void DN_Str8x32AppendFmt (DN_Str8x32 *str, DN_FMT_ATTRIB char const *fmt, ...); +DN_API void DN_Str8x32AppendFmtV (DN_Str8x32 *str, DN_FMT_ATTRIB char const *fmt, va_list args); +DN_API void DN_Str8x64AppendFmt (DN_Str8x64 *str, DN_FMT_ATTRIB char const *fmt, ...); +DN_API void DN_Str8x64AppendFmtV (DN_Str8x64 *str, DN_FMT_ATTRIB char const *fmt, va_list args); +DN_API void DN_Str8x128AppendFmt (DN_Str8x128 *str, DN_FMT_ATTRIB char const *fmt, ...); +DN_API void DN_Str8x128AppendFmtV (DN_Str8x128 *str, DN_FMT_ATTRIB char const *fmt, va_list args); +DN_API void DN_Str8x256AppendFmt (DN_Str8x256 *str, DN_FMT_ATTRIB char const *fmt, ...); +DN_API void DN_Str8x256AppendFmtV (DN_Str8x256 *str, DN_FMT_ATTRIB char const *fmt, va_list args); +DN_API void DN_Str8x512AppendFmt (DN_Str8x512 *str, DN_FMT_ATTRIB char const *fmt, ...); +DN_API void DN_Str8x512AppendFmtV (DN_Str8x512 *str, DN_FMT_ATTRIB char const *fmt, va_list args); +DN_API void DN_Str8x1024AppendFmt (DN_Str8x1024 *str, DN_FMT_ATTRIB char const *fmt, ...); +DN_API void DN_Str8x1024AppendFmtV (DN_Str8x1024 *str, DN_FMT_ATTRIB char const *fmt, va_list args); -DN_API DN_Str8x32 DN_Str8x32FromU64 (DN_U64 val, char seperator); -DN_API bool DN_Str8Is (DN_Str8 string, DN_Str8IsFlags flags); -DN_API char * DN_Str8End (DN_Str8 string); -DN_API DN_Str8 DN_Str8Subset (DN_Str8 string, DN_USize offset, DN_USize count); -DN_API DN_Str8 DN_Str8Advance (DN_Str8 string, DN_USize amount); -DN_API DN_Str8 DN_Str8NextLine (DN_Str8 string); -DN_API DN_Str8BSplitResult DN_Str8BSplitArray (DN_Str8 string, DN_Str8 const *find, DN_USize find_size); -DN_API DN_Str8BSplitResult DN_Str8BSplit (DN_Str8 string, DN_Str8 find); -DN_API DN_Str8BSplitResult DN_Str8BSplitLastArray (DN_Str8 string, DN_Str8 const *find, DN_USize find_size); -DN_API DN_Str8BSplitResult DN_Str8BSplitLast (DN_Str8 string, DN_Str8 find); -DN_API DN_USize DN_Str8Split (DN_Str8 string, DN_Str8 delimiter, DN_Str8 *splits, DN_USize splits_count, DN_Str8SplitFlags mode); -DN_API DN_Str8SplitResult DN_Str8SplitArena (DN_Str8 string, DN_Str8 delimiter, DN_Str8SplitFlags mode, DN_Arena *arena); -DN_API DN_Str8FindResult DN_Str8FindStr8Array (DN_Str8 string, DN_Str8 const *find, DN_USize find_size, DN_Str8EqCase eq_case); -DN_API DN_Str8FindResult DN_Str8FindStr8 (DN_Str8 string, DN_Str8 find, DN_Str8EqCase eq_case); -DN_API DN_Str8FindResult DN_Str8Find (DN_Str8 string, DN_Str8FindFlag flags); -DN_API DN_Str8 DN_Str8Segment (DN_Arena *arena, DN_Str8 src, DN_USize segment_size, char segment_char); -DN_API DN_Str8 DN_Str8ReverseSegment (DN_Arena *arena, DN_Str8 src, DN_USize segment_size, char segment_char); -DN_API bool DN_Str8Eq (DN_Str8 lhs, DN_Str8 rhs, DN_Str8EqCase eq_case); -DN_API bool DN_Str8EqSensitive (DN_Str8 lhs, DN_Str8 rhs); -DN_API bool DN_Str8EqInsensitive (DN_Str8 lhs, DN_Str8 rhs); -DN_API bool DN_Str8StartsWith (DN_Str8 string, DN_Str8 prefix, DN_Str8EqCase eq_case); -DN_API bool DN_Str8StartsWithSensitive (DN_Str8 string, DN_Str8 prefix); -DN_API bool DN_Str8StartsWithInsensitive (DN_Str8 string, DN_Str8 prefix); -DN_API bool DN_Str8EndsWith (DN_Str8 string, DN_Str8 prefix, DN_Str8EqCase eq_case); -DN_API bool DN_Str8EndsWithSensitive (DN_Str8 string, DN_Str8 prefix); -DN_API bool DN_Str8EndsWithInsensitive (DN_Str8 string, DN_Str8 prefix); -DN_API bool DN_Str8HasChar (DN_Str8 string, char ch); +DN_API DN_Str8x32 DN_Str8x32FromU64 (DN_U64 val, char seperator); +DN_API DN_Str8IsResult DN_Str8Is (DN_Str8 string, DN_Str8IsFlags flags); +DN_API char * DN_Str8End (DN_Str8 string); +DN_API DN_Str8 DN_Str8Subset (DN_Str8 string, DN_USize offset, DN_USize count); +DN_API DN_Str8 DN_Str8Advance (DN_Str8 string, DN_USize amount); +DN_API DN_Str8 DN_Str8NextLine (DN_Str8 string); +DN_API DN_Str8BSplitResult DN_Str8BSplitArray (DN_Str8 string, DN_Str8 const *find, DN_USize find_size); +DN_API DN_Str8BSplitResult DN_Str8BSplit (DN_Str8 string, DN_Str8 find); +DN_API DN_Str8BSplitResult DN_Str8BSplitLastArray (DN_Str8 string, DN_Str8 const *find, DN_USize find_size); +DN_API DN_Str8BSplitResult DN_Str8BSplitLast (DN_Str8 string, DN_Str8 find); +DN_API DN_USize DN_Str8Split (DN_Str8 string, DN_Str8 delimiter, DN_Str8 *splits, DN_USize splits_count, DN_Str8SplitFlags mode); +DN_API DN_Str8SplitResult DN_Str8SplitArena (DN_Str8 string, DN_Str8 delimiter, DN_Str8SplitFlags mode, DN_Arena *arena); +DN_API DN_Str8FindResult DN_Str8FindStr8Array (DN_Str8 string, DN_Str8 const *find, DN_USize find_size, DN_Str8EqCase eq_case); +DN_API DN_Str8FindResult DN_Str8FindStr8 (DN_Str8 string, DN_Str8 find, DN_Str8EqCase eq_case); +DN_API DN_Str8FindResult DN_Str8Find (DN_Str8 string, DN_Str8FindFlag flags); +DN_API DN_Str8 DN_Str8Segment (DN_Arena *arena, DN_Str8 src, DN_USize segment_size, char segment_char); +DN_API DN_Str8 DN_Str8ReverseSegment (DN_Arena *arena, DN_Str8 src, DN_USize segment_size, char segment_char); +DN_API bool DN_Str8Eq (DN_Str8 lhs, DN_Str8 rhs, DN_Str8EqCase eq_case); +DN_API bool DN_Str8EqSensitive (DN_Str8 lhs, DN_Str8 rhs); +DN_API bool DN_Str8EqInsensitive (DN_Str8 lhs, DN_Str8 rhs); +DN_API bool DN_Str8StartsWith (DN_Str8 string, DN_Str8 prefix, DN_Str8EqCase eq_case); +DN_API bool DN_Str8StartsWithSensitive (DN_Str8 string, DN_Str8 prefix); +DN_API bool DN_Str8StartsWithInsensitive (DN_Str8 string, DN_Str8 prefix); +DN_API bool DN_Str8EndsWith (DN_Str8 string, DN_Str8 prefix, DN_Str8EqCase eq_case); +DN_API bool DN_Str8EndsWithSensitive (DN_Str8 string, DN_Str8 prefix); +DN_API bool DN_Str8EndsWithInsensitive (DN_Str8 string, DN_Str8 prefix); +DN_API bool DN_Str8HasChar (DN_Str8 string, char ch); -DN_API DN_Str8 DN_Str8TrimPrefix (DN_Str8 string, DN_Str8 prefix, DN_Str8EqCase eq_case); -DN_API DN_Str8 DN_Str8TrimPrefixSensitive (DN_Str8 string, DN_Str8 prefix); -DN_API DN_Str8 DN_Str8TrimPrefixInsensitive (DN_Str8 string, DN_Str8 prefix); -DN_API DN_Str8 DN_Str8TrimHexPrefix (DN_Str8 string); -DN_API DN_Str8 DN_Str8TrimSuffix (DN_Str8 string, DN_Str8 suffix, DN_Str8EqCase eq_case); -DN_API DN_Str8 DN_Str8TrimSuffixSensitive (DN_Str8 string, DN_Str8 suffix); -DN_API DN_Str8 DN_Str8TrimSuffixInsensitive (DN_Str8 string, DN_Str8 suffix); -DN_API DN_Str8 DN_Str8TrimAround (DN_Str8 string, DN_Str8 trim_string, DN_Str8EqCase eq_case); -DN_API DN_Str8 DN_Str8TrimAroundSensitive (DN_Str8 string, DN_Str8 trim_string); -DN_API DN_Str8 DN_Str8TrimAroundInsensitive (DN_Str8 string, DN_Str8 trim_string); -DN_API DN_Str8 DN_Str8TrimHeadWhitespace (DN_Str8 string); -DN_API DN_Str8 DN_Str8TrimTailWhitespace (DN_Str8 string); -DN_API DN_Str8 DN_Str8TrimWhitespaceAround (DN_Str8 string); -DN_API DN_Str8 DN_Str8TrimByteOrderMark (DN_Str8 string); +DN_API DN_Str8 DN_Str8TrimPrefix (DN_Str8 string, DN_Str8 prefix, DN_Str8EqCase eq_case); +DN_API DN_Str8 DN_Str8TrimPrefixSensitive (DN_Str8 string, DN_Str8 prefix); +DN_API DN_Str8 DN_Str8TrimPrefixInsensitive (DN_Str8 string, DN_Str8 prefix); +DN_API DN_Str8 DN_Str8TrimHexPrefix (DN_Str8 string); +DN_API DN_Str8 DN_Str8TrimSuffix (DN_Str8 string, DN_Str8 suffix, DN_Str8EqCase eq_case); +DN_API DN_Str8 DN_Str8TrimSuffixSensitive (DN_Str8 string, DN_Str8 suffix); +DN_API DN_Str8 DN_Str8TrimSuffixInsensitive (DN_Str8 string, DN_Str8 suffix); +DN_API DN_Str8 DN_Str8TrimAround (DN_Str8 string, DN_Str8 trim_string, DN_Str8EqCase eq_case); +DN_API DN_Str8 DN_Str8TrimAroundSensitive (DN_Str8 string, DN_Str8 trim_string); +DN_API DN_Str8 DN_Str8TrimAroundInsensitive (DN_Str8 string, DN_Str8 trim_string); +DN_API DN_Str8 DN_Str8TrimHeadWhitespace (DN_Str8 string); +DN_API DN_Str8 DN_Str8TrimTailWhitespace (DN_Str8 string); +DN_API DN_Str8 DN_Str8TrimWhitespaceAround (DN_Str8 string); +DN_API DN_Str8 DN_Str8TrimByteOrderMark (DN_Str8 string); -DN_API DN_Str8 DN_Str8FileNameFromPath (DN_Str8 path); -DN_API DN_Str8 DN_Str8FileNameNoExtension (DN_Str8 path); -DN_API DN_Str8 DN_Str8FilePathNoExtension (DN_Str8 path); -DN_API DN_Str8 DN_Str8FileExtension (DN_Str8 path); -DN_API DN_Str8 DN_Str8FileDirectoryFromPath (DN_Str8 path); -DN_API DN_Str8 DN_Str8AppendF (DN_Arena *arena, DN_Str8 string, char const *fmt, ...); -DN_API DN_Str8 DN_Str8AppendFV (DN_Arena *arena, DN_Str8 string, char const *fmt, va_list args); -DN_API DN_Str8 DN_Str8FillF (DN_Arena *arena, DN_USize count, char const *fmt, ...); -DN_API DN_Str8 DN_Str8FillFV (DN_Arena *arena, DN_USize count, char const *fmt, va_list args); -DN_API void DN_Str8Remove (DN_Str8 *string, DN_USize offset, DN_USize count); -DN_API DN_Str8 DN_Str8TruncateArena (DN_Str8 string, DN_USize max_count, DN_Str8 truncator, DN_Arena *arena); -DN_API DN_Str8TruncResult DN_Str8TruncMiddlePtr (DN_Str8 str8, DN_USize side_size, DN_Str8 truncator, char *dest, DN_USize dest_max); -DN_API DN_Str8TruncResult DN_Str8TruncMiddle (DN_Str8 str8, DN_USize side_size, DN_Str8 truncator, DN_Arena *arena); -DN_API DN_Str8 DN_Str8Lower (DN_Str8 string, DN_Arena *arena); -DN_API DN_Str8 DN_Str8Upper (DN_Str8 string, DN_Arena *arena); -DN_API DN_Str8 DN_Str8Replace (DN_Str8 string, DN_Str8 find, DN_Str8 replace, DN_USize start_index, DN_Arena *arena, DN_Str8EqCase eq_case); -DN_API DN_Str8 DN_Str8ReplaceSensitive (DN_Str8 string, DN_Str8 find, DN_Str8 replace, DN_USize start_index, DN_Arena *arena); -DN_API DN_Str8 DN_Str8ReplaceInsensitive (DN_Str8 string, DN_Str8 find, DN_Str8 replace, DN_USize start_index, DN_Arena *arena); -DN_API DN_Str8 DN_Str8PadNewLinesAllocator (DN_Str8 string, DN_Str8 pad_string, DN_Allocator allocator); -DN_API DN_Str8 DN_Str8PadNewLinesArena (DN_Str8 string, DN_Str8 pad_string, DN_Arena *arena); -DN_API DN_Str8 DN_Str8LineBreakAllocator (DN_Str8 src, DN_USize desired_width, DN_Str8 delimiter, DN_Str8LineBreakMode mode, DN_Allocator allocator); -DN_API DN_Str8 DN_Str8LineBreakArena (DN_Str8 src, DN_USize desired_width, DN_Str8 delimiter, DN_Str8LineBreakMode mode, DN_Arena *arena); -DN_API DN_Str8 DN_Str8Table (DN_Str8 const* rows, DN_USize num_rows, DN_USize num_cols, DN_Str8TableFlags flags, DN_Arena *arena); +DN_API DN_Str8 DN_Str8FileNameFromPath (DN_Str8 path); +DN_API DN_Str8 DN_Str8FileNameNoExtension (DN_Str8 path); +DN_API DN_Str8 DN_Str8FilePathNoExtension (DN_Str8 path); +DN_API DN_Str8 DN_Str8FileExtension (DN_Str8 path); +DN_API DN_Str8 DN_Str8FileDirectoryFromPath (DN_Str8 path); +DN_API DN_Str8 DN_Str8AppendF (DN_Arena *arena, DN_Str8 string, char const *fmt, ...); +DN_API DN_Str8 DN_Str8AppendFV (DN_Arena *arena, DN_Str8 string, char const *fmt, va_list args); +DN_API DN_Str8 DN_Str8FillF (DN_Arena *arena, DN_USize count, char const *fmt, ...); +DN_API DN_Str8 DN_Str8FillFV (DN_Arena *arena, DN_USize count, char const *fmt, va_list args); +DN_API void DN_Str8Remove (DN_Str8 *string, DN_USize offset, DN_USize count); +DN_API DN_Str8 DN_Str8TruncateArena (DN_Str8 string, DN_USize max_count, DN_Str8 truncator, DN_Arena *arena); +DN_API DN_Str8TruncResult DN_Str8TruncMiddlePtr (DN_Str8 str8, DN_USize side_size, DN_Str8 truncator, char *dest, DN_USize dest_max); +DN_API DN_Str8TruncResult DN_Str8TruncMiddle (DN_Str8 str8, DN_USize side_size, DN_Str8 truncator, DN_Arena *arena); +DN_API DN_Str8 DN_Str8Lower (DN_Str8 string, DN_Arena *arena); +DN_API DN_Str8 DN_Str8Upper (DN_Str8 string, DN_Arena *arena); +DN_API DN_Str8 DN_Str8Replace (DN_Str8 string, DN_Str8 find, DN_Str8 replace, DN_USize start_index, DN_Arena *arena, DN_Str8EqCase eq_case); +DN_API DN_Str8 DN_Str8ReplaceSensitive (DN_Str8 string, DN_Str8 find, DN_Str8 replace, DN_USize start_index, DN_Arena *arena); +DN_API DN_Str8 DN_Str8ReplaceInsensitive (DN_Str8 string, DN_Str8 find, DN_Str8 replace, DN_USize start_index, DN_Arena *arena); +DN_API DN_Str8 DN_Str8PadNewLinesAllocator (DN_Str8 string, DN_Str8 pad_string, DN_Allocator allocator); +DN_API DN_Str8 DN_Str8PadNewLinesArena (DN_Str8 string, DN_Str8 pad_string, DN_Arena *arena); +DN_API DN_Str8 DN_Str8LineBreakAllocator (DN_Str8 src, DN_USize desired_width, DN_Str8 delimiter, DN_Str8LineBreakMode mode, DN_Allocator allocator); +DN_API DN_Str8 DN_Str8LineBreakArena (DN_Str8 src, DN_USize desired_width, DN_Str8 delimiter, DN_Str8LineBreakMode mode, DN_Arena *arena); +DN_API DN_Str8 DN_Str8Table (DN_Str8 const* rows, DN_USize num_rows, DN_USize num_cols, DN_Str8TableFlags flags, DN_Arena *arena); #if DN_WITH_STR8_AVX512F -DN_API DN_Str8FindResult DN_Str8FindStr8AVX512F (DN_Str8 string, DN_Str8 find); -DN_API DN_Str8FindResult DN_Str8FindLastStr8AVX512F (DN_Str8 string, DN_Str8 find); -DN_API DN_Str8BSplitResult DN_Str8BSplitAVX512F (DN_Str8 string, DN_Str8 find); -DN_API DN_Str8BSplitResult DN_Str8BSplitLastAVX512F (DN_Str8 string, DN_Str8 find); -DN_API DN_USize DN_Str8SplitAVX512F (DN_Str8 string, DN_Str8 delimiter, DN_Str8 *splits, DN_USize splits_count, DN_Str8SplitFlags flags); -DN_API DN_Str8Slice DN_Str8SplitAllocAVX512F (DN_Arena *arena, DN_Str8 string, DN_Str8 delimiter, DN_Str8SplitFlags flags); +DN_API DN_Str8FindResult DN_Str8FindStr8AVX512F (DN_Str8 string, DN_Str8 find); +DN_API DN_Str8FindResult DN_Str8FindLastStr8AVX512F (DN_Str8 string, DN_Str8 find); +DN_API DN_Str8BSplitResult DN_Str8BSplitAVX512F (DN_Str8 string, DN_Str8 find); +DN_API DN_Str8BSplitResult DN_Str8BSplitLastAVX512F (DN_Str8 string, DN_Str8 find); +DN_API DN_USize DN_Str8SplitAVX512F (DN_Str8 string, DN_Str8 delimiter, DN_Str8 *splits, DN_USize splits_count, DN_Str8SplitFlags flags); +DN_API DN_Str8Slice DN_Str8SplitAllocAVX512F (DN_Arena *arena, DN_Str8 string, DN_Str8 delimiter, DN_Str8SplitFlags flags); #endif -DN_API DN_Str8 DN_Str8SliceRender (DN_Str8Slice array, DN_Str8 seperator, DN_Arena *arena); -DN_API DN_Str8 DN_Str8RenderSpaceSep (DN_Str8Slice array, DN_Arena *arena); -DN_API int DN_Str8CompareNatural (DN_Str8 lhs, DN_Str8 rhs, DN_Str8EqCase eq_case); -DN_API int DN_Str8CompareLexicographic (DN_Str8 lhs, DN_Str8 rhs, DN_Str8EqCase eq_case); +DN_API DN_Str8 DN_Str8SliceRender (DN_Str8Slice array, DN_Str8 seperator, DN_Arena *arena); +DN_API DN_Str8 DN_Str8RenderSpaceSep (DN_Str8Slice array, DN_Arena *arena); +DN_API int DN_Str8CompareNatural (DN_Str8 lhs, DN_Str8 rhs, DN_Str8EqCase eq_case); +DN_API int DN_Str8CompareLexicographic (DN_Str8 lhs, DN_Str8 rhs, DN_Str8EqCase eq_case); -DN_API bool DN_Str16Eq (DN_Str16 lhs, DN_Str16 rhs); -DN_API DN_Str16 DN_Str16SliceRender (DN_Str16Slice array, DN_Str16 seperator, DN_Arena *arena); -DN_API DN_Str16 DN_Str16RenderSpaceSep (DN_Str16Slice array, DN_Arena *arena); +DN_API bool DN_Str16Eq (DN_Str16 lhs, DN_Str16 rhs); +DN_API DN_Str16 DN_Str16SliceRender (DN_Str16Slice array, DN_Str16 seperator, DN_Arena *arena); +DN_API DN_Str16 DN_Str16RenderSpaceSep (DN_Str16Slice array, DN_Arena *arena); -DN_API DN_Str8Builder DN_Str8BuilderFromArena (DN_Arena *arena); -DN_API DN_Str8Builder DN_Str8BuilderFromStr8PtrRef (DN_Arena *arena, DN_Str8 const *strings, DN_USize count); -DN_API DN_Str8Builder DN_Str8BuilderFromStr8PtrCopy (DN_Arena *arena, DN_Str8 const *strings, DN_USize count); -DN_API DN_Str8Builder DN_Str8BuilderFromBuilder (DN_Arena *arena, DN_Str8Builder const *builder); -DN_API bool DN_Str8BuilderAddArrayRef (DN_Str8Builder *builder, DN_Str8 const *strings, DN_USize count, DN_AddType add); -DN_API bool DN_Str8BuilderAddArrayCopy (DN_Str8Builder *builder, DN_Str8 const *strings, DN_USize count, DN_AddType add); -DN_API bool DN_Str8BuilderAddFV (DN_Str8Builder *builder, DN_AddType add, DN_FMT_ATTRIB char const *fmt, va_list args); -#define DN_Str8BuilderAppendArrayRef(builder, strings, size) DN_Str8BuilderAddArrayRef(builder, strings, size, DN_AddType_Append) -#define DN_Str8BuilderAppendArrayCopy(builder, strings, size) DN_Str8BuilderAddArrayCopy(builder, strings, size, DN_AddType_Append) -#define DN_Str8BuilderAppendSliceRef(builder, slice) DN_Str8BuilderAddArrayRef(builder, slice.data, slice.count, DN_AddType_Append) -#define DN_Str8BuilderAppendSliceCopy(builder, slice) DN_Str8BuilderAddArrayCopy(builder, slice.data, slice.count, DN_AddType_Append) -DN_API bool DN_Str8BuilderAppendRef (DN_Str8Builder *builder, DN_Str8 string); -DN_API bool DN_Str8BuilderAppendCopy (DN_Str8Builder *builder, DN_Str8 string); -#define DN_Str8BuilderAppendFV(builder, fmt, args) DN_Str8BuilderAddFV(builder, DN_AddType_Append, fmt, args) -DN_API bool DN_Str8BuilderAppendF (DN_Str8Builder *builder, DN_FMT_ATTRIB char const *fmt, ...); -DN_API bool DN_Str8BuilderAppendBytesRef (DN_Str8Builder *builder, void const *ptr, DN_USize count); -DN_API bool DN_Str8BuilderAppendBytesCopy (DN_Str8Builder *builder, void const *ptr, DN_USize count); -DN_API bool DN_Str8BuilderAppendBuilderRef (DN_Str8Builder *dest, DN_Str8Builder const *src); -DN_API bool DN_Str8BuilderAppendBuilderCopy (DN_Str8Builder *dest, DN_Str8Builder const *src); -#define DN_Str8BuilderPrependArrayRef(builder, strings, size) DN_Str8BuilderAddArrayRef(builder, strings, size, DN_AddType_Prepend) -#define DN_Str8BuilderPrependArrayCopy(builder, strings, size) DN_Str8BuilderAddArrayCopy(builder, strings, size, DN_AddType_Prepend) -#define DN_Str8BuilderPrependSliceRef(builder, slice) DN_Str8BuilderAddArrayRef(builder, slice.data, slice.count, DN_AddType_Prepend) -#define DN_Str8BuilderPrependSliceCopy(builder, slice) DN_Str8BuilderAddArrayCopy(builder, slice.data, slice.count, DN_AddType_Prepend) -DN_API bool DN_Str8BuilderPrependRef (DN_Str8Builder *builder, DN_Str8 string); -DN_API bool DN_Str8BuilderPrependCopy (DN_Str8Builder *builder, DN_Str8 string); -#define DN_Str8BuilderPrependFV(builder, fmt, args) DN_Str8BuilderAddFV(builder, DN_AddType_Prepend, fmt, args) -DN_API bool DN_Str8BuilderPrependF (DN_Str8Builder *builder, DN_FMT_ATTRIB char const *fmt, ...); -DN_API bool DN_Str8BuilderErase (DN_Str8Builder *builder, DN_Str8 string); -DN_API DN_Str8 DN_Str8FromStr8BuilderAllocator (DN_Str8Builder const *builder, DN_Allocator allocator); -DN_API DN_Str8 DN_Str8FromStr8BuilderArena (DN_Str8Builder const *builder, DN_Arena *arena); -DN_API DN_Str8 DN_Str8FromStr8BuilderDelimitAllocator (DN_Str8Builder const *builder, DN_Str8 delimiter, DN_Allocator allocator); -DN_API DN_Str8 DN_Str8FromStr8BuilderDelimitArena (DN_Str8Builder const *builder, DN_Str8 delimiter, DN_Arena *arena); +DN_API DN_Str8Builder DN_Str8BuilderFromArena (DN_Arena *arena); +DN_API DN_Str8Builder DN_Str8BuilderFromStr8PtrRef (DN_Arena *arena, DN_Str8 const *strings, DN_USize count); +DN_API DN_Str8Builder DN_Str8BuilderFromStr8PtrCopy (DN_Arena *arena, DN_Str8 const *strings, DN_USize count); +DN_API DN_Str8Builder DN_Str8BuilderFromBuilder (DN_Arena *arena, DN_Str8Builder const *builder); +DN_API bool DN_Str8BuilderAddArrayRef (DN_Str8Builder *builder, DN_Str8 const *strings, DN_USize count, DN_AddType add); +DN_API bool DN_Str8BuilderAddArrayCopy (DN_Str8Builder *builder, DN_Str8 const *strings, DN_USize count, DN_AddType add); +DN_API bool DN_Str8BuilderAddFV (DN_Str8Builder *builder, DN_AddType add, DN_FMT_ATTRIB char const *fmt, va_list args); +#define DN_Str8BuilderAppendArrayRef(builder, strings, size) DN_Str8BuilderAddArrayRef(builder, strings, size, DN_AddType_Append) +#define DN_Str8BuilderAppendArrayCopy(builder, strings, size) DN_Str8BuilderAddArrayCopy(builder, strings, size, DN_AddType_Append) +#define DN_Str8BuilderAppendSliceRef(builder, slice) DN_Str8BuilderAddArrayRef(builder, slice.data, slice.count, DN_AddType_Append) +#define DN_Str8BuilderAppendSliceCopy(builder, slice) DN_Str8BuilderAddArrayCopy(builder, slice.data, slice.count, DN_AddType_Append) +DN_API bool DN_Str8BuilderAppendRef (DN_Str8Builder *builder, DN_Str8 string); +DN_API bool DN_Str8BuilderAppendCopy (DN_Str8Builder *builder, DN_Str8 string); +#define DN_Str8BuilderAppendFV(builder, fmt, args) DN_Str8BuilderAddFV(builder, DN_AddType_Append, fmt, args) +DN_API bool DN_Str8BuilderAppendF (DN_Str8Builder *builder, DN_FMT_ATTRIB char const *fmt, ...); +DN_API bool DN_Str8BuilderAppendBytesRef (DN_Str8Builder *builder, void const *ptr, DN_USize count); +DN_API bool DN_Str8BuilderAppendBytesCopy (DN_Str8Builder *builder, void const *ptr, DN_USize count); +DN_API bool DN_Str8BuilderAppendBuilderRef (DN_Str8Builder *dest, DN_Str8Builder const *src); +DN_API bool DN_Str8BuilderAppendBuilderCopy (DN_Str8Builder *dest, DN_Str8Builder const *src); +#define DN_Str8BuilderPrependArrayRef(builder, strings, size) DN_Str8BuilderAddArrayRef(builder, strings, size, DN_AddType_Prepend) +#define DN_Str8BuilderPrependArrayCopy(builder, strings, size) DN_Str8BuilderAddArrayCopy(builder, strings, size, DN_AddType_Prepend) +#define DN_Str8BuilderPrependSliceRef(builder, slice) DN_Str8BuilderAddArrayRef(builder, slice.data, slice.count, DN_AddType_Prepend) +#define DN_Str8BuilderPrependSliceCopy(builder, slice) DN_Str8BuilderAddArrayCopy(builder, slice.data, slice.count, DN_AddType_Prepend) +DN_API bool DN_Str8BuilderPrependRef (DN_Str8Builder *builder, DN_Str8 string); +DN_API bool DN_Str8BuilderPrependCopy (DN_Str8Builder *builder, DN_Str8 string); +#define DN_Str8BuilderPrependFV(builder, fmt, args) DN_Str8BuilderAddFV(builder, DN_AddType_Prepend, fmt, args) +DN_API bool DN_Str8BuilderPrependF (DN_Str8Builder *builder, DN_FMT_ATTRIB char const *fmt, ...); +DN_API bool DN_Str8BuilderErase (DN_Str8Builder *builder, DN_Str8 string); +DN_API DN_Str8 DN_Str8FromStr8BuilderAllocator (DN_Str8Builder const *builder, DN_Allocator allocator); +DN_API DN_Str8 DN_Str8FromStr8BuilderArena (DN_Str8Builder const *builder, DN_Arena *arena); +DN_API DN_Str8 DN_Str8FromStr8BuilderDelimitAllocator (DN_Str8Builder const *builder, DN_Str8 delimiter, DN_Allocator allocator); +DN_API DN_Str8 DN_Str8FromStr8BuilderDelimitArena (DN_Str8Builder const *builder, DN_Str8 delimiter, DN_Arena *arena); -DN_API bool DN_PathAddRef (DN_Path *path, DN_Str8 add, DN_Arena *arena); -DN_API bool DN_PathAdd (DN_Path *path, DN_Str8 add, DN_Arena *arena); -DN_API bool DN_PathAddF (DN_Path *path, DN_FMT_ATTRIB char const *fmt, ...); -DN_API bool DN_PathPop (DN_Path *path); -DN_API DN_Str8 DN_Str8FromPath (DN_Path const *path, DN_Str8 path_seperator, DN_Allocator allocator); -DN_API DN_Str8 DN_Str8FmtPathVArena (DN_Str8 path_seperator, DN_Arena *arena, char const *fmt, va_list args); -DN_API DN_Str8 DN_Str8FmtPathArena (DN_Str8 path_seperator, DN_Arena *arena, DN_FMT_ATTRIB char const *fmt, ...); -DN_API DN_Str8 DN_Str8FmtPathVPool (DN_Str8 path_seperator, DN_Pool *pool, char const *fmt, va_list args); -DN_API DN_Str8 DN_Str8FmtPathPool (DN_Str8 path_seperator, DN_Pool *pool, DN_FMT_ATTRIB char const *fmt, ...); -DN_API DN_Str8 DN_Str8FmtOsPathArena (DN_Arena *arena, DN_FMT_ATTRIB char const *fmt, ...); -DN_API DN_Str8 DN_Str8FmtOsPathPool (DN_Pool *pool, DN_FMT_ATTRIB char const *fmt, ...); +DN_API bool DN_PathAddRef (DN_Path *path, DN_Str8 add, DN_Arena *arena); +DN_API bool DN_PathAdd (DN_Path *path, DN_Str8 add, DN_Arena *arena); +DN_API bool DN_PathAddF (DN_Path *path, DN_FMT_ATTRIB char const *fmt, ...); +DN_API bool DN_PathPop (DN_Path *path); +DN_API DN_Str8Path DN_Str8PathFromPath (DN_Path const *path, DN_Str8 path_seperator, DN_Allocator allocator); +DN_API DN_Str8Path DN_Str8PathFmtVArena (DN_Str8 path_seperator, DN_Arena *arena, char const *fmt, va_list args); +DN_API DN_Str8Path DN_Str8PathFmtArena (DN_Str8 path_seperator, DN_Arena *arena, DN_FMT_ATTRIB char const *fmt, ...); +DN_API DN_Str8Path DN_Str8PathFmtVPool (DN_Str8 path_seperator, DN_Pool *pool, char const *fmt, va_list args); +DN_API DN_Str8Path DN_Str8PathFmtPool (DN_Str8 path_seperator, DN_Pool *pool, DN_FMT_ATTRIB char const *fmt, ...); +DN_API DN_Str8Path DN_Str8PathFmtOsArena (DN_Arena *arena, DN_FMT_ATTRIB char const *fmt, ...); +DN_API DN_Str8Path DN_Str8PathFmtOsPool (DN_Pool *pool, DN_FMT_ATTRIB char const *fmt, ...); -DN_API DN_USize DN_Utf8FromUtf32 (DN_U8 utf8[4], DN_U32 codepoint); -DN_API bool DN_Utf32IsAlphabet (DN_U32 codepoint); -DN_API bool DN_Utf32IsDigit (DN_U32 codepoint); -DN_API bool DN_Utf32IsAlphaNum (DN_U32 codepoint); -DN_API bool DN_Utf32IsWhitespace (DN_U32 codepoint); -DN_API bool DN_Utf32IsHex (DN_U32 codepoint); -DN_API bool DN_Utf32IsWordCharacter (DN_U32 codepoint); -DN_API DN_U32 DN_Utf32ToLower (DN_U32 codepoint); -DN_API DN_U32 DN_Utf32ToUpper (DN_U32 codepoint); -DN_API DN_USize DN_Utf32FromUtf16 (DN_U16 utf16[2], DN_U32 codepoint); -DN_API DN_Utf32FromResult DN_Utf32FromUtf8Stream (DN_Str8 stream); -DN_API bool DN_Utf32FromUtf8Iterate (DN_Utf32FromUtf8Iterator *it, DN_Utf32IterateDir dir, DN_Str8 utf8); -DN_API DN_USize DN_Utf32CodepointCountFromUtf8 (DN_Str8 str, DN_CodepointCountFlags flags); +DN_API DN_USize DN_Utf8FromUtf32 (DN_U8 utf8[4], DN_U32 codepoint); +DN_API bool DN_Utf32IsAlphabet (DN_U32 codepoint); +DN_API bool DN_Utf32IsDigit (DN_U32 codepoint); +DN_API bool DN_Utf32IsAlphaNum (DN_U32 codepoint); +DN_API bool DN_Utf32IsWhitespace (DN_U32 codepoint); +DN_API bool DN_Utf32IsHex (DN_U32 codepoint); +DN_API bool DN_Utf32IsWordCharacter (DN_U32 codepoint); +DN_API DN_U32 DN_Utf32ToLower (DN_U32 codepoint); +DN_API DN_U32 DN_Utf32ToUpper (DN_U32 codepoint); +DN_API DN_USize DN_Utf32FromUtf16 (DN_U16 utf16[2], DN_U32 codepoint); +DN_API DN_Utf32FromResult DN_Utf32FromUtf8Stream (DN_Str8 stream); +DN_API bool DN_Utf32FromUtf8Iterate (DN_Utf32FromUtf8Iterator *it, DN_Utf32IterateDir dir, DN_Str8 utf8); +DN_API DN_USize DN_Utf32CodepointCountFromUtf8 (DN_Str8 str, DN_CodepointCountFlags flags); -DN_API DN_U8 DN_U8FromHexNibble (char hex); -DN_API DN_NibbleFromU8Result DN_NibbleFromU8 (DN_U8 u8); +DN_API DN_U8 DN_U8FromHexNibble (char hex); +DN_API DN_NibbleFromU8Result DN_NibbleFromU8 (DN_U8 u8); -DN_API DN_USize DN_PtrBytesFromStr8Hex (DN_Str8 hex, void *dest, DN_USize dest_count); -DN_API DN_USize DN_PtrBytesFromPtrHex (char const *hex, DN_USize hex_count, void *dest, DN_USize dest_count); -DN_API DN_Str8 DN_Str8BytesFromStr8HexArena (DN_Str8 hex, DN_Arena *arena); -DN_API DN_Str8 DN_Str8BytesFromPtrHexArena (char const *hex, DN_USize hex_count, DN_Arena *arena); -DN_API DN_Str8 DN_Str8BytesFromPtrHexPool (char const *hex, DN_USize hex_count, DN_Pool *pool); -DN_API DN_U8x16 DN_U8x16FromPtrHex32 (char const *hex, DN_USize hex_count); -DN_API DN_U8x32 DN_U8x32FromPtrHex64 (char const *hex, DN_USize hex_count); +DN_API DN_USize DN_PtrBytesFromStr8Hex (DN_Str8 hex, void *dest, DN_USize dest_count); +DN_API DN_USize DN_PtrBytesFromPtrHex (char const *hex, DN_USize hex_count, void *dest, DN_USize dest_count); +DN_API DN_Str8 DN_Str8BytesFromStr8HexArena (DN_Str8 hex, DN_Arena *arena); +DN_API DN_Str8 DN_Str8BytesFromPtrHexArena (char const *hex, DN_USize hex_count, DN_Arena *arena); +DN_API DN_Str8 DN_Str8BytesFromPtrHexPool (char const *hex, DN_USize hex_count, DN_Pool *pool); +DN_API DN_U8x16 DN_U8x16FromPtrHex32 (char const *hex, DN_USize hex_count); +DN_API DN_U8x32 DN_U8x32FromPtrHex64 (char const *hex, DN_USize hex_count); -DN_API DN_HexU64 DN_HexU64FromU64 (DN_U64 value, DN_HexFromU64Type type); -DN_API DN_USize DN_PtrHexFromPtrBytes (void const *bytes, DN_USize bytes_count, void *hex, DN_USize hex_count, DN_TrimLeadingZero trim_leading_z); -DN_API DN_USize DN_PtrHexFromStr8Bytes (DN_Str8 bytes, void *hex, DN_USize hex_count, DN_TrimLeadingZero trim_leading_z); -DN_API DN_Str8 DN_Str8HexFromPtrBytesArena (void const *bytes, DN_USize bytes_count, DN_Arena *arena, DN_TrimLeadingZero trim_leading_z); -DN_API DN_Str8 DN_Str8HexFromStr8BytesArena (DN_Str8 bytes, DN_Arena *arena, DN_TrimLeadingZero trim_leading_z); -DN_API DN_Hex32 DN_Hex32FromPtrBytes16 (void const *bytes, DN_USize bytes_count, DN_TrimLeadingZero trim_leading_z); -DN_API DN_Hex64 DN_Hex64FromPtrBytes32 (void const *bytes, DN_USize bytes_count, DN_TrimLeadingZero trim_leading_z); -DN_API DN_Hex64 DN_Hex64FromU8x32 (DN_U8x32 const *value, DN_TrimLeadingZero trim_leading_z); -DN_API DN_Hex128 DN_Hex128FromPtrBytes64 (void const *bytes, DN_USize bytes_count, DN_TrimLeadingZero trim_leading_z); +DN_API DN_HexU64 DN_HexU64FromU64 (DN_U64 value, DN_HexFromU64Type type); +DN_API DN_USize DN_PtrHexFromPtrBytes (void const *bytes, DN_USize bytes_count, void *hex, DN_USize hex_count, DN_TrimLeadingZero trim_leading_z); +DN_API DN_USize DN_PtrHexFromStr8Bytes (DN_Str8 bytes, void *hex, DN_USize hex_count, DN_TrimLeadingZero trim_leading_z); +DN_API DN_Str8 DN_Str8HexFromPtrBytesArena (void const *bytes, DN_USize bytes_count, DN_Arena *arena, DN_TrimLeadingZero trim_leading_z); +DN_API DN_Str8 DN_Str8HexFromStr8BytesArena (DN_Str8 bytes, DN_Arena *arena, DN_TrimLeadingZero trim_leading_z); +DN_API DN_Hex32 DN_Hex32FromPtrBytes16 (void const *bytes, DN_USize bytes_count, DN_TrimLeadingZero trim_leading_z); +DN_API DN_Hex64 DN_Hex64FromPtrBytes32 (void const *bytes, DN_USize bytes_count, DN_TrimLeadingZero trim_leading_z); +DN_API DN_Hex64 DN_Hex64FromU8x32 (DN_U8x32 const *value, DN_TrimLeadingZero trim_leading_z); +DN_API DN_Hex128 DN_Hex128FromPtrBytes64 (void const *bytes, DN_USize bytes_count, DN_TrimLeadingZero trim_leading_z); -DN_API DN_Str8x128 DN_AgeStr8FromMsU64 (DN_U64 duration_ms, DN_AgeUnit units); -DN_API DN_Str8x128 DN_AgeStr8FromSecU64 (DN_U64 duration_ms, DN_AgeUnit units); -DN_API DN_Str8x128 DN_AgeStr8FromSecF64 (DN_F64 sec, DN_AgeUnit units); +DN_API DN_Str8x128 DN_AgeStr8FromMsU64 (DN_U64 duration_ms, DN_AgeUnit units); +DN_API DN_Str8x128 DN_AgeStr8FromSecU64 (DN_U64 duration_ms, DN_AgeUnit units); +DN_API DN_Str8x128 DN_AgeStr8FromSecF64 (DN_F64 sec, DN_AgeUnit units); -DN_API int DN_IsLeapYear (int year); -DN_API bool DN_DateIsValid (DN_Date date); -DN_API DN_Date DN_DateFromUnixTimeMs (DN_USize unix_ts_ms); -DN_API DN_U64 DN_UnixTimeMsFromDate (DN_Date date); +DN_API int DN_IsLeapYear (int year); +DN_API bool DN_DateIsValid (DN_Date date); +DN_API DN_Date DN_DateFromUnixTimeMs (DN_USize unix_ts_ms); +DN_API DN_U64 DN_UnixTimeMsFromDate (DN_Date date); -DN_API DN_Str8 DN_Str8FromByteType (DN_ByteType type); -DN_API DN_ByteCount DN_ByteCountFromU64 (DN_U64 byte_count, DN_ByteType type); -DN_API DN_Str8x32 DN_Str8x32FromByteCountU64 (DN_U64 byte_count, DN_ByteType type); -#define DN_Str8x32FromByteCountU64Auto(bytes) DN_Str8x32FromByteCountU64(bytes, DN_ByteType_Auto) +DN_API DN_Str8 DN_Str8FromByteType (DN_ByteType type); +DN_API DN_ByteCount DN_ByteCountFromU64 (DN_U64 byte_count, DN_ByteType type); +DN_API DN_Str8x32 DN_Str8x32FromByteCountU64 (DN_U64 byte_count, DN_ByteType type); +#define DN_Str8x32FromByteCountU64Auto(bytes) DN_Str8x32FromByteCountU64(bytes, DN_ByteType_Auto) // NOTE: Profiler // Overview @@ -3479,8 +3700,8 @@ DN_API DN_Str8x32 DN_Str8x32FromByteCountU64 // API // DN_ProfilerInit // You can set `tsc_now` to NULL to use the default timer mechanic which relies on -// DN_CPUGetTsc() which essentially uses __rdtsc. `tsc_frequency` must however always be -// provided, for, DN_CPUGetTsc() you can use `DN_OS_EstimateTscPerSecond()` to calculate the +// DN_CpuTscNow() which essentially uses __rdtsc. `tsc_frequency` must however always be +// provided, for, DN_CpuTscNow() you can use `DN_OS_EstimateTscPerSecond()` to calculate the // frequency of `__rdtsc`. // DN_ProfilerNewFrame // Always call `DN_ProfilerNewFrame` at-least once using the `Zone` family of functions as it @@ -3525,12 +3746,7 @@ DN_API DN_V2USize DN_Profiler2MarkerOffsetFromFrame DN_API DN_Profiler2Marker* DN_Profiler2MarkerFromFrameIndex (DN_Profiler2 *profiler, DN_Profiler2Frame *frame, DN_U32 index); DN_API void DN_QSort_ (void *array, DN_USize array_size, DN_USize elem_size, void *user_context, DN_QSortCompareFunc *compare); -#if defined(__cplusplus) -template void DN_QSortT (T *array, DN_USize array_size, void *user_context, DN_QSortCompareFunc *compare); -#define DN_QSort(array, array_size, user_context, compare) DN_QSortT(array, array_size, user_context, compare) -#else #define DN_QSort(array, array_size, user_context, compare) DN_QSort_(array, array_size, sizeof(*array), user_context, compare) -#endif DN_API bool DN_QSortCompareStr8NaturalAsc (void const* lhs, void const *rhs, void *user_context); DN_API bool DN_QSortCompareStr8NaturalDesc (void const* lhs, void const *rhs, void *user_context); @@ -3612,32 +3828,30 @@ DN_API DN_LogTypeParam DN_LogTypeParamFromType // NOTE: OS primitives that the OS layer can provide for the base layer but is optional. -#if defined(DN_FREESTANDING) -#define DN_StackTraceFromArena(...) {} -#define DN_StackTraceFromAllocator(...) {} -#define DN_StackTraceIterate(...) false -#define DN_Str8FromStackTraceAllocator(...) DN_Str8Lit("N/A") -#define DN_Str8FromStackTraceArena(...) DN_Str8Lit("N/A") -#define DN_Str8FromStackTraceNowAllocator(...) DN_Str8Lit("N/A") -#define DN_Str8FromStackTraceNowArena(...) DN_Str8Lit("N/A") -#define DN_Str8FromStackTraceNowHeap(...) DN_Str8Lit("N/A") -#define DN_StackTraceGetFrames(...) -#define DN_StackTraceRawFrameToFrame(...) -#define DN_StackTracePrint(...) -#define DN_StackTraceReloadSymbols(...) +#if DN_WITH_OS +DN_API DN_StackTrace DN_StackTraceFromAllocator (DN_Allocator allocator, DN_U16 limit); +DN_API DN_StackTrace DN_StackTraceFromArena (DN_Arena *arena, DN_U16 limit); +DN_API bool DN_StackTraceIterate (DN_StackTraceIterator *it, DN_StackTrace const *walk); +DN_API DN_Str8 DN_Str8FromStackTraceAllocator (DN_Allocator allocator, DN_StackTrace const *walk, DN_U16 skip); +DN_API DN_Str8 DN_Str8FromStackTraceArena (DN_Arena *arena, DN_StackTrace const *walk, DN_U16 skip); +DN_API DN_Str8 DN_Str8FromStackTraceNowAllocator (DN_Arena *arena, DN_U16 limit, DN_U16 skip); +DN_API DN_Str8 DN_Str8FromStackTraceNowArena (DN_Arena *arena, DN_U16 limit, DN_U16 skip); +DN_API DN_StackTraceFrameSlice DN_StackTraceGetFrames (DN_Arena *arena, DN_U16 limit); +DN_API DN_StackTraceFrame DN_StackTraceFrameFromRawFrame (DN_Arena *arena, DN_StackTraceRawFrame raw_frame); +DN_API void DN_StackTracePrint (DN_U16 limit); +DN_API void DN_StackTraceReloadSymbols (); #else -DN_API DN_StackTrace DN_StackTraceFromArena (DN_Arena *arena, DN_U16 limit); -DN_API DN_StackTrace DN_StackTraceFromAllocator (DN_Allocator allocator, DN_U16 limit); -DN_API bool DN_StackTraceIterate (DN_StackTraceIterator *it, DN_StackTrace const *walk); -DN_API DN_Str8 DN_Str8FromStackTraceAllocator (DN_Allocator allocator, DN_StackTrace const *walk, DN_U16 skip); -DN_API DN_Str8 DN_Str8FromStackTraceArena (DN_Arena *arena, DN_StackTrace const *walk, DN_U16 skip); -DN_API DN_Str8 DN_Str8FromStackTraceNowAllocator (DN_Arena *arena, DN_U16 limit, DN_U16 skip); -DN_API DN_Str8 DN_Str8FromStackTraceNowArena (DN_Arena *arena, DN_U16 limit, DN_U16 skip); -DN_API DN_Str8 DN_Str8FromStackTraceNowHeap (DN_U16 limit, DN_U16 skip); -DN_API DN_StackTraceFrameSlice DN_StackTraceGetFrames (DN_Arena *arena, DN_U16 limit); -DN_API DN_StackTraceFrame DN_StackTraceRawFrameToFrame (DN_Arena *arena, DN_StackTraceRawFrame raw_frame); -DN_API void DN_StackTracePrint (DN_U16 limit); -DN_API void DN_StackTraceReloadSymbols (); +#define DN_StackTraceFromAllocator(...) {} +#define DN_StackTraceFromArena(...) {} +#define DN_StackTraceIterate(...) false +#define DN_Str8FromStackTraceAllocator(...) {} +#define DN_Str8FromStackTraceArena(...) {} +#define DN_Str8FromStackTraceNowAllocator(...) {} +#define DN_Str8FromStackTraceNowArena(...) {} +#define DN_StackTraceGetFrames(...) {} +#define DN_StackTraceFrameFromRawFrame(...) {} +#define DN_StackTracePrint(...) +#define DN_StackTraceReloadSymbols(...) #endif DN_API DN_F32 DN_F32Lerp (DN_F32 a, DN_F32 t, DN_F32 b); @@ -3831,6 +4045,9 @@ DN_API DN_V3F32 DN_V3F32Normalise #define DN_V4F32FromRgba255ToRgba01(r, g, b, a) DN_Literal(DN_V4F32){{r / 255.f, g / 255.f, b / 255.f, a / 255.f}} #define DN_V4F32FromRgb255ToRgba01(r, g, b) DN_Literal(DN_V4F32){{r / 255.f, g / 255.f, b / 255.f, 1.f}} +#define DN_V4F32Zero DN_V4F32From1N(0) +#define DN_V4F32One DN_V4F32From1N(1) + DN_API DN_V4F32 DN_V4F32Lerp (DN_V4F32 lhs, DN_F32 t01, DN_V4F32 rhs); DN_API bool DN_V4F32Rgba01IsValid (DN_V4F32 rgba01); DN_API DN_V4F32 DN_V4F32FromRgbU32ToRgba01 (DN_U32 u32); @@ -4285,129 +4502,160 @@ DN_API DN_RaycastV2 DN_RaycastLineIntersectV2 // MyStruct *item = DN_IArrayMake(&my_array, DN_ZMem_No); // #if defined(__cplusplus) - #define DN_PArrayFind(ptr, size, ptr_find, eq_func) DN_TArrayFind(ptr, size, ptr_find, eq_func) - #define DN_PArrayFindMemEq(ptr, size, ptr_find) DN_TArrayFindMemEq(ptr, size, ptr_find) - #define DN_PArrayResizePool(ptr, ptr_size, ptr_max, pool, new_max) DN_TArrayResizePool(&(ptr), ptr_size, ptr_max, pool, new_max) - #define DN_PArrayResizeArena(ptr, ptr_size, ptr_max, arena, new_max) DN_TArrayResizeArena(&(ptr), ptr_size, ptr_max, arena, new_max) - #define DN_PArrayReservePool(ptr, ptr_max, pool, new_max) DN_TArrayReservePool(&(ptr), ptr_max, pool, new_max) - #define DN_PArrayReserveArena(ptr, ptr_max, arena, new_max) DN_TArrayReserveArena(&(ptr), ptr_max, arena, new_max) - #define DN_PArrayPreparePool(ptr, size, ptr_max, pool, add_count) DN_TArrayPreparePool(&(ptr), size, ptr_max, pool, add_count) - #define DN_PArrayPrepareArena(ptr, size, ptr_max, arena, add_count) DN_TArrayPrepareArena(&(ptr), size, ptr_max, arena, add_count) - #define DN_PArrayCopyPtrPool(dest, src, count_, pool) DN_TArrayCopyPtrPool(&(dest), src, count_, pool) - #define DN_PArrayCopyPtrPoolAssert(dest, src, count_, pool) DN_TArrayCopyPtrPoolAssert(&(dest), src, count_, pool, DN_CallSiteNow) - #define DN_PArrayCopyPtrArena(dest, src, count_, arena) DN_TArrayCopyPtrArena(&(dest), src, count_, arena) - #define DN_PArrayCopyPtrArenaAssert(dest, src, count_, arena) DN_TArrayCopyPtrArenaAssert(&(dest), src, count_, arena, DN_CallSiteNow) + #define DN_PArrayFind(ptr, size, ptr_find, eq_func) DN_TArrayFind(ptr, size, ptr_find, eq_func) + #define DN_PArrayFindMemEq(ptr, size, ptr_find) DN_TArrayFindMemEq(ptr, size, ptr_find) + #define DN_PArrayResizePool(ptr, ptr_size, ptr_max, pool, new_max) DN_TArrayResizeAllocator(&(ptr), ptr_size, ptr_max, DN_AllocatorFromPool(pool), new_max) + #define DN_PArrayResizeArena(ptr, ptr_size, ptr_max, arena, new_max) DN_TArrayResizeAllocator(&(ptr), ptr_size, ptr_max, DN_AllocatorFromArena(arena), new_max) + #define DN_PArrayReservePool(ptr, ptr_max, pool, new_max) DN_TArrayReserveAllocator(&(ptr), ptr_max, DN_AllocatorFromPool(pool), new_max) + #define DN_PArrayReserveArena(ptr, ptr_max, arena, new_max) DN_TArrayReserveAllocator(&(ptr), ptr_max, DN_AllocatorFromArena(arena), new_max) + #define DN_PArrayPreparePool(ptr, size, ptr_max, pool, add_count) DN_TArrayPrepareAllocator(&(ptr), size, ptr_max, DN_AllocatorFromPool(pool), add_count) + #define DN_PArrayPrepareArena(ptr, size, ptr_max, arena, add_count) DN_TArrayPrepareAllocator(&(ptr), size, ptr_max, DN_AllocatorFromArena(arena), add_count) + #define DN_PArrayCopyPtrPool(dest, src, count_, pool) DN_TArrayCopyPtrAllocator(&(dest), src, count_, DN_AllocatorFromPool(pool)) + #define DN_PArrayCopyPtrPoolAssert(dest, src, count_, pool) DN_TArrayCopyPtrAllocatorAssert(&(dest), src, count_, DN_AllocatorFromPool(pool), DN_CallSiteNow) + #define DN_PArrayCopyPtrArena(dest, src, count_, arena) DN_TArrayCopyPtrAllocator(&(dest), src, count_, DN_AllocatorFromArena(arena)) + #define DN_PArrayCopyPtrArenaAssert(dest, src, count_, arena) DN_TArrayCopyPtrAllocatorAssert(&(dest), src, count_, DN_AllocatorFromArena(arena), DN_CallSiteNow) - #define DN_PArrayMakeArray(ptr, ptr_size, max, count, z_mem) DN_TArrayMakeArray(ptr, ptr_size, max, count, z_mem) - #define DN_PArrayMakeArrayZ(ptr, ptr_size, max, count) DN_TArrayMakeArray(ptr, ptr_size, max, count, DN_ZMem_Yes) - #define DN_PArrayMakeArrayNoZ(ptr, ptr_size, max, count) DN_TArrayMakeArray(ptr, ptr_size, max, count, DN_ZMem_No) - #define DN_PArrayMakeArrayAssert(ptr, ptr_size, max, count, z_mem) DN_TArrayMakeArrayAssert(ptr, ptr_size, max, count, z_mem, DN_CallSiteNow) - #define DN_PArrayMakeArrayAssertZ(ptr, ptr_size, max, count) DN_TArrayMakeArrayAssert(ptr, ptr_size, max, count, DN_ZMem_Yes, DN_CallSiteNow) - #define DN_PArrayMakeArrayAssertNoZ(ptr, ptr_size, max, count) DN_TArrayMakeArrayAssert(ptr, ptr_size, max, count, DN_ZMem_No, DN_CallSiteNow) - #define DN_PArrayMakeArrayArena(ptr, ptr_size, ptr_max, arena, count, z_mem) DN_TArrayMakeArrayArena(&(ptr), ptr_size, ptr_max, arena, count, z_mem) - #define DN_PArrayMakeArrayArenaZ(ptr, ptr_size, ptr_max, arena, count) DN_TArrayMakeArrayArena(&(ptr), ptr_size, ptr_max, arena, count, DN_ZMem_Yes) - #define DN_PArrayMakeArrayArenaNoZ(ptr, ptr_size, ptr_max, arena, count) DN_TArrayMakeArrayArena(&(ptr), ptr_size, ptr_max, arena, count, DN_ZMem_No) - #define DN_PArrayMakeArrayPool(ptr, ptr_size, ptr_max, pool, count, z_mem) DN_TArrayMakeArrayPool(&(ptr), ptr_size, ptr_max, pool, count, z_mem) - #define DN_PArrayMakeArrayPoolZ(ptr, ptr_size, ptr_max, pool, count) DN_TArrayMakeArrayPool(&(ptr), ptr_size, ptr_max, pool, count, DN_ZMem_Yes) - #define DN_PArrayMakeArrayPoolNoZ(ptr, ptr_size, ptr_max, pool, count) DN_TArrayMakeArrayPool(&(ptr), ptr_size, ptr_max, pool, count, DN_ZMem_No) + #define DN_PArrayMakeArray(ptr, ptr_size, max, count, z_mem) DN_TArrayMakeArray(ptr, ptr_size, max, count, z_mem) + #define DN_PArrayMakeArrayZ(ptr, ptr_size, max, count) DN_TArrayMakeArray(ptr, ptr_size, max, count, DN_ZMem_Yes) + #define DN_PArrayMakeArrayNoZ(ptr, ptr_size, max, count) DN_TArrayMakeArray(ptr, ptr_size, max, count, DN_ZMem_No) + #define DN_PArrayMakeArrayAssert(ptr, ptr_size, max, count, z_mem) DN_TArrayMakeArrayAssert(ptr, ptr_size, max, count, z_mem, DN_CallSiteNow) + #define DN_PArrayMakeArrayAssertZ(ptr, ptr_size, max, count) DN_TArrayMakeArrayAssert(ptr, ptr_size, max, count, DN_ZMem_Yes, DN_CallSiteNow) + #define DN_PArrayMakeArrayAssertNoZ(ptr, ptr_size, max, count) DN_TArrayMakeArrayAssert(ptr, ptr_size, max, count, DN_ZMem_No, DN_CallSiteNow) + #define DN_PArrayMakeArrayArena(ptr, ptr_size, ptr_max, arena, count, z_mem) DN_TArrayMakeArrayAllocator(&(ptr), ptr_size, ptr_max, DN_AllocatorFromArena(arena), count, z_mem) + #define DN_PArrayMakeArrayArenaZ(ptr, ptr_size, ptr_max, arena, count) DN_TArrayMakeArrayAllocator(&(ptr), ptr_size, ptr_max, DN_AllocatorFromArena(arena), count, DN_ZMem_Yes) + #define DN_PArrayMakeArrayArenaNoZ(ptr, ptr_size, ptr_max, arena, count) DN_TArrayMakeArrayAllocator(&(ptr), ptr_size, ptr_max, DN_AllocatorFromArena(arena), count, DN_ZMem_No) + #define DN_PArrayMakeArrayPool(ptr, ptr_size, ptr_max, pool, count, z_mem) DN_TArrayMakeArrayAllocator(&(ptr), ptr_size, ptr_max, DN_AllocatorFromPool(pool), count, z_mem) + #define DN_PArrayMakeArrayPoolZ(ptr, ptr_size, ptr_max, pool, count) DN_TArrayMakeArrayAllocator(&(ptr), ptr_size, ptr_max, DN_AllocatorFromPool(pool), count, DN_ZMem_Yes) + #define DN_PArrayMakeArrayPoolNoZ(ptr, ptr_size, ptr_max, pool, count) DN_TArrayMakeArrayAllocator(&(ptr), ptr_size, ptr_max, DN_AllocatorFromPool(pool), count, DN_ZMem_No) - #define DN_PArrayMake(ptr, ptr_size, max, z_mem) DN_TArrayMakeArray(ptr, ptr_size, max, 1, z_mem) - #define DN_PArrayMakeZ(ptr, ptr_size, max) DN_TArrayMakeArray(ptr, ptr_size, max, 1, DN_ZMem_Yes) - #define DN_PArrayMakeNoZ(ptr, ptr_size, max) DN_TArrayMakeArray(ptr, ptr_size, max, 1, DN_ZMem_No) - #define DN_PArrayMakeAssert(ptr, ptr_size, max, z_mem) DN_TArrayMakeArrayAssert(ptr, ptr_size, max, 1, z_mem, DN_CallSiteNow) - #define DN_PArrayMakeAssertZ(ptr, ptr_size, max) DN_TArrayMakeArrayAssert(ptr, ptr_size, max, 1, DN_ZMem_Yes, DN_CallSiteNow) - #define DN_PArrayMakeAssertNoZ(ptr, ptr_size, max) DN_TArrayMakeArrayAssert(ptr, ptr_size, max, 1, DN_ZMem_No, DN_CallSiteNow) - #define DN_PArrayMakeArena(ptr, ptr_size, ptr_max, arena, z_mem) DN_TArrayMakeArrayArena(&(ptr), ptr_size, ptr_max, arena, 1, z_mem) - #define DN_PArrayMakeArenaZ(ptr, ptr_size, ptr_max, arena) DN_TArrayMakeArrayArena(&(ptr), ptr_size, ptr_max, arena, 1, DN_ZMem_Yes) - #define DN_PArrayMakeArenaNoZ(ptr, ptr_size, ptr_max, arena) DN_TArrayMakeArrayArena(&(ptr), ptr_size, ptr_max, arena, 1, DN_ZMem_No) - #define DN_PArrayMakePool(ptr, ptr_size, ptr_max, pool, z_mem) DN_TArrayMakeArrayPool(&(ptr), ptr_size, ptr_max, pool, 1, z_mem) - #define DN_PArrayMakePoolZ(ptr, ptr_size, ptr_max, pool) DN_TArrayMakeArrayPool(&(ptr), ptr_size, ptr_max, pool, 1, DN_ZMem_Yes) - #define DN_PArrayMakePoolNoZ(ptr, ptr_size, ptr_max, pool) DN_TArrayMakeArrayPool(&(ptr), ptr_size, ptr_max, pool, 1, DN_ZMem_No) + #define DN_PArrayMake(ptr, ptr_size, max, z_mem) DN_TArrayMakeArray(ptr, ptr_size, max, 1, z_mem) + #define DN_PArrayMakeZ(ptr, ptr_size, max) DN_TArrayMakeArray(ptr, ptr_size, max, 1, DN_ZMem_Yes) + #define DN_PArrayMakeNoZ(ptr, ptr_size, max) DN_TArrayMakeArray(ptr, ptr_size, max, 1, DN_ZMem_No) + #define DN_PArrayMakeAssert(ptr, ptr_size, max, z_mem) DN_TArrayMakeArrayAssert(ptr, ptr_size, max, 1, z_mem, DN_CallSiteNow) + #define DN_PArrayMakeAssertZ(ptr, ptr_size, max) DN_TArrayMakeArrayAssert(ptr, ptr_size, max, 1, DN_ZMem_Yes, DN_CallSiteNow) + #define DN_PArrayMakeAssertNoZ(ptr, ptr_size, max) DN_TArrayMakeArrayAssert(ptr, ptr_size, max, 1, DN_ZMem_No, DN_CallSiteNow) + #define DN_PArrayMakeArena(ptr, ptr_size, ptr_max, arena, z_mem) DN_TArrayMakeArrayAllocator(&(ptr), ptr_size, ptr_max, DN_AllocatorFromArena(arena), 1, z_mem) + #define DN_PArrayMakeArenaZ(ptr, ptr_size, ptr_max, arena) DN_TArrayMakeArrayAllocator(&(ptr), ptr_size, ptr_max, DN_AllocatorFromArena(arena), 1, DN_ZMem_Yes) + #define DN_PArrayMakeArenaNoZ(ptr, ptr_size, ptr_max, arena) DN_TArrayMakeArrayAllocator(&(ptr), ptr_size, ptr_max, DN_AllocatorFromArena(arena), 1, DN_ZMem_No) + #define DN_PArrayMakePool(ptr, ptr_size, ptr_max, pool, z_mem) DN_TArrayMakeArrayAllocator(&(ptr), ptr_size, ptr_max, DN_AllocatorFromPool(pool), 1, z_mem) + #define DN_PArrayMakePoolZ(ptr, ptr_size, ptr_max, pool) DN_TArrayMakeArrayAllocator(&(ptr), ptr_size, ptr_max, DN_AllocatorFromPool(pool), 1, DN_ZMem_Yes) + #define DN_PArrayMakePoolNoZ(ptr, ptr_size, ptr_max, pool) DN_TArrayMakeArrayAllocator(&(ptr), ptr_size, ptr_max, DN_AllocatorFromPool(pool), 1, DN_ZMem_No) - #define DN_PArrayAddArray(ptr, ptr_size, max, items, count, add) DN_TArrayAddArray(ptr, ptr_size, max, items, count, add) - #define DN_PArrayAddArrayArena(ptr, ptr_size, ptr_max, arena, items, count, add) DN_TArrayAddArrayArena(&(ptr), ptr_size, ptr_max, arena, items, count, add) - #define DN_PArrayAddArrayPool(ptr, ptr_size, ptr_max, pool, items, count, add) DN_TArrayAddArrayPool(&(ptr), ptr_size, ptr_max, pool, items, count, add) - #define DN_PArrayAdd(ptr, ptr_size, max, item, add) DN_TArrayAddArray(ptr, ptr_size, max, &item, 1, add) - #define DN_PArrayAddArena(ptr, ptr_size, ptr_max, arena, item, add) DN_TArrayAddArrayArena(&(ptr), ptr_size, ptr_max, arena, &item, 1, add) - #define DN_PArrayAddPool(ptr, ptr_size, ptr_max, pool, item, add) DN_TArrayAddArrayPool(&(ptr), ptr_size, ptr_max, pool, &item, 1, add) - #define DN_PArrayAppendArray(ptr, ptr_size, max, items, count) DN_TArrayAddArray(ptr, ptr_size, max, items, count, DN_AddType_Append) - #define DN_PArrayAppend(ptr, ptr_size, max, item) DN_TArrayAddArray(ptr, ptr_size, max, &item, 1, DN_AddType_Append) - #define DN_PArrayAppendArena(ptr, ptr_size, ptr_max, arena, item) DN_TArrayAddArrayArena(&(ptr), ptr_size, ptr_max, arena, &item, 1, DN_AddType_Append) - #define DN_PArrayAppendPool(ptr, ptr_size, ptr_max, pool, item) DN_TArrayAddArrayPool(&(ptr), ptr_size, ptr_max, pool, &item, 1, DN_AddType_Append) - #define DN_PArrayAppendAssert(ptr, ptr_size, max, item) DN_TArrayAddArrayAssert(ptr, ptr_size, max, &item, 1, DN_AddType_Append, DN_CallSiteNow) - #define DN_PArrayPrependArray(ptr, ptr_size, max, items, count) DN_TArrayAddArray(ptr, ptr_size, max, items, count, DN_AddType_Prepend) - #define DN_PArrayPrepend(ptr, ptr_size, max, item) DN_TArrayAddArray(ptr, ptr_size, max, &item, 1, DN_AddType_Prepend) - #define DN_PArrayPrependArena(ptr, ptr_size, ptr_max, arena, item) DN_TArrayAddArrayArena(&(ptr), ptr_size, ptr_max, arena, &item, 1, DN_AddType_Prepend) - #define DN_PArrayPrependPool(ptr, ptr_size, ptr_max, pool, item) DN_TArrayAddArrayPool(&(ptr), ptr_size, ptr_max, pool, &item, 1, DN_AddType_Prepend) + #define DN_PArrayAddArray(ptr, ptr_size, max, items, count, add) DN_TArrayAddArray(ptr, ptr_size, max, items, count, add) + #define DN_PArrayAddArrayArena(ptr, ptr_size, ptr_max, arena, items, count, add) DN_TArrayAddArrayAllocator(&(ptr), ptr_size, ptr_max, DN_AllocatorFromArena(arena), items, count, add) + #define DN_PArrayAddArrayPool(ptr, ptr_size, ptr_max, pool, items, count, add) DN_TArrayAddArrayAllocator(&(ptr), ptr_size, ptr_max, DN_AllocatorFromPool(pool), items, count, add) + #define DN_PArrayAdd(ptr, ptr_size, max, item, add) DN_TArrayAddArray(ptr, ptr_size, max, &item, 1, add) + #define DN_PArrayAddArena(ptr, ptr_size, ptr_max, arena, item, add) DN_TArrayAddArrayAllocator(&(ptr), ptr_size, ptr_max, DN_AllocatorFromArena(arena), &item, 1, add) + #define DN_PArrayAddPool(ptr, ptr_size, ptr_max, pool, item, add) DN_TArrayAddArrayAllocator(&(ptr), ptr_size, ptr_max, DN_AllocatorFromPool(pool), &item, 1, add) + #define DN_PArrayAppendArray(ptr, ptr_size, max, items, count) DN_TArrayAddArray(ptr, ptr_size, max, items, count, DN_AddType_Append) + #define DN_PArrayAppend(ptr, ptr_size, max, item) DN_TArrayAddArray(ptr, ptr_size, max, &item, 1, DN_AddType_Append) + #define DN_PArrayAppendArena(ptr, ptr_size, ptr_max, arena, item) DN_TArrayAddArrayAllocator(&(ptr), ptr_size, ptr_max, DN_AllocatorFromArena(arena), &item, 1, DN_AddType_Append) + #define DN_PArrayAppendPool(ptr, ptr_size, ptr_max, pool, item) DN_TArrayAddArrayAllocator(&(ptr), ptr_size, ptr_max, DN_AllocatorFromPool(pool), &item, 1, DN_AddType_Append) + #define DN_PArrayAppendAssert(ptr, ptr_size, max, item) DN_TArrayAddArrayAssert(ptr, ptr_size, max, &item, 1, DN_AddType_Append, DN_CallSiteNow) + #define DN_PArrayPrependArray(ptr, ptr_size, max, items, count) DN_TArrayAddArray(ptr, ptr_size, max, items, count, DN_AddType_Prepend) + #define DN_PArrayPrepend(ptr, ptr_size, max, item) DN_TArrayAddArray(ptr, ptr_size, max, &item, 1, DN_AddType_Prepend) + #define DN_PArrayPrependArena(ptr, ptr_size, ptr_max, arena, item) DN_TArrayAddArrayAllocator(&(ptr), ptr_size, ptr_max, DN_AllocatorFromArena(arena), &item, 1, DN_AddType_Prepend) + #define DN_PArrayPrependPool(ptr, ptr_size, ptr_max, pool, item) DN_TArrayAddArrayAllocator(&(ptr), ptr_size, ptr_max, DN_AllocatorFromPool(pool), &item, 1, DN_AddType_Prepend) - #define DN_PArrayEraseRange(ptr, ptr_size, begin_index, count, erase) DN_TArrayEraseRange(ptr, ptr_size, begin_index, count, erase) - #define DN_PArrayErase(ptr, ptr_size, index, erase) DN_TArrayEraseRange(ptr, ptr_size, index, 1, erase) - #define DN_PArrayInsertArray(ptr, ptr_size, max, index, items, count) DN_TArrayInsertArray(ptr, ptr_size, max, index, items, count) - #define DN_PArrayInsert(ptr, ptr_size, max, index, item) DN_TArrayInsertArray(ptr, ptr_size, max, index, &item, 1) - #define DN_PArrayPopFront(ptr, ptr_size, max, count) DN_TArrayPopFront(ptr, ptr_size, count) - #define DN_PArrayPopBack(ptr, ptr_size, max, count) DN_TArrayPopBack(ptr, ptr_size, count) + #define DN_PArrayEraseRange(ptr, ptr_size, begin_index, count, erase) DN_TArrayEraseRange(ptr, ptr_size, begin_index, count, erase) + #define DN_PArrayErase(ptr, ptr_size, index, erase) DN_TArrayEraseRange(ptr, ptr_size, index, 1, erase) + #define DN_PArrayInsertArray(ptr, ptr_size, max, index, items, count) DN_TArrayInsertArray(ptr, ptr_size, max, index, items, count) + #define DN_PArrayInsert(ptr, ptr_size, max, index, item) DN_TArrayInsertArray(ptr, ptr_size, max, index, &item, 1) + #define DN_PArrayPopFront(ptr, ptr_size, max, count) DN_TArrayPopFront(ptr, ptr_size, count) + #define DN_PArrayPopBack(ptr, ptr_size, max, count) DN_TArrayPopBack(ptr, ptr_size, count) + + #define DN_PArrayResizeHeap(ptr, ptr_size, ptr_max, heap, new_max) DN_TArrayResizeAllocator(&(ptr), ptr_size, ptr_max, DN_AllocatorFromHeap(heap), new_max) + #define DN_PArrayReserveHeap(ptr, ptr_max, heap, new_max) DN_TArrayReserveAllocator(&(ptr), ptr_max, DN_AllocatorFromHeap(heap), new_max) + #define DN_PArrayPrepareHeap(ptr, size, ptr_max, heap, add_count) DN_TArrayPrepareAllocator(&(ptr), size, ptr_max, DN_AllocatorFromHeap(heap), add_count) + #define DN_PArrayCopyPtrHeap(dest, src, count_, heap) DN_TArrayCopyPtrAllocator(&(dest), src, count_, DN_AllocatorFromHeap(heap)) + #define DN_PArrayCopyPtrHeapAssert(dest, src, count_, heap) DN_TArrayCopyPtrAllocatorAssert(&(dest), src, count_, DN_AllocatorFromHeap(heap), DN_CallSiteNow) + #define DN_PArrayMakeArrayHeap(ptr, ptr_size, ptr_max, heap, count, z_mem) DN_TArrayMakeArrayAllocator(&(ptr), ptr_size, ptr_max, DN_AllocatorFromHeap(heap), count, z_mem) + #define DN_PArrayMakeArrayHeapZ(ptr, ptr_size, ptr_max, heap, count) DN_TArrayMakeArrayAllocator(&(ptr), ptr_size, ptr_max, DN_AllocatorFromHeap(heap), count, DN_ZMem_Yes) + #define DN_PArrayMakeArrayHeapNoZ(ptr, ptr_size, ptr_max, heap, count) DN_TArrayMakeArrayAllocator(&(ptr), ptr_size, ptr_max, DN_AllocatorFromHeap(heap), count, DN_ZMem_No) + #define DN_PArrayMakeHeap(ptr, ptr_size, ptr_max, heap, z_mem) DN_TArrayMakeArrayAllocator(&(ptr), ptr_size, ptr_max, DN_AllocatorFromHeap(heap), 1, z_mem) + #define DN_PArrayMakeHeapZ(ptr, ptr_size, ptr_max, heap) DN_TArrayMakeArrayAllocator(&(ptr), ptr_size, ptr_max, DN_AllocatorFromHeap(heap), 1, DN_ZMem_Yes) + #define DN_PArrayMakeHeapNoZ(ptr, ptr_size, ptr_max, heap) DN_TArrayMakeArrayAllocator(&(ptr), ptr_size, ptr_max, DN_AllocatorFromHeap(heap), 1, DN_ZMem_No) + #define DN_PArrayAddArrayHeap(ptr, ptr_size, ptr_max, heap, items, count, add) DN_TArrayAddArrayAllocator(&(ptr), ptr_size, ptr_max, DN_AllocatorFromHeap(heap), items, count, add) + #define DN_PArrayAddHeap(ptr, ptr_size, ptr_max, heap, item, add) DN_TArrayAddArrayAllocator(&(ptr), ptr_size, ptr_max, DN_AllocatorFromHeap(heap), &item, 1, add) + #define DN_PArrayAppendHeap(ptr, ptr_size, ptr_max, heap, item) DN_TArrayAddArrayAllocator(&(ptr), ptr_size, ptr_max, DN_AllocatorFromHeap(heap), &item, 1, DN_AddType_Append) + #define DN_PArrayPrependHeap(ptr, ptr_size, ptr_max, heap, item) DN_TArrayAddArrayAllocator(&(ptr), ptr_size, ptr_max, DN_AllocatorFromHeap(heap), &item, 1, DN_AddType_Prepend) #else - #define DN_PArrayFind(ptr, size, ptr_find, eq_func) DN_ArrayFind(ptr, size, sizeof(*(ptr)), ptr_find, eq_func) - #define DN_PArrayFindMemEq(ptr, size, ptr_find) DN_ArrayFindMemEq(ptr, size, sizeof(*(ptr)), ptr_find) - #define DN_PArrayResizePool(ptr, ptr_size, ptr_max, pool, new_max) DN_ArrayResizePool((void **)&(ptr), ptr_size, ptr_max, sizeof((ptr)[0]), pool, new_max) - #define DN_PArrayResizeArena(ptr, ptr_size, ptr_max, arena, new_max) DN_ArrayResizeArena((void **)&(ptr), ptr_size, ptr_max, sizeof((ptr)[0]), arena, new_max) - #define DN_PArrayReservePool(ptr, ptr_max, pool, new_max) DN_ArrayReservePool((void **)&(ptr), ptr_max, sizeof((ptr)[0]), pool, new_max) - #define DN_PArrayReserveArena(ptr, ptr_max, arena, new_max) DN_ArrayReserveArena((void **)&(ptr), ptr_max, sizeof((ptr)[0]), arena, new_max) - #define DN_PArrayPreparePool(ptr, size, ptr_max, pool, add_count) DN_ArrayPreparePool((void **)(ptr), size, ptr_max, sizeof((*ptr)[0]), pool, add_count) - #define DN_PArrayPrepareArena(ptr, size, ptr_max, arena, add_count) DN_ArrayPrepareArena((void **)(ptr), size, ptr_max, sizeof((*ptr)[0]), arena, add_count) - #define DN_PArrayCopyPtrPool(ptr_array, src, count_, pool) DN_ArrayCopyPtrPool(ptr_array, src, count_, sizeof((*ptr)[0]), pool) - #define DN_PArrayCopyPtrPoolAssert(ptr_array, src, count_, pool) DN_ArrayCopyPtrPool(ptr_array, src, count_, sizeof((*ptr)[0]), pool, DN_CallSiteNow) - #define DN_PArrayCopyPtrArena(ptr_array, src, count_, arena) DN_ArrayCopyPtrArena(ptr_array, src, count_, sizeof((*ptr)[0]), arena) - #define DN_PArrayCopyPtrArenaAssert(ptr_array, src, count_, arena) DN_ArrayCopyPtrArena(ptr_array, src, count_, sizeof((*ptr)[0]), arena, DN_CallSiteNow) + #define DN_PArrayFind(ptr, size, ptr_find, eq_func) DN_ArrayFind(ptr, size, sizeof(*(ptr)), ptr_find, eq_func) + #define DN_PArrayFindMemEq(ptr, size, ptr_find) DN_ArrayFindMemEq(ptr, size, sizeof(*(ptr)), ptr_find) + #define DN_PArrayResizePool(ptr, ptr_size, ptr_max, pool, new_max) DN_ArrayResizeAllocator((void **)&(ptr), ptr_size, ptr_max, sizeof((ptr)[0]), DN_AllocatorFromPool(pool), new_max) + #define DN_PArrayResizeArena(ptr, ptr_size, ptr_max, arena, new_max) DN_ArrayResizeAllocator((void **)&(ptr), ptr_size, ptr_max, sizeof((ptr)[0]), DN_AllocatorFromArena(arena), new_max) + #define DN_PArrayReservePool(ptr, ptr_max, pool, new_max) DN_ArrayReserveAllocator((void **)&(ptr), ptr_max, sizeof((ptr)[0]), DN_AllocatorFromPool(pool), new_max) + #define DN_PArrayReserveArena(ptr, ptr_max, arena, new_max) DN_ArrayReserveAllocator((void **)&(ptr), ptr_max, sizeof((ptr)[0]), DN_AllocatorFromArena(arena), new_max) + #define DN_PArrayPreparePool(ptr, size, ptr_max, pool, add_count) DN_ArrayPrepareAllocator((void **)(ptr), size, ptr_max, sizeof((*ptr)[0]), DN_AllocatorFromPool(pool), add_count) + #define DN_PArrayPrepareArena(ptr, size, ptr_max, arena, add_count) DN_ArrayPrepareAllocator((void **)(ptr), size, ptr_max, sizeof((*ptr)[0]), DN_AllocatorFromArena(arena), add_count) + #define DN_PArrayCopyPtrPool(ptr_array, src, count_, pool) DN_ArrayCopyPtrAllocator(ptr_array, src, count_, sizeof((*ptr)[0]), DN_AllocatorFromPool(pool)) + #define DN_PArrayCopyPtrPoolAssert(ptr_array, src, count_, pool) DN_ArrayCopyPtrAllocatorAssert(ptr_array, src, count_, sizeof((*ptr)[0]), DN_AllocatorFromPool(pool), DN_CallSiteNow) + #define DN_PArrayCopyPtrArena(ptr_array, src, count_, arena) DN_ArrayCopyPtrAllocator(ptr_array, src, count_, sizeof((*ptr)[0]), DN_AllocatorFromArena(arena)) + #define DN_PArrayCopyPtrArenaAssert(ptr_array, src, count_, arena) DN_ArrayCopyPtrAllocatorAssert(ptr_array, src, count_, sizeof((*ptr)[0]), DN_AllocatorFromArena(arena), DN_CallSiteNow) + #define DN_PArrayResizeHeap(ptr, ptr_size, ptr_max, heap, new_max) DN_ArrayResizeAllocator((void **)&(ptr), ptr_size, ptr_max, sizeof((ptr)[0]), DN_AllocatorFromHeap(heap), new_max) + #define DN_PArrayReserveHeap(ptr, ptr_max, heap, new_max) DN_ArrayReserveAllocator((void **)&(ptr), ptr_max, sizeof((ptr)[0]), DN_AllocatorFromHeap(heap), new_max) + #define DN_PArrayPrepareHeap(ptr, size, ptr_max, heap, add_count) DN_ArrayPrepareAllocator((void **)(ptr), size, ptr_max, sizeof((*ptr)[0]), DN_AllocatorFromHeap(heap), add_count) + #define DN_PArrayCopyPtrHeap(ptr_array, src, count_, heap) DN_ArrayCopyPtrAllocator(ptr_array, src, count_, sizeof((*ptr)[0]), DN_AllocatorFromHeap(heap)) + #define DN_PArrayCopyPtrHeapAssert(ptr_array, src, count_, heap) DN_ArrayCopyPtrAllocatorAssert(ptr_array, src, count_, sizeof((*ptr)[0]), DN_AllocatorFromHeap(heap), DN_CallSiteNow) - #define DN_PArrayMakeArray(ptr, ptr_size, max, count, z_mem) (DN_CppDeclType(&(ptr)[0]))DN_ArrayMakeArray(ptr, ptr_size, max, sizeof((ptr)[0]), count, z_mem) - #define DN_PArrayMakeArrayZ(ptr, ptr_size, max, count) (DN_CppDeclType(&(ptr)[0]))DN_ArrayMakeArray(ptr, ptr_size, max, sizeof((ptr)[0]), count, DN_ZMem_Yes) - #define DN_PArrayMakeArrayNoZ(ptr, ptr_size, max, count) (DN_CppDeclType(&(ptr)[0]))DN_ArrayMakeArray(ptr, ptr_size, max, sizeof((ptr)[0]), count, DN_ZMem_No) - #define DN_PArrayMakeArrayAssert(ptr, ptr_size, max, count, z_mem) (DN_CppDeclType(&(ptr)[0]))DN_ArrayMakeArrayAssert(ptr, ptr_size, max, sizeof((ptr)[0]), count, z_mem, DN_CallSiteNow) - #define DN_PArrayMakeArrayAssertZ(ptr, ptr_size, max, count) (DN_CppDeclType(&(ptr)[0]))DN_ArrayMakeArrayAssert(ptr, ptr_size, max, sizeof((ptr)[0]), count, DN_ZMem_Yes, DN_CallSiteNow) - #define DN_PArrayMakeArrayAssertNoZ(ptr, ptr_size, max, count) (DN_CppDeclType(&(ptr)[0]))DN_ArrayMakeArrayAssert(ptr, ptr_size, max, sizeof((ptr)[0]), count, DN_ZMem_No, DN_CallSiteNow) - #define DN_PArrayMakeArrayArena(ptr, ptr_size, max, arena, count, z_mem) (DN_CppDeclType(&(ptr)[0]))DN_ArrayMakeArrayArena((void **)&(ptr), ptr_size, max, sizeof((ptr)[0]), arena, count, z_mem) - #define DN_PArrayMakeArrayArenaZ(ptr, ptr_size, max, arena, count) (DN_CppDeclType(&(ptr)[0]))DN_ArrayMakeArrayArena((void **)&(ptr), ptr_size, max, sizeof((ptr)[0]), arena, count, DN_ZMem_Yes) - #define DN_PArrayMakeArrayArenaNoZ(ptr, ptr_size, max, arena, count) (DN_CppDeclType(&(ptr)[0]))DN_ArrayMakeArrayArena((void **)&(ptr), ptr_size, max, sizeof((ptr)[0]), arena, count, DN_ZMem_No) - #define DN_PArrayMakeArrayPool(ptr, ptr_size, max, pool, count, z_mem) (DN_CppDeclType(&(ptr)[0]))DN_ArrayMakeArrayPool((void **)&(ptr), ptr_size, max, sizeof((ptr)[0]), pool, count, z_mem) - #define DN_PArrayMakeArrayPoolZ(ptr, ptr_size, max, pool, count) (DN_CppDeclType(&(ptr)[0]))DN_ArrayMakeArrayPool((void **)&(ptr), ptr_size, max, sizeof((ptr)[0]), pool, count, DN_ZMem_Yes) - #define DN_PArrayMakeArrayPoolNoZ(ptr, ptr_size, max, pool, count) (DN_CppDeclType(&(ptr)[0]))DN_ArrayMakeArrayPool((void **)&(ptr), ptr_size, max, sizeof((ptr)[0]), pool, count, DN_ZMem_No) + #define DN_PArrayMakeArray(ptr, ptr_size, max, count, z_mem) (DN_CppDeclType(&(ptr)[0]))DN_ArrayMakeArray(ptr, ptr_size, max, sizeof((ptr)[0]), count, z_mem) + #define DN_PArrayMakeArrayZ(ptr, ptr_size, max, count) (DN_CppDeclType(&(ptr)[0]))DN_ArrayMakeArray(ptr, ptr_size, max, sizeof((ptr)[0]), count, DN_ZMem_Yes) + #define DN_PArrayMakeArrayNoZ(ptr, ptr_size, max, count) (DN_CppDeclType(&(ptr)[0]))DN_ArrayMakeArray(ptr, ptr_size, max, sizeof((ptr)[0]), count, DN_ZMem_No) + #define DN_PArrayMakeArrayAssert(ptr, ptr_size, max, count, z_mem) (DN_CppDeclType(&(ptr)[0]))DN_ArrayMakeArrayAssert(ptr, ptr_size, max, sizeof((ptr)[0]), count, z_mem, DN_CallSiteNow) + #define DN_PArrayMakeArrayAssertZ(ptr, ptr_size, max, count) (DN_CppDeclType(&(ptr)[0]))DN_ArrayMakeArrayAssert(ptr, ptr_size, max, sizeof((ptr)[0]), count, DN_ZMem_Yes, DN_CallSiteNow) + #define DN_PArrayMakeArrayAssertNoZ(ptr, ptr_size, max, count) (DN_CppDeclType(&(ptr)[0]))DN_ArrayMakeArrayAssert(ptr, ptr_size, max, sizeof((ptr)[0]), count, DN_ZMem_No, DN_CallSiteNow) + #define DN_PArrayMakeArrayArena(ptr, ptr_size, max, arena, count, z_mem) (DN_CppDeclType(&(ptr)[0]))DN_ArrayMakeArrayAllocator((void **)&(ptr), ptr_size, max, sizeof((ptr)[0]), DN_AllocatorFromArena(arena), count, z_mem) + #define DN_PArrayMakeArrayArenaZ(ptr, ptr_size, max, arena, count) (DN_CppDeclType(&(ptr)[0]))DN_ArrayMakeArrayAllocator((void **)&(ptr), ptr_size, max, sizeof((ptr)[0]), DN_AllocatorFromArena(arena), count, DN_ZMem_Yes) + #define DN_PArrayMakeArrayArenaNoZ(ptr, ptr_size, max, arena, count) (DN_CppDeclType(&(ptr)[0]))DN_ArrayMakeArrayAllocator((void **)&(ptr), ptr_size, max, sizeof((ptr)[0]), DN_AllocatorFromArena(arena), count, DN_ZMem_No) + #define DN_PArrayMakeArrayPool(ptr, ptr_size, max, pool, count, z_mem) (DN_CppDeclType(&(ptr)[0]))DN_ArrayMakeArrayAllocator((void **)&(ptr), ptr_size, max, sizeof((ptr)[0]), DN_AllocatorFromPool(pool), count, z_mem) + #define DN_PArrayMakeArrayPoolZ(ptr, ptr_size, max, pool, count) (DN_CppDeclType(&(ptr)[0]))DN_ArrayMakeArrayAllocator((void **)&(ptr), ptr_size, max, sizeof((ptr)[0]), DN_AllocatorFromPool(pool), count, DN_ZMem_Yes) + #define DN_PArrayMakeArrayPoolNoZ(ptr, ptr_size, max, pool, count) (DN_CppDeclType(&(ptr)[0]))DN_ArrayMakeArrayAllocator((void **)&(ptr), ptr_size, max, sizeof((ptr)[0]), DN_AllocatorFromPool(pool), count, DN_ZMem_No) + #define DN_PArrayMakeArrayHeap(ptr, ptr_size, max, heap, count, z_mem) (DN_CppDeclType(&(ptr)[0]))DN_ArrayMakeArrayAllocator((void **)&(ptr), ptr_size, max, sizeof((ptr)[0]), DN_AllocatorFromHeap(heap), count, z_mem) + #define DN_PArrayMakeArrayHeapZ(ptr, ptr_size, max, heap, count) (DN_CppDeclType(&(ptr)[0]))DN_ArrayMakeArrayAllocator((void **)&(ptr), ptr_size, max, sizeof((ptr)[0]), DN_AllocatorFromHeap(heap), count, DN_ZMem_Yes) + #define DN_PArrayMakeArrayHeapNoZ(ptr, ptr_size, max, heap, count) (DN_CppDeclType(&(ptr)[0]))DN_ArrayMakeArrayAllocator((void **)&(ptr), ptr_size, max, sizeof((ptr)[0]), DN_AllocatorFromHeap(heap), count, DN_ZMem_No) - #define DN_PArrayMake(ptr, ptr_size, max, z_mem) (DN_CppDeclType(&(ptr)[0]))DN_ArrayMakeArray(ptr, ptr_size, max, sizeof((ptr)[0]), 1, z_mem) - #define DN_PArrayMakeZ(ptr, ptr_size, max) (DN_CppDeclType(&(ptr)[0]))DN_ArrayMakeArray(ptr, ptr_size, max, sizeof((ptr)[0]), 1, DN_ZMem_Yes) - #define DN_PArrayMakeNoZ(ptr, ptr_size, max) (DN_CppDeclType(&(ptr)[0]))DN_ArrayMakeArray(ptr, ptr_size, max, sizeof((ptr)[0]), 1, DN_ZMem_No) - #define DN_PArrayMakeAssert(ptr, ptr_size, max, z_mem) (DN_CppDeclType(&(ptr)[0]))DN_ArrayMakeArrayAssert(ptr, ptr_size, max, sizeof((ptr)[0]), 1, z_mem, DN_CallSiteNow) - #define DN_PArrayMakeAssertZ(ptr, ptr_size, max) (DN_CppDeclType(&(ptr)[0]))DN_ArrayMakeArrayAssert(ptr, ptr_size, max, sizeof((ptr)[0]), 1, DN_ZMem_Yes, DN_CallSiteNow) - #define DN_PArrayMakeAssertNoZ(ptr, ptr_size, max) (DN_CppDeclType(&(ptr)[0]))DN_ArrayMakeArrayAssert(ptr, ptr_size, max, sizeof((ptr)[0]), 1, DN_ZMem_No, DN_CallSiteNow) - #define DN_PArrayMakeArena(ptr, ptr_size, max, arena, z_mem) (DN_CppDeclType(&(ptr)[0]))DN_ArrayMakeArrayArena((void **)&(ptr), ptr_size, max, sizeof((ptr)[0]), arena, 1, z_mem) - #define DN_PArrayMakeArenaZ(ptr, ptr_size, max, arena) (DN_CppDeclType(&(ptr)[0]))DN_ArrayMakeArrayArena((void **)&(ptr), ptr_size, max, sizeof((ptr)[0]), arena, 1, DN_ZMem_Yes) - #define DN_PArrayMakeArenaNoZ(ptr, ptr_size, max, arena) (DN_CppDeclType(&(ptr)[0]))DN_ArrayMakeArrayArena((void **)&(ptr), ptr_size, max, sizeof((ptr)[0]), arena, 1, DN_ZMem_No) - #define DN_PArrayMakePool(ptr, ptr_size, max, pool, z_mem) (DN_CppDeclType(&(ptr)[0]))DN_ArrayMakeArrayPool((void **)&(ptr), ptr_size, max, sizeof((ptr)[0]), pool, 1, z_mem) - #define DN_PArrayMakePoolZ(ptr, ptr_size, max, pool) (DN_CppDeclType(&(ptr)[0]))DN_ArrayMakeArrayPool((void **)&(ptr), ptr_size, max, sizeof((ptr)[0]), pool, 1, DN_ZMem_Yes) - #define DN_PArrayMakePoolNoZ(ptr, ptr_size, max, pool) (DN_CppDeclType(&(ptr)[0]))DN_ArrayMakeArrayPool((void **)&(ptr), ptr_size, max, sizeof((ptr)[0]), pool, 1, DN_ZMem_No) + #define DN_PArrayMake(ptr, ptr_size, max, z_mem) (DN_CppDeclType(&(ptr)[0]))DN_ArrayMakeArray(ptr, ptr_size, max, sizeof((ptr)[0]), 1, z_mem) + #define DN_PArrayMakeZ(ptr, ptr_size, max) (DN_CppDeclType(&(ptr)[0]))DN_ArrayMakeArray(ptr, ptr_size, max, sizeof((ptr)[0]), 1, DN_ZMem_Yes) + #define DN_PArrayMakeNoZ(ptr, ptr_size, max) (DN_CppDeclType(&(ptr)[0]))DN_ArrayMakeArray(ptr, ptr_size, max, sizeof((ptr)[0]), 1, DN_ZMem_No) + #define DN_PArrayMakeAssert(ptr, ptr_size, max, z_mem) (DN_CppDeclType(&(ptr)[0]))DN_ArrayMakeArrayAssert(ptr, ptr_size, max, sizeof((ptr)[0]), 1, z_mem, DN_CallSiteNow) + #define DN_PArrayMakeAssertZ(ptr, ptr_size, max) (DN_CppDeclType(&(ptr)[0]))DN_ArrayMakeArrayAssert(ptr, ptr_size, max, sizeof((ptr)[0]), 1, DN_ZMem_Yes, DN_CallSiteNow) + #define DN_PArrayMakeAssertNoZ(ptr, ptr_size, max) (DN_CppDeclType(&(ptr)[0]))DN_ArrayMakeArrayAssert(ptr, ptr_size, max, sizeof((ptr)[0]), 1, DN_ZMem_No, DN_CallSiteNow) + #define DN_PArrayMakeArena(ptr, ptr_size, max, arena, z_mem) (DN_CppDeclType(&(ptr)[0]))DN_ArrayMakeArrayAllocator((void **)&(ptr), ptr_size, max, sizeof((ptr)[0]), DN_AllocatorFromArena(arena), 1, z_mem) + #define DN_PArrayMakeArenaZ(ptr, ptr_size, max, arena) (DN_CppDeclType(&(ptr)[0]))DN_ArrayMakeArrayAllocator((void **)&(ptr), ptr_size, max, sizeof((ptr)[0]), DN_AllocatorFromArena(arena), 1, DN_ZMem_Yes) + #define DN_PArrayMakeArenaNoZ(ptr, ptr_size, max, arena) (DN_CppDeclType(&(ptr)[0]))DN_ArrayMakeArrayAllocator((void **)&(ptr), ptr_size, max, sizeof((ptr)[0]), DN_AllocatorFromArena(arena), 1, DN_ZMem_No) + #define DN_PArrayMakePool(ptr, ptr_size, max, pool, z_mem) (DN_CppDeclType(&(ptr)[0]))DN_ArrayMakeArrayAllocator((void **)&(ptr), ptr_size, max, sizeof((ptr)[0]), DN_AllocatorFromPool(pool), 1, z_mem) + #define DN_PArrayMakePoolZ(ptr, ptr_size, max, pool) (DN_CppDeclType(&(ptr)[0]))DN_ArrayMakeArrayAllocator((void **)&(ptr), ptr_size, max, sizeof((ptr)[0]), DN_AllocatorFromPool(pool), 1, DN_ZMem_Yes) + #define DN_PArrayMakePoolNoZ(ptr, ptr_size, max, pool) (DN_CppDeclType(&(ptr)[0]))DN_ArrayMakeArrayAllocator((void **)&(ptr), ptr_size, max, sizeof((ptr)[0]), DN_AllocatorFromPool(pool), 1, DN_ZMem_No) + #define DN_PArrayMakeHeap(ptr, ptr_size, max, heap, z_mem) (DN_CppDeclType(&(ptr)[0]))DN_ArrayMakeArrayAllocator((void **)&(ptr), ptr_size, max, sizeof((ptr)[0]), DN_AllocatorFromHeap(heap), 1, z_mem) + #define DN_PArrayMakeHeapZ(ptr, ptr_size, max, heap) (DN_CppDeclType(&(ptr)[0]))DN_ArrayMakeArrayAllocator((void **)&(ptr), ptr_size, max, sizeof((ptr)[0]), DN_AllocatorFromHeap(heap), 1, DN_ZMem_Yes) + #define DN_PArrayMakeHeapNoZ(ptr, ptr_size, max, heap) (DN_CppDeclType(&(ptr)[0]))DN_ArrayMakeArrayAllocator((void **)&(ptr), ptr_size, max, sizeof((ptr)[0]), DN_AllocatorFromHeap(heap), 1, DN_ZMem_No) - #define DN_PArrayAddArray(ptr, ptr_size, max, items, count, add) (DN_CppDeclType(&(ptr)[0]))DN_ArrayAddArray(ptr, ptr_size, max, sizeof((ptr)[0]), items, count, add) - #define DN_PArrayAddArrayArena(ptr, ptr_size, max, arena, items, count, add) (DN_CppDeclType(&(ptr)[0]))DN_ArrayAddArrayArena((void **)&(ptr), ptr_size, max, sizeof((ptr)[0]), arena, items, count, add) - #define DN_PArrayAddArrayPool(ptr, ptr_size, max, pool, items, count, add) (DN_CppDeclType(&(ptr)[0]))DN_ArrayAddArrayPool((void **)&(ptr), ptr_size, max, sizeof((ptr)[0]), pool, items, count, add) - #define DN_PArrayAdd(ptr, ptr_size, max, item, add) (DN_CppDeclType(&(ptr)[0]))DN_ArrayAddArray(ptr, ptr_size, max, sizeof((ptr)[0]), &item, 1, add) - #define DN_PArrayAddArena(ptr, ptr_size, max, arena, item, add) (DN_CppDeclType(&(ptr)[0]))DN_ArrayAddArrayArena((void **)&(ptr), ptr_size, max, sizeof((ptr)[0]), arena, &item, 1, add) - #define DN_PArrayAddPool(ptr, ptr_size, max, pool, item, add) (DN_CppDeclType(&(ptr)[0]))DN_ArrayAddArrayPool((void **)&(ptr), ptr_size, max, sizeof((ptr)[0]), pool, &item, 1, add) - #define DN_PArrayAppendArray(ptr, ptr_size, max, items, count) (DN_CppDeclType(&(ptr)[0]))DN_ArrayAddArray(ptr, ptr_size, max, sizeof((ptr)[0]), items, count, DN_AddType_Append) - #define DN_PArrayAppend(ptr, ptr_size, max, item) (DN_CppDeclType(&(ptr)[0]))DN_ArrayAddArray(ptr, ptr_size, max, sizeof((ptr)[0]), &item, 1, DN_AddType_Append) - #define DN_PArrayAppendArena(ptr, ptr_size, max, arena, item) (DN_CppDeclType(&(ptr)[0]))DN_ArrayAddArrayArena((void **)&(ptr), ptr_size, max, sizeof((ptr)[0]), arena, &item, 1, DN_AddType_Append) - #define DN_PArrayAppendPool(ptr, ptr_size, max, pool, item) (DN_CppDeclType(&(ptr)[0]))DN_ArrayAddArrayPool((void **)&(ptr), ptr_size, max, sizeof((ptr)[0]), pool, &item, 1, DN_AddType_Append) - #define DN_PArrayAppendAssert(ptr, ptr_size, max, item) (DN_CppDeclType(&(ptr)[0]))DN_ArrayAddArrayAssert(ptr, ptr_size, max, sizeof((ptr)[0]), &item, 1, DN_AddType_Append, DN_CallSiteNow) - #define DN_PArrayPrependArray(ptr, ptr_size, max, items, count) (DN_CppDeclType(&(ptr)[0]))DN_ArrayAddArray(ptr, ptr_size, max, sizeof((ptr)[0]), items, count, DN_AddType_Prepend) - #define DN_PArrayPrepend(ptr, ptr_size, max, item) (DN_CppDeclType(&(ptr)[0]))DN_ArrayAddArray(ptr, ptr_size, max, sizeof((ptr)[0]), &item, 1, DN_AddType_Prepend) - #define DN_PArrayPrependArena(ptr, ptr_size, max, arena, item) (DN_CppDeclType(&(ptr)[0]))DN_ArrayAddArrayArena((void **)&(ptr), ptr_size, max, sizeof((ptr)[0]), arena, &item, 1, DN_AddType_Prepend) - #define DN_PArrayPrependPool(ptr, ptr_size, max, pool, item) (DN_CppDeclType(&(ptr)[0]))DN_ArrayAddArrayPool((void **)&(ptr), ptr_size, max, sizeof((ptr)[0]), pool, &item, 1, DN_AddType_Prepend) + #define DN_PArrayAddArray(ptr, ptr_size, max, items, count, add) (DN_CppDeclType(&(ptr)[0]))DN_ArrayAddArray(ptr, ptr_size, max, sizeof((ptr)[0]), items, count, add) + #define DN_PArrayAddArrayArena(ptr, ptr_size, max, arena, items, count, add) (DN_CppDeclType(&(ptr)[0]))DN_ArrayAddArrayAllocator((void **)&(ptr), ptr_size, max, sizeof((ptr)[0]), DN_AllocatorFromArena(arena), items, count, add) + #define DN_PArrayAddArrayPool(ptr, ptr_size, max, pool, items, count, add) (DN_CppDeclType(&(ptr)[0]))DN_ArrayAddArrayAllocator((void **)&(ptr), ptr_size, max, sizeof((ptr)[0]), DN_AllocatorFromPool(pool), items, count, add) + #define DN_PArrayAddArrayHeap(ptr, ptr_size, max, heap, items, count, add) (DN_CppDeclType(&(ptr)[0]))DN_ArrayAddArrayAllocator((void **)&(ptr), ptr_size, max, sizeof((ptr)[0]), DN_AllocatorFromHeap(heap), items, count, add) + #define DN_PArrayAdd(ptr, ptr_size, max, item, add) (DN_CppDeclType(&(ptr)[0]))DN_ArrayAddArray(ptr, ptr_size, max, sizeof((ptr)[0]), &item, 1, add) + #define DN_PArrayAddArena(ptr, ptr_size, max, arena, item, add) (DN_CppDeclType(&(ptr)[0]))DN_ArrayAddArrayAllocator((void **)&(ptr), ptr_size, max, sizeof((ptr)[0]), DN_AllocatorFromArena(arena), &item, 1, add) + #define DN_PArrayAddPool(ptr, ptr_size, max, pool, item, add) (DN_CppDeclType(&(ptr)[0]))DN_ArrayAddArrayAllocator((void **)&(ptr), ptr_size, max, sizeof((ptr)[0]), DN_AllocatorFromPool(pool), &item, 1, add) + #define DN_PArrayAddHeap(ptr, ptr_size, max, heap, item, add) (DN_CppDeclType(&(ptr)[0]))DN_ArrayAddArrayAllocator((void **)&(ptr), ptr_size, max, sizeof((ptr)[0]), DN_AllocatorFromHeap(heap), &item, 1, add) + #define DN_PArrayAppendArray(ptr, ptr_size, max, items, count) (DN_CppDeclType(&(ptr)[0]))DN_ArrayAddArray(ptr, ptr_size, max, sizeof((ptr)[0]), items, count, DN_AddType_Append) + #define DN_PArrayAppend(ptr, ptr_size, max, item) (DN_CppDeclType(&(ptr)[0]))DN_ArrayAddArray(ptr, ptr_size, max, sizeof((ptr)[0]), &item, 1, DN_AddType_Append) + #define DN_PArrayAppendArena(ptr, ptr_size, max, arena, item) (DN_CppDeclType(&(ptr)[0]))DN_ArrayAddArrayAllocator((void **)&(ptr), ptr_size, max, sizeof((ptr)[0]), DN_AllocatorFromArena(arena), &item, 1, DN_AddType_Append) + #define DN_PArrayAppendPool(ptr, ptr_size, max, pool, item) (DN_CppDeclType(&(ptr)[0]))DN_ArrayAddArrayAllocator((void **)&(ptr), ptr_size, max, sizeof((ptr)[0]), DN_AllocatorFromPool(pool), &item, 1, DN_AddType_Append) + #define DN_PArrayAppendHeap(ptr, ptr_size, max, heap, item) (DN_CppDeclType(&(ptr)[0]))DN_ArrayAddArrayAllocator((void **)&(ptr), ptr_size, max, sizeof((ptr)[0]), DN_AllocatorFromHeap(heap), &item, 1, DN_AddType_Append) + #define DN_PArrayAppendAssert(ptr, ptr_size, max, item) (DN_CppDeclType(&(ptr)[0]))DN_ArrayAddArrayAssert(ptr, ptr_size, max, sizeof((ptr)[0]), &item, 1, DN_AddType_Append, DN_CallSiteNow) + #define DN_PArrayPrependArray(ptr, ptr_size, max, items, count) (DN_CppDeclType(&(ptr)[0]))DN_ArrayAddArray(ptr, ptr_size, max, sizeof((ptr)[0]), items, count, DN_AddType_Prepend) + #define DN_PArrayPrepend(ptr, ptr_size, max, item) (DN_CppDeclType(&(ptr)[0]))DN_ArrayAddArray(ptr, ptr_size, max, sizeof((ptr)[0]), &item, 1, DN_AddType_Prepend) + #define DN_PArrayPrependArena(ptr, ptr_size, max, arena, item) (DN_CppDeclType(&(ptr)[0]))DN_ArrayAddArrayAllocator((void **)&(ptr), ptr_size, max, sizeof((ptr)[0]), DN_AllocatorFromArena(arena), &item, 1, DN_AddType_Prepend) + #define DN_PArrayPrependPool(ptr, ptr_size, max, pool, item) (DN_CppDeclType(&(ptr)[0]))DN_ArrayAddArrayAllocator((void **)&(ptr), ptr_size, max, sizeof((ptr)[0]), DN_AllocatorFromPool(pool), &item, 1, DN_AddType_Prepend) + #define DN_PArrayPrependHeap(ptr, ptr_size, max, heap, item) (DN_CppDeclType(&(ptr)[0]))DN_ArrayAddArrayAllocator((void **)&(ptr), ptr_size, max, sizeof((ptr)[0]), DN_AllocatorFromHeap(heap), &item, 1, DN_AddType_Prepend) - #define DN_PArrayEraseRange(ptr, ptr_size, begin_index, count, erase) DN_ArrayEraseRange(ptr, ptr_size, sizeof((ptr)[0]), begin_index, count, erase) - #define DN_PArrayErase(ptr, ptr_size, index, erase) DN_ArrayEraseRange(ptr, ptr_size, sizeof((ptr)[0]), index, 1, erase) - #define DN_PArrayInsertArray(ptr, ptr_size, max, index, items, count) (DN_CppDeclType(&(ptr)[0]))DN_ArrayInsertArray(ptr, ptr_size, max, sizeof((ptr)[0]), index, items, count) - #define DN_PArrayInsert(ptr, ptr_size, max, index, item) (DN_CppDeclType(&(ptr)[0]))DN_ArrayInsertArray(ptr, ptr_size, max, sizeof((ptr)[0]), index, &item, 1) - #define DN_PArrayPopFront(ptr, ptr_size, max, count) (DN_CppDeclType(&(ptr)[0]))DN_ArrayPopFront(ptr, ptr_size, sizeof((ptr)[0]), count) - #define DN_PArrayPopBack(ptr, ptr_size, max, count) (DN_CppDeclType(&(ptr)[0]))DN_ArrayPopBack(ptr, ptr_size, sizeof((ptr)[0]), count) + #define DN_PArrayEraseRange(ptr, ptr_size, begin_index, count, erase) DN_ArrayEraseRange(ptr, ptr_size, sizeof((ptr)[0]), begin_index, count, erase) + #define DN_PArrayErase(ptr, ptr_size, index, erase) DN_ArrayEraseRange(ptr, ptr_size, sizeof((ptr)[0]), index, 1, erase) + #define DN_PArrayInsertArray(ptr, ptr_size, max, index, items, count) (DN_CppDeclType(&(ptr)[0]))DN_ArrayInsertArray(ptr, ptr_size, max, sizeof((ptr)[0]), index, items, count) + #define DN_PArrayInsert(ptr, ptr_size, max, index, item) (DN_CppDeclType(&(ptr)[0]))DN_ArrayInsertArray(ptr, ptr_size, max, sizeof((ptr)[0]), index, &item, 1) + #define DN_PArrayPopFront(ptr, ptr_size, max, count) (DN_CppDeclType(&(ptr)[0]))DN_ArrayPopFront(ptr, ptr_size, sizeof((ptr)[0]), count) + #define DN_PArrayPopBack(ptr, ptr_size, max, count) (DN_CppDeclType(&(ptr)[0]))DN_ArrayPopBack(ptr, ptr_size, sizeof((ptr)[0]), count) #endif #define DN_LArrayFind(c_array, size, ptr_find, eq_func) DN_PArrayFind(c_array, size, ptr_find, eq_func) @@ -4445,14 +4693,19 @@ DN_API DN_RaycastV2 DN_RaycastLineIntersectV2 #define DN_IArrayFindMemEq(ptr_array, ptr_find) DN_PArrayFindMemEq((ptr_array)->data, (ptr_array)->count, ptr_find) #define DN_IArrayResizePool(ptr_array, pool, new_max) DN_PArrayResizePool((ptr_array)->data, &(ptr_array)->count, &(ptr_array)->max, pool, new_max) #define DN_IArrayResizeArena(ptr_array, arena, new_max) DN_PArrayResizeArena((ptr_array)->data, &(ptr_array)->count, &(ptr_array)->max, arena, new_max) +#define DN_IArrayResizeHeap(ptr_array, heap, new_max) DN_PArrayResizeHeap((ptr_array)->data, &(ptr_array)->count, &(ptr_array)->max, heap, new_max) #define DN_IArrayReservePool(ptr_array, pool, new_max) DN_PArrayReservePool((ptr_array)->data, &(ptr_array)->max, pool, new_max) #define DN_IArrayReserveArena(ptr_array, arena, new_max) DN_PArrayReserveArena((ptr_array)->data, &(ptr_array)->max, arena, new_max) +#define DN_IArrayReserveHeap(ptr_array, heap, new_max) DN_PArrayReserveHeap((ptr_array)->data, &(ptr_array)->max, heap, new_max) #define DN_IArrayPreparePool(ptr_array, pool, add_count) DN_PArrayPreparePool(&(ptr_array)->data, (ptr_array)->count, &(ptr_array)->max, pool, add_count) #define DN_IArrayPrepareArena(ptr_array, arena, add_count) DN_PArrayPrepareArena(&(ptr_array)->data, (ptr_array)->count, &(ptr_array)->max, arena, add_count) -#define DN_IArrayCopyPtrPool(ptr_array, src, count_, pool) (ptr_array)->max = (ptr_array)->count = DN_PArrayCopyPtrPool((ptr_array), src, count_, pool) -#define DN_IArrayCopyPtrPoolAssert(ptr_array, src, count_, pool) (ptr_array)->max = (ptr_array)->count = DN_PArrayCopyPtrPoolAssert((ptr_array), src, count_, pool) -#define DN_IArrayCopyPtrArena(ptr_array, src, count_, arena) (ptr_array)->max = (ptr_array)->count = DN_PArrayCopyPtrArena((ptr_array), src, count_, arena) -#define DN_IArrayCopyPtrArenaAssert(ptr_array, src, count_, arena) (ptr_array)->max = (ptr_array)->count = DN_PArrayCopyPtrArenaAssert((ptr_array), src, count_, arena) +#define DN_IArrayPrepareHeap(ptr_array, heap, add_count) DN_PArrayPrepareHeap(&(ptr_array)->data, (ptr_array)->count, &(ptr_array)->max, heap, add_count) +#define DN_IArrayCopyPtrPool(ptr_array, src, count_, pool) (ptr_array)->max = (ptr_array)->count = DN_PArrayCopyPtrPool((ptr_array)->data, src, count_, pool) +#define DN_IArrayCopyPtrPoolAssert(ptr_array, src, count_, pool) (ptr_array)->max = (ptr_array)->count = DN_PArrayCopyPtrPoolAssert((ptr_array)->data, src, count_, pool) +#define DN_IArrayCopyPtrArena(ptr_array, src, count_, arena) (ptr_array)->max = (ptr_array)->count = DN_PArrayCopyPtrArena((ptr_array)->data, src, count_, arena) +#define DN_IArrayCopyPtrArenaAssert(ptr_array, src, count_, arena) (ptr_array)->max = (ptr_array)->count = DN_PArrayCopyPtrArenaAssert((ptr_array)->data, src, count_, arena) +#define DN_IArrayCopyPtrHeap(ptr_array, src, count_, heap) (ptr_array)->max = (ptr_array)->count = DN_PArrayCopyPtrHeap((ptr_array)->data, src, count_, heap) +#define DN_IArrayCopyPtrHeapAssert(ptr_array, src, count_, heap) (ptr_array)->max = (ptr_array)->count = DN_PArrayCopyPtrHeapAssert((ptr_array)->data, src, count_, heap) #define DN_IArrayMakeArray(ptr_array, count_, z_mem) DN_PArrayMakeArray((ptr_array)->data, &(ptr_array)->count, (ptr_array)->max, count_, z_mem) #define DN_IArrayMakeArrayZ(ptr_array, count_) DN_PArrayMakeArrayZ((ptr_array)->data, &(ptr_array)->count, (ptr_array)->max, count_) @@ -4466,6 +4719,9 @@ DN_API DN_RaycastV2 DN_RaycastLineIntersectV2 #define DN_IArrayMakeArrayPool(ptr_array, pool, count_, z_mem) DN_PArrayMakeArrayPool((ptr_array)->data, &(ptr_array)->count, &(ptr_array)->max, pool, count_, z_mem) #define DN_IArrayMakeArrayPoolZ(ptr_array, pool, count_) DN_PArrayMakeArrayPoolZ((ptr_array)->data, &(ptr_array)->count, &(ptr_array)->max, pool, count_) #define DN_IArrayMakeArrayPoolNoZ(ptr_array, pool, count_) DN_PArrayMakeArrayPoolNoZ((ptr_array)->data, &(ptr_array)->count, &(ptr_array)->max, pool, count_) +#define DN_IArrayMakeArrayHeap(ptr_array, heap, count_, z_mem) DN_PArrayMakeArrayHeap((ptr_array)->data, &(ptr_array)->count, &(ptr_array)->max, heap, count_, z_mem) +#define DN_IArrayMakeArrayHeapZ(ptr_array, heap, count_) DN_PArrayMakeArrayHeapZ((ptr_array)->data, &(ptr_array)->count, &(ptr_array)->max, heap, count_) +#define DN_IArrayMakeArrayHeapNoZ(ptr_array, heap, count_) DN_PArrayMakeArrayHeapNoZ((ptr_array)->data, &(ptr_array)->count, &(ptr_array)->max, heap, count_) #define DN_IArrayMake(ptr_array, z_mem) DN_PArrayMake((ptr_array)->data, &(ptr_array)->count, (ptr_array)->max, z_mem) #define DN_IArrayMakeZ(ptr_array) DN_PArrayMakeZ((ptr_array)->data, &(ptr_array)->count, (ptr_array)->max) @@ -4479,23 +4735,29 @@ DN_API DN_RaycastV2 DN_RaycastLineIntersectV2 #define DN_IArrayMakePool(ptr_array, pool, z_mem) DN_PArrayMakePool((ptr_array)->data, &(ptr_array)->count, &(ptr_array)->max, pool, z_mem) #define DN_IArrayMakePoolZ(ptr_array, pool) DN_PArrayMakePoolZ((ptr_array)->data, &(ptr_array)->count, &(ptr_array)->max, pool) #define DN_IArrayMakePoolNoZ(ptr_array, pool) DN_PArrayMakePoolNoZ((ptr_array)->data, &(ptr_array)->count, &(ptr_array)->max, pool) -#define DN_IArrayMakeNoZ(ptr_array) DN_PArrayMakeNoZ((ptr_array)->data, &(ptr_array)->count, (ptr_array)->max) +#define DN_IArrayMakeHeap(ptr_array, heap, z_mem) DN_PArrayMakeHeap((ptr_array)->data, &(ptr_array)->count, &(ptr_array)->max, heap, z_mem) +#define DN_IArrayMakeHeapZ(ptr_array, heap) DN_PArrayMakeHeapZ((ptr_array)->data, &(ptr_array)->count, &(ptr_array)->max, heap) +#define DN_IArrayMakeHeapNoZ(ptr_array, heap) DN_PArrayMakeHeapNoZ((ptr_array)->data, &(ptr_array)->count, &(ptr_array)->max, heap) #define DN_IArrayAddArray(ptr_array, items, count_, add) DN_PArrayAddArray((ptr_array)->data, &(ptr_array)->count, (ptr_array)->max, items, count_, add) #define DN_IArrayAddArrayArena(ptr_array, arena, items, count_, add) DN_PArrayAddArrayArena((ptr_array)->data, &(ptr_array)->count, &(ptr_array)->max, arena, items, count_, add) #define DN_IArrayAddArrayPool(ptr_array, pool, items, count_, add) DN_PArrayAddArrayPool((ptr_array)->data, &(ptr_array)->count, &(ptr_array)->max, pool, items, count_, add) +#define DN_IArrayAddArrayHeap(ptr_array, heap, items, count_, add) DN_PArrayAddArrayHeap((ptr_array)->data, &(ptr_array)->count, &(ptr_array)->max, heap, items, count_, add) #define DN_IArrayAdd(ptr_array, item, add) DN_PArrayAdd((ptr_array)->data, &(ptr_array)->count, (ptr_array)->max, item, add) #define DN_IArrayAddArena(ptr_array, arena, item, add) DN_PArrayAddArena((ptr_array)->data, &(ptr_array)->count, &(ptr_array)->max, arena, item, add) #define DN_IArrayAddPool(ptr_array, pool, item, add) DN_PArrayAddPool((ptr_array)->data, &(ptr_array)->count, &(ptr_array)->max, pool, item, add) +#define DN_IArrayAddHeap(ptr_array, heap, item, add) DN_PArrayAddHeap((ptr_array)->data, &(ptr_array)->count, &(ptr_array)->max, heap, item, add) #define DN_IArrayAppendArray(ptr_array, items, count_) DN_PArrayAppendArray((ptr_array)->data, &(ptr_array)->count, (ptr_array)->max, items, count_) #define DN_IArrayAppend(ptr_array, item) DN_PArrayAppend((ptr_array)->data, &(ptr_array)->count, (ptr_array)->max, item) #define DN_IArrayAppendArena(ptr_array, arena, item) DN_PArrayAppendArena((ptr_array)->data, &(ptr_array)->count, &(ptr_array)->max, arena, item) #define DN_IArrayAppendPool(ptr_array, pool, item) DN_PArrayAppendPool((ptr_array)->data, &(ptr_array)->count, &(ptr_array)->max, pool, item) +#define DN_IArrayAppendHeap(ptr_array, heap, item) DN_PArrayAppendHeap((ptr_array)->data, &(ptr_array)->count, &(ptr_array)->max, heap, item) #define DN_IArrayAppendAssert(ptr_array, item) DN_PArrayAppendAssert((ptr_array)->data, &(ptr_array)->count, (ptr_array)->max, item) #define DN_IArrayPrependArray(ptr_array, items, count_) DN_PArrayPrependArray((ptr_array)->data, &(ptr_array)->count, (ptr_array)->max, items, count_) #define DN_IArrayPrepend(ptr_array, item) DN_PArrayPrepend((ptr_array)->data, &(ptr_array)->count, (ptr_array)->max, item) #define DN_IArrayPrependArena(ptr_array, arena, item) DN_PArrayPrependArena((ptr_array)->data, &(ptr_array)->count, &(ptr_array)->max, arena, item) #define DN_IArrayPrependPool(ptr_array, pool, item) DN_PArrayPrependPool((ptr_array)->data, &(ptr_array)->count, &(ptr_array)->max, pool, item) +#define DN_IArrayPrependHeap(ptr_array, heap, item) DN_PArrayPrependHeap((ptr_array)->data, &(ptr_array)->count, &(ptr_array)->max, heap, item) #define DN_IArrayEraseRange(ptr_array, begin_index, count_, erase) DN_PArrayEraseRange((ptr_array)->data, &(ptr_array)->count, begin_index, count_, erase) #define DN_IArrayErase(ptr_array, index, erase) DN_PArrayErase((ptr_array)->data, &(ptr_array)->count, index, erase) #define DN_IArrayInsertArray(ptr_array, index, items, count_) DN_PArrayInsertArray((ptr_array)->data, &(ptr_array)->count, (ptr_array)->max, index, items, count_) @@ -4503,17 +4765,13 @@ DN_API DN_RaycastV2 DN_RaycastLineIntersectV2 #define DN_IArrayPopFront(ptr_array, count_) DN_PArrayPopFront((ptr_array)->data, &(ptr_array)->count, (ptr_array)->max, count_) #define DN_IArrayPopBack(ptr_array, count_) DN_PArrayPopBack((ptr_array)->data, &(ptr_array)->count, (ptr_array)->max, count_) -// NOTE: Slices -// -// Fixed size container allocated up front that have a `T *data` and `DN_USize count` elements. -// -// API -// AllocArena: Allocates the container with the requested `count` elements -// -#define DN_ISliceAllocArena(slice_ptr, count_, zmem, arena) (DN_CppDeclType(&((slice_ptr)->data[0])))DN_SliceAllocArena((void **)&((slice_ptr)->data), &((slice_ptr)->count), count_, sizeof((slice_ptr)->data[0]), alignof(DN_CppDeclType((slice_ptr)->data[0])), zmem, arena) - - -DN_API void* DN_SliceAllocArena (void **data, DN_USize *slice_size_field, DN_USize count, DN_USize elem_size, DN_U8 align, DN_ZMem zmem, DN_Arena *arena); +#define DN_CArraySet(dest_array, src_item) for (DN_USize index = 0; index < DN_ArrayCountU(dest_array); index++) { (dest_array)[index] = (src_item); } +#define DN_CArrayZero(dest_array) DN_Memset(dest_array, 0, sizeof(dest_array[0]) * DN_ArrayCountU(dest_array)) +#define DN_CArrayCopy(dest_array, src_array) do { \ + DN_StaticTypeEq((dest_array)[0], (src_array)[0]); \ + DN_StaticAssert(DN_ArrayCountU(dest_array) == DN_ArrayCountU(src_array)); \ + DN_Memcpy((dest_array), (src_array), sizeof((dest_array)[0]) * DN_ArrayCountU(dest_array)); \ + } while (0) DN_API DN_ArrayFindResult DN_ArrayFind (void *data, DN_USize count, DN_USize elem_size, void const *find, DN_ArrayFindEqFunc *eq_func); DN_API DN_ArrayFindResult DN_ArrayFindMemEq (void *data, DN_USize count, DN_USize elem_size, void const *find); @@ -4523,22 +4781,15 @@ DN_API void* DN_ArrayPopBack (void * DN_API DN_ArrayEraseResult DN_ArrayEraseRange (void *data, DN_USize *count, DN_USize elem_size, DN_USize begin_index, DN_ISize erase_count, DN_ArrayErase erase); DN_API void* DN_ArrayMakeArray (void *data, DN_USize *count, DN_USize max, DN_USize elem_size, DN_USize make_count, DN_ZMem z_mem); DN_API void* DN_ArrayMakeArrayAssert (void *data, DN_USize *count, DN_USize max, DN_USize elem_size, DN_USize make_count, DN_ZMem z_mem, DN_CallSite call_site); -DN_API void* DN_ArrayMakeArrayArena (void **data, DN_USize *count, DN_USize *max, DN_USize elem_size, DN_Arena *arena, DN_USize make_count, DN_ZMem z_mem); -DN_API void* DN_ArrayMakeArrayPool (void **data, DN_USize *count, DN_USize *max, DN_USize elem_size, DN_Pool *pool, DN_USize make_count, DN_ZMem z_mem); +DN_API void* DN_ArrayMakeArrayAllocator (void **data, DN_USize *count, DN_USize *max, DN_USize elem_size, DN_Allocator allocator, DN_USize make_count, DN_ZMem z_mem); DN_API void* DN_ArrayAddArray (void *data, DN_USize *count, DN_USize max, DN_USize elem_size, void const *elems, DN_USize elems_count, DN_AddType add); DN_API void* DN_ArrayAddArrayAssert (void *data, DN_USize *count, DN_USize max, DN_USize elem_size, void const *elems, DN_USize elems_count, DN_AddType add, DN_CallSite call_site); -DN_API void* DN_ArrayAddArrayArena (void **data, DN_USize *count, DN_USize *max, DN_USize elem_size, void const *elems, DN_USize elems_count, DN_Arena *arena, DN_AddType add); -DN_API void* DN_ArrayAddArrayPool (void **data, DN_USize *count, DN_USize *max, DN_USize elem_size, void const *elems, DN_USize elems_count, DN_Pool *pool, DN_AddType add); -DN_API bool DN_ArrayResizePool (void **data, DN_USize *count, DN_USize *max, DN_USize elem_size, DN_Pool *pool, DN_USize new_max); -DN_API bool DN_ArrayResizeArena (void **data, DN_USize *count, DN_USize *max, DN_USize elem_size, DN_Arena *arena, DN_USize new_max); -DN_API bool DN_ArrayReservePool (void **data, DN_USize *max, DN_USize elem_size, DN_Pool *pool, DN_USize new_max); -DN_API bool DN_ArrayReserveArena (void **data, DN_USize *max, DN_USize elem_size, DN_Arena *arena, DN_USize new_max); -DN_API bool DN_ArrayPreparePool (void **data, DN_USize count, DN_USize *max, DN_USize elem_size, DN_Pool *pool, DN_USize add_count); -DN_API bool DN_ArrayPrepareArena (void **data, DN_USize count, DN_USize *max, DN_USize elem_size, DN_Arena *arena, DN_USize add_count); -DN_API DN_USize DN_ArrayCopyPtrArena (void **data, void const *src, DN_USize count, DN_USize elem_size, DN_Arena *arena); -DN_API DN_USize DN_ArrayCopyPtrArenaAssert (void **data, void const *src, DN_USize count, DN_USize elem_size, DN_Arena *arena, DN_CallSite call_site); -DN_API DN_USize DN_ArrayCopyPtrPool (void **data, void const *src, DN_USize count, DN_USize elem_size, DN_Pool *pool); -DN_API DN_USize DN_ArrayCopyPtrPoolAssert (void **data, void const *src, DN_USize count, DN_USize elem_size, DN_Pool *pool, DN_CallSite call_site); +DN_API void* DN_ArrayAddArrayAllocator (void **data, DN_USize *count, DN_USize *max, DN_USize elem_size, DN_Allocator allocator, void const *elems, DN_USize elems_count, DN_AddType add); +DN_API bool DN_ArrayResizeAllocator (void **data, DN_USize *count, DN_USize *max, DN_USize elem_size, DN_Allocator allocator, DN_USize new_max); +DN_API bool DN_ArrayReserveAllocator (void **data, DN_USize *max, DN_USize elem_size, DN_Allocator allocator, DN_USize new_max); +DN_API bool DN_ArrayPrepareAllocator (void **data, DN_USize count, DN_USize *max, DN_USize elem_size, DN_Allocator allocator, DN_USize add_count); +DN_API DN_USize DN_ArrayCopyPtrAllocator (void **data, void const *src, DN_USize count, DN_USize elem_size, DN_Allocator allocator); +DN_API DN_USize DN_ArrayCopyPtrAllocatorAssert (void **data, void const *src, DN_USize count, DN_USize elem_size, DN_Allocator allocator, DN_CallSite call_site); #if defined (__cplusplus) template DN_ArrayFindResult DN_TArrayFind (T *data, DN_USize count, void const *find, DN_ArrayFindEqFunc *eq_func); @@ -4553,32 +4804,15 @@ template T* DN_TArrayMakeArrayAssertZ (T *dat template T* DN_TArrayMakeArrayAssertNoZ (T *data, DN_USize *count, DN_USize max, DN_USize make_count, DN_CallSite call_site); template T* DN_TArrayAddArray (T *data, DN_USize *count, DN_USize max, T const *elems, DN_USize elems_count, DN_AddType add); template T* DN_TArrayAddArrayAssert (T *data, DN_USize *count, DN_USize max, T const *elems, DN_USize elems_count, DN_AddType add, DN_CallSite call_site); -template T* DN_TArrayMakeArrayArena (T **data, DN_USize *count, DN_USize *max, DN_Arena *arena, DN_USize make_count, DN_ZMem z_mem); -template T* DN_TArrayMakeArrayArenaZ (T **data, DN_USize *count, DN_USize *max, DN_Arena *arena, DN_USize make_count); -template T* DN_TArrayMakeArrayArenaNoZ (T **data, DN_USize *count, DN_USize *max, DN_Arena *arena, DN_USize make_count); -template T* DN_TArrayMakeArrayPool (T **data, DN_USize *count, DN_USize *max, DN_Pool *pool, DN_USize make_count, DN_ZMem z_mem); -template T* DN_TArrayMakeArrayPoolZ (T **data, DN_USize *count, DN_USize *max, DN_Pool *pool, DN_USize make_count); -template T* DN_TArrayMakeArrayPoolNoZ (T **data, DN_USize *count, DN_USize *max, DN_Pool *pool, DN_USize make_count); -template T* DN_TArrayAddArrayArena (T **data, DN_USize *count, DN_USize *max, DN_Arena *arena, T const *elems, DN_USize elems_count, DN_AddType add); -template T* DN_TArrayAddArrayPool (T **data, DN_USize *count, DN_USize *max, DN_Pool *pool, T const *elems, DN_USize elems_count, DN_AddType add); -template T* DN_TArrayMakeArena (T **data, DN_USize *count, DN_USize *max, DN_Arena *arena, DN_ZMem z_mem); -template T* DN_TArrayMakeArenaZ (T **data, DN_USize *count, DN_USize *max, DN_Arena *arena); -template T* DN_TArrayMakeArenaNoZ (T **data, DN_USize *count, DN_USize *max, DN_Arena *arena); -template T* DN_TArrayMakePool (T **data, DN_USize *count, DN_USize *max, DN_Pool *pool, DN_ZMem z_mem); -template T* DN_TArrayMakePoolZ (T **data, DN_USize *count, DN_USize *max, DN_Pool *pool); -template T* DN_TArrayMakePoolNoZ (T **data, DN_USize *count, DN_USize *max, DN_Pool *pool); -template T* DN_TArrayAddArena (T **data, DN_USize *count, DN_USize *max, DN_Arena *arena, T const *elems, DN_USize elems_count, DN_AddType add); -template T* DN_TArrayAddPool (T **data, DN_USize *count, DN_USize *max, DN_Pool *pool, T const *elems, DN_USize elems_count, DN_AddType add); -template bool DN_TArrayResizePool (T **data, DN_USize *count, DN_USize *max, DN_Pool *pool, DN_USize new_max); -template bool DN_TArrayResizeArena (T **data, DN_USize *count, DN_USize *max, DN_Arena *arena, DN_USize new_max); -template bool DN_TArrayReservePool (T **data, DN_USize *max, DN_Pool *pool, DN_USize new_max); -template bool DN_TArrayReserveArena (T **data, DN_USize *max, DN_Pool *pool, DN_USize new_max); -template bool DN_TArrayPreparePool (T **data, DN_USize count, DN_USize *max, DN_Pool *pool, DN_USize add_count); -template bool DN_TArrayPrepareArena (T **data, DN_USize count, DN_USize *max, DN_Arena *pool, DN_USize add_count); -template DN_USize DN_TArrayCopyPtrArena (T **data, T const *src, DN_USize count, DN_Arena *arena); -template DN_USize DN_TArrayCopyPtrArenaAssert (T **data, T const *src, DN_USize count, DN_Arena *arena, DN_CallSite call_site); -template DN_USize DN_TArrayCopyPtrPool (T **data, T const *src, DN_USize count, DN_Pool *pool); -template DN_USize DN_TArrayCopyPtrPoolAssert (T **data, T const *src, DN_USize count, DN_Pool *pool, DN_CallSite call_site); +template T* DN_TArrayMakeArrayAllocator (T **data, DN_USize *count, DN_USize *max, DN_Allocator allocator, DN_USize make_count, DN_ZMem z_mem); +template T* DN_TArrayMakeArrayAllocatorZ (T **data, DN_USize *count, DN_USize *max, DN_Allocator allocator, DN_USize make_count); +template T* DN_TArrayMakeArrayAllocatorNoZ (T **data, DN_USize *count, DN_USize *max, DN_Allocator allocator, DN_USize make_count); +template T* DN_TArrayAddArrayAllocator (T **data, DN_USize *count, DN_USize *max, DN_Allocator allocator, T const *elems, DN_USize elems_count, DN_AddType add); +template bool DN_TArrayResizeAllocator (T **data, DN_USize *count, DN_USize *max, DN_Allocator allocator, DN_USize new_max); +template bool DN_TArrayReserveAllocator (T **data, DN_USize *max, DN_Allocator allocator, DN_USize new_max); +template bool DN_TArrayPrepareAllocator (T **data, DN_USize count, DN_USize *max, DN_Allocator allocator, DN_USize add_count); +template DN_USize DN_TArrayCopyPtrAllocator (T **data, T const *src, DN_USize count, DN_Allocator allocator); +template DN_USize DN_TArrayCopyPtrAllocatorAssert(T **data, T const *src, DN_USize count, DN_Allocator allocator, DN_CallSite call_site); #endif DN_API bool DN_RingHasSpace (DN_Ring const *ring, DN_U64 size); @@ -4669,12 +4903,12 @@ DN_API DN_U32 DN_HTableHashFuncMurmur3KeyStr8 (void const* key, DN_API bool DN_HTableKeyEqFuncMemcmp (void const* lhs, void const* rhs, DN_USize size); DN_API bool DN_HTableKeyEqFuncStr8Eq (void const* lhs, void const* rhs, DN_USize size); -#define DN_HTableInitArgsDefault(KeyValueT, kvs_ptr, HashField, KeyField, ValueField) DN_HTableInitArgsDefault_(DN_Cast(void **)&kvs_ptr, sizeof(*kvs_ptr), offsetof(KeyValueT, HashField), sizeof(kvs_ptr->KeyField), offsetof(KeyValueT, KeyField), sizeof(kvs_ptr->ValueField), offsetof(KeyValueT, ValueField)) -DN_API DN_HTableInitArgs DN_HTableInitArgsDefault_ (void** kvs, DN_USize size_of_kvs, DN_USize offset_of_hash, DN_USize size_of_key, DN_USize offset_of_key, DN_USize size_of_value, DN_USize offset_of_value); -DN_API DN_HTableInitResult DN_HTableInitHeap (DN_HTableInitArgs args, DN_Heap heap); -DN_API DN_HTable DN_HTableInitHeapAssert (DN_HTableInitArgs args, DN_Heap heap); -DN_API DN_HTableInitResult DN_HTableInitPool (DN_HTableInitArgs args, DN_Pool pool, DN_HTableDeallocPoolOnDeinit dealloc_pool); -DN_API DN_HTable DN_HTableInitPoolAssert (DN_HTableInitArgs args, DN_Pool pool, DN_HTableDeallocPoolOnDeinit dealloc_pool); +#define DN_HTableInitArgsDefault(KeyValueT, kvs_ptr, HashField, KeyField, ValueField) DN_HTableInitArgsDefaultRaw(DN_Cast(void **)&kvs_ptr, sizeof(*kvs_ptr), offsetof(KeyValueT, HashField), sizeof(kvs_ptr->KeyField), offsetof(KeyValueT, KeyField), sizeof(kvs_ptr->ValueField), offsetof(KeyValueT, ValueField)) +DN_API DN_HTableInitArgs DN_HTableInitArgsDefaultRaw (void** kvs, DN_USize size_of_kvs, DN_USize offset_of_hash, DN_USize size_of_key, DN_USize offset_of_key, DN_USize size_of_value, DN_USize offset_of_value); +DN_API DN_HTableInitResult DN_HTableInitHeap (DN_HTableInitArgs args, DN_Heap *heap); +DN_API DN_HTable DN_HTableInitHeapAssert (DN_HTableInitArgs args, DN_Heap *heap); +DN_API DN_HTableInitResult DN_HTableInitPool (DN_HTableInitArgs args, DN_Pool *pool, DN_HTableDeallocPoolOnDeinit dealloc_pool); +DN_API DN_HTable DN_HTableInitPoolAssert (DN_HTableInitArgs args, DN_Pool *pool, DN_HTableDeallocPoolOnDeinit dealloc_pool); DN_API void DN_HTableDeinit (DN_HTable* table); DN_API DN_HTableLookupResult DN_HTableLookup (DN_HTable const* table, void const* key, DN_HTableAllowTombstone allow_tombstone); @@ -4849,25 +5083,36 @@ DN_API DN_TestCore DN_TestSuite DN_API DN_MemDebuggerSnapshot DN_MemDebuggerSnapshotMake (DN_MemDebugger *debugger, DN_Arena *arena); DN_API bool DN_MemDebuggerSnapshotPtrDataQSortComparePtrLT (void const *lhs, void const *rhs, void*); -DN_API void DN_MemDebuggerAlloc_ (DN_MemDebugger *debugger, void *ptr, DN_USize size, bool alloc_can_leak, DN_CallSite call_site); +DN_API bool DN_MemDebuggerSnapshotPtrDataQSortCompareBytesLT (void const *lhs, void const *rhs, void *user_context); +DN_API bool DN_MemDebuggerSnapshotPtrDataQSortCompareBytesGT (void const *lhs, void const *rhs, void *user_context); +DN_API bool DN_MemDebuggerMemListSnapshotQSortCompareCommitGT (void const *lhs, void const *rhs, void *user_context); +DN_API bool DN_MemDebuggerMemListAllocQSortCompareAllocSizeGT (void const *lhs, void const *rhs, void *user_context); +DN_API void DN_MemDebuggerAlloc_ (DN_MemDebugger *debugger, void *ptr, DN_USize reserve, DN_USize commit, bool alloc_can_leak, DN_CallSite call_site); DN_API void DN_MemDebuggerDealloc_ (DN_MemDebugger *debugger, void *ptr); DN_API void DN_MemDebuggerDump_ (DN_MemDebugger *debugger); -#if defined(DN_MEM_DEBUGGER) -#define DN_MemDebuggerAlloc(debugger, ptr, size, alloc_can_leak, call_site) DN_MemDebuggerAlloc_(debugger, ptr, size, alloc_can_leak, call_site) -#define DN_MemDebuggerDealloc(debugger, ptr) DN_MemDebuggerDealloc_(debugger, ptr) -#define DN_MemDebuggerDump(debugger) DN_MemDebuggerDump_(debugger) +#if DN_MEM_DEBUGGER +#define DN_MemDebuggerAlloc(debugger, ptr, reserve, commit, alloc_can_leak, call_site) DN_MemDebuggerAlloc_(debugger, ptr, reserve, commit, alloc_can_leak, call_site) +#define DN_MemDebuggerDealloc(debugger, ptr) DN_MemDebuggerDealloc_(debugger, ptr) +#define DN_MemDebuggerDump(debugger) DN_MemDebuggerDump_(debugger) #else -#define DN_MemDebuggerAlloc(debugger, ptr, size, alloc_can_leak, call_site) do { (void)ptr; (void)size; (void)alloc_can_leak; } while (0) -#define DN_MemDebuggerDealloc(debugger, ptr) do { (void)ptr; } while (0) -#define DN_MemDebuggerDump(debugger) do { } while (0) +#define DN_MemDebuggerAlloc(debugger, ptr, reserve, commit, alloc_can_leak, call_site) do { (void)ptr; (void)reserve; (void)commit; (void)alloc_can_leak; } while (0) +#define DN_MemDebuggerDealloc(debugger, ptr) do { (void)ptr; } while (0) +#define DN_MemDebuggerDump(debugger) do { } while (0) #endif #if DN_WITH_OS -DN_API DN_Str8 DN_OS_Str8FromStr8BuilderHeap (DN_Str8Builder const *builder); -DN_API void DN_OS_LogPrintFV (DN_LogTypeParam type, void *user_data, DN_CallSite call_site, DN_LogFlags flags, DN_FMT_ATTRIB char const *fmt, va_list args); -DN_API void DN_OS_LogPrintF (DN_LogTypeParam type, void *user_data, DN_CallSite call_site, DN_LogFlags flags, DN_FMT_ATTRIB char const *fmt, ...); -DN_API void DN_OS_SetLogPrintFuncToOS (); +DN_API DN_Str8 DN_OS_Str8FromStackTraceNowHeap (DN_U16 limit, DN_U16 skip); +#else +#define DN_OS_Str8FromStackTraceNowHeap(...) {} +#endif + +#if DN_WITH_OS +DN_API DN_Str8 DN_OS_Str8FromStr8BuilderHeap (DN_Str8Builder const *builder); + +DN_API void DN_OS_LogPrintFV (DN_LogTypeParam type, void *user_data, DN_CallSite call_site, DN_LogFlags flags, DN_FMT_ATTRIB char const *fmt, va_list args); +DN_API void DN_OS_LogPrintF (DN_LogTypeParam type, void *user_data, DN_CallSite call_site, DN_LogFlags flags, DN_FMT_ATTRIB char const *fmt, ...); +DN_API void DN_OS_SetLogPrintFuncToOS (); // NOTE: Logger // Overview @@ -4954,24 +5199,27 @@ DN_API DN_U64 DN_OS_DateLocalUnixTimeSFromUnixTimeS DN_API void DN_OS_GenBytesSecure (void *buffer, DN_U32 size); DN_API bool DN_OS_SetEnvVar (DN_Str8 name, DN_Str8 value); DN_API DN_OSDiskSpace DN_OS_DiskSpace (DN_Str8 path); +DN_API DN_OSMemoryInfo DN_OS_MemoryInfo (); DN_API DN_Str8 DN_OS_ExePath (DN_Arena *arena); DN_API DN_Str8 DN_OS_ExeDir (DN_Arena *arena); -DN_API void DN_OS_OpenUrl (DN_Str8 url); +DN_API void DN_OS_OpenInDefaultApp (DN_Str8 url); DN_API void DN_OS_SleepMs (DN_UInt milliseconds); +DN_API bool DN_OS_OnceEveryS (DN_U64 *tsc, DN_U64 interval_s); DN_API DN_U64 DN_OS_PerfCounterNow (); DN_API DN_U64 DN_OS_PerfCounterFrequency (); -DN_API DN_F64 DN_OS_PerfCounterS (DN_U64 begin, uint64_t end); -DN_API DN_F64 DN_OS_PerfCounterMs (DN_U64 begin, uint64_t end); -DN_API DN_F64 DN_OS_PerfCounterUs (DN_U64 begin, uint64_t end); -DN_API DN_F64 DN_OS_PerfCounterNs (DN_U64 begin, uint64_t end); +DN_API DN_F64 DN_OS_PerfCounterS (DN_U64 begin, DN_U64 end); +DN_API DN_F64 DN_OS_PerfCounterMs (DN_U64 begin, DN_U64 end); +DN_API DN_F64 DN_OS_PerfCounterUs (DN_U64 begin, DN_U64 end); +DN_API DN_F64 DN_OS_PerfCounterNs (DN_U64 begin, DN_U64 end); + DN_API DN_OSTimer DN_OS_TimerBegin (); DN_API void DN_OS_TimerEnd (DN_OSTimer *timer); DN_API DN_F64 DN_OS_TimerS (DN_OSTimer timer); DN_API DN_F64 DN_OS_TimerMs (DN_OSTimer timer); DN_API DN_F64 DN_OS_TimerUs (DN_OSTimer timer); DN_API DN_F64 DN_OS_TimerNs (DN_OSTimer timer); -DN_API DN_U64 DN_OS_EstimateTscPerSecond (uint64_t duration_ms_to_gauge_tsc_frequency); +DN_API DN_U64 DN_OS_EstimateTscPerSecond (DN_U64 duration_ms_to_gauge_tsc_frequency); // NOTE: OS File // Overview @@ -5036,12 +5284,18 @@ DN_API bool DN_OS_FileWriteAllSafeF (D DN_API DN_Str8 DN_OS_Str8FromPathInfoType (DN_OSPathInfoType type); DN_API DN_OSPathInfo DN_OS_PathInfo (DN_Str8 path); +DN_API bool DN_OS_PathInfoFileHasChanged (DN_OSPathInfo lhs, DN_OSPathInfo rhs); DN_API bool DN_OS_PathIsOlderThan (DN_Str8 file, DN_Str8 check_against); -DN_API bool DN_OS_PathDelete (DN_Str8 path); +DN_API DN_OSPathResult DN_OS_PathCanonicalise (DN_Arena *arena, DN_Str8 path, DN_ErrSink *error); +DN_API DN_OSPathResult DN_OS_PathRelativeTo (DN_Arena *arena, DN_Str8 from, DN_Str8 to); +DN_API bool DN_OS_PathIsRelative (DN_Str8 path); DN_API bool DN_OS_PathIsFile (DN_Str8 path); DN_API bool DN_OS_PathIsDir (DN_Str8 path); +DN_API bool DN_OS_PathDelete (DN_Str8 path); DN_API bool DN_OS_PathMakeDir (DN_Str8 path); DN_API bool DN_OS_PathIterateDir (DN_Str8 path, DN_OSDirIterator *it); +DN_API bool DN_OS_PathWatchFileHasChanged (DN_OSPathWatchFile *watch, DN_Str8 path, DN_OSPathWatchFileAcceptChange accept); +DN_API void DN_OS_PathWatchFileAcceptChange (DN_OSPathWatchFile *watch); DN_API void DN_OS_Exit (int32_t exit_code); DN_API DN_OSExecArgs DN_OS_ExecArgsDefault (); @@ -5267,13 +5521,6 @@ DN_API void DN_OS_PrintLnFVStyle (DN_OSPrintDest dest, DN_LogStyle style, // NOTE: Template implementations #if defined(__cplusplus) -template T *DN_MemCopyObjT(T *dest, T const *src, DN_USize count) -{ - T* result = dest; - DN_Memcpy(dest, src, sizeof(T) * count); - return result; -} - template DN_ArrayFindResult DN_TArrayFind(T *data, DN_USize count, void const *find, DN_ArrayFindEqFunc *eq_func) { @@ -5359,189 +5606,69 @@ T *DN_TArrayAddArrayAssert(T *data, DN_USize *count, DN_USize max, T const *elem } template -T *DN_TArrayMakeArrayArena(T **data, DN_USize *count, DN_USize *max, DN_Arena *arena, DN_USize make_count, DN_ZMem z_mem) +T *DN_TArrayMakeArrayAllocator(T **data, DN_USize *count, DN_USize *max, DN_Allocator allocator, DN_USize make_count, DN_ZMem z_mem) { - T *result = DN_Cast(T *)DN_ArrayMakeArrayArena(DN_Cast(void **)data, count, max, sizeof(**data), arena, make_count, z_mem); + T *result = DN_Cast(T *)DN_ArrayMakeArrayAllocator(DN_Cast(void **)data, count, max, sizeof(**data), allocator, make_count, z_mem); return result; } template -T *DN_TArrayMakeArrayArenaZ(T **data, DN_USize *count, DN_USize *max, DN_Arena *arena, DN_USize make_count) +T *DN_TArrayMakeArrayAllocatorZ(T **data, DN_USize *count, DN_USize *max, DN_Allocator allocator, DN_USize make_count) { - T *result = DN_TArrayMakeArrayArena(data, count, max, arena, make_count, DN_ZMem_Yes); + T *result = DN_TArrayMakeArrayAllocator(data, count, max, allocator, make_count, DN_ZMem_Yes); return result; } template -T *DN_TArrayMakeArrayArenaNoZ(T **data, DN_USize *count, DN_USize *max, DN_Arena *arena, DN_USize make_count) +T *DN_TArrayMakeArrayAllocatorNoZ(T **data, DN_USize *count, DN_USize *max, DN_Allocator allocator, DN_USize make_count) { - T *result = DN_TArrayMakeArrayArena(data, count, max, arena, make_count, DN_ZMem_No); + T *result = DN_TArrayMakeArrayAllocator(data, count, max, allocator, make_count, DN_ZMem_No); return result; } template -T *DN_TArrayMakeArrayPool(T **data, DN_USize *count, DN_USize *max, DN_Pool *pool, DN_USize make_count, DN_ZMem z_mem) +T *DN_TArrayAddArrayAllocator(T **data, DN_USize *count, DN_USize *max, DN_Allocator allocator, T const *elems, DN_USize elems_count, DN_AddType add) { - T *result = DN_Cast(T *)DN_ArrayMakeArrayPool(DN_Cast(void **)data, count, max, sizeof(**data), pool, make_count, z_mem); + T *result = DN_Cast(T *)DN_ArrayAddArrayAllocator(DN_Cast(void **)data, count, max, sizeof(**data), allocator, elems, elems_count, add); return result; } template -T *DN_TArrayMakeArrayPoolZ(T **data, DN_USize *count, DN_USize *max, DN_Pool *pool, DN_USize make_count) +bool DN_TArrayResizeAllocator(T **data, DN_USize *count, DN_USize *max, DN_Allocator allocator, DN_USize new_max) { - T *result = DN_TArrayMakeArrayPool(data, count, max, pool, make_count, DN_ZMem_Yes); + bool result = DN_ArrayResizeAllocator(DN_Cast(void **)data, count, max, sizeof(**data), allocator, new_max); return result; } template -T *DN_TArrayMakeArrayPoolNoZ(T **data, DN_USize *count, DN_USize *max, DN_Pool *pool, DN_USize make_count) +bool DN_TArrayReserveAllocator(T **data, DN_USize *max, DN_Allocator allocator, DN_USize new_max) { - T *result = DN_TArrayMakeArrayPool(data, count, max, pool, make_count, DN_ZMem_No); + bool result = DN_ArrayReserveAllocator(DN_Cast(void **)data, max, sizeof(**data), allocator, new_max); return result; } template -T *DN_TArrayAddArrayArena(T **data, DN_USize *count, DN_USize *max, DN_Arena *arena, T const *elems, DN_USize elems_count, DN_AddType add) +bool DN_TArrayPrepareAllocator(T **data, DN_USize count, DN_USize *max, DN_Allocator allocator, DN_USize add_count) { - T *result = DN_Cast(T *)DN_ArrayAddArrayArena(DN_Cast(void **)data, count, max, sizeof(**data), arena, elems, elems_count, add); + bool result = DN_ArrayPrepareAllocator(DN_Cast(void **)data, count, max, sizeof(**data), allocator, add_count); return result; } template -T *DN_TArrayAddArrayPool(T **data, DN_USize *count, DN_USize *max, DN_Pool *pool, T const *elems, DN_USize elems_count, DN_AddType add) +DN_USize DN_TArrayCopyPtrAllocator(T **data, T const *src, DN_USize count, DN_Allocator allocator) { - T *result = DN_Cast(T *)DN_ArrayAddArrayPool(DN_Cast(void **)data, count, max, sizeof(**data), pool, elems, elems_count, add); + DN_USize result = DN_ArrayCopyPtrAllocator(DN_Cast(void **)data, src, count, sizeof(T), allocator); return result; } template -T *DN_TArrayMakeArena(T **data, DN_USize *count, DN_USize *max, DN_Arena *arena, DN_ZMem z_mem) +DN_USize DN_TArrayCopyPtrAllocatorAssert(T **data, T const *src, DN_USize count, DN_Allocator allocator, DN_CallSite call_site) { - T *result = DN_TArrayMakeArrayArena(data, count, max, arena, 1, z_mem); - return result; -} - -template -T *DN_TArrayMakeArenaZ(T **data, DN_USize *count, DN_USize *max, DN_Arena *arena) -{ - T *result = DN_TArrayMakeArrayArena(data, count, max, arena, 1, DN_ZMem_Yes); - return result; -} - -template -T *DN_TArrayMakeArenaNoZ(T **data, DN_USize *count, DN_USize *max, DN_Arena *arena) -{ - T *result = DN_TArrayMakeArrayArena(data, count, max, arena, 1, DN_ZMem_No); - return result; -} - -template -T *DN_TArrayMakePool(T **data, DN_USize *count, DN_USize *max, DN_Pool *pool, DN_ZMem z_mem) -{ - T *result = DN_TArrayMakeArrayPool(data, count, max, pool, 1, z_mem); - return result; -} - -template -T *DN_TArrayMakePoolZ(T **data, DN_USize *count, DN_USize *max, DN_Pool *pool) -{ - T *result = DN_TArrayMakeArrayPool(data, count, max, pool, 1, DN_ZMem_Yes); - return result; -} - -template -T *DN_TArrayMakePoolNoZ(T **data, DN_USize *count, DN_USize *max, DN_Pool *pool) -{ - T *result = DN_TArrayMakeArrayPool(data, count, max, pool, 1, DN_ZMem_No); - return result; -} - -template -T *DN_TArrayAddArena(T **data, DN_USize *count, DN_USize *max, DN_Arena *arena, T const *elems, DN_USize elems_count, DN_AddType add) -{ - T *result = DN_TArrayAddArrayArena(data, count, max, arena, elems, elems_count, add); - return result; -} - -template -T *DN_TArrayAddPool(T **data, DN_USize *count, DN_USize *max, DN_Pool *pool, T const *elems, DN_USize elems_count, DN_AddType add) -{ - T *result = DN_TArrayAddArrayPool(data, count, max, pool, elems, elems_count, add); - return result; -} - -template -bool DN_TArrayResizePool(T **data, DN_USize *count, DN_USize *max, DN_Pool *pool, DN_USize new_max) -{ - bool result = DN_ArrayResizePool(DN_Cast(void **)data, count, max, sizeof(**data), pool, new_max); - return result; -} - -template -bool DN_TArrayResizeArena(T **data, DN_USize *count, DN_USize *max, DN_Arena *arena, DN_USize new_max) -{ - bool result = DN_ArrayResizeArena(DN_Cast(void **)data, count, max, sizeof(**data), arena, new_max); - return result; -} - -template -bool DN_TArrayReservePool(T **data, DN_USize *max, DN_Pool *pool, DN_USize new_max) -{ - bool result = DN_ArrayReservePool(DN_Cast(void **)data, max, sizeof(**data), pool, new_max); - return result; -} - -template -bool DN_TArrayReserveArena(T **data, DN_USize *max, DN_Arena *arena, DN_USize new_max) -{ - bool result = DN_ArrayReserveArena(DN_Cast(void **)data, max, sizeof(**data), arena, new_max); - return result; -} - -template -bool DN_TArrayPreparePool(T **data, DN_USize count, DN_USize *max, DN_Pool *pool, DN_USize add_count) -{ - bool result = DN_ArrayPreparePool(DN_Cast(void **)data, count, max, sizeof(**data), pool, add_count); - return result; -} - -template -bool DN_TArrayPrepareArena(T **data, DN_USize count, DN_USize *max, DN_Arena *arena, DN_USize add_count) -{ - bool result = DN_ArrayPrepareArena(DN_Cast(void **)data, count, max, sizeof(**data), arena, add_count); - return result; -} - -template -DN_USize DN_TArrayCopyPtrArena(T **data, T const *src, DN_USize count, DN_Arena *arena) -{ - DN_USize result = DN_ArrayCopyPtrArena(DN_Cast(void **)data, src, count, sizeof(T), arena); - return result; -} - -template -DN_USize DN_TArrayCopyPtrArenaAssert(T **data, T const *src, DN_USize count, DN_Arena *arena, DN_CallSite call_site) -{ - DN_USize result = DN_ArrayCopyPtrArenaAssert(DN_Cast(void **)data, src, count, sizeof(T), arena, call_site); - return result; -} - -template -DN_USize DN_TArrayCopyPtrPool(T **data, T const *src, DN_USize count, DN_Pool *pool) -{ - DN_USize result = DN_ArrayCopyPtrPool(DN_Cast(void **)data, src, count, sizeof(T), pool); - return result; -} - -template -DN_USize DN_TArrayCopyPtrPoolAssert(T **data, T const *src, DN_USize count, DN_Pool *pool, DN_CallSite call_site) -{ - DN_USize result = DN_ArrayCopyPtrPoolAssert(DN_Cast(void **)data, src, count, sizeof(T), pool, call_site); + DN_USize result = DN_ArrayCopyPtrAllocatorAssert(DN_Cast(void **)data, src, count, sizeof(T), allocator, call_site); return result; } #endif // defined(__cplusplus) -#if DN_WITH_NET typedef enum DN_NETRequestType { DN_NETRequestType_Nil, DN_NETRequestType_HTTP, @@ -5616,7 +5743,7 @@ struct DN_NETResponse typedef struct DN_NETRequest DN_NETRequest; struct DN_NETRequest { - DN_MemList mem; + DN_MemList* mem; DN_Arena arena; DN_Arena start_response_arena; DN_NETRequestType type; @@ -5656,7 +5783,7 @@ struct DN_NETCore { char *base; DN_U64 base_size; - DN_MemList mem; + DN_MemList* mem; DN_Arena arena; DN_OSSemaphore completion_sem; void *context; @@ -5669,20 +5796,23 @@ struct DN_NETCore // object) in the core struct. On top of this is a asynchronous API provided to the caller along // the lines of, do http/ws followed to dispatch a request followed by a blocking wait for // response function. -// + // API // DN_NET_ResponseHasFailed // After a response has been dispatched via do http/ws the returned handle's status can be // queried using this function. A request has failed if the `state` has returned -// `DN_NETResponseState_Error`, or the returned HTTP status code was `>= 400`. +// `DN_NETResponseState_Error`, or the returned HTTP status code was `>= 400`. You can either +// switch on the `response.state` or use this function to blanket identify failed requests. DN_Str8 DN_NET_Str8FromResponseState (DN_NETResponseState state); DN_NETRequest * DN_NET_RequestFromHandle (DN_NETRequestHandle handle); DN_NETRequestHandle DN_NET_HandleFromRequest (DN_NETRequest *request); +bool DN_NET_HandleEq (DN_NETRequestHandle lhs, DN_NETRequestHandle rhs); bool DN_NET_ResponseHasFailed (DN_NETResponse const* resp); bool DN_NET_ResponseHasSucceeded (DN_NETResponse const* resp); bool DN_NET_ResponseIsReady (DN_NETResponse const* resp); DN_Str8 DN_NET_Str8DiagnosticFromResponse(DN_NETResponse const* resp, DN_Arena *arena); +#if DN_WITH_NET // NOTE: Internal functions for different networking implementations to use void DN_NET_BaseInit (DN_NETCore *net, char *base, DN_U64 base_size); DN_NETRequestHandle DN_NET_SetupRequest (DN_NETRequest *request, DN_Str8 url, DN_Str8 method, DN_NETDoHTTPArgs const *args, DN_NETRequestType type); diff --git a/single_header_generator.cpp b/single_header_generator.cpp index 3846870..272731b 100644 --- a/single_header_generator.cpp +++ b/single_header_generator.cpp @@ -65,7 +65,7 @@ static void AppendCppFileLineByLine(DN_Str8Builder *dest, DN_Str8 cpp_path) line = DN_Str8FmtArena(&scratch.arena, "%S// DN: Single header generator commented out => %S", find.start_to_before_match, DN_Str8TrimWhitespaceAround(find.match_to_end_of_buffer)); DN_Str8 rel_include_path = DN_Str8TrimWhitespaceAround(find.after_match_to_end_of_buffer); DN_Str8 root_dir = DN_Str8FileDirectoryFromPath(cpp_path); - extra_include_path = DN_Str8FmtOsPathArena(&scratch.arena, "%S/%S", root_dir, DN_Str8TrimSuffixSensitive(rel_include_path, DN_Str8Lit("\""))); + extra_include_path = DN_Str8PathFmtOsArena(&scratch.arena, "%S/%S", root_dir, DN_Str8TrimSuffixSensitive(rel_include_path, DN_Str8Lit("\""))).value; } } } @@ -113,7 +113,7 @@ int main(int argc, char **argv) DN_Str8Builder builder = DN_Str8BuilderFromArena(&scratch.arena); DN_Str8 suffix = type == FileType_Header ? DN_Str8Lit("h") : DN_Str8Lit("cpp"); for (DN_ForItCArray(it, DN_Str8 const, REL_FILE_PATHS)) { - DN_Str8 path = DN_Str8FmtOsPathArena(&scratch.arena, "%S/%S.%S", dn_root_dir, *it.data, suffix); + DN_Str8 path = DN_Str8PathFmtOsArena(&scratch.arena, "%S/%S.%S", dn_root_dir, *it.data, suffix).value; AppendCppFileLineByLine(&builder, path); } @@ -121,7 +121,7 @@ int main(int argc, char **argv) DN_Str8BuilderPrependF(&builder, "// Generated by the DN single header generator %04u-%02u-%02u %02u:%02u:%02u\n\n", date.year, date.month, date.day, date.hour, date.minutes, date.seconds); DN_Str8 buffer = DN_Str8TrimWhitespaceAround(DN_Str8FromStr8BuilderArena(&builder, &scratch.arena)); - DN_Str8 single_header_path = DN_Str8FmtOsPathArena(&scratch.arena, "%S/dn_single_header.%S", output_dir, suffix); + DN_Str8 single_header_path = DN_Str8PathFmtOsArena(&scratch.arena, "%S/dn_single_header.%S", output_dir, suffix).value; DN_ErrSink *err = DN_TcErrSinkBeginDefault(); DN_OS_FileWriteAllSafe(single_header_path, buffer, err); DN_ErrSinkEndExitIfErrorF(err, -1, "Failed to write Single header file '%S'", single_header_path);