diff --git a/Single-Header/dn_single_header.cpp b/Single-Header/dn_single_header.cpp index 4df4f2b..1e0962c 100644 --- a/Single-Header/dn_single_header.cpp +++ b/Single-Header/dn_single_header.cpp @@ -1,20564 +1,20 @@ -// Generated by the DN single header generator 2025-11-30 21:32:49 +// Generated by the DN single header generator 2026-05-18 11:16:15 -#define DN_BASE_INC_CPP - -// DN: Single header generator inlined this file => #include "Base/dn_base.cpp" -#define DN_BASE_CPP - -#if defined(_CLANGD) - // DN: Single header generator commented out this header => #include "../dn_base_inc.h" -#endif - -DN_API bool DN_MemEq(void const *lhs, DN_USize lhs_size, void const *rhs, DN_USize rhs_size) -{ - bool result = lhs_size == rhs_size && DN_Memcmp(lhs, rhs, rhs_size) == 0; - return result; -} - -#if !defined(DN_PLATFORM_ARM64) && !defined(DN_PLATFORM_EMSCRIPTEN) - #define DN_SUPPORTS_CPU_ID -#endif - -#if defined(DN_SUPPORTS_CPU_ID) && (defined(DN_COMPILER_GCC) || defined(DN_COMPILER_CLANG)) - #include -#endif - -DN_CPUFeatureDecl g_dn_cpu_feature_decl[DN_CPUFeature_Count]; - -DN_API DN_U64 DN_AtomicSetValue64(DN_U64 volatile *target, DN_U64 value) -{ -#if defined(DN_COMPILER_MSVC) || defined(DN_COMPILER_CLANG_CL) - __int64 result; - do { - result = *target; - } while (DN_AtomicCompareExchange64(target, value, result) != result); - return DN_Cast(DN_U64) result; -#elif defined(DN_COMPILER_GCC) || defined(DN_COMPILER_CLANG) - DN_U64 result = __sync_lock_test_and_set(target, value); - return result; -#else - #error Unsupported compiler -#endif -} - -DN_API DN_U32 DN_AtomicSetValue32(DN_U32 volatile *target, DN_U32 value) -{ -#if defined(DN_COMPILER_MSVC) || defined(DN_COMPILER_CLANG_CL) - long result; - do { - result = *target; - } while (DN_AtomicCompareExchange32(target, value, result) != result); - return result; -#elif defined(DN_COMPILER_GCC) || defined(DN_COMPILER_CLANG) - long result = __sync_lock_test_and_set(target, value); - return result; -#else - #error Unsupported compiler -#endif -} - -DN_API DN_CPUIDResult DN_CPUID(DN_CPUIDArgs args) -{ - 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_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_USize chunk_index = query->feature / BITS; - DN_USize chunk_bit = query->feature % BITS; - DN_U64 chunk = report->features[chunk_index]; - query->available = chunk & (1ULL << chunk_bit); - result += DN_Cast(int) query->available; - } - - return result; -} - -DN_API bool DN_CPUHasFeature(DN_CPUReport const *report, DN_CPUFeature feature) -{ - DN_CPUFeatureQuery query = {}; - query.feature = feature; - 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) -{ - bool result = true; - for (DN_USize index = 0; result && index < features_size; index++) - result &= DN_CPUHasFeature(report, features[index]); - return result; -} - -DN_API void DN_CPUSetFeature(DN_CPUReport *report, DN_CPUFeature feature) -{ - 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_CPUReport result = {}; -#if defined(DN_SUPPORTS_CPU_ID) - 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 = {}; - - // NOTE: Query standard function (e.g. eax = 0x0) for function count + cpu vendor - 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); - } - - // NOTE: Extract function count //////////////////////////////////////////////////////////////// - int const STANDARD_FUNC_MAX_EAX = fn_0000_[0x0000].reg.eax; - int const EXTENDED_FUNC_MAX_EAX = fn_8000_[0x0000].reg.eax; - - // NOTE: Enumerate all CPUID results for the known function counts ///////////////////////////// - { - DN_AssertF((STANDARD_FUNC_MAX_EAX + 1) <= DN_ArrayCountI(fn_0000_), - "Max standard count is %d", - STANDARD_FUNC_MAX_EAX + 1); - DN_AssertF((DN_Cast(DN_ISize) EXTENDED_FUNC_MAX_EAX - EXTENDED_FUNC_BASE_EAX + 1) <= DN_ArrayCountI(fn_8000_), - "Max extended count is %zu", - 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 = {}; - args.eax = eax; - 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 = {}; - args.eax = eax; - fn_8000_[index] = DN_CPUID(args); - } - } - - // NOTE: Query CPU vendor ////////////////////////////////////////////////////////////////////// - { - DN_Memcpy(result.vendor + 0, &fn_8000_[0x0000].reg.ebx, REGISTER_SIZE); - DN_Memcpy(result.vendor + 4, &fn_8000_[0x0000].reg.edx, REGISTER_SIZE); - DN_Memcpy(result.vendor + 8, &fn_8000_[0x0000].reg.ecx, REGISTER_SIZE); - } - - // NOTE: Query CPU brand /////////////////////////////////////////////////////////////////////// - if (EXTENDED_FUNC_MAX_EAX >= (EXTENDED_FUNC_BASE_EAX + 4)) { - DN_Memcpy(result.brand + 0, &fn_8000_[0x0002].reg.eax, REGISTER_SIZE); - DN_Memcpy(result.brand + 4, &fn_8000_[0x0002].reg.ebx, REGISTER_SIZE); - DN_Memcpy(result.brand + 8, &fn_8000_[0x0002].reg.ecx, REGISTER_SIZE); - DN_Memcpy(result.brand + 12, &fn_8000_[0x0002].reg.edx, REGISTER_SIZE); - - DN_Memcpy(result.brand + 16, &fn_8000_[0x0003].reg.eax, REGISTER_SIZE); - DN_Memcpy(result.brand + 20, &fn_8000_[0x0003].reg.ebx, REGISTER_SIZE); - DN_Memcpy(result.brand + 24, &fn_8000_[0x0003].reg.ecx, REGISTER_SIZE); - DN_Memcpy(result.brand + 28, &fn_8000_[0x0003].reg.edx, REGISTER_SIZE); - - DN_Memcpy(result.brand + 32, &fn_8000_[0x0004].reg.eax, REGISTER_SIZE); - DN_Memcpy(result.brand + 36, &fn_8000_[0x0004].reg.ebx, REGISTER_SIZE); - DN_Memcpy(result.brand + 40, &fn_8000_[0x0004].reg.ecx, REGISTER_SIZE); - DN_Memcpy(result.brand + 44, &fn_8000_[0x0004].reg.edx, REGISTER_SIZE); - - DN_Assert(result.brand[sizeof(result.brand) - 1] == 0); - } - - // NOTE: Query CPU features ////////////////////////////////////////////////////////////////// - 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_InvalidCodePath; break; - } - - if (available) - DN_CPUSetFeature(&result, DN_Cast(DN_CPUFeature) ext_index); - } -#endif // DN_SUPPORTS_CPU_ID - return result; -} - -// NOTE: DN_TicketMutex //////////////////////////////////////////////////////////////////////////// -DN_API void DN_TicketMutex_Begin(DN_TicketMutex *mutex) -{ - unsigned int ticket = DN_AtomicAddU32(&mutex->ticket, 1); - DN_TicketMutex_BeginTicket(mutex, ticket); -} - -DN_API void DN_TicketMutex_End(DN_TicketMutex *mutex) -{ - DN_AtomicAddU32(&mutex->serving, 1); -} - -DN_API DN_UInt DN_TicketMutex_MakeTicket(DN_TicketMutex *mutex) -{ - DN_UInt result = DN_AtomicAddU32(&mutex->ticket, 1); - return result; -} - -DN_API void DN_TicketMutex_BeginTicket(DN_TicketMutex const *mutex, DN_UInt ticket) -{ - DN_AssertF(mutex->serving <= ticket, - "Mutex skipped ticket? Was ticket generated by the correct mutex via MakeTicket? ticket = %u, " - "mutex->serving = %u", - ticket, - mutex->serving); - while (ticket != mutex->serving) { - // NOTE: Use spinlock intrinsic - _mm_pause(); - } -} - -DN_API bool DN_TicketMutex_CanLock(DN_TicketMutex const *mutex, DN_UInt ticket) -{ - bool result = (ticket == mutex->serving); - return result; -} - -#if defined(DN_COMPILER_MSVC) || defined(DN_COMPILER_CLANG_CL) - #if !defined(DN_CRT_SECURE_NO_WARNINGS_PREVIOUSLY_DEFINED) - #undef _CRT_SECURE_NO_WARNINGS - #endif -#endif - -// NOTE: DN_Bit //////////////////////////////////////////////////////////////////////////////////// -DN_API void DN_BitUnsetInplace(DN_USize *flags, DN_USize bitfield) -{ - *flags = (*flags & ~bitfield); -} - -DN_API void DN_BitSetInplace(DN_USize *flags, DN_USize bitfield) -{ - *flags = (*flags | bitfield); -} - -DN_API bool DN_BitIsSet(DN_USize bits, DN_USize bits_to_set) -{ - auto result = DN_Cast(bool)((bits & bits_to_set) == bits_to_set); - return result; -} - -DN_API bool DN_BitIsNotSet(DN_USize bits, DN_USize bits_to_check) -{ - auto result = !DN_BitIsSet(bits, bits_to_check); - return result; -} - -// NOTE: DN_Safe /////////////////////////////////////////////////////////////////////////////////// -DN_API DN_I64 DN_SafeAddI64(int64_t a, int64_t b) -{ - DN_I64 result = DN_CheckF(a <= INT64_MAX - b, "a=%zd, b=%zd", a, b) ? (a + b) : INT64_MAX; - return result; -} - -DN_API DN_I64 DN_SafeMulI64(int64_t a, int64_t b) -{ - DN_I64 result = DN_CheckF(a <= INT64_MAX / b, "a=%zd, b=%zd", a, b) ? (a * b) : INT64_MAX; - return result; -} - -DN_API DN_U64 DN_SafeAddU64(DN_U64 a, DN_U64 b) -{ - DN_U64 result = DN_CheckF(a <= UINT64_MAX - b, "a=%zu, b=%zu", a, b) ? (a + b) : UINT64_MAX; - return result; -} - -DN_API DN_U64 DN_SafeSubU64(DN_U64 a, DN_U64 b) -{ - DN_U64 result = DN_CheckF(a >= b, "a=%zu, b=%zu", a, b) ? (a - b) : 0; - return result; -} - -DN_API DN_U64 DN_SafeMulU64(DN_U64 a, DN_U64 b) -{ - DN_U64 result = DN_CheckF(a <= UINT64_MAX / b, "a=%zu, b=%zu", a, b) ? (a * b) : UINT64_MAX; - return result; -} - -DN_API DN_U32 DN_SafeSubU32(DN_U32 a, DN_U32 b) -{ - DN_U32 result = DN_CheckF(a >= b, "a=%u, b=%u", a, b) ? (a - b) : 0; - return result; -} - -// NOTE: DN_SaturateCastUSizeToI* //////////////////////////////////////////////////////////// -// INT*_MAX literals will be promoted to the type of uintmax_t as uintmax_t is -// the highest possible rank (unsigned > signed). -DN_API int DN_SaturateCastUSizeToInt(DN_USize val) -{ - int result = DN_Check(DN_Cast(uintmax_t) val <= INT_MAX) ? DN_Cast(int) val : INT_MAX; - return result; -} - -DN_API int8_t DN_SaturateCastUSizeToI8(DN_USize val) -{ - int8_t result = DN_Check(DN_Cast(uintmax_t) val <= INT8_MAX) ? DN_Cast(int8_t) val : INT8_MAX; - return result; -} - -DN_API DN_I16 DN_SaturateCastUSizeToI16(DN_USize val) -{ - DN_I16 result = DN_Check(DN_Cast(uintmax_t) val <= INT16_MAX) ? DN_Cast(DN_I16) val : INT16_MAX; - return result; -} - -DN_API DN_I32 DN_SaturateCastUSizeToI32(DN_USize val) -{ - DN_I32 result = DN_Check(DN_Cast(uintmax_t) val <= INT32_MAX) ? DN_Cast(DN_I32) val : INT32_MAX; - return result; -} - -DN_API int64_t DN_SaturateCastUSizeToI64(DN_USize val) -{ - int64_t result = DN_Check(DN_Cast(uintmax_t) val <= INT64_MAX) ? DN_Cast(int64_t) val : INT64_MAX; - return result; -} - -// NOTE: DN_SaturateCastUSizeToU* //////////////////////////////////////////////////////////// -// Both operands are unsigned and the lowest rank operand will be promoted to -// match the highest rank operand. -DN_API DN_U8 DN_SaturateCastUSizeToU8(DN_USize val) -{ - DN_U8 result = DN_Check(val <= UINT8_MAX) ? DN_Cast(DN_U8) val : UINT8_MAX; - return result; -} - -DN_API DN_U16 DN_SaturateCastUSizeToU16(DN_USize val) -{ - DN_U16 result = DN_Check(val <= UINT16_MAX) ? DN_Cast(DN_U16) val : UINT16_MAX; - return result; -} - -DN_API DN_U32 DN_SaturateCastUSizeToU32(DN_USize val) -{ - DN_U32 result = DN_Check(val <= UINT32_MAX) ? DN_Cast(DN_U32) val : UINT32_MAX; - return result; -} - -DN_API DN_U64 DN_SaturateCastUSizeToU64(DN_USize val) -{ - DN_U64 result = DN_Check(DN_Cast(DN_U64) val <= UINT64_MAX) ? DN_Cast(DN_U64) val : UINT64_MAX; - return result; -} - -// NOTE: DN_SaturateCastU64To* /////////////////////////////////////////////////////////////// -DN_API int DN_SaturateCastU64ToInt(DN_U64 val) -{ - int result = DN_Check(val <= INT_MAX) ? DN_Cast(int) val : INT_MAX; - return result; -} - -DN_API int8_t DN_SaturateCastU64ToI8(DN_U64 val) -{ - int8_t result = DN_Check(val <= INT8_MAX) ? DN_Cast(int8_t) val : INT8_MAX; - return result; -} - -DN_API DN_I16 DN_SaturateCastU64ToI16(DN_U64 val) -{ - DN_I16 result = DN_Check(val <= INT16_MAX) ? DN_Cast(DN_I16) val : INT16_MAX; - return result; -} - -DN_API DN_I32 DN_SaturateCastU64ToI32(DN_U64 val) -{ - DN_I32 result = DN_Check(val <= INT32_MAX) ? DN_Cast(DN_I32) val : INT32_MAX; - return result; -} - -DN_API int64_t DN_SaturateCastU64ToI64(DN_U64 val) -{ - int64_t result = DN_Check(val <= INT64_MAX) ? DN_Cast(int64_t) val : INT64_MAX; - return result; -} - -// Both operands are unsigned and the lowest rank operand will be promoted to -// match the highest rank operand. -DN_API unsigned int DN_SaturateCastU64ToUInt(DN_U64 val) -{ - unsigned int result = DN_Check(val <= UINT8_MAX) ? DN_Cast(unsigned int) val : UINT_MAX; - return result; -} - -DN_API DN_U8 DN_SaturateCastU64ToU8(DN_U64 val) -{ - DN_U8 result = DN_Check(val <= UINT8_MAX) ? DN_Cast(DN_U8) val : UINT8_MAX; - return result; -} - -DN_API DN_U16 DN_SaturateCastU64ToU16(DN_U64 val) -{ - DN_U16 result = DN_Check(val <= UINT16_MAX) ? DN_Cast(DN_U16) val : UINT16_MAX; - return result; -} - -DN_API DN_U32 DN_SaturateCastU64ToU32(DN_U64 val) -{ - DN_U32 result = DN_Check(val <= UINT32_MAX) ? DN_Cast(DN_U32) val : UINT32_MAX; - return result; -} - -// NOTE: DN_SaturateCastISizeToI* //////////////////////////////////////////////////////////// -// Both operands are signed so the lowest rank operand will be promoted to -// match the highest rank operand. -DN_API int DN_SaturateCastISizeToInt(DN_ISize val) -{ - DN_Assert(val >= INT_MIN && val <= INT_MAX); - int result = DN_Cast(int) DN_Clamp(val, INT_MIN, INT_MAX); - return result; -} - -DN_API int8_t DN_SaturateCastISizeToI8(DN_ISize val) -{ - DN_Assert(val >= INT8_MIN && val <= INT8_MAX); - int8_t result = DN_Cast(int8_t) DN_Clamp(val, INT8_MIN, INT8_MAX); - return result; -} - -DN_API DN_I16 DN_SaturateCastISizeToI16(DN_ISize val) -{ - DN_Assert(val >= INT16_MIN && val <= INT16_MAX); - DN_I16 result = DN_Cast(DN_I16) DN_Clamp(val, INT16_MIN, INT16_MAX); - return result; -} - -DN_API DN_I32 DN_SaturateCastISizeToI32(DN_ISize val) -{ - DN_Assert(val >= INT32_MIN && val <= INT32_MAX); - DN_I32 result = DN_Cast(DN_I32) DN_Clamp(val, INT32_MIN, INT32_MAX); - return result; -} - -DN_API int64_t DN_SaturateCastISizeToI64(DN_ISize val) -{ - DN_Assert(DN_Cast(int64_t) val >= INT64_MIN && DN_Cast(int64_t) val <= INT64_MAX); - int64_t result = DN_Cast(int64_t) DN_Clamp(DN_Cast(int64_t) val, INT64_MIN, INT64_MAX); - return result; -} - -// NOTE: DN_SaturateCastISizeToU* //////////////////////////////////////////////////////////// -// If the value is a negative integer, we clamp to 0. Otherwise, we know that -// the value is >=0, we can upcast safely to bounds check against the maximum -// allowed value. -DN_API unsigned int DN_SaturateCastISizeToUInt(DN_ISize val) -{ - unsigned int result = 0; - if (DN_Check(val >= DN_Cast(DN_ISize) 0)) { - if (DN_Check(DN_Cast(uintmax_t) val <= UINT_MAX)) - result = DN_Cast(unsigned int) val; - else - result = UINT_MAX; - } - return result; -} - -DN_API DN_U8 DN_SaturateCastISizeToU8(DN_ISize val) -{ - DN_U8 result = 0; - if (DN_Check(val >= DN_Cast(DN_ISize) 0)) { - if (DN_Check(DN_Cast(uintmax_t) val <= UINT8_MAX)) - result = DN_Cast(DN_U8) val; - else - result = UINT8_MAX; - } - return result; -} - -DN_API DN_U16 DN_SaturateCastISizeToU16(DN_ISize val) -{ - DN_U16 result = 0; - if (DN_Check(val >= DN_Cast(DN_ISize) 0)) { - if (DN_Check(DN_Cast(uintmax_t) val <= UINT16_MAX)) - result = DN_Cast(DN_U16) val; - else - result = UINT16_MAX; - } - return result; -} - -DN_API DN_U32 DN_SaturateCastISizeToU32(DN_ISize val) -{ - DN_U32 result = 0; - if (DN_Check(val >= DN_Cast(DN_ISize) 0)) { - if (DN_Check(DN_Cast(uintmax_t) val <= UINT32_MAX)) - result = DN_Cast(DN_U32) val; - else - result = UINT32_MAX; - } - return result; -} - -DN_API DN_U64 DN_SaturateCastISizeToU64(DN_ISize val) -{ - DN_U64 result = 0; - if (DN_Check(val >= DN_Cast(DN_ISize) 0)) { - if (DN_Check(DN_Cast(uintmax_t) val <= UINT64_MAX)) - result = DN_Cast(DN_U64) val; - else - result = UINT64_MAX; - } - return result; -} - -// NOTE: DN_SaturateCastI64To* /////////////////////////////////////////////////////////////// -// Both operands are signed so the lowest rank operand will be promoted to -// match the highest rank operand. -DN_API DN_ISize DN_SaturateCastI64ToISize(int64_t val) -{ - DN_Check(val >= DN_ISIZE_MIN && val <= DN_ISIZE_MAX); - DN_ISize result = DN_Cast(int64_t) DN_Clamp(val, DN_ISIZE_MIN, DN_ISIZE_MAX); - return result; -} - -DN_API int8_t DN_SaturateCastI64ToI8(int64_t val) -{ - DN_Check(val >= INT8_MIN && val <= INT8_MAX); - int8_t result = DN_Cast(int8_t) DN_Clamp(val, INT8_MIN, INT8_MAX); - return result; -} - -DN_API DN_I16 DN_SaturateCastI64ToI16(int64_t val) -{ - DN_Check(val >= INT16_MIN && val <= INT16_MAX); - DN_I16 result = DN_Cast(DN_I16) DN_Clamp(val, INT16_MIN, INT16_MAX); - return result; -} - -DN_API DN_I32 DN_SaturateCastI64ToI32(int64_t val) -{ - DN_Check(val >= INT32_MIN && val <= INT32_MAX); - DN_I32 result = DN_Cast(DN_I32) DN_Clamp(val, INT32_MIN, INT32_MAX); - return result; -} - -DN_API unsigned int DN_SaturateCastI64ToUInt(int64_t val) -{ - unsigned int result = 0; - if (DN_Check(val >= DN_Cast(int64_t) 0)) { - if (DN_Check(DN_Cast(uintmax_t) val <= UINT_MAX)) - result = DN_Cast(unsigned int) val; - else - result = UINT_MAX; - } - return result; -} - -DN_API DN_ISize DN_SaturateCastI64ToUSize(int64_t val) -{ - DN_USize result = 0; - if (DN_Check(val >= DN_Cast(int64_t) 0)) { - if (DN_Check(DN_Cast(uintmax_t) val <= DN_USIZE_MAX)) - result = DN_Cast(DN_USize) val; - else - result = DN_USIZE_MAX; - } - return result; -} - -DN_API DN_U8 DN_SaturateCastI64ToU8(int64_t val) -{ - DN_U8 result = 0; - if (DN_Check(val >= DN_Cast(int64_t) 0)) { - if (DN_Check(DN_Cast(uintmax_t) val <= UINT8_MAX)) - result = DN_Cast(DN_U8) val; - else - result = UINT8_MAX; - } - return result; -} - -DN_API DN_U16 DN_SaturateCastI64ToU16(int64_t val) -{ - DN_U16 result = 0; - if (DN_Check(val >= DN_Cast(int64_t) 0)) { - if (DN_Check(DN_Cast(uintmax_t) val <= UINT16_MAX)) - result = DN_Cast(DN_U16) val; - else - result = UINT16_MAX; - } - return result; -} - -DN_API DN_U32 DN_SaturateCastI64ToU32(int64_t val) -{ - DN_U32 result = 0; - if (DN_Check(val >= DN_Cast(int64_t) 0)) { - if (DN_Check(DN_Cast(uintmax_t) val <= UINT32_MAX)) - result = DN_Cast(DN_U32) val; - else - result = UINT32_MAX; - } - return result; -} - -DN_API DN_U64 DN_SaturateCastI64ToU64(int64_t val) -{ - DN_U64 result = 0; - if (DN_Check(val >= DN_Cast(int64_t) 0)) { - if (DN_Check(DN_Cast(uintmax_t) val <= UINT64_MAX)) - result = DN_Cast(DN_U64) val; - else - result = UINT64_MAX; - } - return result; -} - -DN_API int8_t DN_SaturateCastIntToI8(int val) -{ - DN_Check(val >= INT8_MIN && val <= INT8_MAX); - int8_t result = DN_Cast(int8_t) DN_Clamp(val, INT8_MIN, INT8_MAX); - return result; -} - -DN_API DN_I16 DN_SaturateCastIntToI16(int val) -{ - DN_Check(val >= INT16_MIN && val <= INT16_MAX); - DN_I16 result = DN_Cast(DN_I16) DN_Clamp(val, INT16_MIN, INT16_MAX); - return result; -} - -DN_API DN_U8 DN_SaturateCastIntToU8(int val) -{ - DN_U8 result = 0; - if (DN_Check(val >= DN_Cast(DN_ISize) 0)) { - if (DN_Check(DN_Cast(uintmax_t) val <= UINT8_MAX)) - result = DN_Cast(DN_U8) val; - else - result = UINT8_MAX; - } - return result; -} - -DN_API DN_U16 DN_SaturateCastIntToU16(int val) -{ - DN_U16 result = 0; - if (DN_Check(val >= DN_Cast(DN_ISize) 0)) { - if (DN_Check(DN_Cast(uintmax_t) val <= UINT16_MAX)) - result = DN_Cast(DN_U16) val; - else - result = UINT16_MAX; - } - return result; -} - -DN_API DN_U32 DN_SaturateCastIntToU32(int val) -{ - static_assert(sizeof(val) <= sizeof(DN_U32), "Sanity check to allow simplifying of casting"); - DN_U32 result = 0; - if (DN_Check(val >= 0)) - result = DN_Cast(DN_U32) val; - return result; -} - -DN_API DN_U64 DN_SaturateCastIntToU64(int val) -{ - static_assert(sizeof(val) <= sizeof(DN_U64), "Sanity check to allow simplifying of casting"); - DN_U64 result = 0; - if (DN_Check(val >= 0)) - result = DN_Cast(DN_U64) val; - return result; -} - -// NOTE: DN_Asan ////////////////////////////////////////////////////////////////////////// //////// -static_assert(DN_IsPowerOfTwoAligned(DN_ASAN_POISON_GUARD_SIZE, DN_ASAN_POISON_ALIGNMENT), - "ASAN poison guard size must be a power-of-two and aligned to ASAN's alignment" - "requirement (8 bytes)"); - -DN_API void DN_ASanPoisonMemoryRegion(void const volatile *ptr, DN_USize size) -{ - if (!ptr || !size) - return; - -#if DN_HAS_FEATURE(address_sanitizer) || defined(__SANITIZE_ADDRESS__) - DN_AssertF(DN_IsPowerOfTwoAligned(ptr, 8), - "Poisoning requires the pointer to be aligned on an 8 byte boundary"); - - __asan_poison_memory_region(ptr, size); - if (DN_ASAN_VET_POISON) { - DN_HardAssert(__asan_address_is_poisoned(ptr)); - DN_HardAssert(__asan_address_is_poisoned((char *)ptr + (size - 1))); - } -#else - (void)ptr; - (void)size; -#endif -} - -DN_API void DN_ASanUnpoisonMemoryRegion(void const volatile *ptr, DN_USize size) -{ - if (!ptr || !size) - return; - -#if DN_HAS_FEATURE(address_sanitizer) || defined(__SANITIZE_ADDRESS__) - __asan_unpoison_memory_region(ptr, size); - if (DN_ASAN_VET_POISON) - DN_HardAssert(__asan_region_is_poisoned((void *)ptr, size) == 0); -#else - (void)ptr; - (void)size; -#endif -} - -DN_API DN_F32 DN_EpsilonClampF32(DN_F32 value, DN_F32 target, DN_F32 epsilon) -{ - DN_F32 delta = DN_Abs(target - value); - DN_F32 result = (delta < epsilon) ? target : value; - return result; -} - -static DN_ArenaBlock *DN_ArenaBlockFromMemFuncs_(DN_U64 reserve, DN_U64 commit, bool track_alloc, bool alloc_can_leak, DN_ArenaMemFuncs mem_funcs) -{ - DN_ArenaBlock *result = nullptr; - switch (mem_funcs.type) { - case DN_ArenaMemFuncType_Nil: - break; - - case DN_ArenaMemFuncType_Basic: { - DN_AssertF(reserve > DN_ARENA_HEADER_SIZE, "%I64u > %I64u", reserve, DN_ARENA_HEADER_SIZE); - result = DN_Cast(DN_ArenaBlock *) mem_funcs.basic_alloc(reserve); - if (!result) - return result; - - result->used = DN_ARENA_HEADER_SIZE; - result->commit = reserve; - result->reserve = reserve; - } break; - - case DN_ArenaMemFuncType_VMem: { - DN_AssertF(mem_funcs.vmem_page_size, "Page size must be set to a non-zero, power of two value"); - DN_Assert(DN_IsPowerOfTwo(mem_funcs.vmem_page_size)); - - DN_USize const page_size = mem_funcs.vmem_page_size; - DN_U64 real_reserve = reserve ? reserve : DN_ARENA_RESERVE_SIZE; - DN_U64 real_commit = commit ? commit : DN_ARENA_COMMIT_SIZE; - real_reserve = DN_AlignUpPowerOfTwo(real_reserve, page_size); - real_commit = DN_Min(DN_AlignUpPowerOfTwo(real_commit, page_size), real_reserve); - DN_AssertF(DN_ARENA_HEADER_SIZE < real_commit && real_commit <= real_reserve, "%I64u < %I64u <= %I64u", DN_ARENA_HEADER_SIZE, real_commit, real_reserve); - - DN_MemCommit mem_commit = real_reserve == real_commit ? DN_MemCommit_Yes : DN_MemCommit_No; - result = DN_Cast(DN_ArenaBlock *) mem_funcs.vmem_reserve(real_reserve, mem_commit, DN_MemPage_ReadWrite); - if (!result) - return result; - - if (mem_commit == DN_MemCommit_No && !mem_funcs.vmem_commit(result, real_commit, DN_MemPage_ReadWrite)) { - mem_funcs.vmem_release(result, real_reserve); - return result; - } - - result->used = DN_ARENA_HEADER_SIZE; - result->commit = real_commit; - result->reserve = real_reserve; - } break; - } - - if (track_alloc && result) - DN_LeakTrackAlloc(&g_dn_->leak, result, result->reserve, alloc_can_leak); - - return result; -} - -static DN_ArenaBlock *DN_ArenaBlockFlagsFromMemFuncs_(DN_U64 reserve, DN_U64 commit, DN_ArenaFlags flags, DN_ArenaMemFuncs mem_funcs) -{ - bool track_alloc = (flags & DN_ArenaFlags_NoAllocTrack) == 0; - bool alloc_can_leak = flags & DN_ArenaFlags_AllocCanLeak; - DN_ArenaBlock *result = DN_ArenaBlockFromMemFuncs_(reserve, commit, track_alloc, alloc_can_leak, mem_funcs); - if (result && ((flags & DN_ArenaFlags_NoPoison) == 0)) - DN_ASanPoisonMemoryRegion(DN_Cast(char *) result + DN_ARENA_HEADER_SIZE, result->commit - DN_ARENA_HEADER_SIZE); - return result; -} - -static void DN_ArenaUpdateStatsOnNewBlock_(DN_Arena *arena, DN_ArenaBlock const *block) -{ - DN_Assert(arena); - if (block) { - arena->stats.info.used += block->used; - arena->stats.info.commit += block->commit; - arena->stats.info.reserve += block->reserve; - arena->stats.info.blocks += 1; - - arena->stats.hwm.used = DN_Max(arena->stats.hwm.used, arena->stats.info.used); - arena->stats.hwm.commit = DN_Max(arena->stats.hwm.commit, arena->stats.info.commit); - arena->stats.hwm.reserve = DN_Max(arena->stats.hwm.reserve, arena->stats.info.reserve); - arena->stats.hwm.blocks = DN_Max(arena->stats.hwm.blocks, arena->stats.info.blocks); - } -} - -DN_API DN_Arena DN_ArenaFromBuffer(void *buffer, DN_USize size, DN_ArenaFlags flags) -{ - 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); - DN_AssertF(DN_IsPowerOfTwo(size), "Buffer (%zu bytes) must be a power-of-two", size); - - // NOTE: Init block - DN_ArenaBlock *block = DN_Cast(DN_ArenaBlock *) buffer; - block->commit = size; - block->reserve = size; - block->used = DN_ARENA_HEADER_SIZE; - if (block && ((flags & DN_ArenaFlags_NoPoison) == 0)) - DN_ASanPoisonMemoryRegion(DN_Cast(char *) block + DN_ARENA_HEADER_SIZE, block->commit - DN_ARENA_HEADER_SIZE); - - DN_Arena result = {}; - result.flags = flags | DN_ArenaFlags_NoGrow | DN_ArenaFlags_NoAllocTrack | DN_ArenaFlags_AllocCanLeak | DN_ArenaFlags_UserBuffer; - result.curr = block; - DN_ArenaUpdateStatsOnNewBlock_(&result, result.curr); - return result; -} - -DN_API DN_Arena DN_ArenaFromMemFuncs(DN_U64 reserve, DN_U64 commit, DN_ArenaFlags flags, DN_ArenaMemFuncs mem_funcs) -{ - DN_Arena result = {}; - result.flags = flags; - result.mem_funcs = mem_funcs; - result.flags |= DN_ArenaFlags_MemFuncs; - result.curr = DN_ArenaBlockFlagsFromMemFuncs_(reserve, commit, flags, mem_funcs); - DN_ArenaUpdateStatsOnNewBlock_(&result, result.curr); - return result; -} - -static void DN_ArenaBlockDeinit_(DN_Arena const *arena, DN_ArenaBlock *block) -{ - DN_USize release_size = block->reserve; - if (DN_BitIsNotSet(arena->flags, DN_ArenaFlags_NoAllocTrack)) - DN_LeakTrackDealloc(&g_dn_->leak, block); - DN_ASanUnpoisonMemoryRegion(block, block->commit); - if (arena->flags & DN_ArenaFlags_MemFuncs) { - if (arena->mem_funcs.type == DN_ArenaMemFuncType_Basic) - arena->mem_funcs.basic_dealloc(block); - else - arena->mem_funcs.vmem_release(block, release_size); - } -} - -DN_API void DN_ArenaDeinit(DN_Arena *arena) -{ - for (DN_ArenaBlock *block = arena ? arena->curr : nullptr; block;) { - DN_ArenaBlock *block_to_free = block; - block = block->prev; - DN_ArenaBlockDeinit_(arena, block_to_free); - } - if (arena) - *arena = {}; -} - -DN_API bool DN_ArenaCommitTo(DN_Arena *arena, DN_U64 pos) -{ - if (!arena || !arena->curr) - return false; - - DN_ArenaBlock *curr = arena->curr; - if (pos <= curr->commit) - return true; - - DN_U64 real_pos = pos; - if (!DN_Check(pos <= curr->reserve)) - real_pos = curr->reserve; - - DN_Assert(arena->mem_funcs.vmem_page_size); - DN_USize end_commit = DN_AlignUpPowerOfTwo(real_pos, arena->mem_funcs.vmem_page_size); - DN_USize commit_size = end_commit - curr->commit; - char *commit_ptr = DN_Cast(char *) curr + curr->commit; - if (!arena->mem_funcs.vmem_commit(commit_ptr, commit_size, DN_MemPage_ReadWrite)) - return false; - - bool poison = DN_ASAN_POISON && ((arena->flags & DN_ArenaFlags_NoPoison) == 0); - if (poison) - DN_ASanPoisonMemoryRegion(commit_ptr, commit_size); - - curr->commit = end_commit; - return true; -} - -DN_API bool DN_ArenaCommit(DN_Arena *arena, DN_U64 size) -{ - if (!arena || !arena->curr) - return false; - DN_U64 pos = DN_Min(arena->curr->reserve, arena->curr->commit + size); - bool result = DN_ArenaCommitTo(arena, pos); - return result; -} - -DN_API bool DN_ArenaGrow(DN_Arena *arena, DN_U64 reserve, DN_U64 commit) -{ - if (arena->flags & (DN_ArenaFlags_NoGrow | DN_ArenaFlags_UserBuffer)) - return false; - - bool result = false; - DN_ArenaBlock *new_block = DN_ArenaBlockFlagsFromMemFuncs_(reserve, commit, arena->flags, arena->mem_funcs); - if (new_block) { - result = true; - new_block->prev = arena->curr; - arena->curr = new_block; - new_block->reserve_sum = new_block->prev->reserve_sum + new_block->prev->reserve; - DN_ArenaUpdateStatsOnNewBlock_(arena, arena->curr); - } - return result; -} - -DN_API void *DN_ArenaAlloc(DN_Arena *arena, DN_U64 size, uint8_t align, DN_ZMem z_mem) -{ - if (!arena) - return nullptr; - - if (!arena->curr) { - arena->curr = DN_ArenaBlockFlagsFromMemFuncs_(DN_ARENA_RESERVE_SIZE, DN_ARENA_COMMIT_SIZE, arena->flags, arena->mem_funcs); - DN_ArenaUpdateStatsOnNewBlock_(arena, arena->curr); - } - - if (!arena->curr) - return nullptr; - - try_alloc_again: - DN_ArenaBlock *curr = arena->curr; - bool poison = DN_ASAN_POISON && ((arena->flags & DN_ArenaFlags_NoPoison) == 0); - uint8_t real_align = poison ? DN_Max(align, DN_ASAN_POISON_ALIGNMENT) : align; - DN_U64 offset_pos = DN_AlignUpPowerOfTwo(curr->used, real_align) + (poison ? DN_ASAN_POISON_GUARD_SIZE : 0); - DN_U64 end_pos = offset_pos + size; - DN_U64 alloc_size = end_pos - curr->used; - - if (end_pos > curr->reserve) { - if (arena->flags & (DN_ArenaFlags_NoGrow | DN_ArenaFlags_UserBuffer)) - 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_ArenaGrow(arena, new_reserve, new_commit)) - return nullptr; - goto try_alloc_again; - } - - DN_USize prev_arena_commit = curr->commit; - if (end_pos > curr->commit) { - DN_Assert(arena->mem_funcs.vmem_page_size); - DN_Assert(arena->mem_funcs.type == DN_ArenaMemFuncType_VMem); - DN_Assert((arena->flags & DN_ArenaFlags_UserBuffer) == 0); - DN_USize end_commit = DN_AlignUpPowerOfTwo(end_pos, arena->mem_funcs.vmem_page_size); - DN_USize commit_size = end_commit - curr->commit; - char *commit_ptr = DN_Cast(char *) curr + curr->commit; - if (!arena->mem_funcs.vmem_commit(commit_ptr, commit_size, DN_MemPage_ReadWrite)) - return nullptr; - if (poison) - DN_ASanPoisonMemoryRegion(commit_ptr, commit_size); - curr->commit = end_commit; - arena->stats.info.commit += commit_size; - arena->stats.hwm.commit = DN_Max(arena->stats.hwm.commit, arena->stats.info.commit); - } - - void *result = DN_Cast(char *) curr + offset_pos; - curr->used += alloc_size; - arena->stats.info.used += alloc_size; - arena->stats.hwm.used = DN_Max(arena->stats.hwm.used, arena->stats.info.used); - DN_ASanUnpoisonMemoryRegion(result, size); - - if (z_mem == DN_ZMem_Yes) { - DN_USize reused_bytes = DN_Min(prev_arena_commit - offset_pos, size); - DN_Memset(result, 0, reused_bytes); - } - - DN_Assert(arena->stats.hwm.used >= arena->stats.info.used); - DN_Assert(arena->stats.hwm.commit >= arena->stats.info.commit); - DN_Assert(arena->stats.hwm.reserve >= arena->stats.info.reserve); - DN_Assert(arena->stats.hwm.blocks >= arena->stats.info.blocks); - return result; -} - -DN_API void *DN_ArenaAllocContiguous(DN_Arena *arena, DN_U64 size, uint8_t align, DN_ZMem z_mem) -{ - DN_ArenaFlags prev_flags = arena->flags; - arena->flags |= (DN_ArenaFlags_NoGrow | DN_ArenaFlags_NoPoison); - void *memory = DN_ArenaAlloc(arena, size, align, z_mem); - arena->flags = prev_flags; - return memory; -} - -DN_API void *DN_ArenaCopy(DN_Arena *arena, void const *data, DN_U64 size, uint8_t align) -{ - if (!arena || !data || size == 0) - return nullptr; - void *result = DN_ArenaAlloc(arena, size, align, DN_ZMem_No); - if (result) - DN_Memcpy(result, data, size); - return result; -} - -DN_API void DN_ArenaPopTo(DN_Arena *arena, DN_U64 init_used) -{ - if (!arena || !arena->curr) - return; - DN_U64 used = DN_Max(DN_ARENA_HEADER_SIZE, init_used); - DN_ArenaBlock *curr = arena->curr; - while (curr->reserve_sum >= used) { - DN_ArenaBlock *block_to_free = curr; - arena->stats.info.used -= block_to_free->used; - arena->stats.info.commit -= block_to_free->commit; - arena->stats.info.reserve -= block_to_free->reserve; - arena->stats.info.blocks -= 1; - if (arena->flags & DN_ArenaFlags_UserBuffer) - break; - curr = curr->prev; - DN_ArenaBlockDeinit_(arena, block_to_free); - } - - arena->stats.info.used -= curr->used; - arena->curr = curr; - curr->used = used - curr->reserve_sum; - char *poison_ptr = (char *)curr + DN_AlignUpPowerOfTwo(curr->used, DN_ASAN_POISON_ALIGNMENT); - DN_USize poison_size = ((char *)curr + curr->commit) - poison_ptr; - DN_ASanPoisonMemoryRegion(poison_ptr, poison_size); - arena->stats.info.used += curr->used; -} - -DN_API void DN_ArenaPop(DN_Arena *arena, DN_U64 amount) -{ - DN_ArenaBlock *curr = arena->curr; - DN_USize used_sum = curr->reserve_sum + curr->used; - if (!DN_Check(amount <= used_sum)) - amount = used_sum; - DN_USize pop_to = used_sum - amount; - DN_ArenaPopTo(arena, pop_to); -} - -DN_API DN_U64 DN_ArenaPos(DN_Arena const *arena) -{ - DN_U64 result = (arena && arena->curr) ? arena->curr->reserve_sum + arena->curr->used : 0; - return result; -} - -DN_API void DN_ArenaClear(DN_Arena *arena) -{ - DN_ArenaPopTo(arena, 0); -} - -DN_API bool DN_ArenaOwnsPtr(DN_Arena const *arena, void *ptr) -{ - bool result = false; - uintptr_t uint_ptr = DN_Cast(uintptr_t) ptr; - for (DN_ArenaBlock const *block = arena ? arena->curr : nullptr; !result && block; block = block->prev) { - uintptr_t begin = DN_Cast(uintptr_t) block + DN_ARENA_HEADER_SIZE; - uintptr_t end = begin + block->reserve; - result = uint_ptr >= begin && uint_ptr <= end; - } - return result; -} - -DN_API DN_Str8x64 DN_ArenaInfoStr8x64(DN_ArenaInfo info) -{ - DN_Str8x64 result = {}; - DN_Str8x32 used = DN_ByteCountStr8x32(info.used); - DN_Str8x32 commit = DN_ByteCountStr8x32(info.commit); - DN_Str8x32 reserve = DN_ByteCountStr8x32(info.reserve); - result = DN_Str8x64FromFmt("Blks/Used/Comm/Resv (%u/%.*s/%.*s/%.*s)", DN_Cast(DN_U32)info.blocks, DN_Str8PrintFmt(used), DN_Str8PrintFmt(commit), DN_Str8PrintFmt(reserve)); - return result; -} - -DN_API DN_ArenaStats DN_ArenaSumStatsArray(DN_ArenaStats const *array, DN_USize size) -{ - DN_ArenaStats result = {}; - for (DN_ForItSize(it, DN_ArenaStats const, array, size)) { - DN_ArenaStats stats = *it.data; - result.info.used += stats.info.used; - result.info.commit += stats.info.commit; - result.info.reserve += stats.info.reserve; - result.info.blocks += stats.info.blocks; - - result.hwm.used = DN_Max(result.hwm.used, result.info.used); - result.hwm.commit = DN_Max(result.hwm.commit, result.info.commit); - result.hwm.reserve = DN_Max(result.hwm.reserve, result.info.reserve); - result.hwm.blocks = DN_Max(result.hwm.blocks, result.info.blocks); - } - return result; -} - -DN_API DN_ArenaStats DN_ArenaSumStats(DN_ArenaStats lhs, DN_ArenaStats rhs) -{ - DN_ArenaStats array[] = {lhs, rhs}; - DN_ArenaStats result = DN_ArenaSumStatsArray(array, DN_ArrayCountU(array)); - return result; -} - -DN_API DN_ArenaStats DN_ArenaSumArenaArrayToStats(DN_Arena const *array, DN_USize size) -{ - DN_ArenaStats result = {}; - for (DN_USize index = 0; index < size; index++) { - DN_Arena const *arena = array + index; - result = DN_ArenaSumStats(result, arena->stats); - } - return result; -} - -DN_API DN_ArenaTempMem DN_ArenaTempMemBegin(DN_Arena *arena) -{ - DN_ArenaTempMem result = {}; - if (arena) { - DN_ArenaBlock *curr = arena->curr; - result = {arena, curr ? curr->reserve_sum + curr->used : 0}; - } - return result; -}; - -DN_API void DN_ArenaTempMemEnd(DN_ArenaTempMem mem) -{ - DN_ArenaPopTo(mem.arena, mem.used_sum); -}; - -DN_ArenaTempMemScope::DN_ArenaTempMemScope(DN_Arena *arena) -{ - mem = DN_ArenaTempMemBegin(arena); -} - -DN_ArenaTempMemScope::~DN_ArenaTempMemScope() -{ - DN_ArenaTempMemEnd(mem); -} - -// NOTE: DN_Pool /////////////////////////////////////////////////////////////////////////////////// -DN_API DN_Pool DN_PoolFromArena(DN_Arena *arena, uint8_t align) -{ - DN_Pool result = {}; - if (arena) { - result.arena = arena; - result.align = align ? align : DN_POOL_DEFAULT_ALIGN; - } - return result; -} - -DN_API bool DN_PoolIsValid(DN_Pool const *pool) -{ - bool result = pool && pool->arena && pool->align; - return result; -} - -DN_API void *DN_PoolAlloc(DN_Pool *pool, DN_USize size) -{ - void *result = nullptr; - if (!DN_PoolIsValid(pool)) - return result; - - DN_USize const required_size = sizeof(DN_PoolSlot) + pool->align + size; - DN_USize const size_to_slot_offset = 5; // __lzcnt64(32) e.g. DN_PoolSlotSize_32B - DN_USize slot_index = 0; - if (required_size > 32) { - // NOTE: Round up if not PoT as the low bits are set. - DN_USize dist_to_next_msb = DN_CountLeadingZerosUSize(required_size) + 1; - dist_to_next_msb -= DN_Cast(DN_USize)(!DN_IsPowerOfTwo(required_size)); - - DN_USize const register_size = sizeof(DN_USize) * 8; - DN_AssertF(register_size >= (dist_to_next_msb - size_to_slot_offset), "lhs=%zu, rhs=%zu", register_size, (dist_to_next_msb - size_to_slot_offset)); - slot_index = register_size - dist_to_next_msb - size_to_slot_offset; - } - - if (!DN_CheckF(slot_index < DN_PoolSlotSize_Count, "Chunk pool does not support the requested allocation size")) - return result; - - DN_USize slot_size_in_bytes = 1ULL << (slot_index + size_to_slot_offset); - DN_AssertF(required_size <= (slot_size_in_bytes << 0), "slot_index=%zu, lhs=%zu, rhs=%zu", slot_index, required_size, (slot_size_in_bytes << 0)); - DN_AssertF(required_size >= (slot_size_in_bytes >> 1), "slot_index=%zu, lhs=%zu, rhs=%zu", slot_index, required_size, (slot_size_in_bytes >> 1)); - - DN_PoolSlot *slot = nullptr; - if (pool->slots[slot_index]) { - slot = pool->slots[slot_index]; - pool->slots[slot_index] = slot->next; - 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); - slot = DN_Cast(DN_PoolSlot *) bytes; - - // NOTE: The raw pointer is round up to the next 'pool->align'-ed - // address ensuring at least 1 byte of padding between the raw pointer - // and the pointer given to the user and that the user pointer is - // aligned to the pool's alignment. - // - // This allows us to smuggle 1 byte behind the user pointer that has - // the offset to the original pointer. - slot->data = DN_Cast(void *) DN_AlignDownPowerOfTwo(DN_Cast(uintptr_t) slot + sizeof(DN_PoolSlot) + pool->align, pool->align); - - uintptr_t offset_to_original_ptr = DN_Cast(uintptr_t) slot->data - DN_Cast(uintptr_t) bytes; - DN_Assert(slot->data > bytes); - DN_Assert(offset_to_original_ptr <= sizeof(DN_PoolSlot) + pool->align); - - // NOTE: Store the offset to the original pointer behind the user's - // pointer. - char *offset_to_original_storage = DN_Cast(char *) slot->data - 1; - DN_Memcpy(offset_to_original_storage, &offset_to_original_ptr, 1); - } - - // NOTE: Smuggle the slot type in the next pointer so that we know, when the - // pointer gets returned which free list to return the pointer to. - result = slot->data; - slot->next = DN_Cast(DN_PoolSlot *) slot_index; - return result; -} - -DN_API void DN_PoolDealloc(DN_Pool *pool, void *ptr) -{ - if (!DN_PoolIsValid(pool) || !ptr) - return; - - DN_Assert(DN_ArenaOwnsPtr(pool->arena, ptr)); - - char const *one_byte_behind_ptr = DN_Cast(char *) ptr - 1; - DN_USize offset_to_original_ptr = 0; - DN_Memcpy(&offset_to_original_ptr, one_byte_behind_ptr, 1); - DN_Assert(offset_to_original_ptr <= sizeof(DN_PoolSlot) + pool->align); - - char *original_ptr = DN_Cast(char *) ptr - offset_to_original_ptr; - DN_PoolSlot *slot = DN_Cast(DN_PoolSlot *) original_ptr; - DN_PoolSlotSize slot_index = DN_Cast(DN_PoolSlotSize)(DN_Cast(uintptr_t) slot->next); - DN_Assert(slot_index < DN_PoolSlotSize_Count); - - slot->next = pool->slots[slot_index]; - pool->slots[slot_index] = slot; -} - -DN_API void *DN_PoolCopy(DN_Pool *pool, void const *data, DN_U64 size, uint8_t align) -{ - if (!pool || !data || size == 0) - return nullptr; - - // TODO: Hmm should align be part of the alloc interface in general? I'm not going to worry - // about this until we crash because of misalignment. - DN_Assert(pool->align >= align); - - void *result = DN_PoolAlloc(pool, size); - if (result) - DN_Memcpy(result, data, size); - return result; -} - -DN_API bool DN_CharIsAlphabet(char ch) -{ - bool result = (ch >= 'A' && ch <= 'Z') || (ch >= 'a' && ch <= 'z'); - return result; -} - -DN_API bool DN_CharIsDigit(char ch) -{ - bool result = (ch >= '0' && ch <= '9'); - return result; -} - -DN_API bool DN_CharIsAlphaNum(char ch) -{ - bool result = DN_CharIsAlphabet(ch) || DN_CharIsDigit(ch); - return result; -} - -DN_API bool DN_CharIsWhitespace(char ch) -{ - bool result = (ch == ' ' || ch == '\t' || ch == '\n' || ch == '\r'); - return result; -} - -DN_API bool DN_CharIsHex(char ch) -{ - bool result = ((ch >= 'a' && ch <= 'f') || (ch >= 'A' && ch <= 'F') || (ch >= '0' && ch <= '9')); - return result; -} - -DN_API char DN_CharToLower(char ch) -{ - char result = ch; - if (result >= 'A' && result <= 'Z') - result += 'a' - 'A'; - return result; -} - -DN_API char DN_CharToUpper(char ch) -{ - char result = ch; - if (result >= 'a' && result <= 'z') - result -= 'a' - 'A'; - return result; -} - -DN_API DN_U64FromResult DN_U64FromStr8(DN_Str8 string, char separator) -{ - // NOTE: Argument check - DN_U64FromResult result = {}; - if (string.size == 0) { - result.success = true; - return result; - } - - // NOTE: Sanitize input/output - DN_Str8 trim_string = DN_Str8TrimWhitespaceAround(string); - if (trim_string.size == 0) { - result.success = true; - return result; - } - - // NOTE: Handle prefix '+' - DN_USize start_index = 0; - if (!DN_CharIsDigit(trim_string.data[0])) { - if (trim_string.data[0] != '+') - return result; - start_index++; - } - - // NOTE: Convert the string number to the binary number - for (DN_USize index = start_index; index < trim_string.size; index++) { - char ch = trim_string.data[index]; - if (index) { - if (separator != 0 && ch == separator) - continue; - } - - if (!DN_CharIsDigit(ch)) - return result; - - result.value = DN_SafeMulU64(result.value, 10); - uint64_t digit = ch - '0'; - result.value = DN_SafeAddU64(result.value, digit); - } - - result.success = true; - return result; -} - -DN_API DN_U64FromResult DN_U64FromPtr(void const *data, DN_USize size, char separator) -{ - DN_Str8 str8 = DN_Str8FromPtr((char *)data, size); - DN_U64FromResult result = DN_U64FromStr8(str8, separator); - return result; -} - -DN_API DN_U64 DN_U64FromPtrUnsafe(void const *data, DN_USize size, char separator) -{ - DN_U64FromResult from = DN_U64FromPtr(data, size, separator); - DN_U64 result = from.value; - DN_Assert(from.success); - return result; -} - -DN_API DN_U64FromResult DN_U64FromHexPtr(void const *hex, DN_USize hex_count) -{ - char *hex_ptr = DN_Cast(char *) hex; - if (hex_count >= 2 && hex_ptr[0] == '0' && (hex_ptr[1] == 'x' || hex_ptr[1] == 'X')) { - hex_ptr += 2; - hex_count -= 2; - } - - DN_U64FromResult result = {}; - DN_USize max_hex_count = sizeof(DN_U64) * 2; - DN_USize count = DN_Min(max_hex_count, hex_count); - DN_Assert(hex_count <= max_hex_count); - for (DN_USize index = 0; index < count; index++) { - char ch = hex_ptr[index]; - DN_U8 val = DN_U8FromHexNibble(ch); - if (val == 0xFF) - return result; - result.value = (result.value << 4) | val; - } - result.success = true; - return result; -} - -DN_API DN_U64 DN_U64FromHexPtrUnsafe(void const *hex, DN_USize hex_count) -{ - DN_U64FromResult from = DN_U64FromHexPtr(hex, hex_count); - DN_U64 result = from.value; - DN_Assert(from.success); - return result; -} - -DN_API DN_U64FromResult DN_U64FromHexStr8(DN_Str8 hex) -{ - DN_U64FromResult result = DN_U64FromHexPtr(hex.data, hex.size); - return result; -} - -DN_API DN_U64 DN_U64FromHexStr8Unsafe(DN_Str8 hex) -{ - DN_U64 result = DN_U64FromHexPtrUnsafe(hex.data, hex.size); - return result; -} - -DN_API DN_I64FromResult DN_I64FromStr8(DN_Str8 string, char separator) -{ - // NOTE: Argument check - DN_I64FromResult result = {}; - if (string.size == 0) { - result.success = true; - return result; - } - - // NOTE: Sanitize input/output - DN_Str8 trim_string = DN_Str8TrimWhitespaceAround(string); - if (trim_string.size == 0) { - result.success = true; - return result; - } - - bool negative = false; - DN_USize start_index = 0; - if (!DN_CharIsDigit(trim_string.data[0])) { - negative = (trim_string.data[start_index] == '-'); - if (!negative && trim_string.data[0] != '+') - return result; - start_index++; - } - - // NOTE: Convert the string number to the binary number - for (DN_USize index = start_index; index < trim_string.size; index++) { - char ch = trim_string.data[index]; - if (index) { - if (separator != 0 && ch == separator) - continue; - } - - if (!DN_CharIsDigit(ch)) - return result; - - result.value = DN_SafeMulU64(result.value, 10); - uint64_t digit = ch - '0'; - result.value = DN_SafeAddU64(result.value, digit); - } - - if (negative) - result.value *= -1; - - result.success = true; - return result; -} - -DN_API DN_I64FromResult DN_I64FromPtr(void const *data, DN_USize size, char separator) -{ - DN_Str8 str8 = DN_Str8FromPtr((char *)data, size); - DN_I64FromResult result = DN_I64FromStr8(str8, separator); - return result; -} - -DN_API DN_I64 DN_I64FromPtrUnsafe(void const *data, DN_USize size, char separator) -{ - DN_I64FromResult from = DN_I64FromPtr(data, size, separator); - DN_I64 result = from.value; - DN_Assert(from.success); - return result; -} - -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 = {}; - DN_USize starting_size = *buf_size; - result.size_req = DN_VSNPrintF(buf + *buf_size, DN_Cast(int)(buf_max - *buf_size), fmt, args); - *buf_size += result.size_req; - if (*buf_size >= (buf_max - 1)) - *buf_size = buf_max - 1; - DN_Assert(*buf_size <= (buf_max - 1)); - result.str8 = DN_Str8FromPtr(buf, *buf_size); - result.truncated = result.str8.size != (starting_size + result.size_req); - return result; -} - -DN_API DN_FmtAppendResult DN_FmtAppend(char *buf, DN_USize *buf_size, DN_USize buf_max, char const *fmt, ...) -{ - va_list args; - va_start(args, fmt); - DN_FmtAppendResult result = DN_FmtVAppend(buf, buf_size, buf_max - (*buf_size), fmt, args); - va_end(args); - return result; -} - -DN_API DN_FmtAppendResult DN_FmtAppendTruncate(char *buf, DN_USize *buf_size, DN_USize buf_max, DN_Str8 truncator, char const *fmt, ...) -{ - va_list args; - va_start(args, fmt); - DN_FmtAppendResult result = DN_FmtVAppend(buf, buf_size, buf_max, fmt, args); - if (result.truncated) - DN_Memcpy(result.str8.data + result.str8.size - truncator.size, truncator.data, truncator.size); - va_end(args); - return result; -} - -DN_API DN_USize DN_FmtSize(DN_FMT_ATTRIB char const *fmt, ...) -{ - va_list args; - va_start(args, fmt); - DN_USize result = DN_VSNPrintF(nullptr, 0, fmt, args); - va_end(args); - return result; -} - -DN_API DN_USize DN_FmtVSize(DN_FMT_ATTRIB char const *fmt, va_list args) -{ - va_list args_copy; - va_copy(args_copy, args); - DN_USize result = DN_VSNPrintF(nullptr, 0, fmt, args_copy); - va_end(args_copy); - return result; -} - -DN_API DN_USize DN_CStr8Size(char const *src) -{ - DN_USize result = 0; - for (; src && src[0] != 0; src++, result++) - ; - return result; -} - -DN_API DN_USize DN_CStr16Size(wchar_t const *src) -{ - DN_USize result = 0; - for (; src && src[0] != 0; src++, result++) - ; - return result; -} - -DN_API bool DN_Str16Eq(DN_Str16 lhs, DN_Str16 rhs) -{ - if (lhs.size != rhs.size) - return false; - bool result = (DN_Memcmp(lhs.data, rhs.data, lhs.size) == 0); - return result; -} - -DN_API DN_Str8 DN_Str8FromCStr8(char const *src) -{ - DN_USize size = DN_CStr8Size(src); - DN_Str8 result = DN_Str8FromPtr(src, size); - return result; -} - -DN_API DN_Str8 DN_Str8FromArena(DN_Arena *arena, DN_USize size, DN_ZMem z_mem) -{ - DN_Str8 result = {}; - result.data = DN_ArenaNewArray(arena, char, size + 1, z_mem); - if (result.data) - result.size = size; - result.data[result.size] = 0; - return result; -} - -DN_API DN_Str8 DN_Str8FromPool(DN_Pool *pool, DN_USize size) -{ - DN_Str8 result = {}; - result.data = DN_PoolNewArray(pool, char, size + 1); - if (result.data) - result.size = size; - result.data[result.size] = 0; - return result; -} - -DN_API DN_Str8 DN_Str8FromPtrArena(DN_Arena *arena, void const *data, DN_USize size) -{ - DN_Str8 result = DN_Str8FromArena(arena, size, DN_ZMem_No); - if (result.size) - DN_Memcpy(result.data, data, size); - return result; -} - -DN_API DN_Str8 DN_Str8FromPtrPool(DN_Pool *pool, void const *data, DN_USize size) -{ - DN_Str8 result = DN_Str8FromPool(pool, size); - if (result.size) - DN_Memcpy(result.data, data, size); - return result; -} - -DN_API DN_Str8 DN_Str8FromStr8Arena(DN_Arena *arena, DN_Str8 string) -{ - DN_Str8 result = {}; - result.data = DN_Cast(char *) DN_ArenaAlloc(arena, string.size + 1, alignof(char), DN_ZMem_No); - if (result.data) { - DN_Memcpy(result.data, string.data, string.size); - result.data[string.size] = 0; - result.size = string.size; - } - return result; -} - -DN_API DN_Str8 DN_Str8FromStr8Pool(DN_Pool *pool, DN_Str8 string) -{ - DN_Str8 result = {}; - result.data = DN_Cast(char *) DN_PoolAlloc(pool, string.size + 1); - if (result.data) { - DN_Memcpy(result.data, string.data, string.size); - result.data[string.size] = 0; - result.size = string.size; - } - return result; -} - -DN_API DN_Str8 DN_Str8FromFmtArena(DN_Arena *arena, DN_FMT_ATTRIB char const *fmt, ...) -{ - va_list va; - va_start(va, fmt); - DN_Str8 result = DN_Str8FromFmtVArena(arena, fmt, va); - va_end(va); - return result; -} - -DN_API DN_Str8 DN_Str8FromFmtVArena(DN_Arena *arena, DN_FMT_ATTRIB char const *fmt, va_list args) -{ - DN_USize size = DN_FmtVSize(fmt, args); - DN_Str8 result = DN_Str8FromArena(arena, size, DN_ZMem_No); - if (result.data) { - DN_USize written = 0; - DN_FmtVAppend(result.data, &written, result.size + 1, fmt, args); - DN_Assert(written == result.size); - } - return result; -} - -DN_API DN_Str8 DN_Str8FromFmtPool(DN_Pool *pool, DN_FMT_ATTRIB char const *fmt, ...) -{ - va_list args; - va_start(args, fmt); - DN_USize size = DN_FmtVSize(fmt, args); - DN_Str8 result = DN_Str8FromPool(pool, size); - if (result.data) { - DN_USize written = 0; - DN_FmtVAppend(result.data, &written, result.size + 1, fmt, args); - DN_Assert(written == result.size); - } - va_end(args); - return result; -} - -DN_API DN_Str8x16 DN_Str8x16FromFmt(DN_FMT_ATTRIB char const *fmt, ...) -{ - va_list args; - va_start(args, fmt); - DN_Str8x16 result = {}; - DN_FmtVAppend(result.data, &result.size, sizeof(result.data), fmt, args); - va_end(args); - return result; -} - -DN_API DN_Str8x16 DN_Str8x16FromFmtV(DN_FMT_ATTRIB char const *fmt, va_list args) -{ - DN_Str8x16 result = {}; - DN_FmtVAppend(result.data, &result.size, sizeof(result.data), fmt, args); - return result; -} - -DN_API DN_Str8x32 DN_Str8x32FromFmt(DN_FMT_ATTRIB char const *fmt, ...) -{ - va_list args; - va_start(args, fmt); - DN_Str8x32 result = {}; - DN_FmtVAppend(result.data, &result.size, sizeof(result.data), fmt, args); - va_end(args); - return result; -} - -DN_API DN_Str8x32 DN_Str8x32FromFmtV(DN_FMT_ATTRIB char const *fmt, va_list args) -{ - DN_Str8x32 result = {}; - DN_FmtVAppend(result.data, &result.size, sizeof(result.data), fmt, args); - return result; -} - -DN_API DN_Str8x64 DN_Str8x64FromFmt(DN_FMT_ATTRIB char const *fmt, ...) -{ - va_list args; - va_start(args, fmt); - DN_Str8x64 result = {}; - DN_FmtVAppend(result.data, &result.size, sizeof(result.data), fmt, args); - va_end(args); - return result; -} - -DN_API DN_Str8x64 DN_Str8x64FromFmtV(DN_FMT_ATTRIB char const *fmt, va_list args) -{ - DN_Str8x64 result = {}; - DN_FmtVAppend(result.data, &result.size, sizeof(result.data), fmt, args); - return result; -} - -DN_API DN_Str8x128 DN_Str8x128FromFmt(DN_FMT_ATTRIB char const *fmt, ...) -{ - va_list args; - va_start(args, fmt); - DN_Str8x128 result = {}; - DN_FmtVAppend(result.data, &result.size, sizeof(result.data), fmt, args); - va_end(args); - return result; -} - -DN_API DN_Str8x128 DN_Str8x128FromFmtV(DN_FMT_ATTRIB char const *fmt, va_list args) -{ - DN_Str8x128 result = {}; - DN_FmtVAppend(result.data, &result.size, sizeof(result.data), fmt, args); - return result; -} - -DN_API DN_Str8x256 DN_Str8x256FromFmt(DN_FMT_ATTRIB char const *fmt, ...) -{ - va_list args; - va_start(args, fmt); - DN_Str8x256 result = {}; - DN_FmtVAppend(result.data, &result.size, sizeof(result.data), fmt, args); - va_end(args); - return result; -} - -DN_API DN_Str8x256 DN_Str8x256FromFmtV(DN_FMT_ATTRIB char const *fmt, va_list args) -{ - DN_Str8x256 result = {}; - DN_FmtVAppend(result.data, &result.size, sizeof(result.data), fmt, args); - return result; -} - -DN_API DN_Str8x32 DN_Str8x32FromU64(DN_U64 val, char separator) -{ - DN_Str8x32 result = {}; - DN_Str8x32 temp = DN_Str8x32FromFmt("%" PRIu64, val); - DN_USize temp_index = 0; - - // NOTE: Write the digits the first, up to [0, 2] digits that do not need a thousandth separator - DN_USize range_without_separator = temp.size % 3; - for (; temp_index < range_without_separator; temp_index++) - result.data[result.size++] = temp.data[temp_index]; - - // NOTE: Write the subsequent digits and every 3rd digit, add the seperator - DN_USize digit_counter = 0; - for (; temp_index < temp.size; temp_index++, digit_counter++) { - if (separator && temp_index && (digit_counter % 3 == 0)) - result.data[result.size++] = separator; - result.data[result.size++] = temp.data[temp_index]; - } - return result; -} - - -DN_API bool DN_Str8IsAll(DN_Str8 string, DN_Str8IsAllType is_all) -{ - bool result = string.size; - if (!result) - return result; - - switch (is_all) { - case DN_Str8IsAllType_Digits: { - for (DN_USize index = 0; result && index < string.size; index++) - result = string.data[index] >= '0' && string.data[index] <= '9'; - } break; - - case DN_Str8IsAllType_Hex: { - DN_Str8 trimmed = DN_Str8TrimPrefix(string, DN_Str8Lit("0x"), DN_Str8EqCase_Insensitive); - for (DN_USize index = 0; result && index < trimmed.size; index++) { - char ch = trimmed.data[index]; - result = (ch >= '0' && ch <= '9') || (ch >= 'a' && ch <= 'f') || (ch >= 'A' && ch <= 'F'); - } - } break; - } - - return result; -} - -DN_API char *DN_Str8End(DN_Str8 string) -{ - char *result = string.data + string.size; - return result; -} - -DN_API DN_Str8 DN_Str8Slice(DN_Str8 string, DN_USize offset, DN_USize size) -{ - DN_Str8 result = DN_Str8FromPtr(string.data, 0); - if (string.size == 0) - return result; - - DN_USize capped_offset = DN_Min(offset, string.size); - DN_USize max_size = string.size - capped_offset; - DN_USize capped_size = DN_Min(size, max_size); - result = DN_Str8FromPtr(string.data + capped_offset, capped_size); - return result; -} - -DN_API DN_Str8 DN_Str8Advance(DN_Str8 string, DN_USize amount) -{ - DN_Str8 result = DN_Str8Slice(string, amount, DN_USIZE_MAX); - return result; -} - -DN_API DN_Str8 DN_Str8NextLine(DN_Str8 string) -{ - DN_Str8 result = DN_Str8BSplit(string, DN_Str8Lit("\n")).rhs; - return result; -} - -DN_API DN_Str8BSplitResult DN_Str8BSplitArray(DN_Str8 string, DN_Str8 const *find, DN_USize find_size) -{ - DN_Str8BSplitResult result = {}; - if (string.size == 0 || !find || find_size == 0) - return result; - - result.lhs = string; - for (size_t index = 0; !result.rhs.data && index < string.size; index++) { - for (DN_USize find_index = 0; find_index < find_size; find_index++) { - DN_Str8 find_item = find[find_index]; - DN_Str8 string_slice = DN_Str8Slice(string, index, find_item.size); - if (DN_Str8Eq(string_slice, find_item)) { - result.lhs.size = index; - result.rhs.data = string_slice.data + find_item.size; - result.rhs.size = string.size - (index + find_item.size); - break; - } - } - } - - return result; -} - -DN_API DN_Str8BSplitResult DN_Str8BSplit(DN_Str8 string, DN_Str8 find) -{ - DN_Str8BSplitResult result = DN_Str8BSplitArray(string, &find, 1); - return result; -} - -DN_API DN_Str8BSplitResult DN_Str8BSplitLastArray(DN_Str8 string, DN_Str8 const *find, DN_USize find_size) -{ - DN_Str8BSplitResult result = {}; - if (string.size == 0 || !find || find_size == 0) - return result; - - result.lhs = string; - for (size_t index = string.size - 1; !result.rhs.data && index < string.size; index--) { - for (DN_USize find_index = 0; find_index < find_size; find_index++) { - DN_Str8 find_item = find[find_index]; - DN_Str8 string_slice = DN_Str8Slice(string, index, find_item.size); - if (DN_Str8Eq(string_slice, find_item)) { - result.lhs.size = index; - result.rhs.data = string_slice.data + find_item.size; - result.rhs.size = string.size - (index + find_item.size); - break; - } - } - } - - return result; -} - -DN_API DN_Str8BSplitResult DN_Str8BSplitLast(DN_Str8 string, DN_Str8 find) -{ - DN_Str8BSplitResult result = DN_Str8BSplitLastArray(string, &find, 1); - return result; -} - -DN_API DN_USize DN_Str8Split(DN_Str8 string, DN_Str8 delimiter, DN_Str8 *splits, DN_USize splits_count, DN_Str8SplitIncludeEmptyStrings mode) -{ - DN_USize result = 0; // The number of splits in the actual string. - if (string.size == 0 || delimiter.size == 0 || delimiter.size <= 0) - return result; - - DN_Str8BSplitResult split = {}; - DN_Str8 first = string; - do { - split = DN_Str8BSplit(first, delimiter); - if (split.lhs.size || mode == DN_Str8SplitIncludeEmptyStrings_Yes) { - if (splits && result < splits_count) - splits[result] = split.lhs; - result++; - } - first = split.rhs; - } while (first.size); - - return result; -} - -DN_API DN_Str8SplitResult DN_Str8SplitArena(DN_Arena *arena, DN_Str8 string, DN_Str8 delimiter, DN_Str8SplitIncludeEmptyStrings mode) -{ - DN_Str8SplitResult result = {}; - DN_USize count = DN_Str8Split(string, delimiter, /*splits*/ nullptr, /*count*/ 0, mode); - result.data = DN_ArenaNewArray(arena, DN_Str8, count, DN_ZMem_No); - if (result.data) { - result.count = DN_Str8Split(string, delimiter, result.data, count, mode); - DN_Assert(count == result.count); - } - return result; -} - -DN_API DN_Str8FindResult DN_Str8FindStr8Array(DN_Str8 string, DN_Str8 const *find, DN_USize find_size, DN_Str8EqCase eq_case) -{ - DN_Str8FindResult result = {}; - for (DN_USize index = 0; !result.found && index < string.size; index++) { - for (DN_USize find_index = 0; find_index < find_size; find_index++) { - DN_Str8 find_item = find[find_index]; - DN_Str8 string_slice = DN_Str8Slice(string, index, find_item.size); - if (DN_Str8Eq(string_slice, find_item, eq_case)) { - result.found = true; - result.index = index; - result.start_to_before_match = DN_Str8FromPtr(string.data, index); - result.match = DN_Str8FromPtr(string.data + index, find_item.size); - result.match_to_end_of_buffer = DN_Str8FromPtr(result.match.data, string.size - index); - result.after_match_to_end_of_buffer = DN_Str8Advance(result.match_to_end_of_buffer, find_item.size); - break; - } - } - } - return result; -} - -DN_API DN_Str8FindResult DN_Str8FindStr8(DN_Str8 string, DN_Str8 find, DN_Str8EqCase eq_case) -{ - DN_Str8FindResult result = DN_Str8FindStr8Array(string, &find, 1, eq_case); - return result; -} - -DN_API DN_Str8FindResult DN_Str8Find(DN_Str8 string, uint32_t flags) -{ - DN_Str8FindResult result = {}; - for (size_t index = 0; !result.found && index < string.size; index++) { - result.found |= ((flags & DN_Str8FindFlag_Digit) && DN_CharIsDigit(string.data[index])); - result.found |= ((flags & DN_Str8FindFlag_Alphabet) && DN_CharIsAlphabet(string.data[index])); - result.found |= ((flags & DN_Str8FindFlag_Whitespace) && DN_CharIsWhitespace(string.data[index])); - result.found |= ((flags & DN_Str8FindFlag_Plus) && string.data[index] == '+'); - result.found |= ((flags & DN_Str8FindFlag_Minus) && string.data[index] == '-'); - if (result.found) { - result.index = index; - result.match = DN_Str8FromPtr(string.data + index, 1); - result.match_to_end_of_buffer = DN_Str8FromPtr(result.match.data, string.size - index); - result.after_match_to_end_of_buffer = DN_Str8Advance(result.match_to_end_of_buffer, 1); - } - } - return result; -} - -DN_API DN_Str8 DN_Str8Segment(DN_Arena *arena, DN_Str8 src, DN_USize segment_size, char segment_char) -{ - if (!segment_size || src.size == 0) { - DN_Str8 result = DN_Str8FromStr8Arena(arena, src); - return result; - } - - DN_USize segments = src.size / segment_size; - if (src.size % segment_size == 0) - segments--; - - DN_USize segment_counter = 0; - DN_Str8 result = DN_Str8FromArena(arena, src.size + segments, DN_ZMem_Yes); - DN_USize write_index = 0; - for (DN_ForIndexU(src_index, src.size)) { - result.data[write_index++] = src.data[src_index]; - if ((src_index + 1) % segment_size == 0 && segment_counter < segments) { - result.data[write_index++] = segment_char; - segment_counter++; - } - DN_AssertF(write_index <= result.size, "result.size=%zu, write_index=%zu", result.size, write_index); - } - - DN_AssertF(write_index == result.size, "result.size=%zu, write_index=%zu", result.size, write_index); - return result; -} - -DN_API DN_Str8 DN_Str8ReverseSegment(DN_Arena *arena, DN_Str8 src, DN_USize segment_size, char segment_char) -{ - if (!segment_size || src.size == 0) { - DN_Str8 result = DN_Str8FromStr8Arena(arena, src); - return result; - } - - DN_USize segments = src.size / segment_size; - if (src.size % segment_size == 0) - segments--; - - DN_USize write_counter = 0; - DN_USize segment_counter = 0; - DN_Str8 result = DN_Str8FromArena(arena, src.size + segments, DN_ZMem_Yes); - DN_USize write_index = result.size - 1; - - DN_MSVC_WARNING_PUSH - DN_MSVC_WARNING_DISABLE(6293) // NOTE: Ill-defined loop - for (size_t src_index = src.size - 1; src_index < src.size; src_index--) { - DN_MSVC_WARNING_POP - result.data[write_index--] = src.data[src_index]; - if (++write_counter % segment_size == 0 && segment_counter < segments) { - result.data[write_index--] = segment_char; - segment_counter++; - } - } - - DN_Assert(write_index == SIZE_MAX); - return result; -} - -DN_API bool DN_Str8Eq(DN_Str8 lhs, DN_Str8 rhs, DN_Str8EqCase eq_case) -{ - if (lhs.size != rhs.size) - return false; - bool result = true; - switch (eq_case) { - case DN_Str8EqCase_Sensitive: { - result = (DN_Memcmp(lhs.data, rhs.data, lhs.size) == 0); - } break; - - case DN_Str8EqCase_Insensitive: { - for (DN_USize index = 0; index < lhs.size && result; index++) - result = (DN_CharToLower(lhs.data[index]) == DN_CharToLower(rhs.data[index])); - } break; - } - return result; -} - -DN_API bool DN_Str8EqInsensitive(DN_Str8 lhs, DN_Str8 rhs) -{ - bool result = DN_Str8Eq(lhs, rhs, DN_Str8EqCase_Insensitive); - return result; -} - -DN_API bool DN_Str8StartsWith(DN_Str8 string, DN_Str8 prefix, DN_Str8EqCase eq_case) -{ - DN_Str8 substring = {string.data, DN_Min(prefix.size, string.size)}; - bool result = DN_Str8Eq(substring, prefix, eq_case); - return result; -} - -DN_API bool DN_Str8StartsWithInsensitive(DN_Str8 string, DN_Str8 prefix) -{ - bool result = DN_Str8StartsWith(string, prefix, DN_Str8EqCase_Insensitive); - return result; -} - -DN_API bool DN_Str8EndsWith(DN_Str8 string, DN_Str8 suffix, DN_Str8EqCase eq_case) -{ - DN_Str8 substring = {string.data + string.size - suffix.size, DN_Min(string.size, suffix.size)}; - bool result = DN_Str8Eq(substring, suffix, eq_case); - return result; -} - -DN_API bool DN_Str8EndsWithInsensitive(DN_Str8 string, DN_Str8 suffix) -{ - bool result = DN_Str8EndsWith(string, suffix, DN_Str8EqCase_Insensitive); - return result; -} - -DN_API bool DN_Str8HasChar(DN_Str8 string, char ch) -{ - bool result = false; - for (DN_USize index = 0; !result && index < string.size; index++) - result = string.data[index] == ch; - return result; -} - -DN_API DN_Str8 DN_Str8TrimPrefix(DN_Str8 string, DN_Str8 prefix, DN_Str8EqCase eq_case) -{ - DN_Str8 result = string; - if (DN_Str8StartsWith(string, prefix, eq_case)) { - result.data += prefix.size; - result.size -= prefix.size; - } - return result; -} - -DN_API DN_Str8 DN_Str8TrimHexPrefix(DN_Str8 string) -{ - DN_Str8 result = DN_Str8TrimPrefix(string, DN_Str8Lit("0x"), DN_Str8EqCase_Insensitive); - return result; -} - -DN_API DN_Str8 DN_Str8TrimSuffix(DN_Str8 string, DN_Str8 suffix, DN_Str8EqCase eq_case) -{ - DN_Str8 result = string; - if (DN_Str8EndsWith(string, suffix, eq_case)) - result.size -= suffix.size; - return result; -} - -DN_API DN_Str8 DN_Str8TrimAround(DN_Str8 string, DN_Str8 trim_string) -{ - DN_Str8 result = DN_Str8TrimPrefix(string, trim_string); - result = DN_Str8TrimSuffix(result, trim_string); - return result; -} - -DN_API DN_Str8 DN_Str8TrimHeadWhitespace(DN_Str8 string) -{ - DN_Str8 result = string; - if (string.size == 0) - return result; - - char const *start = string.data; - char const *end = string.data + string.size; - while (start < end && DN_CharIsWhitespace(start[0])) - start++; - - result = DN_Str8FromPtr(start, end - start); - return result; -} - -DN_API DN_Str8 DN_Str8TrimTailWhitespace(DN_Str8 string) -{ - DN_Str8 result = string; - if (string.size == 0) - return result; - - char const *start = string.data; - char const *end = string.data + string.size; - while (end > start && DN_CharIsWhitespace(end[-1])) - end--; - - result = DN_Str8FromPtr(start, end - start); - return result; -} - -DN_API DN_Str8 DN_Str8TrimWhitespaceAround(DN_Str8 string) -{ - DN_Str8 result = DN_Str8TrimHeadWhitespace(string); - result = DN_Str8TrimTailWhitespace(result); - return result; -} - -DN_API DN_Str8 DN_Str8TrimByteOrderMark(DN_Str8 string) -{ - DN_Str8 result = string; - if (result.size == 0) - return result; - - // TODO(dn): This is little endian - DN_Str8 UTF8_BOM = DN_Str8Lit("\xEF\xBB\xBF"); - DN_Str8 UTF16_BOM_BE = DN_Str8Lit("\xEF\xFF"); - DN_Str8 UTF16_BOM_LE = DN_Str8Lit("\xFF\xEF"); - DN_Str8 UTF32_BOM_BE = DN_Str8Lit("\x00\x00\xFE\xFF"); - DN_Str8 UTF32_BOM_LE = DN_Str8Lit("\xFF\xFE\x00\x00"); - - result = DN_Str8TrimPrefix(result, UTF8_BOM, DN_Str8EqCase_Sensitive); - result = DN_Str8TrimPrefix(result, UTF16_BOM_BE, DN_Str8EqCase_Sensitive); - result = DN_Str8TrimPrefix(result, UTF16_BOM_LE, DN_Str8EqCase_Sensitive); - result = DN_Str8TrimPrefix(result, UTF32_BOM_BE, DN_Str8EqCase_Sensitive); - result = DN_Str8TrimPrefix(result, UTF32_BOM_LE, DN_Str8EqCase_Sensitive); - return result; -} - -DN_API DN_Str8 DN_Str8FileNameFromPath(DN_Str8 path) -{ - DN_Str8 separators[] = {DN_Str8Lit("/"), DN_Str8Lit("\\")}; - DN_Str8BSplitResult split = DN_Str8BSplitLastArray(path, separators, DN_ArrayCountU(separators)); - DN_Str8 result = split.rhs.size ? split.rhs : split.lhs; - return result; -} - -DN_API DN_Str8 DN_Str8FileNameNoExtension(DN_Str8 path) -{ - DN_Str8 file_name = DN_Str8FileNameFromPath(path); - DN_Str8 result = DN_Str8FilePathNoExtension(file_name); - return result; -} - -DN_API DN_Str8 DN_Str8FilePathNoExtension(DN_Str8 path) -{ - DN_Str8BSplitResult split = DN_Str8BSplitLast(path, DN_Str8Lit(".")); - DN_Str8 result = split.lhs; - return result; -} - -DN_API DN_Str8 DN_Str8FileExtension(DN_Str8 path) -{ - DN_Str8BSplitResult split = DN_Str8BSplitLast(path, DN_Str8Lit(".")); - DN_Str8 result = split.rhs; - return result; -} - -DN_API DN_Str8 DN_Str8FileDirectoryFromPath(DN_Str8 path) -{ - DN_Str8 separators[] = {DN_Str8Lit("/"), DN_Str8Lit("\\")}; - DN_Str8BSplitResult split = DN_Str8BSplitLastArray(path, separators, DN_ArrayCountU(separators)); - DN_Str8 result = split.lhs; - return result; -} - -DN_API DN_Str8 DN_Str8AppendF(DN_Arena *arena, DN_Str8 string, char const *fmt, ...) -{ - va_list args; - va_start(args, fmt); - DN_Str8 result = DN_Str8AppendFV(arena, string, fmt, args); - va_end(args); - return result; -} - -DN_API DN_Str8 DN_Str8AppendFV(DN_Arena *arena, DN_Str8 string, char const *fmt, va_list args) -{ - // TODO: Calculate size and write into one buffer instead of 2 appends - DN_Str8 append = DN_Str8FromFmtVArena(arena, fmt, args); - DN_Str8 result = DN_Str8FromArena(arena, string.size + append.size, DN_ZMem_No); - DN_Memcpy(result.data, string.data, string.size); - DN_Memcpy(result.data + string.size, append.data, append.size); - return result; -} - -DN_API DN_Str8 DN_Str8FillF(DN_Arena *arena, DN_USize count, char const *fmt, ...) -{ - va_list args; - va_start(args, fmt); - DN_Str8 result = DN_Str8FillFV(arena, count, fmt, args); - va_end(args); - return result; -} - -DN_API DN_Str8 DN_Str8FillFV(DN_Arena *arena, DN_USize count, char const *fmt, va_list args) -{ - DN_Str8 fill = DN_Str8FromFmtVArena(arena, fmt, args); - DN_Str8 result = DN_Str8FromArena(arena, count * fill.size, DN_ZMem_No); - for (DN_USize index = 0; index < count; index++) { - void *dest = result.data + (index * fill.size); - DN_Memcpy(dest, fill.data, fill.size); - } - return result; -} - -DN_API void DN_Str8Remove(DN_Str8 *string, DN_USize offset, DN_USize size) -{ - if (!string || string->size) - return; - - char *end = string->data + string->size; - char *dest = DN_Min(string->data + offset, end); - char *src = DN_Min(string->data + offset + size, end); - DN_USize bytes_to_move = end - src; - DN_Memmove(dest, src, bytes_to_move); - string->size -= bytes_to_move; -} - -DN_API DN_Str8TruncateResult DN_Str8TruncateMiddle(DN_Arena *arena, DN_Str8 str8, DN_U32 side_size, DN_Str8 truncator) -{ - DN_Str8TruncateResult result = {}; - if (str8.size <= (side_size * 2)) { - result.str8 = DN_Str8FromStr8Arena(arena, str8); - return result; - } - - DN_Str8 head = DN_Str8Slice(str8, 0, side_size); - DN_Str8 tail = DN_Str8Slice(str8, str8.size - side_size, side_size); - DN_MSVC_WARNING_PUSH - DN_MSVC_WARNING_DISABLE(6284) // Object passed as _Param_(3) when a string is required in call to 'DN_Str8FromFmtArena' Actual type: 'struct DN_Str8' - result.str8 = DN_Str8FromFmtArena(arena, "%S%S%S", head, truncator, tail); - DN_MSVC_WARNING_POP - result.truncated = true; - return result; -} - -DN_API DN_Str8 DN_Str8Lower(DN_Arena *arena, DN_Str8 string) -{ - DN_Str8 result = DN_Str8FromStr8Arena(arena, string); - for (DN_ForIndexU(index, result.size)) - result.data[index] = DN_CharToLower(result.data[index]); - return result; -} - -DN_API DN_Str8 DN_Str8Upper(DN_Arena *arena, DN_Str8 string) -{ - DN_Str8 result = DN_Str8FromStr8Arena(arena, string); - for (DN_ForIndexU(index, result.size)) - result.data[index] = DN_CharToUpper(result.data[index]); - return result; -} - -DN_API DN_Str8Builder DN_Str8BuilderFromArena(DN_Arena *arena) -{ - DN_Str8Builder result = {}; - result.arena = arena; - return result; -} - -DN_API DN_Str8Builder DN_Str8BuilderFromStr8PtrRef(DN_Arena *arena, DN_Str8 const *strings, DN_USize size) -{ - DN_Str8Builder result = DN_Str8BuilderFromArena(arena); - DN_Str8BuilderAppendArrayRef(&result, strings, size); - return result; -} - -DN_API DN_Str8Builder DN_Str8BuilderFromStr8PtrCopy(DN_Arena *arena, DN_Str8 const *strings, DN_USize size) -{ - DN_Str8Builder result = DN_Str8BuilderFromArena(arena); - DN_Str8BuilderAppendArrayCopy(&result, strings, size); - return result; -} - -DN_API DN_Str8Builder DN_Str8BuilderFromBuilder(DN_Arena *arena, DN_Str8Builder const *builder) -{ - DN_Str8Builder result = DN_Str8BuilderFromArena(arena); - DN_Str8BuilderAppendBuilderCopy(&result, builder); - return result; -} - -DN_API bool DN_Str8BuilderAddArrayRef(DN_Str8Builder *builder, DN_Str8 const *strings, DN_USize size, DN_Str8BuilderAdd add) -{ - if (!builder) - return false; - - if (!strings || size <= 0) - return true; - - DN_Str8Link *links = DN_ArenaNewArray(builder->arena, DN_Str8Link, size, DN_ZMem_No); - if (!links) - return false; - - if (add == DN_Str8BuilderAdd_Append) { - for (DN_ForIndexU(index, size)) { - DN_Str8 string = strings[index]; - DN_Str8Link *link = links + index; - - link->string = string; - link->next = NULL; - - if (builder->head) - builder->tail->next = link; - else - builder->head = link; - - builder->tail = link; - builder->count++; - builder->string_size += string.size; - } - } else { - DN_Assert(add == DN_Str8BuilderAdd_Prepend); - DN_MSVC_WARNING_PUSH - DN_MSVC_WARNING_DISABLE(6293) // NOTE: Ill-defined loop - for (DN_USize index = size - 1; index < size; index--) { - DN_MSVC_WARNING_POP - DN_Str8 string = strings[index]; - DN_Str8Link *link = links + index; - link->string = string; - link->next = builder->head; - builder->head = link; - if (!builder->tail) - builder->tail = link; - builder->count++; - builder->string_size += string.size; - } - } - return true; -} - -DN_API bool DN_Str8BuilderAddArrayCopy(DN_Str8Builder *builder, DN_Str8 const *strings, DN_USize size, DN_Str8BuilderAdd add) -{ - if (!builder) - return false; - - if (!strings || size <= 0) - return true; - - DN_ArenaTempMem tmp_mem = DN_ArenaTempMemBegin(builder->arena); - bool result = true; - DN_Str8 *strings_copy = DN_ArenaNewArray(builder->arena, DN_Str8, size, DN_ZMem_No); - for (DN_ForIndexU(index, size)) { - strings_copy[index] = DN_Str8FromStr8Arena(builder->arena, strings[index]); - if (strings_copy[index].size != strings[index].size) { - result = false; - break; - } - } - - if (result) - result = DN_Str8BuilderAddArrayRef(builder, strings_copy, size, add); - - if (!result) - DN_ArenaTempMemEnd(tmp_mem); - - return result; -} - -DN_API bool DN_Str8BuilderAddFV(DN_Str8Builder *builder, DN_Str8BuilderAdd add, DN_FMT_ATTRIB char const *fmt, va_list args) -{ - DN_Str8 string = DN_Str8FromFmtVArena(builder->arena, fmt, args); - DN_ArenaTempMem temp_mem = DN_ArenaTempMemBegin(builder->arena); - bool result = DN_Str8BuilderAddArrayRef(builder, &string, 1, add); - if (!result) - DN_ArenaTempMemEnd(temp_mem); - return result; -} - -DN_API bool DN_Str8BuilderAppendRef(DN_Str8Builder *builder, DN_Str8 string) -{ - bool result = DN_Str8BuilderAddArrayRef(builder, &string, 1, DN_Str8BuilderAdd_Append); - return result; -} - -DN_API bool DN_Str8BuilderAppendCopy(DN_Str8Builder *builder, DN_Str8 string) -{ - bool result = DN_Str8BuilderAddArrayCopy(builder, &string, 1, DN_Str8BuilderAdd_Append); - return result; -} - -DN_API bool DN_Str8BuilderAppendF(DN_Str8Builder *builder, DN_FMT_ATTRIB char const *fmt, ...) -{ - va_list args; - va_start(args, fmt); - bool result = DN_Str8BuilderAppendFV(builder, fmt, args); - va_end(args); - return result; -} - -DN_API bool DN_Str8BuilderAppendBytesRef(DN_Str8Builder *builder, void const *ptr, DN_USize size) -{ - DN_Str8 input = DN_Str8FromPtr(ptr, size); - bool result = DN_Str8BuilderAppendRef(builder, input); - return result; -} - -DN_API bool DN_Str8BuilderAppendBytesCopy(DN_Str8Builder *builder, void const *ptr, DN_USize size) -{ - DN_Str8 input = DN_Str8FromPtr(ptr, size); - bool result = DN_Str8BuilderAppendCopy(builder, input); - return result; -} - -static bool DN_Str8BuilderAppendBuilder_(DN_Str8Builder *dest, DN_Str8Builder const *src, bool copy) -{ - if (!dest) - return false; - if (!src) - return true; - - DN_ArenaTempMemBegin(dest->arena); - DN_Str8Link *links = DN_ArenaNewArray(dest->arena, DN_Str8Link, src->count, DN_ZMem_No); - if (!links) - return false; - - DN_Str8Link *first = nullptr; - DN_Str8Link *last = nullptr; - DN_USize link_index = 0; - bool result = true; - for (DN_Str8Link const *it = src->head; it; it = it->next) { - DN_Str8Link *link = links + link_index++; - link->next = nullptr; - link->string = it->string; - - if (copy) { - link->string = DN_Str8FromStr8Arena(dest->arena, it->string); - if (link->string.size != it->string.size) { - result = false; - break; - } - } - - if (last) - last->next = link; - else - first = link; - last = link; - } - - if (result) { - if (dest->head) - dest->tail->next = first; - else - dest->head = first; - dest->tail = last; - dest->count += src->count; - dest->string_size += src->string_size; - } - return true; -} - -DN_API bool DN_Str8BuilderAppendBuilderRef(DN_Str8Builder *dest, DN_Str8Builder const *src) -{ - bool result = DN_Str8BuilderAppendBuilder_(dest, src, false); - return result; -} - -DN_API bool DN_Str8BuilderAppendBuilderCopy(DN_Str8Builder *dest, DN_Str8Builder const *src) -{ - bool result = DN_Str8BuilderAppendBuilder_(dest, src, true); - return result; -} - -DN_API bool DN_Str8BuilderPrependRef(DN_Str8Builder *builder, DN_Str8 string) -{ - bool result = DN_Str8BuilderAddArrayRef(builder, &string, 1, DN_Str8BuilderAdd_Prepend); - return result; -} - -DN_API bool DN_Str8BuilderPrependCopy(DN_Str8Builder *builder, DN_Str8 string) -{ - bool result = DN_Str8BuilderAddArrayCopy(builder, &string, 1, DN_Str8BuilderAdd_Prepend); - return result; -} - -DN_API bool DN_Str8BuilderPrependF(DN_Str8Builder *builder, DN_FMT_ATTRIB char const *fmt, ...) -{ - va_list args; - va_start(args, fmt); - bool result = DN_Str8BuilderPrependFV(builder, fmt, args); - va_end(args); - return result; -} - -DN_API bool DN_Str8BuilderErase(DN_Str8Builder *builder, DN_Str8 string) -{ - for (DN_Str8Link **it = &builder->head; *it; it = &((*it)->next)) { - if (DN_Str8Eq((*it)->string, string)) { - *it = (*it)->next; - builder->string_size -= string.size; - builder->count -= 1; - return true; - } - } - return false; -} - -DN_API DN_Str8 DN_Str8BuilderBuild(DN_Str8Builder const *builder, DN_Arena *arena) -{ - DN_Str8 result = DN_Str8BuilderBuildDelimited(builder, DN_Str8Lit(""), arena); - return result; -} - -DN_API DN_Str8 DN_Str8BuilderBuildDelimited(DN_Str8Builder const *builder, DN_Str8 delimiter, DN_Arena *arena) -{ - DN_Str8 result = DN_ZeroInit; - if (!builder || builder->string_size <= 0 || builder->count <= 0) - return result; - - DN_USize size_for_delimiter = delimiter.size ? ((builder->count - 1) * delimiter.size) : 0; - result.data = DN_ArenaNewArray(arena, - char, - builder->string_size + size_for_delimiter + 1 /*null terminator*/, - DN_ZMem_No); - if (!result.data) - return result; - - for (DN_Str8Link *link = builder->head; link; link = link->next) { - DN_Memcpy(result.data + result.size, link->string.data, link->string.size); - result.size += link->string.size; - if (link->next && delimiter.size) { - DN_Memcpy(result.data + result.size, delimiter.data, delimiter.size); - result.size += delimiter.size; - } - } - - result.data[result.size] = 0; - DN_Assert(result.size == builder->string_size + size_for_delimiter); - return result; -} - -DN_API DN_Slice DN_Str8BuilderBuildSlice(DN_Str8Builder const *builder, DN_Arena *arena) -{ - DN_Slice result = DN_ZeroInit; - if (!builder || builder->string_size <= 0 || builder->count <= 0) - return result; - - result = DN_Slice_Alloc(arena, builder->count, DN_ZMem_No); - if (!result.data) - return result; - - DN_USize slice_index = 0; - for (DN_Str8Link *link = builder->head; link; link = link->next) - result.data[slice_index++] = DN_Str8FromStr8Arena(arena, link->string); - - DN_Assert(slice_index == builder->count); - return result; -} - -// NOTE: DN_Char /////////////////////////////////////////////////////////////////////////////////// -// NOTE: DN_UTF //////////////////////////////////////////////////////////////////////////////////// -DN_API int DN_UTF8_EncodeCodepoint(uint8_t utf8[4], uint32_t codepoint) -{ - // NOTE: Table from https://www.reedbeta.com/blog/programmers-intro-to-unicode/ - // ----------------------------------------+----------------------------+--------------------+ - // UTF-8 (binary) | Code point (binary) | Range | - // ----------------------------------------+----------------------------+--------------------+ - // 0xxx'xxxx | xxx'xxxx | U+0000 - U+007F | - // 110x'xxxx 10yy'yyyy | xxx'xxyy'yyyy | U+0080 - U+07FF | - // 1110'xxxx 10yy'yyyy 10zz'zzzz | xxxx'yyyy'yyzz'zzzz | U+0800 - U+FFFF | - // 1111'0xxx 10yy'yyyy 10zz'zzzz 10ww'wwww | x'xxyy'yyyy'zzzz'zzww'wwww | U+10000 - U+10FFFF | - // ----------------------------------------+----------------------------+--------------------+ - - if (codepoint <= 0b0111'1111) { - utf8[0] = DN_Cast(uint8_t) codepoint; - return 1; - } - - if (codepoint <= 0b0111'1111'1111) { - utf8[0] = (0b1100'0000 | ((codepoint >> 6) & 0b01'1111)); // x - utf8[1] = (0b1000'0000 | ((codepoint >> 0) & 0b11'1111)); // y - return 2; - } - - if (codepoint <= 0b1111'1111'1111'1111) { - utf8[0] = (0b1110'0000 | ((codepoint >> 12) & 0b00'1111)); // x - utf8[1] = (0b1000'0000 | ((codepoint >> 6) & 0b11'1111)); // y - utf8[2] = (0b1000'0000 | ((codepoint >> 0) & 0b11'1111)); // z - return 3; - } - - if (codepoint <= 0b1'1111'1111'1111'1111'1111) { - utf8[0] = (0b1111'0000 | ((codepoint >> 18) & 0b00'0111)); // x - utf8[1] = (0b1000'0000 | ((codepoint >> 12) & 0b11'1111)); // y - utf8[2] = (0b1000'0000 | ((codepoint >> 6) & 0b11'1111)); // z - utf8[3] = (0b1000'0000 | ((codepoint >> 0) & 0b11'1111)); // w - return 4; - } - - return 0; -} - -DN_API int DN_UTF16_EncodeCodepoint(uint16_t utf16[2], uint32_t codepoint) -{ - // NOTE: Table from https://www.reedbeta.com/blog/programmers-intro-to-unicode/ - // ----------------------------------------+------------------------------------+------------------+ - // UTF-16 (binary) | Code point (binary) | Range | - // ----------------------------------------+------------------------------------+------------------+ - // xxxx'xxxx'xxxx'xxxx | xxxx'xxxx'xxxx'xxxx | U+0000???U+FFFF | - // 1101'10xx'xxxx'xxxx 1101'11yy'yyyy'yyyy | xxxx'xxxx'xxyy'yyyy'yyyy + 0x10000 | U+10000???U+10FFFF | - // ----------------------------------------+------------------------------------+------------------+ - - if (codepoint <= 0b1111'1111'1111'1111) { - utf16[0] = DN_Cast(uint16_t) codepoint; - return 1; - } - - if (codepoint <= 0b1111'1111'1111'1111'1111) { - uint32_t surrogate_codepoint = codepoint + 0x10000; - utf16[0] = 0b1101'1000'0000'0000 | ((surrogate_codepoint >> 10) & 0b11'1111'1111); // x - utf16[1] = 0b1101'1100'0000'0000 | ((surrogate_codepoint >> 0) & 0b11'1111'1111); // y - return 2; - } - - return 0; -} - - -DN_API DN_U8 DN_U8FromHexNibble(char hex) -{ - bool digit = hex >= '0' && hex <= '9'; - bool upper = hex >= 'A' && hex <= 'F'; - bool lower = hex >= 'a' && hex <= 'f'; - DN_U8 result = 0xFF; - if (digit) - result = hex - '0'; - if (upper) - result = hex - 'A' + 10; - if (lower) - result = hex - 'a' + 10; - return result; -} - -DN_API DN_NibbleFromU8Result DN_NibbleFromU8(DN_U8 u8) -{ - static char const *table = "0123456789abcdef"; - DN_U8 lhs = (u8 >> 0) & 0xF; - DN_U8 rhs = (u8 >> 4) & 0xF; - DN_NibbleFromU8Result result = {}; - result.nibble0 = table[rhs]; - result.nibble1 = table[lhs]; - return result; -} - -DN_API DN_USize DN_BytesFromHexPtr(void const *hex, DN_USize hex_count, void *bytes, DN_USize bytes_count) -{ - DN_USize result = 0; - DN_U8 const *hex_u8 = DN_Cast(DN_U8 const *) hex; - if (hex_count >= 2 && hex_u8[0] == '0' && (hex_u8[1] == 'x' || hex_u8[1] == 'X')) { - hex_u8 += 2; - hex_count -= 2; - } - - if (hex_count > (bytes_count * 2)) - return result; - - DN_U8 *ptr = DN_Cast(DN_U8 *)bytes; - for (DN_USize index = 0; index < hex_count; index += 2) { - DN_U8 nibble0 = DN_U8FromHexNibble(hex_u8[index + 0]); - DN_U8 nibble1 = DN_U8FromHexNibble(hex_u8[index + 1]); - if (nibble0 == 0xFF || nibble1 == 0xFF) - return result; - *ptr++ = nibble0 << 4 | nibble1 << 0; - result++; - } - return result; -} - -DN_API DN_Str8 DN_BytesFromHexPtrArena(void const *hex, DN_USize hex_size, DN_Arena *arena) -{ - DN_Assert(hex_size % 2 == 0); - DN_Str8 result = {}; - result.data = DN_ArenaNewArray(arena, char, hex_size / 2, DN_ZMem_No); - if (result.data) - result.size = DN_BytesFromHexPtr(hex, hex_size, result.data, hex_size / 2); - return result; -} - -DN_API DN_USize DN_BytesFromHexStr8(DN_Str8 hex, void *dest, DN_USize dest_count) -{ - DN_USize result = DN_BytesFromHexPtr(hex.data, hex.size, dest, dest_count); - return result; -} - -DN_API DN_Str8 DN_BytesFromHexStr8Arena(DN_Str8 hex, DN_Arena *arena) -{ - DN_Str8 result = DN_BytesFromHexPtrArena(hex.data, hex.size, arena); - return result; -} - -DN_API DN_U8x16 DN_BytesFromHex32Ptr(void const *hex, DN_USize hex_count) -{ - DN_U8x16 result = {}; - DN_Assert(hex_count / 2 == sizeof result.data); - DN_USize bytes_written = DN_BytesFromHexPtr(hex, hex_count, result.data, sizeof result); - DN_Assert(bytes_written == sizeof result.data); - return result; -} - -DN_API DN_U8x32 DN_BytesFromHex64Ptr(void const *hex, DN_USize hex_count) -{ - DN_U8x32 result = {}; - DN_Assert(hex_count / 2 == sizeof result.data); - DN_USize bytes_written = DN_BytesFromHexPtr(hex, hex_count, result.data, sizeof result); - DN_Assert(bytes_written == sizeof result.data); - return result; -} - -DN_API DN_HexU64Str8 DN_HexFromU64(DN_U64 value, DN_HexFromU64Type type) -{ - DN_HexU64Str8 result = {}; - DN_HexFromBytesPtr(&value, sizeof(value), result.data, sizeof(result.data)); - if (type == DN_HexFromU64Type_Uppercase) { - for (DN_USize index = 0; index < result.size; index++) - result.data[index] = DN_CharToUpper(result.data[index]); - } - return result; -} - -DN_API DN_USize DN_HexFromBytesPtr(void const *bytes, DN_USize bytes_count, void *hex, DN_USize hex_count) -{ - DN_USize result = 0; - if ((bytes_count * 2) != hex_count) - return result; - DN_U8 const *src_u8 = DN_Cast(DN_U8 const *)bytes; - DN_U8 *ptr = DN_Cast(DN_U8 *)hex; - for (DN_USize index = 0; index < bytes_count; index++) { - DN_NibbleFromU8Result to_nibbles = DN_NibbleFromU8(src_u8[index]); - *ptr++ = to_nibbles.nibble0; - *ptr++ = to_nibbles.nibble1; - result += 2; - } - return result; -} - -DN_API DN_Str8 DN_HexFromBytesPtrArena(void const *bytes, DN_USize bytes_count, DN_Arena *arena) -{ - DN_Str8 result = {}; - result.data = DN_ArenaNewArray(arena, char, bytes_count * 2, DN_ZMem_No); - if (result.data) - result.size = DN_HexFromBytesPtr(bytes, bytes_count, result.data, bytes_count * 2); - return result; -} - -DN_API DN_Hex32 DN_HexFromBytes16Ptr(void const *bytes, DN_USize bytes_count) -{ - DN_Hex32 result = {}; - DN_Assert(bytes_count * 2 == sizeof result.data); - DN_USize hex_written = DN_HexFromBytesPtr(bytes, bytes_count, result.data, sizeof result.data); - DN_Assert(hex_written == sizeof result.data); - return result; -} - -DN_API DN_Hex64 DN_HexFromBytes32Ptr(void const *bytes, DN_USize bytes_count) -{ - DN_Hex64 result = {}; - DN_Assert(bytes_count * 2 == sizeof result.data); - DN_USize hex_written = DN_HexFromBytesPtr(bytes, bytes_count, result.data, sizeof result.data); - DN_Assert(hex_written == sizeof result.data); - return result; -} - -DN_API DN_Hex128 DN_HexFromBytes64Ptr(void const *bytes, DN_USize bytes_count) -{ - DN_Hex128 result = {}; - DN_Assert(bytes_count * 2 == sizeof result.data); - DN_USize hex_written = DN_HexFromBytesPtr(bytes, bytes_count, result.data, sizeof result.data); - DN_Assert(hex_written == sizeof result.data); - return result; -} - -DN_API DN_Str8x128 DN_AgeStr8FromMsU64(DN_U64 duration_ms, DN_AgeUnit units) -{ - DN_Str8x128 result = {}; - DN_U64 remainder_ms = duration_ms; - if (units & DN_AgeUnit_FractionalSec) { - units |= DN_AgeUnit_Sec; - units &= ~DN_AgeUnit_Ms; - } - - DN_Str8 unit_suffix = {}; - if (units & DN_AgeUnit_Year) { - unit_suffix = DN_Str8Lit("y"); - DN_USize value_usize = remainder_ms / (DN_SecFromYears(1) * 1000); - remainder_ms -= DN_SecFromYears(value_usize) * 1000; - if (value_usize) - DN_FmtAppend(result.data, &result.size, sizeof(result.data), "%s%zu%.*s", result.size ? " " : "", value_usize, DN_Str8PrintFmt(unit_suffix)); - } - - if (units & DN_AgeUnit_Week) { - unit_suffix = DN_Str8Lit("w"); - DN_USize value_usize = remainder_ms / (DN_SecFromWeeks(1) * 1000); - remainder_ms -= DN_SecFromWeeks(value_usize) * 1000; - if (value_usize) - DN_FmtAppend(result.data, &result.size, sizeof(result.data), "%s%zu%.*s", result.size ? " " : "", value_usize, DN_Str8PrintFmt(unit_suffix)); - } - - if (units & DN_AgeUnit_Day) { - unit_suffix = DN_Str8Lit("d"); - DN_USize value_usize = remainder_ms / (DN_SecFromDays(1) * 1000); - remainder_ms -= DN_SecFromDays(value_usize) * 1000; - if (value_usize) - DN_FmtAppend(result.data, &result.size, sizeof(result.data), "%s%zu%.*s", result.size ? " " : "", value_usize, DN_Str8PrintFmt(unit_suffix)); - } - - if (units & DN_AgeUnit_Hr) { - unit_suffix = DN_Str8Lit("h"); - DN_USize value_usize = remainder_ms / (DN_SecFromHours(1) * 1000); - remainder_ms -= DN_SecFromHours(value_usize) * 1000; - if (value_usize) - DN_FmtAppend(result.data, &result.size, sizeof(result.data), "%s%zu%.*s", result.size ? " " : "", value_usize, DN_Str8PrintFmt(unit_suffix)); - } - - if (units & DN_AgeUnit_Min) { - unit_suffix = DN_Str8Lit("m"); - DN_USize value_usize = remainder_ms / (DN_SecFromMins(1) * 1000); - remainder_ms -= DN_SecFromMins(value_usize) * 1000; - if (value_usize) - DN_FmtAppend(result.data, &result.size, sizeof(result.data), "%s%zu%.*s", result.size ? " " : "", value_usize, DN_Str8PrintFmt(unit_suffix)); - } - - if (units & DN_AgeUnit_Sec) { - unit_suffix = DN_Str8Lit("s"); - if (units & DN_AgeUnit_FractionalSec) { - DN_F64 remainder_s = remainder_ms / 1000.0; - DN_FmtAppend(result.data, &result.size, sizeof(result.data), "%s%.3f%.*s", result.size ? " " : "", remainder_s, DN_Str8PrintFmt(unit_suffix)); - remainder_ms = 0; - } else { - DN_USize value_usize = remainder_ms / 1000; - remainder_ms -= DN_Cast(DN_USize)(value_usize * 1000); - if (value_usize) - DN_FmtAppend(result.data, &result.size, sizeof(result.data), "%s%zu%.*s", result.size ? " " : "", value_usize, DN_Str8PrintFmt(unit_suffix)); - } - } - - if (units & DN_AgeUnit_Ms) { - unit_suffix = DN_Str8Lit("ms"); - DN_Assert((units & DN_AgeUnit_FractionalSec) == 0); - DN_USize value_usize = remainder_ms; - remainder_ms -= value_usize; - if (value_usize || result.size == 0) - DN_FmtAppend(result.data, &result.size, sizeof(result.data), "%s%zu%.*s", result.size ? " " : "", value_usize, DN_Str8PrintFmt(unit_suffix)); - } - - if (result.size == 0) - DN_FmtAppend(result.data, &result.size, sizeof(result.data), "0%.*s", DN_Str8PrintFmt(unit_suffix)); - return result; -} - -DN_API DN_Str8x128 DN_AgeStr8FromSecU64(DN_U64 duration_s, DN_AgeUnit units) -{ - DN_U64 duration_ms = duration_s * 1000; - DN_Str8x128 result = DN_AgeStr8FromMsU64(duration_ms, units); - return result; -} - -DN_API DN_Str8x128 DN_AgeStr8FromSecF64(DN_F64 duration_s, DN_AgeUnit units) -{ - DN_U64 duration_ms = DN_Cast(DN_U64)(duration_s * 1000.0); - DN_Str8x128 result = DN_AgeStr8FromMsU64(duration_ms, units); - return result; -} - -DN_API int DN_IsLeapYear(int year) -{ - if (year % 4 != 0) - return 0; - if (year % 100 != 0) - return 1; - return (year % 400 == 0); -} - -DN_API bool DN_DateIsValid(DN_Date date) -{ - if (date.year < 1970) - return false; - if (date.month <= 0 || date.month >= 13) - return false; - if (date.day <= 0 || date.day >= 32) - return false; - if (date.hour >= 24) - return false; - if (date.minutes >= 60) - return false; - if (date.seconds >= 60) - return false; - return true; -} - -DN_API DN_Date DN_DateFromUnixTimeMs(DN_USize unix_ts_ms) -{ - DN_Date result = {}; - DN_USize ms = unix_ts_ms % 1000; - DN_USize total_seconds = unix_ts_ms / 1000; - result.milliseconds = (DN_U16)ms; - - DN_USize secs_in_day = total_seconds % 86400; - DN_USize days = total_seconds / 86400; - - result.hour = (DN_U8)(secs_in_day / 3600); - result.minutes = (DN_U8)((secs_in_day % 3600) / 60); - result.seconds = (DN_U8)(secs_in_day % 60); - - DN_U16 days_in_month[13] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; - DN_USize days_left = days; - DN_U16 year = 1970; - - while (days_left >= (DN_IsLeapYear(year) ? 366 : 365)) { - DN_USize days_in_year = DN_IsLeapYear(year) ? 366 : 365; - days_left -= days_in_year; - year++; - } - - DN_U8 month = 1; - for (;;) { - DN_U16 day_count = days_in_month[month]; - if (month == 2 && DN_IsLeapYear(year)) - day_count = 29; - if (days_left < day_count) - break; - days_left -= day_count; - month++; - } - - result.year = year; - result.month = month; - result.day = (DN_U8)days_left + 1; - return result; -} - -DN_API DN_U64 DN_UnixTimeMsFromDate(DN_Date date) -{ - DN_Assert(DN_DateIsValid(date)); - - // Precomputed cumulative days before each month (non-leap year) - const DN_U16 days_before_month[13] = { - 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365}; - - DN_U16 y = date.year; - DN_U8 m = date.month; - DN_U8 d = date.day; - - DN_U32 days = d - 1; // day of month starts at 0 internally - days += days_before_month[m - 1]; // Add days from previous months this year - - if (m > 2 && DN_IsLeapYear(y)) // Add February 29 if leap year and month > 2 - days += 1; - - // Add full years from 1970 to y-1 - for (DN_U16 year = 1970; year < y; ++year) - days += DN_IsLeapYear(year) ? 366 : 365; - - // Convert to seconds - DN_U64 seconds = DN_Cast(DN_U64)days * 86400ULL; - seconds += DN_Cast(DN_U64)date.hour * 3600ULL; - seconds += DN_Cast(DN_U64)date.minutes * 60ULL; - seconds += DN_Cast(DN_U64)date.seconds; - DN_U64 result = seconds * 1000ULL + date.milliseconds; - return result; -} - -DN_API DN_Str8 DN_Str8FromByteCountType(DN_ByteCountType type) -{ - DN_Str8 result = DN_Str8Lit(""); - switch (type) { - case DN_ByteCountType_B: result = DN_Str8Lit("B"); break; - case DN_ByteCountType_KiB: result = DN_Str8Lit("KiB"); break; - case DN_ByteCountType_MiB: result = DN_Str8Lit("MiB"); break; - case DN_ByteCountType_GiB: result = DN_Str8Lit("GiB"); break; - case DN_ByteCountType_TiB: result = DN_Str8Lit("TiB"); break; - case DN_ByteCountType_Count: result = DN_Str8Lit(""); break; - case DN_ByteCountType_Auto: result = DN_Str8Lit(""); break; - } - return result; -} - -DN_API DN_ByteCountResult DN_ByteCountFromType(DN_U64 bytes, DN_ByteCountType type) -{ - DN_Assert(type != DN_ByteCountType_Count); - DN_ByteCountResult result = {}; - result.bytes = DN_Cast(DN_F64) bytes; - if (type == DN_ByteCountType_Auto) - for (; result.type < DN_ByteCountType_Count && result.bytes >= 1024.0; result.type = DN_Cast(DN_ByteCountType)(DN_Cast(DN_USize) result.type + 1)) - result.bytes /= 1024.0; - else - for (; result.type < type; result.type = DN_Cast(DN_ByteCountType)(DN_Cast(DN_USize) result.type + 1)) - result.bytes /= 1024.0; - result.suffix = DN_Str8FromByteCountType(result.type); - return result; -} - -DN_API DN_Str8x32 DN_ByteCountStr8x32FromType(DN_U64 bytes, DN_ByteCountType type) -{ - DN_ByteCountResult byte_count = DN_ByteCountFromType(bytes, type); - DN_Str8x32 result = DN_Str8x32FromFmt("%.2f%.*s", byte_count.bytes, DN_Str8PrintFmt(byte_count.suffix)); - return result; -} - -DN_API DN_Profiler DN_ProfilerInit(DN_ProfilerAnchor *anchors, DN_USize count, DN_USize anchors_per_frame, DN_ProfilerTSCNowFunc *tsc_now, DN_U64 tsc_frequency) -{ - DN_Profiler result = {}; - result.anchors = anchors; - result.anchors_count = count; - result.anchors_per_frame = anchors_per_frame; - result.tsc_now = tsc_now; - result.tsc_frequency = tsc_frequency; - - DN_AssertF(result.tsc_frequency != 0, - "You must set this to the frequency of the timestamp counter function (TSC) (e.g. how " - "many ticks occur between timestamps). We use this to determine the duration between " - "each zone's recorded TSC. For example if the 'tsc_now' was set to Window's " - "QueryPerformanceCounter then 'tsc_frequency' would be set to the value of " - "QueryPerformanceFrequency which is typically 10mhz (e.g. The duration between two " - "consecutive TSC's is 10mhz)." - "" - "Hence frequency can't be zero otherwise it's a divide by 0. If you don't have a TSC " - "function and pass in null, the profiler defaults to rdtsc() and you must measure the " - "frequency of rdtsc yourself. The reason for this is that measuring rdtsc requires " - "having some alternate timing mechanism to measure the duration between the TSCs " - "provided by rdtsc and this profiler makes no assumption about what timing primitives " - "are available other than rdtsc which is a CPU builtin available on basically all " - "platforms or have an equivalent (e.g. __builtin_readcyclecounter)" - "" - "This codebase provides DN_OS_EstimateTSCPerSecond() as an example of how to that for " - "convenience and is available if compiling with the OS layer. Some platforms like " - "Emscripten don't support rdtsc() so you should use an alternative method like " - "emscripten_get_now() or clock_gettime with CLOCK_MONOTONIC."); - return result; -} - -DN_API DN_USize DN_ProfilerFrameCount(DN_Profiler const *profiler) -{ - DN_USize result = profiler->anchors_count / profiler->anchors_per_frame; - return result; -} - -DN_API DN_ProfilerAnchorArray DN_ProfilerFrameAnchorsFromIndex(DN_Profiler *profiler, DN_USize frame_index) -{ - DN_ProfilerAnchorArray result = {}; - DN_USize anchor_offset = frame_index * profiler->anchors_per_frame; - result.data = profiler->anchors + anchor_offset; - result.count = profiler->anchors_per_frame; - return result; -} - -DN_API DN_ProfilerAnchorArray DN_ProfilerFrameAnchors(DN_Profiler *profiler) -{ - DN_ProfilerAnchorArray result = DN_ProfilerFrameAnchorsFromIndex(profiler, profiler->frame_index); - return result; -} - -DN_API DN_ProfilerZone DN_ProfilerBeginZone(DN_Profiler *profiler, DN_Str8 name, DN_U16 anchor_index) -{ - DN_ProfilerZone result = {}; - if (profiler->paused) - return result; - - DN_Assert(anchor_index < profiler->anchors_per_frame); - DN_ProfilerAnchor *anchor = DN_ProfilerFrameAnchors(profiler).data + anchor_index; - anchor->name = name; - - // TODO: We need per-thread-local-storage profiler so that we can use these apis - // across threads. For now, we let them overwrite each other but this is not tenable. - #if 0 - if (anchor->name.size && anchor->name != name) - DN_AssertF(name == anchor->name, "Potentially overwriting a zone by accident? Anchor is '%.*s', name is '%.*s'", DN_Str8PrintFmt(anchor->name), DN_Str8PrintFmt(name)); - #endif - - result.begin_tsc = profiler->tsc_now ? profiler->tsc_now() : DN_CPUGetTSC(); - result.anchor_index = anchor_index; - result.parent_zone = profiler->parent_zone; - result.elapsed_tsc_at_zone_start = anchor->tsc_inclusive; - profiler->parent_zone = anchor_index; - return result; -} - -DN_API void DN_ProfilerEndZone(DN_Profiler *profiler, DN_ProfilerZone zone) -{ - if (profiler->paused) - return; - - DN_Assert(zone.anchor_index < profiler->anchors_per_frame); - DN_Assert(zone.parent_zone < profiler->anchors_per_frame); - - 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 elapsed_tsc = tsc_now - zone.begin_tsc; - - anchor->hit_count++; - anchor->tsc_inclusive = zone.elapsed_tsc_at_zone_start + elapsed_tsc; - anchor->tsc_exclusive += elapsed_tsc; - - if (zone.parent_zone != zone.anchor_index) { - DN_ProfilerAnchor *parent_anchor = array.data + zone.parent_zone; - parent_anchor->tsc_exclusive -= elapsed_tsc; - } - profiler->parent_zone = zone.parent_zone; -} - -DN_API void DN_ProfilerNewFrame(DN_Profiler *profiler) -{ - if (profiler->paused) - return; - - // NOTE: End the frame's zone - DN_ProfilerEndZone(profiler, profiler->frame_zone); - DN_ProfilerAnchorArray old_frame_anchors = DN_ProfilerFrameAnchors(profiler); - DN_ProfilerAnchor old_frame_anchor = old_frame_anchors.data[0]; - profiler->frame_avg_tsc = (profiler->frame_avg_tsc + old_frame_anchor.tsc_inclusive) / 2.f; - - // NOTE: Bump to the next frame - DN_USize frame_count = profiler->anchors_count / profiler->anchors_per_frame; - profiler->frame_index = (profiler->frame_index + 1) % frame_count; - - // NOTE: Zero out the anchors - DN_ProfilerAnchorArray next_anchors = DN_ProfilerFrameAnchors(profiler); - DN_Memset(next_anchors.data, 0, sizeof(*profiler->anchors) * next_anchors.count); - - // NOTE: Start the frame's zone - profiler->frame_zone = DN_ProfilerBeginZone(profiler, DN_Str8Lit("Profiler Frame"), 0); -} - -DN_API void DN_ProfilerDump(DN_Profiler *profiler) -{ - if (profiler->frame_index == 0) - return; - - DN_USize frame_index = profiler->frame_index - 1; - DN_Assert(profiler->frame_index < profiler->anchors_per_frame); - - DN_ProfilerAnchor *anchors = profiler->anchors + (frame_index * profiler->anchors_per_frame); - for (DN_USize index = 1; index < profiler->anchors_per_frame; index++) { - DN_ProfilerAnchor const *anchor = anchors + index; - if (!anchor->hit_count) - continue; - - DN_U64 tsc_exclusive = anchor->tsc_exclusive; - DN_U64 tsc_inclusive = anchor->tsc_inclusive; - DN_F64 tsc_exclusive_milliseconds = tsc_exclusive * 1000 / DN_Cast(DN_F64) profiler->tsc_frequency; - if (tsc_exclusive == tsc_inclusive) { - DN_OS_PrintOutLnF("%.*s[%u]: %.1fms", DN_Str8PrintFmt(anchor->name), anchor->hit_count, tsc_exclusive_milliseconds); - } else { - DN_F64 tsc_inclusive_milliseconds = tsc_inclusive * 1000 / DN_Cast(DN_F64) profiler->tsc_frequency; - DN_OS_PrintOutLnF("%.*s[%u]: %.1f/%.1fms", - DN_Str8PrintFmt(anchor->name), - anchor->hit_count, - tsc_exclusive_milliseconds, - tsc_inclusive_milliseconds); - } - } -} - -DN_API DN_F64 DN_ProfilerSecFromTSC(DN_Profiler *profiler, DN_U64 duration_tsc) -{ - DN_F64 result = DN_Cast(DN_F64)duration_tsc / profiler->tsc_frequency; - return result; -} - -DN_API DN_F64 DN_ProfilerMsFromTSC(DN_Profiler *profiler, DN_U64 duration_tsc) -{ - DN_F64 result = DN_Cast(DN_F64)duration_tsc / profiler->tsc_frequency * 1000.0; - return result; -} -// DN: Single header generator inlined this file => #include "Base/dn_base_containers.cpp" -#define DN_CONTAINERS_CPP - -// DN: Single header generator commented out this header => #include "../dn_base_inc.h" - -DN_API void *DN_CArray2_InsertArray(void *data, DN_USize *size, DN_USize max, DN_USize elem_size, DN_USize index, void const *items, DN_USize count) -{ - void *result = nullptr; - if (!data || !size || !items || count <= 0 || ((*size + count) > max)) - return result; - - DN_USize clamped_index = DN_Min(index, *size); - if (clamped_index != *size) { - char const *src = DN_Cast(char *)data + (clamped_index * elem_size); - char const *dest = DN_Cast(char *)data + ((clamped_index + count) * elem_size); - char const *end = DN_Cast(char *)data + (size[0] * elem_size); - DN_USize bytes_to_move = end - src; - DN_Memmove(DN_Cast(void *) dest, src, bytes_to_move); - } - - result = DN_Cast(char *)data + (clamped_index * elem_size); - DN_Memcpy(result, items, elem_size * count); - *size += count; - return result; -} - -DN_API DN_ArrayEraseResult DN_CArray2_EraseRange(void *data, DN_USize *size, DN_USize elem_size, DN_USize begin_index, DN_ISize count, DN_ArrayErase erase) -{ - DN_ArrayEraseResult result = {}; - if (!data || !size || *size == 0 || count == 0) - return result; - - // Compute the range to erase - DN_USize start = 0, end = 0; - if (count < 0) { - DN_USize abs_count = DN_Abs(count); - start = begin_index >= abs_count ? begin_index - abs_count + 1 : 0; - end = begin_index >= abs_count ? begin_index + 1 : 0; - } else { - start = begin_index; - end = begin_index + count; - } - - // Clamp indices to valid bounds - start = DN_Min(start, *size); - end = DN_Min(end, *size); - - // Erase the range [start, end) - DN_USize erase_count = end > start ? end - start : 0; - if (erase_count) { - char *dest = (char *)data + (elem_size * start); - char *array_end = (char *)data + (elem_size * *size); - char *src = dest + (elem_size * erase_count); - if (erase == DN_ArrayErase_Stable) { - DN_USize move_size = array_end - src; - DN_Memmove(dest, src, move_size); - } else { - char *unstable_src = array_end - (elem_size * erase_count); - DN_USize move_size = array_end - unstable_src; - DN_Memcpy(dest, unstable_src, move_size); - } - *size -= erase_count; - } - - result.items_erased = erase_count; - result.it_index = start; - return result; -} - -DN_API void *DN_CArray2_MakeArray(void *data, DN_USize *size, DN_USize max, DN_USize data_size, DN_USize make_size, DN_ZMem z_mem) -{ - void *result = nullptr; - DN_USize new_size = *size + make_size; - if (new_size <= max) { - result = DN_Cast(char *) data + (data_size * size[0]); - *size = new_size; - if (z_mem == DN_ZMem_Yes) - DN_Memset(result, 0, data_size * make_size); - } - - return result; -} - -DN_API void *DN_CArray2_AddArray(void *data, DN_USize *size, DN_USize max, DN_USize data_size, void const *elems, DN_USize elems_count, DN_ArrayAdd add) -{ - void *result = DN_CArray2_MakeArray(data, size, max, data_size, elems_count, DN_ZMem_No); - if (result) { - if (add == DN_ArrayAdd_Append) { - DN_Memcpy(result, elems, elems_count * data_size); - } else { - char *move_dest = DN_Cast(char *)data + (elems_count * data_size); // Shift elements forward - char *move_src = DN_Cast(char *)data; - DN_Memmove(move_dest, move_src, data_size * size[0]); - DN_Memcpy(data, elems, data_size * elems_count); - } - } - return result; -} - -DN_API bool DN_CArray2_ResizeFromPool(void **data, DN_USize *size, DN_USize *max, DN_USize data_size, DN_Pool *pool, DN_USize new_max) -{ - bool result = true; - if (new_max != *max) { - DN_USize bytes_to_alloc = data_size * new_max; - void *buffer = DN_PoolNewArray(pool, DN_U8, bytes_to_alloc); - if (buffer) { - DN_USize bytes_to_copy = data_size * DN_Min(*size, new_max); - DN_Memcpy(buffer, *data, bytes_to_copy); - DN_PoolDealloc(pool, *data); - *data = buffer; - *max = new_max; - *size = DN_Min(*size, new_max); - } else { - result = false; - } - } - - return result; -} - -DN_API bool DN_CArray2_GrowFromPool(void **data, DN_USize size, DN_USize *max, DN_USize data_size, DN_Pool *pool, DN_USize new_max) -{ - bool result = true; - if (new_max > *max) - result = DN_CArray2_ResizeFromPool(data, &size, max, data_size, pool, new_max); - return result; -} - -DN_API bool DN_CArray2_GrowIfNeededFromPool(void **data, DN_USize size, DN_USize *max, DN_USize data_size, DN_Pool *pool, DN_USize add_count) -{ - bool result = true; - DN_USize new_size = size + add_count; - if (new_size > *max) { - DN_USize new_max = DN_Max(DN_Max(*max * 2, new_size), 8); - result = DN_CArray2_ResizeFromPool(data, &size, max, data_size, pool, new_max); - } - return result; -} - -DN_API void *DN_CSLList_Detach(void **link, void **next) -{ - void *result = *link; - if (*link) { - *link = *next; - *next = nullptr; - } - return result; -} - -DN_API bool DN_Ring_HasSpace(DN_Ring const *ring, DN_U64 size) -{ - DN_U64 avail = ring->write_pos - ring->read_pos; - DN_U64 space = ring->size - avail; - bool result = space >= size; - return result; -} - -DN_API bool DN_Ring_HasData(DN_Ring const *ring, DN_U64 size) -{ - DN_U64 data = ring->write_pos - ring->read_pos; - bool result = data >= size; - return result; -} - -DN_API void DN_Ring_Write(DN_Ring *ring, void const *src, DN_U64 src_size) -{ - DN_Assert(src_size <= ring->size); - DN_U64 offset = ring->write_pos % ring->size; - DN_U64 bytes_before_split = ring->size - offset; - DN_U64 pre_split_bytes = DN_Min(bytes_before_split, src_size); - DN_U64 post_split_bytes = src_size - pre_split_bytes; - void const *pre_split_data = src; - void const *post_split_data = ((char *)src + pre_split_bytes); - DN_Memcpy(ring->base + offset, pre_split_data, pre_split_bytes); - DN_Memcpy(ring->base, post_split_data, post_split_bytes); - ring->write_pos += src_size; -} - -DN_API void DN_Ring_Read(DN_Ring *ring, void *dest, DN_U64 dest_size) -{ - DN_Assert(dest_size <= ring->size); - DN_U64 offset = ring->read_pos % ring->size; - DN_U64 bytes_before_split = ring->size - offset; - DN_U64 pre_split_bytes = DN_Min(bytes_before_split, dest_size); - DN_U64 post_split_bytes = dest_size - pre_split_bytes; - DN_Memcpy(dest, ring->base + offset, pre_split_bytes); - DN_Memcpy((char *)dest + pre_split_bytes, ring->base, post_split_bytes); - ring->read_pos += dest_size; -} - -// NOTE: DN_CArray ///////////////////////////////////////////////////////////////////////////////// -template -DN_ArrayEraseResult DN_CArray_EraseRange(T *data, DN_USize *size, DN_USize begin_index, DN_ISize count, DN_ArrayErase erase) -{ - DN_ArrayEraseResult result = {}; - if (!data || !size || *size == 0 || count == 0) - return result; - - DN_AssertF(count != -1, "There's a bug with negative element erases, see the DN_VArray section in dn_docs.cpp"); - - // NOTE: Caculate the end index of the erase range - DN_ISize abs_count = DN_Abs(count); - DN_USize end_index = 0; - if (count < 0) { - end_index = begin_index - (abs_count - 1); - if (end_index > begin_index) - end_index = 0; - } else { - end_index = begin_index + (abs_count - 1); - if (end_index < begin_index) - end_index = (*size) - 1; - } - - // NOTE: Ensure begin_index < one_past_end_index - if (end_index < begin_index) { - DN_USize tmp = begin_index; - begin_index = end_index; - end_index = tmp; - } - - // NOTE: Ensure indexes are within valid bounds - begin_index = DN_Min(begin_index, *size); - end_index = DN_Min(end_index, *size - 1); - - // NOTE: Erase the items in the range [begin_index, one_past_end_index) - DN_USize one_past_end_index = end_index + 1; - DN_USize erase_count = one_past_end_index - begin_index; - if (erase_count) { - T *end = data + *size; - T *dest = data + begin_index; - if (erase == DN_ArrayErase_Stable) { - T *src = dest + erase_count; - DN_Memmove(dest, src, (end - src) * sizeof(T)); - } else { - T *src = end - erase_count; - DN_Memcpy(dest, src, (end - src) * sizeof(T)); - } - *size -= erase_count; - } - - result.items_erased = erase_count; - result.it_index = begin_index; - return result; -} - -template -T *DN_CArray_MakeArray(T *data, DN_USize *size, DN_USize max, DN_USize count, DN_ZMem z_mem) -{ - if (!data || !size || count == 0) - return nullptr; - - if (!DN_CheckF((*size + count) <= max, "Array is out of space (user requested +%zu items, array has %zu/%zu items)", count, *size, max)) - return nullptr; - - // TODO: Use placement new? Why doesn't this work? - T *result = data + *size; - *size += count; - if (z_mem == DN_ZMem_Yes) - DN_Memset(result, 0, sizeof(*result) * count); - return result; -} - -template -T *DN_CArray_InsertArray(T *data, DN_USize *size, DN_USize max, DN_USize index, T const *items, DN_USize count) -{ - T *result = nullptr; - if (!data || !size || !items || count <= 0 || ((*size + count) > max)) - return result; - - DN_USize clamped_index = DN_Min(index, *size); - if (clamped_index != *size) { - char const *src = DN_Cast(char *)(data + clamped_index); - char const *dest = DN_Cast(char *)(data + (clamped_index + count)); - char const *end = DN_Cast(char *)(data + (*size)); - DN_USize bytes_to_move = end - src; - DN_Memmove(DN_Cast(void *) dest, src, bytes_to_move); - } - - result = data + clamped_index; - DN_Memcpy(result, items, sizeof(T) * count); - *size += count; - return result; -} - -template -T DN_CArray_PopFront(T *data, DN_USize *size, DN_USize count) -{ - T result = {}; - if (!data || !size || *size <= 0) - return result; - - result = data[0]; - DN_USize pop_count = DN_Min(count, *size); - DN_Memmove(data, data + pop_count, (*size - pop_count) * sizeof(T)); - *size -= pop_count; - return result; -} - -template -T DN_CArray_PopBack(T *data, DN_USize *size, DN_USize count) -{ - T result = {}; - if (!data || !size || *size <= 0) - return result; - - DN_USize pop_count = DN_Min(count, *size); - result = data[(*size - 1)]; - *size -= pop_count; - return result; -} - -template -DN_ArrayFindResult DN_CArray_Find(T *data, DN_USize size, T const &value) -{ - DN_ArrayFindResult result = {}; - if (!data || size <= 0) - return result; - - for (DN_USize index = 0; !result.data && index < size; index++) { - T *item = data + index; - if (*item == value) { - result.data = item; - result.index = index; - } - } - - return result; -} - -#if !defined(DN_NO_SARRAY) -// NOTE: DN_SArray ///////////////////////////////////////////////////////////////////////////////// -template -DN_SArray DN_SArray_Init(DN_Arena *arena, DN_USize size, DN_ZMem z_mem) -{ - DN_SArray result = {}; - if (!arena || !size) - return result; - result.data = DN_ArenaNewArray(arena, T, size, z_mem); - if (result.data) - result.max = size; - return result; -} - -template -DN_SArray DN_SArray_InitSlice(DN_Arena *arena, DN_Slice slice, DN_USize size, DN_ZMem z_mem) -{ - DN_USize max = DN_Max(slice.size, size); - DN_SArray result = DN_SArray_Init(arena, max, DN_ZMem_No); - if (DN_SArray_IsValid(&result)) { - DN_SArray_AddArray(&result, slice.data, slice.size); - if (z_mem == DN_ZMem_Yes) - DN_Memset(result.data + result.size, 0, (result.max - result.size) * sizeof(T)); - } - return result; -} - -template -DN_SArray DN_SArray_InitCArray(DN_Arena *arena, T const (&array)[N], DN_USize size, DN_ZMem z_mem) -{ - DN_SArray result = DN_SArray_InitSlice(arena, DN_Slice_Init(DN_Cast(T *) array, N), size, z_mem); - return result; -} - -template -DN_SArray DN_SArray_InitBuffer(T *buffer, DN_USize size) -{ - DN_SArray result = {}; - result.data = buffer; - result.max = size; - return result; -} - -template -bool DN_SArray_IsValid(DN_SArray const *array) -{ - bool result = array && array->data && array->size <= array->max; - return result; -} - -template -DN_Slice DN_SArray_Slice(DN_SArray const *array) -{ - DN_Slice result = {}; - if (array) - result = DN_Slice_Init(DN_Cast(T *) array->data, array->size); - return result; -} - -template -T *DN_SArray_MakeArray(DN_SArray *array, DN_USize count, DN_ZMem z_mem) -{ - if (!DN_SArray_IsValid(array)) - return nullptr; - T *result = DN_CArray_MakeArray(array->data, &array->size, array->max, count, z_mem); - return result; -} - -template -T *DN_SArray_Make(DN_SArray *array, DN_ZMem z_mem) -{ - T *result = DN_SArray_MakeArray(array, 1, z_mem); - return result; -} - -template -T *DN_SArray_AddArray(DN_SArray *array, T const *items, DN_USize count) -{ - T *result = DN_SArray_MakeArray(array, count, DN_ZMem_No); - if (result) - DN_Memcpy(result, items, count * sizeof(T)); - return result; -} - -template -T *DN_SArray_AddCArray(DN_SArray *array, T const (&items)[N]) -{ - T *result = DN_SArray_AddArray(array, items, N); - return result; -} - -template -T *DN_SArray_Add(DN_SArray *array, T const &item) -{ - T *result = DN_SArray_AddArray(array, &item, 1); - return result; -} - -template -T *DN_SArray_InsertArray(DN_SArray *array, DN_USize index, T const *items, DN_USize count) -{ - T *result = nullptr; - if (!DN_SArray_IsValid(array)) - return result; - result = DN_CArray_InsertArray(array->data, &array->size, array->max, index, items, count); - return result; -} - -template -T *DN_SArray_InsertCArray(DN_SArray *array, DN_USize index, T const (&items)[N]) -{ - T *result = DN_SArray_InsertArray(array, index, items, N); - return result; -} - -template -T *DN_SArray_Insert(DN_SArray *array, DN_USize index, T const &item) -{ - T *result = DN_SArray_InsertArray(array, index, &item, 1); - return result; -} - -template -T DN_SArray_PopFront(DN_SArray *array, DN_USize count) -{ - T result = DN_CArray_PopFront(array->data, &array->size, count); - return result; -} - -template -T DN_SArray_PopBack(DN_SArray *array, DN_USize count) -{ - T result = DN_CArray_PopBack(array->data, &array->size, count); - return result; -} - -template -DN_ArrayEraseResult DN_SArray_EraseRange(DN_SArray *array, DN_USize begin_index, DN_ISize count, DN_ArrayErase erase) -{ - DN_ArrayEraseResult result = {}; - if (!DN_SArray_IsValid(array) || array->size == 0 || count == 0) - return result; - result = DN_CArray_EraseRange(array->data, &array->size, begin_index, count, erase); - return result; -} - -template -void DN_SArray_Clear(DN_SArray *array) -{ - if (array) - array->size = 0; -} -#endif // !defined(DN_NO_SARRAY) - -#if !defined(DN_NO_FARRAY) -// NOTE: DN_FArray ///////////////////////////////////////////////////////////////////////////////// -template -DN_FArray DN_FArray_Init(T const *array, DN_USize count) -{ - DN_FArray result = {}; - bool added = DN_FArray_AddArray(&result, array, count); - DN_Assert(added); - return result; -} - -template -DN_FArray DN_FArray_InitSlice(DN_Slice slice) -{ - DN_FArray result = DN_FArray_Init(slice.data, slice.size); - return result; -} - -template -DN_FArray DN_FArray_InitCArray(T const (&items)[K]) -{ - DN_FArray result = DN_FArray_Init(items, K); - return result; -} - -template -bool DN_FArray_IsValid(DN_FArray const *array) -{ - bool result = array && array->size <= DN_ArrayCountU(array->data); - return result; -} - -template -DN_Slice DN_FArray_Slice(DN_FArray const *array) -{ - DN_Slice result = {}; - if (array) - result = DN_Slice_Init(DN_Cast(T *) array->data, array->size); - return result; -} - -template -T *DN_FArray_AddArray(DN_FArray *array, T const *items, DN_USize count) -{ - T *result = DN_FArray_MakeArray(array, count, DN_ZMem_No); - if (result) - DN_Memcpy(result, items, count * sizeof(T)); - return result; -} - -template -T *DN_FArray_AddCArray(DN_FArray *array, T const (&items)[K]) -{ - T *result = DN_FArray_MakeArray(array, K, DN_ZMem_No); - if (result) - DN_Memcpy(result, items, K * sizeof(T)); - return result; -} - -template -T *DN_FArray_Add(DN_FArray *array, T const &item) -{ - T *result = DN_FArray_AddArray(array, &item, 1); - return result; -} - -template -T *DN_FArray_MakeArray(DN_FArray *array, DN_USize count, DN_ZMem z_mem) -{ - if (!DN_FArray_IsValid(array)) - return nullptr; - T *result = DN_CArray_MakeArray(array->data, &array->size, N, count, z_mem); - return result; -} - -template -T *DN_FArray_Make(DN_FArray *array, DN_ZMem z_mem) -{ - T *result = DN_FArray_MakeArray(array, 1, z_mem); - return result; -} - -template -T *DN_FArray_InsertArray(DN_FArray *array, DN_USize index, T const *items, DN_USize count) -{ - T *result = nullptr; - if (!DN_FArray_IsValid(array)) - return result; - result = DN_CArray_InsertArray(array->data, &array->size, N, index, items, count); - return result; -} - -template -T *DN_FArray_InsertCArray(DN_FArray *array, DN_USize index, T const (&items)[K]) -{ - T *result = DN_FArray_InsertArray(array, index, items, K); - return result; -} - -template -T *DN_FArray_Insert(DN_FArray *array, DN_USize index, T const &item) -{ - T *result = DN_FArray_InsertArray(array, index, &item, 1); - return result; -} - -template -T DN_FArray_PopFront(DN_FArray *array, DN_USize count) -{ - T result = DN_CArray_PopFront(array->data, &array->size, count); - return result; -} - -template -T DN_FArray_PopBack(DN_FArray *array, DN_USize count) -{ - T result = DN_CArray_PopBack(array->data, &array->size, count); - return result; -} - -template -DN_ArrayFindResult DN_FArray_Find(DN_FArray *array, T const &find) -{ - DN_ArrayFindResult result = DN_CArray_Find(array->data, array->size, find); - return result; -} - -template -DN_ArrayEraseResult DN_FArray_EraseRange(DN_FArray *array, DN_USize begin_index, DN_ISize count, DN_ArrayErase erase) -{ - DN_ArrayEraseResult result = {}; - if (!DN_FArray_IsValid(array) || array->size == 0 || count == 0) - return result; - result = DN_CArray_EraseRange(array->data, &array->size, begin_index, count, erase); - return result; -} - -template -void DN_FArray_Clear(DN_FArray *array) -{ - if (array) - array->size = 0; -} -#endif // !defined(DN_NO_FARRAY) - -#if !defined(DN_NO_SLICE) -template -DN_Slice DN_Slice_Init(T *const data, DN_USize size) -{ - DN_Slice result = {}; - if (data) { - result.data = data; - result.size = size; - } - return result; -} - -template -DN_Slice DN_Slice_InitCArrayCopy(DN_Arena *arena, T const (&array)[N]) -{ - DN_Slice result = DN_Slice_Alloc(arena, N, DN_ZMem_No); - if (result.data) - DN_Memcpy(result.data, array, sizeof(T) * N); - return result; -} - -template -DN_Slice DN_Slice_CopyPtr(DN_Arena *arena, T *const data, DN_USize size) -{ - T *copy = DN_ArenaNewArrayCopy(arena, T, data, size); - DN_Slice result = DN_Slice_Init(copy, copy ? size : 0); - return result; -} - -template -DN_Slice DN_Slice_Copy(DN_Arena *arena, DN_Slice slice) -{ - DN_Slice result = DN_Slice_CopyPtr(arena, slice.data, slice.size); - return result; -} - -template -DN_Slice DN_Slice_Alloc(DN_Arena *arena, DN_USize size, DN_ZMem z_mem) -{ - DN_Slice result = {}; - if (!arena || size == 0) - return result; - result.data = DN_ArenaNewArray(arena, T, size, z_mem); - if (result.data) - result.size = size; - return result; -} - -#endif // !defined(DN_NO_SLICE) - -#if !defined(DN_NO_DSMAP) -// NOTE: DN_DSMap ////////////////////////////////////////////////////////////////////////////////// -DN_U32 const DN_DS_MAP_DEFAULT_HASH_SEED = 0x8a1ced49; -DN_U32 const DN_DS_MAP_SENTINEL_SLOT = 0; - -template -DN_DSMap DN_DSMap_Init(DN_Arena *arena, DN_U32 size, DN_DSMapFlags flags) -{ - DN_DSMap result = {}; - if (!DN_CheckF(DN_IsPowerOfTwo(size), "Power-of-two size required, given size was '%u'", size)) - return result; - if (size <= 0) - return result; - if (!DN_Check(arena)) - return result; - result.arena = arena; - result.pool = DN_PoolFromArena(arena, DN_POOL_DEFAULT_ALIGN); - result.hash_to_slot = DN_ArenaNewArray(result.arena, DN_U32, size, DN_ZMem_Yes); - result.slots = DN_ArenaNewArray(result.arena, DN_DSMapSlot, size, DN_ZMem_Yes); - result.occupied = 1; // For sentinel - result.size = size; - result.initial_size = size; - result.flags = flags; - DN_AssertF(result.hash_to_slot && result.slots, "We pre-allocated a block of memory sufficient in size for the 2 arrays. Maybe the pointers needed extra space because of natural alignment?"); - return result; -} - -template -void DN_DSMap_Deinit(DN_DSMap *map, DN_ZMem z_mem) -{ - if (!map) - return; - // TODO(doyle): Use z_mem - (void)z_mem; - DN_ArenaDeinit(map->arena); - *map = {}; -} - -template -bool DN_DSMap_IsValid(DN_DSMap const *map) -{ - bool result = map && - map->arena && - map->hash_to_slot && // Hash to slot mapping array must be allocated - map->slots && // Slots array must be allocated - (map->size & (map->size - 1)) == 0 && // Must be power of two size - map->occupied >= 1; // DN_DS_MAP_SENTINEL_SLOT takes up one slot - return result; -} - -template -DN_U32 DN_DSMap_Hash(DN_DSMap const *map, DN_DSMapKey key) -{ - DN_U32 result = 0; - if (!map) - return result; - - if (key.type == DN_DSMapKeyType_U64NoHash) { - result = DN_Cast(DN_U32) key.u64; - return result; - } - - if (key.type == DN_DSMapKeyType_BufferAsU64NoHash) { - result = key.hash; - return result; - } - - DN_U32 seed = map->hash_seed ? map->hash_seed : DN_DS_MAP_DEFAULT_HASH_SEED; - if (map->hash_function) { - map->hash_function(key, seed); - } else { - // NOTE: Courtesy of Demetri Spanos (which this hash table was inspired - // from), the following is a hashing function snippet provided for - // reliable, quick and simple quality hashing functions for hash table - // use. - // Source: https://github.com/demetri/scribbles/blob/c475464756c104c91bab83ed4e14badefef12ab5/hashing/ub_aware_hash_functions.c - - char const *key_ptr = nullptr; - DN_U32 len = 0; - DN_U32 h = seed; - switch (key.type) { - case DN_DSMapKeyType_BufferAsU64NoHash: /*FALLTHRU*/ - case DN_DSMapKeyType_U64NoHash: DN_InvalidCodePath; /*FALLTHRU*/ - case DN_DSMapKeyType_Invalid: break; - - case DN_DSMapKeyType_Buffer: - key_ptr = DN_Cast(char const *) key.buffer_data; - len = key.buffer_size; - break; - - case DN_DSMapKeyType_U64: - key_ptr = DN_Cast(char const *) & key.u64; - len = sizeof(key.u64); - break; - } - - // Murmur3 32-bit without UB unaligned accesses - // DN_U32 mur3_32_no_UB(const void *key, int len, DN_U32 h) - - // main body, work on 32-bit blocks at a time - for (DN_U32 i = 0; i < len / 4; i++) { - DN_U32 k; - memcpy(&k, &key_ptr[i * 4], sizeof(k)); - - k *= 0xcc9e2d51; - k = ((k << 15) | (k >> 17)) * 0x1b873593; - h = (((h ^ k) << 13) | ((h ^ k) >> 19)) * 5 + 0xe6546b64; - } - - // load/mix up to 3 remaining tail bytes into a tail block - DN_U32 t = 0; - uint8_t *tail = ((uint8_t *)key_ptr) + 4 * (len / 4); - switch (len & 3) { - case 3: t ^= tail[2] << 16; - case 2: t ^= tail[1] << 8; - case 1: { - t ^= tail[0] << 0; - h ^= ((0xcc9e2d51 * t << 15) | (0xcc9e2d51 * t >> 17)) * 0x1b873593; - } - } - - // finalization mix, including key length - h = ((h ^ len) ^ ((h ^ len) >> 16)) * 0x85ebca6b; - h = (h ^ (h >> 13)) * 0xc2b2ae35; - result = h ^ (h >> 16); - } - return result; -} - -template -DN_U32 DN_DSMap_HashToSlotIndex(DN_DSMap const *map, DN_DSMapKey key) -{ - DN_Assert(key.type != DN_DSMapKeyType_Invalid); - DN_U32 result = DN_DS_MAP_SENTINEL_SLOT; - if (!DN_DSMap_IsValid(map)) - return result; - - result = key.hash & (map->size - 1); - for (;;) { - if (result == DN_DS_MAP_SENTINEL_SLOT) // Sentinel is reserved - result++; - - if (map->hash_to_slot[result] == DN_DS_MAP_SENTINEL_SLOT) // Slot is vacant, can use - return result; - - DN_DSMapSlot *slot = map->slots + map->hash_to_slot[result]; - if (slot->key.type == DN_DSMapKeyType_Invalid || (slot->key.hash == key.hash && slot->key == key)) - return result; - - result = (result + 1) & (map->size - 1); - } -} - -template -DN_DSMapResult DN_DSMap_Find(DN_DSMap const *map, DN_DSMapKey key) -{ - DN_DSMapResult result = {}; - if (DN_DSMap_IsValid(map)) { - DN_U32 index = DN_DSMap_HashToSlotIndex(map, key); - if (index != DN_DS_MAP_SENTINEL_SLOT && map->hash_to_slot[index] == DN_DS_MAP_SENTINEL_SLOT) { - result.slot = map->slots; // NOTE: Set to sentinel value - } else { - result.slot = map->slots + map->hash_to_slot[index]; - result.found = true; - } - result.value = &result.slot->value; - } - return result; -} - -template -DN_DSMapResult DN_DSMap_Make(DN_DSMap *map, DN_DSMapKey key) -{ - DN_DSMapResult result = {}; - if (!DN_DSMap_IsValid(map)) - return result; - - DN_U32 index = DN_DSMap_HashToSlotIndex(map, key); - if (map->hash_to_slot[index] == DN_DS_MAP_SENTINEL_SLOT) { - // NOTE: Create the slot - if (index != DN_DS_MAP_SENTINEL_SLOT) - map->hash_to_slot[index] = map->occupied++; - - // NOTE: Check if resize is required - bool map_is_75pct_full = (map->occupied * 4) > (map->size * 3); - if (map_is_75pct_full) { - if (!DN_DSMap_Resize(map, map->size * 2)) - return result; - result = DN_DSMap_Make(map, key); - } else { - result.slot = map->slots + map->hash_to_slot[index]; - result.slot->key = key; // NOTE: Assign key to new slot - if ((key.type == DN_DSMapKeyType_Buffer || - key.type == DN_DSMapKeyType_BufferAsU64NoHash) && - !key.no_copy_buffer) - result.slot->key.buffer_data = DN_PoolNewArrayCopy(&map->pool, char, key.buffer_data, key.buffer_size); - } - } else { - result.slot = map->slots + map->hash_to_slot[index]; - result.found = true; - } - - result.value = &result.slot->value; - DN_Assert(result.slot->key.type != DN_DSMapKeyType_Invalid); - return result; -} - -template -DN_DSMapResult DN_DSMap_Set(DN_DSMap *map, DN_DSMapKey key, T const &value) -{ - DN_DSMapResult result = {}; - if (!DN_DSMap_IsValid(map)) - return result; - - result = DN_DSMap_Make(map, key); - result.slot->value = value; - return result; -} - -template -DN_DSMapResult DN_DSMap_FindKeyU64(DN_DSMap const *map, DN_U64 key) -{ - DN_DSMapKey map_key = DN_DSMap_KeyU64(map, key); - DN_DSMapResult result = DN_DSMap_Find(map, map_key); - return result; -} - -template -DN_DSMapResult DN_DSMap_MakeKeyU64(DN_DSMap *map, DN_U64 key) -{ - DN_DSMapKey map_key = DN_DSMap_KeyU64(map, key); - DN_DSMapResult result = DN_DSMap_Make(map, map_key); - return result; -} - -template -DN_DSMapResult DN_DSMap_SetKeyU64(DN_DSMap *map, DN_U64 key, T const &value) -{ - DN_DSMapKey map_key = DN_DSMap_KeyU64(map, key); - DN_DSMapResult result = DN_DSMap_Set(map, map_key, value); - return result; -} - -template -DN_DSMapResult DN_DSMap_FindKeyStr8(DN_DSMap const *map, DN_Str8 key) -{ - DN_DSMapKey map_key = DN_DSMap_KeyStr8(map, key); - DN_DSMapResult result = DN_DSMap_Find(map, map_key); - return result; -} - -template -DN_DSMapResult DN_DSMap_MakeKeyStr8(DN_DSMap *map, DN_Str8 key) -{ - DN_DSMapKey map_key = DN_DSMap_KeyStr8(map, key); - DN_DSMapResult result = DN_DSMap_Make(map, map_key); - return result; -} - -template -DN_DSMapResult DN_DSMap_SetKeyStr8(DN_DSMap *map, DN_Str8 key, T const &value) -{ - DN_DSMapKey map_key = DN_DSMap_KeyStr8(map, key); - DN_DSMapResult result = DN_DSMap_Set(map, map_key); - return result; -} - -template -bool DN_DSMap_Resize(DN_DSMap *map, DN_U32 size) -{ - if (!DN_DSMap_IsValid(map) || size < map->occupied || size < map->initial_size) - return false; - - DN_Arena *prev_arena = map->arena; - DN_Arena new_arena = {}; - new_arena.mem_funcs = prev_arena->mem_funcs; - new_arena.flags = prev_arena->flags; - new_arena.label = prev_arena->label; - new_arena.prev = prev_arena->prev; - new_arena.next = prev_arena->next; - - DN_DSMap new_map = DN_DSMap_Init(&new_arena, size, map->flags); - if (!DN_DSMap_IsValid(&new_map)) - return false; - - new_map.initial_size = map->initial_size; - for (DN_U32 old_index = 1 /*Sentinel*/; old_index < map->occupied; old_index++) { - DN_DSMapSlot *old_slot = map->slots + old_index; - DN_DSMapKey old_key = old_slot->key; - if (old_key.type == DN_DSMapKeyType_Invalid) - continue; - DN_DSMap_Set(&new_map, old_key, old_slot->value); - } - - if ((map->flags & DN_DSMapFlags_DontFreeArenaOnResize) == 0) - DN_DSMap_Deinit(map, DN_ZMem_No); - *map = new_map; // Update the map inplace - map->arena = prev_arena; // Restore the previous arena pointer, it's been de-init-ed - *map->arena = new_arena; // Re-init the old arena with the new data - map->pool.arena = map->arena; - return true; -} - -template -bool DN_DSMap_Erase(DN_DSMap *map, DN_DSMapKey key) -{ - if (!DN_DSMap_IsValid(map)) - return false; - - DN_U32 index = DN_DSMap_HashToSlotIndex(map, key); - if (index == 0) - return true; - - DN_U32 slot_index = map->hash_to_slot[index]; - if (slot_index == DN_DS_MAP_SENTINEL_SLOT) - return false; - - // NOTE: Mark the slot as unoccupied - map->hash_to_slot[index] = DN_DS_MAP_SENTINEL_SLOT; - - DN_DSMapSlot *slot = map->slots + slot_index; - if (!slot->key.no_copy_buffer) - DN_PoolDealloc(&map->pool, DN_Cast(void *) slot->key.buffer_data); - *slot = {}; // TODO: Optional? - - if (map->occupied > 1 /*Sentinel*/) { - // NOTE: Repair the hash chain, e.g. rehash all the items after the removed - // element and reposition them if necessary. - for (DN_U32 probe_index = index;;) { - probe_index = (probe_index + 1) & (map->size - 1); - if (map->hash_to_slot[probe_index] == DN_DS_MAP_SENTINEL_SLOT) - break; - - DN_DSMapSlot *probe = map->slots + map->hash_to_slot[probe_index]; - DN_U32 new_index = probe->key.hash & (map->size - 1); - if (index <= probe_index) { - if (index < new_index && new_index <= probe_index) - continue; - } else { - if (index < new_index || new_index <= probe_index) - continue; - } - - map->hash_to_slot[index] = map->hash_to_slot[probe_index]; - map->hash_to_slot[probe_index] = DN_DS_MAP_SENTINEL_SLOT; - index = probe_index; - } - - // NOTE: We have erased a slot from the hash table, this leaves a gap - // in our contiguous array. After repairing the chain, the hash mapping - // is correct. - // We will now fill in the vacant spot that we erased using the last - // element in the slot list. - if (map->occupied >= 3 /*Ignoring sentinel, at least 2 other elements to unstable erase*/) { - DN_U32 last_index = map->occupied - 1; - if (last_index != slot_index) { - // NOTE: Copy in last slot to the erase slot - DN_DSMapSlot *last_slot = map->slots + last_index; - map->slots[slot_index] = *last_slot; - - // NOTE: Update the hash-to-slot mapping for the value that was copied in - DN_U32 hash_to_slot_index = DN_DSMap_HashToSlotIndex(map, last_slot->key); - map->hash_to_slot[hash_to_slot_index] = slot_index; - *last_slot = {}; // TODO: Optional? - } - } - } - - map->occupied--; - bool map_is_below_25pct_full = (map->occupied * 4) < (map->size * 1); - if (map_is_below_25pct_full && (map->size / 2) >= map->initial_size) - DN_DSMap_Resize(map, map->size / 2); - - return true; -} - -template -bool DN_DSMap_EraseKeyU64(DN_DSMap *map, DN_U64 key) -{ - DN_DSMapKey map_key = DN_DSMap_KeyU64(map, key); - bool result = DN_DSMap_Erase(map, map_key); - return result; -} - -template -bool DN_DSMap_EraseKeyStr8(DN_DSMap *map, DN_Str8 key) -{ - DN_DSMapKey map_key = DN_DSMap_KeyStr8(map, key); - bool result = DN_DSMap_Erase(map, map_key); - return result; -} - -template -DN_DSMapKey DN_DSMap_KeyBuffer(DN_DSMap const *map, void const *data, DN_USize size) -{ - DN_Assert(size > 0 && size <= UINT32_MAX); - DN_DSMapKey result = {}; - result.type = DN_DSMapKeyType_Buffer; - result.buffer_data = data; - result.buffer_size = DN_Cast(DN_U32) size; - result.hash = DN_DSMap_Hash(map, result); - return result; -} - -template -DN_DSMapKey DN_DSMap_KeyBufferAsU64NoHash(DN_DSMap const *map, void const *data, DN_U32 size) -{ - DN_DSMapKey result = {}; - result.type = DN_DSMapKeyType_BufferAsU64NoHash; - result.buffer_data = data; - result.buffer_size = DN_Cast(DN_U32) size; - DN_Assert(size >= sizeof(result.hash)); - DN_Memcpy(&result.hash, data, sizeof(result.hash)); - return result; -} - -template -DN_DSMapKey DN_DSMap_KeyU64(DN_DSMap const *map, DN_U64 u64) -{ - DN_DSMapKey result = {}; - result.type = DN_DSMapKeyType_U64; - result.u64 = u64; - result.hash = DN_DSMap_Hash(map, result); - return result; -} - -template -DN_DSMapKey DN_DSMap_KeyStr8(DN_DSMap const *map, DN_Str8 string) -{ - DN_DSMapKey result = DN_DSMap_KeyBuffer(map, string.data, string.size); - return result; -} -#endif // !defined(DN_NO_DSMAP) - -#if !defined(DN_NO_LIST) -// NOTE: DN_List /////////////////////////////////////////////////////////////////////////////////// -template -DN_List DN_List_Init(DN_USize chunk_size) -{ - DN_List result = {}; - result.chunk_size = chunk_size; - return result; -} - -template -DN_List DN_List_InitCArray(DN_Arena *arena, DN_USize chunk_size, T const (&array)[N]) -{ - DN_List result = DN_List_Init(arena, chunk_size); - for (DN_ForIndexU(index, N)) - DN_List_Add(&result, array[index]); - return result; -} - -template -DN_List DN_List_InitSliceCopy(DN_Arena *arena, DN_USize chunk_size, DN_Slice slice) -{ - DN_List result = DN_List_Init(arena, chunk_size); - for (DN_ForIndexU(index, slice.size)) - DN_List_Add(&result, slice.data[index]); - return result; -} - -template -DN_API bool DN_List_AttachTail_(DN_List *list, DN_ListChunk *tail) -{ - if (!tail) - return false; - - if (list->tail) { - list->tail->next = tail; - tail->prev = list->tail; - } - - list->tail = tail; - - if (!list->head) - list->head = list->tail; - return true; -} - -template -DN_API DN_ListChunk *DN_List_AllocArena_(DN_List *list, DN_Arena *arena, DN_USize count) -{ - auto *result = DN_ArenaNew(arena, DN_ListChunk, DN_ZMem_Yes); - DN_ArenaTempMem tmem = DN_ArenaTempMemBegin(arena); - if (!result) - return nullptr; - - DN_USize items = DN_Max(list->chunk_size, count); - result->data = DN_ArenaNewArray(arena, T, items, DN_ZMem_Yes); - result->size = items; - if (!result->data) { - DN_ArenaTempMemEnd(tmem); - result = nullptr; - } - - DN_List_AttachTail_(list, result); - return result; -} - -template -DN_API DN_ListChunk *DN_List_AllocPool_(DN_List *list, DN_Pool *pool, DN_USize count) -{ - auto *result = DN_PoolNew(pool, DN_ListChunk); - if (!result) - return nullptr; - - DN_USize items = DN_Max(list->chunk_size, count); - result->data = DN_PoolNewArray(pool, T, items); - result->size = items; - if (!result->data) { - DN_PoolDealloc(result); - result = nullptr; - } - - DN_List_AttachTail_(list, result); - return result; -} - -template -DN_API T *DN_List_MakeArena(DN_List *list, DN_Arena *arena, DN_USize count) -{ - if (list->chunk_size == 0) - list->chunk_size = 128; - - if (!list->tail || (list->tail->count + count) > list->tail->size) { - if (!DN_List_AllocArena_(list, arena, count)) - return nullptr; - } - - T *result = list->tail->data + list->tail->count; - list->tail->count += count; - list->count += count; - return result; -} - -template -DN_API T *DN_List_MakePool(DN_List *list, DN_Pool *pool, DN_USize count) -{ - if (list->chunk_size == 0) - list->chunk_size = 128; - - if (!list->tail || (list->tail->count + count) > list->tail->size) { - if (!DN_List_AllocPool_(list, pool, count)) - return nullptr; - } - - T *result = list->tail->data + list->tail->count; - list->tail->count += count; - list->count += count; - return result; -} - -template -DN_API T *DN_List_AddArena(DN_List *list, DN_Arena *arena, T const &value) -{ - T *result = DN_List_MakeArena(list, arena, 1); - *result = value; - return result; -} - -template -DN_API T *DN_List_AddPool(DN_List *list, DN_Pool *pool, T const &value) -{ - T *result = DN_List_MakePool(list, pool, 1); - *result = value; - return result; -} - -template -DN_API bool DN_List_AddCArray(DN_List *list, T const (&array)[N]) -{ - if (!list) - return false; - for (T const &item : array) - if (!DN_List_Add(list, item)) - return false; - return true; -} - -template -DN_API void DN_List_AddListArena(DN_List *list, DN_Arena *arena, DN_List other) -{ - if (!list) - return; - // TODO(doyle): Copy chunk by chunk - for (DN_ListIterator it = {}; DN_List_Iterate(&other, &it, 0 /*start_index*/);) - DN_List_AddArena(list, arena, *it.data); -} - -template -DN_API void DN_List_AddListPool(DN_List *list, DN_Pool *pool, DN_List other) -{ - if (!list) - return; - // TODO(doyle): Copy chunk by chunk - for (DN_ListIterator it = {}; DN_List_Iterate(&other, &it, 0 /*start_index*/);) - DN_List_AddPool(list, pool, *it.data); -} - -template -void DN_List_Clear(DN_List *list) -{ - if (!list) - return; - list->head = list->tail = nullptr; - list->count = 0; -} - -template -DN_API bool DN_List_Iterate(DN_List *list, DN_ListIterator *it, DN_USize start_index) -{ - bool result = false; - if (!list || !it || list->chunk_size <= 0) - return result; - - if (it->init) { - it->index++; - } else { - *it = {}; - if (start_index == 0) { - it->chunk = list->head; - } else { - DN_List_At(list, start_index, &it->chunk); - if (list->chunk_size > 0) - it->chunk_data_index = start_index % list->chunk_size; - } - - it->init = true; - } - - if (it->chunk) { - if (it->chunk_data_index >= it->chunk->count) { - it->chunk = it->chunk->next; - it->chunk_data_index = 0; - } - - if (it->chunk) { - it->data = it->chunk->data + it->chunk_data_index++; - result = true; - } - } - - if (!it->chunk) - DN_Assert(result == false); - return result; -} - -template -DN_API T *DN_List_At(DN_List *list, DN_USize index, DN_ListChunk **at_chunk) -{ - if (!list || index >= list->count || !list->head) - return nullptr; - - // NOTE: Scan forwards to the chunk we need. We don't have random access to chunks - DN_ListChunk **chunk = &list->head; - DN_USize running_index = index; - for (; (*chunk) && running_index >= (*chunk)->size; chunk = &((*chunk)->next)) - running_index -= (*chunk)->size; - - T *result = nullptr; - if (*chunk) - result = (*chunk)->data + running_index; - - if (result && at_chunk) - *at_chunk = *chunk; - - return result; -} - -template -DN_Slice DN_List_ToSliceCopy(DN_List const *list, DN_Arena *arena) -{ - // TODO(doyle): Chunk memcopies is much faster - DN_Slice result = DN_Slice_Alloc(arena, list->count, DN_ZMem_No); - if (result.size) { - DN_USize slice_index = 0; - DN_MSVC_WARNING_PUSH - DN_MSVC_WARNING_DISABLE(6011) // Dereferencing NULL pointer 'x' - for (DN_ListIterator it = {}; DN_List_Iterate(DN_Cast(DN_List *) list, &it, 0);) - result.data[slice_index++] = *it.data; - DN_MSVC_WARNING_POP - DN_Assert(slice_index == result.size); - } - return result; -} -#endif // !defined(DN_NO_LIST) - -// NOTE: DN_Slice ////////////////////////////////////////////////////////////////////////////////// -DN_API DN_Str8 DN_Slice_Str8Render(DN_Arena *arena, DN_Slice array, DN_Str8 separator) -{ - DN_Str8 result = {}; - if (!arena) - return result; - - DN_USize total_size = 0; - for (DN_USize index = 0; index < array.size; index++) { - if (index) - total_size += separator.size; - DN_Str8 item = array.data[index]; - total_size += item.size; - } - - result = DN_Str8FromArena(arena, total_size, DN_ZMem_No); - if (result.data) { - DN_USize write_index = 0; - for (DN_USize index = 0; index < array.size; index++) { - if (index) { - DN_Memcpy(result.data + write_index, separator.data, separator.size); - write_index += separator.size; - } - DN_Str8 item = array.data[index]; - DN_Memcpy(result.data + write_index, item.data, item.size); - write_index += item.size; - } - } - - return result; -} - -DN_API DN_Str8 DN_Slice_Str8RenderSpaceSeparated(DN_Arena *arena, DN_Slice array) -{ - DN_Str8 result = DN_Slice_Str8Render(arena, array, DN_Str8Lit(" ")); - return result; -} - -DN_API DN_Str16 DN_Slice_Str16Render(DN_Arena *arena, DN_Slice array, DN_Str16 separator) -{ - DN_Str16 result = {}; - if (!arena) - return result; - - DN_USize total_size = 0; - for (DN_USize index = 0; index < array.size; index++) { - if (index) - total_size += separator.size; - DN_Str16 item = array.data[index]; - total_size += item.size; - } - - result = {DN_ArenaNewArray(arena, wchar_t, total_size + 1, DN_ZMem_No), total_size}; - if (result.data) { - DN_USize write_index = 0; - for (DN_USize index = 0; index < array.size; index++) { - if (index) { - DN_Memcpy(result.data + write_index, separator.data, separator.size * sizeof(result.data[0])); - write_index += separator.size; - } - DN_Str16 item = array.data[index]; - DN_Memcpy(result.data + write_index, item.data, item.size * sizeof(result.data[0])); - write_index += item.size; - } - } - - result.data[total_size] = 0; - return result; -} - -DN_API DN_Str16 DN_Slice_Str16RenderSpaceSeparated(DN_Arena *arena, DN_Slice array) -{ - DN_Str16 result = DN_Slice_Str16Render(arena, array, DN_Str16Lit(L" ")); - return result; -} - -#if !defined(DN_NO_DSMAP) -// NOTE: DN_DSMap ////////////////////////////////////////////////////////////////////////////////// -DN_API DN_DSMapKey DN_DSMap_KeyU64NoHash(DN_U64 u64) -{ - DN_DSMapKey result = {}; - result.type = DN_DSMapKeyType_U64NoHash; - result.u64 = u64; - result.hash = DN_Cast(DN_U32) u64; - return result; -} - -DN_API bool DN_DSMap_KeyEquals(DN_DSMapKey lhs, DN_DSMapKey rhs) -{ - bool result = false; - if (lhs.type == rhs.type && lhs.hash == rhs.hash) { - switch (lhs.type) { - case DN_DSMapKeyType_Invalid: result = true; break; - case DN_DSMapKeyType_U64NoHash: result = true; break; - case DN_DSMapKeyType_U64: result = lhs.u64 == rhs.u64; break; - - case DN_DSMapKeyType_BufferAsU64NoHash: /*FALLTHRU*/ - case DN_DSMapKeyType_Buffer: { - if (lhs.buffer_size == rhs.buffer_size) - result = DN_Memcmp(lhs.buffer_data, rhs.buffer_data, lhs.buffer_size) == 0; - } break; - } - } - return result; -} - -DN_API bool operator==(DN_DSMapKey lhs, DN_DSMapKey rhs) -{ - bool result = DN_DSMap_KeyEquals(lhs, rhs); - return result; -} -#endif // !defined(DN_NO_DSMAP) -// DN: Single header generator inlined this file => #include "Base/dn_base_log.cpp" -#define DN_BASE_LOG_CPP - -// DN: Single header generator commented out this header => #include "../dn_base_inc.h" - -static DN_LOGEmitFromTypeFVFunc *g_dn_base_log_emit_from_type_fv_func_; -static void *g_dn_base_log_emit_from_type_fv_user_context_; - -DN_API DN_Str8 DN_LOG_ColourEscapeCodeStr8FromRGB(DN_LOGColourType colour, DN_U8 r, DN_U8 g, DN_U8 b) -{ - DN_THREAD_LOCAL char buffer[32]; - buffer[0] = 0; - DN_Str8 result = {}; - result.size = DN_SNPrintF(buffer, - DN_ArrayCountU(buffer), - "\x1b[%d;2;%u;%u;%um", - colour == DN_LOGColourType_Fg ? 38 : 48, - r, - g, - b); - result.data = buffer; - return result; -} - -DN_API DN_Str8 DN_LOG_ColourEscapeCodeStr8FromU32(DN_LOGColourType colour, DN_U32 value) -{ - DN_U8 r = DN_Cast(DN_U8)(value >> 24); - DN_U8 g = DN_Cast(DN_U8)(value >> 16); - DN_U8 b = DN_Cast(DN_U8)(value >> 8); - DN_Str8 result = DN_LOG_ColourEscapeCodeStr8FromRGB(colour, r, g, b); - return result; -} - -DN_API DN_LOGPrefixSize DN_LOG_MakePrefix(DN_LOGStyle style, DN_LOGTypeParam type, DN_CallSite call_site, DN_LOGDate date, char *dest, DN_USize dest_size) -{ - DN_Str8 type_str8 = type.str8; - if (type.is_u32_enum) { - switch (type.u32) { - case DN_LOGType_Debug: type_str8 = DN_Str8Lit("DEBUG"); break; - case DN_LOGType_Info: type_str8 = DN_Str8Lit("INFO "); break; - case DN_LOGType_Warning: type_str8 = DN_Str8Lit("WARN"); break; - case DN_LOGType_Error: type_str8 = DN_Str8Lit("ERROR"); break; - case DN_LOGType_Count: type_str8 = DN_Str8Lit("BADXX"); break; - } - } - - static DN_USize max_type_length = 0; - max_type_length = DN_Max(max_type_length, type_str8.size); - int type_padding = DN_Cast(int)(max_type_length - type_str8.size); - - DN_Str8 colour_esc = {}; - DN_Str8 bold_esc = {}; - DN_Str8 reset_esc = {}; - if (style.colour) { - bold_esc = DN_Str8Lit(DN_LOG_BoldEscapeCode); - reset_esc = DN_Str8Lit(DN_LOG_ResetEscapeCode); - colour_esc = DN_LOG_ColourEscapeCodeStr8FromRGB(DN_LOGColourType_Fg, style.r, style.g, style.b); - } - - DN_Str8 file_name = DN_Str8FileNameFromPath(call_site.file); - DN_GCC_WARNING_PUSH - DN_GCC_WARNING_DISABLE(-Wformat) - DN_GCC_WARNING_DISABLE(-Wformat-extra-args) - DN_MSVC_WARNING_PUSH - DN_MSVC_WARNING_DISABLE(4477) - int size = DN_SNPrintF(dest, - DN_Cast(int)dest_size, - "%04u-%02u-%02uT%02u:%02u:%02u" // date - "%S" // colour - "%S" // bold - " %S" // type - "%.*s" // type padding - "%S" // reset - " %S" // file name - ":%05I32u " // line number - , - date.year, - date.month, - date.day, - date.hour, - date.minute, - date.second, - colour_esc, // colour - bold_esc, // bold - type_str8, // type - DN_Cast(int) type_padding, - "", // type padding - reset_esc, // reset - file_name, // file name - call_site.line); // line number - DN_MSVC_WARNING_POP // '%S' requires an argument of type 'wchar_t *', but variadic argument 7 has type 'DN_Str8' - DN_GCC_WARNING_POP - - static DN_USize max_header_length = 0; - DN_USize size_no_ansi_codes = size - colour_esc.size - reset_esc.size - bold_esc.size; - max_header_length = DN_Max(max_header_length, size_no_ansi_codes); - DN_USize header_padding = max_header_length - size_no_ansi_codes; - - DN_LOGPrefixSize result = {}; - result.size = size; - result.padding = header_padding; - return result; -} - -DN_API void DN_LOG_SetEmitFromTypeFVFunc(DN_LOGEmitFromTypeFVFunc *print_func, void *user_data) -{ - g_dn_base_log_emit_from_type_fv_func_ = print_func; - g_dn_base_log_emit_from_type_fv_user_context_ = user_data; -} - -DN_API void DN_LOG_EmitFromType(DN_LOGTypeParam type, DN_CallSite call_site, DN_FMT_ATTRIB char const *fmt, ...) -{ - DN_LOGEmitFromTypeFVFunc *func = g_dn_base_log_emit_from_type_fv_func_; - void *user_context = g_dn_base_log_emit_from_type_fv_user_context_; - if (func) { - va_list args; - va_start(args, fmt); - func(type, user_context, call_site, fmt, args); - va_end(args); - } -} - -DN_API DN_LOGTypeParam DN_LOG_MakeU32LogTypeParam(DN_LOGType type) -{ - DN_LOGTypeParam result = {}; - result.is_u32_enum = true; - result.u32 = type; - return result; -} -// DN: Single header generator inlined this file => #include "Base/dn_base_leak.cpp" -#define DN_BASE_LEAK_CPP - -// DN: Single header generator commented out this header => #include "../dn_base_inc.h" - -DN_API void DN_LeakTrackAlloc_(DN_LeakTracker *leak, void *ptr, DN_USize size, bool leak_permitted) -{ - if (!ptr) - return; - - DN_TicketMutex_Begin(&leak->alloc_table_mutex); - DN_DEFER - { - DN_TicketMutex_End(&leak->alloc_table_mutex); - }; - - // NOTE: If the entry was not added, we are reusing a pointer that has been freed. - // TODO: Add API for always making the item but exposing a var to indicate if the item was newly created or it - // already existed. - DN_Str8 stack_trace = DN_StackTraceWalkStr8FromHeap(128, 3 /*skip*/); - DN_DSMap *alloc_table = &leak->alloc_table; - DN_DSMapResult alloc_entry = DN_DSMap_MakeKeyU64(alloc_table, DN_Cast(DN_U64) ptr); - DN_LeakAlloc *alloc = alloc_entry.value; - if (alloc_entry.found) { - if ((alloc->flags & DN_LeakAllocFlag_Freed) == 0) { - DN_Str8x32 alloc_size = DN_ByteCountStr8x32(alloc->size); - DN_Str8x32 new_alloc_size = DN_ByteCountStr8x32(size); - DN_HardAssertF( - alloc->flags & DN_LeakAllocFlag_Freed, - "This pointer is already in the leak tracker, however it has not been freed yet. This " - "same pointer is being ask to be tracked twice in the allocation table, e.g. one if its " - "previous free calls has not being marked freed with an equivalent call to " - "DN_LeakTrackDealloc()\n" - "\n" - "The pointer (0x%p) originally allocated %.*s at:\n" - "\n" - "%.*s\n" - "\n" - "The pointer is allocating %.*s again at:\n" - "\n" - "%.*s\n", - ptr, - DN_Str8PrintFmt(alloc_size), - DN_Str8PrintFmt(alloc->stack_trace), - DN_Str8PrintFmt(new_alloc_size), - DN_Str8PrintFmt(stack_trace)); - } - - // NOTE: Pointer was reused, clean up the prior entry - leak->alloc_table_bytes_allocated_for_stack_traces -= alloc->stack_trace.size; - leak->alloc_table_bytes_allocated_for_stack_traces -= alloc->freed_stack_trace.size; - - DN_OS_MemDealloc(alloc->stack_trace.data); - DN_OS_MemDealloc(alloc->freed_stack_trace.data); - *alloc = {}; - } - - alloc->ptr = ptr; - alloc->size = size; - alloc->stack_trace = stack_trace; - alloc->flags |= leak_permitted ? DN_LeakAllocFlag_LeakPermitted : 0; - leak->alloc_table_bytes_allocated_for_stack_traces += alloc->stack_trace.size; -} - -DN_API void DN_LeakTrackDealloc_(DN_LeakTracker *leak, void *ptr) -{ - if (!ptr) - return; - - DN_TicketMutex_Begin(&leak->alloc_table_mutex); - DN_DEFER - { - DN_TicketMutex_End(&leak->alloc_table_mutex); - }; - - DN_Str8 stack_trace = DN_StackTraceWalkStr8FromHeap(128, 3 /*skip*/); - DN_DSMap *alloc_table = &leak->alloc_table; - DN_DSMapResult alloc_entry = DN_DSMap_FindKeyU64(alloc_table, DN_Cast(uintptr_t) ptr); - DN_HardAssertF(alloc_entry.found, - "Allocated pointer can not be removed as it does not exist in the " - "allocation table. When this memory was allocated, the pointer was " - "not added to the allocation table [ptr=%p]", - ptr); - - DN_LeakAlloc *alloc = alloc_entry.value; - if (alloc->flags & DN_LeakAllocFlag_Freed) { - DN_Str8x32 freed_size = DN_ByteCountStr8x32(alloc->freed_size); - DN_HardAssertF((alloc->flags & DN_LeakAllocFlag_Freed) == 0, - "Double free detected, pointer to free was already marked " - "as freed. Either the pointer was reallocated but not " - "traced, or, the pointer was freed twice.\n" - "\n" - "The pointer (0x%p) originally allocated %.*s at:\n" - "\n" - "%.*s\n" - "\n" - "The pointer was freed at:\n" - "\n" - "%.*s\n" - "\n" - "The pointer is being freed again at:\n" - "\n" - "%.*s\n", - ptr, - DN_Str8PrintFmt(freed_size), - DN_Str8PrintFmt(alloc->stack_trace), - DN_Str8PrintFmt(alloc->freed_stack_trace), - DN_Str8PrintFmt(stack_trace)); - } - - DN_Assert(alloc->freed_stack_trace.size == 0); - alloc->flags |= DN_LeakAllocFlag_Freed; - alloc->freed_stack_trace = stack_trace; - leak->alloc_table_bytes_allocated_for_stack_traces += alloc->freed_stack_trace.size; -} - -DN_API void DN_LeakDump_(DN_LeakTracker *leak) -{ - DN_U64 leak_count = 0; - DN_U64 leaked_bytes = 0; - for (DN_USize index = 1; index < leak->alloc_table.occupied; index++) { - DN_DSMapSlot *slot = leak->alloc_table.slots + index; - DN_LeakAlloc *alloc = &slot->value; - bool alloc_leaked = (alloc->flags & DN_LeakAllocFlag_Freed) == 0; - bool leak_permitted = (alloc->flags & DN_LeakAllocFlag_LeakPermitted); - if (alloc_leaked && !leak_permitted) { - leaked_bytes += alloc->size; - leak_count++; - DN_Str8x32 alloc_size = DN_ByteCountStr8x32(alloc->size); - DN_LOG_WarningF( - "Pointer (0x%p) leaked %.*s at:\n" - "%.*s", - alloc->ptr, - DN_Str8PrintFmt(alloc_size), - DN_Str8PrintFmt(alloc->stack_trace)); - } - } - - if (leak_count) { - DN_Str8x32 leak_size = DN_ByteCountStr8x32(leaked_bytes); - DN_LOG_WarningF("There were %I64u leaked allocations totalling %.*s", leak_count, DN_Str8PrintFmt(leak_size)); - } -} -#define DN_OS_INC_CPP - -// DN: Single header generator inlined this file => #include "OS/dn_os_tls.cpp" -#define DN_OS_TLSCPP - -#if defined(_CLANGD) - // DN: Single header generator commented out this header => #include "dn_os_tls.h" -#if !defined(DN_OS_TLS_H) -#define DN_OS_TLS_H - -#if defined(_CLANGD) - // DN: Single header generator commented out this header => #include "../dn_base_inc.h" - // DN: Single header generator commented out this header => #include "../dn_os_inc.h" -#endif - -// NOTE: DN_OSErrSink -enum DN_OSErrSinkMode -{ - DN_OSErrSinkMode_Nil, // Default behaviour to accumulate errors into the sink - DN_OSErrSinkMode_DebugBreakOnEndAndLog, // Debug break (int3) when error is encountered and the sink is ended by the 'end and log' functions. - DN_OSErrSinkMode_ExitOnError, // When an error is encountered, exit the program with the error code of the error that was caught. -}; - -struct DN_OSErrSinkMsg -{ - DN_I32 error_code; - DN_Str8 msg; - DN_CallSite call_site; - DN_OSErrSinkMsg *next; - DN_OSErrSinkMsg *prev; -}; - -struct DN_OSErrSinkNode -{ - DN_CallSite call_site; // Call site that the node was created - DN_OSErrSinkMode mode; // Controls how the sink behaves when an error is registered onto the sink. - DN_OSErrSinkMsg *msg_sentinel; // List of error messages accumulated for the current scope - DN_U64 arena_pos; // Position to reset the arena when the scope is ended -}; - -struct DN_OSErrSink -{ - DN_Arena * arena; // Dedicated allocator from the thread's local storage - DN_OSErrSinkNode stack[128]; // Each entry contains errors accumulated between a [begin, end] region of the active sink. - DN_USize stack_size; -}; - -enum DN_OSTLSArena -{ - DN_OSTLSArena_Main, // NOTE: Arena for permanent allocations - DN_OSTLSArena_ErrorSink, // NOTE: Arena for logging error information for this thread - - // NOTE: Per-thread scratch arenas (2 to prevent aliasing) - DN_OSTLSArena_TMem0, - DN_OSTLSArena_TMem1, - - DN_OSTLSArena_Count, -}; - -struct DN_OSTLS -{ - DN_B32 init; // Flag to track if TLS has been initialised - DN_U64 thread_id; - DN_CallSite call_site; // Stores call-site information when requested by thread - DN_OSErrSink err_sink; // Error handling state - DN_Arena arenas[DN_OSTLSArena_Count]; // Default arenas that the thread has access to implicitly - DN_Arena * arena_stack[8]; // Active stack of arenas push/popped arenas on into the TLS - DN_USize arena_stack_index; - - DN_Arena * frame_arena; - char name[64]; - DN_U8 name_size; -}; - -// Push the temporary memory arena when retrieved, popped when the arena goes -// out of scope. Pushed arenas are used automatically as the allocator in TLS -// suffixed function. -enum DN_OSTLSPushTMem -{ - DN_OSTLSPushTMem_No, - DN_OSTLSPushTMem_Yes, -}; - -struct DN_OSTLSTMem -{ - DN_OSTLSTMem(DN_OSTLS *context, uint8_t context_index, DN_OSTLSPushTMem push_scratch); - ~DN_OSTLSTMem(); - DN_Arena *arena; - DN_B32 destructed; - DN_OSTLSPushTMem push_arena; - DN_ArenaTempMem temp_mem; -}; - -struct DN_OSTLSInitArgs -{ - DN_U64 reserve; - DN_U64 commit; - DN_U64 err_sink_reserve; - DN_U64 err_sink_commit; -}; - -DN_API void DN_OS_TLSInit (DN_OSTLS *tls, DN_OSTLSInitArgs args); -DN_API void DN_OS_TLSDeinit (DN_OSTLS *tls); -DN_API DN_OSTLS * DN_OS_TLSGet (); -DN_API void DN_OS_TLSSetCurrentThreadTLS (DN_OSTLS *tls); -DN_API DN_Arena * DN_OS_TLSArena (); -DN_API DN_OSTLSTMem DN_OS_TLSGetTMem (void const *conflict_arena, DN_OSTLSPushTMem push_tmp_mem); -DN_API void DN_OS_TLSPushArena (DN_Arena *arena); -DN_API void DN_OS_TLSPopArena (); -DN_API DN_Arena * DN_OS_TLSTopArena (); -DN_API void DN_OS_TLSBeginFrame (DN_Arena *frame_arena); -DN_API DN_Arena * DN_OS_TLSFrameArena (); -#define DN_OS_TLSSaveCallSite do { DN_OS_TLSGet()->call_site = DN_CALL_SITE; } while (0) -#define DN_OS_TLSTMem(...) DN_OS_TLSGetTMem(__VA_ARGS__, DN_OSTLSPushTMem_No) -#define DN_OS_TLSPushTMem(...) DN_OS_TLSGetTMem(__VA_ARGS__, DN_OSTLSPushTMem_Yes) - -DN_API DN_OSErrSink * DN_OS_ErrSinkBegin_ (DN_OSErrSinkMode mode, DN_CallSite call_site); -#define DN_OS_ErrSinkBegin(mode) DN_OS_ErrSinkBegin_(mode, DN_CALL_SITE) -#define DN_OS_ErrSinkBeginDefault() DN_OS_ErrSinkBegin(DN_OSErrSinkMode_Nil) -DN_API bool DN_OS_ErrSinkHasError (DN_OSErrSink *err); -DN_API DN_OSErrSinkMsg * DN_OS_ErrSinkEnd (DN_Arena *arena, DN_OSErrSink *err); -DN_API DN_Str8 DN_OS_ErrSinkEndStr8 (DN_Arena *arena, DN_OSErrSink *err); -DN_API void DN_OS_ErrSinkEndAndIgnore (DN_OSErrSink *err); -DN_API bool DN_OS_ErrSinkEndAndLogError_ (DN_OSErrSink *err, DN_CallSite call_site, DN_Str8 msg); -DN_API bool DN_OS_ErrSinkEndAndLogErrorFV_ (DN_OSErrSink *err, DN_CallSite call_site, DN_FMT_ATTRIB char const *fmt, va_list args); -DN_API bool DN_OS_ErrSinkEndAndLogErrorF_ (DN_OSErrSink *err, DN_CallSite call_site, DN_FMT_ATTRIB char const *fmt, ...); -DN_API void DN_OS_ErrSinkEndAndExitIfErrorF_ (DN_OSErrSink *err, DN_CallSite call_site, DN_U32 exit_val, DN_FMT_ATTRIB char const *fmt, ...); -DN_API void DN_OS_ErrSinkEndAndExitIfErrorFV_ (DN_OSErrSink *err, DN_CallSite call_site, DN_U32 exit_val, DN_FMT_ATTRIB char const *fmt, va_list args); -DN_API void DN_OS_ErrSinkAppendFV_ (DN_OSErrSink *err, DN_U32 error_code, DN_FMT_ATTRIB char const *fmt, va_list args); -DN_API void DN_OS_ErrSinkAppendF_ (DN_OSErrSink *err, DN_U32 error_code, DN_FMT_ATTRIB char const *fmt, ...); -#define DN_OS_ErrSinkEndAndLogError(err, err_msg) DN_OS_ErrSinkEndAndLogError_(err, DN_CALL_SITE, err_msg) -#define DN_OS_ErrSinkEndAndLogErrorFV(err, fmt, args) DN_OS_ErrSinkEndAndLogErrorFV_(err, DN_CALL_SITE, fmt, args) -#define DN_OS_ErrSinkEndAndLogErrorF(err, fmt, ...) DN_OS_ErrSinkEndAndLogErrorF_(err, DN_CALL_SITE, fmt, ##__VA_ARGS__) -#define DN_OS_ErrSinkEndAndExitIfErrorFV(err, exit_val, fmt, args) DN_OS_ErrSinkEndAndExitIfErrorFV_(err, DN_CALL_SITE, exit_val, fmt, args) -#define DN_OS_ErrSinkEndAndExitIfErrorF(err, exit_val, fmt, ...) DN_OS_ErrSinkEndAndExitIfErrorF_(err, DN_CALL_SITE, exit_val, fmt, ##__VA_ARGS__) - -#define DN_OS_ErrSinkAppendFV(error, error_code, fmt, args) \ - do { \ - DN_OS_TLSSaveCallSite; \ - DN_OS_ErrSinkAppendFV_(error, error_code, fmt, args); \ - } while (0) - -#define DN_OS_ErrSinkAppendF(error, error_code, fmt, ...) \ - do { \ - DN_OS_TLSSaveCallSite; \ - DN_OS_ErrSinkAppendF_(error, error_code, fmt, ##__VA_ARGS__); \ - } while (0) - -#endif // defined(DN_OS_TLS_H) -#endif - -// NOTE: DN_OSTLS //////////////////////////////////////////////////////////////////////////////////// -DN_OSTLSTMem::DN_OSTLSTMem(DN_OSTLS *tls, DN_U8 arena_index, DN_OSTLSPushTMem push_tmem) -{ - DN_Assert(arena_index == DN_OSTLSArena_TMem0 || arena_index == DN_OSTLSArena_TMem1); - arena = tls->arenas + arena_index; - temp_mem = DN_ArenaTempMemBegin(arena); - destructed = false; - push_arena = push_tmem; - if (push_arena) - DN_OS_TLSPushArena(arena); -} - -DN_OSTLSTMem::~DN_OSTLSTMem() -{ - DN_Assert(destructed == false); - DN_ArenaTempMemEnd(temp_mem); - destructed = true; - if (push_arena) - DN_OS_TLSPopArena(); -} - -DN_API void DN_OS_TLSInit(DN_OSTLS *tls, DN_OSTLSInitArgs args) -{ - DN_Check(tls); - if (tls->init) - return; - - DN_U64 reserve = args.reserve ? args.reserve : DN_Kilobytes(64); - DN_U64 err_sink_reserve = args.err_sink_reserve ? args.err_sink_reserve : DN_Kilobytes(64); - - #if !defined(DN_PLATFORM_EMSCRIPTEN) - DN_U64 commit = args.commit ? args.commit : DN_Kilobytes(4); - DN_U64 err_sink_commit = args.err_sink_commit ? args.err_sink_commit : DN_Kilobytes(4); - #endif - - // TODO: We shouldn't have the no alloc track flag here but the initial TLS - // init on OS init happens before CORE init. CORE init is the one responsible - // for setting up the alloc tracking data structures. - for (DN_ForItCArray(it, DN_Arena, tls->arenas)) { - DN_Arena *arena = it.data; - switch (DN_Cast(DN_OSTLSArena) it.index) { - default: { - #if defined(DN_PLATFORM_EMSCRIPTEN) - *arena = DN_ArenaFromHeap(reserve, DN_ArenaFlags_AllocCanLeak | DN_ArenaFlags_NoAllocTrack); - #else - *arena = DN_ArenaFromVMem(reserve, commit, DN_ArenaFlags_AllocCanLeak | DN_ArenaFlags_NoAllocTrack); - #endif - } break; - - case DN_OSTLSArena_ErrorSink: { - #if defined(DN_PLATFORM_EMSCRIPTEN) - *arena = DN_ArenaFromHeap(err_sink_reserve, DN_ArenaFlags_AllocCanLeak | DN_ArenaFlags_NoAllocTrack); - #else - *arena = DN_ArenaFromVMem(err_sink_reserve, err_sink_commit, DN_ArenaFlags_AllocCanLeak | DN_ArenaFlags_NoAllocTrack); - #endif - } break; - - case DN_OSTLSArena_Count: DN_InvalidCodePath; break; - } - } - - tls->thread_id = DN_OS_ThreadID(); - tls->err_sink.arena = tls->arenas + DN_OSTLSArena_ErrorSink; - tls->init = true; -} - -DN_API void DN_OS_TLSDeinit(DN_OSTLS *tls) -{ - tls->init = false; - tls->err_sink = {}; - tls->arena_stack_index = {}; - for (DN_ForItCArray(it, DN_Arena, tls->arenas)) - DN_ArenaDeinit(it.data); -} - -DN_THREAD_LOCAL DN_OSTLS *g_dn_curr_thread_tls; -DN_API void DN_OS_TLSSetCurrentThreadTLS(DN_OSTLS *tls) -{ - g_dn_curr_thread_tls = tls; -} - -DN_API DN_OSTLS *DN_OS_TLSGet() -{ - DN_RawAssert(g_dn_curr_thread_tls && - "DN must be initialised (via DN_Core_Init) before calling any functions depending on " - "TLS if this is the main thread, OR, the created thread has not called " - "SetCurrentThreadTLS yet so the TLS data structure hasn't been assigned yet"); - return g_dn_curr_thread_tls; -} - -DN_API DN_Arena *DN_OS_TLSArena() -{ - DN_OSTLS *tls = DN_OS_TLSGet(); - DN_Arena *result = tls->arenas + DN_OSTLSArena_Main; - return result; -} - -// TODO: Is there a way to handle conflict arenas without the user needing to -// manually pass it in? -DN_API DN_OSTLSTMem DN_OS_TLSGetTMem(void const *conflict_arena, DN_OSTLSPushTMem push_tmem) -{ - DN_OSTLS *tls = DN_OS_TLSGet(); - DN_U8 tls_index = (DN_U8)-1; - for (DN_U8 index = DN_OSTLSArena_TMem0; index <= DN_OSTLSArena_TMem1; index++) { - DN_Arena *arena = tls->arenas + index; - if (!conflict_arena || arena != conflict_arena) { - tls_index = index; - break; - } - } - - DN_Assert(tls_index != (DN_U8)-1); - return DN_OSTLSTMem(tls, tls_index, push_tmem); -} - -DN_API void DN_OS_TLSPushArena(DN_Arena *arena) -{ - DN_Assert(arena); - DN_OSTLS *tls = DN_OS_TLSGet(); - DN_Assert(tls->arena_stack_index < DN_ArrayCountU(tls->arena_stack)); - tls->arena_stack[tls->arena_stack_index++] = arena; -} - -DN_API void DN_OS_TLSPopArena() -{ - DN_OSTLS *tls = DN_OS_TLSGet(); - DN_Assert(tls->arena_stack_index > 0); - tls->arena_stack_index--; -} - -DN_API DN_Arena *DN_OS_TLSTopArena() -{ - DN_OSTLS *tls = DN_OS_TLSGet(); - DN_Arena *result = nullptr; - if (tls->arena_stack_index) - result = tls->arena_stack[tls->arena_stack_index - 1]; - return result; -} - -DN_API void DN_OS_TLSBeginFrame(DN_Arena *frame_arena) -{ - DN_OSTLS *tls = DN_OS_TLSGet(); - tls->frame_arena = frame_arena; -} - -DN_API DN_Arena *DN_OS_TLSFrameArena() -{ - DN_OSTLS *tls = DN_OS_TLSGet(); - DN_Arena *result = tls->frame_arena; - DN_AssertF(result, "Frame arena must be set by calling DN_OS_TLSBeginFrame at the beginning of the frame"); - return result; -} - -// NOTE: DN_OSErrSink //////////////////////////////////////////////////////////////////////////////// -static void DN_OS_ErrSinkCheck_(DN_OSErrSink const *err) -{ - DN_AssertF(err->arena, "Arena should be assigned in TLS init"); - if (err->stack_size == 0) - return; - - DN_OSErrSinkNode const *node = err->stack + (err->stack_size - 1); - DN_Assert(node->mode >= DN_OSErrSinkMode_Nil && node->mode <= DN_OSErrSinkMode_ExitOnError); - DN_Assert(node->msg_sentinel); - - // NOTE: Walk the list ensuring we eventually terminate at the sentinel (e.g. we have a - // well formed doubly-linked-list terminated by a sentinel, or otherwise we will hit the - // walk limit or dereference a null pointer and assert) - size_t WALK_LIMIT = 99'999; - size_t walk = 0; - for (DN_OSErrSinkMsg *it = node->msg_sentinel->next; it != node->msg_sentinel; it = it->next, walk++) { - DN_AssertF(it, "Encountered null pointer which should not happen in a sentinel DLL"); - DN_Assert(walk < WALK_LIMIT); - } -} - -DN_API DN_OSErrSink *DN_OS_ErrSinkBegin_(DN_OSErrSinkMode mode, DN_CallSite call_site) -{ - DN_OSTLS *tls = DN_OS_TLSGet(); - DN_OSErrSink *err = &tls->err_sink; - DN_OSErrSink *result = err; - DN_USize arena_pos = DN_ArenaPos(result->arena); - - if (tls->err_sink.stack_size == DN_ArrayCountU(err->stack)) { - DN_Str8Builder builder = DN_Str8BuilderFromTLS(); - DN_USize counter = 0; - for (DN_ForItSize(it, DN_OSErrSinkNode, err->stack, err->stack_size)) { - DN_MSVC_WARNING_PUSH - DN_MSVC_WARNING_DISABLE(6284) // Object passed as _Param_(4) when a string is required in call to 'DN_Str8BuilderAppendF' Actual type: 'struct DN_Str8'. - DN_Str8BuilderAppendF(&builder, " [%04zu] %S:%u %S\n", counter++, it.data->call_site.file, it.data->call_site.line, it.data->call_site.function); - DN_MSVC_WARNING_POP - } - - DN_MSVC_WARNING_PUSH - DN_MSVC_WARNING_DISABLE(6284) // Object passed as _Param_(6) when a string is required in call to 'DN_LOG_EmitFromType' Actual type: 'struct DN_Str8'. - DN_AssertF(tls->err_sink.stack_size < DN_ArrayCountU(err->stack), - "Error sink has run out of error scopes, potential leak. Scopes were\n%S", DN_Str8BuilderBuildFromTLS(&builder)); - DN_MSVC_WARNING_POP - } - - DN_OSErrSinkNode *node = tls->err_sink.stack + tls->err_sink.stack_size++; - node->arena_pos = arena_pos; - node->mode = mode; - node->call_site = call_site; - DN_DLList_InitArena(node->msg_sentinel, DN_OSErrSinkMsg, result->arena); - - // NOTE: Handle allocation error - if (!DN_Check(node && node->msg_sentinel)) { - DN_ArenaPopTo(result->arena, arena_pos); - node->msg_sentinel = nullptr; - tls->err_sink.stack_size--; - } - - return result; -} - -DN_API bool DN_OS_ErrSinkHasError(DN_OSErrSink *err) -{ - bool result = false; - if (err && err->stack_size) { - DN_OSErrSinkNode *node = err->stack + (err->stack_size - 1); - result = DN_DLList_HasItems(node->msg_sentinel); - } - return result; -} - -DN_API DN_OSErrSinkMsg *DN_OS_ErrSinkEnd(DN_Arena *arena, DN_OSErrSink *err) -{ - DN_OSErrSinkMsg *result = nullptr; - DN_OS_ErrSinkCheck_(err); - if (!err || err->stack_size == 0) - return result; - - DN_AssertF(arena != err->arena, - "You are not allowed to reuse the arena for ending the error sink because the memory would get popped and lost"); - // NOTE: Walk the list and allocate it onto the user's arena - DN_OSErrSinkNode *node = err->stack + (err->stack_size - 1); - DN_OSErrSinkMsg *prev = nullptr; - for (DN_OSErrSinkMsg *it = node->msg_sentinel->next; it != node->msg_sentinel; it = it->next) { - DN_OSErrSinkMsg *entry = DN_ArenaNew(arena, DN_OSErrSinkMsg, DN_ZMem_Yes); - entry->msg = DN_Str8FromStr8Arena(arena, it->msg); - entry->call_site = it->call_site; - entry->error_code = it->error_code; - if (!result) - result = entry; // Assign first entry if we haven't yet - if (prev) - prev->next = entry; // Link the prev message to the current one - prev = entry; // Update prev to latest - } - - // NOTE: Deallocate all the memory for this scope - err->stack_size--; - DN_ArenaPopTo(err->arena, node->arena_pos); - return result; -} - -static void DN_OS_ErrSinkAddMsgToStr8Builder(DN_Str8Builder *builder, DN_OSErrSinkMsg *msg, DN_OSErrSinkMsg *end) -{ - if (msg == end) // NOTE: No error messages to add - return; - - if (msg->next == end) { - DN_OSErrSinkMsg *it = msg; - DN_Str8 file_name = DN_Str8FileNameFromPath(it->call_site.file); - DN_Str8BuilderAppendF(builder, - "%.*s:%05I32u:%.*s %.*s", - DN_Str8PrintFmt(file_name), - it->call_site.line, - DN_Str8PrintFmt(it->call_site.function), - DN_Str8PrintFmt(it->msg)); - } else { - // NOTE: More than one message - for (DN_OSErrSinkMsg *it = msg; it != end; it = it->next) { - DN_Str8 file_name = DN_Str8FileNameFromPath(it->call_site.file); - DN_Str8BuilderAppendF(builder, - "%s - %.*s:%05I32u:%.*s%s%.*s", - it == msg ? "" : "\n", - DN_Str8PrintFmt(file_name), - it->call_site.line, - DN_Str8PrintFmt(it->call_site.function), - it->msg.size ? " " : "", - DN_Str8PrintFmt(it->msg)); - } - } -} - -DN_API DN_Str8 DN_OS_ErrSinkEndStr8(DN_Arena *arena, DN_OSErrSink *err) -{ - DN_Str8 result = {}; - DN_OS_ErrSinkCheck_(err); - if (!err || err->stack_size == 0) - return result; - - DN_AssertF(arena != err->arena, - "You are not allowed to reuse the arena for ending the error sink because the memory would get popped and lost"); - - // NOTE: Walk the list and allocate it onto the user's arena - DN_OSTLSTMem tmem = DN_OS_TLSPushTMem(arena); - DN_Str8Builder builder = DN_Str8BuilderFromTLS(); - DN_OSErrSinkNode *node = err->stack + (err->stack_size - 1); - DN_OS_ErrSinkAddMsgToStr8Builder(&builder, node->msg_sentinel->next, node->msg_sentinel); - - // NOTE: Deallocate all the memory for this scope - err->stack_size--; - DN_U64 arena_pos = node->arena_pos; - DN_ArenaPopTo(err->arena, arena_pos); - - result = DN_Str8BuilderBuild(&builder, arena); - return result; -} - -DN_API void DN_OS_ErrSinkEndAndIgnore(DN_OSErrSink *err) -{ - DN_OS_ErrSinkEnd(nullptr, err); -} - -DN_API bool DN_OS_ErrSinkEndAndLogError_(DN_OSErrSink *err, DN_CallSite call_site, DN_Str8 err_msg) -{ - DN_AssertF(err->stack_size, "Begin must be called before calling end"); - DN_OSErrSinkNode *node = err->stack + (err->stack_size - 1); - DN_AssertF(node->msg_sentinel, "Begin must be called before calling end"); - - DN_OSTLSTMem tmem = DN_OS_TLSPushTMem(nullptr); - DN_OSErrSinkMode mode = node->mode; - DN_OSErrSinkMsg *msg = DN_OS_ErrSinkEnd(tmem.arena, err); - if (!msg) - return false; - - DN_Str8Builder builder = DN_Str8BuilderFromTLS(); - if (err_msg.size) { - DN_Str8BuilderAppendRef(&builder, err_msg); - DN_Str8BuilderAppendRef(&builder, DN_Str8Lit(":")); - } else { - DN_Str8BuilderAppendRef(&builder, DN_Str8Lit("Error(s) encountered:")); - } - - if (msg->next) // NOTE: More than 1 message - DN_Str8BuilderAppendRef(&builder, DN_Str8Lit("\n")); - DN_OS_ErrSinkAddMsgToStr8Builder(&builder, msg, nullptr); - - DN_Str8 log = DN_Str8BuilderBuildFromTLS(&builder); - DN_LOG_EmitFromType(DN_LOG_MakeU32LogTypeParam(DN_LOGType_Error), call_site, "%.*s", DN_Str8PrintFmt(log)); - - if (mode == DN_OSErrSinkMode_DebugBreakOnEndAndLog) - DN_DebugBreak; - return true; -} - -DN_API bool DN_OS_ErrSinkEndAndLogErrorFV_(DN_OSErrSink *err, DN_CallSite call_site, DN_FMT_ATTRIB char const *fmt, va_list args) -{ - DN_OSTLSTMem tmem = DN_OS_TLSTMem(nullptr); - DN_Str8 log = DN_Str8FromFmtVArena(tmem.arena, fmt, args); - bool result = DN_OS_ErrSinkEndAndLogError_(err, call_site, log); - return result; -} - -DN_API bool DN_OS_ErrSinkEndAndLogErrorF_(DN_OSErrSink *err, DN_CallSite call_site, DN_FMT_ATTRIB char const *fmt, ...) -{ - va_list args; - va_start(args, fmt); - DN_OSTLSTMem tmem = DN_OS_TLSTMem(nullptr); - DN_Str8 log = DN_Str8FromFmtVArena(tmem.arena, fmt, args); - bool result = DN_OS_ErrSinkEndAndLogError_(err, call_site, log); - va_end(args); - return result; -} - -DN_API void DN_OS_ErrSinkEndAndExitIfErrorFV_(DN_OSErrSink *err, DN_CallSite call_site, DN_U32 exit_val, DN_FMT_ATTRIB char const *fmt, va_list args) -{ - if (DN_OS_ErrSinkEndAndLogErrorFV_(err, call_site, fmt, args)) { - DN_DebugBreak; - DN_OS_Exit(exit_val); - } -} - -DN_API void DN_OS_ErrSinkEndAndExitIfErrorF_(DN_OSErrSink *err, DN_CallSite call_site, DN_U32 exit_val, DN_FMT_ATTRIB char const *fmt, ...) -{ - va_list args; - va_start(args, fmt); - DN_OS_ErrSinkEndAndExitIfErrorFV_(err, call_site, exit_val, fmt, args); - va_end(args); -} - -DN_API void DN_OS_ErrSinkAppendFV_(DN_OSErrSink *err, DN_U32 error_code, DN_FMT_ATTRIB char const *fmt, va_list args) -{ - if (!err) - return; - DN_Assert(err && err->stack_size); - DN_OSErrSinkNode *node = err->stack + (err->stack_size - 1); - DN_AssertF(node, "Error sink must be begun by calling 'Begin' before using this function."); - - DN_OSErrSinkMsg *msg = DN_ArenaNew(err->arena, DN_OSErrSinkMsg, DN_ZMem_Yes); - if (DN_Check(msg)) { - msg->msg = DN_Str8FromFmtVArena(err->arena, fmt, args); - msg->error_code = error_code; - msg->call_site = DN_OS_TLSGet()->call_site; - DN_DLList_Prepend(node->msg_sentinel, msg); - - if (node->mode == DN_OSErrSinkMode_ExitOnError) - DN_OS_ErrSinkEndAndExitIfErrorF_(err, msg->call_site, error_code, "Fatal error %u", error_code); - } -} - -DN_API void DN_OS_ErrSinkAppendF_(DN_OSErrSink *err, DN_U32 error_code, DN_FMT_ATTRIB char const *fmt, ...) -{ - if (!err) - return; - va_list args; - va_start(args, fmt); - DN_OS_ErrSinkAppendFV_(err, error_code, fmt, args); - va_end(args); -} - -// DN: Single header generator inlined this file => #include "OS/dn_os.cpp" -#define DN_OS_CPP - -#if defined(_CLANGD) - // DN: Single header generator commented out this header => #include "../dn_base_inc.h" - // DN: Single header generator commented out this header => #include "../dn_os_inc.h" -#endif - -#if defined(DN_PLATFORM_POSIX) -#include // get_nprocs -#include // getpagesize -#endif - -static void DN_OS_LOGEmitFromTypeTypeFV_(DN_LOGTypeParam type, void *user_data, DN_CallSite call_site, DN_FMT_ATTRIB char const *fmt, va_list args) -{ - DN_Assert(user_data); - DN_OSCore *core = DN_Cast(DN_OSCore *)user_data; - - // NOTE: Open log file for appending if requested //////////////////////////////////////////////// - DN_TicketMutex_Begin(&core->log_file_mutex); - if (core->log_to_file && !core->log_file.handle && !core->log_file.error) { - DN_OSTLSTMem tmem = DN_OS_TLSTMem(nullptr); - DN_MSVC_WARNING_PUSH - DN_MSVC_WARNING_DISABLE(6284) // Object passed as _Param_(3) when a string is required in call to 'DN_OS_PathF' Actual type: 'struct DN_Str8'. - DN_Str8 log_path = DN_OS_PathF(tmem.arena, "%S/dn.log", DN_OS_EXEDir(tmem.arena)); - DN_MSVC_WARNING_POP - core->log_file = DN_OS_FileOpen(log_path, DN_OSFileOpen_CreateAlways, DN_OSFileAccess_AppendOnly, nullptr); - } - DN_TicketMutex_End(&core->log_file_mutex); - - DN_LOGStyle style = {}; - if (!core->log_no_colour) { - style.colour = true; - style.bold = DN_LOGBold_Yes; - if (type.is_u32_enum) { - switch (type.u32) { - case DN_LOGType_Debug: { - style.colour = false; - style.bold = DN_LOGBold_No; - } break; - - case DN_LOGType_Info: { - style.g = 0x87; - style.b = 0xff; - } break; - - case DN_LOGType_Warning: { - style.r = 0xff; - style.g = 0xff; - } break; - - case DN_LOGType_Error: { - style.r = 0xff; - } break; - } - } - } - - DN_Date os_date = DN_OS_DateLocalTimeNow(); - DN_LOGDate log_date = {}; - log_date.year = os_date.year; - log_date.month = os_date.month; - log_date.day = os_date.day; - log_date.hour = os_date.hour; - log_date.minute = os_date.minutes; - log_date.second = os_date.seconds; - - char prefix_buffer[128] = {}; - DN_LOGPrefixSize prefix_size = DN_LOG_MakePrefix(style, type, call_site, log_date, prefix_buffer, sizeof(prefix_buffer)); - - va_list args_copy; - va_copy(args_copy, args); - DN_TicketMutex_Begin(&core->log_file_mutex); - { - DN_OS_FileWrite(&core->log_file, DN_Str8FromPtr(prefix_buffer, prefix_size.size), nullptr); - DN_OS_FileWriteF(&core->log_file, nullptr, "%*s ", DN_Cast(int)prefix_size.padding, ""); - DN_OS_FileWriteFV(&core->log_file, nullptr, fmt, args_copy); - DN_OS_FileWrite(&core->log_file, DN_Str8Lit("\n"), nullptr); - } - DN_TicketMutex_End(&core->log_file_mutex); - va_end(args_copy); - - DN_OSPrintDest dest = (type.is_u32_enum && type.u32 == DN_LOGType_Error) ? DN_OSPrintDest_Err : DN_OSPrintDest_Out; - DN_OS_Print(dest, DN_Str8FromPtr(prefix_buffer, prefix_size.size)); - DN_OS_PrintF(dest, "%*s ", DN_Cast(int)prefix_size.padding, ""); - DN_OS_PrintLnFV(dest, fmt, args); -} - -DN_API void DN_OS_EmitLogsWithOSPrintFunctions(DN_OSCore *os) -{ - DN_Assert(os); - DN_LOG_SetEmitFromTypeFVFunc(DN_OS_LOGEmitFromTypeTypeFV_, os); -} - -DN_API void DN_OS_DumpThreadContextArenaStat(DN_Str8 file_path) -{ -#if defined(DN_DEBUG_THREAD_CONTEXT) - // NOTE: Open a file to write the arena stats to - FILE *file = nullptr; - fopen_s(&file, file_path.data, "a+b"); - if (file) { - DN_LOG_ErrorF("Failed to dump thread context arenas [file=%.*s]", DN_Str8PrintFmt(file_path)); - return; - } - - // NOTE: Copy the stats from library book-keeping - // NOTE: Extremely short critical section, copy the stats then do our - // work on it. - DN_ArenaStat stats[DN_CArray_CountI(g_dn_core->thread_context_arena_stats)]; - int stats_size = 0; - - DN_TicketMutex_Begin(&g_dn_core->thread_context_mutex); - stats_size = g_dn_core->thread_context_arena_stats_count; - DN_Memcpy(stats, g_dn_core->thread_context_arena_stats, sizeof(stats[0]) * stats_size); - DN_TicketMutex_End(&g_dn_core->thread_context_mutex); - - // NOTE: Print the cumulative stat - DN_DateHMSTimeStr now = DN_Date_HMSLocalTimeStrNow(); - fprintf(file, - "Time=%.*s %.*s | Thread Context Arenas | Count=%d\n", - now.date_size, - now.date, - now.hms_size, - now.hms, - g_dn_core->thread_context_arena_stats_count); - - // NOTE: Write the cumulative thread arena data - { - DN_ArenaStat stat = {}; - for (DN_USize index = 0; index < stats_size; index++) { - DN_ArenaStat const *current = stats + index; - stat.capacity += current->capacity; - stat.used += current->used; - stat.wasted += current->wasted; - stat.blocks += current->blocks; - - stat.capacity_hwm = DN_Max(stat.capacity_hwm, current->capacity_hwm); - stat.used_hwm = DN_Max(stat.used_hwm, current->used_hwm); - stat.wasted_hwm = DN_Max(stat.wasted_hwm, current->wasted_hwm); - stat.blocks_hwm = DN_Max(stat.blocks_hwm, current->blocks_hwm); - } - - DN_ArenaStatStr stats_string = DN_ArenaStatStr(&stat); - fprintf(file, " [ALL] CURR %.*s\n", stats_string.size, stats_string.data); - } - - // NOTE: Print individual thread arena data - for (DN_USize index = 0; index < stats_size; index++) { - DN_ArenaStat const *current = stats + index; - DN_ArenaStatStr current_string = DN_ArenaStatStr(current); - fprintf(file, " [%03d] CURR %.*s\n", DN_Cast(int) index, current_string.size, current_string.data); - } - - fclose(file); - DN_LOG_InfoF("Dumped thread context arenas [file=%.*s]", DN_Str8PrintFmt(file_path)); -#else - (void)file_path; -#endif // #if defined(DN_DEBUG_THREAD_CONTEXT) -} - -DN_API DN_Str8 DN_OS_BytesFromHexPtrArenaFrame(void const *hex, DN_USize hex_count) -{ - DN_Arena *frame_arena = DN_OS_TLSFrameArena(); - DN_Str8 result = DN_BytesFromHexPtrArena(hex, hex_count, frame_arena); - return result; -} - -DN_API DN_Str8 DN_OS_BytesFromHexStr8ArenaFrame(DN_Str8 hex) -{ - DN_Str8 result = DN_OS_BytesFromHexPtrArenaFrame(hex.data, hex.size); - return result; -} - -DN_API DN_Str8 DN_OS_HexFromBytesPtrArenaFrame(void const *bytes, DN_USize bytes_count) -{ - DN_Arena *frame_arena = DN_OS_TLSFrameArena(); - DN_Str8 result = DN_HexFromBytesPtrArena(bytes, bytes_count, frame_arena); - return result; -} - -DN_API DN_Str8 DN_OS_HexFromBytesPtrArenaTLS(void const *bytes, DN_USize bytes_count) -{ - DN_Arena *tls_arena = DN_OS_TLSArena(); - DN_Str8 result = DN_HexFromBytesPtrArena(bytes, bytes_count, tls_arena); - return result; -} - -// NOTE: Date -DN_API DN_Str8x32 DN_OS_DateLocalTimeStr8(DN_Date time, char date_separator, char hms_separator) -{ - DN_Str8x32 result = DN_Str8x32FromFmt("%hu%c%02hhu%c%02hhu %02hhu%c%02hhu%c%02hhu", - time.year, - date_separator, - time.month, - date_separator, - time.day, - time.hour, - hms_separator, - time.minutes, - hms_separator, - time.seconds); - return result; -} - -DN_API DN_Str8x32 DN_OS_DateLocalTimeStr8Now(char date_separator, char hms_separator) -{ - DN_Date time = DN_OS_DateLocalTimeNow(); - DN_Str8x32 result = DN_OS_DateLocalTimeStr8(time, date_separator, hms_separator); - return result; -} - -// NOTE: Other -DN_API DN_Str8 DN_OS_EXEDir(DN_Arena *arena) -{ - DN_Str8 result = {}; - if (!arena) - return result; - DN_OSTLSTMem tmem = DN_OS_TLSTMem(arena); - DN_Str8 exe_path = DN_OS_EXEPath(tmem.arena); - DN_Str8 separators[] = {DN_Str8Lit("/"), DN_Str8Lit("\\")}; - DN_Str8BSplitResult split = DN_Str8BSplitLastArray(exe_path, separators, DN_ArrayCountU(separators)); - result = DN_Str8FromStr8Arena(arena, split.lhs); - return result; -} - -// NOTE: Counters -DN_API DN_F64 DN_OS_PerfCounterS(uint64_t begin, uint64_t end) -{ - uint64_t frequency = DN_OS_PerfCounterFrequency(); - uint64_t ticks = end - begin; - DN_F64 result = ticks / DN_Cast(DN_F64) frequency; - return result; -} - -DN_API DN_F64 DN_OS_PerfCounterMs(uint64_t begin, uint64_t end) -{ - uint64_t frequency = DN_OS_PerfCounterFrequency(); - uint64_t ticks = end - begin; - DN_F64 result = (ticks * 1'000) / DN_Cast(DN_F64) frequency; - return result; -} - -DN_API DN_F64 DN_OS_PerfCounterUs(uint64_t begin, uint64_t end) -{ - uint64_t frequency = DN_OS_PerfCounterFrequency(); - uint64_t ticks = end - begin; - DN_F64 result = (ticks * 1'000'000) / DN_Cast(DN_F64) frequency; - return result; -} - -DN_API DN_F64 DN_OS_PerfCounterNs(uint64_t begin, uint64_t end) -{ - uint64_t frequency = DN_OS_PerfCounterFrequency(); - uint64_t ticks = end - begin; - DN_F64 result = (ticks * 1'000'000'000) / DN_Cast(DN_F64) frequency; - return result; -} - -DN_API DN_OSTimer DN_OS_TimerBegin() -{ - DN_OSTimer result = {}; - result.start = DN_OS_PerfCounterNow(); - return result; -} - -DN_API void DN_OS_TimerEnd(DN_OSTimer *timer) -{ - timer->end = DN_OS_PerfCounterNow(); -} - -DN_API DN_F64 DN_OS_TimerS(DN_OSTimer timer) -{ - DN_F64 result = DN_OS_PerfCounterS(timer.start, timer.end); - return result; -} - -DN_API DN_F64 DN_OS_TimerMs(DN_OSTimer timer) -{ - DN_F64 result = DN_OS_PerfCounterMs(timer.start, timer.end); - return result; -} - -DN_API DN_F64 DN_OS_TimerUs(DN_OSTimer timer) -{ - DN_F64 result = DN_OS_PerfCounterUs(timer.start, timer.end); - return result; -} - -DN_API DN_F64 DN_OS_TimerNs(DN_OSTimer timer) -{ - DN_F64 result = DN_OS_PerfCounterNs(timer.start, timer.end); - return result; -} - -DN_API uint64_t DN_OS_EstimateTSCPerSecond(uint64_t 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; - if (tsc_begin) { - uint64_t 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; - } - return result; -} - -DN_API bool DN_OS_PathIsOlderThan(DN_Str8 path, DN_Str8 check_against) -{ - DN_OSPathInfo file_info = DN_OS_PathInfo(path); - DN_OSPathInfo check_against_info = DN_OS_PathInfo(check_against); - bool result = !file_info.exists || file_info.last_write_time_in_s < check_against_info.last_write_time_in_s; - return result; -} - -DN_API bool DN_OS_FileWrite(DN_OSFile *file, DN_Str8 buffer, DN_OSErrSink *error) -{ - bool result = DN_OS_FileWritePtr(file, buffer.data, buffer.size, error); - return result; -} - -struct DN_OSFileWriteChunker_ -{ - DN_OSErrSink *err; - DN_OSFile *file; - bool success; -}; - -static char *DN_OS_FileWriteChunker_(const char *buf, void *user, int len) -{ - DN_OSFileWriteChunker_ *chunker = DN_Cast(DN_OSFileWriteChunker_ *)user; - chunker->success = DN_OS_FileWritePtr(chunker->file, buf, len, chunker->err); - char *result = chunker->success ? DN_Cast(char *) buf : nullptr; - return result; -} - -DN_API bool DN_OS_FileWriteFV(DN_OSFile *file, DN_OSErrSink *error, DN_FMT_ATTRIB char const *fmt, va_list args) -{ - bool result = false; - if (!file || !fmt) - return result; - - DN_OSFileWriteChunker_ chunker = {}; - chunker.err = error; - chunker.file = file; - char buffer[STB_SPRINTF_MIN]; - STB_SPRINTF_DECORATE(vsprintfcb)(DN_OS_FileWriteChunker_, &chunker, buffer, fmt, args); - - result = chunker.success; - return result; -} - -DN_API bool DN_OS_FileWriteF(DN_OSFile *file, DN_OSErrSink *error, DN_FMT_ATTRIB char const *fmt, ...) -{ - va_list args; - va_start(args, fmt); - bool result = DN_OS_FileWriteFV(file, error, fmt, args); - va_end(args); - return result; -} - -DN_API DN_Str8 DN_OS_FileReadAll(DN_Allocator alloc_type, void *allocator, DN_Str8 path, DN_OSErrSink *err) -{ - // NOTE: Query file size - DN_Str8 result = {}; - DN_OSPathInfo path_info = DN_OS_PathInfo(path); - if (!path_info.exists) { - DN_OS_ErrSinkAppendF(err, 1, "File does not exist/could not be queried for reading '%.*s'", DN_Str8PrintFmt(path)); - return result; - } - - // NOTE: Allocate - DN_ArenaTempMem arena_tmp = {}; - if (alloc_type == DN_Allocator_Arena) { - DN_Arena *arena = DN_Cast(DN_Arena *) allocator; - arena_tmp = DN_ArenaTempMemBegin(arena); - result = DN_Str8FromArena(arena, path_info.size, DN_ZMem_No); - } else { - DN_Pool *pool = DN_Cast(DN_Pool *) allocator; - result = DN_Str8FromPool(pool, path_info.size); - } - - if (!result.data) { - DN_Str8x32 bytes_str = DN_ByteCountStr8x32(path_info.size); - DN_OS_ErrSinkAppendF(err, 1 /*err_code*/, "Failed to allocate %.*s for reading file '%.*s'", DN_Str8PrintFmt(bytes_str), DN_Str8PrintFmt(path)); - return result; - } - - // NOTE: Read all - DN_OSFile file = DN_OS_FileOpen(path, DN_OSFileOpen_OpenIfExist, DN_OSFileAccess_Read, err); - DN_OSFileRead read = DN_OS_FileRead(&file, result.data, result.size, err); - if (file.error || !read.success) { - if (alloc_type == DN_Allocator_Arena) { - DN_ArenaTempMemEnd(arena_tmp); - } else { - DN_Pool *pool = DN_Cast(DN_Pool *) allocator; - DN_PoolDealloc(pool, result.data); - } - result = {}; - } - - DN_OS_FileClose(&file); - return result; -} - -DN_API DN_Str8 DN_OS_FileReadAllArena(DN_Arena *arena, DN_Str8 path, DN_OSErrSink *err) -{ - DN_Str8 result = DN_OS_FileReadAll(DN_Allocator_Arena, arena, path, err); - return result; -} - -DN_API DN_Str8 DN_OS_FileReadAllPool(DN_Pool *pool, DN_Str8 path, DN_OSErrSink *err) -{ - DN_Str8 result = DN_OS_FileReadAll(DN_Allocator_Pool, pool, path, err); - return result; -} - -DN_API DN_Str8 DN_OS_FileReadAllTLS(DN_Str8 path, DN_OSErrSink *err) -{ - DN_Str8 result = DN_OS_FileReadAll(DN_Allocator_Arena, DN_OS_TLSArena(), path, err); - return result; -} - -DN_API bool DN_OS_FileWriteAll(DN_Str8 path, DN_Str8 buffer, DN_OSErrSink *error) -{ - DN_OSFile file = DN_OS_FileOpen(path, DN_OSFileOpen_CreateAlways, DN_OSFileAccess_Write, error); - bool result = DN_OS_FileWrite(&file, buffer, error); - DN_OS_FileClose(&file); - return result; -} - -DN_API bool DN_OS_FileWriteAllFV(DN_Str8 file_path, DN_OSErrSink *error, DN_FMT_ATTRIB char const *fmt, va_list args) -{ - DN_OSTLSTMem tmem = DN_OS_TLSTMem(nullptr); - DN_Str8 buffer = DN_Str8FromFmtVArena(tmem.arena, fmt, args); - bool result = DN_OS_FileWriteAll(file_path, buffer, error); - return result; -} - -DN_API bool DN_OS_FileWriteAllF(DN_Str8 file_path, DN_OSErrSink *error, DN_FMT_ATTRIB char const *fmt, ...) -{ - va_list args; - va_start(args, fmt); - bool result = DN_OS_FileWriteAllFV(file_path, error, fmt, args); - va_end(args); - return result; -} - -DN_API bool DN_OS_FileWriteAllSafe(DN_Str8 path, DN_Str8 buffer, DN_OSErrSink *error) -{ - DN_OSTLSTMem tmem = DN_OS_TLSTMem(nullptr); - DN_Str8 tmp_path = DN_Str8FromFmtArena(tmem.arena, "%.*s.tmp", DN_Str8PrintFmt(path)); - if (!DN_OS_FileWriteAll(tmp_path, buffer, error)) - return false; - if (!DN_OS_FileCopy(tmp_path, path, true /*overwrite*/, error)) - return false; - if (!DN_OS_PathDelete(tmp_path)) - return false; - return true; -} - -DN_API bool DN_OS_FileWriteAllSafeFV(DN_Str8 path, DN_OSErrSink *error, DN_FMT_ATTRIB char const *fmt, va_list args) -{ - DN_OSTLSTMem tmem = DN_OS_TLSTMem(nullptr); - DN_Str8 buffer = DN_Str8FromFmtVArena(tmem.arena, fmt, args); - bool result = DN_OS_FileWriteAllSafe(path, buffer, error); - return result; -} - -DN_API bool DN_OS_FileWriteAllSafeF(DN_Str8 path, DN_OSErrSink *error, DN_FMT_ATTRIB char const *fmt, ...) -{ - va_list args; - va_start(args, fmt); - bool result = DN_OS_FileWriteAllSafeFV(path, error, fmt, args); - return result; -} - -DN_API bool DN_OS_PathAddRef(DN_Arena *arena, DN_OSPath *fs_path, DN_Str8 path) -{ - if (!arena || !fs_path || path.size == 0) - return false; - - if (path.size <= 0) - return true; - - DN_Str8 const delimiter_array[] = { - DN_Str8Lit("\\"), - DN_Str8Lit("/")}; - - if (fs_path->links_size == 0) - fs_path->has_prefix_path_separator = (path.data[0] == '/'); - - for (;;) { - DN_Str8BSplitResult delimiter = DN_Str8BSplitArray(path, delimiter_array, DN_ArrayCountU(delimiter_array)); - for (; delimiter.lhs.data; delimiter = DN_Str8BSplitArray(delimiter.rhs, delimiter_array, DN_ArrayCountU(delimiter_array))) { - if (delimiter.lhs.size <= 0) - continue; - - DN_OSPathLink *link = DN_ArenaNew(arena, DN_OSPathLink, DN_ZMem_Yes); - if (!link) - return false; - - link->string = delimiter.lhs; - link->prev = fs_path->tail; - if (fs_path->tail) - fs_path->tail->next = link; - else - fs_path->head = link; - fs_path->tail = link; - fs_path->links_size += 1; - fs_path->string_size += delimiter.lhs.size; - } - - if (!delimiter.lhs.data) - break; - } - - return true; -} - -DN_API bool DN_OS_PathAddRefTLS(DN_OSPath *fs_path, DN_Str8 path) -{ - bool result = DN_OS_PathAddRef(DN_OS_TLSTopArena(), fs_path, path); - return result; -} - -DN_API bool DN_OS_PathAddRefFrame(DN_OSPath *fs_path, DN_Str8 path) -{ - bool result = DN_OS_PathAddRef(DN_OS_TLSFrameArena(), fs_path, path); - return result; -} - -DN_API bool DN_OS_PathAdd(DN_Arena *arena, DN_OSPath *fs_path, DN_Str8 path) -{ - DN_Str8 copy = DN_Str8FromStr8Arena(arena, path); - bool result = copy.size ? true : DN_OS_PathAddRef(arena, fs_path, copy); - return result; -} - -DN_API bool DN_OS_PathAddF(DN_Arena *arena, DN_OSPath *fs_path, DN_FMT_ATTRIB char const *fmt, ...) -{ - va_list args; - va_start(args, fmt); - DN_Str8 path = DN_Str8FromFmtVArena(arena, fmt, args); - va_end(args); - bool result = DN_OS_PathAddRef(arena, fs_path, path); - return result; -} - -DN_API bool DN_OS_PathPop(DN_OSPath *fs_path) -{ - if (!fs_path) - return false; - - if (fs_path->tail) { - DN_Assert(fs_path->head); - fs_path->links_size -= 1; - fs_path->string_size -= fs_path->tail->string.size; - fs_path->tail = fs_path->tail->prev; - if (fs_path->tail) - fs_path->tail->next = nullptr; - else - fs_path->head = nullptr; - } else { - DN_Assert(!fs_path->head); - } - - return true; -} - -DN_API DN_Str8 DN_OS_PathTo(DN_Arena *arena, DN_Str8 path, DN_Str8 path_separator) -{ - DN_OSPath fs_path = {}; - DN_OS_PathAddRef(arena, &fs_path, path); - DN_Str8 result = DN_OS_PathBuildWithSeparator(arena, &fs_path, path_separator); - return result; -} - -DN_API DN_Str8 DN_OS_PathToF(DN_Arena *arena, DN_Str8 path_separator, DN_FMT_ATTRIB char const *fmt, ...) -{ - DN_OSTLSTMem tmem = DN_OS_TLSTMem(arena); - va_list args; - va_start(args, fmt); - DN_Str8 path = DN_Str8FromFmtVArena(tmem.arena, fmt, args); - va_end(args); - DN_Str8 result = DN_OS_PathTo(arena, path, path_separator); - return result; -} - -DN_API DN_Str8 DN_OS_Path(DN_Arena *arena, DN_Str8 path) -{ - DN_Str8 result = DN_OS_PathTo(arena, path, DN_OSPathSeperatorString); - return result; -} - -DN_API DN_Str8 DN_OS_PathF(DN_Arena *arena, DN_FMT_ATTRIB char const *fmt, ...) -{ - DN_OSTLSTMem tmem = DN_OS_TLSTMem(arena); - va_list args; - va_start(args, fmt); - DN_Str8 path = DN_Str8FromFmtVArena(tmem.arena, fmt, args); - va_end(args); - DN_Str8 result = DN_OS_Path(arena, path); - return result; -} - -DN_API DN_Str8 DN_OS_PathBuildWithSeparator(DN_Arena *arena, DN_OSPath const *fs_path, DN_Str8 path_separator) -{ - DN_Str8 result = {}; - if (!fs_path || fs_path->links_size <= 0) - return result; - - // NOTE: Each link except the last one needs the path separator appended to it, '/' or '\\' - DN_USize string_size = (fs_path->has_prefix_path_separator ? path_separator.size : 0) + fs_path->string_size + ((fs_path->links_size - 1) * path_separator.size); - result = DN_Str8FromArena(arena, string_size, DN_ZMem_No); - if (result.data) { - char *dest = result.data; - if (fs_path->has_prefix_path_separator) { - DN_Memcpy(dest, path_separator.data, path_separator.size); - dest += path_separator.size; - } - - for (DN_OSPathLink *link = fs_path->head; link; link = link->next) { - DN_Str8 string = link->string; - DN_Memcpy(dest, string.data, string.size); - dest += string.size; - - if (link != fs_path->tail) { - DN_Memcpy(dest, path_separator.data, path_separator.size); - dest += path_separator.size; - } - } - } - - result.data[string_size] = 0; - return result; -} - -// NOTE: DN_OSExec ///////////////////////////////////////////////////////////////////////////////// -DN_API DN_OSExecResult DN_OS_Exec(DN_Slice cmd_line, - DN_OSExecArgs *args, - DN_Arena *arena, - DN_OSErrSink *error) -{ - DN_OSExecAsyncHandle async_handle = DN_OS_ExecAsync(cmd_line, args, error); - DN_OSExecResult result = DN_OS_ExecWait(async_handle, arena, error); - return result; -} - -DN_API DN_OSExecResult DN_OS_ExecOrAbort(DN_Slice cmd_line, DN_OSExecArgs *args, DN_Arena *arena) -{ - DN_OSErrSink *error = DN_OS_ErrSinkBegin(DN_OSErrSinkMode_Nil); - DN_OSExecResult result = DN_OS_Exec(cmd_line, args, arena, error); - if (result.os_error_code) - DN_OS_ErrSinkEndAndExitIfErrorF(error, result.os_error_code, "OS failed to execute the requested command returning the error code %u", result.os_error_code); - - if (result.exit_code) - DN_OS_ErrSinkEndAndExitIfErrorF(error, result.exit_code, "OS executed command and returned non-zero exit code %u", result.exit_code); - DN_OS_ErrSinkEndAndIgnore(error); - return result; -} - -// NOTE: DN_OSThread /////////////////////////////////////////////////////////////////////////////// -static void DN_OS_ThreadExecute_(void *user_context) -{ - DN_OSThread *thread = DN_Cast(DN_OSThread *) user_context; - DN_OS_TLSInit(&thread->tls, thread->tls_init_args); - DN_OS_TLSSetCurrentThreadTLS(&thread->tls); - DN_OS_SemaphoreWait(&thread->init_semaphore, DN_OS_SEMAPHORE_INFINITE_TIMEOUT); - thread->func(thread); -} - -DN_API void DN_OS_ThreadSetName(DN_Str8 name) -{ - DN_OSTLS *tls = DN_OS_TLSGet(); - tls->name_size = DN_Cast(uint8_t) DN_Min(name.size, sizeof(tls->name) - 1); - DN_Memcpy(tls->name, name.data, tls->name_size); - tls->name[tls->name_size] = 0; - -#if defined(DN_PLATFORM_WIN32) - DN_W32_ThreadSetName(name); -#else - DN_Posix_ThreadSetName(name); -#endif -} - -// NOTE: DN_OSHttp ///////////////////////////////////////////////////////////////////////////////// -DN_API void DN_OS_HttpRequestWait(DN_OSHttpResponse *response) -{ - if (response && response->on_complete_semaphore.handle != 0) - DN_OS_SemaphoreWait(&response->on_complete_semaphore, DN_OS_SEMAPHORE_INFINITE_TIMEOUT); -} - -DN_API DN_OSHttpResponse DN_OS_HttpRequest(DN_Arena *arena, DN_Str8 host, DN_Str8 path, DN_OSHttpRequestSecure secure, DN_Str8 method, DN_Str8 body, DN_Str8 headers) -{ - // TODO(doyle): Revise the memory allocation and its lifetime - DN_OSHttpResponse result = {}; - DN_OSTLSTMem tmem = DN_OS_TLSTMem(arena); - result.tmem_arena = tmem.arena; - - DN_OS_HttpRequestAsync(&result, arena, host, path, secure, method, body, headers); - DN_OS_HttpRequestWait(&result); - return result; -} -// DN: Single header generator inlined this file => #include "OS/dn_os_allocator.cpp" -#define DN_OS_ALLOCATOR_CPP - -#if defined(_CLANGD) - // DN: Single header generator commented out this header => #include "../dn_base_inc.h" - // DN: Single header generator commented out this header => #include "../dn_os_inc.h" - // DN: Single header generator commented out this header => #include "../dn_inc.h" -#endif - -static void *DN_ArenaBasicAllocFromOSHeap(DN_USize size) -{ - void *result = DN_OS_MemAlloc(size, DN_ZMem_Yes); - return result; -} - -DN_API DN_Arena DN_ArenaFromHeap(DN_U64 size, DN_ArenaFlags flags) -{ - DN_ArenaMemFuncs mem_funcs = {}; - mem_funcs.type = DN_ArenaMemFuncType_Basic; - mem_funcs.basic_alloc = DN_ArenaBasicAllocFromOSHeap; - mem_funcs.basic_dealloc = DN_OS_MemDealloc; - DN_Arena result = DN_ArenaFromMemFuncs(size, size, flags, mem_funcs); - return result; -} - -DN_API DN_Arena DN_ArenaFromVMem(DN_U64 reserve, DN_U64 commit, DN_ArenaFlags flags) -{ - DN_ArenaMemFuncs mem_funcs = {}; - mem_funcs.type = DN_ArenaMemFuncType_VMem; - mem_funcs.vmem_page_size = g_dn_->os.page_size; - mem_funcs.vmem_reserve = DN_OS_MemReserve; - mem_funcs.vmem_commit = DN_OS_MemCommit; - mem_funcs.vmem_release = DN_OS_MemRelease; - DN_Arena result = DN_ArenaFromMemFuncs(reserve, commit, flags, mem_funcs); - return result; -} - -// DN: Single header generator inlined this file => #include "OS/dn_os_containers.cpp" -#define DN_OS_CONTAINERS_CPP - -// DN: Single header generator commented out this header => #include "dn_os_containers.h" -#if !defined(DN_OS_CONTAINERS_H) -#define DN_OS_CONTAINERS_H - -#if defined(_CLANGD) - // DN: Single header generator commented out this header => #include "../dn_base_inc.h" -#endif - -// NOTE: DN_VArray -// TODO(doyle): Add an API for shrinking the array by decomitting pages back to the OS. -template struct DN_VArray -{ - T *data; // Pointer to the start of the array items in the block of memory - DN_USize size; // Number of items currently in the array - DN_USize max; // Maximum number of items this array can store - DN_USize commit; // Bytes committed - - T *begin() { return data; } - T *end () { return data + size; } - T const *begin() const { return data; } - T const *end () const { return data + size; } -}; - -template DN_VArray DN_VArray_InitByteSize (DN_USize byte_size); -template DN_VArray DN_VArray_Init (DN_USize max); -template DN_VArray DN_VArray_InitSlice (DN_Slice slice, DN_USize max); -template DN_VArray DN_VArray_InitCArray (T const (&items)[N], DN_USize max); -template void DN_VArray_Deinit (DN_VArray *array); -template bool DN_VArray_IsValid (DN_VArray const *array); -template DN_Slice DN_VArray_Slice (DN_VArray const *array); -template bool DN_VArray_Reserve (DN_VArray *array, DN_USize count); -template T * DN_VArray_AddArray (DN_VArray *array, T const *items, DN_USize count); -template T * DN_VArray_AddCArray (DN_VArray *array, T const (&items)[N]); -template T * DN_VArray_Add (DN_VArray *array, T const &item); -#define DN_VArray_AddArrayAssert(...) DN_HardAssert(DN_VArray_AddArray(__VA_ARGS__)) -#define DN_VArray_AddCArrayAssert(...) DN_HardAssert(DN_VArray_AddCArray(__VA_ARGS__)) -#define DN_VArray_AddAssert(...) DN_HardAssert(DN_VArray_Add(__VA_ARGS__)) -template T * DN_VArray_MakeArray (DN_VArray *array, DN_USize count, DN_ZMem z_mem); -template T * DN_VArray_Make (DN_VArray *array, DN_ZMem z_mem); -#define DN_VArray_MakeArrayAssert(...) DN_HardAssert(DN_VArray_MakeArray(__VA_ARGS__)) -#define DN_VArray_MakeAssert(...) DN_HardAssert(DN_VArray_Make(__VA_ARGS__)) -template T * DN_VArray_InsertArray (DN_VArray *array, DN_USize index, T const *items, DN_USize count); -template T * DN_VArray_InsertCArray (DN_VArray *array, DN_USize index, T const (&items)[N]); -template T * DN_VArray_Insert (DN_VArray *array, DN_USize index, T const &item); -#define DN_VArray_InsertArrayAssert(...) DN_HardAssert(DN_VArray_InsertArray(__VA_ARGS__)) -#define DN_VArray_InsertCArrayAssert(...) DN_HardAssert(DN_VArray_InsertCArray(__VA_ARGS__)) -#define DN_VArray_InsertAssert(...) DN_HardAssert(DN_VArray_Insert(__VA_ARGS__)) -template T DN_VArray_PopFront (DN_VArray *array, DN_USize count); -template T DN_VArray_PopBack (DN_VArray *array, DN_USize count); -template DN_ArrayEraseResult DN_VArray_EraseRange (DN_VArray *array, DN_USize begin_index, DN_ISize count, DN_ArrayErase erase); -template void DN_VArray_Clear (DN_VArray *array, DN_ZMem z_mem); -#endif // !defined(DN_OS_CONTAINERS_H) - -/* -//////////////////////////////////////////////////////////////////////////////////////////////////// -// -// $$$$$$\ $$$$$$\ $$\ $$\ $$$$$$$$\ $$$$$$\ $$$$$$\ $$\ $$\ $$$$$$$$\ $$$$$$$\ $$$$$$\ -// $$ __$$\ $$ __$$\ $$$\ $$ |\__$$ __|$$ __$$\ \_$$ _|$$$\ $$ |$$ _____|$$ __$$\ $$ __$$\ -// $$ / \__|$$ / $$ |$$$$\ $$ | $$ | $$ / $$ | $$ | $$$$\ $$ |$$ | $$ | $$ |$$ / \__| -// $$ | $$ | $$ |$$ $$\$$ | $$ | $$$$$$$$ | $$ | $$ $$\$$ |$$$$$\ $$$$$$$ |\$$$$$$\ -// $$ | $$ | $$ |$$ \$$$$ | $$ | $$ __$$ | $$ | $$ \$$$$ |$$ __| $$ __$$< \____$$\ -// $$ | $$\ $$ | $$ |$$ |\$$$ | $$ | $$ | $$ | $$ | $$ |\$$$ |$$ | $$ | $$ |$$\ $$ | -// \$$$$$$ | $$$$$$ |$$ | \$$ | $$ | $$ | $$ |$$$$$$\ $$ | \$$ |$$$$$$$$\ $$ | $$ |\$$$$$$ | -// \______/ \______/ \__| \__| \__| \__| \__|\______|\__| \__|\________|\__| \__| \______/ -// -// dn_containers.cpp -// -//////////////////////////////////////////////////////////////////////////////////////////////////// -*/ - -// NOTE: DN_VArray ///////////////////////////////////////////////////////////////////////////////// -template -DN_VArray DN_VArray_InitByteSize(DN_USize byte_size) -{ - DN_VArray result = {}; - result.data = DN_Cast(T *) DN_OS_MemReserve(byte_size, DN_MemCommit_No, DN_MemPage_ReadWrite); - if (result.data) - result.max = byte_size / sizeof(T); - return result; -} - -template -DN_VArray DN_VArray_Init(DN_USize max) -{ - DN_VArray result = DN_VArray_InitByteSize(max * sizeof(T)); - DN_Assert(result.max >= max); - return result; -} - -template -DN_VArray DN_VArray_InitSlice(DN_Slice slice, DN_USize max) -{ - DN_USize real_max = DN_Max(slice.size, max); - DN_VArray result = DN_VArray_Init(real_max); - if (DN_VArray_IsValid(&result)) - DN_VArray_AddArray(&result, slice.data, slice.size); - return result; -} - -template -DN_VArray DN_VArray_InitCArray(T const (&items)[N], DN_USize max) -{ - DN_USize real_max = DN_Max(N, max); - DN_VArray result = DN_VArray_InitSlice(DN_Slice_Init(items, N), real_max); - return result; -} - -template -void DN_VArray_Deinit(DN_VArray *array) -{ - DN_OS_MemRelease(array->data, array->max * sizeof(T)); - *array = {}; -} - -template -bool DN_VArray_IsValid(DN_VArray const *array) -{ - bool result = array->data && array->size <= array->max; - return result; -} - -template -DN_Slice DN_VArray_Slice(DN_VArray const *array) -{ - DN_Slice result = {}; - if (array) - result = DN_Slice_Init(array->data, array->size); - return result; -} - -template -T *DN_VArray_AddArray(DN_VArray *array, T const *items, DN_USize count) -{ - T *result = DN_VArray_MakeArray(array, count, DN_ZMem_No); - if (result) - DN_Memcpy(result, items, count * sizeof(T)); - return result; -} - -template -T *DN_VArray_AddCArray(DN_VArray *array, T const (&items)[N]) -{ - T *result = DN_VArray_AddArray(array, items, N); - return result; -} - -template -T *DN_VArray_Add(DN_VArray *array, T const &item) -{ - T *result = DN_VArray_AddArray(array, &item, 1); - return result; -} - -template -T *DN_VArray_MakeArray(DN_VArray *array, DN_USize count, DN_ZMem z_mem) -{ - if (!DN_VArray_IsValid(array)) - return nullptr; - - if (!DN_CheckF((array->size + count) < array->max, "Array is out of space (user requested +%zu items, array has %zu/%zu items)", count, array->size, array->max)) - return nullptr; - - if (!DN_VArray_Reserve(array, count)) - return nullptr; - - // TODO: Use placement new - T *result = array->data + array->size; - array->size += count; - if (z_mem == DN_ZMem_Yes) - DN_Memset(result, 0, count * sizeof(T)); - return result; -} - -template -T *DN_VArray_Make(DN_VArray *array, DN_ZMem z_mem) -{ - T *result = DN_VArray_MakeArray(array, 1, z_mem); - return result; -} - -template -T *DN_VArray_InsertArray(DN_VArray *array, DN_USize index, T const *items, DN_USize count) -{ - T *result = nullptr; - if (!DN_VArray_IsValid(array)) - return result; - if (DN_VArray_Reserve(array, array->size + count)) - result = DN_CArray_InsertArray(array->data, &array->size, array->max, index, items, count); - return result; -} - -template -T *DN_VArray_InsertCArray(DN_VArray *array, DN_USize index, T const (&items)[N]) -{ - T *result = DN_VArray_InsertArray(array, index, items, N); - return result; -} - -template -T *DN_VArray_Insert(DN_VArray *array, DN_USize index, T const &item) -{ - T *result = DN_VArray_InsertArray(array, index, &item, 1); - return result; -} - -template -T *DN_VArray_PopFront(DN_VArray *array, DN_USize count) -{ - T *result = DN_CArray_PopFront(array->data, &array->size, count); - return result; -} - -template -T *DN_VArray_PopBack(DN_VArray *array, DN_USize count) -{ - T *result = DN_CArray_PopBack(array->data, &array->size, count); - return result; -} - -template -DN_ArrayEraseResult DN_VArray_EraseRange(DN_VArray *array, DN_USize begin_index, DN_ISize count, DN_ArrayErase erase) -{ - DN_ArrayEraseResult result = {}; - if (!DN_VArray_IsValid(array)) - return result; - result = DN_CArray_EraseRange(array->data, &array->size, begin_index, count, erase); - return result; -} - -template -void DN_VArray_Clear(DN_VArray *array, DN_ZMem z_mem) -{ - if (array) { - if (z_mem == DN_ZMem_Yes) - DN_Memset(array->data, 0, array->size * sizeof(T)); - array->size = 0; - } -} - -template -bool DN_VArray_Reserve(DN_VArray *array, DN_USize count) -{ - if (!DN_VArray_IsValid(array) || count == 0) - return false; - - DN_USize real_commit = (array->size + count) * sizeof(T); - DN_USize aligned_commit = DN_AlignUpPowerOfTwo(real_commit, g_dn_->os.page_size); - if (array->commit >= aligned_commit) - return true; - bool result = DN_OS_MemCommit(array->data, aligned_commit, DN_MemPage_ReadWrite); - array->commit = aligned_commit; - return result; -} -// DN: Single header generator inlined this file => #include "OS/dn_os_print.cpp" -#define DN_OS_PRINT_CPP - -DN_API DN_LOGStyle DN_OS_PrintStyleColour(uint8_t r, uint8_t g, uint8_t b, DN_LOGBold bold) -{ - DN_LOGStyle result = {}; - result.bold = bold; - result.colour = true; - result.r = r; - result.g = g; - result.b = b; - return result; -} - -DN_API DN_LOGStyle DN_OS_PrintStyleColourU32(uint32_t rgb, DN_LOGBold bold) -{ - uint8_t r = (rgb >> 24) & 0xFF; - uint8_t g = (rgb >> 16) & 0xFF; - uint8_t b = (rgb >> 8) & 0xFF; - DN_LOGStyle result = DN_OS_PrintStyleColour(r, g, b, bold); - return result; -} - -DN_API DN_LOGStyle DN_OS_PrintStyleBold() -{ - DN_LOGStyle result = {}; - result.bold = DN_LOGBold_Yes; - return result; -} - -DN_API void DN_OS_Print(DN_OSPrintDest dest, DN_Str8 string) -{ - DN_Assert(dest == DN_OSPrintDest_Out || dest == DN_OSPrintDest_Err); - -#if defined(DN_PLATFORM_WIN32) - // NOTE: Get the output handles from kernel //////////////////////////////////////////////////// - DN_THREAD_LOCAL void *std_out_print_handle = nullptr; - DN_THREAD_LOCAL void *std_err_print_handle = nullptr; - DN_THREAD_LOCAL bool std_out_print_to_console = false; - DN_THREAD_LOCAL bool std_err_print_to_console = false; - - if (!std_out_print_handle) { - unsigned long mode = 0; - (void)mode; - std_out_print_handle = GetStdHandle(STD_OUTPUT_HANDLE); - std_out_print_to_console = GetConsoleMode(std_out_print_handle, &mode) != 0; - - std_err_print_handle = GetStdHandle(STD_ERROR_HANDLE); - std_err_print_to_console = GetConsoleMode(std_err_print_handle, &mode) != 0; - } - - // NOTE: Select the output handle ////////////////////////////////////////////////////////////// - void *print_handle = std_out_print_handle; - bool print_to_console = std_out_print_to_console; - if (dest == DN_OSPrintDest_Err) { - print_handle = std_err_print_handle; - print_to_console = std_err_print_to_console; - } - - // NOTE: Write the string ////////////////////////////////////////////////////////////////////// - DN_Assert(string.size < DN_Cast(unsigned long) - 1); - unsigned long bytes_written = 0; - (void)bytes_written; - if (print_to_console) - WriteConsoleA(print_handle, string.data, DN_Cast(unsigned long) string.size, &bytes_written, nullptr); - else - WriteFile(print_handle, string.data, DN_Cast(unsigned long) string.size, &bytes_written, nullptr); -#else - fprintf(dest == DN_OSPrintDest_Out ? stdout : stderr, "%.*s", DN_Str8PrintFmt(string)); -#endif -} - -DN_API void DN_OS_PrintF(DN_OSPrintDest dest, DN_FMT_ATTRIB char const *fmt, ...) -{ - va_list args; - va_start(args, fmt); - DN_OS_PrintFV(dest, fmt, args); - va_end(args); -} - -DN_API void DN_OS_PrintFStyle(DN_OSPrintDest dest, DN_LOGStyle style, DN_FMT_ATTRIB char const *fmt, ...) -{ - va_list args; - va_start(args, fmt); - DN_OS_PrintFVStyle(dest, style, fmt, args); - va_end(args); -} - -DN_API void DN_OS_PrintStyle(DN_OSPrintDest dest, DN_LOGStyle style, DN_Str8 string) -{ - if (string.data && string.size) { - if (style.colour) - DN_OS_Print(dest, DN_LOG_ColourEscapeCodeStr8FromRGB(DN_LOGColourType_Fg, style.r, style.g, style.b)); - if (style.bold == DN_LOGBold_Yes) - DN_OS_Print(dest, DN_Str8Lit(DN_LOG_BoldEscapeCode)); - DN_OS_Print(dest, string); - if (style.colour || style.bold == DN_LOGBold_Yes) - DN_OS_Print(dest, DN_Str8Lit(DN_LOG_ResetEscapeCode)); - } -} - -static char *DN_OS_PrintVSPrintfChunker_(const char *buf, void *user, int len) -{ - DN_Str8 string = {}; - string.data = DN_Cast(char *) buf; - string.size = len; - - DN_OSPrintDest dest = DN_Cast(DN_OSPrintDest) DN_Cast(uintptr_t) user; - DN_OS_Print(dest, string); - return (char *)buf; -} - -DN_API void DN_OS_PrintFV(DN_OSPrintDest dest, DN_FMT_ATTRIB char const *fmt, va_list args) -{ - char buffer[STB_SPRINTF_MIN]; - STB_SPRINTF_DECORATE(vsprintfcb) - (DN_OS_PrintVSPrintfChunker_, DN_Cast(void *) DN_Cast(uintptr_t) dest, buffer, fmt, args); -} - -DN_API void DN_OS_PrintFVStyle(DN_OSPrintDest dest, DN_LOGStyle style, DN_FMT_ATTRIB char const *fmt, va_list args) -{ - if (fmt) { - if (style.colour) - DN_OS_Print(dest, DN_LOG_ColourEscapeCodeStr8FromRGB(DN_LOGColourType_Fg, style.r, style.g, style.b)); - if (style.bold == DN_LOGBold_Yes) - DN_OS_Print(dest, DN_Str8Lit(DN_LOG_BoldEscapeCode)); - DN_OS_PrintFV(dest, fmt, args); - if (style.colour || style.bold == DN_LOGBold_Yes) - DN_OS_Print(dest, DN_Str8Lit(DN_LOG_ResetEscapeCode)); - } -} - -DN_API void DN_OS_PrintLn(DN_OSPrintDest dest, DN_Str8 string) -{ - DN_OS_Print(dest, string); - DN_OS_Print(dest, DN_Str8Lit("\n")); -} - -DN_API void DN_OS_PrintLnF(DN_OSPrintDest dest, DN_FMT_ATTRIB char const *fmt, ...) -{ - va_list args; - va_start(args, fmt); - DN_OS_PrintLnFV(dest, fmt, args); - va_end(args); -} - -DN_API void DN_OS_PrintLnFV(DN_OSPrintDest dest, DN_FMT_ATTRIB char const *fmt, va_list args) -{ - DN_OS_PrintFV(dest, fmt, args); - DN_OS_Print(dest, DN_Str8Lit("\n")); -} - -DN_API void DN_OS_PrintLnStyle(DN_OSPrintDest dest, DN_LOGStyle style, DN_Str8 string) -{ - DN_OS_PrintStyle(dest, style, string); - DN_OS_Print(dest, DN_Str8Lit("\n")); -} - -DN_API void DN_OS_PrintLnFStyle(DN_OSPrintDest dest, DN_LOGStyle style, DN_FMT_ATTRIB char const *fmt, ...) -{ - va_list args; - va_start(args, fmt); - DN_OS_PrintLnFVStyle(dest, style, fmt, args); - va_end(args); -} - -DN_API void DN_OS_PrintLnFVStyle(DN_OSPrintDest dest, DN_LOGStyle style, DN_FMT_ATTRIB char const *fmt, va_list args) -{ - DN_OS_PrintFVStyle(dest, style, fmt, args); - DN_OS_Print(dest, DN_Str8Lit("\n")); -} -// DN: Single header generator inlined this file => #include "OS/dn_os_string.cpp" -#define DN_OS_STRING_CPP - -#if defined(_CLANGD) - // DN: Single header generator commented out this header => #include "../dn_base_inc.h" - // DN: Single header generator commented out this header => #include "../dn_os_inc.h" -#endif - -// NOTE: DN_Str8 -DN_API DN_Str8 DN_Str8FromFmtArenaFrame(DN_FMT_ATTRIB char const *fmt, ...) -{ - va_list args; - va_start(args, fmt); - DN_Arena *frame_arena = DN_OS_TLSGet()->frame_arena; - DN_Str8 result = DN_Str8FromFmtVArena(frame_arena, fmt, args); - va_end(args); - return result; -} - -DN_API DN_Str8 DN_Str8FromFmtVArenaFrame(DN_FMT_ATTRIB char const *fmt, va_list args) -{ - DN_Arena *frame_arena = DN_OS_TLSGet()->frame_arena; - DN_Str8 result = DN_Str8FromFmtVArena(frame_arena, fmt, args); - return result; -} - -DN_API DN_Str8 DN_Str8FromArenaFrame(DN_USize size, DN_ZMem z_mem) -{ - DN_Arena *frame_arena = DN_OS_TLSGet()->frame_arena; - DN_Str8 result = DN_Str8FromArena(frame_arena, size, z_mem); - return result; -} - -DN_API DN_Str8 DN_Str8FromHeapF(DN_FMT_ATTRIB char const *fmt, ...) -{ - va_list args; - va_start(args, fmt); - DN_USize size = DN_FmtVSize(fmt, args); - DN_Str8 result = DN_Str8FromHeap(size, DN_ZMem_No); - DN_VSNPrintF(result.data, DN_Cast(int)(result.size + 1), fmt, args); - va_end(args); - return result; -} - -DN_API DN_Str8 DN_Str8FromHeap(DN_USize size, DN_ZMem z_mem) -{ - DN_Str8 result = {}; - result.data = DN_Cast(char *)DN_OS_MemAlloc(size + 1, z_mem); - if (result.data) { - result.size = size; - result.data[result.size] = 0; - } - return result; -} - -DN_API DN_Str8 DN_Str8FromTLSFV(DN_FMT_ATTRIB char const *fmt, va_list args) -{ - DN_Str8 result = DN_Str8FromFmtVArena(DN_OS_TLSTopArena(), fmt, args); - return result; -} - - -DN_API DN_Str8 DN_Str8FromTLSF(DN_FMT_ATTRIB char const *fmt, ...) -{ - va_list args; - va_start(args, fmt); - DN_Str8 result = DN_Str8FromFmtVArena(DN_OS_TLSTopArena(), fmt, args); - va_end(args); - return result; -} - -DN_API DN_Str8 DN_Str8FromTLS(DN_USize size, DN_ZMem z_mem) -{ - DN_Str8 result = DN_Str8FromArena(DN_OS_TLSTopArena(), size, z_mem); - return result; -} - -DN_API DN_Str8 DN_Str8FromStr8Frame(DN_Str8 string) -{ - DN_Str8 result = DN_Str8FromStr8Arena(DN_OS_TLSGet()->frame_arena, string); - return result; -} - -DN_API DN_Str8 DN_Str8FromStr8TLS(DN_Str8 string) -{ - DN_Str8 result = DN_Str8FromStr8Arena(DN_OS_TLSTopArena(), string); - return result; -} - -DN_API DN_Str8SplitResult DN_Str8SplitFromFrame(DN_Str8 string, DN_Str8 delimiter, DN_Str8SplitIncludeEmptyStrings mode) -{ - DN_Str8SplitResult result = DN_Str8SplitArena(DN_OS_TLSGet()->frame_arena, string, delimiter, mode); - return result; -} - -DN_API DN_Str8SplitResult DN_Str8SplitFromTLS(DN_Str8 string, DN_Str8 delimiter, DN_Str8SplitIncludeEmptyStrings mode) -{ - DN_Str8SplitResult result = DN_Str8SplitArena(DN_OS_TLSTopArena(), string, delimiter, mode); - return result; -} - -DN_API DN_Str8 DN_Str8SegmentFromFrame(DN_Str8 src, DN_USize segment_size, char segment_char) -{ - DN_Str8 result = DN_Str8Segment(DN_OS_TLSGet()->frame_arena, src, segment_size, segment_char); - return result; -} - -DN_API DN_Str8 DN_Str8SegmentFromTLS(DN_Str8 src, DN_USize segment_size, char segment_char) -{ - DN_Str8 result = DN_Str8Segment(DN_OS_TLSTopArena(), src, segment_size, segment_char); - return result; -} - -DN_API DN_Str8 DN_Str8ReverseSegmentFromFrame(DN_Str8 src, DN_USize segment_size, char segment_char) -{ - DN_Str8 result = DN_Str8ReverseSegment(DN_OS_TLSGet()->frame_arena, src, segment_size, segment_char); - return result; -} - -DN_API DN_Str8 DN_Str8ReverseSegmentFromTLS(DN_Str8 src, DN_USize segment_size, char segment_char) -{ - DN_Str8 result = DN_Str8ReverseSegment(DN_OS_TLSTopArena(), src, segment_size, segment_char); - return result; -} - -DN_API DN_Str8 DN_Str8AppendFFromFrame(DN_Str8 string, char const *fmt, ...) -{ - va_list args; - va_start(args, fmt); - DN_Str8 result = DN_Str8AppendFV(DN_OS_TLSGet()->frame_arena, string, fmt, args); - va_end(args); - return result; -} - -DN_API DN_Str8 DN_Str8AppendFFromTLS(DN_Str8 string, char const *fmt, ...) -{ - va_list args; - va_start(args, fmt); - DN_Str8 result = DN_Str8AppendFV(DN_OS_TLSTopArena(), string, fmt, args); - va_end(args); - return result; -} - -DN_API DN_Str8 DN_Str8FillFFromFrame(DN_USize count, char const *fmt, ...) -{ - va_list args; - va_start(args, fmt); - DN_Str8 result = DN_Str8FillFV(DN_OS_TLSGet()->frame_arena, count, fmt, args); - va_end(args); - return result; -} - -DN_API DN_Str8 DN_Str8FillFFromTLS(DN_USize count, char const *fmt, ...) -{ - va_list args; - va_start(args, fmt); - DN_Str8 result = DN_Str8FillFV(DN_OS_TLSTopArena(), count, fmt, args); - va_end(args); - return result; -} - -DN_API DN_Str8TruncateResult DN_Str8TruncateMiddleArenaFrame(DN_Str8 str8, uint32_t side_size, DN_Str8 truncator) -{ - DN_Str8TruncateResult result = DN_Str8TruncateMiddle(DN_OS_TLSGet()->frame_arena, str8, side_size, truncator); - return result; -} - -DN_API DN_Str8TruncateResult DN_Str8TruncateMiddleArenaTLS(DN_Str8 str8, uint32_t side_size, DN_Str8 truncator) -{ - DN_Str8TruncateResult result = DN_Str8TruncateMiddle(DN_OS_TLSTopArena(), str8, side_size, truncator); - return result; -} - -DN_API DN_Str8 DN_Str8PadNewLines(DN_Arena *arena, DN_Str8 src, DN_Str8 pad) -{ - // TODO: Implement this without requiring TLS so it can go into base strings - DN_OSTLSTMem tmem = DN_OS_TLSPushTMem(arena); - DN_Str8Builder builder = DN_Str8BuilderFromTLS(); - - DN_Str8BSplitResult split = DN_Str8BSplit(src, DN_Str8Lit("\n")); - while (split.lhs.size) { - DN_Str8BuilderAppendRef(&builder, pad); - DN_Str8BuilderAppendRef(&builder, split.lhs); - split = DN_Str8BSplit(split.rhs, DN_Str8Lit("\n")); - if (split.lhs.size) - DN_Str8BuilderAppendRef(&builder, DN_Str8Lit("\n")); - } - - DN_Str8 result = DN_Str8BuilderBuild(&builder, arena); - return result; -} - -DN_API DN_Str8 DN_Str8PadNewLinesFromFrame(DN_Str8 src, DN_Str8 pad) -{ - DN_Str8 result = DN_Str8PadNewLines(DN_OS_TLSGet()->frame_arena, src, pad); - return result; -} - -DN_API DN_Str8 DN_Str8PadNewLinesFromTLS(DN_Str8 src, DN_Str8 pad) -{ - DN_Str8 result = DN_Str8PadNewLines(DN_OS_TLSTopArena(), src, pad); - return result; -} - -DN_API DN_Str8 DN_Str8UpperFromFrame(DN_Str8 string) -{ - DN_Str8 result = DN_Str8Upper(DN_OS_TLSGet()->frame_arena, string); - return result; -} - -DN_API DN_Str8 DN_Str8UpperFromTLS(DN_Str8 string) -{ - DN_Str8 result = DN_Str8Upper(DN_OS_TLSTopArena(), string); - return result; -} - -DN_API DN_Str8 DN_Str8LowerFromFrame(DN_Str8 string) -{ - DN_Str8 result = DN_Str8Lower(DN_OS_TLSGet()->frame_arena, string); - return result; -} - -DN_API DN_Str8 DN_Str8LowerFromTLS(DN_Str8 string) -{ - DN_Str8 result = DN_Str8Lower(DN_OS_TLSTopArena(), string); - return result; -} - -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) -{ - // TODO: Implement this without requiring TLS so it can go into base strings - DN_Str8 result = {}; - if (string.size == 0 || find.size == 0 || find.size > string.size || find.size == 0 || string.size == 0) { - result = DN_Str8FromStr8Arena(arena, string); - return result; - } - - DN_OSTLSTMem tmem = DN_OS_TLSTMem(arena); - DN_Str8Builder string_builder = DN_Str8BuilderFromArena(tmem.arena); - DN_USize max = string.size - find.size; - DN_USize head = start_index; - - for (DN_USize tail = head; tail <= max; tail++) { - DN_Str8 check = DN_Str8Slice(string, tail, find.size); - if (!DN_Str8Eq(check, find, eq_case)) - continue; - - if (start_index > 0 && string_builder.string_size == 0) { - // User provided a hint in the string to start searching from, we - // need to add the string up to the hint. We only do this if there's - // a replacement action, otherwise we have a special case for no - // replacements, where the entire string gets copied. - DN_Str8 slice = DN_Str8FromPtr(string.data, head); - DN_Str8BuilderAppendRef(&string_builder, slice); - } - - DN_Str8 range = DN_Str8Slice(string, head, (tail - head)); - DN_Str8BuilderAppendRef(&string_builder, range); - DN_Str8BuilderAppendRef(&string_builder, replace); - head = tail + find.size; - tail += find.size - 1; // NOTE: -1 since the for loop will post increment us past the end of the find string - } - - if (string_builder.string_size == 0) { - // NOTE: No replacement possible, so we just do a full-copy - result = DN_Str8FromStr8Arena(arena, string); - } else { - DN_Str8 remainder = DN_Str8FromPtr(string.data + head, string.size - head); - DN_Str8BuilderAppendRef(&string_builder, remainder); - result = DN_Str8BuilderBuild(&string_builder, arena); - } - - return result; -} - -DN_API DN_Str8 DN_Str8ReplaceInsensitive(DN_Str8 string, DN_Str8 find, DN_Str8 replace, DN_USize start_index, DN_Arena *arena) -{ - DN_Str8 result = DN_Str8Replace(string, find, replace, start_index, arena, DN_Str8EqCase_Insensitive); - return result; -} - -// NOTE: DN_Str8Builder //////////////////////////////////////////////////////////////////////////// -DN_API DN_Str8 DN_Str8BuilderBuildFromOSHeap(DN_Str8Builder const *builder) -{ - DN_Str8 result = DN_ZeroInit; - if (!builder || builder->string_size <= 0 || builder->count <= 0) - return result; - - result.data = DN_Cast(char *) DN_OS_MemAlloc(builder->string_size + 1, DN_ZMem_No); - if (!result.data) - return result; - - for (DN_Str8Link *link = builder->head; link; link = link->next) { - DN_Memcpy(result.data + result.size, link->string.data, link->string.size); - result.size += link->string.size; - } - - result.data[result.size] = 0; - DN_Assert(result.size == builder->string_size); - return result; -} - -#if defined(DN_PLATFORM_POSIX) || defined(DN_PLATFORM_EMSCRIPTEN) - // DN: Single header generator inlined this file => #include "OS/dn_os_posix.cpp" -#define DN_OS_POSIX_CPP - -#if defined(_CLANGD) - // DN: Single header generator commented out this header => #include "../dn_base_inc.h" - // DN: Single header generator commented out this header => #include "../dn_os_inc.h" -#endif - -#include // readdir, opendir, closedir -#include - -// NOTE: DN_OSMem -static DN_U32 DN_OS_MemConvertPageToOSFlags_(DN_U32 protect) -{ - DN_Assert((protect & ~DN_MemPage_All) == 0); - DN_Assert(protect != 0); - DN_U32 result = 0; - - if (protect & (DN_MemPage_NoAccess | DN_MemPage_Guard)) { - result = PROT_NONE; - } else { - if (protect & DN_MemPage_Read) - result = PROT_READ; - if (protect & DN_MemPage_Write) - result = PROT_WRITE; - } - return result; -} - -DN_API void *DN_OS_MemReserve(DN_USize size, DN_MemCommit commit, DN_U32 page_flags) -{ - #if defined(DN_PLATFORM_EMSCRIPTEN) - DN_InvalidCodePathF("Emscripten does not support virtual memory, you should use DN_OS_MemAlloc"); - #endif - - unsigned long os_page_flags = DN_OS_MemConvertPageToOSFlags_(page_flags); - - if (commit == DN_MemCommit_Yes) - os_page_flags |= (PROT_READ | PROT_WRITE); - - void *result = mmap(nullptr, size, os_page_flags, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); - DN_AtomicAddU64(&g_dn_->os.mem_allocs_total, 1); - DN_AtomicAddU64(&g_dn_->os.mem_allocs_frame, 1); - if (result == MAP_FAILED) - result = nullptr; - return result; -} - -DN_API bool DN_OS_MemCommit(void *ptr, DN_USize size, DN_U32 page_flags) -{ - #if defined(DN_PLATFORM_EMSCRIPTEN) - DN_InvalidCodePathF("Emscripten does not support virtual memory"); - #endif - bool result = false; - if (!ptr || size == 0) - return false; - - unsigned long os_page_flags = DN_OS_MemConvertPageToOSFlags_(page_flags); - result = mprotect(ptr, size, os_page_flags) == 0; - DN_AtomicAddU64(&g_dn_->os.mem_allocs_total, 1); - DN_AtomicAddU64(&g_dn_->os.mem_allocs_frame, 1); - return result; -} - -DN_API void DN_OS_MemDecommit(void *ptr, DN_USize size) -{ - #if defined(DN_PLATFORM_EMSCRIPTEN) - DN_InvalidCodePathF("Emscripten does not support virtual memory"); - #endif - mprotect(ptr, size, PROT_NONE); - madvise(ptr, size, MADV_FREE); -} - -DN_API void DN_OS_MemRelease(void *ptr, DN_USize size) -{ - #if defined(DN_PLATFORM_EMSCRIPTEN) - DN_InvalidCodePathF("Emscripten does not support virtual memory"); - #endif - munmap(ptr, size); -} - -DN_API int DN_OS_MemProtect(void *ptr, DN_USize size, DN_U32 page_flags) -{ - #if defined(DN_PLATFORM_EMSCRIPTEN) - DN_InvalidCodePathF("Emscripten does not support virtual memory"); - #endif - if (!ptr || size == 0) - return 0; - - static DN_Str8 const ALIGNMENT_ERROR_MSG = DN_Str8Lit( - "Page protection requires pointers to be page aligned because we " - "can only guard memory at a multiple of the page boundary."); - DN_AssertF(DN_IsPowerOfTwoAligned(DN_Cast(uintptr_t) ptr, g_dn_->os.page_size), - "%s", - ALIGNMENT_ERROR_MSG.data); - DN_AssertF( - DN_IsPowerOfTwoAligned(size, g_dn_->os.page_size), "%s", ALIGNMENT_ERROR_MSG.data); - - unsigned long os_page_flags = DN_OS_MemConvertPageToOSFlags_(page_flags); - int result = mprotect(ptr, size, os_page_flags); - DN_AssertF(result == 0, "mprotect failed (%d)", errno); - return result; -} - -DN_API void *DN_OS_MemAlloc(DN_USize size, DN_ZMem z_mem) -{ - void *result = z_mem == DN_ZMem_Yes ? calloc(1, size) : malloc(size); - return result; -} - -DN_API void DN_OS_MemDealloc(void *ptr) -{ - free(ptr); -} - -// NOTE: Date -DN_API DN_Date DN_OS_DateLocalTimeNow() -{ - DN_Date result = {}; - struct timespec ts; - clock_gettime(CLOCK_REALTIME, &ts); - - // NOTE: localtime_r is used because it is thread safe - // See: https://linux.die.net/man/3/localtime - // According to POSIX.1-2004, localtime() is required to behave as though - // tzset(3) was called, while localtime_r() does not have this requirement. - // For portable code tzset(3) should be called before localtime_r(). - for (static bool once = true; once; once = false) - tzset(); - - struct tm time = {}; - localtime_r(&ts.tv_sec, &time); - - result.hour = time.tm_hour; - result.minutes = time.tm_min; - result.seconds = time.tm_sec; - result.milliseconds = ts.tv_nsec / (1000 * 1000); // TODO: Verify that getting the milliseconds like this is correct - - result.day = DN_Cast(DN_U8) time.tm_mday; - result.month = DN_Cast(DN_U8) time.tm_mon + 1; - result.year = 1900 + DN_Cast(DN_U16) time.tm_year; - return result; -} - -DN_API DN_U64 DN_OS_DateUnixTimeNs() -{ - struct timespec ts = {}; - clock_gettime(CLOCK_REALTIME, &ts); - DN_U64 result = (ts.tv_sec * 1000 /*ms*/ * 1000 /*us*/ * 1000 /*ns*/) + ts.tv_nsec; - return result; -} - -DN_API DN_U64 DN_OS_DateUnixTimeSFromLocalDate(DN_Date date) -{ - struct tm tm_time = {0}; - tm_time.tm_year = (int)date.year - 1900; - tm_time.tm_mon = (int)date.month - 1; // month is 1-12 in your struct - tm_time.tm_mday = (int)date.day; // day of month 1-31 - tm_time.tm_hour = (int)date.hour; - tm_time.tm_min = (int)date.minutes; - tm_time.tm_sec = (int)date.seconds; - tm_time.tm_isdst = -1; // tm_isdst = -1 lets mktime() determine whether DST is in effect - time_t unix_time = mktime(&tm_time); - DN_U64 result = DN_Cast(DN_U64) unix_time; - return result; -} - -DN_API DN_U64 DN_OS_DateLocalUnixTimeSFromUnixTimeS(DN_U64 unix_ts_s) -{ - struct tm tm_local; - time_t unix_ts = unix_ts_s; - void *ret = localtime_r(&unix_ts, &tm_local); - DN_Assert(ret); - - long local_offset_seconds = tm_local.tm_gmtoff; - DN_U64 result = unix_ts_s; - if (local_offset_seconds > 0) - result += local_offset_seconds; - else - result -= local_offset_seconds; - return result; -} - -DN_API DN_Date DN_OS_DateUnixTimeSToDate(DN_U64 time) -{ - time_t posix_time = DN_Cast(time_t) time; - struct tm posix_date = *gmtime(&posix_time); - DN_Date result = {}; - result.year = posix_date.tm_year + 1900; - result.month = posix_date.tm_mon + 1; - result.day = posix_date.tm_mday; - result.hour = posix_date.tm_hour; - result.minutes = posix_date.tm_min; - result.seconds = posix_date.tm_sec; - return result; -} - -DN_API void DN_OS_GenBytesSecure(void *buffer, DN_U32 size) -{ -#if defined(DN_PLATFORM_EMSCRIPTEN) - DN_InvalidCodePath; - (void)buffer; - (void)size; -#else - DN_Assert(buffer && size); - DN_USize bytes_written = 0; - while (bytes_written < size) { - DN_USize bytes_remaining = size - bytes_written; - DN_USize need_amount = DN_Min(bytes_remaining, 32); - DN_USize bytes_read = 0; - do { - bytes_read = getrandom((DN_U8 *)buffer + bytes_written, need_amount, 0); - } while (bytes_read != need_amount || errno == EAGAIN || errno == EINTR); - bytes_written += bytes_read; - } -#endif -} - -DN_API bool DN_OS_SetEnvVar(DN_Str8 name, DN_Str8 value) -{ - DN_AssertFOnce(false, "Unimplemented"); - (void)name; - (void)value; - bool result = false; - return result; -} - -DN_API DN_OSDiskSpace DN_OS_DiskSpace(DN_Str8 path) -{ - DN_OSTLSTMem tmem = DN_OS_TLSPushTMem(nullptr); - DN_OSDiskSpace result = {}; - DN_Str8 path_z_terminated = DN_Str8FromStr8Arena(tmem.arena, path); - - struct statvfs info = {}; - if (statvfs(path_z_terminated.data, &info) != 0) - return result; - - result.success = true; - result.avail = info.f_bavail * info.f_frsize; - result.size = info.f_blocks * info.f_frsize; - return result; -} - -DN_API DN_Str8 DN_OS_EXEPath(DN_Arena *arena) -{ - DN_Str8 result = {}; - if (!arena) - return result; - - int required_size_wo_null_terminator = 0; - for (int try_size = 128;; try_size *= 2) { - auto scoped_arena = DN_ArenaTempMemScope(arena); - char *try_buf = DN_ArenaNewArray(arena, char, try_size, DN_ZMem_No); - int bytes_written = readlink("/proc/self/exe", try_buf, try_size); - if (bytes_written == -1) { - // Failed, we're unable to determine the executable directory - break; - } else if (bytes_written == try_size) { - // Try again, if returned size was equal- we may of prematurely - // truncated according to the man pages - continue; - } else { - // readlink will give us the path to the executable. Once we - // determine the correct buffer size required to get the full file - // path, we do some post-processing on said string and extract just - // the directory. - - // TODO(dn): It'd be nice if there's some way of keeping this - // try_buf around, memcopy the byte and trash the try_buf from the - // arena. Instead we just get the size and redo the call one last - // time after this "calculate" step. - DN_AssertF(bytes_written < try_size, - "bytes_written can never be greater than the try size, function writes at " - "most try_size"); - required_size_wo_null_terminator = bytes_written; - break; - } - } - - if (required_size_wo_null_terminator) { - DN_ArenaTempMem temp_mem = DN_ArenaTempMemBegin(arena); - char *exe_path = - DN_ArenaNewArray(arena, char, required_size_wo_null_terminator + 1, DN_ZMem_No); - exe_path[required_size_wo_null_terminator] = 0; - - int bytes_written = readlink("/proc/self/exe", exe_path, required_size_wo_null_terminator); - if (bytes_written == -1) { - // Note that if read-link fails again can be because there's - // a potential race condition here, our exe or directory could have - // been deleted since the last call, so we need to be careful. - DN_ArenaTempMemEnd(temp_mem); - } else { - result = DN_Str8FromPtr(exe_path, required_size_wo_null_terminator); - } - } - return result; -} - -DN_API void DN_OS_SleepMs(DN_UInt milliseconds) -{ - struct timespec ts; - ts.tv_sec = milliseconds / 1000; - ts.tv_nsec = (milliseconds % 1000) * 1'000'000; // Convert remaining milliseconds to nanoseconds - // nanosleep can fail if interrupted by a signal, so we loop until the full sleep time has passed - while (nanosleep(&ts, &ts) == -1 && errno == EINTR) - ; -} - -DN_API DN_U64 DN_OS_PerfCounterFrequency() -{ - // NOTE: On Linux we use clock_gettime(CLOCK_MONOTONIC_RAW) (or CLOCK_MONOTONIC) which - // increments at nanosecond granularity. - DN_U64 result = 1'000'000'000; - return result; -} - -static DN_POSIXCore *DN_OS_GetPOSIXCore_() -{ - DN_Assert(g_dn_ && g_dn_->os.platform_context); - DN_POSIXCore *result = DN_Cast(DN_POSIXCore *)g_dn_->os.platform_context; - return result; -} - -DN_API DN_U64 DN_OS_PerfCounterNow() -{ - DN_POSIXCore *posix = DN_OS_GetPOSIXCore_(); - struct timespec ts; - clock_gettime(posix->clock_monotonic_raw ? CLOCK_MONOTONIC_RAW : CLOCK_MONOTONIC, &ts); - DN_U64 result = DN_Cast(DN_U64) ts.tv_sec * 1'000'000'000 + DN_Cast(DN_U64) ts.tv_nsec; - return result; -} - -DN_API bool DN_OS_FileCopy(DN_Str8 src, DN_Str8 dest, bool overwrite, DN_OSErrSink *error) -{ - bool result = false; - #if defined(DN_PLATFORM_EMSCRIPTEN) - DN_OS_ErrSinkAppendF(error, 1, "Unsupported on Emscripten because of their VFS model"); - #else - int src_fd = open(src.data, O_RDONLY); - if (src_fd == -1) { - int error_code = errno; - DN_OS_ErrSinkAppendF(error, - error_code, - "Failed to open file '%.*s' for copying: (%d) %s", - DN_Str8PrintFmt(src), - error_code, - strerror(error_code)); - return result; - } - DN_DEFER - { - close(src_fd); - }; - - // NOTE: File permission is set to read/write by owner, read by others - int dest_fd = open(dest.data, O_WRONLY | O_CREAT | (overwrite ? O_TRUNC : 0), 0644); - if (dest_fd == -1) { - int error_code = errno; - DN_OS_ErrSinkAppendF(error, - error_code, - "Failed to open file destination '%.*s' for copying to: (%d) %s", - DN_Str8PrintFmt(src), - error_code, - strerror(error_code)); - return result; - } - DN_DEFER - { - close(dest_fd); - }; - - struct stat stat_existing; - int fstat_result = fstat(src_fd, &stat_existing); - if (fstat_result == -1) { - int error_code = errno; - DN_OS_ErrSinkAppendF(error, - error_code, - "Failed to query file size of '%.*s' for copying: (%d) %s", - DN_Str8PrintFmt(src), - error_code, - strerror(error_code)); - return result; - } - - ssize_t bytes_written = sendfile64(dest_fd, src_fd, 0, stat_existing.st_size); - result = (bytes_written == stat_existing.st_size); - if (!result) { - int error_code = errno; - DN_OSTLSTMem tmem = DN_OS_TLSTMem(nullptr); - DN_Str8 file_size_str8 = DN_Str8FromByteCount(tmem.arena, stat_existing.st_size, DN_ByteCountType_Auto); - DN_Str8 bytes_written_str8 = DN_Str8FromByteCount(tmem.arena, bytes_written, DN_ByteCountType_Auto); - DN_OS_ErrSinkAppendF(error, - error_code, - "Failed to copy file '%.*s' to '%.*s', we copied %.*s but the file " - "size is %.*s: (%d) %s", - DN_Str8PrintFmt(src), - DN_Str8PrintFmt(dest), - DN_Str8PrintFmt(bytes_written_str8), - DN_Str8PrintFmt(file_size_str8), - error_code, - strerror(error_code)); - } - - #endif - return result; -} - -DN_API bool DN_OS_FileMove(DN_Str8 src, DN_Str8 dest, bool overwrite, DN_OSErrSink *error) -{ - // See: https://github.com/gingerBill/gb/blob/master/gb.h - bool result = false; - bool file_moved = true; - if (link(src.data, dest.data) == -1) { - // NOTE: Link can fail if we're trying to link across different volumes - // so we fall back to a binary directory. - file_moved |= DN_OS_FileCopy(src, dest, overwrite, error); - } - - if (file_moved) { - result = true; - int unlink_result = unlink(src.data); - if (unlink_result == -1) { - int error_code = errno; - DN_OS_ErrSinkAppendF( - error, - error_code, - "File '%.*s' was moved but failed to be unlinked from old location: (%d) %s", - DN_Str8PrintFmt(src), - error_code, - strerror(error_code)); - } - } - return result; -} - -DN_API DN_OSFile DN_OS_FileOpen(DN_Str8 path, - DN_OSFileOpen open_mode, - DN_OSFileAccess access, - DN_OSErrSink *error) -{ - DN_OSFile result = {}; - if (path.size == 0 || path.size <= 0) - return result; - - if ((access & ~(DN_OSFileAccess_All) || ((access & DN_OSFileAccess_All) == 0))) { - DN_InvalidCodePath; - return result; - } - - if (access & DN_OSFileAccess_Execute) { - result.error = true; - DN_OS_ErrSinkAppendF( - error, - 1, - "Failed to open file '%.*s': File access flag 'execute' is not supported", - DN_Str8PrintFmt(path)); - DN_InvalidCodePath; // TODO: Not supported via fopen - return result; - } - - // NOTE: fopen interface is not as expressive as the Win32 - // We will fopen the file beforehand to setup the state/check for validity - // before closing and reopening it with the correct request access - // permissions. - { - FILE *handle = nullptr; - switch (open_mode) { - case DN_OSFileOpen_CreateAlways: handle = fopen(path.data, "w"); break; - case DN_OSFileOpen_OpenIfExist: handle = fopen(path.data, "r"); break; - case DN_OSFileOpen_OpenAlways: handle = fopen(path.data, "a"); break; - default: DN_InvalidCodePath; break; - } - - if (!handle) { // TODO(doyle): FileOpen flag to string - result.error = true; - DN_OS_ErrSinkAppendF(error, - 1, - "Failed to open file '%.*s': File could not be opened in requested " - "mode 'DN_OSFileOpen' flag %d", - DN_Str8PrintFmt(path), - open_mode); - return result; - } - fclose(handle); - } - - char const *fopen_mode = nullptr; - if (access & DN_OSFileAccess_AppendOnly) - fopen_mode = "a+"; - else if (access & DN_OSFileAccess_Write) - fopen_mode = "w+"; - else if (access & DN_OSFileAccess_Read) - fopen_mode = "r"; - - FILE *handle = fopen(path.data, fopen_mode); - if (!handle) { - result.error = true; - DN_OS_ErrSinkAppendF(error, - 1, - "Failed to open file '%S': File could not be opened with requested " - "access mode 'DN_OSFileAccess' %d", - path, - fopen_mode); - return result; - } - result.handle = handle; - return result; -} - -DN_API DN_OSFileRead DN_OS_FileRead(DN_OSFile *file, void *buffer, DN_USize size, DN_OSErrSink *err) -{ - DN_OSFileRead result = {}; - if (!file || !file->handle || file->error || !buffer || size <= 0) - return result; - - result.bytes_read = fread(buffer, 1, size, DN_Cast(FILE *) file->handle); - if (feof(DN_Cast(FILE*)file->handle)) { - DN_OSTLSTMem tmem = DN_OS_TLSTMem(nullptr); - DN_Str8x32 buffer_size_str8 = DN_ByteCountStr8x32(size); - DN_OS_ErrSinkAppendF(err, 1, "Failed to read %S from file", buffer_size_str8); - return result; - } - - result.success = true; - return result; -} - -DN_API bool DN_OS_FileWritePtr(DN_OSFile *file, void const *buffer, DN_USize size, DN_OSErrSink *err) -{ - if (!file || !file->handle || file->error || !buffer || size <= 0) - return false; - bool result = - fwrite(buffer, DN_Cast(DN_USize) size, 1 /*count*/, DN_Cast(FILE *) file->handle) == - 1 /*count*/; - if (!result) { - DN_OSTLSTMem tmem = DN_OS_TLSTMem(nullptr); - DN_Str8x32 buffer_size_str8 = DN_ByteCountStr8x32(size); - DN_OS_ErrSinkAppendF(err, 1, "Failed to write buffer (%s) to file handle", DN_Str8PrintFmt(buffer_size_str8)); - } - return result; -} - -DN_API bool DN_OS_FileFlush(DN_OSFile *file, DN_OSErrSink *err) -{ - // TODO: errno is not thread safe - int fd = fileno(DN_Cast(FILE *) file->handle); - if (fd == -1) { - DN_OS_ErrSinkAppendF(err, errno, "Failed to flush file buffer to disk, file handle could not be converted to descriptor (%d): %s", fd, strerror(errno)); - return false; - } - - int fsync_result = fsync(fd); - if (fsync_result == -1) { - DN_OS_ErrSinkAppendF(err, errno, "Failed to flush file buffer to disk (%d): %s", fsync_result, strerror(errno)); - return false; - } - return true; -} - -DN_API void DN_OS_FileClose(DN_OSFile *file) -{ - if (!file || !file->handle || file->error) - return; - fclose(DN_Cast(FILE *) file->handle); - *file = {}; -} - -DN_API DN_OSPathInfo DN_OS_PathInfo(DN_Str8 path) -{ - DN_OSPathInfo result = {}; - if (path.size == 0) - return result; - - struct stat file_stat; - if (lstat(path.data, &file_stat) != -1) { - result.exists = true; - result.size = file_stat.st_size; - result.last_access_time_in_s = file_stat.st_atime; - result.last_write_time_in_s = file_stat.st_mtime; - // TODO(dn): Seems linux does not support creation time via stat. We - // shoddily deal with this. - result.create_time_in_s = DN_Min(result.last_access_time_in_s, result.last_write_time_in_s); - - if (S_ISDIR(file_stat.st_mode)) - result.type = DN_OSPathInfoType_Directory; - else if (S_ISREG(file_stat.st_mode)) - result.type = DN_OSPathInfoType_File; - } - return result; -} - -DN_API bool DN_OS_PathDelete(DN_Str8 path) -{ - bool result = false; - if (path.size) - result = remove(path.data) == 0; - return result; -} - -DN_API bool DN_OS_PathIsFile(DN_Str8 path) -{ - bool result = false; - if (path.size == 0) - return result; - - struct stat stat_result; - if (lstat(path.data, &stat_result) != -1) - result = S_ISREG(stat_result.st_mode) || S_ISLNK(stat_result.st_mode); - return result; -} - -DN_API bool DN_OS_PathIsDir(DN_Str8 path) -{ - bool result = false; - if (path.size == 0) - return result; - - struct stat stat_result; - if (lstat(path.data, &stat_result) != -1) - result = S_ISDIR(stat_result.st_mode); - return result; -} - -DN_API bool DN_OS_PathMakeDir(DN_Str8 path) -{ - DN_OSTLSTMem tmem = DN_OS_TLSTMem(nullptr); - bool result = true; - - // TODO(doyle): Implement this without using the path indexes, it's not - // necessary. See Windows implementation. - DN_USize path_indexes_size = 0; - uint16_t path_indexes[64] = {}; - - DN_Str8 copy = DN_Str8FromStr8Arena(tmem.arena, path); - for (DN_USize index = copy.size - 1; index < copy.size; index--) { - bool first_char = index == (copy.size - 1); - char ch = copy.data[index]; - if (ch == '/' || first_char) { - char temp = copy.data[index]; - - if (!first_char) - copy.data[index] = 0; // Temporarily null terminate it - - bool is_file = DN_OS_PathIsFile(copy); - - if (!first_char) - copy.data[index] = temp; // Undo null termination - - if (is_file) { - // NOTE: There's something that exists in at this path, but - // it's not a directory. This request to make a directory is - // invalid. - return false; - } else if (DN_OS_PathIsDir(copy)) { - // NOTE: We found a directory, we can stop here and start - // building up all the directories that didn't exist up to - // this point. - break; - } else { - // NOTE: There's nothing that exists at this path, we can - // create a directory here - path_indexes[path_indexes_size++] = DN_Cast(uint16_t) index; - } - } - } - - for (DN_USize index = path_indexes_size - 1; result && index < path_indexes_size; index--) { - uint16_t path_index = path_indexes[index]; - char temp = copy.data[path_index]; - - if (index != 0) - copy.data[path_index] = 0; - result |= mkdir(copy.data, 0774) == 0; - if (index != 0) - copy.data[path_index] = temp; - } - return result; -} - -DN_API bool DN_OS_PathIterateDir(DN_Str8 path, DN_OSDirIterator *it) -{ - if (!it->handle) { - it->handle = opendir(path.data); - if (!it->handle) - return false; - } - - struct dirent *entry; - for (;;) { - entry = readdir(DN_Cast(DIR *) it->handle); - if (entry == NULL) - break; - - if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0) - continue; - - DN_USize name_size = DN_CStr8Size(entry->d_name); - DN_USize clamped_size = DN_Min(sizeof(it->buffer) - 1, name_size); - DN_AssertF(name_size == clamped_size, "name: %s, name_size: %zu, clamped_size: %zu", entry->d_name, name_size, clamped_size); - DN_Memcpy(it->buffer, entry->d_name, clamped_size); - it->buffer[clamped_size] = 0; - it->file_name = DN_Str8FromPtr(it->buffer, clamped_size); - return true; - } - - closedir(DN_Cast(DIR *) it->handle); - it->handle = NULL; - it->file_name = {}; - it->buffer[0] = 0; - return false; -} - -DN_API void DN_OS_Exit(int32_t exit_code) -{ - exit(DN_Cast(int) exit_code); -} - -enum DN_OSPipeType_ -{ - DN_OSPipeType__Read, - DN_OSPipeType__Write, - DN_OSPipeType__Count, -}; - -DN_API DN_OSExecResult DN_OS_ExecWait(DN_OSExecAsyncHandle handle, - DN_Arena *arena, - DN_OSErrSink *error) -{ - DN_OSExecResult result = {}; - if (!handle.process || handle.os_error_code || handle.exit_code) { - if (handle.os_error_code) - result.os_error_code = handle.os_error_code; - else - result.exit_code = handle.exit_code; - - DN_Assert(!handle.stdout_read); - DN_Assert(!handle.stdout_write); - DN_Assert(!handle.stderr_read); - DN_Assert(!handle.stderr_write); - return result; - } - -#if defined(DN_PLATFORM_EMSCRIPTEN) - DN_InvalidCodePathF("Unsupported operation"); -#endif - - static_assert(sizeof(pid_t) <= sizeof(handle.process), - "We store the PID opaquely in a register sized pointer"); - pid_t process = {}; - DN_Memcpy(&process, &handle.process, sizeof(process)); - for (;;) { - int status = 0; - if (waitpid(process, &status, 0) < 0) { - result.os_error_code = errno; - break; - } - - if (WIFEXITED(status)) { - result.exit_code = WEXITSTATUS(status); - break; - } - - if (WIFSIGNALED(status)) { - result.os_error_code = WTERMSIG(status); - break; - } - } - - int stdout_pipe[DN_OSPipeType__Count] = {}; - int stderr_pipe[DN_OSPipeType__Count] = {}; - DN_Memcpy(&stdout_pipe[DN_OSPipeType__Read], - &handle.stdout_read, - sizeof(stdout_pipe[DN_OSPipeType__Read])); - DN_Memcpy(&stdout_pipe[DN_OSPipeType__Write], - &handle.stdout_write, - sizeof(stdout_pipe[DN_OSPipeType__Write])); - DN_Memcpy(&stderr_pipe[DN_OSPipeType__Read], - &handle.stderr_read, - sizeof(stderr_pipe[DN_OSPipeType__Read])); - DN_Memcpy(&stderr_pipe[DN_OSPipeType__Write], - &handle.stderr_write, - sizeof(stderr_pipe[DN_OSPipeType__Write])); - - // NOTE: Process has finished, stop the write end of the pipe - close(stdout_pipe[DN_OSPipeType__Write]); - close(stderr_pipe[DN_OSPipeType__Write]); - - // NOTE: Read the data from the read end of the pipe - if (result.os_error_code == 0) { - DN_OSTLSTMem tmem = DN_OS_TLSTMem(arena); - if (arena && handle.stdout_read) { - char buffer[4096]; - DN_Str8Builder builder = DN_Str8BuilderFromArena(tmem.arena); - for (;;) { - ssize_t bytes_read = - read(stdout_pipe[DN_OSPipeType__Read], buffer, sizeof(buffer)); - if (bytes_read <= 0) - break; - DN_Str8BuilderAppendF(&builder, "%.*s", bytes_read, buffer); - } - - result.stdout_text = DN_Str8BuilderBuild(&builder, arena); - } - - if (arena && handle.stderr_read) { - char buffer[4096]; - DN_Str8Builder builder = DN_Str8BuilderFromArena(tmem.arena); - for (;;) { - ssize_t bytes_read = - read(stderr_pipe[DN_OSPipeType__Read], buffer, sizeof(buffer)); - if (bytes_read <= 0) - break; - DN_Str8BuilderAppendF(&builder, "%.*s", bytes_read, buffer); - } - - result.stderr_text = DN_Str8BuilderBuild(&builder, arena); - } - } - - close(stdout_pipe[DN_OSPipeType__Read]); - close(stderr_pipe[DN_OSPipeType__Read]); - return result; -} - -DN_API DN_OSExecAsyncHandle DN_OS_ExecAsync(DN_Slice cmd_line, - DN_OSExecArgs *args, - DN_OSErrSink *error) -{ -#if defined(DN_PLATFORM_EMSCRIPTEN) - DN_InvalidCodePathF("Unsupported operation"); -#endif - DN_AssertFOnce(args->environment.size == 0, "Unimplemented in POSIX"); - - DN_OSExecAsyncHandle result = {}; - if (cmd_line.size == 0) - return result; - - DN_OSTLSTMem tmem = DN_OS_TLSTMem(nullptr); - DN_Str8 cmd_rendered = DN_Slice_Str8Render(tmem.arena, cmd_line, DN_Str8Lit(" ")); - int stdout_pipe[DN_OSPipeType__Count] = {}; - int stderr_pipe[DN_OSPipeType__Count] = {}; - - // NOTE: Open stdout pipe ////////////////////////////////////////////////////////////////////// - if (DN_BitIsSet(args->flags, DN_OSExecFlags_SaveStdout)) { - if (pipe(stdout_pipe) == -1) { - result.os_error_code = errno; - DN_OS_ErrSinkAppendF( - error, - result.os_error_code, - "Failed to create stdout pipe to redirect the output of the command '%.*s': %s", - DN_Str8PrintFmt(cmd_rendered), - strerror(result.os_error_code)); - return result; - } - DN_Assert(stdout_pipe[DN_OSPipeType__Read] != 0); - DN_Assert(stdout_pipe[DN_OSPipeType__Write] != 0); - } - - DN_DEFER - { - if (result.os_error_code == 0 && result.exit_code == 0) - return; - close(stdout_pipe[DN_OSPipeType__Read]); - close(stdout_pipe[DN_OSPipeType__Write]); - }; - - // NOTE: Open stderr pipe ////////////////////////////////////////////////////////////////////// - if (DN_BitIsSet(args->flags, DN_OSExecFlags_SaveStderr)) { - if (DN_BitIsSet(args->flags, DN_OSExecFlags_MergeStderrToStdout)) { - stderr_pipe[DN_OSPipeType__Read] = stdout_pipe[DN_OSPipeType__Read]; - stderr_pipe[DN_OSPipeType__Write] = stdout_pipe[DN_OSPipeType__Write]; - } else if (pipe(stderr_pipe) == -1) { - result.os_error_code = errno; - DN_OS_ErrSinkAppendF( - error, - result.os_error_code, - "Failed to create stderr pipe to redirect the output of the command '%.*s': %s", - DN_Str8PrintFmt(cmd_rendered), - strerror(result.os_error_code)); - return result; - } - DN_Assert(stderr_pipe[DN_OSPipeType__Read] != 0); - DN_Assert(stderr_pipe[DN_OSPipeType__Write] != 0); - } - - DN_DEFER - { - if (result.os_error_code == 0 && result.exit_code == 0) - return; - close(stderr_pipe[DN_OSPipeType__Read]); - close(stderr_pipe[DN_OSPipeType__Write]); - }; - - pid_t child_pid = fork(); - if (child_pid < 0) { - result.os_error_code = errno; - DN_OS_ErrSinkAppendF( - error, - result.os_error_code, - "Failed to fork process to execute the command '%.*s': %s", - DN_Str8PrintFmt(cmd_rendered), - strerror(result.os_error_code)); - return result; - } - - if (child_pid == 0) { // Child process - if (DN_BitIsSet(args->flags, DN_OSExecFlags_SaveStdout) && - (dup2(stdout_pipe[DN_OSPipeType__Write], STDOUT_FILENO) == -1)) { - result.os_error_code = errno; - DN_OS_ErrSinkAppendF( - error, - result.os_error_code, - "Failed to redirect stdout 'write' pipe for output of command '%.*s': %s", - DN_Str8PrintFmt(cmd_rendered), - strerror(result.os_error_code)); - return result; - } - - if (DN_BitIsSet(args->flags, DN_OSExecFlags_SaveStderr) && - (dup2(stderr_pipe[DN_OSPipeType__Write], STDERR_FILENO) == -1)) { - result.os_error_code = errno; - DN_OS_ErrSinkAppendF( - error, - result.os_error_code, - "Failed to redirect stderr 'read' pipe for output of command '%.*s': %s", - DN_Str8PrintFmt(cmd_rendered), - strerror(result.os_error_code)); - return result; - } - - // NOTE: Convert the command into something suitable for execvp - char **argv = - DN_ArenaNewArray(tmem.arena, char *, cmd_line.size + 1 /*null*/, DN_ZMem_Yes); - if (!argv) { - result.exit_code = -1; - DN_OS_ErrSinkAppendF( - error, - result.os_error_code, - "Failed to create argument values from command line '%.*s': Out of memory", - DN_Str8PrintFmt(cmd_rendered)); - return result; - } - - for (DN_ForIndexU(arg_index, cmd_line.size)) { - DN_Str8 arg = cmd_line.data[arg_index]; - argv[arg_index] = DN_Str8FromStr8Arena(tmem.arena, arg).data; // NOTE: Copy string to guarantee it is null-terminated - } - - // NOTE: Change the working directory if there is one - char *prev_working_dir = nullptr; - DN_DEFER - { - if (!prev_working_dir) - return; - if (result.os_error_code == 0) { - int chdir_result = chdir(prev_working_dir); - (void)chdir_result; - } - free(prev_working_dir); - }; - - if (args->working_dir.size) { - prev_working_dir = get_current_dir_name(); - DN_Str8 working_dir = DN_Str8FromStr8Arena(tmem.arena, args->working_dir); - if (chdir(working_dir.data) == -1) { - result.os_error_code = errno; - DN_OS_ErrSinkAppendF( - error, - result.os_error_code, - "Failed to create argument values from command line '%.*s': %s", - DN_Str8PrintFmt(cmd_rendered), - strerror(result.os_error_code)); - return result; - } - } - - // NOTE: Execute the command. We reuse argv because the first arg, the - // binary to execute is guaranteed to be null-terminated. - if (execvp(argv[0], argv) < 0) { - result.os_error_code = errno; - DN_OS_ErrSinkAppendF( - error, - result.os_error_code, - "Failed to execute command'%.*s': %s", - DN_Str8PrintFmt(cmd_rendered), - strerror(result.os_error_code)); - return result; - } - } - - DN_Assert(result.os_error_code == 0); - DN_Memcpy(&result.stdout_read, - &stdout_pipe[DN_OSPipeType__Read], - sizeof(stdout_pipe[DN_OSPipeType__Read])); - DN_Memcpy(&result.stdout_write, - &stdout_pipe[DN_OSPipeType__Write], - sizeof(stdout_pipe[DN_OSPipeType__Write])); - - if (DN_BitIsSet(args->flags, DN_OSExecFlags_SaveStderr) && DN_BitIsNotSet(args->flags, DN_OSExecFlags_MergeStderrToStdout)) { - DN_Memcpy(&result.stderr_read, - &stderr_pipe[DN_OSPipeType__Read], - sizeof(stderr_pipe[DN_OSPipeType__Read])); - DN_Memcpy(&result.stderr_write, - &stderr_pipe[DN_OSPipeType__Write], - sizeof(stderr_pipe[DN_OSPipeType__Write])); - } - result.exec_flags = args->flags; - DN_Memcpy(&result.process, &child_pid, sizeof(child_pid)); - return result; -} - -DN_API DN_OSExecResult DN_OS_ExecPump(DN_OSExecAsyncHandle handle, - char *stdout_buffer, - size_t *stdout_size, - char *stderr_buffer, - size_t *stderr_size, - DN_U32 timeout_ms, - DN_OSErrSink *err) -{ - DN_InvalidCodePath; - DN_OSExecResult result = {}; - return result; -} - -static DN_POSIXSyncPrimitive *DN_OS_U64ToPOSIXSyncPrimitive_(DN_U64 u64) -{ - DN_POSIXSyncPrimitive *result = nullptr; - DN_Memcpy(&result, &u64, sizeof(result)); - return result; -} - -static DN_U64 DN_POSIX_SyncPrimitiveToU64(DN_POSIXSyncPrimitive *primitive) -{ - DN_U64 result = 0; - static_assert(sizeof(result) >= sizeof(primitive), "Pointer size mis-match"); - DN_Memcpy(&result, &primitive, sizeof(result)); - return result; -} - -static DN_POSIXSyncPrimitive *DN_POSIX_AllocSyncPrimitive_() -{ - DN_POSIXCore *posix = DN_OS_GetPOSIXCore_(); - DN_POSIXSyncPrimitive *result = nullptr; - pthread_mutex_lock(&posix->sync_primitive_free_list_mutex); - { - if (posix->sync_primitive_free_list) { - result = posix->sync_primitive_free_list; - posix->sync_primitive_free_list = posix->sync_primitive_free_list->next; - result->next = nullptr; - } else { - DN_OSCore *os = &g_dn_->os; - result = DN_ArenaNew(&os->arena, DN_POSIXSyncPrimitive, DN_ZMem_Yes); - } - } - pthread_mutex_unlock(&posix->sync_primitive_free_list_mutex); - return result; -} - -static void DN_POSIX_DeallocSyncPrimitive_(DN_POSIXSyncPrimitive *primitive) -{ - if (primitive) { - DN_POSIXCore *posix = DN_OS_GetPOSIXCore_(); - pthread_mutex_lock(&posix->sync_primitive_free_list_mutex); - primitive->next = posix->sync_primitive_free_list; - posix->sync_primitive_free_list = primitive; - pthread_mutex_unlock(&posix->sync_primitive_free_list_mutex); - } -} - -// NOTE: DN_OSSemaphore //////////////////////////////////////////////////////////////////////////// -DN_API DN_OSSemaphore DN_OS_SemaphoreInit(DN_U32 initial_count) -{ - DN_OSSemaphore result = {}; - DN_POSIXSyncPrimitive *primitive = DN_POSIX_AllocSyncPrimitive_(); - if (primitive) { - int pshared = 0; // Share the semaphore across all threads in the process - if (sem_init(&primitive->sem, pshared, initial_count) == 0) - result.handle = DN_POSIX_SyncPrimitiveToU64(primitive); - else - DN_POSIX_DeallocSyncPrimitive_(primitive); - } - return result; -} - -DN_API void DN_OS_SemaphoreDeinit(DN_OSSemaphore *semaphore) -{ - if (semaphore && semaphore->handle != 0) { - DN_POSIXSyncPrimitive *primitive = DN_OS_U64ToPOSIXSyncPrimitive_(semaphore->handle); - sem_destroy(&primitive->sem); - DN_POSIX_DeallocSyncPrimitive_(primitive); - *semaphore = {}; - } -} - -DN_API void DN_OS_SemaphoreIncrement(DN_OSSemaphore *semaphore, DN_U32 amount) -{ - if (semaphore && semaphore->handle != 0) { - DN_POSIXSyncPrimitive *primitive = DN_OS_U64ToPOSIXSyncPrimitive_(semaphore->handle); - #if defined(DN_OS_WIN32) - sem_post_multiple(&primitive->sem, amount); // mingw extension - #else - for (DN_ForIndexU(index, amount)) - sem_post(&primitive->sem); - #endif // !defined(DN_OS_WIN32) - } -} - -DN_API DN_OSSemaphoreWaitResult DN_OS_SemaphoreWait(DN_OSSemaphore *semaphore, - DN_U32 timeout_ms) -{ - DN_OSSemaphoreWaitResult result = {}; - if (!semaphore || semaphore->handle == 0) - return result; - - DN_POSIXSyncPrimitive *primitive = DN_OS_U64ToPOSIXSyncPrimitive_(semaphore->handle); - if (timeout_ms == DN_OS_SEMAPHORE_INFINITE_TIMEOUT) { - int wait_result = 0; - do { - wait_result = sem_wait(&primitive->sem); - } while (wait_result == -1 && errno == EINTR); - - if (wait_result == 0) - result = DN_OSSemaphoreWaitResult_Success; - } else { - DN_U64 now_ms = DN_OS_DateUnixTimeMs(); - DN_U64 end_ts_ms = now_ms + timeout_ms; - - struct timespec abs_timeout = {}; - abs_timeout.tv_sec = end_ts_ms / 1'000; - abs_timeout.tv_nsec = 1'000'000 * (end_ts_ms - (end_ts_ms / 1'000) * 1'000); - if (sem_timedwait(&primitive->sem, &abs_timeout) == 0) - result = DN_OSSemaphoreWaitResult_Success; - else if (errno == ETIMEDOUT) - result = DN_OSSemaphoreWaitResult_Timeout; - } - return result; -} - -// NOTE: DN_OSMutex //////////////////////////////////////////////////////////////////////////////// -DN_API DN_OSMutex DN_OS_MutexInit() -{ - DN_POSIXSyncPrimitive *primitive = DN_POSIX_AllocSyncPrimitive_(); - DN_OSMutex result = {}; - if (primitive) { - if (pthread_mutex_init(&primitive->mutex, nullptr) == 0) - result.handle = DN_POSIX_SyncPrimitiveToU64(primitive); - else - DN_POSIX_DeallocSyncPrimitive_(primitive); - } - return result; -} - -DN_API void DN_OS_MutexDeinit(DN_OSMutex *mutex) -{ - if (mutex && mutex->handle != 0) { - DN_POSIXSyncPrimitive *primitive = DN_OS_U64ToPOSIXSyncPrimitive_(mutex->handle); - pthread_mutex_destroy(&primitive->mutex); - DN_POSIX_DeallocSyncPrimitive_(primitive); - *mutex = {}; - } -} - -DN_API void DN_OS_MutexLock(DN_OSMutex *mutex) -{ - if (mutex && mutex->handle != 0) { - DN_POSIXSyncPrimitive *primitive = DN_OS_U64ToPOSIXSyncPrimitive_(mutex->handle); - pthread_mutex_lock(&primitive->mutex); - } -} - -DN_API void DN_OS_MutexUnlock(DN_OSMutex *mutex) -{ - if (mutex && mutex->handle != 0) { - DN_POSIXSyncPrimitive *primitive = DN_OS_U64ToPOSIXSyncPrimitive_(mutex->handle); - pthread_mutex_unlock(&primitive->mutex); - } -} - -DN_API DN_OSConditionVariable DN_OS_ConditionVariableInit() -{ - DN_POSIXSyncPrimitive *primitive = DN_POSIX_AllocSyncPrimitive_(); - DN_OSConditionVariable result = {}; - if (primitive) { - if (pthread_cond_init(&primitive->cv, nullptr) == 0) - result.handle = DN_POSIX_SyncPrimitiveToU64(primitive); - else - DN_POSIX_DeallocSyncPrimitive_(primitive); - } - return result; -} - -DN_API void DN_OS_ConditionVariableDeinit(DN_OSConditionVariable *cv) -{ - if (cv && cv->handle != 0) { - DN_POSIXSyncPrimitive *primitive = DN_OS_U64ToPOSIXSyncPrimitive_(cv->handle); - pthread_cond_destroy(&primitive->cv); - DN_POSIX_DeallocSyncPrimitive_(primitive); - *cv = {}; - } -} - -DN_API bool DN_OS_ConditionVariableWaitUntil(DN_OSConditionVariable *cv, DN_OSMutex *mutex, DN_U64 end_ts_ms) -{ - bool result = false; - if (cv && mutex && mutex->handle != 0 && cv->handle != 0) { - DN_POSIXSyncPrimitive *cv_primitive = DN_OS_U64ToPOSIXSyncPrimitive_(cv->handle); - DN_POSIXSyncPrimitive *mutex_primitive = DN_OS_U64ToPOSIXSyncPrimitive_(mutex->handle); - - struct timespec time = {}; - time.tv_sec = end_ts_ms / 1'000; - time.tv_nsec = 1'000'000 * (end_ts_ms - (end_ts_ms / 1'000) * 1'000); - int wait_result = pthread_cond_timedwait(&cv_primitive->cv, &mutex_primitive->mutex, &time); - result = (wait_result != ETIMEDOUT); - } - return result; -} - -DN_API bool DN_OS_ConditionVariableWait(DN_OSConditionVariable *cv, DN_OSMutex *mutex, DN_U64 sleep_ms) -{ - DN_U64 end_ts_ms = DN_OS_DateUnixTimeMs() + sleep_ms; - bool result = DN_OS_ConditionVariableWaitUntil(cv, mutex, end_ts_ms); - return result; -} - -DN_API void DN_OS_ConditionVariableSignal(DN_OSConditionVariable *cv) -{ - if (cv && cv->handle != 0) { - DN_POSIXSyncPrimitive *primitive = DN_OS_U64ToPOSIXSyncPrimitive_(cv->handle); - pthread_cond_signal(&primitive->cv); - } -} - -DN_API void DN_OS_ConditionVariableBroadcast(DN_OSConditionVariable *cv) -{ - if (cv && cv->handle != 0) { - DN_POSIXSyncPrimitive *primitive = DN_OS_U64ToPOSIXSyncPrimitive_(cv->handle); - pthread_cond_broadcast(&primitive->cv); - } -} - -// NOTE: DN_OSThread /////////////////////////////////////////////////////////////////////////////// -static void *DN_OS_ThreadFunc_(void *user_context) -{ - DN_OS_ThreadExecute_(user_context); - return nullptr; -} - -DN_API bool DN_OS_ThreadInit(DN_OSThread *thread, DN_OSThreadFunc *func, void *user_context) -{ - bool result = false; - if (!thread) - return result; - - thread->func = func; - thread->user_context = user_context; - thread->init_semaphore = DN_OS_SemaphoreInit(0 /*initial_count*/); - - // TODO(doyle): Check if semaphore is valid - // NOTE: pthread_t is essentially the thread ID. In Windows, the handle and - // the ID are different things. For pthreads then we just duplicate the - // thread ID to both variables - pthread_t p_thread = {}; - static_assert(sizeof(p_thread) <= sizeof(thread->handle), - "We store the thread handle opaquely in our abstraction, " - "there must be enough bytes to store pthread's structure"); - static_assert(sizeof(p_thread) <= sizeof(thread->thread_id), - "We store the thread handle opaquely in our abstraction, " - "there must be enough bytes to store pthread's structure"); - - pthread_attr_t attribs = {}; - pthread_attr_init(&attribs); - result = pthread_create(&p_thread, &attribs, DN_OS_ThreadFunc_, thread) == 0; - pthread_attr_destroy(&attribs); - - if (result) { - DN_Memcpy(&thread->handle, &p_thread, sizeof(p_thread)); - DN_Memcpy(&thread->thread_id, &p_thread, sizeof(p_thread)); - } - - if (result) { - DN_OS_SemaphoreIncrement(&thread->init_semaphore, 1); - } else { - DN_OS_SemaphoreDeinit(&thread->init_semaphore); - *thread = {}; - } - - return result; -} - -DN_API void DN_OS_ThreadDeinit(DN_OSThread *thread) -{ - if (!thread || !thread->handle) - return; - - pthread_t thread_id = {}; - DN_Memcpy(&thread_id, &thread->thread_id, sizeof(thread_id)); - - void *return_val = nullptr; - pthread_join(thread_id, &return_val); - thread->handle = {}; - thread->thread_id = {}; -} - -DN_API DN_U32 DN_OS_ThreadID() -{ - pid_t result = gettid(); - DN_Assert(gettid() >= 0); - return DN_Cast(DN_U32) result; -} - -DN_API void DN_Posix_Init(DN_POSIXCore *posix) -{ - int mutex_init = pthread_mutex_init(&posix->sync_primitive_free_list_mutex, nullptr); - DN_Assert(mutex_init == 0); - - struct timespec ts; - posix->clock_monotonic_raw = clock_gettime(CLOCK_MONOTONIC_RAW, &ts) != -1; - if (!posix->clock_monotonic_raw) { - int get_result = clock_gettime(CLOCK_MONOTONIC, &ts); - DN_AssertF(get_result != -1, "CLOCK_MONOTONIC_RAW and CLOCK_MONOTONIC are not supported by this platform"); - } -} - -DN_API void DN_Posix_ThreadSetName(DN_Str8 name) -{ -#if defined(DN_PLATFORM_EMSCRIPTEN) - (void)name; -#else - DN_OSTLSTMem tmem = DN_OS_TLSPushTMem(nullptr); - DN_Str8 copy = DN_Str8FromStr8Arena(tmem.arena, name); - pthread_t thread = pthread_self(); - pthread_setname_np(thread, (char *)copy.data); -#endif -} - -DN_API DN_POSIXProcSelfStatus DN_Posix_ProcSelfStatus() -{ - DN_POSIXProcSelfStatus result = {}; - - // NOTE: Example - // - // ... - // VmPeak: 3352 kB - // VmSize: 3352 kB - // VmLck: 0 kB - // ... - // - // VmSize is the total virtual memory used - DN_OSFile file = DN_OS_FileOpen(DN_Str8Lit("/proc/self/status"), DN_OSFileOpen_OpenIfExist, DN_OSFileAccess_Read, nullptr); - DN_OSTLSTMem tmem = DN_OS_TLSPushTMem(nullptr); - - if (!file.error) { - char buf[256]; - DN_Str8Builder builder = DN_Str8BuilderFromTLS(); - for (;;) { - DN_OSFileRead read = DN_OS_FileRead(&file, buf, sizeof(buf), nullptr); - if (!read.success || read.bytes_read == 0) - break; - DN_Str8BuilderAppendF(&builder, "%.*s", DN_Cast(int)read.bytes_read, buf); - } - - DN_Str8 const NAME = DN_Str8Lit("Name:"); - DN_Str8 const PID = DN_Str8Lit("Pid:"); - DN_Str8 const VM_PEAK = DN_Str8Lit("VmPeak:"); - DN_Str8 const VM_SIZE = DN_Str8Lit("VmSize:"); - DN_Str8 status_buf = DN_Str8BuilderBuildFromTLS(&builder); - DN_Str8SplitResult lines = DN_Str8SplitFromTLS(status_buf, DN_Str8Lit("\n"), DN_Str8SplitIncludeEmptyStrings_No); - - for (DN_ForItSize(line_it, DN_Str8, lines.data, lines.count)) { - DN_Str8 line = DN_Str8TrimWhitespaceAround(*line_it.data); - if (DN_Str8StartsWith(line, NAME, DN_Str8EqCase_Insensitive)) { - DN_Str8 str8 = DN_Str8TrimWhitespaceAround(DN_Str8Slice(line, NAME.size, line.size)); - result.name_size = DN_Min(str8.size, sizeof(result.name)); - DN_Memcpy(result.name, str8.data, result.name_size); - } else if (DN_Str8StartsWith(line, PID, DN_Str8EqCase_Insensitive)) { - DN_Str8 str8 = DN_Str8TrimWhitespaceAround(DN_Str8Slice(line, PID.size, line.size)); - DN_U64FromResult to_u64 = DN_U64FromStr8(str8, 0); - result.pid = to_u64.value; - DN_Assert(to_u64.success); - } else if (DN_Str8StartsWith(line, VM_SIZE, DN_Str8EqCase_Insensitive)) { - DN_Str8 size_with_kb = DN_Str8TrimWhitespaceAround(DN_Str8Slice(line, VM_SIZE.size, line.size)); - DN_Assert(DN_Str8EndsWith(size_with_kb, DN_Str8Lit("kB"))); - DN_Str8 vm_size = DN_Str8BSplit(size_with_kb, DN_Str8Lit(" ")).lhs; - DN_U64FromResult to_u64 = DN_U64FromStr8(vm_size, 0); - result.vm_size = DN_Kilobytes(to_u64.value); - DN_Assert(to_u64.success); - } else if (DN_Str8StartsWith(line, VM_PEAK, DN_Str8EqCase_Insensitive)) { - DN_Str8 size_with_kb = DN_Str8TrimWhitespaceAround(DN_Str8Slice(line, VM_PEAK.size, line.size)); - DN_Assert(DN_Str8EndsWith(size_with_kb, DN_Str8Lit("kB"))); - DN_Str8 vm_size = DN_Str8BSplit(size_with_kb, DN_Str8Lit(" ")).lhs; - DN_U64FromResult to_u64 = DN_U64FromStr8(vm_size, 0); - result.vm_peak = DN_Kilobytes(to_u64.value); - DN_Assert(to_u64.success); - } - } - } - DN_OS_FileClose(&file); - return result; -} - -// NOTE: DN_OSHttp ///////////////////////////////////////////////////////////////////////////////// -#if 0 // TODO(doyle): Implement websockets for Windows and Emscripten -static EM_BOOL EMWebSocketOnOpenCallback(int type, const EmscriptenWebSocketOpenEvent *event, void *user_context) -{ - (void)user_context; - (void)type; - (void)event; - // EMSCRIPTEN_RESULT result = emscripten_websocket_send_utf8_text(event->socket, R"({"jsonrpc":"2.0","id":1,"method": "eth_subscribe","params":["newHeads"]})"); - // if (result) - // DN_LOG_InfoF("Failed to emscripten_websocket_send_utf8_text(): %d\n", result); - return EM_TRUE; -} - -static EM_BOOL EMWebSocketOnMsgCallback(int type, const EmscriptenWebSocketMessageEvent *event __attribute__((nonnull)), void *user_context) -{ - (void)type; - (void)user_context; - (void)event; - if (event->isText) { - DN_LOG_InfoF("Received: %.*s", event->numBytes, event->data); - } else { - DN_LOG_InfoF("Received: %d bytes", event->numBytes); - } - return EM_TRUE; -} - -static EM_BOOL EMWebSocketOnErrorCallback(int type, const EmscriptenWebSocketErrorEvent *event, void *user_context) -{ - (void)user_context; - (void)type; - (void)event; - return EM_TRUE; -} - -static EM_BOOL EMWebSocketOnCloseCallback(int type, const EmscriptenWebSocketCloseEvent *event, void *user_context) -{ - (void)user_context; - (void)type; - (void)event; - return EM_TRUE; -} -#endif - -#if defined(DN_PLATFORM_EMSCRIPTEN) -static void DN_OS_HttpRequestEMFetchOnSuccessCallback(emscripten_fetch_t *fetch) -{ - DN_OSHttpResponse *response = DN_Cast(DN_OSHttpResponse *) fetch->userData; - if (!DN_Check(response)) - return; - - response->http_status = DN_Cast(DN_U32) fetch->status; - response->body = DN_Str8FromArena(response->arena, fetch->numBytes, DN_ZMem_No); - if (response->body.data) - DN_Memcpy(response->body.data, fetch->data, fetch->numBytes); - - DN_OS_SemaphoreIncrement(&response->on_complete_semaphore, 1); - DN_AtomicAddU32(&response->done, 1); -} - -static void DN_OS_HttpRequestEMFetchOnErrorCallback(emscripten_fetch_t *fetch) -{ - DN_OSHttpResponse *response = DN_Cast(DN_OSHttpResponse *) fetch->userData; - if (!DN_Check(response)) - return; - - response->http_status = DN_Cast(DN_U32) fetch->status; - response->body = DN_Str8FromArena(response->arena, fetch->numBytes, DN_ZMem_No); - if (response->body.size) - DN_Memcpy(response->body.data, fetch->data, fetch->numBytes); - - DN_OS_SemaphoreIncrement(&response->on_complete_semaphore, 1); - DN_AtomicAddU32(&response->done, 1); -} -#endif - -DN_API void DN_OS_HttpRequestAsync(DN_OSHttpResponse *response, - DN_Arena *arena, - DN_Str8 host, - DN_Str8 path, - DN_OSHttpRequestSecure secure, - DN_Str8 method, - DN_Str8 body, - DN_Str8 headers) -{ - if (!response || !arena) - return; - - response->arena = arena; - response->builder.arena = - response->tmem_arena ? response->tmem_arena : &response->tmp_arena; - - DN_Arena *tmem = response->tmem_arena; - DN_OSTLSTMem tmem_ = DN_OS_TLSTMem(arena); - if (!tmem) - tmem = tmem_.arena; - -#if defined(DN_PLATFORM_EMSCRIPTEN) - emscripten_fetch_attr_t fetch_attribs = {}; - emscripten_fetch_attr_init(&fetch_attribs); - - if (method.size >= sizeof(fetch_attribs.requestMethod)) { - response->error_msg = - DN_Str8FromFmtArena(arena, - "Request method in EM has a size limit of 31 characters, method was " - "'%.*s' which is %zu characters long", - DN_Str8PrintFmt(method), - method.size); - DN_CheckF(method.size < sizeof(fetch_attribs.requestMethod), - "%.*s", - DN_Str8PrintFmt(response->error_msg)); - response->error_code = DN_Cast(DN_U32) - 1; - DN_AtomicAddU32(&response->done, 1); - return; - } - - DN_Memcpy(fetch_attribs.requestMethod, method.data, method.size); - - fetch_attribs.requestData = body.data; - fetch_attribs.requestDataSize = body.size; - fetch_attribs.attributes = EMSCRIPTEN_FETCH_LOAD_TO_MEMORY; - fetch_attribs.onsuccess = DN_OS_HttpRequestEMFetchOnSuccessCallback; - fetch_attribs.onerror = DN_OS_HttpRequestEMFetchOnErrorCallback; - fetch_attribs.userData = response; - - DN_Str8 url = DN_Str8FromFmtArena(tmem, "%.*s%.*s", DN_Str8PrintFmt(host), DN_Str8PrintFmt(path)); - DN_LOG_InfoF("Initiating HTTP '%s' request to '%.*s' with payload '%.*s'", - fetch_attribs.requestMethod, - DN_Str8PrintFmt(url), - DN_Str8PrintFmt(body)); - response->on_complete_semaphore = DN_OS_SemaphoreInit(0); - response->em_handle = emscripten_fetch(&fetch_attribs, url.data); -#else // #elif defined(DN_OS_WIN32) - DN_InvalidCodePathF("Unimplemented function"); -#endif -} - -DN_API void DN_OS_HttpRequestFree(DN_OSHttpResponse *response) -{ -// NOTE: Cleanup -#if defined(DN_PLATFORM_EMSCRIPTEN) - if (response->em_handle) { - emscripten_fetch_close(response->em_handle); - response->em_handle = nullptr; - } -#endif // #elif defined(DN_OS_WIN32) - - DN_ArenaDeinit(&response->tmp_arena); - DN_OS_SemaphoreDeinit(&response->on_complete_semaphore); - *response = {}; -} -#elif defined(DN_PLATFORM_WIN32) - // DN: Single header generator inlined this file => #include "OS/dn_os_w32.cpp" -#define DN_OS_WIN32_CPP - -/* -//////////////////////////////////////////////////////////////////////////////////////////////////// -// -// $$$$$$\ $$$$$$\ $$\ $$\ $$$$$$\ $$\ $$\ $$$$$$\ $$$$$$\ -// $$ __$$\ $$ __$$\ $$ | $\ $$ |\_$$ _|$$$\ $$ |$$ ___$$\ $$ __$$\ -// $$ / $$ |$$ / \__| $$ |$$$\ $$ | $$ | $$$$\ $$ |\_/ $$ |\__/ $$ | -// $$ | $$ |\$$$$$$\ $$ $$ $$\$$ | $$ | $$ $$\$$ | $$$$$ / $$$$$$ | -// $$ | $$ | \____$$\ $$$$ _$$$$ | $$ | $$ \$$$$ | \___$$\ $$ ____/ -// $$ | $$ |$$\ $$ | $$$ / \$$$ | $$ | $$ |\$$$ |$$\ $$ |$$ | -// $$$$$$ |\$$$$$$ | $$ / \$$ |$$$$$$\ $$ | \$$ |\$$$$$$ |$$$$$$$$\ -// \______/ \______/ \__/ \__|\______|\__| \__| \______/ \________| -// -// dn_os_w32.cpp -// -//////////////////////////////////////////////////////////////////////////////////////////////////// -*/ - -// NOTE: DN_Mem /////////////////////////////////////////////////////////////////////////// -static DN_U32 DN_OS_MemConvertPageToOSFlags_(DN_U32 protect) -{ - DN_Assert((protect & ~DN_MemPage_All) == 0); - DN_Assert(protect != 0); - DN_U32 result = 0; - - if (protect & DN_MemPage_NoAccess) { - result = PAGE_NOACCESS; - } else if (protect & DN_MemPage_ReadWrite) { - result = PAGE_READWRITE; - } else if (protect & DN_MemPage_Read) { - result = PAGE_READONLY; - } else if (protect & DN_MemPage_Write) { - DN_LOG_WarningF("Windows does not support write-only pages, granting read+write access"); - result = PAGE_READWRITE; - } - - if (protect & DN_MemPage_Guard) - result |= PAGE_GUARD; - - DN_AssertF(result != PAGE_GUARD, "Page guard is a modifier, you must also specify a page permission like read or/and write"); - return result; -} - -DN_API void *DN_OS_MemReserve(DN_USize size, DN_MemCommit commit, DN_U32 page_flags) -{ - unsigned long os_page_flags = DN_OS_MemConvertPageToOSFlags_(page_flags); - unsigned long flags = MEM_RESERVE; - if (commit == DN_MemCommit_Yes) - flags |= MEM_COMMIT; - - void *result = VirtualAlloc(nullptr, size, flags, os_page_flags); - if (flags & MEM_COMMIT) { - DN_Assert(g_dn_); - DN_AtomicAddU64(&g_dn_->os.vmem_allocs_total, 1); - DN_AtomicAddU64(&g_dn_->os.vmem_allocs_frame, 1); - } - return result; -} - -DN_API bool DN_OS_MemCommit(void *ptr, DN_USize size, DN_U32 page_flags) -{ - bool result = false; - if (!ptr || size == 0) - return false; - unsigned long os_page_flags = DN_OS_MemConvertPageToOSFlags_(page_flags); - result = VirtualAlloc(ptr, size, MEM_COMMIT, os_page_flags) != nullptr; - DN_Assert(g_dn_); - DN_AtomicAddU64(&g_dn_->os.vmem_allocs_total, 1); - DN_AtomicAddU64(&g_dn_->os.vmem_allocs_frame, 1); - return result; -} - -DN_API void DN_OS_MemDecommit(void *ptr, DN_USize size) -{ - // NOTE: This is a decommit call, which is explicitly saying to free the - // pages but not the address space, you would use OS_MemRelease to release - // everything. - DN_MSVC_WARNING_PUSH - DN_MSVC_WARNING_DISABLE(6250) // Calling 'VirtualFree' without the MEM_RELEASE flag might free memory but not address descriptors (VADs). This causes address space leaks. - VirtualFree(ptr, size, MEM_DECOMMIT); - DN_MSVC_WARNING_POP -} - -DN_API void DN_OS_MemRelease(void *ptr, DN_USize size) -{ - (void)size; - VirtualFree(ptr, 0, MEM_RELEASE); -} - -DN_API int DN_OS_MemProtect(void *ptr, DN_USize size, DN_U32 page_flags) -{ - if (!ptr || size == 0) - return 0; - - static DN_Str8 const ALIGNMENT_ERROR_MSG = - DN_Str8Lit("Page protection requires pointers to be page aligned because we can only guard memory at a multiple of the page boundary."); - DN_AssertF(DN_IsPowerOfTwoAligned(DN_Cast(uintptr_t) ptr, g_dn_->os.page_size), "%s", ALIGNMENT_ERROR_MSG.data); - DN_AssertF(DN_IsPowerOfTwoAligned(size, g_dn_->os.page_size), "%s", ALIGNMENT_ERROR_MSG.data); - - unsigned long os_page_flags = DN_OS_MemConvertPageToOSFlags_(page_flags); - unsigned long prev_flags = 0; - int result = VirtualProtect(ptr, size, os_page_flags, &prev_flags); - - (void)prev_flags; - if (result == 0) - DN_AssertF(result, "VirtualProtect failed"); - return result; -} - -DN_API void *DN_OS_MemAlloc(DN_USize size, DN_ZMem z_mem) -{ - DN_RawAssert(g_dn_->init_flags & DN_InitFlags_OS && "DN must be initialised with the OS flag"); - DN_U32 flags = z_mem == DN_ZMem_Yes ? HEAP_ZERO_MEMORY : 0; - DN_Assert(size <= DN_Cast(DWORD)(-1)); - void *result = HeapAlloc(GetProcessHeap(), flags, DN_Cast(DWORD) size); - DN_Assert(g_dn_); - DN_AtomicAddU64(&g_dn_->os.mem_allocs_total, 1); - DN_AtomicAddU64(&g_dn_->os.mem_allocs_frame, 1); - return result; -} - -DN_API void DN_OS_MemDealloc(void *ptr) -{ - HeapFree(GetProcessHeap(), 0, ptr); -} - -// NOTE: Date -DN_API DN_Date DN_OS_DateLocalTimeNow() -{ - SYSTEMTIME sys_time; - GetLocalTime(&sys_time); - - DN_Date result = {}; - result.hour = DN_Cast(DN_U8) sys_time.wHour; - result.milliseconds = DN_Cast(DN_U8) sys_time.wMilliseconds; - result.minutes = DN_Cast(DN_U8) sys_time.wMinute; - result.seconds = DN_Cast(DN_U8) sys_time.wSecond; - result.day = DN_Cast(DN_U8) sys_time.wDay; - result.month = DN_Cast(DN_U8) sys_time.wMonth; - result.year = DN_Cast(DN_U16) sys_time.wYear; - return result; -} - -const DN_U64 DN_OS_WIN32_UNIX_TIME_START = 0x019DB1DED53E8000; // January 1, 1970 (start of Unix epoch) in "ticks" -const DN_U64 DN_OS_WIN32_FILE_TIME_TICKS_PER_SECOND = 10'000'000; // Filetime returned is in intervals of 100 nanoseconds - -DN_API DN_U64 DN_OS_DateUnixTimeNs() -{ - FILETIME file_time; - GetSystemTimeAsFileTime(&file_time); - - // NOTE: Filetime returned is in intervals of 100 nanoeseconds so we - // multiply by 100 to get nanoseconds. - LARGE_INTEGER date_time; - date_time.u.LowPart = file_time.dwLowDateTime; - date_time.u.HighPart = file_time.dwHighDateTime; - DN_U64 result = (date_time.QuadPart - DN_OS_WIN32_UNIX_TIME_START) * 100; - return result; -} - -static SYSTEMTIME DN_OS_DateToSystemTime_(DN_Date date) -{ - SYSTEMTIME result = {}; - result.wYear = date.year; - result.wMonth = date.month; - result.wDay = date.day; - result.wHour = date.hour; - result.wMinute = date.minutes; - result.wSecond = date.seconds; - result.wMilliseconds = date.milliseconds; - return result; -} - -static DN_U64 DN_OS_SystemTimeToUnixTimeS_(SYSTEMTIME *sys_time) -{ - FILETIME file_time = {}; - SystemTimeToFileTime(sys_time, &file_time); - - LARGE_INTEGER date_time; - date_time.u.LowPart = file_time.dwLowDateTime; - date_time.u.HighPart = file_time.dwHighDateTime; - DN_U64 result = (date_time.QuadPart - DN_OS_WIN32_UNIX_TIME_START) / DN_OS_WIN32_FILE_TIME_TICKS_PER_SECOND; - return result; -} - -DN_API DN_U64 DN_OS_DateUnixTimeSFromLocalDate(DN_Date date) -{ - SYSTEMTIME local_time = DN_OS_DateToSystemTime_(date); - SYSTEMTIME sys_time = {}; - TzSpecificLocalTimeToSystemTime(nullptr, &local_time, &sys_time); - DN_U64 result = DN_OS_SystemTimeToUnixTimeS_(&sys_time); - return result; -} - -DN_API DN_U64 DN_OS_DateLocalUnixTimeSFromUnixTimeS(DN_U64 unix_ts_s) -{ - DN_U64 unix_time = DN_Cast(DN_U64) unix_ts_s * 10000000LL; // seconds -> 100ns units - DN_U64 filetime_utc = unix_time + 116444736000000000LL; // Unix epoch -> Windows epoch - FILETIME ft_utc = {DN_Cast(DWORD) filetime_utc, DN_Cast(DWORD)(filetime_utc >> 32)}; - FILETIME ft_local; - bool converted = FileTimeToLocalFileTime(&ft_utc, &ft_local); - DN_Assert(converted); - - DN_U64 filetime_local = (DN_Cast(DN_U64) ft_local.dwHighDateTime << 32) | ft_local.dwLowDateTime; - DN_U64 result = (filetime_local - 116444736000000000LL) / 10000000LL; - return result; -} - -DN_API void DN_OS_GenBytesSecure(void *buffer, DN_U32 size) -{ - DN_Assert(g_dn_); - DN_W32Core *w32 = DN_Cast(DN_W32Core *) g_dn_->os.platform_context; - DN_Assert(w32->bcrypt_init_success); - - long gen_status = BCryptGenRandom(w32->bcrypt_rng_handle, DN_Cast(unsigned char *) buffer, size, 0 /*flags*/); - // NOTE: This can only fail if the handle is invalid or one or more parameters are invalid. We - // validate our parameters so this shouldn't be the case. - DN_Assert(gen_status == 0); -} - -DN_API DN_OSDiskSpace DN_OS_DiskSpace(DN_Str8 path) -{ - DN_OSTLSTMem tmem = DN_OS_TLSPushTMem(nullptr); - DN_OSDiskSpace result = {}; - DN_Str16 path16 = DN_W32_Str8ToStr16(tmem.arena, path); - - ULARGE_INTEGER free_bytes_avail_to_caller; - ULARGE_INTEGER total_number_of_bytes; - ULARGE_INTEGER total_number_of_free_bytes; - if (!GetDiskFreeSpaceExW(path16.data, - &free_bytes_avail_to_caller, - &total_number_of_bytes, - &total_number_of_free_bytes)) - return result; - - result.success = true; - result.avail = free_bytes_avail_to_caller.QuadPart; - result.size = total_number_of_bytes.QuadPart; - return result; -} - -DN_API bool DN_OS_SetEnvVar(DN_Str8 name, DN_Str8 value) -{ - DN_OSTLSTMem tmem = DN_OS_TLSPushTMem(nullptr); - DN_Str16 name16 = DN_W32_Str8ToStr16(tmem.arena, name); - DN_Str16 value16 = DN_W32_Str8ToStr16(tmem.arena, value); - bool result = SetEnvironmentVariableW(name16.data, value16.data) != 0; - return result; -} - -DN_API DN_Str8 DN_OS_EXEPath(DN_Arena *arena) -{ - DN_Str8 result = {}; - if (!arena) - return result; - DN_OSTLSTMem tmem = DN_OS_TLSTMem(arena); - DN_Str16 exe_dir16 = DN_W32_EXEPathW(tmem.arena); - result = DN_W32_Str16ToStr8(arena, exe_dir16); - return result; -} - -DN_API void DN_OS_SleepMs(DN_UInt milliseconds) -{ - Sleep(milliseconds); -} - -DN_API DN_U64 DN_OS_PerfCounterFrequency() -{ - DN_Assert(g_dn_); - DN_W32Core *w32 = DN_Cast(DN_W32Core *) g_dn_->os.platform_context; - DN_Assert(w32->qpc_frequency.QuadPart); - DN_U64 result = w32->qpc_frequency.QuadPart; - return result; -} - -DN_API DN_U64 DN_OS_PerfCounterNow() -{ - LARGE_INTEGER integer = {}; - QueryPerformanceCounter(&integer); - DN_U64 result = integer.QuadPart; - return result; -} - -static DN_U64 DN_W32_FileTimeToSeconds_(FILETIME const *time) -{ - ULARGE_INTEGER time_large_int = {}; - time_large_int.u.LowPart = time->dwLowDateTime; - time_large_int.u.HighPart = time->dwHighDateTime; - DN_U64 result = (time_large_int.QuadPart / 10000000ULL) - 11644473600ULL; - return result; -} - -DN_API bool DN_OS_FileCopy(DN_Str8 src, DN_Str8 dest, bool overwrite, DN_OSErrSink *err) -{ - bool result = false; - DN_OSTLSTMem tmem = DN_OS_TLSTMem(nullptr); - DN_Str16 src16 = DN_W32_Str8ToStr16(tmem.arena, src); - DN_Str16 dest16 = DN_W32_Str8ToStr16(tmem.arena, dest); - - int fail_if_exists = overwrite == false; - result = CopyFileW(src16.data, dest16.data, fail_if_exists) != 0; - - if (!result) { - DN_W32Error win_error = DN_W32_LastError(tmem.arena); - DN_OS_ErrSinkAppendF(err, - win_error.code, - "Failed to copy file '%.*s' to '%.*s': (%u) %.*s", - DN_Str8PrintFmt(src), - DN_Str8PrintFmt(dest), - win_error.code, - DN_Str8PrintFmt(win_error.msg)); - } - return result; -} - -DN_API bool DN_OS_FileMove(DN_Str8 src, DN_Str8 dest, bool overwrite, DN_OSErrSink *err) -{ - bool result = false; - DN_OSTLSTMem tmem = DN_OS_TLSTMem(nullptr); - DN_Str16 src16 = DN_W32_Str8ToStr16(tmem.arena, src); - DN_Str16 dest16 = DN_W32_Str8ToStr16(tmem.arena, dest); - - unsigned long flags = MOVEFILE_COPY_ALLOWED; - if (overwrite) - flags |= MOVEFILE_REPLACE_EXISTING; - - result = MoveFileExW(src16.data, dest16.data, flags) != 0; - if (!result) { - DN_W32Error win_error = DN_W32_LastError(tmem.arena); - DN_OS_ErrSinkAppendF(err, - win_error.code, - "Failed to move file '%.*s' to '%.*s': (%u) %.*s", - DN_Str8PrintFmt(src), - DN_Str8PrintFmt(dest), - win_error.code, - DN_Str8PrintFmt(win_error.msg)); - } - return result; -} - -DN_API DN_OSFile DN_OS_FileOpen(DN_Str8 path, DN_OSFileOpen open_mode, DN_U32 access, DN_OSErrSink *err) -{ - DN_OSFile result = {}; - if (path.size == 0 || path.size <= 0) - return result; - - if ((access & ~DN_OSFileAccess_All) || ((access & DN_OSFileAccess_All) == 0)) { - DN_InvalidCodePath; - return result; - } - - unsigned long create_flag = 0; - switch (open_mode) { - case DN_OSFileOpen_CreateAlways: create_flag = CREATE_ALWAYS; break; - case DN_OSFileOpen_OpenIfExist: create_flag = OPEN_EXISTING; break; - case DN_OSFileOpen_OpenAlways: create_flag = OPEN_ALWAYS; break; - default: DN_InvalidCodePath; return result; - } - - unsigned long access_mode = 0; - if (access & DN_OSFileAccess_AppendOnly) { - DN_AssertF((access & ~DN_OSFileAccess_AppendOnly) == 0, - "Append can only be applied exclusively to the file, other access modes not permitted"); - access_mode = FILE_APPEND_DATA; - } else { - if (access & DN_OSFileAccess_Read) - access_mode |= GENERIC_READ; - if (access & DN_OSFileAccess_Write) - access_mode |= GENERIC_WRITE; - if (access & DN_OSFileAccess_Execute) - access_mode |= GENERIC_EXECUTE; - } - - DN_OSTLSTMem tmem = DN_OS_TLSTMem(nullptr); - DN_Str16 path16 = DN_W32_Str8ToStr16(tmem.arena, path); - void *handle = CreateFileW(/*LPCWSTR lpFileName*/ path16.data, - /*DWORD dwDesiredAccess*/ access_mode, - /*DWORD dwShareMode*/ FILE_SHARE_READ | FILE_SHARE_WRITE, - /*LPSECURITY_ATTRIBUTES lpSecurityAttributes*/ nullptr, - /*DWORD dwCreationDisposition*/ create_flag, - /*DWORD dwFlagsAndAttributes*/ FILE_ATTRIBUTE_NORMAL, - /*HANDLE hTemplateFile*/ nullptr); - - if (handle == INVALID_HANDLE_VALUE) { - DN_W32Error win_error = DN_W32_LastError(tmem.arena); - result.error = true; - DN_OS_ErrSinkAppendF(err, win_error.code, "Failed to open file at '%.*s': '%.*s'", DN_Str8PrintFmt(path), DN_Str8PrintFmt(win_error.msg)); - return result; - } - - result.handle = handle; - return result; -} - -DN_API DN_OSFileRead DN_OS_FileRead(DN_OSFile *file, void *buffer, DN_USize size, DN_OSErrSink *err) -{ - DN_OSFileRead result = {}; - if (!file || !file->handle || file->error || !buffer || size <= 0) - return result; - - DN_OSTLSTMem tmem = DN_OS_TLSTMem(nullptr); - if (!DN_Check(size <= (unsigned long)-1)) { - DN_Str8x32 buffer_size_str8 = DN_ByteCountStr8x32(size); - DN_OS_ErrSinkAppendF( - err, - 1 /*error_code*/, - "Current implementation doesn't support reading >4GiB file (requested %.*s), implement Win32 overlapped IO", - DN_Str8PrintFmt(buffer_size_str8)); - return result; - } - - unsigned long bytes_read = 0; - unsigned long read_result = ReadFile(/*HANDLE hFile*/ file->handle, - /*LPVOID lpBuffer*/ buffer, - /*DWORD nNumberOfBytesToRead*/ DN_Cast(unsigned long) size, - /*LPDWORD lpNumberOfByesRead*/ &bytes_read, - /*LPOVERLAPPED lpOverlapped*/ nullptr); - if (read_result == 0) { - DN_W32Error win_error = DN_W32_LastError(tmem.arena); - DN_OS_ErrSinkAppendF(err, win_error.code, "Failed to read data from file: (%u) %.*s", win_error.code, DN_Str8PrintFmt(win_error.msg)); - return result; - } - - if (bytes_read != size) { - DN_W32Error win_error = DN_W32_LastError(tmem.arena); - DN_OS_ErrSinkAppendF( - err, - win_error.code, - "Failed to read the desired number of bytes from file, we read %uB but we expected %uB: (%u) %.*s", - bytes_read, - DN_Cast(unsigned long) size, - win_error.code, - DN_Str8PrintFmt(win_error.msg)); - return result; - } - - result.bytes_read = bytes_read; - result.success = true; - return result; -} - -DN_API bool DN_OS_FileWritePtr(DN_OSFile *file, void const *buffer, DN_USize size, DN_OSErrSink *err) -{ - if (!file || !file->handle || file->error || !buffer || size <= 0) - return false; - - bool result = true; - char const *end = DN_Cast(char *) buffer + size; - for (char const *ptr = DN_Cast(char const *) buffer; result && ptr != end;) { - unsigned long write_size = DN_Cast(unsigned long) DN_Min((unsigned long)-1, end - ptr); - unsigned long bytes_written = 0; - result = WriteFile(file->handle, ptr, write_size, &bytes_written, nullptr /*lpOverlapped*/) != 0; - ptr += bytes_written; - } - - if (!result) { - DN_OSTLSTMem tmem = DN_OS_TLSTMem(nullptr); - DN_W32Error win_error = DN_W32_LastError(tmem.arena); - DN_Str8x32 buffer_size_str8 = DN_ByteCountStr8x32(size); - DN_OS_ErrSinkAppendF(err, win_error.code, "Failed to write buffer (%.*s) to file handle: %.*s", DN_Str8PrintFmt(buffer_size_str8), DN_Str8PrintFmt(win_error.msg)); - } - return result; -} - -DN_API bool DN_OS_FileFlush(DN_OSFile *file, DN_OSErrSink *err) -{ - if (!file || !file->handle || file->error) - return false; - - BOOL result = FlushFileBuffers(DN_Cast(HANDLE) file->handle); - if (!result) { - DN_OSTLSTMem tmem = DN_OS_TLSTMem(nullptr); - DN_W32Error win_error = DN_W32_LastError(tmem.arena); - DN_OS_ErrSinkAppendF(err, win_error.code, "Failed to flush file buffer to disk: %.*s", DN_Str8PrintFmt(win_error.msg)); - } - - return DN_Cast(bool) result; -} - -DN_API void DN_OS_FileClose(DN_OSFile *file) -{ - if (!file || !file->handle || file->error) - return; - CloseHandle(file->handle); - *file = {}; -} - -DN_API DN_OSPathInfo DN_OS_PathInfo(DN_Str8 path) -{ - DN_OSPathInfo result = {}; - if (path.size == 0) - return result; - - DN_OSTLSTMem tmem = DN_OS_TLSTMem(nullptr); - DN_Str16 path16 = DN_W32_Str8ToStr16(tmem.arena, path); - - WIN32_FILE_ATTRIBUTE_DATA attrib_data = {}; - if (!GetFileAttributesExW(path16.data, GetFileExInfoStandard, &attrib_data)) - return result; - - result.exists = true; - result.create_time_in_s = DN_W32_FileTimeToSeconds_(&attrib_data.ftCreationTime); - result.last_access_time_in_s = DN_W32_FileTimeToSeconds_(&attrib_data.ftLastAccessTime); - result.last_write_time_in_s = DN_W32_FileTimeToSeconds_(&attrib_data.ftLastWriteTime); - - LARGE_INTEGER large_int = {}; - large_int.u.HighPart = DN_Cast(int32_t) attrib_data.nFileSizeHigh; - large_int.u.LowPart = attrib_data.nFileSizeLow; - result.size = (DN_U64)large_int.QuadPart; - - if (attrib_data.dwFileAttributes != INVALID_FILE_ATTRIBUTES) { - if (attrib_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) - result.type = DN_OSPathInfoType_Directory; - else - result.type = DN_OSPathInfoType_File; - } - - return result; -} - -DN_API bool DN_OS_PathDelete(DN_Str8 path) -{ - bool result = false; - if (path.size == 0) - return result; - - DN_OSTLSTMem tmem = DN_OS_TLSTMem(nullptr); - DN_Str16 path16 = DN_W32_Str8ToStr16(tmem.arena, path); - if (path16.size) { - result = DeleteFileW(path16.data); - if (!result) - result = RemoveDirectoryW(path16.data); - } - return result; -} - -DN_API bool DN_OS_PathIsFile(DN_Str8 path) -{ - bool result = false; - if (path.size == 0) - return result; - - DN_OSTLSTMem tmem = DN_OS_TLSTMem(nullptr); - DN_Str16 path16 = DN_W32_Str8ToStr16(tmem.arena, path); - if (path16.size) { - WIN32_FILE_ATTRIBUTE_DATA attrib_data = {}; - if (GetFileAttributesExW(path16.data, GetFileExInfoStandard, &attrib_data)) - result = (attrib_data.dwFileAttributes != INVALID_FILE_ATTRIBUTES) && - !(attrib_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY); - } - return result; -} - -DN_API bool DN_OS_PathIsDir(DN_Str8 path) -{ - bool result = false; - if (path.size == 0) - return result; - - DN_OSTLSTMem tmem = DN_OS_TLSTMem(nullptr); - DN_Str16 path16 = DN_W32_Str8ToStr16(tmem.arena, path); - if (path16.size) { - WIN32_FILE_ATTRIBUTE_DATA attrib_data = {}; - if (GetFileAttributesExW(path16.data, GetFileExInfoStandard, &attrib_data)) - result = (attrib_data.dwFileAttributes != INVALID_FILE_ATTRIBUTES) && - (attrib_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY); - } - - return result; -} - -DN_API bool DN_OS_PathMakeDir(DN_Str8 path) -{ - bool result = true; - DN_OSTLSTMem tmem = DN_OS_TLSTMem(nullptr); - DN_Str16 path16 = DN_W32_Str8ToStr16(tmem.arena, path); - - // NOTE: Go back from the end of the string to all the directories in the - // string, and try to create them. Since Win32 API cannot create - // intermediate directories that don't exist in a path we need to go back - // and record all the directories until we encounter one that exists. - // - // From that point onwards go forwards and make all the directories - // inbetween by null-terminating the string temporarily, creating the - // directory and so forth until we reach the end. - // - // If we find a file at some point in the path we fail out because the - // series of directories can not be made if a file exists with the same - // name. - for (DN_USize index = 0; index < path16.size; index++) { - bool first_char = index == (path16.size - 1); - wchar_t ch = path16.data[index]; - if (ch == '/' || ch == '\\' || first_char) { - wchar_t temp = path16.data[index]; - if (!first_char) - path16.data[index] = 0; // Temporarily null terminate it - - WIN32_FILE_ATTRIBUTE_DATA attrib_data = {}; - bool successful = GetFileAttributesExW(path16.data, GetFileExInfoStandard, &attrib_data); // Check - - if (successful) { - if (attrib_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { - // NOTE: The directory exists, continue iterating the path - } else { - // NOTE: There's some kind of file that exists at the path - // but it's not a directory. This request to make a - // directory is invalid. - return false; - } - } else { - // NOTE: There's nothing that exists at this path, we can create - // a directory here - result |= (CreateDirectoryW(path16.data, nullptr) == 0); - } - - if (!first_char) - path16.data[index] = temp; // Undo null termination - } - } - return result; -} - -DN_API bool DN_OS_PathIterateDir(DN_Str8 path, DN_OSDirIterator *it) -{ - if (path.size == 0 || !it || path.size <= 0) - return false; - - DN_OSTLSTMem tmem = DN_OS_TLSTMem(nullptr); - DN_W32FolderIteratorW wide_it = {}; - DN_Str16 path16 = {}; - if (it->handle) { - wide_it.handle = it->handle; - } else { - bool needs_asterisks = DN_Str8EndsWith(path, DN_Str8Lit("\\")) || - DN_Str8EndsWith(path, DN_Str8Lit("/")); - bool has_glob = DN_Str8EndsWith(path, DN_Str8Lit("\\*")) || - DN_Str8EndsWith(path, DN_Str8Lit("/*")); - - DN_Str8 adjusted_path = path; - if (!has_glob) { - // NOTE: We are missing the glob for enumerating the files, we will - // 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_OS_PathF(tmem.arena, "%.*s*", DN_Str8PrintFmt(path)); - else - adjusted_path = DN_OS_PathF(tmem.arena, "%.*s/*", DN_Str8PrintFmt(path)); - } - - path16 = DN_W32_Str8ToStr16(tmem.arena, adjusted_path); - if (path16.size <= 0) // Conversion error - return false; - } - - bool result = DN_W32_DirWIterate(path16, &wide_it); - it->handle = wide_it.handle; - if (result) { - int size = DN_W32_Str16ToStr8Buffer(wide_it.file_name, it->buffer, DN_ArrayCountU(it->buffer)); - it->file_name = DN_Str8FromPtr(it->buffer, size); - } - - return result; -} - - -// NOTE: DN_OSExec ///////////////////////////////////////////////////////////////////////////////// -DN_API void DN_OS_Exit(int32_t exit_code) -{ - ExitProcess(DN_Cast(UINT) exit_code); -} - -DN_API DN_OSExecResult DN_OS_ExecPump(DN_OSExecAsyncHandle handle, - char *stdout_buffer, - DN_USize *stdout_size, - char *stderr_buffer, - DN_USize *stderr_size, - DN_U32 timeout_ms, - DN_OSErrSink *err) -{ - DN_OSExecResult result = {}; - size_t stdout_buffer_size = 0; - size_t stderr_buffer_size = 0; - if (stdout_size) { - stdout_buffer_size = *stdout_size; - *stdout_size = 0; - } - - if (stderr_size) { - stderr_buffer_size = *stderr_size; - *stderr_size = 0; - } - - if (!handle.process || handle.os_error_code || handle.exit_code) { - if (handle.os_error_code) - result.os_error_code = handle.os_error_code; - else - result.exit_code = handle.exit_code; - - DN_Assert(!handle.stdout_read); - DN_Assert(!handle.stdout_write); - DN_Assert(!handle.stderr_read); - DN_Assert(!handle.stderr_write); - DN_Assert(!handle.process); - return result; - } - - DN_OSTLSTMem tmem = DN_OS_TLSTMem(nullptr); - DWORD stdout_bytes_available = 0; - DWORD stderr_bytes_available = 0; - PeekNamedPipe(handle.stdout_read, nullptr, 0, nullptr, &stdout_bytes_available, nullptr); - PeekNamedPipe(handle.stderr_read, nullptr, 0, nullptr, &stderr_bytes_available, nullptr); - - DWORD exec_result = WAIT_TIMEOUT; - if (stdout_bytes_available == 0 && stderr_bytes_available == 0) - exec_result = WaitForSingleObject(handle.process, timeout_ms); - - if (exec_result == WAIT_FAILED) { - DN_W32Error win_error = DN_W32_LastError(tmem.arena); - result.os_error_code = win_error.code; - DN_OS_ErrSinkAppendF(err, result.os_error_code, "Executed command failed to terminate: %.*s", DN_Str8PrintFmt(win_error.msg)); - } else if (DN_Check(exec_result == WAIT_TIMEOUT || exec_result == WAIT_OBJECT_0)) { - // NOTE: Read stdout from process - // If the pipes are full, the process will block. We periodically - // flush the pipes to make sure this doesn't happen - char sink[DN_Kilobytes(8)]; - stdout_bytes_available = 0; - if (PeekNamedPipe(handle.stdout_read, nullptr, 0, nullptr, &stdout_bytes_available, nullptr)) { - if (stdout_bytes_available) { - DWORD bytes_read = 0; - char *dest_buffer = handle.stdout_write && stdout_buffer ? stdout_buffer : sink; - DN_USize dest_size = handle.stdout_write && stdout_buffer ? stdout_buffer_size : DN_ArrayCountU(sink); - BOOL success = ReadFile(handle.stdout_read, dest_buffer, DN_Cast(DWORD) dest_size, &bytes_read, NULL); - if (success) { - if (stdout_size) - *stdout_size = bytes_read; - } else { - DN_OS_ErrSinkAppendF(err, 1, "Failed to read bytes from stdout"); - } - } - } - - // NOTE: Read stderr from process - stderr_bytes_available = 0; - if (PeekNamedPipe(handle.stderr_read, nullptr, 0, nullptr, &stderr_bytes_available, nullptr)) { - if (stderr_bytes_available) { - char *dest_buffer = handle.stderr_write && stderr_buffer ? stderr_buffer : sink; - size_t dest_size = handle.stderr_write && stderr_buffer ? stderr_buffer_size : DN_ArrayCountU(sink); - DWORD bytes_read = 0; - BOOL success = ReadFile(handle.stderr_read, dest_buffer, DN_Cast(DWORD) dest_size, &bytes_read, NULL); - if (success) { - if (stderr_size) - *stderr_size = bytes_read; - } else { - DN_OS_ErrSinkAppendF(err, 1, "Failed to read bytes from stderr"); - } - } - } - } - - result.finished = exec_result == WAIT_OBJECT_0 || exec_result == WAIT_FAILED; - if (exec_result == WAIT_OBJECT_0) { - DWORD exit_status; - if (GetExitCodeProcess(handle.process, &exit_status)) { - result.exit_code = exit_status; - } else { - DN_W32Error win_error = DN_W32_LastError(tmem.arena); - result.os_error_code = win_error.code; - DN_OS_ErrSinkAppendF(err, - result.os_error_code, - "Failed to retrieve command exit code: %.*s", - DN_Str8PrintFmt(win_error.msg)); - } - - // NOTE: Cleanup - if (handle.stdout_write) - CloseHandle(handle.stdout_write); - if (handle.stderr_write) - CloseHandle(handle.stderr_write); - if (handle.stdout_read) - CloseHandle(handle.stdout_read); - if (handle.stderr_read) - CloseHandle(handle.stderr_read); - if (handle.process) - CloseHandle(handle.process); - } - - result.stdout_text = DN_Str8FromPtr(stdout_buffer, stdout_size ? *stdout_size : 0); - result.stderr_text = DN_Str8FromPtr(stderr_buffer, stderr_size ? *stderr_size : 0); - return result; -} - -DN_API DN_OSExecResult DN_OS_ExecWait(DN_OSExecAsyncHandle handle, DN_Arena *arena, DN_OSErrSink *err) -{ - DN_OSExecResult result = {}; - if (!handle.process || handle.os_error_code || handle.exit_code) { - result.finished = true; - if (handle.os_error_code) - result.os_error_code = handle.os_error_code; - else - result.exit_code = handle.exit_code; - - DN_Assert(!handle.stdout_read); - DN_Assert(!handle.stdout_write); - DN_Assert(!handle.stderr_read); - DN_Assert(!handle.stderr_write); - DN_Assert(!handle.process); - return result; - } - - DN_OSTLSTMem tmem = DN_OS_TLSTMem(arena); - DN_Str8Builder stdout_builder = {}; - DN_Str8Builder stderr_builder = {}; - if (arena) { - stdout_builder.arena = tmem.arena; - stderr_builder.arena = tmem.arena; - } - - DN_U32 const SLOW_WAIT_TIME_MS = 100; - DN_U32 const FAST_WAIT_TIME_MS = 20; - DN_U32 wait_ms = FAST_WAIT_TIME_MS; - while (!result.finished) { - size_t stdout_size = DN_Kilobytes(8); - size_t stderr_size = DN_Kilobytes(8); - char *stdout_buffer = DN_ArenaNewArray(tmem.arena, char, stdout_size, DN_ZMem_No); - char *stderr_buffer = DN_ArenaNewArray(tmem.arena, char, stderr_size, DN_ZMem_No); - result = DN_OS_ExecPump(handle, stdout_buffer, &stdout_size, stderr_buffer, &stderr_size, wait_ms, err); - DN_Str8BuilderAppendCopy(&stdout_builder, result.stdout_text); - DN_Str8BuilderAppendCopy(&stderr_builder, result.stderr_text); - wait_ms = (result.stdout_text.size || result.stderr_text.size) ? FAST_WAIT_TIME_MS : SLOW_WAIT_TIME_MS; - } - - // NOTE: Get stdout/stderr. If no arena is passed this is a no-op ////////////////////////////// - result.stdout_text = DN_Str8BuilderBuild(&stdout_builder, arena); - result.stderr_text = DN_Str8BuilderBuild(&stderr_builder, arena); - return result; -} - -DN_API DN_OSExecAsyncHandle DN_OS_ExecAsync(DN_Slice cmd_line, DN_OSExecArgs *args, DN_OSErrSink *err) -{ - // NOTE: Pre-amble ///////////////////////////////////////////////////////////////////////////// - DN_OSExecAsyncHandle result = {}; - if (cmd_line.size == 0) - return result; - - DN_OSTLSTMem tmem = DN_OS_TLSTMem(nullptr); - DN_Str8 cmd_rendered = DN_Slice_Str8Render(tmem.arena, cmd_line, DN_Str8Lit(" ")); - DN_Str16 cmd16 = DN_W32_Str8ToStr16(tmem.arena, cmd_rendered); - DN_Str16 working_dir16 = DN_W32_Str8ToStr16(tmem.arena, args->working_dir); - - DN_Str8Builder env_builder = DN_Str8BuilderFromTLS(); - DN_Str8BuilderAppendArrayRef(&env_builder, args->environment.data, args->environment.size); - if (env_builder.string_size) - DN_Str8BuilderAppendRef(&env_builder, DN_Str8Lit("\0")); - - DN_Str8 env_block8 = DN_Str8BuilderBuildDelimitedFromTLS(&env_builder, DN_Str8Lit("\0")); - DN_Str16 env_block16 = {}; - if (env_block8.size) - env_block16 = DN_W32_Str8ToStr16(tmem.arena, env_block8); - - // NOTE: Stdout/err security attributes //////////////////////////////////////////////////////// - SECURITY_ATTRIBUTES save_std_security_attribs = {}; - save_std_security_attribs.nLength = sizeof(save_std_security_attribs); - save_std_security_attribs.bInheritHandle = true; - - // NOTE: Redirect stdout /////////////////////////////////////////////////////////////////////// - HANDLE stdout_read = {}; - HANDLE stdout_write = {}; - DN_DEFER - { - if (result.os_error_code || result.exit_code) { - CloseHandle(stdout_read); - CloseHandle(stdout_write); - } - }; - - if (DN_BitIsSet(args->flags, DN_OSExecFlags_SaveStdout)) { - if (!CreatePipe(&stdout_read, &stdout_write, &save_std_security_attribs, /*nSize*/ 0)) { - DN_W32Error win_error = DN_W32_LastError(tmem.arena); - result.os_error_code = win_error.code; - DN_OS_ErrSinkAppendF( - err, - result.os_error_code, - "Failed to create stdout pipe to redirect the output of the command '%.*s': %.*s", - DN_Str8PrintFmt(cmd_rendered), - DN_Str8PrintFmt(win_error.msg)); - return result; - } - - if (!SetHandleInformation(stdout_read, HANDLE_FLAG_INHERIT, 0)) { - DN_W32Error win_error = DN_W32_LastError(tmem.arena); - result.os_error_code = win_error.code; - DN_OS_ErrSinkAppendF(err, - result.os_error_code, - "Failed to make stdout 'read' pipe non-inheritable when trying to " - "execute command '%.*s': %.*s", - DN_Str8PrintFmt(cmd_rendered), - DN_Str8PrintFmt(win_error.msg)); - return result; - } - } - - // NOTE: Redirect stderr /////////////////////////////////////////////////////////////////////// - HANDLE stderr_read = {}; - HANDLE stderr_write = {}; - DN_DEFER - { - if (result.os_error_code || result.exit_code) { - CloseHandle(stderr_read); - CloseHandle(stderr_write); - } - }; - - if (DN_BitIsSet(args->flags, DN_OSExecFlags_SaveStderr)) { - if (DN_BitIsSet(args->flags, DN_OSExecFlags_MergeStderrToStdout)) { - stderr_read = stdout_read; - stderr_write = stdout_write; - } else { - if (!CreatePipe(&stderr_read, &stderr_write, &save_std_security_attribs, /*nSize*/ 0)) { - DN_W32Error win_error = DN_W32_LastError(tmem.arena); - result.os_error_code = win_error.code; - DN_OS_ErrSinkAppendF( - err, - result.os_error_code, - "Failed to create stderr pipe to redirect the output of the command '%.*s': %.*s", - DN_Str8PrintFmt(cmd_rendered), - DN_Str8PrintFmt(win_error.msg)); - return result; - } - - if (!SetHandleInformation(stderr_read, HANDLE_FLAG_INHERIT, 0)) { - DN_W32Error win_error = DN_W32_LastError(tmem.arena); - result.os_error_code = win_error.code; - DN_OS_ErrSinkAppendF(err, - result.os_error_code, - "Failed to make stderr 'read' pipe non-inheritable when trying to " - "execute command '%.*s': %.*s", - DN_Str8PrintFmt(cmd_rendered), - DN_Str8PrintFmt(win_error.msg)); - return result; - } - } - } - - // NOTE: Execute command /////////////////////////////////////////////////////////////////////// - PROCESS_INFORMATION proc_info = {}; - STARTUPINFOW startup_info = {}; - startup_info.cb = sizeof(STARTUPINFOW); - startup_info.hStdError = stderr_write ? stderr_write : GetStdHandle(STD_ERROR_HANDLE); - startup_info.hStdOutput = stdout_write ? stdout_write : GetStdHandle(STD_OUTPUT_HANDLE); - startup_info.hStdInput = GetStdHandle(STD_INPUT_HANDLE); - startup_info.dwFlags |= STARTF_USESTDHANDLES; - BOOL create_result = CreateProcessW(nullptr, - cmd16.data, - nullptr, - nullptr, - true, - CREATE_NO_WINDOW | CREATE_UNICODE_ENVIRONMENT, - env_block16.data, - working_dir16.data, - &startup_info, - &proc_info); - if (!create_result) { - DN_W32Error win_error = DN_W32_LastError(tmem.arena); - result.os_error_code = win_error.code; - DN_OS_ErrSinkAppendF(err, - result.os_error_code, - "Failed to execute command '%.*s': %.*s", - DN_Str8PrintFmt(cmd_rendered), - DN_Str8PrintFmt(win_error.msg)); - return result; - } - - // NOTE: Post-amble //////////////////////////////////////////////////////////////////////////// - CloseHandle(proc_info.hThread); - result.process = proc_info.hProcess; - result.stdout_read = stdout_read; - result.stdout_write = stdout_write; - if (DN_BitIsSet(args->flags, DN_OSExecFlags_SaveStderr) && DN_BitIsNotSet(args->flags, DN_OSExecFlags_MergeStderrToStdout)) { - result.stderr_read = stderr_read; - result.stderr_write = stderr_write; - } - result.exec_flags = args->flags; - return result; -} - -static DN_W32Core *DN_OS_GetW32Core_() -{ - DN_Assert(g_dn_ && g_dn_->os.platform_context); - DN_W32Core *result = DN_Cast(DN_W32Core *)g_dn_->os.platform_context; - return result; -} - -static DN_W32SyncPrimitive *DN_OS_U64ToW32SyncPrimitive_(DN_U64 u64) -{ - DN_W32SyncPrimitive *result = nullptr; - DN_Memcpy(&result, &u64, sizeof(u64)); - return result; -} - -static DN_U64 DN_W32_SyncPrimitiveToU64(DN_W32SyncPrimitive *primitive) -{ - DN_U64 result = 0; - static_assert(sizeof(result) == sizeof(primitive), "Pointer size mis-match"); - DN_Memcpy(&result, &primitive, sizeof(result)); - return result; -} - -static DN_W32SyncPrimitive *DN_W32_AllocSyncPrimitive_() -{ - DN_W32Core *w32 = DN_OS_GetW32Core_(); - DN_W32SyncPrimitive *result = nullptr; - EnterCriticalSection(&w32->sync_primitive_free_list_mutex); - { - if (w32->sync_primitive_free_list) { - result = w32->sync_primitive_free_list; - w32->sync_primitive_free_list = w32->sync_primitive_free_list->next; - result->next = nullptr; - } else { - DN_OSCore *os = &g_dn_->os; - result = DN_ArenaNew(&os->arena, DN_W32SyncPrimitive, DN_ZMem_Yes); - } - } - LeaveCriticalSection(&w32->sync_primitive_free_list_mutex); - return result; -} - -static void DN_W32_DeallocSyncPrimitive_(DN_W32SyncPrimitive *primitive) -{ - if (primitive) { - DN_W32Core *w32 = DN_OS_GetW32Core_(); - EnterCriticalSection(&w32->sync_primitive_free_list_mutex); - primitive->next = w32->sync_primitive_free_list; - w32->sync_primitive_free_list = primitive; - LeaveCriticalSection(&w32->sync_primitive_free_list_mutex); - } -} - -// NOTE: DN_OSSemaphore //////////////////////////////////////////////////////////////////////////// -DN_API DN_OSSemaphore DN_OS_SemaphoreInit(DN_U32 initial_count) -{ - DN_OSSemaphore result = {}; - DN_W32SyncPrimitive *primitive = DN_W32_AllocSyncPrimitive_(); - if (primitive) { - SECURITY_ATTRIBUTES security_attribs = {}; - primitive->sem = CreateSemaphoreA(&security_attribs, initial_count, INT32_MAX, nullptr /*name*/); - if (primitive->sem) - result.handle = DN_W32_SyncPrimitiveToU64(primitive); - if (!primitive->sem) - DN_W32_DeallocSyncPrimitive_(primitive); - } - return result; -} - -DN_API void DN_OS_SemaphoreDeinit(DN_OSSemaphore *semaphore) -{ - if (semaphore && semaphore->handle != 0) { - DN_W32SyncPrimitive *primitive = DN_OS_U64ToW32SyncPrimitive_(semaphore->handle); - CloseHandle(primitive->sem); - DN_W32_DeallocSyncPrimitive_(primitive); - *semaphore = {}; - } -} - -DN_API void DN_OS_SemaphoreIncrement(DN_OSSemaphore *semaphore, DN_U32 amount) -{ - if (semaphore && semaphore->handle != 0) { - DN_W32SyncPrimitive *primitive = DN_OS_U64ToW32SyncPrimitive_(semaphore->handle); - LONG prev_count = 0; - ReleaseSemaphore(primitive->sem, amount, &prev_count); - } -} - -DN_API DN_OSSemaphoreWaitResult DN_OS_SemaphoreWait(DN_OSSemaphore *semaphore, DN_U32 timeout_ms) -{ - DN_OSSemaphoreWaitResult result = {}; - if (semaphore && semaphore->handle != 0) { - DN_W32SyncPrimitive *primitive = DN_OS_U64ToW32SyncPrimitive_(semaphore->handle); - DWORD wait_result = WaitForSingleObject(primitive->sem, timeout_ms == DN_OS_SEMAPHORE_INFINITE_TIMEOUT ? INFINITE : timeout_ms); - if (wait_result == WAIT_TIMEOUT) - result = DN_OSSemaphoreWaitResult_Timeout; - else if (wait_result == WAIT_OBJECT_0) - result = DN_OSSemaphoreWaitResult_Success; - } - return result; -} - -// NOTE: DN_OSMutex //////////////////////////////////////////////////////////////////////////////// -DN_API DN_OSMutex DN_OS_MutexInit() -{ - DN_W32SyncPrimitive *primitive = DN_W32_AllocSyncPrimitive_(); - if (primitive) - InitializeCriticalSection(&primitive->mutex); - DN_OSMutex result = {}; - result.handle = DN_W32_SyncPrimitiveToU64(primitive); - return result; -} - -DN_API void DN_OS_MutexDeinit(DN_OSMutex *mutex) -{ - if (mutex && mutex->handle != 0) { - DN_W32SyncPrimitive *primitive = DN_OS_U64ToW32SyncPrimitive_(mutex->handle); - DeleteCriticalSection(&primitive->mutex); - DN_W32_DeallocSyncPrimitive_(primitive); - *mutex = {}; - } -} - -DN_API void DN_OS_MutexLock(DN_OSMutex *mutex) -{ - if (mutex && mutex->handle != 0) { - DN_W32SyncPrimitive *primitive = DN_OS_U64ToW32SyncPrimitive_(mutex->handle); - EnterCriticalSection(&primitive->mutex); - } -} - -DN_API void DN_OS_MutexUnlock(DN_OSMutex *mutex) -{ - if (mutex && mutex->handle != 0) { - DN_W32SyncPrimitive *primitive = DN_OS_U64ToW32SyncPrimitive_(mutex->handle); - LeaveCriticalSection(&primitive->mutex); - } -} - -// NOTE: DN_OSConditionVariable //////////////////////////////////////////////////////////////////// -DN_API DN_OSConditionVariable DN_OS_ConditionVariableInit() -{ - DN_W32SyncPrimitive *primitive = DN_W32_AllocSyncPrimitive_(); - if (primitive) - InitializeConditionVariable(&primitive->cv); - DN_OSConditionVariable result = {}; - result.handle = DN_W32_SyncPrimitiveToU64(primitive); - return result; -} - -DN_API void DN_OS_ConditionVariableDeinit(DN_OSConditionVariable *cv) -{ - if (cv && cv->handle != 0) { - DN_W32SyncPrimitive *primitive = DN_OS_U64ToW32SyncPrimitive_(cv->handle); - DN_W32_DeallocSyncPrimitive_(primitive); - *cv = {}; - } -} - -DN_API bool DN_OS_ConditionVariableWaitUntil(DN_OSConditionVariable *cv, DN_OSMutex *mutex, DN_U64 end_ts_ms) -{ - bool result = false; - DN_U64 now_ms = DN_OS_DateUnixTimeNs() / (1000 * 1000); - if (now_ms < end_ts_ms) { - DN_U64 sleep_ms = end_ts_ms - now_ms; - result = DN_OS_ConditionVariableWait(cv, mutex, sleep_ms); - } - return result; -} - -DN_API bool DN_OS_ConditionVariableWait(DN_OSConditionVariable *cv, DN_OSMutex *mutex, DN_U64 sleep_ms) -{ - bool result = false; - if (mutex && cv && mutex->handle != 0 && cv->handle != 0 && sleep_ms > 0) { - DN_W32SyncPrimitive *mutex_primitive = DN_OS_U64ToW32SyncPrimitive_(mutex->handle); - DN_W32SyncPrimitive *cv_primitive = DN_OS_U64ToW32SyncPrimitive_(cv->handle); - result = SleepConditionVariableCS(&cv_primitive->cv, &mutex_primitive->mutex, DN_Cast(DWORD) sleep_ms); - } - return result; -} - -DN_API void DN_OS_ConditionVariableSignal(DN_OSConditionVariable *cv) -{ - if (cv && cv->handle != 0) { - DN_W32SyncPrimitive *primitive = DN_OS_U64ToW32SyncPrimitive_(cv->handle); - WakeConditionVariable(&primitive->cv); - } -} - -DN_API void DN_OS_ConditionVariableBroadcast(DN_OSConditionVariable *cv) -{ - if (cv && cv->handle != 0) { - DN_W32SyncPrimitive *primitive = DN_OS_U64ToW32SyncPrimitive_(cv->handle); - WakeAllConditionVariable(&primitive->cv); - } -} - -// NOTE: DN_OSThread /////////////////////////////////////////////////////////////////////////////// -static DWORD __stdcall DN_OS_ThreadFunc_(void *user_context) -{ - DN_OS_ThreadExecute_(user_context); - return 0; -} - -DN_API bool DN_OS_ThreadInit(DN_OSThread *thread, DN_OSThreadFunc *func, void *user_context) -{ - bool result = false; - if (!thread) - return result; - - thread->func = func; - thread->user_context = user_context; - thread->init_semaphore = DN_OS_SemaphoreInit(0 /*initial_count*/); - - // TODO(doyle): Check if semaphore is valid - DWORD thread_id = 0; - SECURITY_ATTRIBUTES security_attribs = {}; - thread->handle = CreateThread(&security_attribs, - 0 /*stack_size*/, - DN_OS_ThreadFunc_, - thread, - 0 /*creation_flags*/, - &thread_id); - - result = thread->handle != INVALID_HANDLE_VALUE; - if (result) - thread->thread_id = thread_id; - - // NOTE: Ensure that thread_id is set before 'thread->func' is called. - if (result) { - DN_OS_SemaphoreIncrement(&thread->init_semaphore, 1); - } else { - DN_OS_SemaphoreDeinit(&thread->init_semaphore); - *thread = {}; - } - - return result; -} - -DN_API void DN_OS_ThreadDeinit(DN_OSThread *thread) -{ - if (!thread || !thread->handle) - return; - - WaitForSingleObject(thread->handle, INFINITE); - CloseHandle(thread->handle); - thread->handle = INVALID_HANDLE_VALUE; - thread->thread_id = {}; - DN_OS_TLSDeinit(&thread->tls); -} - -DN_API DN_U32 DN_OS_ThreadID() -{ - unsigned long result = GetCurrentThreadId(); - return result; -} - -DN_API void DN_W32_ThreadSetName(DN_Str8 name) -{ - DN_OSTLS *tls = DN_OS_TLSGet(); - DN_ArenaTempMem tmem = DN_ArenaTempMemBegin(tls->arenas + DN_OSTLSArena_TMem0); - - // NOTE: SetThreadDescription is only available in - // Windows Server 2016, Windows 10 LTSB 2016 and Windows 10 version 1607 - // - // See: https://learn.microsoft.com/en-us/windows/w32/api/processthreadsapi/nf-processthreadsapi-setthreaddescription - DN_W32Core *w32 = DN_OS_GetW32Core_(); - if (w32->set_thread_description) { - DN_Str16 name16 = DN_W32_Str8ToStr16(tmem.arena, name); - w32->set_thread_description(GetCurrentThread(), (WCHAR *)name16.data); - DN_ArenaTempMemEnd(tmem); - return; - } - - // NOTE: Fallback to throw-exception method to set thread name - #pragma pack(push, 8) - - struct DN_W32ThreadNameInfo - { - DN_U32 dwType; - char *szName; - DN_U32 dwThreadID; - DN_U32 dwFlags; - }; - - #pragma pack(pop) - - DN_Str8 copy = DN_Str8FromStr8Arena(tmem.arena, name); - DN_W32ThreadNameInfo info = {}; - info.dwType = 0x1000; - info.szName = (char *)copy.data; - info.dwThreadID = DN_OS_ThreadID(); - - // 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(6322) // Empty _except block - __try { - RaiseException(0x406D1388, 0, sizeof(info) / sizeof(void *), (const ULONG_PTR *)&info); - } __except (EXCEPTION_EXECUTE_HANDLER) { - } - DN_MSVC_WARNING_POP - - DN_ArenaTempMemEnd(tmem); -} - -// NOTE: DN_OSHttp ///////////////////////////////////////////////////////////////////////////////// -void DN_OS_HttpRequestWin32Callback(HINTERNET session, DWORD *dwContext, DWORD dwInternetStatus, VOID *lpvStatusInformation, DWORD dwStatusInformationLength) -{ - (void)session; - (void)dwStatusInformationLength; - - DN_OSHttpResponse *response = DN_Cast(DN_OSHttpResponse *) dwContext; - HINTERNET request = DN_Cast(HINTERNET) response->w32_request_handle; - DN_W32Error error = {}; - DWORD const READ_BUFFER_SIZE = DN_Megabytes(1); - - if (dwInternetStatus == WINHTTP_CALLBACK_STATUS_RESOLVING_NAME) { - } else if (dwInternetStatus == WINHTTP_CALLBACK_STATUS_NAME_RESOLVED) { - } else if (dwInternetStatus == WINHTTP_CALLBACK_STATUS_CONNECTING_TO_SERVER) { - } else if (dwInternetStatus == WINHTTP_CALLBACK_STATUS_CONNECTED_TO_SERVER) { - } else if (dwInternetStatus == WINHTTP_CALLBACK_STATUS_SENDING_REQUEST) { - } else if (dwInternetStatus == WINHTTP_CALLBACK_STATUS_REQUEST_SENT) { - } else if (dwInternetStatus == WINHTTP_CALLBACK_STATUS_RECEIVING_RESPONSE) { - } else if (dwInternetStatus == WINHTTP_CALLBACK_STATUS_RESPONSE_RECEIVED) { - } else if (dwInternetStatus == WINHTTP_CALLBACK_STATUS_CLOSING_CONNECTION) { - } else if (dwInternetStatus == WINHTTP_CALLBACK_STATUS_CONNECTION_CLOSED) { - } else if (dwInternetStatus == WINHTTP_CALLBACK_STATUS_CONNECTION_CLOSED) { - } else if (dwInternetStatus == WINHTTP_CALLBACK_STATUS_HANDLE_CREATED) { - } else if (dwInternetStatus == WINHTTP_CALLBACK_STATUS_HANDLE_CLOSING) { - } else if (dwInternetStatus == WINHTTP_CALLBACK_STATUS_DETECTING_PROXY) { - } else if (dwInternetStatus == WINHTTP_CALLBACK_STATUS_REDIRECT) { - } else if (dwInternetStatus == WINHTTP_CALLBACK_STATUS_INTERMEDIATE_RESPONSE) { - } else if (dwInternetStatus == WINHTTP_CALLBACK_STATUS_SECURE_FAILURE) { - } else if (dwInternetStatus == WINHTTP_CALLBACK_STATUS_HEADERS_AVAILABLE) { - DWORD status = 0; - DWORD status_size = sizeof(status_size); - if (WinHttpQueryHeaders(request, - WINHTTP_QUERY_STATUS_CODE | WINHTTP_QUERY_FLAG_NUMBER, - WINHTTP_HEADER_NAME_BY_INDEX, - &status, - &status_size, - WINHTTP_NO_HEADER_INDEX)) { - response->http_status = DN_Cast(uint16_t) status; - - // NOTE: You can normally call into WinHttpQueryDataAvailable which means the kernel - // will buffer the response into a single buffer and return us the full size of the - // request. - // - // or - // - // You may call WinHttpReadData directly to write the memory into our buffer directly. - // This is advantageous to avoid a copy from the kernel buffer into our buffer. If the - // end user application knows the typical payload size then they can optimise for this - // to prevent unnecessary allocation on the user side. - void *buffer = DN_ArenaAlloc(response->builder.arena, READ_BUFFER_SIZE, 1 /*align*/, DN_ZMem_No); - if (!WinHttpReadData(request, buffer, READ_BUFFER_SIZE, nullptr)) - error = DN_W32_LastError(&response->tmp_arena); - } else { - error = DN_W32_LastError(&response->tmp_arena); - } - } else if (dwInternetStatus == WINHTTP_CALLBACK_STATUS_DATA_AVAILABLE) { - } else if (dwInternetStatus == WINHTTP_CALLBACK_STATUS_READ_COMPLETE) { - DWORD bytes_read = dwStatusInformationLength; - if (bytes_read) { - DN_Str8 prev_buffer = DN_Str8FromPtr(DN_Cast(char *) lpvStatusInformation, bytes_read); - DN_Str8BuilderAppendRef(&response->builder, prev_buffer); - - void *buffer = DN_ArenaAlloc(response->builder.arena, READ_BUFFER_SIZE, 1 /*align*/, DN_ZMem_No); - if (!WinHttpReadData(request, buffer, READ_BUFFER_SIZE, nullptr)) - error = DN_W32_LastError(&response->tmp_arena); - } - } else if (dwInternetStatus == WINHTTP_CALLBACK_STATUS_WRITE_COMPLETE) { - } else if (dwInternetStatus == WINHTTP_CALLBACK_STATUS_REQUEST_ERROR) { - WINHTTP_ASYNC_RESULT *async_result = DN_Cast(WINHTTP_ASYNC_RESULT *) lpvStatusInformation; - error = DN_W32_ErrorCodeToMsg(&response->tmp_arena, DN_Cast(DN_U32) async_result->dwError); - } else if (dwInternetStatus == WINHTTP_CALLBACK_STATUS_SENDREQUEST_COMPLETE) { - if (!WinHttpReceiveResponse(request, 0)) - error = DN_W32_LastError(&response->tmp_arena); - } - - // NOTE: If the request handle is missing, then, the response has been freed. - // MSDN says that this callback can still be called after closing the handle - // and trigger the WINHTTP_CALLBACK_STATUS_REQUEST_ERROR. - if (request) { - bool read_complete = dwInternetStatus == WINHTTP_CALLBACK_STATUS_READ_COMPLETE && dwStatusInformationLength == 0; - if (read_complete) - response->body = DN_Str8BuilderBuild(&response->builder, response->arena); - - if (read_complete || dwInternetStatus == WINHTTP_CALLBACK_STATUS_REQUEST_ERROR || error.code) { - DN_OS_SemaphoreIncrement(&response->on_complete_semaphore, 1); - DN_AtomicAddU32(&response->done, 1); - } - - if (error.code) { - response->error_code = error.code; - response->error_msg = error.msg; - } - } -} - -DN_API void DN_OS_HttpRequestAsync(DN_OSHttpResponse *response, - DN_Arena *arena, - DN_Str8 host, - DN_Str8 path, - DN_OSHttpRequestSecure secure, - DN_Str8 method, - DN_Str8 body, - DN_Str8 headers) -{ - if (!response || !arena) - return; - - response->arena = arena; - response->builder.arena = response->tmem_arena ? response->tmem_arena : &response->tmp_arena; - - DN_Arena *tmem_arena = response->tmem_arena; - DN_OSTLSTMem tmem_ = DN_OS_TLSTMem(arena); - if (!tmem_arena) - tmem_arena = tmem_.arena; - - DN_W32Error error = {}; - DN_DEFER - { - response->error_msg = error.msg; - response->error_code = error.code; - if (error.code) { - // NOTE: 'Wait' handles failures gracefully, skipping the wait and - // cleans up the request - DN_OS_HttpRequestWait(response); - DN_AtomicAddU32(&response->done, 1); - } - }; - - response->w32_request_session = WinHttpOpen(nullptr /*user agent*/, WINHTTP_ACCESS_TYPE_AUTOMATIC_PROXY, WINHTTP_NO_PROXY_NAME, WINHTTP_NO_PROXY_BYPASS, WINHTTP_FLAG_ASYNC); - if (!response->w32_request_session) { - error = DN_W32_LastError(&response->tmp_arena); - return; - } - - DWORD callback_flags = WINHTTP_CALLBACK_STATUS_HEADERS_AVAILABLE | - WINHTTP_CALLBACK_STATUS_READ_COMPLETE | - WINHTTP_CALLBACK_STATUS_REQUEST_ERROR | - WINHTTP_CALLBACK_STATUS_SENDREQUEST_COMPLETE; - if (WinHttpSetStatusCallback(response->w32_request_session, - DN_Cast(WINHTTP_STATUS_CALLBACK) DN_OS_HttpRequestWin32Callback, - callback_flags, - DN_Cast(DWORD_PTR) nullptr /*dwReserved*/) == WINHTTP_INVALID_STATUS_CALLBACK) { - error = DN_W32_LastError(&response->tmp_arena); - return; - } - - DN_Str16 host16 = DN_W32_Str8ToStr16(tmem_arena, host); - response->w32_request_connection = WinHttpConnect(response->w32_request_session, host16.data, secure ? INTERNET_DEFAULT_HTTPS_PORT : INTERNET_DEFAULT_HTTP_PORT, 0 /*reserved*/); - if (!response->w32_request_connection) { - error = DN_W32_LastError(&response->tmp_arena); - return; - } - - DN_Str16 method16 = DN_W32_Str8ToStr16(tmem_arena, method); - DN_Str16 path16 = DN_W32_Str8ToStr16(tmem_arena, path); - response->w32_request_handle = WinHttpOpenRequest(response->w32_request_connection, - method16.data, - path16.data, - nullptr /*version*/, - nullptr /*referrer*/, - nullptr /*accept types*/, - secure ? WINHTTP_FLAG_SECURE : 0); - if (!response->w32_request_handle) { - error = DN_W32_LastError(&response->tmp_arena); - return; - } - - DN_Str16 headers16 = DN_W32_Str8ToStr16(tmem_arena, headers); - response->on_complete_semaphore = DN_OS_SemaphoreInit(0); - if (!WinHttpSendRequest(response->w32_request_handle, - headers16.data, - DN_Cast(DWORD) headers16.size, - body.data /*optional data*/, - DN_Cast(DWORD) body.size /*optional length*/, - DN_Cast(DWORD) body.size /*total content length*/, - DN_Cast(DWORD_PTR) response)) { - error = DN_W32_LastError(&response->tmp_arena); - return; - } -} - -DN_API void DN_OS_HttpRequestFree(DN_OSHttpResponse *response) -{ - // NOTE: Cleanup - // NOTE: These calls are synchronous even when the HTTP request is async. - WinHttpCloseHandle(response->w32_request_handle); - WinHttpCloseHandle(response->w32_request_connection); - WinHttpCloseHandle(response->w32_request_session); - - response->w32_request_session = nullptr; - response->w32_request_connection = nullptr; - response->w32_request_handle = nullptr; - DN_ArenaDeinit(&response->tmp_arena); - DN_OS_SemaphoreDeinit(&response->on_complete_semaphore); - - *response = {}; -} - -// NOTE: DN_W32 //////////////////////////////////////////////////////////////////////////////////// -DN_API DN_Str16 DN_W32_ErrorCodeToMsg16Alloc(DN_U32 error_code) -{ - DWORD flags = FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS; - void *module_to_get_errors_from = nullptr; - if (error_code >= 12000 && error_code <= 12175) { - flags |= FORMAT_MESSAGE_FROM_HMODULE; - module_to_get_errors_from = GetModuleHandleA("winhttp.dll"); - } - - wchar_t *result16 = nullptr; - DWORD size = FormatMessageW(/*DWORD dwFlags */ flags | FORMAT_MESSAGE_ALLOCATE_BUFFER, - /*LPCVOID lpSource */ module_to_get_errors_from, - /*DWORD dwMessageId */ error_code, - /*DWORD dwLanguageId*/ 0, - /*LPWSTR lpBuffer */ (LPWSTR)&result16, - /*DWORD nSize */ 0, - /*va_list *Arguments */ nullptr); - - DN_Str16 result = {}; - result.data = result16; - result.size = size; - return result; -} - -DN_API DN_W32Error DN_W32_ErrorCodeToMsgAlloc(DN_U32 error_code) -{ - DN_W32Error result = {}; - result.code = error_code; - DN_Str16 error16 = DN_W32_ErrorCodeToMsg16Alloc(error_code); - if (error16.size) - result.msg = DN_W32_Str16ToStr8FromHeap(error16); - if (error16.data) - LocalFree(error16.data); - return result; -} - -DN_API DN_W32Error DN_W32_ErrorCodeToMsg(DN_Arena *arena, DN_U32 error_code) -{ - DN_W32Error result = {}; - result.code = error_code; - if (arena) { - DN_Str16 error16 = DN_W32_ErrorCodeToMsg16Alloc(error_code); - if (error16.size) - result.msg = DN_W32_Str16ToStr8(arena, error16); - if (error16.data) - LocalFree(error16.data); - } - return result; -} - -DN_API DN_W32Error DN_W32_LastError(DN_Arena *arena) -{ - DN_W32Error result = DN_W32_ErrorCodeToMsg(arena, GetLastError()); - return result; -} - -DN_API DN_W32Error DN_W32_LastErrorAlloc() -{ - DN_W32Error result = DN_W32_ErrorCodeToMsgAlloc(GetLastError()); - return result; -} - -DN_API void DN_W32_MakeProcessDPIAware() -{ - 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 UTF8 to Str16 ////////////////////////////////////////////// -DN_API DN_Str16 DN_W32_Str8ToStr16(DN_Arena *arena, DN_Str8 src) -{ - DN_Str16 result = {}; - if (!arena || src.size == 0) - return result; - - int required_size = MultiByteToWideChar(CP_UTF8, 0 /*dwFlags*/, src.data, DN_Cast(int) src.size, nullptr /*dest*/, 0 /*dest size*/); - if (required_size <= 0) - return result; - - wchar_t *buffer = DN_ArenaNewArray(arena, wchar_t, required_size + 1, DN_ZMem_No); - if (!buffer) - return result; - - int chars_written = MultiByteToWideChar(CP_UTF8, 0 /*dwFlags*/, src.data, DN_Cast(int) src.size, buffer, required_size); - if (DN_Check(chars_written == required_size)) { - result.data = buffer; - result.size = chars_written; - result.data[result.size] = 0; - } - return result; -} - -DN_API int DN_W32_Str8ToStr16Buffer(DN_Str8 src, wchar_t *dest, int dest_size) -{ - int result = 0; - if (src.size == 0) - return result; - - result = MultiByteToWideChar(CP_UTF8, 0 /*dwFlags*/, src.data, DN_Cast(int) src.size, nullptr /*dest*/, 0 /*dest size*/); - if (result <= 0 || result > dest_size || !dest) - return result; - - result = MultiByteToWideChar(CP_UTF8, 0 /*dwFlags*/, src.data, DN_Cast(int) src.size, dest, DN_Cast(int) dest_size); - dest[DN_Min(result, dest_size - 1)] = 0; - return result; -} - -// NOTE: Windows Str16 To UTF8 ////////////////////////////////////////////////////////////////// -DN_API int DN_W32_Str16ToStr8Buffer(DN_Str16 src, char *dest, int dest_size) -{ - int result = 0; - if (src.size == 0) - return result; - - int src_size = DN_SaturateCastISizeToInt(src.size); - if (src_size <= 0) - return result; - - result = WideCharToMultiByte(CP_UTF8, 0 /*dwFlags*/, src.data, src_size, nullptr /*dest*/, 0 /*dest size*/, nullptr, nullptr); - if (result <= 0 || result > dest_size || !dest) - return result; - - result = WideCharToMultiByte(CP_UTF8, 0 /*dwFlags*/, src.data, src_size, dest, DN_Cast(int) dest_size, nullptr, nullptr); - dest[DN_Min(result, dest_size - 1)] = 0; - return result; -} - -DN_API DN_Str8 DN_W32_Str16ToStr8(DN_Arena *arena, DN_Str16 src) -{ - DN_Str8 result = {}; - if (!arena || src.size == 0) - return result; - - int src_size = DN_SaturateCastISizeToInt(src.size); - if (src_size <= 0) - return result; - - int required_size = WideCharToMultiByte(CP_UTF8, 0 /*dwFlags*/, src.data, src_size, nullptr /*dest*/, 0 /*dest size*/, nullptr, nullptr); - if (required_size <= 0) - return result; - - // NOTE: Str8 allocate ensures there's one extra byte for - // null-termination already so no-need to +1 the required size - DN_ArenaTempMemScope temp_mem = DN_ArenaTempMemScope(arena); - DN_Str8 buffer = DN_Str8FromArena(arena, required_size, DN_ZMem_No); - if (buffer.size == 0) - return result; - - int chars_written = WideCharToMultiByte(CP_UTF8, 0 /*dwFlags*/, src.data, src_size, buffer.data, DN_Cast(int) buffer.size, nullptr, nullptr); - if (DN_Check(chars_written == required_size)) { - result = buffer; - result.data[result.size] = 0; - temp_mem.mem = {}; - } - - return result; -} - -DN_API DN_Str8 DN_W32_Str16ToStr8FromHeap(DN_Str16 src) -{ - DN_Str8 result = {}; - if (src.size == 0) - return result; - - int src_size = DN_SaturateCastISizeToInt(src.size); - if (src_size <= 0) - return result; - - int required_size = WideCharToMultiByte(CP_UTF8, 0 /*dwFlags*/, src.data, src_size, nullptr /*dest*/, 0 /*dest size*/, nullptr, nullptr); - if (required_size <= 0) - return result; - - // NOTE: Str8 allocate ensures there's one extra byte for - // null-termination already so no-need to +1 the required size - DN_Str8 buffer = DN_Str8FromHeap(required_size, DN_ZMem_No); - if (buffer.size == 0) - return result; - - int chars_written = WideCharToMultiByte(CP_UTF8, 0 /*dwFlags*/, src.data, src_size, buffer.data, DN_Cast(int) buffer.size, nullptr, nullptr); - if (DN_Check(chars_written == required_size)) { - result = buffer; - result.data[result.size] = 0; - } else { - DN_OS_MemDealloc(buffer.data); - buffer = {}; - } - - return result; -} - -// NOTE: Windows Executable Directory ////////////////////////////////////////// -DN_API DN_Str16 DN_W32_EXEPathW(DN_Arena *arena) -{ - DN_OSTLSTMem tmem = DN_OS_TLSTMem(arena); - DN_Str16 result = {}; - DN_USize module_size = 0; - wchar_t *module_path = nullptr; - do { - module_size += 256; - module_path = DN_ArenaNewArray(tmem.arena, wchar_t, module_size, DN_ZMem_No); - if (!module_path) - return result; - module_size = DN_Cast(DN_USize) GetModuleFileNameW(nullptr /*module*/, module_path, DN_Cast(int) module_size); - } while (GetLastError() == ERROR_INSUFFICIENT_BUFFER); - - DN_USize index_of_last_slash = 0; - for (DN_USize index = module_size - 1; !index_of_last_slash && index < module_size; index--) - index_of_last_slash = module_path[index] == '\\' ? index : 0; - - result.data = DN_ArenaNewArray(arena, wchar_t, module_size + 1, DN_ZMem_No); - result.size = module_size; - DN_Memcpy(result.data, module_path, sizeof(wchar_t) * result.size); - result.data[result.size] = 0; - return result; -} - -DN_API DN_Str16 DN_W32_EXEDirW(DN_Arena *arena) -{ - // TODO(doyle): Implement a DN_Str16_BinarySearchReverse - DN_OSTLSTMem tmem = DN_OS_TLSTMem(arena); - DN_Str16 result = {}; - DN_USize module_size = 0; - wchar_t *module_path = nullptr; - do { - module_size += 256; - module_path = DN_ArenaNewArray(tmem.arena, wchar_t, module_size, DN_ZMem_No); - if (!module_path) - return result; - module_size = DN_Cast(DN_USize) GetModuleFileNameW(nullptr /*module*/, module_path, DN_Cast(int) module_size); - } while (GetLastError() == ERROR_INSUFFICIENT_BUFFER); - - DN_USize index_of_last_slash = 0; - for (DN_USize index = module_size - 1; !index_of_last_slash && index < module_size; index--) - index_of_last_slash = module_path[index] == '\\' ? index : 0; - - result.data = DN_ArenaNewArray(arena, wchar_t, index_of_last_slash + 1, DN_ZMem_No); - result.size = index_of_last_slash; - DN_Memcpy(result.data, module_path, sizeof(wchar_t) * result.size); - result.data[result.size] = 0; - return result; -} - -DN_API DN_Str8 DN_W32_WorkingDir(DN_Arena *arena, DN_Str8 suffix) -{ - DN_OSTLSTMem tmem = DN_OS_TLSTMem(arena); - DN_Str16 suffix16 = DN_W32_Str8ToStr16(tmem.arena, suffix); - DN_Str16 dir16 = DN_W32_WorkingDirW(tmem.arena, suffix16); - DN_Str8 result = DN_W32_Str16ToStr8(arena, dir16); - return result; -} - -DN_API DN_Str16 DN_W32_WorkingDirW(DN_Arena *arena, DN_Str16 suffix) -{ - DN_Assert(suffix.size >= 0); - DN_Str16 result = {}; - - // NOTE: required_size is the size required *including* the null-terminator - DN_OSTLSTMem tmem = DN_OS_TLSTMem(arena); - unsigned long required_size = GetCurrentDirectoryW(0, nullptr); - unsigned long desired_size = required_size + DN_Cast(unsigned long) suffix.size; - - wchar_t *tmem_w_path = DN_ArenaNewArray(tmem.arena, wchar_t, desired_size, DN_ZMem_No); - if (!tmem_w_path) - return result; - - unsigned long bytes_written_wo_null_terminator = GetCurrentDirectoryW(desired_size, tmem_w_path); - if ((bytes_written_wo_null_terminator + 1) != required_size) { - // TODO(dn): Error - return result; - } - - wchar_t *w_path = DN_ArenaNewArray(arena, wchar_t, desired_size, DN_ZMem_No); - if (!w_path) - return result; - - if (suffix.size) { - DN_Memcpy(w_path, tmem_w_path, sizeof(*tmem_w_path) * bytes_written_wo_null_terminator); - DN_Memcpy(w_path + bytes_written_wo_null_terminator, suffix.data, sizeof(suffix.data[0]) * suffix.size); - w_path[desired_size] = 0; - } - - result = DN_Str16{w_path, DN_Cast(DN_USize)(desired_size - 1)}; - return result; -} - -DN_API bool DN_W32_DirWIterate(DN_Str16 path, DN_W32FolderIteratorW *it) -{ - WIN32_FIND_DATAW find_data = {}; - if (it->handle) { - if (FindNextFileW(it->handle, &find_data) == 0) { - FindClose(it->handle); - return false; - } - } else { - it->handle = FindFirstFileExW(path.data, /*LPCWSTR lpFileName,*/ - FindExInfoStandard, /*FINDEX_INFO_LEVELS fInfoLevelId,*/ - &find_data, /*LPVOID lpFindFileData,*/ - FindExSearchNameMatch, /*FINDEX_SEARCH_OPS fSearchOp,*/ - nullptr, /*LPVOID lpSearchFilter,*/ - FIND_FIRST_EX_LARGE_FETCH /*unsigned long dwAdditionalFlags)*/); - - if (it->handle == INVALID_HANDLE_VALUE) - return false; - } - - it->file_name_buf[0] = 0; - it->file_name = DN_Str16{it->file_name_buf, 0}; - - do { - if (find_data.cFileName[0] == '.' || (find_data.cFileName[0] == '.' && find_data.cFileName[1] == '.')) - continue; - - it->file_name.size = DN_CStr16Size(find_data.cFileName); - DN_Assert(it->file_name.size < (DN_ArrayCountU(it->file_name_buf) - 1)); - DN_Memcpy(it->file_name.data, find_data.cFileName, it->file_name.size * sizeof(wchar_t)); - it->file_name_buf[it->file_name.size] = 0; - break; - } while (FindNextFileW(it->handle, &find_data) != 0); - - bool result = it->file_name.size > 0; - if (!result) - FindClose(it->handle); - return result; -} -#else - #error Please define a platform e.g. 'DN_PLATFORM_WIN32' to enable the correct implementation for platform APIs -#endif - -// DN: Single header generator inlined this file => #include "OS/dn_os_stacktrace.cpp" -#define DN_CORE_DEBUG_CPP - -// DN: Single header generator commented out this header => #include "../dn_base_inc.h" -// DN: Single header generator commented out this header => #include "../dn_os_inc.h" - -DN_API DN_StackTraceWalkResult DN_StackTraceWalk(DN_Arena *arena, uint16_t limit) -{ - DN_StackTraceWalkResult result = {}; -#if defined(DN_OS_WIN32) - if (!arena) - return result; - - static DN_TicketMutex mutex = {}; - DN_TicketMutex_Begin(&mutex); - - HANDLE thread = GetCurrentThread(); - result.process = GetCurrentProcess(); - - DN_W32Core *w32 = DN_OS_GetW32Core_(); - if (!w32->sym_initialised) { - w32->sym_initialised = true; - SymSetOptions(SYMOPT_LOAD_LINES); - if (!SymInitialize(result.process, nullptr /*UserSearchPath*/, true /*fInvadeProcess*/)) { - DN_OSTLSTMem tmem = DN_OS_TLSTMem(arena); - DN_W32Error error = DN_W32_LastError(tmem.arena); - DN_LOG_ErrorF("SymInitialize failed, stack trace can not be generated (%lu): %.*s\n", error.code, DN_Str8PrintFmt(error.msg)); - } - } - - 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_FArray raw_frames = {}; - while (raw_frames.size < 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_FArray_Add(&raw_frames, frame.AddrPC.Offset); - } - DN_TicketMutex_End(&mutex); - - result.base_addr = DN_ArenaNewArray(arena, uint64_t, raw_frames.size, DN_ZMem_No); - result.size = DN_Cast(uint16_t) raw_frames.size; - DN_Memcpy(result.base_addr, raw_frames.data, raw_frames.size * sizeof(raw_frames.data[0])); -#else - (void)limit; - (void)arena; -#endif - return result; -} - -static void DN_StackTraceAddWalkToStr8Builder(DN_StackTraceWalkResult const *walk, DN_Str8Builder *builder, DN_USize skip) -{ - DN_StackTraceRawFrame raw_frame = {}; - raw_frame.process = walk->process; - for (DN_USize index = skip; index < walk->size; index++) { - raw_frame.base_addr = walk->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 == walk->size - 1) ? "" : "\n"); - } -} - -DN_API bool DN_StackTraceWalkResultIterate(DN_StackTraceWalkResultIterator *it, DN_StackTraceWalkResult const *walk) -{ - bool result = false; - if (!it || !walk || !walk->base_addr || !walk->process) - return result; - - if (it->index >= walk->size) - return false; - - result = true; - it->raw_frame.process = walk->process; - it->raw_frame.base_addr = walk->base_addr[it->index++]; - return result; -} - -DN_API DN_Str8 DN_StackTraceWalkResultToStr8(DN_Arena *arena, DN_StackTraceWalkResult const *walk, uint16_t skip) -{ - DN_Str8 result{}; - if (!walk || !arena) - return result; - - DN_OSTLSTMem tmem = DN_OS_TLSTMem(arena); - DN_Str8Builder builder = DN_Str8BuilderFromArena(tmem.arena); - DN_StackTraceAddWalkToStr8Builder(walk, &builder, skip); - result = DN_Str8BuilderBuild(&builder, arena); - return result; -} - -DN_API DN_Str8 DN_StackTraceWalkStr8(DN_Arena *arena, uint16_t limit, uint16_t skip) -{ - DN_OSTLSTMem tmem = DN_OS_TLSPushTMem(arena); - DN_StackTraceWalkResult walk = DN_StackTraceWalk(tmem.arena, limit); - DN_Str8 result = DN_StackTraceWalkResultToStr8(arena, &walk, skip); - return result; -} - -DN_API DN_Str8 DN_StackTraceWalkStr8FromHeap(uint16_t limit, uint16_t skip) -{ - // NOTE: We don't use WalkResultToStr8 because that uses the TLS arenas which - // does not use the OS heap. - DN_Arena arena = DN_ArenaFromHeap(DN_Kilobytes(64), DN_ArenaFlags_NoAllocTrack); - DN_Str8Builder builder = DN_Str8BuilderFromArena(&arena); - DN_StackTraceWalkResult walk = DN_StackTraceWalk(&arena, limit); - DN_StackTraceAddWalkToStr8Builder(&walk, &builder, skip); - DN_Str8 result = DN_Str8BuilderBuildFromOSHeap(&builder); - DN_ArenaDeinit(&arena); - return result; -} - -DN_API DN_Slice DN_StackTraceGetFrames(DN_Arena *arena, uint16_t limit) -{ - DN_Slice result = {}; - if (!arena) - return result; - - DN_OSTLSTMem tmem = DN_OS_TLSTMem(arena); - DN_StackTraceWalkResult walk = DN_StackTraceWalk(tmem.arena, limit); - if (!walk.size) - return result; - - DN_USize slice_index = 0; - result = DN_Slice_Alloc(arena, walk.size, DN_ZMem_No); - for (DN_StackTraceWalkResultIterator it = {}; DN_StackTraceWalkResultIterate(&it, &walk);) - result.data[slice_index++] = DN_StackTraceRawFrameToFrame(arena, it.raw_frame); - 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_Str16{line.FileName, DN_CStr16Size(line.FileName)}; - DN_Str16 function_name16 = DN_Str16{symbol->Name, symbol->NameLen}; - - DN_StackTraceFrame result = {}; - result.address = raw_frame.base_addr; - result.line_number = line.LineNumber; - result.file_name = DN_W32_Str16ToStr8(arena, file_name16); - result.function_name = DN_W32_Str16ToStr8(arena, function_name16); - - if (result.function_name.size == 0) - result.function_name = DN_Str8Lit(""); - if (result.file_name.size == 0) - result.file_name = DN_Str8Lit(""); -#else - DN_StackTraceFrame result = {}; -#endif - return result; -} - -DN_API void DN_StackTracePrint(uint16_t limit) -{ - DN_OSTLSTMem tmem = DN_OS_TLSTMem(nullptr); - DN_Slice stack_trace = DN_StackTraceGetFrames(tmem.arena, limit); - for (DN_StackTraceFrame &frame : stack_trace) - DN_OS_PrintErrLnF("%.*s(%I64u): %.*s", DN_Str8PrintFmt(frame.file_name), frame.line_number, DN_Str8PrintFmt(frame.function_name)); -} - -DN_API void DN_StackTraceReloadSymbols() -{ -#if defined(DN_OS_WIN32) - HANDLE process = GetCurrentProcess(); - SymRefreshModuleList(process); -#endif -} -#define DN_INC_CPP - -#if defined(_CLANGD) - // DN: Single header generator inlined this file => #include "dn_inc.h" -#if !defined(DN_INC_H) -#define DN_INC_H - -#if defined(_CLANGD) - // DN: Single header generator commented out this header => #include "dn_base_inc.h" -#if !defined(DN_BASE_INC_H) -#define DN_BASE_INC_H - -// NOTE: DN configuration -// All the following configuration options are optional. If omitted, DN has default behaviours to -// handle the various options. -// -// Platform Target -// Define one of the following directives to configure this library to compile for that platform. -// By default, the library will auto-detect the current host platform and select that as the -// target platform. -// -// DN_PLATFORM_EMSCRIPTEN -// DN_PLATFORM_POSIX -// DN_PLATFORM_WIN32 -// -// For example -// -// #define DN_PLATFORM_WIN32 -// -// Will ensure that is included and the OS layer is implemented using Win32 -// primitives. -// -// Static functions -// All public functions in the DN library are prefixed with the macro '#define DN_API'. By -// default 'DN_API' is not defined to anything. Define -// -// DN_STATIC_API -// -// To replace all the prefixed with 'static' ensuring that the functions in the library do not -// export an entry into the linking table and thereby optimise compilation times as the linker -// will not try to resolve symbols from other translation units from the the unit including the -// DN library. -// -// Using the in-built replacement header for (requires dn_os_inc.h) -// If you are building DN for the Windows platform, is a large legacy header that -// applications have to link to use Windows syscalls. By default DN library uses a replacement -// header for all the Windows functions that it uses in the OS layer removing the need to include -// to improve compilation times. This can be disabled by defining: -// -// DN_NO_WINDOWS_H_REPLACEMENT_HEADER -// -// To instead use . DN automatically detects if is included in an earlier -// translation unit and will automatically disable the in-built replacement header in which case -// this does not need to be defined. -// -// Freestanding -// 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. - -// DN: Single header generator commented out this header => #include "Base/dn_base_compiler.h" -#if !defined(DN_BASE_COMPILER_H) -#define DN_BASE_COMPILER_H - -// NOTE: Compiler identification -// Warning! Order is important here, clang-cl on Windows defines _MSC_VER -#if defined(_MSC_VER) - #if defined(__clang__) - #define DN_COMPILER_CLANG_CL - #define DN_COMPILER_CLANG - #else - #define DN_COMPILER_MSVC - #endif -#elif defined(__clang__) - #define DN_COMPILER_CLANG -#elif defined(__GNUC__) - #define DN_COMPILER_GCC -#endif - -// NOTE: __has_feature -// MSVC for example does not support the feature detection macro for instance so we compile it out -#if defined(__has_feature) - #define DN_HAS_FEATURE(expr) __has_feature(expr) -#else - #define DN_HAS_FEATURE(expr) 0 -#endif - -// NOTE: __has_builtin -// MSVC for example does not support the feature detection macro for instance so we compile it out -#if defined(__has_builtin) - #define DN_HAS_BUILTIN(expr) __has_builtin(expr) -#else - #define DN_HAS_BUILTIN(expr) 0 -#endif - -// NOTE: Warning suppression macros -#if defined(DN_COMPILER_MSVC) - #define DN_MSVC_WARNING_PUSH __pragma(warning(push)) - #define DN_MSVC_WARNING_DISABLE(...) __pragma(warning(disable :##__VA_ARGS__)) - #define DN_MSVC_WARNING_POP __pragma(warning(pop)) -#else - #define DN_MSVC_WARNING_PUSH - #define DN_MSVC_WARNING_DISABLE(...) - #define DN_MSVC_WARNING_POP -#endif - -#if defined(DN_COMPILER_CLANG) || defined(DN_COMPILER_GCC) || defined(DN_COMPILER_CLANG_CL) - #define DN_GCC_WARNING_PUSH _Pragma("GCC diagnostic push") - #define DN_GCC_WARNING_DISABLE_HELPER_0(x) #x - #define DN_GCC_WARNING_DISABLE_HELPER_1(y) DN_GCC_WARNING_DISABLE_HELPER_0(GCC diagnostic ignored #y) - #define DN_GCC_WARNING_DISABLE(warning) _Pragma(DN_GCC_WARNING_DISABLE_HELPER_1(warning)) - #define DN_GCC_WARNING_POP _Pragma("GCC diagnostic pop") -#else - #define DN_GCC_WARNING_PUSH - #define DN_GCC_WARNING_DISABLE(...) - #define DN_GCC_WARNING_POP -#endif - -// NOTE: Host OS identification -#if defined(_WIN32) - #define DN_OS_WIN32 -#elif defined(__gnu_linux__) || defined(__linux__) - #define DN_OS_UNIX -#endif - -// NOTE: Platform identification -#if !defined(DN_PLATFORM_EMSCRIPTEN) && \ - !defined(DN_PLATFORM_POSIX) && \ - !defined(DN_PLATFORM_WIN32) - #if defined(__aarch64__) || defined(_M_ARM64) - #define DN_PLATFORM_ARM64 - #elif defined(__EMSCRIPTEN__) - #define DN_PLATFORM_EMSCRIPTEN - #elif defined(DN_OS_WIN32) - #define DN_PLATFORM_WIN32 - #else - #define DN_PLATFORM_POSIX - #endif -#endif - -// NOTE: Windows crap -#if defined(DN_COMPILER_MSVC) || defined(DN_COMPILER_CLANG_CL) - #if defined(_CRT_SECURE_NO_WARNINGS) - #define DN_CRT_SECURE_NO_WARNINGS_PREVIOUSLY_DEFINED - #else - #define _CRT_SECURE_NO_WARNINGS - #endif -#endif - -// NOTE: Force Inline -#if defined(DN_COMPILER_MSVC) || defined(DN_COMPILER_CLANG_CL) - #define DN_FORCE_INLINE __forceinline -#else - #define DN_FORCE_INLINE inline __attribute__((always_inline)) -#endif - -// NOTE: Function/Variable Annotations -#if defined(DN_STATIC_API) - #define DN_API static -#else - #define DN_API -#endif - -// NOTE: C/CPP Literals -// Declare struct literals that work in both C and C++ because the syntax is different between -// languages. -#if 0 - struct Foo { int a; } - struct Foo foo = DN_LITERAL(Foo){32}; // Works on both C and C++ -#endif - -#if defined(__cplusplus) - #define DN_Literal(T) T -#else - #define DN_Literal(T) (T) -#endif - -// NOTE: Thread Locals -#if defined(__cplusplus) - #define DN_THREAD_LOCAL thread_local -#else - #define DN_THREAD_LOCAL _Thread_local -#endif - -// NOTE: C variadic argument annotations -// TODO: Other compilers -#if defined(DN_COMPILER_MSVC) - #define DN_FMT_ATTRIB _Printf_format_string_ -#else - #define DN_FMT_ATTRIB -#endif - -// NOTE: Type Cast -#define DN_Cast(val) (val) - -// NOTE: Zero initialisation macro -#if defined(__cplusplus) - #define DN_ZeroInit {} -#else - #define DN_ZeroInit {0} -#endif - -// NOTE: Address sanitizer -#if !defined(DN_ASAN_POISON) - #define DN_ASAN_POISON 0 -#endif - -#if !defined(DN_ASAN_VET_POISON) - #define DN_ASAN_VET_POISON 0 -#endif - -#define DN_ASAN_POISON_ALIGNMENT 8 - -#if !defined(DN_ASAN_POISON_GUARD_SIZE) - #define DN_ASAN_POISON_GUARD_SIZE 128 -#endif - -#if DN_HAS_FEATURE(address_sanitizer) || defined(__SANITIZE_ADDRESS__) - #include -#endif -#endif // !defined(DN_BASE_COMPILER_H) -// DN: Single header generator commented out this header => #include "Base/dn_base.h" -#if !defined(DN_BASE_H) -#define DN_BASE_H - -#if defined(_CLANGD) - // DN: Single header generator commented out this header => #include "../dn_base_inc.h" -#endif - -// NOTE: Macros -#define DN_Stringify(x) #x -#define DN_TokenCombine2(x, y) x ## y -#define DN_TokenCombine(x, y) DN_TokenCombine2(x, y) - -#include // va_list -#include -#include -#include -#include // PRIu64... - -#if !defined(DN_OS_WIN32) -#include // exit() -#endif - -#define DN_ForIndexU(index, size) DN_USize index = 0; index < size; index++ -#define DN_ForIndexI(index, size) DN_ISize index = 0; index < size; index++ -#define DN_ForItSize(it, T, array, size) struct { DN_USize index; T *data; } it = {0, &(array)[0]}; it.index < (size); it.index++, it.data = (array) + it.index -#define DN_ForItSizeReverse(it, T, array, size) struct { DN_USize index; T *data; } it = {(size) - 1, &(array)[size - 1]}; it.index < (size); it.index--, it.data = (array) + it.index -#define DN_ForIt(it, T, array) struct { DN_USize index; T *data; } it = {0, &(array)->data[0]}; it.index < (array)->size; it.index++, it.data = ((array)->data) + it.index -#define DN_ForLinkedListIt(it, T, list) struct { DN_USize index; T *data; } it = {0, list}; it.data; it.index++, it.data = ((it).data->next) -#define DN_ForItCArray(it, T, array) struct { DN_USize index; T *data; } it = {0, &(array)[0]}; it.index < DN_ArrayCountU(array); it.index++, it.data = (array) + it.index - -#define DN_AlignUpPowerOfTwo(value, pot) (((uintptr_t)(value) + ((uintptr_t)(pot) - 1)) & ~((uintptr_t)(pot) - 1)) -#define DN_AlignDownPowerOfTwo(value, pot) ((uintptr_t)(value) & ~((uintptr_t)(pot) - 1)) -#define DN_IsPowerOfTwo(value) ((((uintptr_t)(value)) & (((uintptr_t)(value)) - 1)) == 0) -#define DN_IsPowerOfTwoAligned(value, pot) ((((uintptr_t)value) & (((uintptr_t)pot) - 1)) == 0) - -// NOTE: String.h Dependencies -#if !defined(DN_Memcpy) || !defined(DN_Memset) || !defined(DN_Memcmp) || !defined(DN_Memmove) - #include - #if !defined(DN_Memcpy) - #define DN_Memcpy(dest, src, count) memcpy((dest), (src), (count)) - #endif - #if !defined(DN_Memset) - #define DN_Memset(dest, value, count) memset((dest), (value), (count)) - #endif - #if !defined(DN_Memcmp) - #define DN_Memcmp(lhs, rhs, count) memcmp((lhs), (rhs), (count)) - #endif - #if !defined(DN_Memmove) - #define DN_Memmove(dest, src, count) memmove((dest), (src), (count)) - #endif -#endif - -// NOTE: Math.h Dependencies -#if !defined(DN_SqrtF32) || !defined(DN_SinF32) || !defined(DN_CosF32) || !defined(DN_TanF32) - #include - #if !defined(DN_SqrtF32) - #define DN_SqrtF32(val) sqrtf(val) - #endif - #if !defined(DN_SinF32) - #define DN_SinF32(val) sinf(val) - #endif - #if !defined(DN_CosF32) - #define DN_CosF32(val) cosf(val) - #endif - #if !defined(DN_TanF32) - #define DN_TanF32(val) tanf(val) - #endif -#endif - -// NOTE: Math -#define DN_PiF32 3.14159265359f - -#define DN_DegreesToRadians(degrees) ((degrees) * (DN_PI / 180.0f)) -#define DN_RadiansToDegrees(radians) ((radians) * (180.f * DN_PI)) - -#define DN_Abs(val) (((val) < 0) ? (-(val)) : (val)) -#define DN_Max(a, b) (((a) > (b)) ? (a) : (b)) -#define DN_Min(a, b) (((a) < (b)) ? (a) : (b)) -#define DN_Clamp(val, lo, hi) DN_Max(DN_Min(val, hi), lo) -#define DN_Squared(val) ((val) * (val)) - -#define DN_Swap(a, b) \ - do { \ - auto temp = a; \ - a = b; \ - b = temp; \ - } while (0) - -// NOTE: Size -#define DN_SizeOfI(val) DN_Cast(ptrdiff_t)sizeof(val) -#define DN_ArrayCountU(array) (sizeof(array)/(sizeof((array)[0]))) -#define DN_ArrayCountI(array) (DN_ISize)DN_ArrayCountU(array) -#define DN_CharCountU(string) (sizeof(string) - 1) - -// NOTE: SI Byte -#define DN_Bytes(val) ((DN_U64)val) -#define DN_Kilobytes(val) ((DN_U64)1024 * DN_Bytes(val)) -#define DN_Megabytes(val) ((DN_U64)1024 * DN_Kilobytes(val)) -#define DN_Gigabytes(val) ((DN_U64)1024 * DN_Megabytes(val)) - -// NOTE: Time -#define DN_MsFromSec(val) ((val) * 1000ULL) -#define DN_SecFromMins(val) ((val) * 60ULL) -#define DN_SecFromHours(val) (DN_SecFromMins(val) * 60ULL) -#define DN_SecFromDays(val) (DN_SecFromHours(val) * 24ULL) -#define DN_SecFromWeeks(val) (DN_SecFromDays(val) * 7ULL) -#define DN_SecFromYears(val) (DN_SecFromWeeks(val) * 52ULL) - -// NOTE: Debug Break -#if !defined(DN_DebugBreak) - #if defined(NDEBUG) - #define DN_DebugBreak - #else - #if defined(DN_COMPILER_MSVC) || defined(DN_COMPILER_CLANG_CL) - #define DN_DebugBreak __debugbreak() - #elif DN_HAS_BUILTIN(__builtin_debugtrap) - #define DN_DebugBreak __builtin_debugtrap() - #elif DN_HAS_BUILTIN(__builtin_trap) || defined(DN_COMPILER_GCC) - #define DN_DebugBreak __builtin_trap() - #else - #include - #if defined(SIGTRAP) - #define DN_DebugBreak raise(SIGTRAP) - #else - #define DN_DebugBreak raise(SIGABRT) - #endif - #endif - #endif -#endif - -// NOTE: Byte swaps -#define DN_ByteSwap64(u64) (((((u64) >> 56) & 0xFF) << 0) | \ - ((((u64) >> 48) & 0xFF) << 8) | \ - ((((u64) >> 40) & 0xFF) << 16) | \ - ((((u64) >> 32) & 0xFF) << 24) | \ - ((((u64) >> 24) & 0xFF) << 32) | \ - ((((u64) >> 16) & 0xFF) << 40) | \ - ((((u64) >> 8) & 0xFF) << 48) | \ - ((((u64) >> 0) & 0xFF) << 56)) - -// NOTE: Types -typedef intptr_t DN_ISize; -typedef uintptr_t DN_USize; - -typedef int8_t DN_I8; -typedef int16_t DN_I16; -typedef int32_t DN_I32; -typedef int64_t DN_I64; - -typedef uint8_t DN_U8; -typedef uint16_t DN_U16; -typedef uint32_t DN_U32; -typedef uint64_t DN_U64; - -typedef uintptr_t DN_UPtr; -typedef float DN_F32; -typedef double DN_F64; -typedef unsigned int DN_UInt; -typedef DN_I32 DN_B32; - -#define DN_F32_MAX 3.402823466e+38F -#define DN_F32_MIN 1.175494351e-38F -#define DN_F64_MAX 1.7976931348623158e+308 -#define DN_F64_MIN 2.2250738585072014e-308 -#define DN_USIZE_MAX UINTPTR_MAX -#define DN_ISIZE_MAX INTPTR_MAX -#define DN_ISIZE_MIN INTPTR_MIN - -enum DN_ZMem -{ - DN_ZMem_No, // Memory can be handed out without zero-ing it out - DN_ZMem_Yes, // Memory should be zero-ed out before giving to the callee -}; - -struct DN_Str8 -{ - char *data; // The bytes of the string - DN_USize size; // The number of bytes in the string -}; - -struct DN_Str8x16 { char data[16]; DN_USize size; }; -struct DN_Str8x32 { char data[32]; DN_USize size; }; -struct DN_Str8x64 { char data[64]; DN_USize size; }; -struct DN_Str8x128 { char data[128]; DN_USize size; }; -struct DN_Str8x256 { char data[256]; DN_USize size; }; - -struct DN_Hex32 { char data[32]; }; -struct DN_Hex64 { char data[64]; }; -struct DN_Hex128 { char data[128]; }; - -struct DN_HexU64Str8 -{ - char data[(sizeof(DN_U64) * 2) + 1 /*null-terminator*/]; - DN_U8 size; -}; - -enum DN_HexFromU64Type -{ - DN_HexFromU64Type_Nil, - DN_HexFromU64Type_Uppercase, -}; - -struct DN_Str16 // A pointer and length style string that holds slices to UTF16 bytes. -{ - wchar_t *data; // The UTF16 bytes of the string - DN_USize size; // The number of characters in the string -}; - -struct DN_U8x16 { DN_U8 data[16]; }; -struct DN_U8x32 { DN_U8 data[32]; }; -struct DN_U8x64 { DN_U8 data[64]; }; - -template -struct DN_Slice // A pointer and length container of data -{ - T *data; - DN_USize size; - - T *begin() { return data; } - T *end() { return data + size; } - T const *begin() const { return data; } - T const *end() const { return data + size; } -}; - -struct DN_CallSite -{ - DN_Str8 file; - DN_Str8 function; - DN_U32 line; -}; - -#define DN_CALL_SITE DN_CallSite { DN_Str8Lit(__FILE__), DN_Str8Lit(__func__), __LINE__ } - -// NOTE: Defer Macro -#if defined(__cplusplus) -template -struct DN_Defer -{ - Procedure proc; - DN_Defer(Procedure p) : proc(p) {} - ~DN_Defer() { proc(); } -}; - -struct DN_DeferHelper -{ - template - DN_Defer operator+(Lambda lambda) { return DN_Defer(lambda); }; -}; - -#define DN_UniqueName(prefix) DN_TokenCombine(prefix, __LINE__) -#define DN_DEFER const auto DN_UniqueName(defer_lambda_) = DN_DeferHelper() + [&]() -#endif // defined(__cplusplus) - -#define DN_DeferLoop(begin, end) \ - bool DN_UniqueName(once) = (begin, true); \ - DN_UniqueName(once); \ - end, DN_UniqueName(once) = false - - -// NOTE: Intrinsics -// NOTE: DN_AtomicAdd/Exchange return the previous value store in the target -#if defined(DN_COMPILER_MSVC) || defined(DN_COMPILER_CLANG_CL) - #include - #define DN_AtomicCompareExchange64(dest, desired_val, prev_val) _InterlockedCompareExchange64((__int64 volatile *)dest, desired_val, prev_val) - #define DN_AtomicCompareExchange32(dest, desired_val, prev_val) _InterlockedCompareExchange((long volatile *)dest, desired_val, prev_val) - - #define DN_AtomicLoadU64(target) *(target) - #define DN_AtomicLoadU32(target) *(target) - #define DN_AtomicAddU32(target, value) _InterlockedExchangeAdd((long volatile *)target, value) - #define DN_AtomicAddU64(target, value) _InterlockedExchangeAdd64((__int64 volatile *)target, value) - #define DN_AtomicSubU32(target, value) DN_AtomicAddU32(DN_Cast(long volatile *) target, (long)-value) - #define DN_AtomicSubU64(target, value) DN_AtomicAddU64(target, (DN_U64) - value) - - #define DN_CountLeadingZerosU64(value) __lzcnt64(value) - #define DN_CountLeadingZerosU32(value) __lzcnt(value) - #define DN_CPUGetTSC() __rdtsc() - #define DN_CompilerReadBarrierAndCPUReadFence _ReadBarrier(); _mm_lfence() - #define DN_CompilerWriteBarrierAndCPUWriteFence _WriteBarrier(); _mm_sfence() -#elif defined(DN_COMPILER_GCC) || defined(DN_COMPILER_CLANG) - #if defined(__ANDROID__) - #elif defined(DN_PLATFORM_EMSCRIPTEN) - #if !defined(__wasm_simd128__) - #error DN_Base requires -msse2 to be passed to Emscripten - #endif - #include - #else - #include - #endif - - #define DN_AtomicLoadU64(target) __atomic_load_n(x, __ATOMIC_SEQ_CST) - #define DN_AtomicLoadU32(target) __atomic_load_n(x, __ATOMIC_SEQ_CST) - #define DN_AtomicAddU32(target, value) __atomic_fetch_add(target, value, __ATOMIC_ACQ_REL) - #define DN_AtomicAddU64(target, value) __atomic_fetch_add(target, value, __ATOMIC_ACQ_REL) - #define DN_AtomicSubU32(target, value) __atomic_fetch_sub(target, value, __ATOMIC_ACQ_REL) - #define DN_AtomicSubU64(target, value) __atomic_fetch_sub(target, value, __ATOMIC_ACQ_REL) - - #define DN_CountLeadingZerosU64(value) __builtin_clzll(value) - #define DN_CountLeadingZerosU32(value) __builtin_clzl(value) - - #if defined(DN_COMPILER_GCC) - #define DN_CPUGetTSC() __rdtsc() - #else - #define DN_CPUGetTSC() __builtin_readcyclecounter() - #endif - - #if defined(DN_PLATFORM_EMSCRIPTEN) - #define DN_CompilerReadBarrierAndCPUReadFence - #define DN_CompilerWriteBarrierAndCPUWriteFence - #else - #define DN_CompilerReadBarrierAndCPUReadFence asm volatile("lfence" ::: "memory") - #define DN_CompilerWriteBarrierAndCPUWriteFence asm volatile("sfence" ::: "memory") - #endif -#else - #error "Compiler not supported" -#endif - -#if defined(__aarch64__) || defined(_M_X64) || defined(__x86_64__) || defined(__x86_64) - #define DN_CountLeadingZerosUSize(value) DN_CountLeadingZerosU64(value) -#else - #define DN_CountLeadingZerosUSize(value) DN_CountLeadingZerosU32(value) -#endif - -struct DN_CPURegisters -{ - int eax; - int ebx; - int ecx; - int edx; -}; - -union DN_CPUIDResult -{ - DN_CPURegisters reg; - int values[4]; -}; - -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) - -enum DN_CPUFeature -{ - #define DN_CPU_FEAT_XENTRY(label) DN_CPUFeature_##label, - DN_CPU_FEAT_XMACRO - #undef DN_CPU_FEAT_XENTRY - DN_CPUFeature_Count, -}; - -struct DN_CPUFeatureDecl -{ - DN_CPUFeature value; - DN_Str8 label; -}; - -struct DN_CPUFeatureQuery -{ - DN_CPUFeature feature; - bool available; -}; - -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]; -}; - -struct DN_TicketMutex -{ - unsigned int volatile ticket; // The next ticket to give out to the thread taking the mutex - unsigned int volatile serving; // The ticket ID to block the mutex on until it is returned -}; - -struct DN_U64FromResult -{ - bool success; - DN_U64 value; -}; - -struct DN_I64FromResult -{ - bool success; - DN_I64 value; -}; - -enum DN_MemCommit -{ - DN_MemCommit_No, - DN_MemCommit_Yes, -}; - -typedef DN_U32 DN_MemPage; -enum DN_MemPage_ -{ - // Exception on read/write with a page. This flag overrides the read/write - // access. - DN_MemPage_NoAccess = 1 << 0, - - DN_MemPage_Read = 1 << 1, // Only read permitted on the page. - - // Only write permitted on the page. On Windows this is not supported and - // will be promoted to read+write permissions. - DN_MemPage_Write = 1 << 2, - - DN_MemPage_ReadWrite = DN_MemPage_Read | DN_MemPage_Write, - - // Modifier used in conjunction with previous flags. Raises exception on - // first access to the page, then, the underlying protection flags are - // active. This is supported on Windows, on other OS's using this flag will - // set the OS equivalent of DN_MemPage_NoAccess. - // This flag must only be used in DN_Mem_Protect - DN_MemPage_Guard = 1 << 3, - - // If leak tracing is enabled, this flag will allow the allocation recorded - // from the reserve call to be leaked, e.g. not printed when leaks are - // dumped to the console. - DN_MemPage_AllocRecordLeakPermitted = 1 << 4, - - // If leak tracing is enabled this flag will prevent any allocation record - // from being created in the allocation table at all. If this flag is - // enabled, 'OSMemPage_AllocRecordLeakPermitted' has no effect since the - // record will never be created. - DN_MemPage_NoAllocRecordEntry = 1 << 5, - - // [INTERNAL] Do not use. All flags together do not constitute a correct - // configuration of pages. - DN_MemPage_All = DN_MemPage_NoAccess | - DN_MemPage_ReadWrite | - DN_MemPage_Guard | - DN_MemPage_AllocRecordLeakPermitted | - DN_MemPage_NoAllocRecordEntry, -}; - -#if !defined(DN_ARENA_RESERVE_SIZE) - #define DN_ARENA_RESERVE_SIZE DN_Megabytes(64) -#endif - -#if !defined(DN_ARENA_COMMIT_SIZE) - #define DN_ARENA_COMMIT_SIZE DN_Kilobytes(64) -#endif - -enum DN_Allocator -{ - DN_Allocator_Arena, - DN_Allocator_Pool, -}; - -struct DN_ArenaBlock -{ - DN_ArenaBlock *prev; - DN_U64 used; - DN_U64 commit; - DN_U64 reserve; - DN_U64 reserve_sum; -}; - -typedef DN_U32 DN_ArenaFlags; -enum DN_ArenaFlags_ -{ - DN_ArenaFlags_Nil = 0, - DN_ArenaFlags_NoGrow = 1 << 0, - DN_ArenaFlags_NoPoison = 1 << 1, - DN_ArenaFlags_NoAllocTrack = 1 << 2, - DN_ArenaFlags_AllocCanLeak = 1 << 3, - - // NOTE: Internal flags. Do not use - DN_ArenaFlags_UserBuffer = 1 << 4, - DN_ArenaFlags_MemFuncs = 1 << 5, -}; - -struct DN_ArenaInfo -{ - DN_U64 used; - DN_U64 commit; - DN_U64 reserve; - DN_U64 blocks; -}; - -struct DN_ArenaStats -{ - DN_ArenaInfo info; - DN_ArenaInfo hwm; -}; - -struct DN_ArenaStatsStr8x64 -{ - DN_Str8x64 info; - DN_Str8x64 hwm; -}; - -enum DN_ArenaMemFuncType -{ - DN_ArenaMemFuncType_Nil, - DN_ArenaMemFuncType_Basic, - DN_ArenaMemFuncType_VMem, -}; - -typedef void *(DN_ArenaMemBasicAllocFunc)(DN_USize size); -typedef void (DN_ArenaMemBasicDeallocFunc)(void *ptr); -typedef void *(DN_ArenaMemVMemReserveFunc)(DN_USize size, DN_MemCommit commit, DN_MemPage page_flags); -typedef bool (DN_ArenaMemVMemCommitFunc)(void *ptr, DN_USize size, DN_U32 page_flags); -typedef void (DN_ArenaMemVMemReleaseFunc)(void *ptr, DN_USize size); -struct DN_ArenaMemFuncs -{ - DN_ArenaMemFuncType type; - DN_ArenaMemBasicAllocFunc *basic_alloc; - DN_ArenaMemBasicDeallocFunc *basic_dealloc; - - DN_U32 vmem_page_size; - DN_ArenaMemVMemReserveFunc *vmem_reserve; - DN_ArenaMemVMemCommitFunc *vmem_commit; - DN_ArenaMemVMemReleaseFunc *vmem_release; -}; - -struct DN_Arena -{ - DN_ArenaMemFuncs mem_funcs; - DN_ArenaBlock *curr; - DN_ArenaStats stats; - DN_ArenaFlags flags; - DN_Str8 label; - DN_Arena *prev, *next; -}; - -struct DN_ArenaTempMem -{ - DN_Arena *arena; - DN_U64 used_sum; -}; - -struct DN_ArenaTempMemScope -{ - DN_ArenaTempMemScope(DN_Arena *arena); - ~DN_ArenaTempMemScope(); - DN_ArenaTempMem mem; -}; - -DN_USize const DN_ARENA_HEADER_SIZE = DN_AlignUpPowerOfTwo(sizeof(DN_Arena), 64); - -#if !defined(DN_POOL_DEFAULT_ALIGN) - #define DN_POOL_DEFAULT_ALIGN 16 -#endif - -struct DN_PoolSlot -{ - void *data; - DN_PoolSlot *next; -}; - -enum DN_PoolSlotSize -{ - DN_PoolSlotSize_32B, - DN_PoolSlotSize_64B, - DN_PoolSlotSize_128B, - DN_PoolSlotSize_256B, - DN_PoolSlotSize_512B, - DN_PoolSlotSize_1KiB, - DN_PoolSlotSize_2KiB, - DN_PoolSlotSize_4KiB, - DN_PoolSlotSize_8KiB, - DN_PoolSlotSize_16KiB, - DN_PoolSlotSize_32KiB, - DN_PoolSlotSize_64KiB, - DN_PoolSlotSize_128KiB, - DN_PoolSlotSize_256KiB, - DN_PoolSlotSize_512KiB, - DN_PoolSlotSize_1MiB, - DN_PoolSlotSize_2MiB, - DN_PoolSlotSize_4MiB, - DN_PoolSlotSize_8MiB, - DN_PoolSlotSize_16MiB, - DN_PoolSlotSize_32MiB, - DN_PoolSlotSize_64MiB, - DN_PoolSlotSize_128MiB, - DN_PoolSlotSize_256MiB, - DN_PoolSlotSize_512MiB, - DN_PoolSlotSize_1GiB, - DN_PoolSlotSize_2GiB, - DN_PoolSlotSize_4GiB, - DN_PoolSlotSize_8GiB, - DN_PoolSlotSize_16GiB, - DN_PoolSlotSize_32GiB, - DN_PoolSlotSize_Count, -}; - -struct DN_Pool -{ - DN_Arena *arena; - DN_PoolSlot *slots[DN_PoolSlotSize_Count]; - DN_U8 align; -}; - -struct DN_NibbleFromU8Result -{ - char nibble0; - char nibble1; -}; - -enum DN_Str8EqCase -{ - DN_Str8EqCase_Sensitive, - DN_Str8EqCase_Insensitive, -}; - -enum DN_Str8IsAllType -{ - DN_Str8IsAllType_Digits, - DN_Str8IsAllType_Hex, -}; - -struct DN_Str8BSplitResult -{ - DN_Str8 lhs; - DN_Str8 rhs; -}; - -struct DN_Str8FindResult -{ - bool found; // True if string was found. If false, the subsequent fields below are not set. - DN_USize index; // Index in the buffer where the found string starts - DN_Str8 match; // Matching string in the buffer that was searched - DN_Str8 match_to_end_of_buffer; // Substring containing the found string to the end of the buffer - DN_Str8 after_match_to_end_of_buffer; // Substring starting after the found string to the end of the buffer - DN_Str8 start_to_before_match; // Substring from the start of the buffer up until the found string, not including it -}; - -enum DN_Str8FindFlag -{ - DN_Str8FindFlag_Digit = 1 << 0, // 0-9 - DN_Str8FindFlag_Whitespace = 1 << 1, // '\r', '\t', '\n', ' ' - DN_Str8FindFlag_Alphabet = 1 << 2, // A-Z, a-z - DN_Str8FindFlag_Plus = 1 << 3, // + - DN_Str8FindFlag_Minus = 1 << 4, // - - DN_Str8FindFlag_AlphaNum = DN_Str8FindFlag_Alphabet | DN_Str8FindFlag_Digit, -}; - -enum DN_Str8SplitIncludeEmptyStrings -{ - DN_Str8SplitIncludeEmptyStrings_No, - DN_Str8SplitIncludeEmptyStrings_Yes, -}; - -struct DN_Str8TruncateResult -{ - bool truncated; - DN_Str8 str8; -}; - -struct DN_Str8SplitResult -{ - DN_Str8 *data; - DN_USize count; -}; - -struct DN_Str8Link -{ - DN_Str8 string; // The string - DN_Str8Link *next; // The next string in the linked list - DN_Str8Link *prev; // The prev string in the linked list -}; - -struct DN_Str8Builder -{ - DN_Arena *arena; // Allocator to use to back the string list - DN_Str8Link *head; // First string in the linked list of strings - DN_Str8Link *tail; // Last string in the linked list of strings - DN_USize string_size; // The size in bytes necessary to construct the current string - DN_USize count; // The number of links in the linked list of strings -}; - -enum DN_Str8BuilderAdd -{ - DN_Str8BuilderAdd_Append, - DN_Str8BuilderAdd_Prepend, -}; - -typedef DN_U32 DN_AgeUnit; -enum DN_AgeUnit_ -{ - DN_AgeUnit_Ms = 1 << 0, - DN_AgeUnit_Sec = 1 << 1, - DN_AgeUnit_Min = 1 << 2, - DN_AgeUnit_Hr = 1 << 3, - DN_AgeUnit_Day = 1 << 4, - DN_AgeUnit_Week = 1 << 5, - DN_AgeUnit_Year = 1 << 6, - DN_AgeUnit_FractionalSec = 1 << 7, - DN_AgeUnit_HMS = DN_AgeUnit_Sec | DN_AgeUnit_Min | DN_AgeUnit_Hr, - DN_AgeUnit_All = DN_AgeUnit_Ms | DN_AgeUnit_HMS | DN_AgeUnit_Day | DN_AgeUnit_Week | DN_AgeUnit_Year, -}; - -enum DN_ByteCountType -{ - DN_ByteCountType_B, - DN_ByteCountType_KiB, - DN_ByteCountType_MiB, - DN_ByteCountType_GiB, - DN_ByteCountType_TiB, - DN_ByteCountType_Count, - DN_ByteCountType_Auto, -}; - -struct DN_ByteCountResult -{ - DN_ByteCountType type; - DN_Str8 suffix; // "KiB", "MiB", "GiB" .. e.t.c - DN_F64 bytes; -}; - -struct DN_Date -{ - DN_U8 day; - DN_U8 month; - DN_U16 year; - DN_U8 hour; - DN_U8 minutes; - DN_U8 seconds; - DN_U16 milliseconds; -}; - -struct DN_FmtAppendResult -{ - DN_USize size_req; - DN_Str8 str8; - bool truncated; -}; - -struct DN_ProfilerAnchor -{ - // Inclusive refers to the time spent to complete the function call - // including all children functions. - // - // Exclusive refers to the time spent in the function, not including any - // time spent in children functions that we call that are also being - // profiled. If we recursively call into ourselves, the time we spent in - // our function is accumulated. - DN_U64 tsc_inclusive; - DN_U64 tsc_exclusive; - DN_U16 hit_count; - DN_Str8 name; -}; - -struct DN_ProfilerZone -{ - DN_U16 anchor_index; - DN_U64 begin_tsc; - DN_U16 parent_zone; - DN_U64 elapsed_tsc_at_zone_start; -}; - -struct DN_ProfilerAnchorArray -{ - DN_ProfilerAnchor *data; - DN_USize count; -}; - -typedef DN_U64 (DN_ProfilerTSCNowFunc)(); -struct DN_Profiler -{ - DN_USize frame_index; - DN_ProfilerAnchor *anchors; - DN_USize anchors_count; - DN_USize anchors_per_frame; - DN_U16 parent_zone; - bool paused; - DN_ProfilerTSCNowFunc *tsc_now; - DN_U64 tsc_frequency; - DN_ProfilerZone frame_zone; - DN_F64 frame_avg_tsc; -}; - -#if !defined(DN_STB_SPRINTF_HEADER_ONLY) - #define STB_SPRINTF_IMPLEMENTATION - #define STB_SPRINTF_STATIC -#endif - -DN_MSVC_WARNING_PUSH -DN_MSVC_WARNING_DISABLE(4505) // Unused function warning -DN_GCC_WARNING_PUSH -DN_GCC_WARNING_DISABLE(-Wunused-function) -// DN: Single header generator commented out this header => #include "../External/stb_sprintf.h" -// NOTE: Additional *unofficial* changes -// - Adding STBSP__ASAN to STBSP__PUBLICDEC so that MSVC's ASAN does not trigger (https://github.com/nothings/stb/pull/1350) -// - Adding __attribute__((no_sanitize("undefined"))) to STBSP__ASAN for CLANG so that UBSAN does not trigger (https://github.com/nothings/stb/pull/1477) -// - Adding '%S' for DN_Str8 -// - Using defined(__wasm64__) to correctly assign stbsp__uintptr to stbsp__uint64 for a 64bit WASM target. - -// stb_sprintf - v1.10 - public domain snprintf() implementation -// originally by Jeff Roberts / RAD Game Tools, 2015/10/20 -// http://github.com/nothings/stb -// -// allowed types: sc uidBboXx p AaGgEef n -// lengths : hh h ll j z t I64 I32 I -// -// Contributors: -// Fabian "ryg" Giesen (reformatting) -// github:aganm (attribute format) -// -// Contributors (bugfixes): -// github:d26435 -// github:trex78 -// github:account-login -// Jari Komppa (SI suffixes) -// Rohit Nirmal -// Marcin Wojdyr -// Leonard Ritter -// Stefano Zanotti -// Adam Allison -// Arvid Gerstmann -// Markus Kolb -// -// LICENSE: -// -// See end of file for license information. - -#ifndef STB_SPRINTF_H_INCLUDE -#define STB_SPRINTF_H_INCLUDE - -/* -Single file sprintf replacement. - -Originally written by Jeff Roberts at RAD Game Tools - 2015/10/20. -Hereby placed in public domain. - -This is a full sprintf replacement that supports everything that -the C runtime sprintfs support, including float/double, 64-bit integers, -hex floats, field parameters (%*.*d stuff), length reads backs, etc. - -Why would you need this if sprintf already exists? Well, first off, -it's *much* faster (see below). It's also much smaller than the CRT -versions code-space-wise. We've also added some simple improvements -that are super handy (commas in thousands, callbacks at buffer full, -for example). Finally, the format strings for MSVC and GCC differ -for 64-bit integers (among other small things), so this lets you use -the same format strings in cross platform code. - -It uses the standard single file trick of being both the header file -and the source itself. If you just include it normally, you just get -the header file function definitions. To get the code, you include -it from a C or C++ file and define STB_SPRINTF_IMPLEMENTATION first. - -It only uses va_args macros from the C runtime to do it's work. It -does cast doubles to S64s and shifts and divides U64s, which does -drag in CRT code on most platforms. - -It compiles to roughly 8K with float support, and 4K without. -As a comparison, when using MSVC static libs, calling sprintf drags -in 16K. - -API: -==== -int stbsp_sprintf( char * buf, char const * fmt, ... ) -int stbsp_snprintf( char * buf, int count, char const * fmt, ... ) - Convert an arg list into a buffer. stbsp_snprintf always returns - a zero-terminated string (unlike regular snprintf). - -int stbsp_vsprintf( char * buf, char const * fmt, va_list va ) -int stbsp_vsnprintf( char * buf, int count, char const * fmt, va_list va ) - Convert a va_list arg list into a buffer. stbsp_vsnprintf always returns - a zero-terminated string (unlike regular snprintf). - -int stbsp_vsprintfcb( STBSP_SPRINTFCB * callback, void * user, char * buf, char const * fmt, va_list va ) - typedef char * STBSP_SPRINTFCB( char const * buf, void * user, int len ); - Convert into a buffer, calling back every STB_SPRINTF_MIN chars. - Your callback can then copy the chars out, print them or whatever. - This function is actually the workhorse for everything else. - The buffer you pass in must hold at least STB_SPRINTF_MIN characters. - // you return the next buffer to use or 0 to stop converting - -void stbsp_set_separators( char comma, char period ) - Set the comma and period characters to use. - -FLOATS/DOUBLES: -=============== -This code uses a internal float->ascii conversion method that uses -doubles with error correction (double-doubles, for ~105 bits of -precision). This conversion is round-trip perfect - that is, an atof -of the values output here will give you the bit-exact double back. - -One difference is that our insignificant digits will be different than -with MSVC or GCC (but they don't match each other either). We also -don't attempt to find the minimum length matching float (pre-MSVC15 -doesn't either). - -If you don't need float or doubles at all, define STB_SPRINTF_NOFLOAT -and you'll save 4K of code space. - -64-BIT INTS: -============ -This library also supports 64-bit integers and you can use MSVC style or -GCC style indicators (%I64d or %lld). It supports the C99 specifiers -for size_t and ptr_diff_t (%jd %zd) as well. - -EXTRAS: -======= -Like some GCCs, for integers and floats, you can use a ' (single quote) -specifier and commas will be inserted on the thousands: "%'d" on 12345 -would print 12,345. - -For integers and floats, you can use a "$" specifier and the number -will be converted to float and then divided to get kilo, mega, giga or -tera and then printed, so "%$d" 1000 is "1.0 k", "%$.2d" 2536000 is -"2.53 M", etc. For byte values, use two $:s, like "%$$d" to turn -2536000 to "2.42 Mi". If you prefer JEDEC suffixes to SI ones, use three -$:s: "%$$$d" -> "2.42 M". To remove the space between the number and the -suffix, add "_" specifier: "%_$d" -> "2.53M". - -In addition to octal and hexadecimal conversions, you can print -integers in binary: "%b" for 256 would print 100. - -PERFORMANCE vs MSVC 2008 32-/64-bit (GCC is even slower than MSVC): -=================================================================== -"%d" across all 32-bit ints (4.8x/4.0x faster than 32-/64-bit MSVC) -"%24d" across all 32-bit ints (4.5x/4.2x faster) -"%x" across all 32-bit ints (4.5x/3.8x faster) -"%08x" across all 32-bit ints (4.3x/3.8x faster) -"%f" across e-10 to e+10 floats (7.3x/6.0x faster) -"%e" across e-10 to e+10 floats (8.1x/6.0x faster) -"%g" across e-10 to e+10 floats (10.0x/7.1x faster) -"%f" for values near e-300 (7.9x/6.5x faster) -"%f" for values near e+300 (10.0x/9.1x faster) -"%e" for values near e-300 (10.1x/7.0x faster) -"%e" for values near e+300 (9.2x/6.0x faster) -"%.320f" for values near e-300 (12.6x/11.2x faster) -"%a" for random values (8.6x/4.3x faster) -"%I64d" for 64-bits with 32-bit values (4.8x/3.4x faster) -"%I64d" for 64-bits > 32-bit values (4.9x/5.5x faster) -"%s%s%s" for 64 char strings (7.1x/7.3x faster) -"...512 char string..." ( 35.0x/32.5x faster!) -*/ - -#if defined(__clang__) - #if defined(__has_feature) && defined(__has_attribute) - #if __has_feature(address_sanitizer) - #if __has_attribute(__no_sanitize__) - #define STBSP__ASAN __attribute__((__no_sanitize__("address"))) - #elif __has_attribute(__no_sanitize_address__) - #define STBSP__ASAN __attribute__((__no_sanitize_address__)) - #elif __has_attribute(__no_address_safety_analysis__) - #define STBSP__ASAN __attribute__((__no_address_safety_analysis__)) - #endif - #endif - #endif -#elif defined(__GNUC__) && (__GNUC__ >= 5 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8)) - #if defined(__SANITIZE_ADDRESS__) && __SANITIZE_ADDRESS__ - #define STBSP__ASAN __attribute__((__no_sanitize_address__)) - #endif -#elif defined(_MSC_VER) - #if defined(__SANITIZE_ADDRESS__) - #define STBSP__ASAN __declspec(no_sanitize_address) - #endif -#endif - -#ifndef STBSP__ASAN -#define STBSP__ASAN -#endif - -#ifdef STB_SPRINTF_STATIC -#define STBSP__PUBLICDEC static STBSP__ASAN -#define STBSP__PUBLICDEF static STBSP__ASAN -#else -#ifdef __cplusplus -#define STBSP__PUBLICDEC extern "C" STBSP__ASAN -#define STBSP__PUBLICDEF extern "C" STBSP__ASAN -#else -#define STBSP__PUBLICDEC extern STBSP__ASAN -#define STBSP__PUBLICDEF STBSP__ASAN -#endif -#endif - -#if defined(__has_attribute) - #if __has_attribute(format) - #define STBSP__ATTRIBUTE_FORMAT(fmt,va) __attribute__((format(printf,fmt,va))) - #endif -#endif - -#ifndef STBSP__ATTRIBUTE_FORMAT -#define STBSP__ATTRIBUTE_FORMAT(fmt,va) -#endif - -#ifdef _MSC_VER -#define STBSP__NOTUSED(v) (void)(v) -#else -#define STBSP__NOTUSED(v) (void)sizeof(v) -#endif - -#include // for va_arg(), va_list() -#include // size_t, ptrdiff_t - -#ifndef STB_SPRINTF_MIN -#define STB_SPRINTF_MIN 512 // how many characters per callback -#endif -typedef char *STBSP_SPRINTFCB(const char *buf, void *user, int len); - -#ifndef STB_SPRINTF_DECORATE -#define STB_SPRINTF_DECORATE(name) stbsp_##name // define this before including if you want to change the names -#endif - -STBSP__PUBLICDEC int STB_SPRINTF_DECORATE(vsprintf)(char *buf, char const *fmt, va_list va); -STBSP__PUBLICDEC int STB_SPRINTF_DECORATE(vsnprintf)(char *buf, int count, char const *fmt, va_list va); -STBSP__PUBLICDEC int STB_SPRINTF_DECORATE(sprintf)(char *buf, char const *fmt, ...) STBSP__ATTRIBUTE_FORMAT(2,3); -STBSP__PUBLICDEC int STB_SPRINTF_DECORATE(snprintf)(char *buf, int count, char const *fmt, ...) STBSP__ATTRIBUTE_FORMAT(3,4); - -STBSP__PUBLICDEC int STB_SPRINTF_DECORATE(vsprintfcb)(STBSP_SPRINTFCB *callback, void *user, char *buf, char const *fmt, va_list va); -STBSP__PUBLICDEC void STB_SPRINTF_DECORATE(set_separators)(char comma, char period); - -#endif // STB_SPRINTF_H_INCLUDE - -#ifdef STB_SPRINTF_IMPLEMENTATION - -#define stbsp__uint32 unsigned int -#define stbsp__int32 signed int - -#ifdef _MSC_VER -#define stbsp__uint64 unsigned __int64 -#define stbsp__int64 signed __int64 -#else -#define stbsp__uint64 unsigned long long -#define stbsp__int64 signed long long -#endif -#define stbsp__uint16 unsigned short - -#ifndef stbsp__uintptr -#if defined(__ppc64__) || defined(__powerpc64__) || defined(__aarch64__) || defined(_M_X64) || defined(__x86_64__) || defined(__x86_64) || defined(__s390x__) || defined(__wasm64__) -#define stbsp__uintptr stbsp__uint64 -#else -#define stbsp__uintptr stbsp__uint32 -#endif -#endif - -#ifndef STB_SPRINTF_MSVC_MODE // used for MSVC2013 and earlier (MSVC2015 matches GCC) -#if defined(_MSC_VER) && (_MSC_VER < 1900) -#define STB_SPRINTF_MSVC_MODE -#endif -#endif - -#ifdef STB_SPRINTF_NOUNALIGNED // define this before inclusion to force stbsp_sprintf to always use aligned accesses -#define STBSP__UNALIGNED(code) -#else -#define STBSP__UNALIGNED(code) code -#endif - -#ifndef STB_SPRINTF_NOFLOAT -// internal float utility functions -static stbsp__int32 stbsp__real_to_str(char const **start, stbsp__uint32 *len, char *out, stbsp__int32 *decimal_pos, double value, stbsp__uint32 frac_digits); -static stbsp__int32 stbsp__real_to_parts(stbsp__int64 *bits, stbsp__int32 *expo, double value); -#define STBSP__SPECIAL 0x7000 -#endif - -static char stbsp__period = '.'; -static char stbsp__comma = ','; -static struct -{ - short temp; // force next field to be 2-byte aligned - char pair[201]; -} stbsp__digitpair = -{ - 0, - "00010203040506070809101112131415161718192021222324" - "25262728293031323334353637383940414243444546474849" - "50515253545556575859606162636465666768697071727374" - "75767778798081828384858687888990919293949596979899" -}; - -STBSP__PUBLICDEF void STB_SPRINTF_DECORATE(set_separators)(char pcomma, char pperiod) -{ - stbsp__period = pperiod; - stbsp__comma = pcomma; -} - -#define STBSP__LEFTJUST 1 -#define STBSP__LEADINGPLUS 2 -#define STBSP__LEADINGSPACE 4 -#define STBSP__LEADING_0X 8 -#define STBSP__LEADINGZERO 16 -#define STBSP__INTMAX 32 -#define STBSP__TRIPLET_COMMA 64 -#define STBSP__NEGATIVE 128 -#define STBSP__METRIC_SUFFIX 256 -#define STBSP__HALFWIDTH 512 -#define STBSP__METRIC_NOSPACE 1024 -#define STBSP__METRIC_1024 2048 -#define STBSP__METRIC_JEDEC 4096 - -static void stbsp__lead_sign(stbsp__uint32 fl, char *sign) -{ - sign[0] = 0; - if (fl & STBSP__NEGATIVE) { - sign[0] = 1; - sign[1] = '-'; - } else if (fl & STBSP__LEADINGSPACE) { - sign[0] = 1; - sign[1] = ' '; - } else if (fl & STBSP__LEADINGPLUS) { - sign[0] = 1; - sign[1] = '+'; - } -} - -static STBSP__ASAN stbsp__uint32 stbsp__strlen_limited(char const *s, stbsp__uint32 limit) -{ - char const * sn = s; - - // get up to 4-byte alignment - for (;;) { - if (((stbsp__uintptr)sn & 3) == 0) - break; - - if (!limit || *sn == 0) - return (stbsp__uint32)(sn - s); - - ++sn; - --limit; - } - - // scan over 4 bytes at a time to find terminating 0 - // this will intentionally scan up to 3 bytes past the end of buffers, - // but becase it works 4B aligned, it will never cross page boundaries - // (hence the STBSP__ASAN markup; the over-read here is intentional - // and harmless) - while (limit >= 4) { - stbsp__uint32 v = *(stbsp__uint32 *)sn; - // bit hack to find if there's a 0 byte in there - if ((v - 0x01010101) & (~v) & 0x80808080UL) - break; - - sn += 4; - limit -= 4; - } - - // handle the last few characters to find actual size - while (limit && *sn) { - ++sn; - --limit; - } - - return (stbsp__uint32)(sn - s); -} - -STBSP__PUBLICDEF int STB_SPRINTF_DECORATE(vsprintfcb)(STBSP_SPRINTFCB *callback, void *user, char *buf, char const *fmt, va_list va) -{ - static char hex[] = "0123456789abcdefxp"; - static char hexu[] = "0123456789ABCDEFXP"; - char *bf; - char const *f; - int tlen = 0; - - bf = buf; - f = fmt; - for (;;) { - stbsp__int32 fw, pr, tz; - stbsp__uint32 fl; - - // macros for the callback buffer stuff - #define stbsp__chk_cb_bufL(bytes) \ - { \ - int len = (int)(bf - buf); \ - if ((len + (bytes)) >= STB_SPRINTF_MIN) { \ - tlen += len; \ - if (0 == (bf = buf = callback(buf, user, len))) \ - goto done; \ - } \ - } - #define stbsp__chk_cb_buf(bytes) \ - { \ - if (callback) { \ - stbsp__chk_cb_bufL(bytes); \ - } \ - } - #define stbsp__flush_cb() \ - { \ - stbsp__chk_cb_bufL(STB_SPRINTF_MIN - 1); \ - } // flush if there is even one byte in the buffer - #define stbsp__cb_buf_clamp(cl, v) \ - cl = v; \ - if (callback) { \ - int lg = STB_SPRINTF_MIN - (int)(bf - buf); \ - if (cl > lg) \ - cl = lg; \ - } - - // fast copy everything up to the next % (or end of string) - for (;;) { - while (((stbsp__uintptr)f) & 3) { - schk1: - if (f[0] == '%') - goto scandd; - schk2: - if (f[0] == 0) - goto endfmt; - stbsp__chk_cb_buf(1); - *bf++ = f[0]; - ++f; - } - for (;;) { - // Check if the next 4 bytes contain %(0x25) or end of string. - // Using the 'hasless' trick: - // https://graphics.stanford.edu/~seander/bithacks.html#HasLessInWord - stbsp__uint32 v, c; - v = *(stbsp__uint32 *)f; - c = (~v) & 0x80808080; - if (((v ^ 0x25252525) - 0x01010101) & c) - goto schk1; - if ((v - 0x01010101) & c) - goto schk2; - if (callback) - if ((STB_SPRINTF_MIN - (int)(bf - buf)) < 4) - goto schk1; - #ifdef STB_SPRINTF_NOUNALIGNED - if(((stbsp__uintptr)bf) & 3) { - bf[0] = f[0]; - bf[1] = f[1]; - bf[2] = f[2]; - bf[3] = f[3]; - } else - #endif - { - *(stbsp__uint32 *)bf = v; - } - bf += 4; - f += 4; - } - } - scandd: - - ++f; - - // ok, we have a percent, read the modifiers first - fw = 0; - pr = -1; - fl = 0; - tz = 0; - - // flags - for (;;) { - switch (f[0]) { - // if we have left justify - case '-': - fl |= STBSP__LEFTJUST; - ++f; - continue; - // if we have leading plus - case '+': - fl |= STBSP__LEADINGPLUS; - ++f; - continue; - // if we have leading space - case ' ': - fl |= STBSP__LEADINGSPACE; - ++f; - continue; - // if we have leading 0x - case '#': - fl |= STBSP__LEADING_0X; - ++f; - continue; - // if we have thousand commas - case '\'': - fl |= STBSP__TRIPLET_COMMA; - ++f; - continue; - // if we have kilo marker (none->kilo->kibi->jedec) - case '$': - if (fl & STBSP__METRIC_SUFFIX) { - if (fl & STBSP__METRIC_1024) { - fl |= STBSP__METRIC_JEDEC; - } else { - fl |= STBSP__METRIC_1024; - } - } else { - fl |= STBSP__METRIC_SUFFIX; - } - ++f; - continue; - // if we don't want space between metric suffix and number - case '_': - fl |= STBSP__METRIC_NOSPACE; - ++f; - continue; - // if we have leading zero - case '0': - fl |= STBSP__LEADINGZERO; - ++f; - goto flags_done; - default: goto flags_done; - } - } - flags_done: - - // get the field width - if (f[0] == '*') { - fw = va_arg(va, stbsp__uint32); - ++f; - } else { - while ((f[0] >= '0') && (f[0] <= '9')) { - fw = fw * 10 + f[0] - '0'; - f++; - } - } - // get the precision - if (f[0] == '.') { - ++f; - if (f[0] == '*') { - pr = va_arg(va, stbsp__uint32); - ++f; - } else { - pr = 0; - while ((f[0] >= '0') && (f[0] <= '9')) { - pr = pr * 10 + f[0] - '0'; - f++; - } - } - } - - // handle integer size overrides - switch (f[0]) { - // are we halfwidth? - case 'h': - fl |= STBSP__HALFWIDTH; - ++f; - if (f[0] == 'h') - ++f; // QUARTERWIDTH - break; - // are we 64-bit (unix style) - case 'l': - fl |= ((sizeof(long) == 8) ? STBSP__INTMAX : 0); - ++f; - if (f[0] == 'l') { - fl |= STBSP__INTMAX; - ++f; - } - break; - // are we 64-bit on intmax? (c99) - case 'j': - fl |= (sizeof(size_t) == 8) ? STBSP__INTMAX : 0; - ++f; - break; - // are we 64-bit on size_t or ptrdiff_t? (c99) - case 'z': - fl |= (sizeof(ptrdiff_t) == 8) ? STBSP__INTMAX : 0; - ++f; - break; - case 't': - fl |= (sizeof(ptrdiff_t) == 8) ? STBSP__INTMAX : 0; - ++f; - break; - // are we 64-bit (msft style) - case 'I': - if ((f[1] == '6') && (f[2] == '4')) { - fl |= STBSP__INTMAX; - f += 3; - } else if ((f[1] == '3') && (f[2] == '2')) { - f += 3; - } else { - fl |= ((sizeof(void *) == 8) ? STBSP__INTMAX : 0); - ++f; - } - break; - default: break; - } - - // handle each replacement - switch (f[0]) { - #define STBSP__NUMSZ 512 // big enough for e308 (with commas) or e-307 - char num[STBSP__NUMSZ]; - char lead[8]; - char tail[8]; - char *s; - char const *h; - stbsp__uint32 l, n, cs; - stbsp__uint64 n64; -#ifndef STB_SPRINTF_NOFLOAT - double fv; -#endif - stbsp__int32 dp; - char const *sn; - - case 's': - // get the string - s = va_arg(va, char *); - if (s == 0) - s = (char *)"null"; - // get the length, limited to desired precision - // always limit to ~0u chars since our counts are 32b - l = stbsp__strlen_limited(s, (pr >= 0) ? pr : ~0u); - lead[0] = 0; - tail[0] = 0; - pr = 0; - dp = 0; - cs = 0; - // copy the string in - goto scopy; - - case 'S': - { - DN_Str8 str8 = va_arg(va, DN_Str8); - s = (char *)str8.data; - l = (uint32_t)str8.size; - lead[0] = 0; - tail[0] = 0; - pr = 0; - dp = 0; - cs = 0; - }goto scopy; - - case 'c': // char - // get the character - s = num + STBSP__NUMSZ - 1; - *s = (char)va_arg(va, int); - l = 1; - lead[0] = 0; - tail[0] = 0; - pr = 0; - dp = 0; - cs = 0; - goto scopy; - - case 'n': // weird write-bytes specifier - { - int *d = va_arg(va, int *); - *d = tlen + (int)(bf - buf); - } break; - -#ifdef STB_SPRINTF_NOFLOAT - case 'A': // float - case 'a': // hex float - case 'G': // float - case 'g': // float - case 'E': // float - case 'e': // float - case 'f': // float - va_arg(va, double); // eat it - s = (char *)"No float"; - l = 8; - lead[0] = 0; - tail[0] = 0; - pr = 0; - cs = 0; - STBSP__NOTUSED(dp); - goto scopy; -#else - case 'A': // hex float - case 'a': // hex float - h = (f[0] == 'A') ? hexu : hex; - fv = va_arg(va, double); - if (pr == -1) - pr = 6; // default is 6 - // read the double into a string - if (stbsp__real_to_parts((stbsp__int64 *)&n64, &dp, fv)) - fl |= STBSP__NEGATIVE; - - s = num + 64; - - stbsp__lead_sign(fl, lead); - - if (dp == -1023) - dp = (n64) ? -1022 : 0; - else - n64 |= (((stbsp__uint64)1) << 52); - n64 <<= (64 - 56); - if (pr < 15) - n64 += ((((stbsp__uint64)8) << 56) >> (pr * 4)); -// add leading chars - -#ifdef STB_SPRINTF_MSVC_MODE - *s++ = '0'; - *s++ = 'x'; -#else - lead[1 + lead[0]] = '0'; - lead[2 + lead[0]] = 'x'; - lead[0] += 2; -#endif - *s++ = h[(n64 >> 60) & 15]; - n64 <<= 4; - if (pr) - *s++ = stbsp__period; - sn = s; - - // print the bits - n = pr; - if (n > 13) - n = 13; - if (pr > (stbsp__int32)n) - tz = pr - n; - pr = 0; - while (n--) { - *s++ = h[(n64 >> 60) & 15]; - n64 <<= 4; - } - - // print the expo - tail[1] = h[17]; - if (dp < 0) { - tail[2] = '-'; - dp = -dp; - } else - tail[2] = '+'; - n = (dp >= 1000) ? 6 : ((dp >= 100) ? 5 : ((dp >= 10) ? 4 : 3)); - tail[0] = (char)n; - for (;;) { - tail[n] = '0' + dp % 10; - if (n <= 3) - break; - --n; - dp /= 10; - } - - dp = (int)(s - sn); - l = (int)(s - (num + 64)); - s = num + 64; - cs = 1 + (3 << 24); - goto scopy; - - case 'G': // float - case 'g': // float - h = (f[0] == 'G') ? hexu : hex; - fv = va_arg(va, double); - if (pr == -1) - pr = 6; - else if (pr == 0) - pr = 1; // default is 6 - // read the double into a string - if (stbsp__real_to_str(&sn, &l, num, &dp, fv, (pr - 1) | 0x80000000)) - fl |= STBSP__NEGATIVE; - - // clamp the precision and delete extra zeros after clamp - n = pr; - if (l > (stbsp__uint32)pr) - l = pr; - while ((l > 1) && (pr) && (sn[l - 1] == '0')) { - --pr; - --l; - } - - // should we use %e - if ((dp <= -4) || (dp > (stbsp__int32)n)) { - if (pr > (stbsp__int32)l) - pr = l - 1; - else if (pr) - --pr; // when using %e, there is one digit before the decimal - goto doexpfromg; - } - // this is the insane action to get the pr to match %g semantics for %f - if (dp > 0) { - pr = (dp < (stbsp__int32)l) ? l - dp : 0; - } else { - pr = -dp + ((pr > (stbsp__int32)l) ? (stbsp__int32) l : pr); - } - goto dofloatfromg; - - case 'E': // float - case 'e': // float - h = (f[0] == 'E') ? hexu : hex; - fv = va_arg(va, double); - if (pr == -1) - pr = 6; // default is 6 - // read the double into a string - if (stbsp__real_to_str(&sn, &l, num, &dp, fv, pr | 0x80000000)) - fl |= STBSP__NEGATIVE; - doexpfromg: - tail[0] = 0; - stbsp__lead_sign(fl, lead); - if (dp == STBSP__SPECIAL) { - s = (char *)sn; - cs = 0; - pr = 0; - goto scopy; - } - s = num + 64; - // handle leading chars - *s++ = sn[0]; - - if (pr) - *s++ = stbsp__period; - - // handle after decimal - if ((l - 1) > (stbsp__uint32)pr) - l = pr + 1; - for (n = 1; n < l; n++) - *s++ = sn[n]; - // trailing zeros - tz = pr - (l - 1); - pr = 0; - // dump expo - tail[1] = h[0xe]; - dp -= 1; - if (dp < 0) { - tail[2] = '-'; - dp = -dp; - } else - tail[2] = '+'; -#ifdef STB_SPRINTF_MSVC_MODE - n = 5; -#else - n = (dp >= 100) ? 5 : 4; -#endif - tail[0] = (char)n; - for (;;) { - tail[n] = '0' + dp % 10; - if (n <= 3) - break; - --n; - dp /= 10; - } - cs = 1 + (3 << 24); // how many tens - goto flt_lead; - - case 'f': // float - fv = va_arg(va, double); - doafloat: - // do kilos - if (fl & STBSP__METRIC_SUFFIX) { - double divisor; - divisor = 1000.0f; - if (fl & STBSP__METRIC_1024) - divisor = 1024.0; - while (fl < 0x4000000) { - if ((fv < divisor) && (fv > -divisor)) - break; - fv /= divisor; - fl += 0x1000000; - } - } - if (pr == -1) - pr = 6; // default is 6 - // read the double into a string - if (stbsp__real_to_str(&sn, &l, num, &dp, fv, pr)) - fl |= STBSP__NEGATIVE; - dofloatfromg: - tail[0] = 0; - stbsp__lead_sign(fl, lead); - if (dp == STBSP__SPECIAL) { - s = (char *)sn; - cs = 0; - pr = 0; - goto scopy; - } - s = num + 64; - - // handle the three decimal varieties - if (dp <= 0) { - stbsp__int32 i; - // handle 0.000*000xxxx - *s++ = '0'; - if (pr) - *s++ = stbsp__period; - n = -dp; - if ((stbsp__int32)n > pr) - n = pr; - i = n; - while (i) { - if ((((stbsp__uintptr)s) & 3) == 0) - break; - *s++ = '0'; - --i; - } - while (i >= 4) { - *(stbsp__uint32 *)s = 0x30303030; - s += 4; - i -= 4; - } - while (i) { - *s++ = '0'; - --i; - } - if ((stbsp__int32)(l + n) > pr) - l = pr - n; - i = l; - while (i) { - *s++ = *sn++; - --i; - } - tz = pr - (n + l); - cs = 1 + (3 << 24); // how many tens did we write (for commas below) - } else { - cs = (fl & STBSP__TRIPLET_COMMA) ? ((600 - (stbsp__uint32)dp) % 3) : 0; - if ((stbsp__uint32)dp >= l) { - // handle xxxx000*000.0 - n = 0; - for (;;) { - if ((fl & STBSP__TRIPLET_COMMA) && (++cs == 4)) { - cs = 0; - *s++ = stbsp__comma; - } else { - *s++ = sn[n]; - ++n; - if (n >= l) - break; - } - } - if (n < (stbsp__uint32)dp) { - n = dp - n; - if ((fl & STBSP__TRIPLET_COMMA) == 0) { - while (n) { - if ((((stbsp__uintptr)s) & 3) == 0) - break; - *s++ = '0'; - --n; - } - while (n >= 4) { - *(stbsp__uint32 *)s = 0x30303030; - s += 4; - n -= 4; - } - } - while (n) { - if ((fl & STBSP__TRIPLET_COMMA) && (++cs == 4)) { - cs = 0; - *s++ = stbsp__comma; - } else { - *s++ = '0'; - --n; - } - } - } - cs = (int)(s - (num + 64)) + (3 << 24); // cs is how many tens - if (pr) { - *s++ = stbsp__period; - tz = pr; - } - } else { - // handle xxxxx.xxxx000*000 - n = 0; - for (;;) { - if ((fl & STBSP__TRIPLET_COMMA) && (++cs == 4)) { - cs = 0; - *s++ = stbsp__comma; - } else { - *s++ = sn[n]; - ++n; - if (n >= (stbsp__uint32)dp) - break; - } - } - cs = (int)(s - (num + 64)) + (3 << 24); // cs is how many tens - if (pr) - *s++ = stbsp__period; - if ((l - dp) > (stbsp__uint32)pr) - l = pr + dp; - while (n < l) { - *s++ = sn[n]; - ++n; - } - tz = pr - (l - dp); - } - } - pr = 0; - - // handle k,m,g,t - if (fl & STBSP__METRIC_SUFFIX) { - char idx; - idx = 1; - if (fl & STBSP__METRIC_NOSPACE) - idx = 0; - tail[0] = idx; - tail[1] = ' '; - { - if (fl >> 24) { // SI kilo is 'k', JEDEC and SI kibits are 'K'. - if (fl & STBSP__METRIC_1024) - tail[idx + 1] = "_KMGT"[fl >> 24]; - else - tail[idx + 1] = "_kMGT"[fl >> 24]; - idx++; - // If printing kibits and not in jedec, add the 'i'. - if (fl & STBSP__METRIC_1024 && !(fl & STBSP__METRIC_JEDEC)) { - tail[idx + 1] = 'i'; - idx++; - } - tail[0] = idx; - } - } - }; - - flt_lead: - // get the length that we copied - l = (stbsp__uint32)(s - (num + 64)); - s = num + 64; - goto scopy; -#endif - - case 'B': // upper binary - case 'b': // lower binary - h = (f[0] == 'B') ? hexu : hex; - lead[0] = 0; - if (fl & STBSP__LEADING_0X) { - lead[0] = 2; - lead[1] = '0'; - lead[2] = h[0xb]; - } - l = (8 << 4) | (1 << 8); - goto radixnum; - - case 'o': // octal - h = hexu; - lead[0] = 0; - if (fl & STBSP__LEADING_0X) { - lead[0] = 1; - lead[1] = '0'; - } - l = (3 << 4) | (3 << 8); - goto radixnum; - - case 'p': // pointer - fl |= (sizeof(void *) == 8) ? STBSP__INTMAX : 0; - pr = sizeof(void *) * 2; - fl &= ~STBSP__LEADINGZERO; // 'p' only prints the pointer with zeros - // fall through - to X - - case 'X': // upper hex - case 'x': // lower hex - h = (f[0] == 'X') ? hexu : hex; - l = (4 << 4) | (4 << 8); - lead[0] = 0; - if (fl & STBSP__LEADING_0X) { - lead[0] = 2; - lead[1] = '0'; - lead[2] = h[16]; - } - radixnum: - // get the number - if (fl & STBSP__INTMAX) - n64 = va_arg(va, stbsp__uint64); - else - n64 = va_arg(va, stbsp__uint32); - - s = num + STBSP__NUMSZ; - dp = 0; - // clear tail, and clear leading if value is zero - tail[0] = 0; - if (n64 == 0) { - lead[0] = 0; - if (pr == 0) { - l = 0; - cs = 0; - goto scopy; - } - } - // convert to string - for (;;) { - *--s = h[n64 & ((1 << (l >> 8)) - 1)]; - n64 >>= (l >> 8); - if (!((n64) || ((stbsp__int32)((num + STBSP__NUMSZ) - s) < pr))) - break; - if (fl & STBSP__TRIPLET_COMMA) { - ++l; - if ((l & 15) == ((l >> 4) & 15)) { - l &= ~15; - *--s = stbsp__comma; - } - } - }; - // get the tens and the comma pos - cs = (stbsp__uint32)((num + STBSP__NUMSZ) - s) + ((((l >> 4) & 15)) << 24); - // get the length that we copied - l = (stbsp__uint32)((num + STBSP__NUMSZ) - s); - // copy it - goto scopy; - - case 'u': // unsigned - case 'i': - case 'd': // integer - // get the integer and abs it - if (fl & STBSP__INTMAX) { - stbsp__int64 i64 = va_arg(va, stbsp__int64); - n64 = (stbsp__uint64)i64; - if ((f[0] != 'u') && (i64 < 0)) { - n64 = (stbsp__uint64)-i64; - fl |= STBSP__NEGATIVE; - } - } else { - stbsp__int32 i = va_arg(va, stbsp__int32); - n64 = (stbsp__uint32)i; - if ((f[0] != 'u') && (i < 0)) { - n64 = (stbsp__uint32)-i; - fl |= STBSP__NEGATIVE; - } - } - -#ifndef STB_SPRINTF_NOFLOAT - if (fl & STBSP__METRIC_SUFFIX) { - if (n64 < 1024) - pr = 0; - else if (pr == -1) - pr = 1; - fv = (double)(stbsp__int64)n64; - goto doafloat; - } -#endif - - // convert to string - s = num + STBSP__NUMSZ; - l = 0; - - for (;;) { - // do in 32-bit chunks (avoid lots of 64-bit divides even with constant denominators) - char *o = s - 8; - if (n64 >= 100000000) { - n = (stbsp__uint32)(n64 % 100000000); - n64 /= 100000000; - } else { - n = (stbsp__uint32)n64; - n64 = 0; - } - if ((fl & STBSP__TRIPLET_COMMA) == 0) { - do { - s -= 2; - *(stbsp__uint16 *)s = *(stbsp__uint16 *)&stbsp__digitpair.pair[(n % 100) * 2]; - n /= 100; - } while (n); - } - while (n) { - if ((fl & STBSP__TRIPLET_COMMA) && (l++ == 3)) { - l = 0; - *--s = stbsp__comma; - --o; - } else { - *--s = (char)(n % 10) + '0'; - n /= 10; - } - } - if (n64 == 0) { - if ((s[0] == '0') && (s != (num + STBSP__NUMSZ))) - ++s; - break; - } - while (s != o) - if ((fl & STBSP__TRIPLET_COMMA) && (l++ == 3)) { - l = 0; - *--s = stbsp__comma; - --o; - } else { - *--s = '0'; - } - } - - tail[0] = 0; - stbsp__lead_sign(fl, lead); - - // get the length that we copied - l = (stbsp__uint32)((num + STBSP__NUMSZ) - s); - if (l == 0) { - *--s = '0'; - l = 1; - } - cs = l + (3 << 24); - if (pr < 0) - pr = 0; - - scopy: - // get fw=leading/trailing space, pr=leading zeros - if (pr < (stbsp__int32)l) - pr = l; - n = pr + lead[0] + tail[0] + tz; - if (fw < (stbsp__int32)n) - fw = n; - fw -= n; - pr -= l; - - // handle right justify and leading zeros - if ((fl & STBSP__LEFTJUST) == 0) { - if (fl & STBSP__LEADINGZERO) // if leading zeros, everything is in pr - { - pr = (fw > pr) ? fw : pr; - fw = 0; - } else { - fl &= ~STBSP__TRIPLET_COMMA; // if no leading zeros, then no commas - } - } - - // copy the spaces and/or zeros - if (fw + pr) { - stbsp__int32 i; - stbsp__uint32 c; - - // copy leading spaces (or when doing %8.4d stuff) - if ((fl & STBSP__LEFTJUST) == 0) - while (fw > 0) { - stbsp__cb_buf_clamp(i, fw); - fw -= i; - while (i) { - if ((((stbsp__uintptr)bf) & 3) == 0) - break; - *bf++ = ' '; - --i; - } - while (i >= 4) { - *(stbsp__uint32 *)bf = 0x20202020; - bf += 4; - i -= 4; - } - while (i) { - *bf++ = ' '; - --i; - } - stbsp__chk_cb_buf(1); - } - - // copy leader - sn = lead + 1; - while (lead[0]) { - stbsp__cb_buf_clamp(i, lead[0]); - lead[0] -= (char)i; - while (i) { - *bf++ = *sn++; - --i; - } - stbsp__chk_cb_buf(1); - } - - // copy leading zeros - c = cs >> 24; - cs &= 0xffffff; - cs = (fl & STBSP__TRIPLET_COMMA) ? ((stbsp__uint32)(c - ((pr + cs) % (c + 1)))) : 0; - while (pr > 0) { - stbsp__cb_buf_clamp(i, pr); - pr -= i; - if ((fl & STBSP__TRIPLET_COMMA) == 0) { - while (i) { - if ((((stbsp__uintptr)bf) & 3) == 0) - break; - *bf++ = '0'; - --i; - } - while (i >= 4) { - *(stbsp__uint32 *)bf = 0x30303030; - bf += 4; - i -= 4; - } - } - while (i) { - if ((fl & STBSP__TRIPLET_COMMA) && (cs++ == c)) { - cs = 0; - *bf++ = stbsp__comma; - } else - *bf++ = '0'; - --i; - } - stbsp__chk_cb_buf(1); - } - } - - // copy leader if there is still one - sn = lead + 1; - while (lead[0]) { - stbsp__int32 i; - stbsp__cb_buf_clamp(i, lead[0]); - lead[0] -= (char)i; - while (i) { - *bf++ = *sn++; - --i; - } - stbsp__chk_cb_buf(1); - } - - // copy the string - n = l; - while (n) { - stbsp__int32 i; - stbsp__cb_buf_clamp(i, n); - n -= i; - STBSP__UNALIGNED(while (i >= 4) { - *(stbsp__uint32 volatile *)bf = *(stbsp__uint32 volatile *)s; - bf += 4; - s += 4; - i -= 4; - }) - while (i) { - *bf++ = *s++; - --i; - } - stbsp__chk_cb_buf(1); - } - - // copy trailing zeros - while (tz) { - stbsp__int32 i; - stbsp__cb_buf_clamp(i, tz); - tz -= i; - while (i) { - if ((((stbsp__uintptr)bf) & 3) == 0) - break; - *bf++ = '0'; - --i; - } - while (i >= 4) { - *(stbsp__uint32 *)bf = 0x30303030; - bf += 4; - i -= 4; - } - while (i) { - *bf++ = '0'; - --i; - } - stbsp__chk_cb_buf(1); - } - - // copy tail if there is one - sn = tail + 1; - while (tail[0]) { - stbsp__int32 i; - stbsp__cb_buf_clamp(i, tail[0]); - tail[0] -= (char)i; - while (i) { - *bf++ = *sn++; - --i; - } - stbsp__chk_cb_buf(1); - } - - // handle the left justify - if (fl & STBSP__LEFTJUST) - if (fw > 0) { - while (fw) { - stbsp__int32 i; - stbsp__cb_buf_clamp(i, fw); - fw -= i; - while (i) { - if ((((stbsp__uintptr)bf) & 3) == 0) - break; - *bf++ = ' '; - --i; - } - while (i >= 4) { - *(stbsp__uint32 *)bf = 0x20202020; - bf += 4; - i -= 4; - } - while (i--) - *bf++ = ' '; - stbsp__chk_cb_buf(1); - } - } - break; - - default: // unknown, just copy code - s = num + STBSP__NUMSZ - 1; - *s = f[0]; - l = 1; - fw = fl = 0; - lead[0] = 0; - tail[0] = 0; - pr = 0; - dp = 0; - cs = 0; - goto scopy; - } - ++f; - } -endfmt: - - if (!callback) - *bf = 0; - else - stbsp__flush_cb(); - -done: - return tlen + (int)(bf - buf); -} - -// cleanup -#undef STBSP__LEFTJUST -#undef STBSP__LEADINGPLUS -#undef STBSP__LEADINGSPACE -#undef STBSP__LEADING_0X -#undef STBSP__LEADINGZERO -#undef STBSP__INTMAX -#undef STBSP__TRIPLET_COMMA -#undef STBSP__NEGATIVE -#undef STBSP__METRIC_SUFFIX -#undef STBSP__NUMSZ -#undef stbsp__chk_cb_bufL -#undef stbsp__chk_cb_buf -#undef stbsp__flush_cb -#undef stbsp__cb_buf_clamp - -// ============================================================================ -// wrapper functions - -STBSP__PUBLICDEF int STB_SPRINTF_DECORATE(sprintf)(char *buf, char const *fmt, ...) -{ - int result; - va_list va; - va_start(va, fmt); - result = STB_SPRINTF_DECORATE(vsprintfcb)(0, 0, buf, fmt, va); - va_end(va); - return result; -} - -typedef struct stbsp__context { - char *buf; - int count; - int length; - char tmp[STB_SPRINTF_MIN]; -} stbsp__context; - -static char *stbsp__clamp_callback(const char *buf, void *user, int len) -{ - stbsp__context *c = (stbsp__context *)user; - c->length += len; - - if (len > c->count) - len = c->count; - - if (len) { - if (buf != c->buf) { - const char *s, *se; - char *d; - d = c->buf; - s = buf; - se = buf + len; - do { - *d++ = *s++; - } while (s < se); - } - c->buf += len; - c->count -= len; - } - - if (c->count <= 0) - return c->tmp; - return (c->count >= STB_SPRINTF_MIN) ? c->buf : c->tmp; // go direct into buffer if you can -} - -static char * stbsp__count_clamp_callback( const char * buf, void * user, int len ) -{ - stbsp__context * c = (stbsp__context*)user; - (void) sizeof(buf); - - c->length += len; - return c->tmp; // go direct into buffer if you can -} - -STBSP__PUBLICDEF int STB_SPRINTF_DECORATE( vsnprintf )( char * buf, int count, char const * fmt, va_list va ) -{ - stbsp__context c; - - if ( (count == 0) && !buf ) - { - c.length = 0; - - STB_SPRINTF_DECORATE( vsprintfcb )( stbsp__count_clamp_callback, &c, c.tmp, fmt, va ); - } - else - { - int l; - - c.buf = buf; - c.count = count; - c.length = 0; - - STB_SPRINTF_DECORATE( vsprintfcb )( stbsp__clamp_callback, &c, stbsp__clamp_callback(0,&c,0), fmt, va ); - - // zero-terminate - l = (int)( c.buf - buf ); - if ( l >= count ) // should never be greater, only equal (or less) than count - l = count - 1; - buf[l] = 0; - } - - return c.length; -} - -STBSP__PUBLICDEF int STB_SPRINTF_DECORATE(snprintf)(char *buf, int count, char const *fmt, ...) -{ - int result; - va_list va; - va_start(va, fmt); - - result = STB_SPRINTF_DECORATE(vsnprintf)(buf, count, fmt, va); - va_end(va); - - return result; -} - -STBSP__PUBLICDEF int STB_SPRINTF_DECORATE(vsprintf)(char *buf, char const *fmt, va_list va) -{ - return STB_SPRINTF_DECORATE(vsprintfcb)(0, 0, buf, fmt, va); -} - -// ======================================================================= -// low level float utility functions - -#ifndef STB_SPRINTF_NOFLOAT - -// copies d to bits w/ strict aliasing (this compiles to nothing on /Ox) -#define STBSP__COPYFP(dest, src) \ - { \ - int cn; \ - for (cn = 0; cn < 8; cn++) \ - ((char *)&dest)[cn] = ((char *)&src)[cn]; \ - } - -// get float info -static stbsp__int32 stbsp__real_to_parts(stbsp__int64 *bits, stbsp__int32 *expo, double value) -{ - double d; - stbsp__int64 b = 0; - - // load value and round at the frac_digits - d = value; - - STBSP__COPYFP(b, d); - - *bits = b & ((((stbsp__uint64)1) << 52) - 1); - *expo = (stbsp__int32)(((b >> 52) & 2047) - 1023); - - return (stbsp__int32)((stbsp__uint64) b >> 63); -} - -static double const stbsp__bot[23] = { - 1e+000, 1e+001, 1e+002, 1e+003, 1e+004, 1e+005, 1e+006, 1e+007, 1e+008, 1e+009, 1e+010, 1e+011, - 1e+012, 1e+013, 1e+014, 1e+015, 1e+016, 1e+017, 1e+018, 1e+019, 1e+020, 1e+021, 1e+022 -}; -static double const stbsp__negbot[22] = { - 1e-001, 1e-002, 1e-003, 1e-004, 1e-005, 1e-006, 1e-007, 1e-008, 1e-009, 1e-010, 1e-011, - 1e-012, 1e-013, 1e-014, 1e-015, 1e-016, 1e-017, 1e-018, 1e-019, 1e-020, 1e-021, 1e-022 -}; -static double const stbsp__negboterr[22] = { - -5.551115123125783e-018, -2.0816681711721684e-019, -2.0816681711721686e-020, -4.7921736023859299e-021, -8.1803053914031305e-022, 4.5251888174113741e-023, - 4.5251888174113739e-024, -2.0922560830128471e-025, -6.2281591457779853e-026, -3.6432197315497743e-027, 6.0503030718060191e-028, 2.0113352370744385e-029, - -3.0373745563400371e-030, 1.1806906454401013e-032, -7.7705399876661076e-032, 2.0902213275965398e-033, -7.1542424054621921e-034, -7.1542424054621926e-035, - 2.4754073164739869e-036, 5.4846728545790429e-037, 9.2462547772103625e-038, -4.8596774326570872e-039 -}; -static double const stbsp__top[13] = { - 1e+023, 1e+046, 1e+069, 1e+092, 1e+115, 1e+138, 1e+161, 1e+184, 1e+207, 1e+230, 1e+253, 1e+276, 1e+299 -}; -static double const stbsp__negtop[13] = { - 1e-023, 1e-046, 1e-069, 1e-092, 1e-115, 1e-138, 1e-161, 1e-184, 1e-207, 1e-230, 1e-253, 1e-276, 1e-299 -}; -static double const stbsp__toperr[13] = { - 8388608, - 6.8601809640529717e+028, - -7.253143638152921e+052, - -4.3377296974619174e+075, - -1.5559416129466825e+098, - -3.2841562489204913e+121, - -3.7745893248228135e+144, - -1.7356668416969134e+167, - -3.8893577551088374e+190, - -9.9566444326005119e+213, - 6.3641293062232429e+236, - -5.2069140800249813e+259, - -5.2504760255204387e+282 -}; -static double const stbsp__negtoperr[13] = { - 3.9565301985100693e-040, -2.299904345391321e-063, 3.6506201437945798e-086, 1.1875228833981544e-109, - -5.0644902316928607e-132, -6.7156837247865426e-155, -2.812077463003139e-178, -5.7778912386589953e-201, - 7.4997100559334532e-224, -4.6439668915134491e-247, -6.3691100762962136e-270, -9.436808465446358e-293, - 8.0970921678014997e-317 -}; - -#if defined(_MSC_VER) && (_MSC_VER <= 1200) -static stbsp__uint64 const stbsp__powten[20] = { - 1, - 10, - 100, - 1000, - 10000, - 100000, - 1000000, - 10000000, - 100000000, - 1000000000, - 10000000000, - 100000000000, - 1000000000000, - 10000000000000, - 100000000000000, - 1000000000000000, - 10000000000000000, - 100000000000000000, - 1000000000000000000, - 10000000000000000000U -}; -#define stbsp__tento19th ((stbsp__uint64)1000000000000000000) -#else -static stbsp__uint64 const stbsp__powten[20] = { - 1, - 10, - 100, - 1000, - 10000, - 100000, - 1000000, - 10000000, - 100000000, - 1000000000, - 10000000000ULL, - 100000000000ULL, - 1000000000000ULL, - 10000000000000ULL, - 100000000000000ULL, - 1000000000000000ULL, - 10000000000000000ULL, - 100000000000000000ULL, - 1000000000000000000ULL, - 10000000000000000000ULL -}; -#define stbsp__tento19th (1000000000000000000ULL) -#endif - -#define stbsp__ddmulthi(oh, ol, xh, yh) \ - { \ - double ahi = 0, alo, bhi = 0, blo; \ - stbsp__int64 bt; \ - oh = xh * yh; \ - STBSP__COPYFP(bt, xh); \ - bt &= ((~(stbsp__uint64)0) << 27); \ - STBSP__COPYFP(ahi, bt); \ - alo = xh - ahi; \ - STBSP__COPYFP(bt, yh); \ - bt &= ((~(stbsp__uint64)0) << 27); \ - STBSP__COPYFP(bhi, bt); \ - blo = yh - bhi; \ - ol = ((ahi * bhi - oh) + ahi * blo + alo * bhi) + alo * blo; \ - } - -#define stbsp__ddtoS64(ob, xh, xl) \ - { \ - double ahi = 0, alo, vh, t; \ - ob = (stbsp__int64)xh; \ - vh = (double)ob; \ - ahi = (xh - vh); \ - t = (ahi - xh); \ - alo = (xh - (ahi - t)) - (vh + t); \ - ob += (stbsp__int64)(ahi + alo + xl); \ - } - -#define stbsp__ddrenorm(oh, ol) \ - { \ - double s; \ - s = oh + ol; \ - ol = ol - (s - oh); \ - oh = s; \ - } - -#define stbsp__ddmultlo(oh, ol, xh, xl, yh, yl) ol = ol + (xh * yl + xl * yh); - -#define stbsp__ddmultlos(oh, ol, xh, yl) ol = ol + (xh * yl); - -static void stbsp__raise_to_power10(double *ohi, double *olo, double d, stbsp__int32 power) // power can be -323 to +350 -{ - double ph, pl; - if ((power >= 0) && (power <= 22)) { - stbsp__ddmulthi(ph, pl, d, stbsp__bot[power]); - } else { - stbsp__int32 e, et, eb; - double p2h, p2l; - - e = power; - if (power < 0) - e = -e; - et = (e * 0x2c9) >> 14; /* %23 */ - if (et > 13) - et = 13; - eb = e - (et * 23); - - ph = d; - pl = 0.0; - if (power < 0) { - if (eb) { - --eb; - stbsp__ddmulthi(ph, pl, d, stbsp__negbot[eb]); - stbsp__ddmultlos(ph, pl, d, stbsp__negboterr[eb]); - } - if (et) { - stbsp__ddrenorm(ph, pl); - --et; - stbsp__ddmulthi(p2h, p2l, ph, stbsp__negtop[et]); - stbsp__ddmultlo(p2h, p2l, ph, pl, stbsp__negtop[et], stbsp__negtoperr[et]); - ph = p2h; - pl = p2l; - } - } else { - if (eb) { - e = eb; - if (eb > 22) - eb = 22; - e -= eb; - stbsp__ddmulthi(ph, pl, d, stbsp__bot[eb]); - if (e) { - stbsp__ddrenorm(ph, pl); - stbsp__ddmulthi(p2h, p2l, ph, stbsp__bot[e]); - stbsp__ddmultlos(p2h, p2l, stbsp__bot[e], pl); - ph = p2h; - pl = p2l; - } - } - if (et) { - stbsp__ddrenorm(ph, pl); - --et; - stbsp__ddmulthi(p2h, p2l, ph, stbsp__top[et]); - stbsp__ddmultlo(p2h, p2l, ph, pl, stbsp__top[et], stbsp__toperr[et]); - ph = p2h; - pl = p2l; - } - } - } - stbsp__ddrenorm(ph, pl); - *ohi = ph; - *olo = pl; -} - -// given a float value, returns the significant bits in bits, and the position of the -// decimal point in decimal_pos. +/-INF and NAN are specified by special values -// returned in the decimal_pos parameter. -// frac_digits is absolute normally, but if you want from first significant digits (got %g and %e), or in 0x80000000 -static stbsp__int32 stbsp__real_to_str(char const **start, stbsp__uint32 *len, char *out, stbsp__int32 *decimal_pos, double value, stbsp__uint32 frac_digits) -{ - double d; - stbsp__int64 bits = 0; - stbsp__int32 expo, e, ng, tens; - - d = value; - STBSP__COPYFP(bits, d); - expo = (stbsp__int32)((bits >> 52) & 2047); - ng = (stbsp__int32)((stbsp__uint64) bits >> 63); - if (ng) - d = -d; - - if (expo == 2047) // is nan or inf? - { - *start = (bits & ((((stbsp__uint64)1) << 52) - 1)) ? "NaN" : "Inf"; - *decimal_pos = STBSP__SPECIAL; - *len = 3; - return ng; - } - - if (expo == 0) // is zero or denormal - { - if (((stbsp__uint64) bits << 1) == 0) // do zero - { - *decimal_pos = 1; - *start = out; - out[0] = '0'; - *len = 1; - return ng; - } - // find the right expo for denormals - { - stbsp__int64 v = ((stbsp__uint64)1) << 51; - while ((bits & v) == 0) { - --expo; - v >>= 1; - } - } - } - - // find the decimal exponent as well as the decimal bits of the value - { - double ph, pl; - - // log10 estimate - very specifically tweaked to hit or undershoot by no more than 1 of log10 of all expos 1..2046 - tens = expo - 1023; - tens = (tens < 0) ? ((tens * 617) / 2048) : (((tens * 1233) / 4096) + 1); - - // move the significant bits into position and stick them into an int - stbsp__raise_to_power10(&ph, &pl, d, 18 - tens); - - // get full as much precision from double-double as possible - stbsp__ddtoS64(bits, ph, pl); - - // check if we undershot - if (((stbsp__uint64)bits) >= stbsp__tento19th) - ++tens; - } - - // now do the rounding in integer land - frac_digits = (frac_digits & 0x80000000) ? ((frac_digits & 0x7ffffff) + 1) : (tens + frac_digits); - if ((frac_digits < 24)) { - stbsp__uint32 dg = 1; - if ((stbsp__uint64)bits >= stbsp__powten[9]) - dg = 10; - while ((stbsp__uint64)bits >= stbsp__powten[dg]) { - ++dg; - if (dg == 20) - goto noround; - } - if (frac_digits < dg) { - stbsp__uint64 r; - // add 0.5 at the right position and round - e = dg - frac_digits; - if ((stbsp__uint32)e >= 24) - goto noround; - r = stbsp__powten[e]; - bits = bits + (r / 2); - if ((stbsp__uint64)bits >= stbsp__powten[dg]) - ++tens; - bits /= r; - } - noround:; - } - - // kill long trailing runs of zeros - if (bits) { - stbsp__uint32 n; - for (;;) { - if (bits <= 0xffffffff) - break; - if (bits % 1000) - goto donez; - bits /= 1000; - } - n = (stbsp__uint32)bits; - while ((n % 1000) == 0) - n /= 1000; - bits = n; - donez:; - } - - // convert to string - out += 64; - e = 0; - for (;;) { - stbsp__uint32 n; - char *o = out - 8; - // do the conversion in chunks of U32s (avoid most 64-bit divides, worth it, constant denomiators be damned) - if (bits >= 100000000) { - n = (stbsp__uint32)(bits % 100000000); - bits /= 100000000; - } else { - n = (stbsp__uint32)bits; - bits = 0; - } - while (n) { - out -= 2; - *(stbsp__uint16 *)out = *(stbsp__uint16 *)&stbsp__digitpair.pair[(n % 100) * 2]; - n /= 100; - e += 2; - } - if (bits == 0) { - if ((e) && (out[0] == '0')) { - ++out; - --e; - } - break; - } - while (out != o) { - *--out = '0'; - ++e; - } - } - - *decimal_pos = tens; - *start = out; - *len = e; - return ng; -} - -#undef stbsp__ddmulthi -#undef stbsp__ddrenorm -#undef stbsp__ddmultlo -#undef stbsp__ddmultlos -#undef STBSP__SPECIAL -#undef STBSP__COPYFP - -#endif // STB_SPRINTF_NOFLOAT - -// clean up -#undef stbsp__uint16 -#undef stbsp__uint32 -#undef stbsp__int32 -#undef stbsp__uint64 -#undef stbsp__int64 -#undef STBSP__UNALIGNED - -#endif // STB_SPRINTF_IMPLEMENTATION - -/* ------------------------------------------------------------------------------- -This software is available under 2 licenses -- choose whichever you prefer. ------------------------------------------------------------------------------- -ALTERNATIVE A - MIT License -Copyright (c) 2017 Sean Barrett -Permission is hereby granted, free of charge, to any person obtaining a copy of -this software and associated documentation files (the "Software"), to deal in -the Software without restriction, including without limitation the rights to -use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies -of the Software, and to permit persons to whom the Software is furnished to do -so, subject to the following conditions: -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. ------------------------------------------------------------------------------- -ALTERNATIVE B - Public Domain (www.unlicense.org) -This is free and unencumbered software released into the public domain. -Anyone is free to copy, modify, publish, use, compile, sell, or distribute this -software, either in source code form or as a compiled binary, for any purpose, -commercial or non-commercial, and by any means. -In jurisdictions that recognize copyright laws, the author or authors of this -software dedicate any and all copyright interest in the software to the public -domain. We make this dedication for the benefit of the public at large and to -the detriment of our heirs and successors. We intend this dedication to be an -overt act of relinquishment in perpetuity of all present and future rights to -this software under copyright law. -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN -ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ------------------------------------------------------------------------------- -*/ -DN_GCC_WARNING_POP -DN_MSVC_WARNING_POP - -DN_API void DN_BeginFrame (); - -#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_MemEq (void const *lhs, DN_USize lhs_size, void const *rhs, DN_USize rhs_size); - -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_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 void DN_TicketMutex_Begin (DN_TicketMutex *mutex); -DN_API void DN_TicketMutex_End (DN_TicketMutex *mutex); -DN_API DN_UInt DN_TicketMutex_MakeTicket (DN_TicketMutex *mutex); -DN_API void DN_TicketMutex_BeginTicket (DN_TicketMutex const *mutex, DN_UInt ticket); -DN_API bool DN_TicketMutex_CanLock (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); -#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_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 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 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 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_UInt DN_SaturateCastI64ToUInt (DN_I64 val); -DN_API DN_ISize 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 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_Arena DN_ArenaFromBuffer (void *buffer, DN_USize size, DN_ArenaFlags flags); -DN_API DN_Arena DN_ArenaFromMemFuncs (DN_U64 reserve, DN_U64 commit, DN_ArenaFlags flags, DN_ArenaMemFuncs mem_funcs); -DN_API void DN_ArenaDeinit (DN_Arena *arena); -DN_API bool DN_ArenaCommit (DN_Arena *arena, DN_U64 size); -DN_API bool DN_ArenaCommitTo (DN_Arena *arena, DN_U64 pos); -DN_API bool DN_ArenaGrow (DN_Arena *arena, DN_U64 reserve, DN_U64 commit); -DN_API void * DN_ArenaAlloc (DN_Arena *arena, DN_U64 size, uint8_t align, DN_ZMem zmem); -DN_API void * DN_ArenaAllocContiguous (DN_Arena *arena, DN_U64 size, uint8_t align, DN_ZMem zmem); -DN_API void * DN_ArenaCopy (DN_Arena *arena, void const *data, DN_U64 size, uint8_t align); -DN_API void DN_ArenaPopTo (DN_Arena *arena, DN_U64 init_used); -DN_API void DN_ArenaPop (DN_Arena *arena, DN_U64 amount); -DN_API DN_U64 DN_ArenaPos (DN_Arena const *arena); -DN_API void DN_ArenaClear (DN_Arena *arena); -DN_API bool DN_ArenaOwnsPtr (DN_Arena const *arena, void *ptr); -DN_API DN_Str8x64 DN_ArenaInfoStr8x64 (DN_ArenaInfo info); -DN_API DN_ArenaStats DN_ArenaSumStatsArray (DN_ArenaStats const *array, DN_USize size); -DN_API DN_ArenaStats DN_ArenaSumStats (DN_ArenaStats lhs, DN_ArenaStats rhs); -DN_API DN_ArenaStats DN_ArenaSumArenaArrayToStats(DN_Arena const *array, DN_USize size); -DN_API DN_ArenaTempMem DN_ArenaTempMemBegin (DN_Arena *arena); -DN_API void DN_ArenaTempMemEnd (DN_ArenaTempMem mem); -#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_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)) - -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 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_U64FromStr8 (DN_Str8 string, char separator); -DN_API DN_U64FromResult DN_U64FromPtr (void const *data, DN_USize size, char separator); -DN_API DN_U64 DN_U64FromPtrUnsafe (void const *data, DN_USize size, char separator); -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_I64FromResult DN_I64FromStr8 (DN_Str8 string, char separator); -DN_API DN_I64FromResult DN_I64FromPtr (void const *data, DN_USize size, char separator); -DN_API DN_I64 DN_I64FromPtrUnsafe (void const *data, DN_USize size, char separator); - -DN_API DN_USize DN_FmtVSize (DN_FMT_ATTRIB char const *fmt, va_list args); -DN_API DN_USize DN_FmtSize (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_CStr8Size (char const *src); -DN_API DN_USize DN_CStr16Size (wchar_t const *src); - -#define DN_Str16Lit(string) DN_Str16{(wchar_t *)(string), sizeof(string)/sizeof(string[0]) - 1} -#define DN_Str8Lit(c_str) DN_Literal(DN_Str8){(char *)(c_str), sizeof(c_str) - 1} -#define DN_Str8PrintFmt(string) (int)((string).size), (string).data -#define DN_Str8FromPtr(data, size) DN_Literal(DN_Str8){(char *)(data), (DN_USize)(size)} -#define DN_Str8FromStruct(ptr) DN_Str8FromPtr((ptr)->data, (ptr)->size) -DN_API DN_Str8 DN_Str8FromCStr8 (char const *src); -DN_API DN_Str8 DN_Str8FromArena (DN_Arena *arena, DN_USize size, DN_ZMem z_mem); -DN_API DN_Str8 DN_Str8FromPool (DN_Pool *pool, DN_USize size); -DN_API DN_Str8 DN_Str8FromPtrArena (DN_Arena *arena, void const *data, DN_USize size); -DN_API DN_Str8 DN_Str8FromPtrPool (DN_Pool *pool, void const *data, DN_USize size); -DN_API DN_Str8 DN_Str8FromStr8Arena (DN_Arena *arena, DN_Str8 string); -DN_API DN_Str8 DN_Str8FromStr8Pool (DN_Pool *pool, DN_Str8 string); -DN_API DN_Str8 DN_Str8FromFmtArena (DN_Arena *arena, DN_FMT_ATTRIB char const *fmt, ...); -DN_API DN_Str8 DN_Str8FromFmtVArena (DN_Arena *arena, DN_FMT_ATTRIB char const *fmt, va_list args); -DN_API DN_Str8 DN_Str8FromFmtPool (DN_Pool *pool, DN_FMT_ATTRIB char const *fmt, ...); -DN_API DN_Str8 DN_Str8FromByteCountType (DN_ByteCountType type); -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_Str8x32 DN_Str8x32FromU64 (DN_U64 val, char separator); -DN_API bool DN_Str8IsAll (DN_Str8 string, DN_Str8IsAllType is_all); -DN_API char * DN_Str8End (DN_Str8 string); -DN_API DN_Str8 DN_Str8Slice (DN_Str8 string, DN_USize offset, DN_USize size); -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_Str8SplitIncludeEmptyStrings mode); -DN_API DN_Str8SplitResult DN_Str8SplitArena (DN_Arena *arena, DN_Str8 string, DN_Str8 delimiter, DN_Str8SplitIncludeEmptyStrings mode); -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, uint32_t 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_Str8EqCase_Sensitive); -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_Str8EqCase_Sensitive); -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_Str8EqCase_Sensitive); -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_Str8EqCase_Sensitive); -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_Str8EqCase_Sensitive); -DN_API DN_Str8 DN_Str8TrimAround (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 size); -DN_API DN_Str8TruncateResult DN_Str8TruncateMiddle (DN_Arena *arena, DN_Str8 str8, DN_U32 side_size, DN_Str8 truncator); -DN_API DN_Str8 DN_Str8Lower (DN_Arena *arena, DN_Str8 string); -DN_API DN_Str8 DN_Str8Upper (DN_Arena *arena, DN_Str8 string); - -DN_API DN_Str8Builder DN_Str8BuilderFromArena (DN_Arena *arena); -DN_API DN_Str8Builder DN_Str8BuilderFromStr8PtrRef (DN_Arena *arena, DN_Str8 const *strings, DN_USize size); -DN_API DN_Str8Builder DN_Str8BuilderFromStr8PtrCopy (DN_Arena *arena, DN_Str8 const *strings, DN_USize size); -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 size, DN_Str8BuilderAdd add); -DN_API bool DN_Str8BuilderAddArrayCopy (DN_Str8Builder *builder, DN_Str8 const *strings, DN_USize size, DN_Str8BuilderAdd add); -DN_API bool DN_Str8BuilderAddFV (DN_Str8Builder *builder, DN_Str8BuilderAdd add, DN_FMT_ATTRIB char const *fmt, va_list args); -#define DN_Str8BuilderAppendArrayRef(builder, strings, size) DN_Str8BuilderAddArrayRef(builder, strings, size, DN_Str8BuilderAdd_Append) -#define DN_Str8BuilderAppendArrayCopy(builder, strings, size) DN_Str8BuilderAddArrayCopy(builder, strings, size, DN_Str8BuilderAdd_Append) -#define DN_Str8BuilderAppendSliceRef(builder, slice) DN_Str8BuilderAddArrayRef(builder, slice.data, slice.size, DN_Str8BuilderAdd_Append) -#define DN_Str8BuilderAppendSliceCopy(builder, slice) DN_Str8BuilderAddArrayCopy(builder, slice.data, slice.size, DN_Str8BuilderAdd_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_Str8BuilderAdd_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 size); -DN_API bool DN_Str8BuilderAppendBytesCopy (DN_Str8Builder *builder, void const *ptr, DN_USize size); -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_Str8BuilderAdd_Prepend) -#define DN_Str8BuilderPrependArrayCopy(builder, strings, size) DN_Str8BuilderAddArrayCopy(builder, strings, size, DN_Str8BuilderAdd_Prepend) -#define DN_Str8BuilderPrependSliceRef(builder, slice) DN_Str8BuilderAddArrayRef(builder, slice.data, slice.size, DN_Str8BuilderAdd_Prepend) -#define DN_Str8BuilderPrependSliceCopy(builder, slice) DN_Str8BuilderAddArrayCopy(builder, slice.data, slice.size, DN_Str8BuilderAdd_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_Str8BuilderAdd_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_Str8BuilderBuild (DN_Str8Builder const *builder, DN_Arena *arena); -DN_API DN_Str8 DN_Str8BuilderBuildDelimited (DN_Str8Builder const *builder, DN_Str8 delimiter, DN_Arena *arena); -DN_API DN_Slice DN_Str8BuilderBuildSlice (DN_Str8Builder const *builder, DN_Arena *arena); - -DN_API int DN_EncodeUTF8Codepoint (uint8_t utf8[4], uint32_t codepoint); -DN_API int DN_EncodeUTF16Codepoint (uint16_t utf16[2], uint32_t codepoint); - -DN_API DN_U8 DN_U8FromHexNibble (char hex); -DN_API DN_NibbleFromU8Result DN_NibbleFromU8 (DN_U8 u8); - -DN_API DN_USize DN_BytesFromHexPtr (void const *hex, DN_USize hex_count, void *dest, DN_USize dest_count); -DN_API DN_Str8 DN_BytesFromHexPtrArena (void const *hex, DN_USize hex_count, DN_Arena *arena); -DN_API DN_USize DN_BytesFromHexStr8 (DN_Str8 hex, void *dest, DN_USize dest_count); -DN_API DN_Str8 DN_BytesFromHexStr8Arena (DN_Str8 hex, DN_Arena *arena); -DN_API DN_U8x16 DN_BytesFromHex32Ptr (void const *hex, DN_USize hex_count); -DN_API DN_U8x32 DN_BytesFromHex64Ptr (void const *hex, DN_USize hex_count); - -DN_API DN_HexU64Str8 DN_HexFromU64 (DN_U64 value, DN_HexFromU64Type type); -DN_API DN_USize DN_HexFromBytesPtr (void const *bytes, DN_USize bytes_count, void *hex, DN_USize hex_count); -DN_API DN_Str8 DN_HexFromBytesPtrArena (void const *bytes, DN_USize bytes_count, DN_Arena *arena); -DN_API DN_Hex32 DN_HexFromBytes16Ptr (void const *bytes, DN_USize bytes_count); -DN_API DN_Hex64 DN_HexFromBytes32Ptr (void const *bytes, DN_USize bytes_count); -DN_API DN_Hex128 DN_HexFromBytes64Ptr (void const *bytes, DN_USize bytes_count); - -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 DN_ByteCountResult DN_ByteCountFromType (DN_U64 bytes, DN_ByteCountType type); -#define DN_ByteCount(bytes) DN_ByteCountFromType(bytes, DN_ByteCountType_Auto) -DN_API DN_Str8x32 DN_ByteCountStr8x32FromType (DN_U64 bytes, DN_ByteCountType type); -#define DN_ByteCountStr8x32(bytes) DN_ByteCountStr8x32FromType(bytes, DN_ByteCountType_Auto) - -#define DN_ProfilerZoneLoop(prof, name, index) \ - DN_ProfilerZone DN_UniqueName(zone_) = DN_ProfilerBeginZone(prof, DN_Str8Lit(name), index), DN_UniqueName(dummy_) = {}; \ - DN_UniqueName(dummy_).begin_tsc == 0; \ - DN_ProfilerEndZone(prof, DN_UniqueName(zone_)), DN_UniqueName(dummy_).begin_tsc = 1 - -#define DN_ProfilerZoneLoopAuto(prof, name) DN_ProfilerZoneLoop(prof, name, __COUNTER__ + 1) -DN_API DN_Profiler DN_ProfilerInit (DN_ProfilerAnchor *anchors, DN_USize count, DN_USize anchors_per_frame, DN_ProfilerTSCNowFunc *tsc_now, DN_U64 tsc_frequency); -DN_API DN_ProfilerZone DN_ProfilerBeginZone (DN_Profiler *profiler, DN_Str8 name, DN_U16 anchor_index); -#define DN_ProfilerBeginZoneAuto(prof, name) DN_ProfilerBeginZone(prof, DN_Str8Lit(name), __COUNTER__ + 1) -DN_API void DN_ProfilerEndZone (DN_Profiler *profiler, DN_ProfilerZone zone); -DN_API DN_USize DN_ProfilerFrameCount (DN_Profiler const *profiler); -DN_API DN_ProfilerAnchorArray DN_ProfilerFrameAnchorsFromIndex (DN_Profiler *profiler, DN_USize frame_index); -DN_API DN_ProfilerAnchorArray DN_ProfilerFrameAnchors (DN_Profiler *profiler); -DN_API void DN_ProfilerNewFrame (DN_Profiler *profiler); -DN_API void DN_ProfilerDump (DN_Profiler *profiler); -DN_API DN_F64 DN_ProfilerSecFromTSC (DN_Profiler *profiler, DN_U64 duration_tsc); -DN_API DN_F64 DN_ProfilerMsFromTSC (DN_Profiler *profiler, DN_U64 duration_tsc); - -#endif // !defined(DN_BASE_H) -// DN: Single header generator commented out this header => #include "Base/dn_base_os.h" -#if !defined(DN_BASE_OS_H) -#define DN_BASE_OS_H - -// DN: Single header generator commented out this header => #include "../dn_base_inc.h" - -// NOTE: OS primitives that the OS layer can provide for the base layer but is optional. - -struct DN_StackTraceFrame -{ - DN_U64 address; - DN_U64 line_number; - DN_Str8 file_name; - DN_Str8 function_name; -}; - -struct DN_StackTraceRawFrame -{ - void *process; - DN_U64 base_addr; -}; - -struct DN_StackTraceWalkResult -{ - void *process; // [Internal] Windows handle to the process - DN_U64 *base_addr; // The addresses of the functions in the stack trace - DN_U16 size; // The number of `base_addr`'s stored from the walk -}; - -struct DN_StackTraceWalkResultIterator -{ - DN_StackTraceRawFrame raw_frame; - DN_U16 index; -}; - - -#if defined(DN_FREESTANDING) -#define DN_StackTraceWalkStr8FromHeap(...) DN_Str8Lit("N/A") -#define DN_StackTraceWalk(...) -#define DN_StackTraceWalkResultIterate(...) -#define DN_StackTraceWalkResultToStr8(...) DN_Str8Lit("N/A") -#define DN_StackTraceWalkStr8(...) DN_Str8Lit("N/A") -#define DN_StackTraceWalkStr8FromHeap(...) DN_Str8Lit("N/A") -#define DN_StackTraceGetFrames(...) -#define DN_StackTraceRawFrameToFrame(...) -#define DN_StackTracePrint(...) -#define DN_StackTraceReloadSymbols(...) -#else -DN_API DN_StackTraceWalkResult DN_StackTraceWalk (struct DN_Arena *arena, DN_U16 limit); -DN_API bool DN_StackTraceWalkResultIterate(DN_StackTraceWalkResultIterator *it, DN_StackTraceWalkResult const *walk); -DN_API DN_Str8 DN_StackTraceWalkResultToStr8 (struct DN_Arena *arena, DN_StackTraceWalkResult const *walk, DN_U16 skip); -DN_API DN_Str8 DN_StackTraceWalkStr8 (struct DN_Arena *arena, DN_U16 limit, DN_U16 skip); -DN_API DN_Str8 DN_StackTraceWalkStr8FromHeap (DN_U16 limit, DN_U16 skip); -DN_API DN_Slice DN_StackTraceGetFrames (struct DN_Arena *arena, DN_U16 limit); -DN_API DN_StackTraceFrame DN_StackTraceRawFrameToFrame (struct DN_Arena *arena, DN_StackTraceRawFrame raw_frame); -DN_API void DN_StackTracePrint (DN_U16 limit); -DN_API void DN_StackTraceReloadSymbols (); -#endif -#endif // !defined(DN_BASE_OS_H) -// DN: Single header generator commented out this header => #include "Base/dn_base_assert.h" -#if !defined(DN_BASE_ASSERT_H) -#define DN_BASE_ASSERT_H - -#define DN_HardAssertF(expr, fmt, ...) \ - do { \ - if (!(expr)) { \ - DN_Str8 stack_trace_ = DN_StackTraceWalkStr8FromHeap(128 /*limit*/, 2 /*skip*/); \ - DN_LOG_ErrorF("Hard assertion [" #expr "], stack trace was:\n\n%.*s\n\n" fmt, \ - DN_Str8PrintFmt(stack_trace_), \ - ##__VA_ARGS__); \ - DN_DebugBreak; \ - } \ - } while (0) -#define DN_HardAssert(expr) DN_HardAssertF(expr, "") - -// NOTE: Our default assert requires stack traces which has a bit of a chicken-and-egg problem if -// we're trying to detect some code related to the DN startup sequence. If we try to assert before -// the OS layer is initialised stack-traces will try to use temporary memory which requires TLS to -// be setup which belongs to the OS. -// -// This causes recursion errors as they call into each other. We use RawAsserts for these kind of -// checks. -#if defined(DN_NO_ASSERT) - #define DN_RawAssert(...) - #define DN_Assert(...) - #define DN_AssertOnce(...) - #define DN_AssertF(...) - #define DN_AssertFOnce(...) -#else - #define DN_RawAssert(expr) do { if (!(expr)) DN_DebugBreak; } while (0) - - #define DN_AssertF(expr, fmt, ...) \ - do { \ - if (!(expr)) { \ - DN_Str8 stack_trace_ = DN_StackTraceWalkStr8FromHeap(128 /*limit*/, 2 /*skip*/); \ - DN_LOG_ErrorF("Assertion [" #expr "], stack trace was:\n\n%.*s\n\n" fmt, \ - DN_Str8PrintFmt(stack_trace_), \ - ##__VA_ARGS__); \ - DN_DebugBreak; \ - } \ - } while (0) - - #define DN_AssertFOnce(expr, fmt, ...) \ - do { \ - static bool once = true; \ - if (!(expr) && once) { \ - once = false; \ - DN_Str8 stack_trace_ = DN_StackTraceWalkStr8FromHeap(128 /*limit*/, 2 /*skip*/); \ - DN_LOG_ErrorF("Assertion [" #expr "], stack trace was:\n\n%.*s\n\n" fmt, \ - DN_Str8PrintFmt(stack_trace_), \ - ##__VA_ARGS__); \ - DN_DebugBreak; \ - } \ - } while (0) - - #define DN_Assert(expr) DN_AssertF((expr), "") - #define DN_AssertOnce(expr) DN_AssertFOnce((expr), "") -#endif - -#define DN_InvalidCodePathF(fmt, ...) DN_HardAssertF(0, fmt, ##__VA_ARGS__) -#define DN_InvalidCodePath DN_InvalidCodePathF("Invalid code path triggered") -#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_Check(expr) DN_CheckF(expr, "") -#if defined(DN_NO_CHECK_BREAK) - #define DN_CheckF(expr, fmt, ...) \ - ((expr) ? true : (DN_LOG_WarningF(fmt, ##__VA_ARGS__), false)) -#else - #define DN_CheckF(expr, fmt, ...) \ - ((expr) ? true : (DN_LOG_ErrorF(fmt, ##__VA_ARGS__), DN_StackTracePrint(128 /*limit*/), DN_DebugBreak, false)) -#endif - -#endif -// DN: Single header generator commented out this header => #include "Base/dn_base_log.h" -#if !defined(DN_BASE_LOG_H) -#define DN_BASE_LOG_H - -// DN: Single header generator commented out this header => #include "../dn_base_inc.h" - -enum DN_LOGType -{ - DN_LOGType_Debug, - DN_LOGType_Info, - DN_LOGType_Warning, - DN_LOGType_Error, - DN_LOGType_Count, -}; - -enum DN_LOGBold -{ - DN_LOGBold_No, - DN_LOGBold_Yes, -}; - -struct DN_LOGStyle -{ - DN_LOGBold bold; - bool colour; - DN_U8 r, g, b; -}; - -struct DN_LOGTypeParam -{ - bool is_u32_enum; - DN_U32 u32; - DN_Str8 str8; -}; - -enum DN_LOGColourType -{ - DN_LOGColourType_Fg, - DN_LOGColourType_Bg, -}; - -struct DN_LOGDate -{ - DN_U16 year; - DN_U8 month; - DN_U8 day; - - DN_U8 hour; - DN_U8 minute; - DN_U8 second; -}; - -struct DN_LOGPrefixSize -{ - DN_USize size; - DN_USize padding; -}; - -typedef void DN_LOGEmitFromTypeFVFunc(DN_LOGTypeParam type, void *user_data, DN_CallSite call_site, DN_FMT_ATTRIB char const *fmt, va_list args); - -#define DN_LOG_ResetEscapeCode "\x1b[0m" -#define DN_LOG_BoldEscapeCode "\x1b[1m" -DN_API DN_Str8 DN_LOG_ColourEscapeCodeStr8FromRGB(DN_LOGColourType colour, DN_U8 r, DN_U8 g, DN_U8 b); -DN_API DN_Str8 DN_LOG_ColourEscapeCodeStr8FromU32(DN_LOGColourType colour, DN_U32 value); -DN_API DN_LOGPrefixSize DN_LOG_MakePrefix (DN_LOGStyle style, DN_LOGTypeParam type, DN_CallSite call_site, DN_LOGDate date, char *dest, DN_USize dest_size); -DN_API void DN_LOG_SetEmitFromTypeFVFunc (DN_LOGEmitFromTypeFVFunc *print_func, void *user_data); -DN_API void DN_LOG_EmitFromType (DN_LOGTypeParam type, DN_CallSite call_site, DN_FMT_ATTRIB char const *fmt, ...); -DN_API DN_LOGTypeParam DN_LOG_MakeU32LogTypeParam (DN_LOGType type); -#define DN_LOG_DebugF(fmt, ...) DN_LOG_EmitFromType(DN_LOG_MakeU32LogTypeParam(DN_LOGType_Debug), DN_CALL_SITE, fmt, ##__VA_ARGS__) -#define DN_LOG_InfoF(fmt, ...) DN_LOG_EmitFromType(DN_LOG_MakeU32LogTypeParam(DN_LOGType_Info), DN_CALL_SITE, fmt, ##__VA_ARGS__) -#define DN_LOG_WarningF(fmt, ...) DN_LOG_EmitFromType(DN_LOG_MakeU32LogTypeParam(DN_LOGType_Warning), DN_CALL_SITE, fmt, ##__VA_ARGS__) -#define DN_LOG_ErrorF(fmt, ...) DN_LOG_EmitFromType(DN_LOG_MakeU32LogTypeParam(DN_LOGType_Error), DN_CALL_SITE, fmt, ##__VA_ARGS__) -#endif // !defined(DN_BASE_LOG_H) -// DN: Single header generator commented out this header => #include "Base/dn_base_containers.h" -#if !defined(DN_CONTAINERS_H) -#define DN_CONTAINERS_H - -// DN: Single header generator commented out this header => #include "../dn_base_inc.h" - -struct DN_Ring -{ - DN_U64 size; - char *base; - DN_U64 write_pos; - DN_U64 read_pos; -}; - -// NOTE: DN_CArray ///////////////////////////////////////////////////////////////////////////////// -enum DN_ArrayErase -{ - DN_ArrayErase_Unstable, - DN_ArrayErase_Stable, -}; - -enum DN_ArrayAdd -{ - DN_ArrayAdd_Append, - DN_ArrayAdd_Prepend, -}; - -struct DN_ArrayEraseResult -{ - // The next index your for-index should be set to such that you can continue - // to iterate the remainder of the array, e.g: - // - // for (DN_USize index = 0; index < array.size; index++) { - // if (erase) - // index = DN_FArray_EraseRange(&array, index, -3, DN_ArrayErase_Unstable); - // } - DN_USize it_index; - DN_USize items_erased; // The number of items erased -}; - -template struct DN_ArrayFindResult -{ - T *data; // Pointer to the value if a match is found, null pointer otherwise - DN_USize index; // Index to the value if a match is found, 0 otherwise -}; - -#if !defined(DN_NO_SARRAY) -// NOTE: DN_SArray ///////////////////////////////////////////////////////////////////////////////// -template struct DN_SArray -{ - T *data; // Pointer to the start of the array items in the block of memory - DN_USize size; // Number of items currently in the array - DN_USize max; // Maximum number of items this array can store - - T *begin() { return data; } - T *end () { return data + size; } - T const *begin() const { return data; } - T const *end () const { return data + size; } -}; -#endif // !defined(DN_NO_SARRAY) - -#if !defined(DN_NO_FARRAY) -// NOTE: DN_FArray ///////////////////////////////////////////////////////////////////////////////// -template struct DN_FArray -{ - T data[N]; // Pointer to the start of the array items in the block of memory - DN_USize size; // Number of items currently in the array - - T *begin() { return data; } - T *end () { return data + size; } - T const *begin() const { return data; } - T const *end () const { return data + size; } -}; - -template using DN_FArray8 = DN_FArray; -template using DN_FArray16 = DN_FArray; -template using DN_FArray32 = DN_FArray; -template using DN_FArray64 = DN_FArray; -#endif // !defined(DN_NO_FARRAY) - -#if !defined(DN_NO_DSMAP) -// NOTE: DN_DSMap ////////////////////////////////////////////////////////////////////////////////// -enum DN_DSMapKeyType -{ - // Key | Key Hash | Map Index - DN_DSMapKeyType_Invalid, - DN_DSMapKeyType_U64, // U64 | Hash(U64) | Hash(U64) % map_size - DN_DSMapKeyType_U64NoHash, // U64 | U64 | U64 % map_size - DN_DSMapKeyType_Buffer, // Buffer | Hash(buffer) | Hash(buffer) % map_size - DN_DSMapKeyType_BufferAsU64NoHash, // Buffer | U64(buffer[0:4]) | U64(buffer[0:4]) % map_size -}; - -struct DN_DSMapKey -{ - DN_DSMapKeyType type; - DN_U32 hash; // Hash to lookup in the map. If it equals, we check that the original key payload matches - void const *buffer_data; - DN_U32 buffer_size; - DN_U64 u64; - bool no_copy_buffer; -}; - -template -struct DN_DSMapSlot -{ - DN_DSMapKey key; // Hash table lookup key - T value; // Hash table value -}; - -typedef DN_U32 DN_DSMapFlags; -enum DN_DSMapFlags_ -{ - DN_DSMapFlags_Nil = 0, - DN_DSMapFlags_DontFreeArenaOnResize = 1 << 0, -}; - -using DN_DSMapHashFunction = DN_U32(DN_DSMapKey key, DN_U32 seed); -template struct DN_DSMap -{ - DN_U32 *hash_to_slot; // Mapping from hash to a index in the slots array - DN_DSMapSlot *slots; // Values of the array stored contiguously, non-sorted order - DN_U32 size; // Total capacity of the map and is a power of two - DN_U32 occupied; // Number of slots used in the hash table - DN_Arena *arena; // Backing arena for the hash table - DN_Pool pool; // Allocator for keys that are variable-sized buffers - DN_U32 initial_size; // Initial map size, map cannot shrink on erase below this size - DN_DSMapHashFunction *hash_function; // Custom hashing function to use if field is set - DN_U32 hash_seed; // Seed for the hashing function, when 0, DN_DS_MAP_DEFAULT_HASH_SEED is used - DN_DSMapFlags flags; -}; - -template struct DN_DSMapResult -{ - bool found; - DN_DSMapSlot *slot; - T *value; -}; -#endif // !defined(DN_NO_DSMAP) - -#if !defined(DN_NO_LIST) -// NOTE: DN_List /////////////////////////////////////////////////////////////////////////////////// -template struct DN_ListChunk -{ - T *data; - DN_USize size; - DN_USize count; - DN_ListChunk *next; - DN_ListChunk *prev; -}; - -template struct DN_ListIterator -{ - DN_B32 init; // True if DN_List_Iterate has been called at-least once on this iterator - DN_ListChunk *chunk; // The chunk that the iterator is reading from - DN_USize chunk_data_index; // The index in the chunk the iterator is referencing - DN_USize index; // The index of the item in the list as if it was flat array - T *data; // Pointer to the data the iterator is referencing. Nullptr if invalid. -}; - -template struct DN_List -{ - DN_USize count; // Cumulative count of all items made across all list chunks - DN_USize chunk_size; // When new ListChunk's are required, the minimum 'data' entries to allocate for that node. - DN_ListChunk *head; - DN_ListChunk *tail; -}; -#endif // !defined(DN_NO_LIST) - -// NOTE: Macros for operating on data structures that are embedded into a C style struct or from a -// set of defined variables from the available scope. Keep it stupid simple, structs and functions. -// Minimal amount of container types with flexible construction leads to less duplicated container -// code and less template meta-programming. -// -// LArray => Literal Array -// Define a C array and size: -// -// ``` -// MyStruct buffer[TB_ASType_Count] = {}; -// DN_USize size = 0; -// MyStruct *item = DN_LArray_Make(buffer, size, DN_ArrayCountU(buffer), DN_ZMem_No); -// ``` -// -// IArray => Intrusive Array -// Define a struct with the members 'data', 'size' and 'max': -// -// ``` -// struct MyArray { -// MyStruct *data; -// DN_USize size; -// DN_USize max; -// } my_array = {}; -// -// MyStruct *item = DN_IArray_Make(&my_array, MyArray, DN_ZMem_No); -// ``` -// ISLList => Intrusive Singly Linked List -// Define a struct with the members 'next': -// -// ``` -// struct MyLinkItem { -// int data; -// MyLinkItem *next; -// } my_link = {}; -// -// MyLinkItem *first_item = DN_ISLList_Detach(&my_link, MyLinkItem); -// ``` - -#define DN_DLList_Init(list) \ - (list)->next = (list)->prev = (list) - -#define DN_DLList_IsSentinel(list, item) ((list) == (item)) - -#define DN_DLList_InitArena(list, T, arena) \ - do { \ - (list) = DN_ArenaNew(arena, T, DN_ZMem_Yes); \ - DN_DLList_Init(list); \ - } while (0) - -#define DN_DLList_InitPool(list, T, pool) \ - do { \ - (list) = DN_PoolNew(pool, T); \ - DN_DLList_Init(list); \ - } while (0) - -#define DN_DLList_Detach(item) \ - do { \ - if (item) { \ - (item)->prev->next = (item)->next; \ - (item)->next->prev = (item)->prev; \ - (item)->next = nullptr; \ - (item)->prev = nullptr; \ - } \ - } while (0) - -#define DN_DLList_Dequeue(list, dest_ptr) \ - if (DN_DLList_HasItems(list)) { \ - dest_ptr = (list)->next; \ - DN_DLList_Detach(dest_ptr); \ - } - -#define DN_DLList_Append(list, item) \ - do { \ - if (item) { \ - if ((item)->next) \ - DN_DLList_Detach(item); \ - (item)->next = (list)->next; \ - (item)->prev = (list); \ - (item)->next->prev = (item); \ - (item)->prev->next = (item); \ - } \ - } while (0) - -#define DN_DLList_Prepend(list, item) \ - do { \ - if (item) { \ - if ((item)->next) \ - DN_DLList_Detach(item); \ - (item)->next = (list); \ - (item)->prev = (list)->prev; \ - (item)->next->prev = (item); \ - (item)->prev->next = (item); \ - } \ - } while (0) - -#define DN_DLList_IsEmpty(list) \ - (!(list) || ((list) == (list)->next)) - -#define DN_DLList_IsInit(list) \ - ((list)->next && (list)->prev) - -#define DN_DLList_HasItems(list) \ - ((list) && ((list) != (list)->next)) - -#define DN_DLList_ForEach(it, list) \ - auto *it = (list)->next; (it) != (list); (it) = (it)->next - -#define DN_DoublyLLDetach(head, ptr) \ - do { \ - if ((head) && (head) == (ptr)) \ - (head) = (head)->next; \ - if ((ptr)) { \ - if ((ptr)->next) \ - (ptr)->next->prev = (ptr)->prev; \ - if ((ptr)->prev) \ - (ptr)->prev->next = (ptr)->next; \ - (ptr)->prev = (ptr)->next = 0; \ - } \ - } while (0) - -#define DN_DoublyLLAppend(head, ptr) \ - do { \ - if ((ptr)) { \ - DN_AssertF((ptr)->prev == 0 && (ptr)->next == 0, "Detach the pointer first"); \ - (ptr)->prev = (head); \ - (ptr)->next = 0; \ - if ((head)) { \ - (ptr)->next = (head)->next; \ - (head)->next = (ptr); \ - } else { \ - (head) = (ptr); \ - } \ - } \ - } while (0) - -#define DN_DoublyLLPrepend(head, ptr) \ - do { \ - if ((ptr)) { \ - DN_AssertF((ptr)->prev == 0 && (ptr)->next == 0, "Detach the pointer first"); \ - (ptr)->prev = nullptr; \ - (ptr)->next = (head); \ - if ((head)) { \ - (ptr)->prev = (head)->prev; \ - (head)->prev = (ptr); \ - } else { \ - (head) = (ptr); \ - } \ - } \ - } while (0) - -#define DN_ISLList_Detach(list) (decltype(list))DN_CSLList_Detach((void **)&(list), (void **)&(list)->next) - -#define DN_LArray_ResizeFromPool(c_array, size, max, pool, new_max) DN_CArray2_ResizeFromPool((void **)&(c_array), size, max, sizeof((c_array)[0]), pool, new_max) -#define DN_LArray_GrowFromPool(c_array, size, max, pool, new_max) DN_CArray2_GrowFromPool((void **)&(c_array), size, max, sizeof((c_array)[0]), pool, new_max) -#define DN_LArray_GrowIfNeededFromPool(c_array, size, max, pool, add_count) DN_CArray2_GrowIfNeededFromPool((void **)(c_array), size, max, sizeof((c_array)[0]), pool, add_count) -#define DN_LArray_MakeArray(c_array, size, max, count, z_mem) (decltype(&(c_array)[0]))DN_CArray2_MakeArray(c_array, size, max, sizeof((c_array)[0]), count, z_mem) -#define DN_LArray_MakeArrayZ(c_array, size, max, count) (decltype(&(c_array)[0]))DN_CArray2_MakeArray(c_array, size, max, sizeof((c_array)[0]), count, DN_ZMem_Yes) -#define DN_LArray_Make(c_array, size, max, z_mem) (decltype(&(c_array)[0]))DN_CArray2_MakeArray(c_array, size, max, sizeof((c_array)[0]), 1, z_mem) -#define DN_LArray_MakeZ(c_array, size, max) (decltype(&(c_array)[0]))DN_CArray2_MakeArray(c_array, size, max, sizeof((c_array)[0]), 1, DN_ZMem_Yes) -#define DN_LArray_AddArray(c_array, size, max, items, count, add) (decltype(&(c_array)[0]))DN_CArray2_AddArray(c_array, size, max, sizeof((c_array)[0]), items, count, add) -#define DN_LArray_Add(c_array, size, max, item, add) (decltype(&(c_array)[0]))DN_CArray2_AddArray(c_array, size, max, sizeof((c_array)[0]), &item, 1, add) -#define DN_LArray_AppendArray(c_array, size, max, items, count) (decltype(&(c_array)[0]))DN_CArray2_AddArray(c_array, size, max, sizeof((c_array)[0]), items, count, DN_ArrayAdd_Append) -#define DN_LArray_Append(c_array, size, max, item) (decltype(&(c_array)[0]))DN_CArray2_AddArray(c_array, size, max, sizeof((c_array)[0]), &item, 1, DN_ArrayAdd_Append) -#define DN_LArray_PrependArray(c_array, size, max, items, count) (decltype(&(c_array)[0]))DN_CArray2_AddArray(c_array, size, max, sizeof((c_array)[0]), items, count, DN_ArrayAdd_Prepend) -#define DN_LArray_Prepend(c_array, size, max, item) (decltype(&(c_array)[0]))DN_CArray2_AddArray(c_array, size, max, sizeof((c_array)[0]), &item, 1, DN_ArrayAdd_Prepend) -#define DN_LArray_EraseRange(c_array, size, begin_index, count, erase) DN_CArray2_EraseRange(c_array, size, sizeof((c_array)[0]), begin_index, count, erase) -#define DN_LArray_Erase(c_array, size, index, erase) DN_CArray2_EraseRange(c_array, size, sizeof((c_array)[0]), index, 1, erase) -#define DN_LArray_InsertArray(c_array, size, max, index, items, count) (decltype(&(c_array)[0]))DN_CArray2_InsertArray(c_array, size, max, sizeof((c_array)[0]), index, items, count) -#define DN_LArray_Insert(c_array, size, max, index, item) (decltype(&(c_array)[0]))DN_CArray2_InsertArray(c_array, size, max, sizeof((c_array)[0]), index, &item, 1) - -#define DN_IArray_ResizeFromPool(array, pool, new_max) DN_CArray2_ResizeFromPool((void **)(&(array)->data), &(array)->size, &(array)->max, sizeof((array)->data[0]), pool, new_max) -#define DN_IArray_GrowFromPool(array, pool, new_max) DN_CArray2_GrowFromPool((void **)(&(array)->data), &(array)->size, &(array)->max, sizeof((array)->data[0]), pool, new_max) -#define DN_IArray_GrowIfNeededFromPool(array, pool, add_count) DN_CArray2_GrowIfNeededFromPool((void **)(&(array)->data), (array)->size, &(array)->max, sizeof((array)->data[0]), pool, add_count) -#define DN_IArray_MakeArray(array, count, z_mem) (decltype(&((array)->data)[0]))DN_CArray2_MakeArray((array)->data, &(array)->size, (array)->max, sizeof(((array)->data)[0]), count, z_mem) -#define DN_IArray_MakeArrayZ(array, count) (decltype(&((array)->data)[0]))DN_CArray2_MakeArray((array)->data, &(array)->size, (array)->max, sizeof(((array)->data)[0]), count, DN_ZMem_Yes) -#define DN_IArray_Make(array, z_mem) (decltype(&((array)->data)[0]))DN_CArray2_MakeArray((array)->data, &(array)->size, (array)->max, sizeof(((array)->data)[0]), 1, z_mem) -#define DN_IArray_MakeZ(array) (decltype(&((array)->data)[0]))DN_CArray2_MakeArray((array)->data, &(array)->size, (array)->max, sizeof(((array)->data)[0]), 1, DN_ZMem_Yes) -#define DN_IArray_AddArray(array, items, count, add) (decltype(&((array)->data)[0]))DN_CArray2_AddArray((array)->data, &(array)->size, (array)->max, sizeof(((array)->data)[0]), items, count, add) -#define DN_IArray_Add(array, item, add) (decltype(&((array)->data)[0]))DN_CArray2_AddArray((array)->data, &(array)->size, (array)->max, sizeof(((array)->data)[0]), &item, 1, add) -#define DN_IArray_AppendArray(array, items, count) (decltype(&((array)->data)[0]))DN_CArray2_AddArray((array)->data, &(array)->size, (array)->max, sizeof(((array)->data)[0]), items, count, DN_ArrayAdd_Append) -#define DN_IArray_Append(array, item) (decltype(&((array)->data)[0]))DN_CArray2_AddArray((array)->data, &(array)->size, (array)->max, sizeof(((array)->data)[0]), &item, 1, DN_ArrayAdd_Append) -#define DN_IArray_PrependArray(array, items, count) (decltype(&((array)->data)[0]))DN_CArray2_AddArray((array)->data, &(array)->size, (array)->max, sizeof(((array)->data)[0]), items, count, DN_ArrayAdd_Prepend) -#define DN_IArray_Prepend(array, item) (decltype(&((array)->data)[0]))DN_CArray2_AddArray((array)->data, &(array)->size, (array)->max, sizeof(((array)->data)[0]), &item, 1, DN_ArrayAdd_Prepend) -#define DN_IArray_EraseRange(array, begin_index, count, erase) DN_CArray2_EraseRange((array)->data, &(array)->size, sizeof(((array)->data)[0]), begin_index, count, erase) -#define DN_IArray_Erase(array, index, erase) DN_CArray2_EraseRange((array)->data, &(array)->size, sizeof(((array)->data)[0]), index, 1, erase) -#define DN_IArray_InsertArray(array, index, items, count) (decltype(&((array)->data)[0]))DN_CArray2_InsertArray((array)->data, &(array)->size, (array)->max, sizeof(((array)->data)[0]), index, items, count) -#define DN_IArray_Insert(array, index, item, count) (decltype(&((array)->data)[0]))DN_CArray2_InsertArray((array)->data, &(array)->size, (array)->max, sizeof(((array)->data)[0]), index, &item, 1) - -DN_API DN_ArrayEraseResult DN_CArray2_EraseRange (void *data, DN_USize *size, DN_USize elem_size, DN_USize begin_index, DN_ISize count, DN_ArrayErase erase); -DN_API void *DN_CArray2_MakeArray (void *data, DN_USize *size, DN_USize max, DN_USize data_size, DN_USize make_size, DN_ZMem z_mem); -DN_API void *DN_CArray2_AddArray (void *data, DN_USize *size, DN_USize max, DN_USize data_size, void const *elems, DN_USize elems_count, DN_ArrayAdd add); -DN_API bool DN_CArray2_Resize (void **data, DN_USize *size, DN_USize *max, DN_USize data_size, DN_Pool *pool, DN_USize new_max); -DN_API bool DN_CArray2_Grow (void **data, DN_USize *size, DN_USize *max, DN_USize data_size, DN_Pool *pool, DN_USize new_max); -DN_API bool DN_CArray2_GrowIfNeededFromPool (void **data, DN_USize size, DN_USize *max, DN_USize data_size, DN_Pool *pool); -DN_API void *DN_CSLList_Detach (void **link, void **next); - -DN_API bool DN_Ring_HasSpace (DN_Ring const *ring, DN_U64 size); -DN_API bool DN_Ring_HasData (DN_Ring const *ring, DN_U64 size); -DN_API void DN_Ring_Write (DN_Ring *ring, void const *src, DN_U64 src_size); -#define DN_Ring_WriteStruct(ring, item) DN_Ring_Write((ring), (item), sizeof(*(item))) -DN_API void DN_Ring_Read (DN_Ring *ring, void *dest, DN_U64 dest_size); -#define DN_Ring_ReadStruct(ring, dest) DN_Ring_Read((ring), (dest), sizeof(*(dest))) - -template DN_ArrayEraseResult DN_CArray_EraseRange (T *data, DN_USize *size, DN_USize begin_index, DN_ISize count, DN_ArrayErase erase); -template T * DN_CArray_MakeArray (T *data, DN_USize *size, DN_USize max, DN_USize count, DN_ZMem z_mem); -template T * DN_CArray_InsertArray (T *data, DN_USize *size, DN_USize max, DN_USize index, T const *items, DN_USize count); -template T DN_CArray_PopFront (T *data, DN_USize *size, DN_USize count); -template T DN_CArray_PopBack (T *data, DN_USize *size, DN_USize count); -template DN_ArrayFindResult DN_CArray_Find (T *data, DN_USize size, T const &value); - -// NOTE: DN_SArray ///////////////////////////////////////////////////////////////////////////////// -#if !defined(DN_NO_SARRAY) -template DN_SArray DN_SArray_Init (DN_Arena *arena, DN_USize size, DN_ZMem z_mem); -template DN_SArray DN_SArray_InitSlice (DN_Arena *arena, DN_Slice slice, DN_USize size, DN_ZMem z_mem); -template DN_SArray DN_SArray_InitCArray (DN_Arena *arena, T const (&array)[N], DN_USize size, DN_ZMem); -template DN_SArray DN_SArray_InitBuffer (T* buffer, DN_USize size); -template bool DN_SArray_IsValid (DN_SArray const *array); -template DN_Slice DN_SArray_Slice (DN_SArray const *array); -template T * DN_SArray_AddArray (DN_SArray *array, T const *items, DN_USize count); -template T * DN_SArray_AddCArray (DN_SArray *array, T const (&items)[N]); -template T * DN_SArray_Add (DN_SArray *array, T const &item); -#define DN_SArray_AddArrayAssert(...) DN_HardAssert(DN_SArray_AddArray(__VA_ARGS__)) -#define DN_SArray_AddCArrayAssert(...) DN_HardAssert(DN_SArray_AddCArray(__VA_ARGS__)) -#define DN_SArray_AddAssert(...) DN_HardAssert(DN_SArray_Add(__VA_ARGS__)) -template T * DN_SArray_MakeArray (DN_SArray *array, DN_USize count, DN_ZMem z_mem); -template T * DN_SArray_Make (DN_SArray *array, DN_ZMem z_mem); -#define DN_SArray_MakeArrayAssert(...) DN_HardAssert(DN_SArray_MakeArray(__VA_ARGS__)) -#define DN_SArray_MakeAssert(...) DN_HardAssert(DN_SArray_Make(__VA_ARGS__)) -template T * DN_SArray_InsertArray (DN_SArray *array, DN_USize index, T const *items, DN_USize count); -template T * DN_SArray_InsertCArray (DN_SArray *array, DN_USize index, T const (&items)[N]); -template T * DN_SArray_Insert (DN_SArray *array, DN_USize index, T const &item); -#define DN_SArray_InsertArrayAssert(...) DN_HardAssert(DN_SArray_InsertArray(__VA_ARGS__)) -#define DN_SArray_InsertCArrayAssert(...) DN_HardAssert(DN_SArray_InsertCArray(__VA_ARGS__)) -#define DN_SArray_InsertAssert(...) DN_HardAssert(DN_SArray_Insert(__VA_ARGS__)) -template T DN_SArray_PopFront (DN_SArray *array, DN_USize count); -template T DN_SArray_PopBack (DN_SArray *array, DN_USize count); -template DN_ArrayEraseResult DN_SArray_EraseRange (DN_SArray *array, DN_USize begin_index, DN_ISize count, DN_ArrayErase erase); -template void DN_SArray_Clear (DN_SArray *array); -#endif // !defined(DN_NO_SARRAY) - -#if !defined(DN_NO_FARRAY) -#define DN_FArray_ToSArray(array) DN_SArray_InitBuffer((array)->data, DN_ArrayCountU((array)->data)) -template DN_FArray DN_FArray_Init (T const *array, DN_USize count); -#define DN_FArray_HasData(array) ((array).data && (array).size) -template DN_FArray DN_FArray_InitSlice (DN_Slice slice); -template DN_FArray DN_FArray_InitCArray (T const (&items)[K]); -template bool DN_FArray_IsValid (DN_FArray const *array); -template DN_USize DN_FArray_Max (DN_FArray const *) { return N; } -template DN_Slice DN_FArray_Slice (DN_FArray const *array); -template T * DN_FArray_AddArray (DN_FArray *array, T const *items, DN_USize count); -template T * DN_FArray_AddCArray (DN_FArray *array, T const (&items)[K]); -template T * DN_FArray_Add (DN_FArray *array, T const &item); -#define DN_FArray_AddArrayAssert(...) DN_HardAssert(DN_FArray_AddArray(__VA_ARGS__)) -#define DN_FArray_AddCArrayAssert(...) DN_HardAssert(DN_FArray_AddCArray(__VA_ARGS__)) -#define DN_FArray_AddAssert(...) DN_HardAssert(DN_FArray_Add(__VA_ARGS__)) -template T * DN_FArray_MakeArray (DN_FArray *array, DN_USize count, DN_ZMem z_mem); -template T * DN_FArray_Make (DN_FArray *array, DN_ZMem z_mem); -#define DN_FArray_MakeArrayAssert(...) DN_HardAssert(DN_FArray_MakeArray(__VA_ARGS__)) -#define DN_FArray_MakeAssert(...) DN_HardAssert(DN_FArray_Make(__VA_ARGS__)) -template T * DN_FArray_InsertArray (DN_FArray *array, T const &item, DN_USize index); -template T * DN_FArray_InsertCArray (DN_FArray *array, DN_USize index, T const (&items)[K]); -template T * DN_FArray_Insert (DN_FArray *array, DN_USize index, T const &item); -#define DN_FArray_InsertArrayAssert(...) DN_HardAssert(DN_FArray_InsertArray(__VA_ARGS__)) -#define DN_FArray_InsertAssert(...) DN_HardAssert(DN_FArray_Insert(__VA_ARGS__)) -template T DN_FArray_PopFront (DN_FArray *array, DN_USize count); -template T DN_FArray_PopBack (DN_FArray *array, DN_USize count); -template DN_ArrayFindResult DN_FArray_Find (DN_FArray *array, T const &find); -template DN_ArrayEraseResult DN_FArray_EraseRange (DN_FArray *array, DN_USize begin_index, DN_ISize count, DN_ArrayErase erase); -template void DN_FArray_Clear (DN_FArray *array); -#endif // !defined(DN_NO_FARRAY) - -#if !defined(DN_NO_SLICE) -#define DN_TO_SLICE(val) DN_Slice_Init((val)->data, (val)->size) -#define DN_Slice_InitCArray(array) DN_Slice_Init(array, DN_ArrayCountU(array)) -template DN_Slice DN_Slice_Init (T* const data, DN_USize size); -template DN_Slice DN_Slice_InitCArrayCopy (DN_Arena *arena, T const (&array)[N]); -template DN_Slice DN_Slice_Copy (DN_Arena *arena, DN_Slice slice); -template DN_Slice DN_Slice_CopyPtr (DN_Arena *arena, T* const data, DN_USize size); -template DN_Slice DN_Slice_Alloc (DN_Arena *arena, DN_USize size, DN_ZMem z_mem); - DN_Str8 DN_Slice_Str8Render (DN_Arena *arena, DN_Slice array, DN_Str8 separator); - DN_Str8 DN_Slice_Str8RenderSpaceSeparated (DN_Arena *arena, DN_Slice array); - DN_Str16 DN_Slice_Str16Render (DN_Arena *arena, DN_Slice array, DN_Str16 separator); - DN_Str16 DN_Slice_Str16RenderSpaceSeparated(DN_Arena *arena, DN_Slice array); -#endif // !defined(DN_NO_SLICE) - -#if !defined(DN_NO_DSMAP) -template DN_DSMap DN_DSMap_Init (DN_Arena *arena, DN_U32 size, DN_DSMapFlags flags); -template void DN_DSMap_Deinit (DN_DSMap *map, DN_ZMem z_mem); -template bool DN_DSMap_IsValid (DN_DSMap const *map); -template DN_U32 DN_DSMap_Hash (DN_DSMap const *map, DN_DSMapKey key); -template DN_U32 DN_DSMap_HashToSlotIndex (DN_DSMap const *map, DN_DSMapKey key); -template DN_DSMapResult DN_DSMap_Find (DN_DSMap const *map, DN_DSMapKey key); -template DN_DSMapResult DN_DSMap_Make (DN_DSMap *map, DN_DSMapKey key); -template DN_DSMapResult DN_DSMap_Set (DN_DSMap *map, DN_DSMapKey key, T const &value); -template DN_DSMapResult DN_DSMap_FindKeyU64 (DN_DSMap const *map, DN_U64 key); -template DN_DSMapResult DN_DSMap_MakeKeyU64 (DN_DSMap *map, DN_U64 key); -template DN_DSMapResult DN_DSMap_SetKeyU64 (DN_DSMap *map, DN_U64 key, T const &value); -template DN_DSMapResult DN_DSMap_FindKeyStr8 (DN_DSMap const *map, DN_Str8 key); -template DN_DSMapResult DN_DSMap_MakeKeyStr8 (DN_DSMap *map, DN_Str8 key); -template DN_DSMapResult DN_DSMap_SetKeyStr8 (DN_DSMap *map, DN_Str8 key, T const &value); -template bool DN_DSMap_Resize (DN_DSMap *map, DN_U32 size); -template bool DN_DSMap_Erase (DN_DSMap *map, DN_DSMapKey key); -template bool DN_DSMap_EraseKeyU64 (DN_DSMap *map, DN_U64 key); -template bool DN_DSMap_EraseKeyStr8 (DN_DSMap *map, DN_Str8 key); -template DN_DSMapKey DN_DSMap_KeyBuffer (DN_DSMap const *map, void const *data, DN_U32 size); -template DN_DSMapKey DN_DSMap_KeyBufferAsU64NoHash (DN_DSMap const *map, void const *data, DN_U32 size); -template DN_DSMapKey DN_DSMap_KeyU64 (DN_DSMap const *map, DN_U64 u64); -template DN_DSMapKey DN_DSMap_KeyStr8 (DN_DSMap const *map, DN_Str8 string); -#define DN_DSMap_KeyCStr8(map, string) DN_DSMap_KeyBuffer(map, string, sizeof((string))/sizeof((string)[0]) - 1) -DN_API DN_DSMapKey DN_DSMap_KeyU64NoHash (DN_U64 u64); -DN_API bool DN_DSMap_KeyEquals (DN_DSMapKey lhs, DN_DSMapKey rhs); -DN_API bool operator== (DN_DSMapKey lhs, DN_DSMapKey rhs); -#endif // !defined(DN_NO_DSMAP) - -#if !defined(DN_NO_LIST) -template DN_List DN_List_Init (DN_USize chunk_size); -template DN_List DN_List_InitCArray (DN_Arena *arena, DN_USize chunk_size, T const (&array)[N]); -template T * DN_List_At (DN_List *list, DN_USize index, DN_ListChunk **at_chunk); -template void DN_List_Clear (DN_List *list); -template bool DN_List_Iterate (DN_List *list, DN_ListIterator *it, DN_USize start_index); -template T * DN_List_MakeArena (DN_List *list, DN_Arena *arena, DN_USize count); -template T * DN_List_MakePool (DN_List *list, DN_Pool *pool, DN_USize count); -template T * DN_List_AddArena (DN_List *list, DN_Arena *arena, T const &value); -template T * DN_List_AddPool (DN_List *list, DN_Pool *pool, T const &value); -template void DN_List_AddListArena (DN_List *list, DN_Arena *arena, DN_List other); -template void DN_List_AddListArena (DN_List *list, DN_Pool *pool, DN_List other); -template DN_Slice DN_List_ToSliceCopy (DN_List const *list, DN_Arena* arena); -#endif // !defined(DN_NO_LIST) -#endif // !defined(DN_CONTAINER_H) -// DN: Single header generator commented out this header => #include "Base/dn_base_leak.h" -// DN: Single header generator commented out this header => #include "../dn_base_inc.h" - -enum DN_LeakAllocFlag -{ - DN_LeakAllocFlag_Freed = 1 << 0, - DN_LeakAllocFlag_LeakPermitted = 1 << 1, -}; - -struct DN_LeakAlloc -{ - void *ptr; // 8 Pointer to the allocation being tracked - DN_USize size; // 16 Size of the allocation - DN_USize freed_size; // 24 Store the size of the allocation when it is freed - DN_Str8 stack_trace; // 40 Stack trace at the point of allocation - DN_Str8 freed_stack_trace; // 56 Stack trace of where the allocation was freed - DN_U16 flags; // 72 Bit flags from `DN_LeakAllocFlag` -}; - -// NOTE: We aim to keep the allocation record as light as possible as memory tracking can get -// expensive. Enforce that there is no unexpected padding. -DN_StaticAssert(sizeof(DN_LeakAlloc) == 64 || sizeof(DN_LeakAlloc) == 32); // NOTE: 64 bit vs 32 bit pointers respectively - -struct DN_LeakTracker -{ - DN_DSMap alloc_table; - DN_TicketMutex alloc_table_mutex; - DN_Arena alloc_table_arena; - DN_U64 alloc_table_bytes_allocated_for_stack_traces; -}; - -DN_API void DN_LeakTrackAlloc_ (DN_LeakTracker *leak, void *ptr, DN_USize size, bool alloc_can_leak); -DN_API void DN_LeakTrackDealloc_(DN_LeakTracker *leak, void *ptr); -DN_API void DN_LeakDump_ (DN_LeakTracker *leak); - -#if defined(DN_LEAK_TRACKING) -#define DN_LeakTrackAlloc(leak, ptr, size, alloc_can_leak) DN_LeakTrackAlloc_(leak, ptr, size, alloc_can_leak) -#define DN_LeakTrackDealloc(leak, ptr) DN_LeakTrackDealloc_(leak, ptr) -#define DN_LeakDump(leak) DN_LeakDump_(leak) -#else -#define DN_LeakTrackAlloc(leak, ptr, size, alloc_can_leak) do { (void)ptr; (void)size; (void)alloc_can_leak; } while (0) -#define DN_LeakTrackDealloc(leak, ptr) do { (void)ptr; } while (0) -#define DN_LeakDump(leak) do { } while (0) -#endif - - -#endif // !defined(DN_BASE_INC_H) - // DN: Single header generator commented out this header => #include "dn_os_inc.h" -#if !defined(DN_OS_INC_H) -#define DN_OS_INC_H - -#if defined(DN_PLATFORM_WIN32) - // DN: Single header generator commented out this header => #include "OS/dn_os_windows.h" -#if !defined(DN_OS_WINDOWS_H) -#define DN_OS_WINDOWS_H - -#if defined(_CLANGD) - // DN: Single header generator commented out this header => #include "../dn_base_inc.h" -#endif - -#if defined(DN_COMPILER_MSVC) || defined(DN_COMPILER_CLANG_CL) - #pragma comment(lib, "bcrypt") - #pragma comment(lib, "winhttp") - #pragma comment(lib, "dbghelp") - #pragma comment(lib, "comdlg32") - #pragma comment(lib, "pathcch") - #pragma comment(lib, "Shell32") // ShellExecuteW - #pragma comment(lib, "shlwapi") -#endif - -#if defined(DN_NO_WINDOWS_H_REPLACEMENT_HEADER) || defined(_INC_WINDOWS) - #define WIN32_LEAN_AND_MEAN - #include // LONG - #include // DN_OS_SecureRNGBytes -> BCryptOpenAlgorithmProvider ... etc - #include // DN_Win_MakeProcessDPIAware -> SetProcessDpiAwareProc - #include // PathRelativePathTO - #include // PathCchCanonicalizeEx - #include // WinHttp* - #include // PROCESS_MEMORY_COUNTERS_EX2 - #include // OPENFILENAMEW - #include -#else - DN_MSVC_WARNING_PUSH - DN_MSVC_WARNING_DISABLE(4201) // warning C4201: nonstandard extension used: nameless struct/union - - // NOTE: basetsd.h ///////////////////////////////////////////////////////////////////////////// - typedef unsigned __int64 ULONG_PTR, *PULONG_PTR; - typedef unsigned __int64 UINT_PTR, *PUINT_PTR; - typedef ULONG_PTR SIZE_T, *PSIZE_T; - typedef __int64 LONG_PTR, *PLONG_PTR; - typedef ULONG_PTR DWORD_PTR, *PDWORD_PTR; - typedef unsigned __int64 ULONG64, *PULONG64; - typedef unsigned __int64 DWORD64, *PDWORD64; - - // NOTE: shared/minwindef.h //////////////////////////////////////////////////////////////////// - struct HINSTANCE__ { - int unused; - }; - typedef struct HINSTANCE__ *HINSTANCE; - - typedef unsigned long DWORD; - typedef int BOOL; - typedef int INT; - typedef unsigned long ULONG; - typedef unsigned int UINT; - typedef unsigned short WORD; - typedef unsigned char BYTE; - typedef unsigned char UCHAR; - typedef HINSTANCE HMODULE; /* HMODULEs can be used in place of HINSTANCEs */ - typedef void * HANDLE; - typedef HANDLE HLOCAL; - - typedef unsigned __int64 WPARAM; - typedef LONG_PTR LPARAM; - typedef LONG_PTR LRESULT; - - #define MAX_PATH 260 - - typedef struct _FILETIME { - DWORD dwLowDateTime; - DWORD dwHighDateTime; - } FILETIME, *PFILETIME, *LPFILETIME; - - // NOTE: shared/winerror.h ///////////////////////////////////////////////////////////////////// - // NOTE: GetModuleFileNameW - #define ERROR_INSUFFICIENT_BUFFER 122L // dderror - - // NOTE: um/winnls.h /////////////////////////////////////////////////////////////////////////// - // NOTE: MultiByteToWideChar - #define CP_UTF8 65001 // UTF-8 translation - - // NOTE: um/winnt.h //////////////////////////////////////////////////////////////////////////// - typedef void VOID; - typedef __int64 LONGLONG; - typedef unsigned __int64 ULONGLONG; - typedef void * HANDLE; - typedef char CHAR; - typedef short SHORT; - typedef long LONG; - typedef wchar_t WCHAR; // wc, 16-bit UNICODE character - typedef CHAR * NPSTR, *LPSTR, *PSTR; - typedef WCHAR * NWPSTR, *LPWSTR, *PWSTR; - typedef long HRESULT; - - // NOTE: VirtualAlloc: Allocation Type - #define MEM_RESERVE 0x00002000 - #define MEM_COMMIT 0x00001000 - #define MEM_DECOMMIT 0x00004000 - #define MEM_RELEASE 0x00008000 - - // NOTE: VirtualAlloc: Page Permissions - #define PAGE_NOACCESS 0x01 - #define PAGE_READONLY 0x02 - #define PAGE_READWRITE 0x04 - #define PAGE_GUARD 0x100 - - // NOTE: HeapAlloc - #define HEAP_ZERO_MEMORY 0x00000008 - #define HEAP_NO_SERIALIZE 0x00000001 - #define HEAP_GROWABLE 0x00000002 - #define HEAP_GENERATE_EXCEPTIONS 0x00000004 - #define HEAP_ZERO_MEMORY 0x00000008 - #define HEAP_REALLOC_IN_PLACE_ONLY 0x00000010 - #define HEAP_TAIL_CHECKING_ENABLED 0x00000020 - #define HEAP_FREE_CHECKING_ENABLED 0x00000040 - #define HEAP_DISABLE_COALESCE_ON_FREE 0x00000080 - #define HEAP_CREATE_ALIGN_16 0x00010000 - #define HEAP_CREATE_ENABLE_TRACING 0x00020000 - #define HEAP_CREATE_ENABLE_EXECUTE 0x00040000 - #define HEAP_MAXIMUM_TAG 0x0FFF - #define HEAP_PSEUDO_TAG_FLAG 0x8000 - #define HEAP_TAG_SHIFT 18 - #define HEAP_CREATE_SEGMENT_HEAP 0x00000100 - #define HEAP_CREATE_HARDENED 0x00000200 - - // NOTE: FormatMessageA - #define MAKELANGID(p, s) ((((WORD )(s)) << 10) | (WORD )(p)) - #define LANG_NEUTRAL 0x00 - #define SUBLANG_DEFAULT 0x01 // user default - - // NOTE: CreateFile - #define GENERIC_READ (0x80000000L) - #define GENERIC_WRITE (0x40000000L) - #define GENERIC_EXECUTE (0x20000000L) - #define GENERIC_ALL (0x10000000L) - - #define FILE_APPEND_DATA (0x0004) // file - - // NOTE: CreateFile/FindFirstFile - #define FILE_SHARE_READ 0x00000001 - #define FILE_SHARE_WRITE 0x00000002 - #define FILE_SHARE_DELETE 0x00000004 - - #define FILE_ATTRIBUTE_READONLY 0x00000001 - #define FILE_ATTRIBUTE_HIDDEN 0x00000002 - #define FILE_ATTRIBUTE_SYSTEM 0x00000004 - #define FILE_ATTRIBUTE_DIRECTORY 0x00000010 - #define FILE_ATTRIBUTE_NORMAL 0x00000080 - - // NOTE: STACKFRAME64 - #define IMAGE_FILE_MACHINE_AMD64 0x8664 // AMD64 (K8) - - // NOTE: WaitForSingleObject - #define WAIT_TIMEOUT 258L // dderror - #define STATUS_WAIT_0 ((DWORD )0x00000000L) - #define STATUS_ABANDONED_WAIT_0 ((DWORD )0x00000080L) - - #define S_OK ((HRESULT)0L) - #define S_FALSE ((HRESULT)1L) - - typedef union _ULARGE_INTEGER { - struct { - DWORD LowPart; - DWORD HighPart; - } DUMMYSTRUCTNAME; - struct { - DWORD LowPart; - DWORD HighPart; - } u; - ULONGLONG QuadPart; - } ULARGE_INTEGER; - - typedef union _LARGE_INTEGER { - struct { - DWORD LowPart; - LONG HighPart; - } DUMMYSTRUCTNAME; - struct { - DWORD LowPart; - LONG HighPart; - } u; - LONGLONG QuadPart; - } LARGE_INTEGER; - - typedef struct __declspec(align(16)) _M128A { - ULONGLONG Low; - LONGLONG High; - } M128A, *PM128A; - - typedef struct __declspec(align(16)) _XSAVE_FORMAT { - WORD ControlWord; - WORD StatusWord; - BYTE TagWord; - BYTE Reserved1; - WORD ErrorOpcode; - DWORD ErrorOffset; - WORD ErrorSelector; - WORD Reserved2; - DWORD DataOffset; - WORD DataSelector; - WORD Reserved3; - DWORD MxCsr; - DWORD MxCsr_Mask; - M128A FloatRegisters[8]; - #if defined(_WIN64) - M128A XmmRegisters[16]; - BYTE Reserved4[96]; - #else - M128A XmmRegisters[8]; - BYTE Reserved4[224]; - #endif - } XSAVE_FORMAT, *PXSAVE_FORMAT; - typedef XSAVE_FORMAT XMM_SAVE_AREA32, *PXMM_SAVE_AREA32; - - typedef struct __declspec(align(16)) _CONTEXT { - DWORD64 P1Home; - DWORD64 P2Home; - DWORD64 P3Home; - DWORD64 P4Home; - DWORD64 P5Home; - DWORD64 P6Home; - DWORD ContextFlags; - DWORD MxCsr; - WORD SegCs; - WORD SegDs; - WORD SegEs; - WORD SegFs; - WORD SegGs; - WORD SegSs; - DWORD EFlags; - DWORD64 Dr0; - DWORD64 Dr1; - DWORD64 Dr2; - DWORD64 Dr3; - DWORD64 Dr6; - DWORD64 Dr7; - DWORD64 Rax; - DWORD64 Rcx; - DWORD64 Rdx; - DWORD64 Rbx; - DWORD64 Rsp; - DWORD64 Rbp; - DWORD64 Rsi; - DWORD64 Rdi; - DWORD64 R8; - DWORD64 R9; - DWORD64 R10; - DWORD64 R11; - DWORD64 R12; - DWORD64 R13; - DWORD64 R14; - DWORD64 R15; - DWORD64 Rip; - - union { - XMM_SAVE_AREA32 FltSave; - - struct { - M128A Header[2]; - M128A Legacy[8]; - M128A Xmm0; - M128A Xmm1; - M128A Xmm2; - M128A Xmm3; - M128A Xmm4; - M128A Xmm5; - M128A Xmm6; - M128A Xmm7; - M128A Xmm8; - M128A Xmm9; - M128A Xmm10; - M128A Xmm11; - M128A Xmm12; - M128A Xmm13; - M128A Xmm14; - M128A Xmm15; - } DUMMYSTRUCTNAME; - } DUMMYUNIONNAME; - - M128A VectorRegister[26]; - DWORD64 VectorControl; - DWORD64 DebugControl; - DWORD64 LastBranchToRip; - DWORD64 LastBranchFromRip; - DWORD64 LastExceptionToRip; - DWORD64 LastExceptionFromRip; - } CONTEXT; - - typedef struct _LIST_ENTRY { - struct _LIST_ENTRY *Flink; - struct _LIST_ENTRY *Blink; - } LIST_ENTRY, *PLIST_ENTRY, PRLIST_ENTRY; - - typedef struct _RTL_CRITICAL_SECTION_DEBUG { - WORD Type; - WORD CreatorBackTraceIndex; - struct _RTL_CRITICAL_SECTION *CriticalSection; - LIST_ENTRY ProcessLocksList; - DWORD EntryCount; - DWORD ContentionCount; - DWORD Flags; - WORD CreatorBackTraceIndexHigh; - WORD Identifier; - } RTL_CRITICAL_SECTION_DEBUG, *PRTL_CRITICAL_SECTION_DEBUG, RTL_RESOURCE_DEBUG, *PRTL_RESOURCE_DEBUG; - - typedef struct _RTL_CONDITION_VARIABLE { - VOID *Ptr; - } RTL_CONDITION_VARIABLE, *PRTL_CONDITION_VARIABLE; - - #pragma pack(push, 8) - typedef struct _RTL_CRITICAL_SECTION { - PRTL_CRITICAL_SECTION_DEBUG DebugInfo; - - // - // The following three fields control entering and exiting the critical - // section for the resource - // - - LONG LockCount; - LONG RecursionCount; - HANDLE OwningThread; // from the thread's ClientId->UniqueThread - HANDLE LockSemaphore; - ULONG_PTR SpinCount; // force size on 64-bit systems when packed - } RTL_CRITICAL_SECTION, *PRTL_CRITICAL_SECTION; - #pragma pack(pop) - - typedef struct _MODLOAD_DATA { - DWORD ssize; // size of this struct - DWORD ssig; // signature identifying the passed data - VOID *data; // pointer to passed data - DWORD size; // size of passed data - DWORD flags; // options - } MODLOAD_DATA, *PMODLOAD_DATA; - - #define SLMFLAG_VIRTUAL 0x1 - #define SLMFLAG_ALT_INDEX 0x2 - #define SLMFLAG_NO_SYMBOLS 0x4 - - extern "C" - { - __declspec(dllimport) VOID __stdcall RtlCaptureContext(CONTEXT *ContextRecord); - __declspec(dllimport) HANDLE __stdcall GetCurrentProcess(void); - __declspec(dllimport) HANDLE __stdcall GetCurrentThread(void); - __declspec(dllimport) DWORD __stdcall SymSetOptions(DWORD SymOptions); - __declspec(dllimport) BOOL __stdcall SymInitialize(HANDLE hProcess, const CHAR* UserSearchPath, BOOL fInvadeProcess); - __declspec(dllimport) DWORD64 __stdcall SymLoadModuleEx(HANDLE hProcess, HANDLE hFile, CHAR const *ImageName, CHAR const *ModuleName, DWORD64 BaseOfDll, DWORD DllSize, MODLOAD_DATA *Data, DWORD Flags); - __declspec(dllimport) BOOL __stdcall SymUnloadModule64(HANDLE hProcess, DWORD64 BaseOfDll); - } - - // NOTE: um/heapapi.h //////////////////////////////////////////////////////////////////// - extern "C" - { - __declspec(dllimport) HANDLE __stdcall HeapCreate(DWORD flOptions, SIZE_T dwInitialSize, SIZE_T dwMaximumSize); - __declspec(dllimport) BOOL __stdcall HeapDestroy(HANDLE hHeap); - __declspec(dllimport) VOID * __stdcall HeapAlloc(HANDLE hHeap, DWORD dwFlags,SIZE_T dwBytes); - __declspec(dllimport) VOID * __stdcall HeapReAlloc(HANDLE hHeap, DWORD dwFlags, VOID *lpMem, SIZE_T dwBytes); - __declspec(dllimport) BOOL __stdcall HeapFree(HANDLE hHeap, DWORD dwFlags, VOID *lpMem); - __declspec(dllimport) SIZE_T __stdcall HeapSize(HANDLE hHeap, DWORD dwFlags, VOID const *lpMem); - __declspec(dllimport) HANDLE __stdcall GetProcessHeap(VOID); - __declspec(dllimport) SIZE_T __stdcall HeapCompact(HANDLE hHeap, DWORD dwFlags); - } - - // NOTE: shared/windef.h //////////////////////////////////////////////////////////////////// - typedef struct tagPOINT - { - LONG x; - LONG y; - } POINT, *PPOINT, *NPPOINT, *LPPOINT; - - // NOTE: handleapi.h /////////////////////////////////////////////////////////////////////////// - #define INVALID_HANDLE_VALUE ((HANDLE)(LONG_PTR)-1) - - extern "C" - { - __declspec(dllimport) BOOL __stdcall CloseHandle(HANDLE hObject); - } - - // NOTE: consoleapi.h /////////////////////////////////////////////////////////////////////////// - extern "C" - { - __declspec(dllimport) BOOL __stdcall WriteConsoleA(HANDLE hConsoleOutput, const VOID* lpBuffer, DWORD nNumberOfCharsToWrite, DWORD *lpNumberOfCharsWritten, VOID *lpReserved); - __declspec(dllimport) BOOL __stdcall AllocConsole(VOID); - __declspec(dllimport) BOOL __stdcall FreeConsole(VOID); - __declspec(dllimport) BOOL __stdcall AttachConsole(DWORD dwProcessId); - __declspec(dllimport) BOOL __stdcall GetConsoleMode(HANDLE hConsoleHandle, DWORD *lpMode); - } - - // NOTE: um/minwinbase.h /////////////////////////////////////////////////////////////////////// - // NOTE: FindFirstFile - #define FIND_FIRST_EX_CASE_SENSITIVE 0x00000001 - #define FIND_FIRST_EX_LARGE_FETCH 0x00000002 - - // NOTE: WaitFor.. - #define WAIT_FAILED ((DWORD)0xFFFFFFFF) - #define WAIT_OBJECT_0 ((STATUS_WAIT_0 ) + 0 ) - #define WAIT_ABANDONED ((STATUS_ABANDONED_WAIT_0 ) + 0 ) - #define WAIT_ABANDONED_0 ((STATUS_ABANDONED_WAIT_0 ) + 0 ) - - // NOTE: CreateProcessW - #define CREATE_UNICODE_ENVIRONMENT 0x00000400 - #define CREATE_NO_WINDOW 0x08000000 - - typedef enum _GET_FILEEX_INFO_LEVELS { - GetFileExInfoStandard, - GetFileExMaxInfoLevel - } GET_FILEEX_INFO_LEVELS; - - typedef struct _SECURITY_ATTRIBUTES { - DWORD nLength; - VOID *lpSecurityDescriptor; - BOOL bInheritHandle; - } SECURITY_ATTRIBUTES, *PSECURITY_ATTRIBUTES, *LPSECURITY_ATTRIBUTES; - - typedef enum _FINDEX_INFO_LEVELS { - FindExInfoStandard, - FindExInfoBasic, - FindExInfoMaxInfoLevel - } FINDEX_INFO_LEVELS; - - typedef enum _FINDEX_SEARCH_OPS { - FindExSearchNameMatch, - FindExSearchLimitToDirectories, - FindExSearchLimitToDevices, - FindExSearchMaxSearchOp - } FINDEX_SEARCH_OPS; - - typedef struct _WIN32_FIND_DATAW { - DWORD dwFileAttributes; - FILETIME ftCreationTime; - FILETIME ftLastAccessTime; - FILETIME ftLastWriteTime; - DWORD nFileSizeHigh; - DWORD nFileSizeLow; - DWORD dwReserved0; - DWORD dwReserved1; - WCHAR cFileName[ MAX_PATH ]; - WCHAR cAlternateFileName[ 14 ]; - #ifdef _MAC - DWORD dwFileType; - DWORD dwCreatorType; - WORD wFinderFlags; - #endif - } WIN32_FIND_DATAW, *PWIN32_FIND_DATAW, *LPWIN32_FIND_DATAW; - - typedef struct _SYSTEMTIME { - WORD wYear; - WORD wMonth; - WORD wDayOfWeek; - WORD wDay; - WORD wHour; - WORD wMinute; - WORD wSecond; - WORD wMilliseconds; - } SYSTEMTIME, *PSYSTEMTIME, *LPSYSTEMTIME; - - typedef struct _OVERLAPPED { - ULONG_PTR Internal; - ULONG_PTR InternalHigh; - union { - struct { - DWORD Offset; - DWORD OffsetHigh; - } DUMMYSTRUCTNAME; - VOID *Pointer; - } DUMMYUNIONNAME; - - HANDLE hEvent; - } OVERLAPPED, *LPOVERLAPPED; - - typedef RTL_CRITICAL_SECTION CRITICAL_SECTION; - - #define WAIT_FAILED ((DWORD)0xFFFFFFFF) - #define WAIT_OBJECT_0 ((STATUS_WAIT_0 ) + 0 ) - - #define INFINITE 0xFFFFFFFF // Wait/Synchronisation: Infinite timeout - - #define STD_INPUT_HANDLE ((DWORD)-10) - #define STD_OUTPUT_HANDLE ((DWORD)-11) - #define STD_ERROR_HANDLE ((DWORD)-12) - - #define HANDLE_FLAG_INHERIT 0x00000001 - #define HANDLE_FLAG_PROTECT_FROM_CLOSE 0x00000002 - - // NOTE: MoveFile - #define MOVEFILE_REPLACE_EXISTING 0x00000001 - #define MOVEFILE_COPY_ALLOWED 0x00000002 - - // NOTE: FormatMessageA - #define FORMAT_MESSAGE_ALLOCATE_BUFFER 0x00000100 - #define FORMAT_MESSAGE_IGNORE_INSERTS 0x00000200 - #define FORMAT_MESSAGE_FROM_HMODULE 0x00000800 - #define FORMAT_MESSAGE_FROM_SYSTEM 0x00001000 - - // NOTE: CreateProcessW - #define STARTF_USESTDHANDLES 0x00000100 - - extern "C" - { - __declspec(dllimport) BOOL __stdcall MoveFileExW (const WCHAR *lpExistingFileName, const WCHAR *lpNewFileName, DWORD dwFlags); - __declspec(dllimport) BOOL __stdcall CopyFileW (const WCHAR *lpExistingFileName, const WCHAR *lpNewFileName, BOOL bFailIfExists); - __declspec(dllimport) HANDLE __stdcall CreateSemaphoreA(SECURITY_ATTRIBUTES *lpSemaphoreAttributes, LONG lInitialCount, LONG lMaximumCount, const CHAR *lpName); - __declspec(dllimport) DWORD __stdcall FormatMessageW (DWORD dwFlags, VOID const *lpSource, DWORD dwMessageId, DWORD dwLanguageId, LPWSTR lpBuffer, DWORD nSize, va_list *Arguments); - __declspec(dllimport) HLOCAL __stdcall LocalFree (HLOCAL hMem); - } - - // NOTE: um/stringapiset.h ///////////////////////////////////////////////////////////////////// - extern "C" - { - __declspec(dllimport) int __stdcall MultiByteToWideChar(UINT CodePage, DWORD dwFlags, const CHAR *lpMultiByteStr, int cbMultiByte, WCHAR *lpWideCharStr, int cchWideChar); - __declspec(dllimport) int __stdcall WideCharToMultiByte(UINT CodePage, DWORD dwFlags, const WCHAR *lpWideCharStr, int cchWideChar, LPSTR lpMultiByteStr, int cbMultiByte, const CHAR *lpDefaultChar, BOOL *lpUsedDefaultChar); - } - - // NOTE: um/fileapi.h ////////////////////////////////////////////////////////////////////////// - #define INVALID_FILE_SIZE ((DWORD)0xFFFFFFFF) - #define INVALID_FILE_ATTRIBUTES ((DWORD)-1) - - // NOTE: CreateFile - #define CREATE_NEW 1 - #define CREATE_ALWAYS 2 - #define OPEN_EXISTING 3 - #define OPEN_ALWAYS 4 - #define TRUNCATE_EXISTING 5 - - typedef struct _WIN32_FILE_ATTRIBUTE_DATA { - DWORD dwFileAttributes; - FILETIME ftCreationTime; - FILETIME ftLastAccessTime; - FILETIME ftLastWriteTime; - DWORD nFileSizeHigh; - DWORD nFileSizeLow; - } WIN32_FILE_ATTRIBUTE_DATA, *LPWIN32_FILE_ATTRIBUTE_DATA; - - extern "C" - { - __declspec(dllimport) BOOL __stdcall FlushFileBuffers (HANDLE hFile); - __declspec(dllimport) BOOL __stdcall CreateDirectoryW (const WCHAR *lpPathName, SECURITY_ATTRIBUTES *lpSecurityAttributes); - __declspec(dllimport) BOOL __stdcall RemoveDirectoryW (const WCHAR *lpPathName); - __declspec(dllimport) BOOL __stdcall FindNextFileW (HANDLE hFindFile, WIN32_FIND_DATAW *lpFindFileData); - __declspec(dllimport) BOOL __stdcall FindClose (HANDLE hFindFile); - __declspec(dllimport) BOOL __stdcall FileTimeToLocalFileTime(const FILETIME *lpFileTime, FILETIME *lpLocalFileTime); - - __declspec(dllimport) HANDLE __stdcall FindFirstFileExW (const WCHAR *lpFileName, FINDEX_INFO_LEVELS fInfoLevelId, VOID *lpFindFileData, FINDEX_SEARCH_OPS fSearchOp, VOID *lpSearchFilter, DWORD dwAdditionalFlags); - __declspec(dllimport) BOOL __stdcall GetFileAttributesExW (const WCHAR *lpFileName, GET_FILEEX_INFO_LEVELS fInfoLevelId, VOID *lpFileInformation); - __declspec(dllimport) BOOL __stdcall GetFileSizeEx (HANDLE hFile, LARGE_INTEGER *lpFileSize); - __declspec(dllimport) BOOL __stdcall DeleteFileW (const WCHAR *lpFileName); - __declspec(dllimport) HANDLE __stdcall CreateFileW (const WCHAR *lpFileName, DWORD dwDesiredAccess, DWORD dwShareMode, SECURITY_ATTRIBUTES *lpSecurityAttributes, DWORD dwCreationDisposition, DWORD dwFlagsAndAttributes, HANDLE hTemplateFile); - __declspec(dllimport) BOOL __stdcall ReadFile (HANDLE hFile, VOID *lpBuffer, DWORD nNumberOfBytesToRead, DWORD *lpNumberOfBytesRead, OVERLAPPED *lpOverlapped); - __declspec(dllimport) BOOL __stdcall WriteFile (HANDLE hFile, const VOID *lpBuffer, DWORD nNumberOfBytesToWrite, DWORD *lpNumberOfBytesWritten, OVERLAPPED *lpOverlapped); - __declspec(dllimport) BOOL __stdcall GetDiskFreeSpaceExW (WCHAR const *lpDirectoryName, ULARGE_INTEGER *lpFreeBytesAvailableToCaller, ULARGE_INTEGER *lpTotalNumberOfBytes, ULARGE_INTEGER *lpTotalNumberOfFreeBytes); - } - - // NOTE: um/processenv.h /////////////////////////////////////////////////////////////////////// - extern "C" - { - __declspec(dllimport) DWORD __stdcall GetCurrentDirectoryW (DWORD nBufferLength, WCHAR *lpBuffer); - __declspec(dllimport) HANDLE __stdcall GetStdHandle (DWORD nStdHandle); - __declspec(dllimport) WCHAR* __stdcall GetEnvironmentStringsW (); - __declspec(dllimport) BOOL __stdcall FreeEnvironmentStringsW(WCHAR *penv); - __declspec(dllimport) DWORD __stdcall GetEnvironmentVariableW(WCHAR const *lpName, WCHAR *lpBuffer, DWORD nSize); - __declspec(dllimport) BOOL __stdcall SetEnvironmentVariableW(WCHAR const *lpName, WCHAR const *lpValue); - } - - // NOTE: um/psapi.h //////////////////////////////////////////////////////////////////////////// - typedef struct _PROCESS_MEMORY_COUNTERS { - 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; - } PROCESS_MEMORY_COUNTERS; - typedef PROCESS_MEMORY_COUNTERS *PPROCESS_MEMORY_COUNTERS; - - extern "C" - { - __declspec(dllimport) BOOL __stdcall GetProcessMemoryInfo(HANDLE Process, PPROCESS_MEMORY_COUNTERS ppsmemCounters, DWORD cb); - } - - // NOTE: um/sysinfoapi.h /////////////////////////////////////////////////////////////////////// - typedef struct _SYSTEM_INFO { - union { - DWORD dwOemId; // Obsolete field...do not use - struct { - WORD wProcessorArchitecture; - WORD wReserved; - } DUMMYSTRUCTNAME; - } DUMMYUNIONNAME; - DWORD dwPageSize; - VOID *lpMinimumApplicationAddress; - VOID *lpMaximumApplicationAddress; - DWORD_PTR dwActiveProcessorMask; - DWORD dwNumberOfProcessors; - DWORD dwProcessorType; - DWORD dwAllocationGranularity; - WORD wProcessorLevel; - WORD wProcessorRevision; - } SYSTEM_INFO, *LPSYSTEM_INFO; - - extern "C" - { - __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); - } - - // NOTE: um/timezoneapi.h ////////////////////////////////////////////////////////////////////// - typedef struct _TIME_ZONE_INFORMATION { - LONG Bias; - WCHAR StandardName[32]; - SYSTEMTIME StandardDate; - LONG StandardBias; - WCHAR DaylightName[32]; - SYSTEMTIME DaylightDate; - LONG DaylightBias; - } TIME_ZONE_INFORMATION, *PTIME_ZONE_INFORMATION, *LPTIME_ZONE_INFORMATION; - - extern "C" - { - __declspec(dllimport) BOOL __stdcall FileTimeToSystemTime (const FILETIME* lpFileTime, SYSTEMTIME *lpSystemTime); - __declspec(dllimport) BOOL __stdcall SystemTimeToFileTime (const SYSTEMTIME* lpSystemTime, FILETIME *lpFileTime); - __declspec(dllimport) BOOL __stdcall TzSpecificLocalTimeToSystemTime(const TIME_ZONE_INFORMATION* lpTimeZoneInformation, const SYSTEMTIME* lpLocalTime, const LPSYSTEMTIME lpUniversalTime); - } - - // NOTE: shared/windef.h /////////////////////////////////////////////////////////////////////// - typedef struct tagRECT { - LONG left; - LONG top; - LONG right; - LONG bottom; - } RECT; - - struct HWND__ { - int unused; - }; - typedef struct HWND__ *HWND; - - struct DPI_AWARENESS_CONTEXT__ { - int unused; - }; - typedef struct DPI_AWARENESS_CONTEXT__ *DPI_AWARENESS_CONTEXT; - - typedef enum DPI_AWARENESS { - DPI_AWARENESS_INVALID = -1, - DPI_AWARENESS_UNAWARE = 0, - DPI_AWARENESS_SYSTEM_AWARE = 1, - DPI_AWARENESS_PER_MONITOR_AWARE = 2 - } DPI_AWARENESS; - - #define DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2 ((DPI_AWARENESS_CONTEXT)-4) - - // NOTE: um/winuser.h ////////////////////////////////////////////////////////////////////////// - typedef struct tagWINDOWPLACEMENT { - UINT length; - UINT flags; - UINT showCmd; - POINT ptMinPosition; - POINT ptMaxPosition; - RECT rcNormalPosition; - #ifdef _MAC - RECT rcDevice; - #endif - } WINDOWPLACEMENT; - typedef WINDOWPLACEMENT *PWINDOWPLACEMENT, *LPWINDOWPLACEMENT; - - #define SW_HIDE 0 - #define SW_NORMAL 1 - #define SW_MAXIMIZE 3 - #define SW_SHOWNOACTIVATE 4 - #define SW_SHOW 5 - #define SW_FORCEMINIMIZE 11 - - extern "C" - { - __declspec(dllimport) BOOL __stdcall GetWindowRect (HWND hWnd, RECT *lpRect); - __declspec(dllimport) BOOL __stdcall SetWindowPos (HWND hWnd, HWND hWndInsertAfter, int X, int Y, int cx, int cy, UINT uFlags); - __declspec(dllimport) UINT __stdcall GetWindowModuleFileNameA(HWND hwnd, LPSTR pszFileName, UINT cchFileNameMax); - __declspec(dllimport) BOOL __stdcall ShowWindow (HWND hWnd, int nCmdShow); - __declspec(dllimport) BOOL __stdcall GetWindowPlacement (HWND hWnd, WINDOWPLACEMENT *lpwndpl); - - } - - // NOTE: um/wininet.h ////////////////////////////////////////////////////////////////////////// - typedef WORD INTERNET_PORT; - typedef VOID *HINTERNET; - - // NOTE: um/winhttp.h ////////////////////////////////////////////////////////////////////////// - #define WINHTTP_ACCESS_TYPE_DEFAULT_PROXY 0 - #define WINHTTP_ACCESS_TYPE_NO_PROXY 1 - #define WINHTTP_ACCESS_TYPE_NAMED_PROXY 3 - #define WINHTTP_ACCESS_TYPE_AUTOMATIC_PROXY 4 - - #define INTERNET_DEFAULT_PORT 0 // use the protocol-specific default - #define INTERNET_DEFAULT_HTTP_PORT 80 // " " HTTP " - #define INTERNET_DEFAULT_HTTPS_PORT 443 // " " HTTPS " - - // NOTE: WinHttpOpen - #define WINHTTP_FLAG_ASYNC 0x10000000 // this session is asynchronous (where supported) - #define WINHTTP_FLAG_SECURE_DEFAULTS 0x30000000 // note that this flag also forces async - - // NOTE: WinHttpOpenRequest - #define WINHTTP_FLAG_SECURE 0x00800000 // use SSL if applicable (HTTPS) - #define WINHTTP_FLAG_ESCAPE_PERCENT 0x00000004 // if escaping enabled, escape percent as well - #define WINHTTP_FLAG_NULL_CODEPAGE 0x00000008 // assume all symbols are ASCII, use fast convertion - #define WINHTTP_FLAG_ESCAPE_DISABLE 0x00000040 // disable escaping - #define WINHTTP_FLAG_ESCAPE_DISABLE_QUERY 0x00000080 // if escaping enabled escape path part, but do not escape query - #define WINHTTP_FLAG_BYPASS_PROXY_CACHE 0x00000100 // add "pragma: no-cache" request header - #define WINHTTP_FLAG_REFRESH WINHTTP_FLAG_BYPASS_PROXY_CACHE - #define WINHTTP_FLAG_AUTOMATIC_CHUNKING 0x00000200 // Send request without content-length header or chunked TE - - #define WINHTTP_NO_PROXY_NAME NULL - #define WINHTTP_NO_PROXY_BYPASS NULL - - // - // WINHTTP_QUERY_FLAG_NUMBER - if this bit is set in the dwInfoLevel parameter of - // HttpQueryHeader(), then the value of the header will be converted to a number - // before being returned to the caller, if applicable - // - #define WINHTTP_QUERY_FLAG_NUMBER 0x20000000 - - #define WINHTTP_QUERY_MIME_VERSION 0 - #define WINHTTP_QUERY_CONTENT_TYPE 1 - #define WINHTTP_QUERY_CONTENT_TRANSFER_ENCODING 2 - #define WINHTTP_QUERY_CONTENT_ID 3 - #define WINHTTP_QUERY_CONTENT_DESCRIPTION 4 - #define WINHTTP_QUERY_CONTENT_LENGTH 5 - #define WINHTTP_QUERY_CONTENT_LANGUAGE 6 - #define WINHTTP_QUERY_ALLOW 7 - #define WINHTTP_QUERY_PUBLIC 8 - #define WINHTTP_QUERY_DATE 9 - #define WINHTTP_QUERY_EXPIRES 10 - #define WINHTTP_QUERY_LAST_MODIFIED 11 - #define WINHTTP_QUERY_MESSAGE_ID 12 - #define WINHTTP_QUERY_URI 13 - #define WINHTTP_QUERY_DERIVED_FROM 14 - #define WINHTTP_QUERY_COST 15 - #define WINHTTP_QUERY_LINK 16 - #define WINHTTP_QUERY_PRAGMA 17 - #define WINHTTP_QUERY_VERSION 18 // special: part of status line - #define WINHTTP_QUERY_STATUS_CODE 19 // special: part of status line - #define WINHTTP_QUERY_STATUS_TEXT 20 // special: part of status line - #define WINHTTP_QUERY_RAW_HEADERS 21 // special: all headers as ASCIIZ - #define WINHTTP_QUERY_RAW_HEADERS_CRLF 22 // special: all headers - #define WINHTTP_QUERY_CONNECTION 23 - #define WINHTTP_QUERY_ACCEPT 24 - #define WINHTTP_QUERY_ACCEPT_CHARSET 25 - #define WINHTTP_QUERY_ACCEPT_ENCODING 26 - #define WINHTTP_QUERY_ACCEPT_LANGUAGE 27 - #define WINHTTP_QUERY_AUTHORIZATION 28 - #define WINHTTP_QUERY_CONTENT_ENCODING 29 - #define WINHTTP_QUERY_FORWARDED 30 - #define WINHTTP_QUERY_FROM 31 - #define WINHTTP_QUERY_IF_MODIFIED_SINCE 32 - #define WINHTTP_QUERY_LOCATION 33 - #define WINHTTP_QUERY_ORIG_URI 34 - #define WINHTTP_QUERY_REFERER 35 - #define WINHTTP_QUERY_RETRY_AFTER 36 - #define WINHTTP_QUERY_SERVER 37 - #define WINHTTP_QUERY_TITLE 38 - #define WINHTTP_QUERY_USER_AGENT 39 - #define WINHTTP_QUERY_WWW_AUTHENTICATE 40 - #define WINHTTP_QUERY_PROXY_AUTHENTICATE 41 - #define WINHTTP_QUERY_ACCEPT_RANGES 42 - #define WINHTTP_QUERY_SET_COOKIE 43 - #define WINHTTP_QUERY_COOKIE 44 - #define WINHTTP_QUERY_REQUEST_METHOD 45 // special: GET/POST etc. - #define WINHTTP_QUERY_REFRESH 46 - #define WINHTTP_QUERY_CONTENT_DISPOSITION 47 - - // NOTE: WinHttpQueryHeaders prettifiers for optional parameters. - #define WINHTTP_HEADER_NAME_BY_INDEX NULL - #define WINHTTP_NO_OUTPUT_BUFFER NULL - #define WINHTTP_NO_HEADER_INDEX NULL - - // NOTE: Http Response Status Codes - #define HTTP_STATUS_CONTINUE 100 // OK to continue with request - #define HTTP_STATUS_SWITCH_PROTOCOLS 101 // server has switched protocols in upgrade header - - #define HTTP_STATUS_OK 200 // request completed - #define HTTP_STATUS_CREATED 201 // object created, reason = new URI - #define HTTP_STATUS_ACCEPTED 202 // async completion (TBS) - #define HTTP_STATUS_PARTIAL 203 // partial completion - #define HTTP_STATUS_NO_CONTENT 204 // no info to return - #define HTTP_STATUS_RESET_CONTENT 205 // request completed, but clear form - #define HTTP_STATUS_PARTIAL_CONTENT 206 // partial GET fulfilled - #define HTTP_STATUS_WEBDAV_MULTI_STATUS 207 // WebDAV Multi-Status - - #define HTTP_STATUS_AMBIGUOUS 300 // server couldn't decide what to return - #define HTTP_STATUS_MOVED 301 // object permanently moved - #define HTTP_STATUS_REDIRECT 302 // object temporarily moved - #define HTTP_STATUS_REDIRECT_METHOD 303 // redirection w/ new access method - #define HTTP_STATUS_NOT_MODIFIED 304 // if-modified-since was not modified - #define HTTP_STATUS_USE_PROXY 305 // redirection to proxy, location header specifies proxy to use - #define HTTP_STATUS_REDIRECT_KEEP_VERB 307 // HTTP/1.1: keep same verb - #define HTTP_STATUS_PERMANENT_REDIRECT 308 // Object permanently moved keep verb - - #define HTTP_STATUS_BAD_REQUEST 400 // invalid syntax - #define HTTP_STATUS_DENIED 401 // access denied - #define HTTP_STATUS_PAYMENT_REQ 402 // payment required - #define HTTP_STATUS_FORBIDDEN 403 // request forbidden - #define HTTP_STATUS_NOT_FOUND 404 // object not found - #define HTTP_STATUS_BAD_METHOD 405 // method is not allowed - #define HTTP_STATUS_NONE_ACCEPTABLE 406 // no response acceptable to client found - #define HTTP_STATUS_PROXY_AUTH_REQ 407 // proxy authentication required - #define HTTP_STATUS_REQUEST_TIMEOUT 408 // server timed out waiting for request - #define HTTP_STATUS_CONFLICT 409 // user should resubmit with more info - #define HTTP_STATUS_GONE 410 // the resource is no longer available - #define HTTP_STATUS_LENGTH_REQUIRED 411 // the server refused to accept request w/o a length - #define HTTP_STATUS_PRECOND_FAILED 412 // precondition given in request failed - #define HTTP_STATUS_REQUEST_TOO_LARGE 413 // request entity was too large - #define HTTP_STATUS_URI_TOO_LONG 414 // request URI too long - #define HTTP_STATUS_UNSUPPORTED_MEDIA 415 // unsupported media type - #define HTTP_STATUS_RETRY_WITH 449 // retry after doing the appropriate action. - - #define HTTP_STATUS_SERVER_ERROR 500 // internal server error - #define HTTP_STATUS_NOT_SUPPORTED 501 // required not supported - #define HTTP_STATUS_BAD_GATEWAY 502 // error response received from gateway - #define HTTP_STATUS_SERVICE_UNAVAIL 503 // temporarily overloaded - #define HTTP_STATUS_GATEWAY_TIMEOUT 504 // timed out waiting for gateway - #define HTTP_STATUS_VERSION_NOT_SUP 505 // HTTP version not supported - - #define HTTP_STATUS_FIRST HTTP_STATUS_CONTINUE - #define HTTP_STATUS_LAST HTTP_STATUS_VERSION_NOT_SUP - - #define WINHTTP_CALLBACK_STATUS_RESOLVING_NAME 0x00000001 - #define WINHTTP_CALLBACK_STATUS_NAME_RESOLVED 0x00000002 - #define WINHTTP_CALLBACK_STATUS_CONNECTING_TO_SERVER 0x00000004 - #define WINHTTP_CALLBACK_STATUS_CONNECTED_TO_SERVER 0x00000008 - #define WINHTTP_CALLBACK_STATUS_SENDING_REQUEST 0x00000010 - #define WINHTTP_CALLBACK_STATUS_REQUEST_SENT 0x00000020 - #define WINHTTP_CALLBACK_STATUS_RECEIVING_RESPONSE 0x00000040 - #define WINHTTP_CALLBACK_STATUS_RESPONSE_RECEIVED 0x00000080 - #define WINHTTP_CALLBACK_STATUS_CLOSING_CONNECTION 0x00000100 - #define WINHTTP_CALLBACK_STATUS_CONNECTION_CLOSED 0x00000200 - #define WINHTTP_CALLBACK_STATUS_HANDLE_CREATED 0x00000400 - #define WINHTTP_CALLBACK_STATUS_HANDLE_CLOSING 0x00000800 - #define WINHTTP_CALLBACK_STATUS_DETECTING_PROXY 0x00001000 - #define WINHTTP_CALLBACK_STATUS_REDIRECT 0x00004000 - #define WINHTTP_CALLBACK_STATUS_INTERMEDIATE_RESPONSE 0x00008000 - #define WINHTTP_CALLBACK_STATUS_SECURE_FAILURE 0x00010000 - #define WINHTTP_CALLBACK_STATUS_HEADERS_AVAILABLE 0x00020000 - #define WINHTTP_CALLBACK_STATUS_DATA_AVAILABLE 0x00040000 - #define WINHTTP_CALLBACK_STATUS_READ_COMPLETE 0x00080000 - #define WINHTTP_CALLBACK_STATUS_WRITE_COMPLETE 0x00100000 - #define WINHTTP_CALLBACK_STATUS_REQUEST_ERROR 0x00200000 - #define WINHTTP_CALLBACK_STATUS_SENDREQUEST_COMPLETE 0x00400000 - - #define WINHTTP_CALLBACK_STATUS_GETPROXYFORURL_COMPLETE 0x01000000 - #define WINHTTP_CALLBACK_STATUS_CLOSE_COMPLETE 0x02000000 - #define WINHTTP_CALLBACK_STATUS_SHUTDOWN_COMPLETE 0x04000000 - #define WINHTTP_CALLBACK_STATUS_SETTINGS_WRITE_COMPLETE 0x10000000 - #define WINHTTP_CALLBACK_STATUS_SETTINGS_READ_COMPLETE 0x20000000 - - #define WINHTTP_CALLBACK_FLAG_RESOLVE_NAME (WINHTTP_CALLBACK_STATUS_RESOLVING_NAME | WINHTTP_CALLBACK_STATUS_NAME_RESOLVED) - #define WINHTTP_CALLBACK_FLAG_CONNECT_TO_SERVER (WINHTTP_CALLBACK_STATUS_CONNECTING_TO_SERVER | WINHTTP_CALLBACK_STATUS_CONNECTED_TO_SERVER) - #define WINHTTP_CALLBACK_FLAG_SEND_REQUEST (WINHTTP_CALLBACK_STATUS_SENDING_REQUEST | WINHTTP_CALLBACK_STATUS_REQUEST_SENT) - #define WINHTTP_CALLBACK_FLAG_RECEIVE_RESPONSE (WINHTTP_CALLBACK_STATUS_RECEIVING_RESPONSE | WINHTTP_CALLBACK_STATUS_RESPONSE_RECEIVED) - #define WINHTTP_CALLBACK_FLAG_CLOSE_CONNECTION (WINHTTP_CALLBACK_STATUS_CLOSING_CONNECTION | WINHTTP_CALLBACK_STATUS_CONNECTION_CLOSED) - #define WINHTTP_CALLBACK_FLAG_HANDLES (WINHTTP_CALLBACK_STATUS_HANDLE_CREATED | WINHTTP_CALLBACK_STATUS_HANDLE_CLOSING) - #define WINHTTP_CALLBACK_FLAG_DETECTING_PROXY WINHTTP_CALLBACK_STATUS_DETECTING_PROXY - #define WINHTTP_CALLBACK_FLAG_REDIRECT WINHTTP_CALLBACK_STATUS_REDIRECT - #define WINHTTP_CALLBACK_FLAG_INTERMEDIATE_RESPONSE WINHTTP_CALLBACK_STATUS_INTERMEDIATE_RESPONSE - #define WINHTTP_CALLBACK_FLAG_SECURE_FAILURE WINHTTP_CALLBACK_STATUS_SECURE_FAILURE - #define WINHTTP_CALLBACK_FLAG_SENDREQUEST_COMPLETE WINHTTP_CALLBACK_STATUS_SENDREQUEST_COMPLETE - #define WINHTTP_CALLBACK_FLAG_HEADERS_AVAILABLE WINHTTP_CALLBACK_STATUS_HEADERS_AVAILABLE - #define WINHTTP_CALLBACK_FLAG_DATA_AVAILABLE WINHTTP_CALLBACK_STATUS_DATA_AVAILABLE - #define WINHTTP_CALLBACK_FLAG_READ_COMPLETE WINHTTP_CALLBACK_STATUS_READ_COMPLETE - #define WINHTTP_CALLBACK_FLAG_WRITE_COMPLETE WINHTTP_CALLBACK_STATUS_WRITE_COMPLETE - #define WINHTTP_CALLBACK_FLAG_REQUEST_ERROR WINHTTP_CALLBACK_STATUS_REQUEST_ERROR - - #define WINHTTP_CALLBACK_FLAG_GETPROXYFORURL_COMPLETE WINHTTP_CALLBACK_STATUS_GETPROXYFORURL_COMPLETE - - #define WINHTTP_CALLBACK_FLAG_ALL_COMPLETIONS (WINHTTP_CALLBACK_STATUS_SENDREQUEST_COMPLETE \ - | WINHTTP_CALLBACK_STATUS_HEADERS_AVAILABLE \ - | WINHTTP_CALLBACK_STATUS_DATA_AVAILABLE \ - | WINHTTP_CALLBACK_STATUS_READ_COMPLETE \ - | WINHTTP_CALLBACK_STATUS_WRITE_COMPLETE \ - | WINHTTP_CALLBACK_STATUS_REQUEST_ERROR \ - | WINHTTP_CALLBACK_STATUS_GETPROXYFORURL_COMPLETE) - - #define WINHTTP_CALLBACK_FLAG_ALL_NOTIFICATIONS 0xffffffff - #define WINHTTP_INVALID_STATUS_CALLBACK ((WINHTTP_STATUS_CALLBACK)(-1L)) - - typedef struct _WINHTTP_EXTENDED_HEADER - { - union - { - CHAR const *pwszName; - WCHAR const *pszName; - }; - union - { - WCHAR const *pwszValue; - CHAR const *pszValue; - }; - } WINHTTP_EXTENDED_HEADER, *PWINHTTP_EXTENDED_HEADER; - - typedef struct _WINHTTP_ASYNC_RESULT - { - DWORD *dwResult; // indicates which async API has encountered an error - DWORD dwError; // the error code if the API failed - } WINHTTP_ASYNC_RESULT, *LPWINHTTP_ASYNC_RESULT, *PWINHTTP_ASYNC_RESULT; - - typedef - VOID - (*WINHTTP_STATUS_CALLBACK)( - HINTERNET hInternet, - DWORD *dwContext, - DWORD dwInternetStatus, - VOID *lpvStatusInformation, - DWORD dwStatusInformationLength - ); - - extern "C" - { - __declspec(dllimport) HINTERNET __stdcall WinHttpOpen(WCHAR const *pszAgentW, DWORD dwAccessType, WCHAR const *pszProxyW, WCHAR const *pszProxyBypassW, DWORD dwFlags); - __declspec(dllimport) BOOL __stdcall WinHttpCloseHandle(HINTERNET hInternet); - __declspec(dllimport) HINTERNET __stdcall WinHttpConnect(HINTERNET hSession, WCHAR const *pswzServerName, INTERNET_PORT nServerPort, DWORD dwReserved); - __declspec(dllimport) BOOL __stdcall WinHttpReadData(HINTERNET hRequest, VOID *lpBuffer, DWORD dwNumberOfBytesToRead, DWORD *lpdwNumberOfBytesRead); - __declspec(dllimport) HINTERNET __stdcall WinHttpOpenRequest(HINTERNET hConnect, WCHAR const *pwszVerb, WCHAR const *pwszObjectName, WCHAR const *pwszVersion, WCHAR const *pwszReferrer, WCHAR const *ppwszAcceptTypes, DWORD dwFlags); - __declspec(dllimport) BOOL __stdcall WinHttpSendRequest(HINTERNET hRequest, WCHAR const *lpszHeaders, DWORD dwHeadersLength, VOID *lpOptional, DWORD dwOptionalLength, DWORD dwTotalLength, DWORD_PTR dwContext); - __declspec(dllimport) DWORD __stdcall WinHttpAddRequestHeadersEx(HINTERNET hRequest, DWORD dwModifiers, ULONGLONG ullFlags, ULONGLONG ullExtra, DWORD cHeaders, WINHTTP_EXTENDED_HEADER *pHeaders); - __declspec(dllimport) BOOL __stdcall WinHttpSetCredentials(HINTERNET hRequest, // HINTERNET handle returned by WinHttpOpenRequest. - DWORD AuthTargets, // Only WINHTTP_AUTH_TARGET_SERVER and WINHTTP_AUTH_TARGET_PROXY are supported in this version and they are mutually exclusive - DWORD AuthScheme, // must be one of the supported Auth Schemes returned from WinHttpQueryAuthSchemes() - WCHAR * pwszUserName, // 1) NULL if default creds is to be used, in which case pszPassword will be ignored - WCHAR * pwszPassword, // 1) "" == Blank Password; 2)Parameter ignored if pszUserName is NULL; 3) Invalid to pass in NULL if pszUserName is not NULL - VOID * pAuthParams); - __declspec(dllimport) BOOL __stdcall WinHttpQueryHeaders(HINTERNET hRequest, DWORD dwInfoLevel, WCHAR const *pwszName, VOID *lpBuffer, DWORD *lpdwBufferLength, DWORD *lpdwIndex); - __declspec(dllimport) BOOL __stdcall WinHttpReceiveResponse(HINTERNET hRequest, VOID *lpReserved); - __declspec(dllimport) WINHTTP_STATUS_CALLBACK __stdcall WinHttpSetStatusCallback(HINTERNET hInternet, WINHTTP_STATUS_CALLBACK lpfnInternetCallback, DWORD dwNotificationFlags, DWORD_PTR dwReserved); - } - - // NOTE: um/DbgHelp.h ////////////////////////////////////////////////////////////////////////// - #define SYMOPT_CASE_INSENSITIVE 0x00000001 - #define SYMOPT_UNDNAME 0x00000002 - #define SYMOPT_DEFERRED_LOADS 0x00000004 - #define SYMOPT_NO_CPP 0x00000008 - #define SYMOPT_LOAD_LINES 0x00000010 - #define SYMOPT_OMAP_FIND_NEAREST 0x00000020 - #define SYMOPT_LOAD_ANYTHING 0x00000040 - #define SYMOPT_IGNORE_CVREC 0x00000080 - #define SYMOPT_NO_UNQUALIFIED_LOADS 0x00000100 - #define SYMOPT_FAIL_CRITICAL_ERRORS 0x00000200 - #define SYMOPT_EXACT_SYMBOLS 0x00000400 - #define SYMOPT_ALLOW_ABSOLUTE_SYMBOLS 0x00000800 - #define SYMOPT_IGNORE_NT_SYMPATH 0x00001000 - #define SYMOPT_INCLUDE_32BIT_MODULES 0x00002000 - #define SYMOPT_PUBLICS_ONLY 0x00004000 - #define SYMOPT_NO_PUBLICS 0x00008000 - #define SYMOPT_AUTO_PUBLICS 0x00010000 - #define SYMOPT_NO_IMAGE_SEARCH 0x00020000 - #define SYMOPT_SECURE 0x00040000 - #define SYMOPT_NO_PROMPTS 0x00080000 - #define SYMOPT_OVERWRITE 0x00100000 - #define SYMOPT_IGNORE_IMAGEDIR 0x00200000 - #define SYMOPT_FLAT_DIRECTORY 0x00400000 - #define SYMOPT_FAVOR_COMPRESSED 0x00800000 - #define SYMOPT_ALLOW_ZERO_ADDRESS 0x01000000 - #define SYMOPT_DISABLE_SYMSRV_AUTODETECT 0x02000000 - #define SYMOPT_READONLY_CACHE 0x04000000 - #define SYMOPT_SYMPATH_LAST 0x08000000 - #define SYMOPT_DISABLE_FAST_SYMBOLS 0x10000000 - #define SYMOPT_DISABLE_SYMSRV_TIMEOUT 0x20000000 - #define SYMOPT_DISABLE_SRVSTAR_ON_STARTUP 0x40000000 - #define SYMOPT_DEBUG 0x80000000 - - #define MAX_SYM_NAME 2000 - - typedef enum { - AddrMode1616, - AddrMode1632, - AddrModeReal, - AddrModeFlat - } ADDRESS_MODE; - - typedef struct _tagADDRESS64 { - DWORD64 Offset; - WORD Segment; - ADDRESS_MODE Mode; - } ADDRESS64, *LPADDRESS64; - - - typedef struct _KDHELP64 { - DWORD64 Thread; - DWORD ThCallbackStack; - DWORD ThCallbackBStore; - DWORD NextCallback; - DWORD FramePointer; - DWORD64 KiCallUserMode; - DWORD64 KeUserCallbackDispatcher; - DWORD64 SystemRangeStart; - DWORD64 KiUserExceptionDispatcher; - DWORD64 StackBase; - DWORD64 StackLimit; - DWORD BuildVersion; - DWORD RetpolineStubFunctionTableSize; - DWORD64 RetpolineStubFunctionTable; - DWORD RetpolineStubOffset; - DWORD RetpolineStubSize; - DWORD64 Reserved0[2]; - } KDHELP64, *PKDHELP64; - - typedef struct _tagSTACKFRAME64 { - ADDRESS64 AddrPC; // program counter - ADDRESS64 AddrReturn; // return address - ADDRESS64 AddrFrame; // frame pointer - ADDRESS64 AddrStack; // stack pointer - ADDRESS64 AddrBStore; // backing store pointer - VOID *FuncTableEntry; // pointer to pdata/fpo or NULL - DWORD64 Params[4]; // possible arguments to the function - BOOL Far; // WOW far call - BOOL Virtual; // is this a virtual frame? - DWORD64 Reserved[3]; - KDHELP64 KdHelp; - } STACKFRAME64; - - typedef struct _IMAGEHLP_LINEW64 { - DWORD SizeOfStruct; // set to sizeof(IMAGEHLP_LINE64) - VOID *Key; // internal - DWORD LineNumber; // line number in file - WCHAR *FileName; // full filename - DWORD64 Address; // first instruction of line - } IMAGEHLP_LINEW64; - - typedef struct _SYMBOL_INFOW { - ULONG SizeOfStruct; - ULONG TypeIndex; // Type Index of symbol - ULONG64 Reserved[2]; - ULONG Index; - ULONG Size; - ULONG64 ModBase; // Base Address of module comtaining this symbol - ULONG Flags; - ULONG64 Value; // Value of symbol, ValuePresent should be 1 - ULONG64 Address; // Address of symbol including base address of module - ULONG Register; // register holding value or pointer to value - ULONG Scope; // scope of the symbol - ULONG Tag; // pdb classification - ULONG NameLen; // Actual length of name - ULONG MaxNameLen; - WCHAR Name[1]; // Name of symbol - } SYMBOL_INFOW; - - typedef BOOL (__stdcall READ_PROCESS_MEMORY_ROUTINE64)(HANDLE hProcess, DWORD64 qwBaseAddress, VOID *lpBuffer, DWORD nSize, DWORD *lpNumberOfBytesRead); - typedef VOID * (__stdcall FUNCTION_TABLE_ACCESS_ROUTINE64)(HANDLE ahProcess, DWORD64 AddrBase); - typedef DWORD64(__stdcall GET_MODULE_BASE_ROUTINE64)(HANDLE hProcess, DWORD64 Address); - typedef DWORD64(__stdcall TRANSLATE_ADDRESS_ROUTINE64)(HANDLE hProcess, HANDLE hThread, ADDRESS64 *lpaddr); - - extern "C" - { - __declspec(dllimport) BOOL __stdcall StackWalk64 (DWORD MachineType, HANDLE hProcess, HANDLE hThread, STACKFRAME64 *StackFrame, VOID *ContextRecord, READ_PROCESS_MEMORY_ROUTINE64 *ReadMemoryRoutine, FUNCTION_TABLE_ACCESS_ROUTINE64 *FunctionTableAccessRoutine, GET_MODULE_BASE_ROUTINE64 *GetModuleBaseRoutine, TRANSLATE_ADDRESS_ROUTINE64 *TranslateAddress); - __declspec(dllimport) BOOL __stdcall SymFromAddrW (HANDLE hProcess, DWORD64 Address, DWORD64 *Displacement, SYMBOL_INFOW *Symbol); - __declspec(dllimport) VOID * __stdcall SymFunctionTableAccess64(HANDLE hProcess, DWORD64 AddrBase); - __declspec(dllimport) BOOL __stdcall SymGetLineFromAddrW64 (HANDLE hProcess, DWORD64 dwAddr, DWORD *pdwDisplacement, IMAGEHLP_LINEW64 *Line); - __declspec(dllimport) DWORD64 __stdcall SymGetModuleBase64 (HANDLE hProcess, DWORD64 qwAddr); - __declspec(dllimport) BOOL __stdcall SymRefreshModuleList (HANDLE hProcess); - }; - - // NOTE: um/errhandlingapi.h /////////////////////////////////////////////////////////////////// - extern "C" - { - __declspec(dllimport) DWORD __stdcall GetLastError(VOID); - } - - // NOTE: um/libloaderapi.h ///////////////////////////////////////////////////////////////////// - extern "C" - { - __declspec(dllimport) HMODULE __stdcall LoadLibraryA (const CHAR *lpLibFileName); - __declspec(dllimport) BOOL __stdcall FreeLibrary (HMODULE hLibModule); - __declspec(dllimport) void * __stdcall GetProcAddress (HMODULE hModule, const CHAR *lpProcName); - __declspec(dllimport) HMODULE __stdcall GetModuleHandleA (const CHAR *lpModuleName); - __declspec(dllimport) DWORD __stdcall GetModuleFileNameW(HMODULE hModule, WCHAR *lpFilename, DWORD nSize); - } - - // NOTE: um/synchapi.h ///////////////////////////////////////////////////////////////////////// - typedef RTL_CONDITION_VARIABLE CONDITION_VARIABLE, *PCONDITION_VARIABLE; - - extern "C" - { - __declspec(dllimport) VOID __stdcall InitializeConditionVariable (CONDITION_VARIABLE *ConditionVariable); - __declspec(dllimport) VOID __stdcall WakeConditionVariable (CONDITION_VARIABLE *ConditionVariable); - __declspec(dllimport) VOID __stdcall WakeAllConditionVariable (CONDITION_VARIABLE *ConditionVariable); - __declspec(dllimport) BOOL __stdcall SleepConditionVariableCS (CONDITION_VARIABLE *ConditionVariable, CRITICAL_SECTION *CriticalSection, DWORD dwMilliseconds); - - __declspec(dllimport) VOID __stdcall InitializeCriticalSection (CRITICAL_SECTION *lpCriticalSection); - __declspec(dllimport) VOID __stdcall EnterCriticalSection (CRITICAL_SECTION *lpCriticalSection); - __declspec(dllimport) VOID __stdcall LeaveCriticalSection (CRITICAL_SECTION *lpCriticalSection); - __declspec(dllimport) BOOL __stdcall InitializeCriticalSectionAndSpinCount(CRITICAL_SECTION *lpCriticalSection, DWORD dwSpinCount); - __declspec(dllimport) BOOL __stdcall InitializeCriticalSectionEx (CRITICAL_SECTION *lpCriticalSection, DWORD dwSpinCount, DWORD Flags); - __declspec(dllimport) DWORD __stdcall SetCriticalSectionSpinCount (CRITICAL_SECTION *lpCriticalSection, DWORD dwSpinCount); - __declspec(dllimport) BOOL __stdcall TryEnterCriticalSection (CRITICAL_SECTION *lpCriticalSection); - __declspec(dllimport) VOID __stdcall DeleteCriticalSection (CRITICAL_SECTION *lpCriticalSection); - - __declspec(dllimport) DWORD __stdcall WaitForSingleObject (HANDLE hHandle, DWORD dwMilliseconds); - __declspec(dllimport) BOOL __stdcall ReleaseSemaphore (HANDLE hSemaphore, LONG lReleaseCount, LONG *lpPreviousCount); - __declspec(dllimport) VOID __stdcall Sleep (DWORD dwMilliseconds); - } - - // NOTE: um/profileapi.h /////////////////////////////////////////////////////////////////////// - extern "C" - { - __declspec(dllimport) BOOL __stdcall QueryPerformanceCounter (LARGE_INTEGER* lpPerformanceCount); - __declspec(dllimport) BOOL __stdcall QueryPerformanceFrequency(LARGE_INTEGER* lpFrequency); - } - - // NOTE: um/processthreadsapi.h //////////////////////////////////////////////////////////////// - typedef struct _PROCESS_INFORMATION { - HANDLE hProcess; - HANDLE hThread; - DWORD dwProcessId; - DWORD dwThreadId; - } PROCESS_INFORMATION, *PPROCESS_INFORMATION, *LPPROCESS_INFORMATION; - - typedef struct _STARTUPINFOW { - DWORD cb; - WCHAR *lpReserved; - WCHAR *lpDesktop; - WCHAR *lpTitle; - DWORD dwX; - DWORD dwY; - DWORD dwXSize; - DWORD dwYSize; - DWORD dwXCountChars; - DWORD dwYCountChars; - DWORD dwFillAttribute; - DWORD dwFlags; - WORD wShowWindow; - WORD cbReserved2; - BYTE *lpReserved2; - HANDLE hStdInput; - HANDLE hStdOutput; - HANDLE hStdError; - } STARTUPINFOW, *LPSTARTUPINFOW; - - typedef DWORD (__stdcall *PTHREAD_START_ROUTINE)( - VOID *lpThreadParameter - ); - typedef PTHREAD_START_ROUTINE LPTHREAD_START_ROUTINE; - - extern "C" - { - __declspec(dllimport) BOOL __stdcall CreateProcessW (WCHAR const *lpApplicationName, WCHAR *lpCommandLine, SECURITY_ATTRIBUTES *lpProcessAttributes, SECURITY_ATTRIBUTES *lpThreadAttributes, BOOL bInheritHandles, DWORD dwCreationFlags, VOID *lpEnvironment, WCHAR const *lpCurrentDirectory, STARTUPINFOW *lpStartupInfo, PROCESS_INFORMATION *lpProcessInformation); - __declspec(dllimport) HANDLE __stdcall CreateThread (SECURITY_ATTRIBUTES *lpThreadAttributes, SIZE_T dwStackSize, PTHREAD_START_ROUTINE lpStartAddress, VOID *lpParameter, DWORD dwCreationFlags, DWORD *lpThreadId); - __declspec(dllimport) DWORD __stdcall GetCurrentThreadId(VOID); - __declspec(dllimport) BOOL __stdcall GetExitCodeProcess(HANDLE hProcess, DWORD *lpExitCode); - __declspec(dllimport) void __stdcall ExitProcess (UINT uExitCode); - } - - // NOTE: um/memoryapi.h //////////////////////////////////////////////////////////////////////// - extern "C" - { - __declspec(dllimport) VOID * __stdcall VirtualAlloc (VOID *lpAddress, SIZE_T dwSize, DWORD flAllocationType, DWORD flProtect); - __declspec(dllimport) BOOL __stdcall VirtualProtect(VOID *lpAddress, SIZE_T dwSize, DWORD flNewProtect, DWORD *lpflOldProtect); - __declspec(dllimport) BOOL __stdcall VirtualFree (VOID *lpAddress, SIZE_T dwSize, DWORD dwFreeType); - } - - // NOTE: shared/bcrypt.h /////////////////////////////////////////////////////////////////////// - typedef VOID *BCRYPT_ALG_HANDLE; - typedef LONG NTSTATUS; - - extern "C" - { - __declspec(dllimport) NTSTATUS __stdcall BCryptOpenAlgorithmProvider(BCRYPT_ALG_HANDLE *phAlgorithm, const WCHAR *pszAlgId, const WCHAR *pszImplementation, ULONG dwFlags); - __declspec(dllimport) NTSTATUS __stdcall BCryptGenRandom (BCRYPT_ALG_HANDLE hAlgorithm, UCHAR *pbBuffer, ULONG cbBuffer, ULONG dwFlags); - } - - // NOTE: um/shellapi.h ///////////////////////////////////////////////////////////////////////// - extern "C" - { - __declspec(dllimport) HINSTANCE __stdcall ShellExecuteA(HWND hwnd, CHAR const *lpOperation, CHAR const *lpFile, CHAR const *lpParameters, CHAR const *lpDirectory, INT nShowCmd); - __declspec(dllimport) HINSTANCE __stdcall ShellExecuteW(HWND hwnd, WCHAR const *lpOperation, WCHAR const *lpFile, WCHAR const *lpParameters, WCHAR const *lpDirectory, INT nShowCmd); - } - - // NOTE: um/debugapi.h ///////////////////////////////////////////////////////////////////////// - extern "C" - { - __declspec(dllimport) BOOL __stdcall IsDebuggerPresent(); - } - - // NOTE: um/namedpipeapi.h ///////////////////////////////////////////////////////////////////// - extern "C" - { - __declspec(dllimport) BOOL __stdcall CreatePipe (HANDLE *hReadPipe, HANDLE *hWritePipe, LPSECURITY_ATTRIBUTES lpPipeAttributes, DWORD nSize); - __declspec(dllimport) BOOL __stdcall PeekNamedPipe(HANDLE hNamedPipe, VOID *lpBuffer, DWORD nBufferSize, DWORD *lpBytesRead, DWORD *lpTotalBytesAvail, DWORD *lpBytesLeftThisMessage); - } - - // NOTE: um/handleapi.h //////////////////////////////////////////////////////////////////////// - extern "C" - { - __declspec(dllimport) BOOL __stdcall SetHandleInformation(HANDLE hObject, DWORD dwMask, DWORD dwFlags); - } - - // NOTE: um/commdlg.h ////////////////////////////////////////////////////////////////////////// - typedef UINT_PTR (__stdcall *LPOFNHOOKPROC)(HWND, UINT, WPARAM, LPARAM); - typedef struct tagOFNW { - DWORD lStructSize; - HWND hwndOwner; - HINSTANCE hInstance; - WCHAR const * lpstrFilter; - LPWSTR lpstrCustomFilter; - DWORD nMaxCustFilter; - DWORD nFilterIndex; - LPWSTR lpstrFile; - DWORD nMaxFile; - LPWSTR lpstrFileTitle; - DWORD nMaxFileTitle; - WCHAR const * lpstrInitialDir; - WCHAR const * lpstrTitle; - DWORD Flags; - WORD nFileOffset; - WORD nFileExtension; - WCHAR const * lpstrDefExt; - LPARAM lCustData; - LPOFNHOOKPROC lpfnHook; - WCHAR const * lpTemplateName; - #ifdef _MAC - LPEDITMENU lpEditInfo; - LPCSTR lpstrPrompt; - #endif - #if (_WIN32_WINNT >= 0x0500) - void * pvReserved; - DWORD dwReserved; - DWORD FlagsEx; - #endif // (_WIN32_WINNT >= 0x0500) - } OPENFILENAMEW, *LPOPENFILENAMEW; - - - #define OFN_READONLY 0x00000001 - #define OFN_OVERWRITEPROMPT 0x00000002 - #define OFN_HIDEREADONLY 0x00000004 - #define OFN_NOCHANGEDIR 0x00000008 - #define OFN_SHOWHELP 0x00000010 - #define OFN_ENABLEHOOK 0x00000020 - #define OFN_ENABLETEMPLATE 0x00000040 - #define OFN_ENABLETEMPLATEHANDLE 0x00000080 - #define OFN_NOVALIDATE 0x00000100 - #define OFN_ALLOWMULTISELECT 0x00000200 - #define OFN_EXTENSIONDIFFERENT 0x00000400 - #define OFN_PATHMUSTEXIST 0x00000800 - #define OFN_FILEMUSTEXIST 0x00001000 - #define OFN_CREATEPROMPT 0x00002000 - #define OFN_SHAREAWARE 0x00004000 - #define OFN_NOREADONLYRETURN 0x00008000 - #define OFN_NOTESTFILECREATE 0x00010000 - #define OFN_NONETWORKBUTTON 0x00020000 - #define OFN_NOLONGNAMES 0x00040000 // force no long names for 4.x modules - #if(WINVER >= 0x0400) - #define OFN_EXPLORER 0x00080000 // new look commdlg - #define OFN_NODEREFERENCELINKS 0x00100000 - #define OFN_LONGNAMES 0x00200000 // force long names for 3.x modules - // OFN_ENABLEINCLUDENOTIFY and OFN_ENABLESIZING require - // Windows 2000 or higher to have any effect. - #define OFN_ENABLEINCLUDENOTIFY 0x00400000 // send include message to callback - #define OFN_ENABLESIZING 0x00800000 - #endif /* WINVER >= 0x0400 */ - #if (_WIN32_WINNT >= 0x0500) - #define OFN_DONTADDTORECENT 0x02000000 - #define OFN_FORCESHOWHIDDEN 0x10000000 // Show All files including System and hidden files - #endif // (_WIN32_WINNT >= 0x0500) - - //FlagsEx Values - #if (_WIN32_WINNT >= 0x0500) - #define OFN_EX_NOPLACESBAR 0x00000001 - #endif // (_WIN32_WINNT >= 0x0500) - - extern "C" - { - __declspec(dllimport) BOOL __stdcall GetSaveFileNameW(LPOPENFILENAMEW); - __declspec(dllimport) BOOL __stdcall GetOpenFileNameW(LPOPENFILENAMEW); - } - - // NOTE: um/shlwapi.h ////////////////////////////////////////////////////////////////////////// - extern "C" - { - __declspec(dllimport) BOOL __stdcall PathRelativePathToW(WCHAR *pszPath, WCHAR const *pszFrom, DWORD dwAttrFrom, WCHAR const *pszTo, DWORD dwAttrTo); - __declspec(dllimport) BOOL __stdcall PathIsRelativeW(WCHAR *pszPath); - } - - // NOTE: um/pathcch.h ////////////////////////////////////////////////////////////////////////// - typedef enum PATHCCH_OPTIONS - { - PATHCCH_NONE = 0x0, - - // This option allows applications to gain access to long paths. It has two - // different behaviors. For process configured to enable long paths it will allow - // the returned path to be longer than the max path limit that is normally imposed. - // For process that are not this option will convert long paths into the extended - // length DOS device form (with \\?\ prefix) when the path is longer than the limit. - // This form is not length limited by the Win32 file system API on all versions of Windows. - // This second behavior is the same behavior for OSes that don't have the long path feature. - // This can not be specified with PATHCCH_ENSURE_IS_EXTENDED_LENGTH_PATH. - PATHCCH_ALLOW_LONG_PATHS = 0x01, - - // Can only be used when PATHCCH_ALLOW_LONG_PATHS is specified. This - // Forces the API to treat the caller as long path enabled, independent of the - // process's long name enabled state. Cannot be used with PATHCCH_FORCE_DISABLE_LONG_NAME_PROCESS. - PATHCCH_FORCE_ENABLE_LONG_NAME_PROCESS = 0x02, - - // Can only be used when PATHCCH_ALLOW_LONG_PATHS is specified. This - // Forces the API to treat the caller as long path disabled, independent of the - // process's long name enabled state. Cannot be used with PATHCCH_FORCE_ENABLE_LONG_NAME_PROCESS. - PATHCCH_FORCE_DISABLE_LONG_NAME_PROCESS = 0x04, - - // Disable the normalization of path segments that includes removing trailing dots and spaces. - // This enables access to paths that win32 path normalization will block. - PATHCCH_DO_NOT_NORMALIZE_SEGMENTS = 0x08, - - // Convert the input path into the extended length DOS device path form (with the \\?\ prefix) - // if not already in that form. This enables access to paths that are otherwise not addressable - // due to Win32 normalization rules (that can strip trailing dots and spaces) and path - // length limitations. This option implies the same behavior of PATHCCH_DO_NOT_NORMALIZE_SEGMENTS. - // This can not be specified with PATHCCH_ALLOW_LONG_PATHS. - PATHCCH_ENSURE_IS_EXTENDED_LENGTH_PATH = 0x10, - - // When combining or normalizing a path ensure there is a trailing backslash. - PATHCCH_ENSURE_TRAILING_SLASH = 0x020, - - // Convert forward slashes to back slashes and collapse multiple slashes. - // This is needed to to support sub-path or identity comparisons. - PATHCCH_CANONICALIZE_SLASHES = 0x040, - } PATHCCH_OPTIONS; - - extern "C" - { - __declspec(dllimport) HRESULT __stdcall PathCchCanonicalizeEx(PWSTR pszPathOut, size_t cchPathOut, WCHAR const *pszPathIn, ULONG dwFlags); - }; - - // NOTE: um/errhandlingapi.h /////////////////////////////////////////////////////////////////// - extern "C" - { - __declspec(dllimport) VOID __stdcall RaiseException(DWORD dwExceptionCode, DWORD dwExceptionFlags, DWORD nNumberOfArguments, const ULONG_PTR* lpArguments); - }; - - // NOTE: include/excpt.h /////////////////////////////////////////////////////////////////// - #define EXCEPTION_EXECUTE_HANDLER 1 - #define EXCEPTION_CONTINUE_SEARCH 0 - #define EXCEPTION_CONTINUE_EXECUTION (-1) - - DN_MSVC_WARNING_POP -#endif // !defined(_INC_WINDOWS) -#endif // !defined(DN_OS_WINDOWS_H) - // DN: Single header generator commented out this header => #include "OS/dn_os_w32.h" -#if !defined(DN_OS_WIN32_H) -#define DN_OS_WIN32_H - -#if defined(_CLANGD) - // DN: Single header generator commented out this header => #include "../dn_base_inc.h" - // DN: Single header generator commented out this header => #include "dn_os_windows.h" -#if !defined(DN_OS_WINDOWS_H) -#define DN_OS_WINDOWS_H - -#if defined(_CLANGD) - // DN: Single header generator commented out this header => #include "../dn_base_inc.h" -#endif - -#if defined(DN_COMPILER_MSVC) || defined(DN_COMPILER_CLANG_CL) - #pragma comment(lib, "bcrypt") - #pragma comment(lib, "winhttp") - #pragma comment(lib, "dbghelp") - #pragma comment(lib, "comdlg32") - #pragma comment(lib, "pathcch") - #pragma comment(lib, "Shell32") // ShellExecuteW - #pragma comment(lib, "shlwapi") -#endif - -#if defined(DN_NO_WINDOWS_H_REPLACEMENT_HEADER) || defined(_INC_WINDOWS) - #define WIN32_LEAN_AND_MEAN - #include // LONG - #include // DN_OS_SecureRNGBytes -> BCryptOpenAlgorithmProvider ... etc - #include // DN_Win_MakeProcessDPIAware -> SetProcessDpiAwareProc - #include // PathRelativePathTO - #include // PathCchCanonicalizeEx - #include // WinHttp* - #include // PROCESS_MEMORY_COUNTERS_EX2 - #include // OPENFILENAMEW - #include -#else - DN_MSVC_WARNING_PUSH - DN_MSVC_WARNING_DISABLE(4201) // warning C4201: nonstandard extension used: nameless struct/union - - // NOTE: basetsd.h ///////////////////////////////////////////////////////////////////////////// - typedef unsigned __int64 ULONG_PTR, *PULONG_PTR; - typedef unsigned __int64 UINT_PTR, *PUINT_PTR; - typedef ULONG_PTR SIZE_T, *PSIZE_T; - typedef __int64 LONG_PTR, *PLONG_PTR; - typedef ULONG_PTR DWORD_PTR, *PDWORD_PTR; - typedef unsigned __int64 ULONG64, *PULONG64; - typedef unsigned __int64 DWORD64, *PDWORD64; - - // NOTE: shared/minwindef.h //////////////////////////////////////////////////////////////////// - struct HINSTANCE__ { - int unused; - }; - typedef struct HINSTANCE__ *HINSTANCE; - - typedef unsigned long DWORD; - typedef int BOOL; - typedef int INT; - typedef unsigned long ULONG; - typedef unsigned int UINT; - typedef unsigned short WORD; - typedef unsigned char BYTE; - typedef unsigned char UCHAR; - typedef HINSTANCE HMODULE; /* HMODULEs can be used in place of HINSTANCEs */ - typedef void * HANDLE; - typedef HANDLE HLOCAL; - - typedef unsigned __int64 WPARAM; - typedef LONG_PTR LPARAM; - typedef LONG_PTR LRESULT; - - #define MAX_PATH 260 - - typedef struct _FILETIME { - DWORD dwLowDateTime; - DWORD dwHighDateTime; - } FILETIME, *PFILETIME, *LPFILETIME; - - // NOTE: shared/winerror.h ///////////////////////////////////////////////////////////////////// - // NOTE: GetModuleFileNameW - #define ERROR_INSUFFICIENT_BUFFER 122L // dderror - - // NOTE: um/winnls.h /////////////////////////////////////////////////////////////////////////// - // NOTE: MultiByteToWideChar - #define CP_UTF8 65001 // UTF-8 translation - - // NOTE: um/winnt.h //////////////////////////////////////////////////////////////////////////// - typedef void VOID; - typedef __int64 LONGLONG; - typedef unsigned __int64 ULONGLONG; - typedef void * HANDLE; - typedef char CHAR; - typedef short SHORT; - typedef long LONG; - typedef wchar_t WCHAR; // wc, 16-bit UNICODE character - typedef CHAR * NPSTR, *LPSTR, *PSTR; - typedef WCHAR * NWPSTR, *LPWSTR, *PWSTR; - typedef long HRESULT; - - // NOTE: VirtualAlloc: Allocation Type - #define MEM_RESERVE 0x00002000 - #define MEM_COMMIT 0x00001000 - #define MEM_DECOMMIT 0x00004000 - #define MEM_RELEASE 0x00008000 - - // NOTE: VirtualAlloc: Page Permissions - #define PAGE_NOACCESS 0x01 - #define PAGE_READONLY 0x02 - #define PAGE_READWRITE 0x04 - #define PAGE_GUARD 0x100 - - // NOTE: HeapAlloc - #define HEAP_ZERO_MEMORY 0x00000008 - #define HEAP_NO_SERIALIZE 0x00000001 - #define HEAP_GROWABLE 0x00000002 - #define HEAP_GENERATE_EXCEPTIONS 0x00000004 - #define HEAP_ZERO_MEMORY 0x00000008 - #define HEAP_REALLOC_IN_PLACE_ONLY 0x00000010 - #define HEAP_TAIL_CHECKING_ENABLED 0x00000020 - #define HEAP_FREE_CHECKING_ENABLED 0x00000040 - #define HEAP_DISABLE_COALESCE_ON_FREE 0x00000080 - #define HEAP_CREATE_ALIGN_16 0x00010000 - #define HEAP_CREATE_ENABLE_TRACING 0x00020000 - #define HEAP_CREATE_ENABLE_EXECUTE 0x00040000 - #define HEAP_MAXIMUM_TAG 0x0FFF - #define HEAP_PSEUDO_TAG_FLAG 0x8000 - #define HEAP_TAG_SHIFT 18 - #define HEAP_CREATE_SEGMENT_HEAP 0x00000100 - #define HEAP_CREATE_HARDENED 0x00000200 - - // NOTE: FormatMessageA - #define MAKELANGID(p, s) ((((WORD )(s)) << 10) | (WORD )(p)) - #define LANG_NEUTRAL 0x00 - #define SUBLANG_DEFAULT 0x01 // user default - - // NOTE: CreateFile - #define GENERIC_READ (0x80000000L) - #define GENERIC_WRITE (0x40000000L) - #define GENERIC_EXECUTE (0x20000000L) - #define GENERIC_ALL (0x10000000L) - - #define FILE_APPEND_DATA (0x0004) // file - - // NOTE: CreateFile/FindFirstFile - #define FILE_SHARE_READ 0x00000001 - #define FILE_SHARE_WRITE 0x00000002 - #define FILE_SHARE_DELETE 0x00000004 - - #define FILE_ATTRIBUTE_READONLY 0x00000001 - #define FILE_ATTRIBUTE_HIDDEN 0x00000002 - #define FILE_ATTRIBUTE_SYSTEM 0x00000004 - #define FILE_ATTRIBUTE_DIRECTORY 0x00000010 - #define FILE_ATTRIBUTE_NORMAL 0x00000080 - - // NOTE: STACKFRAME64 - #define IMAGE_FILE_MACHINE_AMD64 0x8664 // AMD64 (K8) - - // NOTE: WaitForSingleObject - #define WAIT_TIMEOUT 258L // dderror - #define STATUS_WAIT_0 ((DWORD )0x00000000L) - #define STATUS_ABANDONED_WAIT_0 ((DWORD )0x00000080L) - - #define S_OK ((HRESULT)0L) - #define S_FALSE ((HRESULT)1L) - - typedef union _ULARGE_INTEGER { - struct { - DWORD LowPart; - DWORD HighPart; - } DUMMYSTRUCTNAME; - struct { - DWORD LowPart; - DWORD HighPart; - } u; - ULONGLONG QuadPart; - } ULARGE_INTEGER; - - typedef union _LARGE_INTEGER { - struct { - DWORD LowPart; - LONG HighPart; - } DUMMYSTRUCTNAME; - struct { - DWORD LowPart; - LONG HighPart; - } u; - LONGLONG QuadPart; - } LARGE_INTEGER; - - typedef struct __declspec(align(16)) _M128A { - ULONGLONG Low; - LONGLONG High; - } M128A, *PM128A; - - typedef struct __declspec(align(16)) _XSAVE_FORMAT { - WORD ControlWord; - WORD StatusWord; - BYTE TagWord; - BYTE Reserved1; - WORD ErrorOpcode; - DWORD ErrorOffset; - WORD ErrorSelector; - WORD Reserved2; - DWORD DataOffset; - WORD DataSelector; - WORD Reserved3; - DWORD MxCsr; - DWORD MxCsr_Mask; - M128A FloatRegisters[8]; - #if defined(_WIN64) - M128A XmmRegisters[16]; - BYTE Reserved4[96]; - #else - M128A XmmRegisters[8]; - BYTE Reserved4[224]; - #endif - } XSAVE_FORMAT, *PXSAVE_FORMAT; - typedef XSAVE_FORMAT XMM_SAVE_AREA32, *PXMM_SAVE_AREA32; - - typedef struct __declspec(align(16)) _CONTEXT { - DWORD64 P1Home; - DWORD64 P2Home; - DWORD64 P3Home; - DWORD64 P4Home; - DWORD64 P5Home; - DWORD64 P6Home; - DWORD ContextFlags; - DWORD MxCsr; - WORD SegCs; - WORD SegDs; - WORD SegEs; - WORD SegFs; - WORD SegGs; - WORD SegSs; - DWORD EFlags; - DWORD64 Dr0; - DWORD64 Dr1; - DWORD64 Dr2; - DWORD64 Dr3; - DWORD64 Dr6; - DWORD64 Dr7; - DWORD64 Rax; - DWORD64 Rcx; - DWORD64 Rdx; - DWORD64 Rbx; - DWORD64 Rsp; - DWORD64 Rbp; - DWORD64 Rsi; - DWORD64 Rdi; - DWORD64 R8; - DWORD64 R9; - DWORD64 R10; - DWORD64 R11; - DWORD64 R12; - DWORD64 R13; - DWORD64 R14; - DWORD64 R15; - DWORD64 Rip; - - union { - XMM_SAVE_AREA32 FltSave; - - struct { - M128A Header[2]; - M128A Legacy[8]; - M128A Xmm0; - M128A Xmm1; - M128A Xmm2; - M128A Xmm3; - M128A Xmm4; - M128A Xmm5; - M128A Xmm6; - M128A Xmm7; - M128A Xmm8; - M128A Xmm9; - M128A Xmm10; - M128A Xmm11; - M128A Xmm12; - M128A Xmm13; - M128A Xmm14; - M128A Xmm15; - } DUMMYSTRUCTNAME; - } DUMMYUNIONNAME; - - M128A VectorRegister[26]; - DWORD64 VectorControl; - DWORD64 DebugControl; - DWORD64 LastBranchToRip; - DWORD64 LastBranchFromRip; - DWORD64 LastExceptionToRip; - DWORD64 LastExceptionFromRip; - } CONTEXT; - - typedef struct _LIST_ENTRY { - struct _LIST_ENTRY *Flink; - struct _LIST_ENTRY *Blink; - } LIST_ENTRY, *PLIST_ENTRY, PRLIST_ENTRY; - - typedef struct _RTL_CRITICAL_SECTION_DEBUG { - WORD Type; - WORD CreatorBackTraceIndex; - struct _RTL_CRITICAL_SECTION *CriticalSection; - LIST_ENTRY ProcessLocksList; - DWORD EntryCount; - DWORD ContentionCount; - DWORD Flags; - WORD CreatorBackTraceIndexHigh; - WORD Identifier; - } RTL_CRITICAL_SECTION_DEBUG, *PRTL_CRITICAL_SECTION_DEBUG, RTL_RESOURCE_DEBUG, *PRTL_RESOURCE_DEBUG; - - typedef struct _RTL_CONDITION_VARIABLE { - VOID *Ptr; - } RTL_CONDITION_VARIABLE, *PRTL_CONDITION_VARIABLE; - - #pragma pack(push, 8) - typedef struct _RTL_CRITICAL_SECTION { - PRTL_CRITICAL_SECTION_DEBUG DebugInfo; - - // - // The following three fields control entering and exiting the critical - // section for the resource - // - - LONG LockCount; - LONG RecursionCount; - HANDLE OwningThread; // from the thread's ClientId->UniqueThread - HANDLE LockSemaphore; - ULONG_PTR SpinCount; // force size on 64-bit systems when packed - } RTL_CRITICAL_SECTION, *PRTL_CRITICAL_SECTION; - #pragma pack(pop) - - typedef struct _MODLOAD_DATA { - DWORD ssize; // size of this struct - DWORD ssig; // signature identifying the passed data - VOID *data; // pointer to passed data - DWORD size; // size of passed data - DWORD flags; // options - } MODLOAD_DATA, *PMODLOAD_DATA; - - #define SLMFLAG_VIRTUAL 0x1 - #define SLMFLAG_ALT_INDEX 0x2 - #define SLMFLAG_NO_SYMBOLS 0x4 - - extern "C" - { - __declspec(dllimport) VOID __stdcall RtlCaptureContext(CONTEXT *ContextRecord); - __declspec(dllimport) HANDLE __stdcall GetCurrentProcess(void); - __declspec(dllimport) HANDLE __stdcall GetCurrentThread(void); - __declspec(dllimport) DWORD __stdcall SymSetOptions(DWORD SymOptions); - __declspec(dllimport) BOOL __stdcall SymInitialize(HANDLE hProcess, const CHAR* UserSearchPath, BOOL fInvadeProcess); - __declspec(dllimport) DWORD64 __stdcall SymLoadModuleEx(HANDLE hProcess, HANDLE hFile, CHAR const *ImageName, CHAR const *ModuleName, DWORD64 BaseOfDll, DWORD DllSize, MODLOAD_DATA *Data, DWORD Flags); - __declspec(dllimport) BOOL __stdcall SymUnloadModule64(HANDLE hProcess, DWORD64 BaseOfDll); - } - - // NOTE: um/heapapi.h //////////////////////////////////////////////////////////////////// - extern "C" - { - __declspec(dllimport) HANDLE __stdcall HeapCreate(DWORD flOptions, SIZE_T dwInitialSize, SIZE_T dwMaximumSize); - __declspec(dllimport) BOOL __stdcall HeapDestroy(HANDLE hHeap); - __declspec(dllimport) VOID * __stdcall HeapAlloc(HANDLE hHeap, DWORD dwFlags,SIZE_T dwBytes); - __declspec(dllimport) VOID * __stdcall HeapReAlloc(HANDLE hHeap, DWORD dwFlags, VOID *lpMem, SIZE_T dwBytes); - __declspec(dllimport) BOOL __stdcall HeapFree(HANDLE hHeap, DWORD dwFlags, VOID *lpMem); - __declspec(dllimport) SIZE_T __stdcall HeapSize(HANDLE hHeap, DWORD dwFlags, VOID const *lpMem); - __declspec(dllimport) HANDLE __stdcall GetProcessHeap(VOID); - __declspec(dllimport) SIZE_T __stdcall HeapCompact(HANDLE hHeap, DWORD dwFlags); - } - - // NOTE: shared/windef.h //////////////////////////////////////////////////////////////////// - typedef struct tagPOINT - { - LONG x; - LONG y; - } POINT, *PPOINT, *NPPOINT, *LPPOINT; - - // NOTE: handleapi.h /////////////////////////////////////////////////////////////////////////// - #define INVALID_HANDLE_VALUE ((HANDLE)(LONG_PTR)-1) - - extern "C" - { - __declspec(dllimport) BOOL __stdcall CloseHandle(HANDLE hObject); - } - - // NOTE: consoleapi.h /////////////////////////////////////////////////////////////////////////// - extern "C" - { - __declspec(dllimport) BOOL __stdcall WriteConsoleA(HANDLE hConsoleOutput, const VOID* lpBuffer, DWORD nNumberOfCharsToWrite, DWORD *lpNumberOfCharsWritten, VOID *lpReserved); - __declspec(dllimport) BOOL __stdcall AllocConsole(VOID); - __declspec(dllimport) BOOL __stdcall FreeConsole(VOID); - __declspec(dllimport) BOOL __stdcall AttachConsole(DWORD dwProcessId); - __declspec(dllimport) BOOL __stdcall GetConsoleMode(HANDLE hConsoleHandle, DWORD *lpMode); - } - - // NOTE: um/minwinbase.h /////////////////////////////////////////////////////////////////////// - // NOTE: FindFirstFile - #define FIND_FIRST_EX_CASE_SENSITIVE 0x00000001 - #define FIND_FIRST_EX_LARGE_FETCH 0x00000002 - - // NOTE: WaitFor.. - #define WAIT_FAILED ((DWORD)0xFFFFFFFF) - #define WAIT_OBJECT_0 ((STATUS_WAIT_0 ) + 0 ) - #define WAIT_ABANDONED ((STATUS_ABANDONED_WAIT_0 ) + 0 ) - #define WAIT_ABANDONED_0 ((STATUS_ABANDONED_WAIT_0 ) + 0 ) - - // NOTE: CreateProcessW - #define CREATE_UNICODE_ENVIRONMENT 0x00000400 - #define CREATE_NO_WINDOW 0x08000000 - - typedef enum _GET_FILEEX_INFO_LEVELS { - GetFileExInfoStandard, - GetFileExMaxInfoLevel - } GET_FILEEX_INFO_LEVELS; - - typedef struct _SECURITY_ATTRIBUTES { - DWORD nLength; - VOID *lpSecurityDescriptor; - BOOL bInheritHandle; - } SECURITY_ATTRIBUTES, *PSECURITY_ATTRIBUTES, *LPSECURITY_ATTRIBUTES; - - typedef enum _FINDEX_INFO_LEVELS { - FindExInfoStandard, - FindExInfoBasic, - FindExInfoMaxInfoLevel - } FINDEX_INFO_LEVELS; - - typedef enum _FINDEX_SEARCH_OPS { - FindExSearchNameMatch, - FindExSearchLimitToDirectories, - FindExSearchLimitToDevices, - FindExSearchMaxSearchOp - } FINDEX_SEARCH_OPS; - - typedef struct _WIN32_FIND_DATAW { - DWORD dwFileAttributes; - FILETIME ftCreationTime; - FILETIME ftLastAccessTime; - FILETIME ftLastWriteTime; - DWORD nFileSizeHigh; - DWORD nFileSizeLow; - DWORD dwReserved0; - DWORD dwReserved1; - WCHAR cFileName[ MAX_PATH ]; - WCHAR cAlternateFileName[ 14 ]; - #ifdef _MAC - DWORD dwFileType; - DWORD dwCreatorType; - WORD wFinderFlags; - #endif - } WIN32_FIND_DATAW, *PWIN32_FIND_DATAW, *LPWIN32_FIND_DATAW; - - typedef struct _SYSTEMTIME { - WORD wYear; - WORD wMonth; - WORD wDayOfWeek; - WORD wDay; - WORD wHour; - WORD wMinute; - WORD wSecond; - WORD wMilliseconds; - } SYSTEMTIME, *PSYSTEMTIME, *LPSYSTEMTIME; - - typedef struct _OVERLAPPED { - ULONG_PTR Internal; - ULONG_PTR InternalHigh; - union { - struct { - DWORD Offset; - DWORD OffsetHigh; - } DUMMYSTRUCTNAME; - VOID *Pointer; - } DUMMYUNIONNAME; - - HANDLE hEvent; - } OVERLAPPED, *LPOVERLAPPED; - - typedef RTL_CRITICAL_SECTION CRITICAL_SECTION; - - #define WAIT_FAILED ((DWORD)0xFFFFFFFF) - #define WAIT_OBJECT_0 ((STATUS_WAIT_0 ) + 0 ) - - #define INFINITE 0xFFFFFFFF // Wait/Synchronisation: Infinite timeout - - #define STD_INPUT_HANDLE ((DWORD)-10) - #define STD_OUTPUT_HANDLE ((DWORD)-11) - #define STD_ERROR_HANDLE ((DWORD)-12) - - #define HANDLE_FLAG_INHERIT 0x00000001 - #define HANDLE_FLAG_PROTECT_FROM_CLOSE 0x00000002 - - // NOTE: MoveFile - #define MOVEFILE_REPLACE_EXISTING 0x00000001 - #define MOVEFILE_COPY_ALLOWED 0x00000002 - - // NOTE: FormatMessageA - #define FORMAT_MESSAGE_ALLOCATE_BUFFER 0x00000100 - #define FORMAT_MESSAGE_IGNORE_INSERTS 0x00000200 - #define FORMAT_MESSAGE_FROM_HMODULE 0x00000800 - #define FORMAT_MESSAGE_FROM_SYSTEM 0x00001000 - - // NOTE: CreateProcessW - #define STARTF_USESTDHANDLES 0x00000100 - - extern "C" - { - __declspec(dllimport) BOOL __stdcall MoveFileExW (const WCHAR *lpExistingFileName, const WCHAR *lpNewFileName, DWORD dwFlags); - __declspec(dllimport) BOOL __stdcall CopyFileW (const WCHAR *lpExistingFileName, const WCHAR *lpNewFileName, BOOL bFailIfExists); - __declspec(dllimport) HANDLE __stdcall CreateSemaphoreA(SECURITY_ATTRIBUTES *lpSemaphoreAttributes, LONG lInitialCount, LONG lMaximumCount, const CHAR *lpName); - __declspec(dllimport) DWORD __stdcall FormatMessageW (DWORD dwFlags, VOID const *lpSource, DWORD dwMessageId, DWORD dwLanguageId, LPWSTR lpBuffer, DWORD nSize, va_list *Arguments); - __declspec(dllimport) HLOCAL __stdcall LocalFree (HLOCAL hMem); - } - - // NOTE: um/stringapiset.h ///////////////////////////////////////////////////////////////////// - extern "C" - { - __declspec(dllimport) int __stdcall MultiByteToWideChar(UINT CodePage, DWORD dwFlags, const CHAR *lpMultiByteStr, int cbMultiByte, WCHAR *lpWideCharStr, int cchWideChar); - __declspec(dllimport) int __stdcall WideCharToMultiByte(UINT CodePage, DWORD dwFlags, const WCHAR *lpWideCharStr, int cchWideChar, LPSTR lpMultiByteStr, int cbMultiByte, const CHAR *lpDefaultChar, BOOL *lpUsedDefaultChar); - } - - // NOTE: um/fileapi.h ////////////////////////////////////////////////////////////////////////// - #define INVALID_FILE_SIZE ((DWORD)0xFFFFFFFF) - #define INVALID_FILE_ATTRIBUTES ((DWORD)-1) - - // NOTE: CreateFile - #define CREATE_NEW 1 - #define CREATE_ALWAYS 2 - #define OPEN_EXISTING 3 - #define OPEN_ALWAYS 4 - #define TRUNCATE_EXISTING 5 - - typedef struct _WIN32_FILE_ATTRIBUTE_DATA { - DWORD dwFileAttributes; - FILETIME ftCreationTime; - FILETIME ftLastAccessTime; - FILETIME ftLastWriteTime; - DWORD nFileSizeHigh; - DWORD nFileSizeLow; - } WIN32_FILE_ATTRIBUTE_DATA, *LPWIN32_FILE_ATTRIBUTE_DATA; - - extern "C" - { - __declspec(dllimport) BOOL __stdcall FlushFileBuffers (HANDLE hFile); - __declspec(dllimport) BOOL __stdcall CreateDirectoryW (const WCHAR *lpPathName, SECURITY_ATTRIBUTES *lpSecurityAttributes); - __declspec(dllimport) BOOL __stdcall RemoveDirectoryW (const WCHAR *lpPathName); - __declspec(dllimport) BOOL __stdcall FindNextFileW (HANDLE hFindFile, WIN32_FIND_DATAW *lpFindFileData); - __declspec(dllimport) BOOL __stdcall FindClose (HANDLE hFindFile); - __declspec(dllimport) BOOL __stdcall FileTimeToLocalFileTime(const FILETIME *lpFileTime, FILETIME *lpLocalFileTime); - - __declspec(dllimport) HANDLE __stdcall FindFirstFileExW (const WCHAR *lpFileName, FINDEX_INFO_LEVELS fInfoLevelId, VOID *lpFindFileData, FINDEX_SEARCH_OPS fSearchOp, VOID *lpSearchFilter, DWORD dwAdditionalFlags); - __declspec(dllimport) BOOL __stdcall GetFileAttributesExW (const WCHAR *lpFileName, GET_FILEEX_INFO_LEVELS fInfoLevelId, VOID *lpFileInformation); - __declspec(dllimport) BOOL __stdcall GetFileSizeEx (HANDLE hFile, LARGE_INTEGER *lpFileSize); - __declspec(dllimport) BOOL __stdcall DeleteFileW (const WCHAR *lpFileName); - __declspec(dllimport) HANDLE __stdcall CreateFileW (const WCHAR *lpFileName, DWORD dwDesiredAccess, DWORD dwShareMode, SECURITY_ATTRIBUTES *lpSecurityAttributes, DWORD dwCreationDisposition, DWORD dwFlagsAndAttributes, HANDLE hTemplateFile); - __declspec(dllimport) BOOL __stdcall ReadFile (HANDLE hFile, VOID *lpBuffer, DWORD nNumberOfBytesToRead, DWORD *lpNumberOfBytesRead, OVERLAPPED *lpOverlapped); - __declspec(dllimport) BOOL __stdcall WriteFile (HANDLE hFile, const VOID *lpBuffer, DWORD nNumberOfBytesToWrite, DWORD *lpNumberOfBytesWritten, OVERLAPPED *lpOverlapped); - __declspec(dllimport) BOOL __stdcall GetDiskFreeSpaceExW (WCHAR const *lpDirectoryName, ULARGE_INTEGER *lpFreeBytesAvailableToCaller, ULARGE_INTEGER *lpTotalNumberOfBytes, ULARGE_INTEGER *lpTotalNumberOfFreeBytes); - } - - // NOTE: um/processenv.h /////////////////////////////////////////////////////////////////////// - extern "C" - { - __declspec(dllimport) DWORD __stdcall GetCurrentDirectoryW (DWORD nBufferLength, WCHAR *lpBuffer); - __declspec(dllimport) HANDLE __stdcall GetStdHandle (DWORD nStdHandle); - __declspec(dllimport) WCHAR* __stdcall GetEnvironmentStringsW (); - __declspec(dllimport) BOOL __stdcall FreeEnvironmentStringsW(WCHAR *penv); - __declspec(dllimport) DWORD __stdcall GetEnvironmentVariableW(WCHAR const *lpName, WCHAR *lpBuffer, DWORD nSize); - __declspec(dllimport) BOOL __stdcall SetEnvironmentVariableW(WCHAR const *lpName, WCHAR const *lpValue); - } - - // NOTE: um/psapi.h //////////////////////////////////////////////////////////////////////////// - typedef struct _PROCESS_MEMORY_COUNTERS { - 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; - } PROCESS_MEMORY_COUNTERS; - typedef PROCESS_MEMORY_COUNTERS *PPROCESS_MEMORY_COUNTERS; - - extern "C" - { - __declspec(dllimport) BOOL __stdcall GetProcessMemoryInfo(HANDLE Process, PPROCESS_MEMORY_COUNTERS ppsmemCounters, DWORD cb); - } - - // NOTE: um/sysinfoapi.h /////////////////////////////////////////////////////////////////////// - typedef struct _SYSTEM_INFO { - union { - DWORD dwOemId; // Obsolete field...do not use - struct { - WORD wProcessorArchitecture; - WORD wReserved; - } DUMMYSTRUCTNAME; - } DUMMYUNIONNAME; - DWORD dwPageSize; - VOID *lpMinimumApplicationAddress; - VOID *lpMaximumApplicationAddress; - DWORD_PTR dwActiveProcessorMask; - DWORD dwNumberOfProcessors; - DWORD dwProcessorType; - DWORD dwAllocationGranularity; - WORD wProcessorLevel; - WORD wProcessorRevision; - } SYSTEM_INFO, *LPSYSTEM_INFO; - - extern "C" - { - __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); - } - - // NOTE: um/timezoneapi.h ////////////////////////////////////////////////////////////////////// - typedef struct _TIME_ZONE_INFORMATION { - LONG Bias; - WCHAR StandardName[32]; - SYSTEMTIME StandardDate; - LONG StandardBias; - WCHAR DaylightName[32]; - SYSTEMTIME DaylightDate; - LONG DaylightBias; - } TIME_ZONE_INFORMATION, *PTIME_ZONE_INFORMATION, *LPTIME_ZONE_INFORMATION; - - extern "C" - { - __declspec(dllimport) BOOL __stdcall FileTimeToSystemTime (const FILETIME* lpFileTime, SYSTEMTIME *lpSystemTime); - __declspec(dllimport) BOOL __stdcall SystemTimeToFileTime (const SYSTEMTIME* lpSystemTime, FILETIME *lpFileTime); - __declspec(dllimport) BOOL __stdcall TzSpecificLocalTimeToSystemTime(const TIME_ZONE_INFORMATION* lpTimeZoneInformation, const SYSTEMTIME* lpLocalTime, const LPSYSTEMTIME lpUniversalTime); - } - - // NOTE: shared/windef.h /////////////////////////////////////////////////////////////////////// - typedef struct tagRECT { - LONG left; - LONG top; - LONG right; - LONG bottom; - } RECT; - - struct HWND__ { - int unused; - }; - typedef struct HWND__ *HWND; - - struct DPI_AWARENESS_CONTEXT__ { - int unused; - }; - typedef struct DPI_AWARENESS_CONTEXT__ *DPI_AWARENESS_CONTEXT; - - typedef enum DPI_AWARENESS { - DPI_AWARENESS_INVALID = -1, - DPI_AWARENESS_UNAWARE = 0, - DPI_AWARENESS_SYSTEM_AWARE = 1, - DPI_AWARENESS_PER_MONITOR_AWARE = 2 - } DPI_AWARENESS; - - #define DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2 ((DPI_AWARENESS_CONTEXT)-4) - - // NOTE: um/winuser.h ////////////////////////////////////////////////////////////////////////// - typedef struct tagWINDOWPLACEMENT { - UINT length; - UINT flags; - UINT showCmd; - POINT ptMinPosition; - POINT ptMaxPosition; - RECT rcNormalPosition; - #ifdef _MAC - RECT rcDevice; - #endif - } WINDOWPLACEMENT; - typedef WINDOWPLACEMENT *PWINDOWPLACEMENT, *LPWINDOWPLACEMENT; - - #define SW_HIDE 0 - #define SW_NORMAL 1 - #define SW_MAXIMIZE 3 - #define SW_SHOWNOACTIVATE 4 - #define SW_SHOW 5 - #define SW_FORCEMINIMIZE 11 - - extern "C" - { - __declspec(dllimport) BOOL __stdcall GetWindowRect (HWND hWnd, RECT *lpRect); - __declspec(dllimport) BOOL __stdcall SetWindowPos (HWND hWnd, HWND hWndInsertAfter, int X, int Y, int cx, int cy, UINT uFlags); - __declspec(dllimport) UINT __stdcall GetWindowModuleFileNameA(HWND hwnd, LPSTR pszFileName, UINT cchFileNameMax); - __declspec(dllimport) BOOL __stdcall ShowWindow (HWND hWnd, int nCmdShow); - __declspec(dllimport) BOOL __stdcall GetWindowPlacement (HWND hWnd, WINDOWPLACEMENT *lpwndpl); - - } - - // NOTE: um/wininet.h ////////////////////////////////////////////////////////////////////////// - typedef WORD INTERNET_PORT; - typedef VOID *HINTERNET; - - // NOTE: um/winhttp.h ////////////////////////////////////////////////////////////////////////// - #define WINHTTP_ACCESS_TYPE_DEFAULT_PROXY 0 - #define WINHTTP_ACCESS_TYPE_NO_PROXY 1 - #define WINHTTP_ACCESS_TYPE_NAMED_PROXY 3 - #define WINHTTP_ACCESS_TYPE_AUTOMATIC_PROXY 4 - - #define INTERNET_DEFAULT_PORT 0 // use the protocol-specific default - #define INTERNET_DEFAULT_HTTP_PORT 80 // " " HTTP " - #define INTERNET_DEFAULT_HTTPS_PORT 443 // " " HTTPS " - - // NOTE: WinHttpOpen - #define WINHTTP_FLAG_ASYNC 0x10000000 // this session is asynchronous (where supported) - #define WINHTTP_FLAG_SECURE_DEFAULTS 0x30000000 // note that this flag also forces async - - // NOTE: WinHttpOpenRequest - #define WINHTTP_FLAG_SECURE 0x00800000 // use SSL if applicable (HTTPS) - #define WINHTTP_FLAG_ESCAPE_PERCENT 0x00000004 // if escaping enabled, escape percent as well - #define WINHTTP_FLAG_NULL_CODEPAGE 0x00000008 // assume all symbols are ASCII, use fast convertion - #define WINHTTP_FLAG_ESCAPE_DISABLE 0x00000040 // disable escaping - #define WINHTTP_FLAG_ESCAPE_DISABLE_QUERY 0x00000080 // if escaping enabled escape path part, but do not escape query - #define WINHTTP_FLAG_BYPASS_PROXY_CACHE 0x00000100 // add "pragma: no-cache" request header - #define WINHTTP_FLAG_REFRESH WINHTTP_FLAG_BYPASS_PROXY_CACHE - #define WINHTTP_FLAG_AUTOMATIC_CHUNKING 0x00000200 // Send request without content-length header or chunked TE - - #define WINHTTP_NO_PROXY_NAME NULL - #define WINHTTP_NO_PROXY_BYPASS NULL - - // - // WINHTTP_QUERY_FLAG_NUMBER - if this bit is set in the dwInfoLevel parameter of - // HttpQueryHeader(), then the value of the header will be converted to a number - // before being returned to the caller, if applicable - // - #define WINHTTP_QUERY_FLAG_NUMBER 0x20000000 - - #define WINHTTP_QUERY_MIME_VERSION 0 - #define WINHTTP_QUERY_CONTENT_TYPE 1 - #define WINHTTP_QUERY_CONTENT_TRANSFER_ENCODING 2 - #define WINHTTP_QUERY_CONTENT_ID 3 - #define WINHTTP_QUERY_CONTENT_DESCRIPTION 4 - #define WINHTTP_QUERY_CONTENT_LENGTH 5 - #define WINHTTP_QUERY_CONTENT_LANGUAGE 6 - #define WINHTTP_QUERY_ALLOW 7 - #define WINHTTP_QUERY_PUBLIC 8 - #define WINHTTP_QUERY_DATE 9 - #define WINHTTP_QUERY_EXPIRES 10 - #define WINHTTP_QUERY_LAST_MODIFIED 11 - #define WINHTTP_QUERY_MESSAGE_ID 12 - #define WINHTTP_QUERY_URI 13 - #define WINHTTP_QUERY_DERIVED_FROM 14 - #define WINHTTP_QUERY_COST 15 - #define WINHTTP_QUERY_LINK 16 - #define WINHTTP_QUERY_PRAGMA 17 - #define WINHTTP_QUERY_VERSION 18 // special: part of status line - #define WINHTTP_QUERY_STATUS_CODE 19 // special: part of status line - #define WINHTTP_QUERY_STATUS_TEXT 20 // special: part of status line - #define WINHTTP_QUERY_RAW_HEADERS 21 // special: all headers as ASCIIZ - #define WINHTTP_QUERY_RAW_HEADERS_CRLF 22 // special: all headers - #define WINHTTP_QUERY_CONNECTION 23 - #define WINHTTP_QUERY_ACCEPT 24 - #define WINHTTP_QUERY_ACCEPT_CHARSET 25 - #define WINHTTP_QUERY_ACCEPT_ENCODING 26 - #define WINHTTP_QUERY_ACCEPT_LANGUAGE 27 - #define WINHTTP_QUERY_AUTHORIZATION 28 - #define WINHTTP_QUERY_CONTENT_ENCODING 29 - #define WINHTTP_QUERY_FORWARDED 30 - #define WINHTTP_QUERY_FROM 31 - #define WINHTTP_QUERY_IF_MODIFIED_SINCE 32 - #define WINHTTP_QUERY_LOCATION 33 - #define WINHTTP_QUERY_ORIG_URI 34 - #define WINHTTP_QUERY_REFERER 35 - #define WINHTTP_QUERY_RETRY_AFTER 36 - #define WINHTTP_QUERY_SERVER 37 - #define WINHTTP_QUERY_TITLE 38 - #define WINHTTP_QUERY_USER_AGENT 39 - #define WINHTTP_QUERY_WWW_AUTHENTICATE 40 - #define WINHTTP_QUERY_PROXY_AUTHENTICATE 41 - #define WINHTTP_QUERY_ACCEPT_RANGES 42 - #define WINHTTP_QUERY_SET_COOKIE 43 - #define WINHTTP_QUERY_COOKIE 44 - #define WINHTTP_QUERY_REQUEST_METHOD 45 // special: GET/POST etc. - #define WINHTTP_QUERY_REFRESH 46 - #define WINHTTP_QUERY_CONTENT_DISPOSITION 47 - - // NOTE: WinHttpQueryHeaders prettifiers for optional parameters. - #define WINHTTP_HEADER_NAME_BY_INDEX NULL - #define WINHTTP_NO_OUTPUT_BUFFER NULL - #define WINHTTP_NO_HEADER_INDEX NULL - - // NOTE: Http Response Status Codes - #define HTTP_STATUS_CONTINUE 100 // OK to continue with request - #define HTTP_STATUS_SWITCH_PROTOCOLS 101 // server has switched protocols in upgrade header - - #define HTTP_STATUS_OK 200 // request completed - #define HTTP_STATUS_CREATED 201 // object created, reason = new URI - #define HTTP_STATUS_ACCEPTED 202 // async completion (TBS) - #define HTTP_STATUS_PARTIAL 203 // partial completion - #define HTTP_STATUS_NO_CONTENT 204 // no info to return - #define HTTP_STATUS_RESET_CONTENT 205 // request completed, but clear form - #define HTTP_STATUS_PARTIAL_CONTENT 206 // partial GET fulfilled - #define HTTP_STATUS_WEBDAV_MULTI_STATUS 207 // WebDAV Multi-Status - - #define HTTP_STATUS_AMBIGUOUS 300 // server couldn't decide what to return - #define HTTP_STATUS_MOVED 301 // object permanently moved - #define HTTP_STATUS_REDIRECT 302 // object temporarily moved - #define HTTP_STATUS_REDIRECT_METHOD 303 // redirection w/ new access method - #define HTTP_STATUS_NOT_MODIFIED 304 // if-modified-since was not modified - #define HTTP_STATUS_USE_PROXY 305 // redirection to proxy, location header specifies proxy to use - #define HTTP_STATUS_REDIRECT_KEEP_VERB 307 // HTTP/1.1: keep same verb - #define HTTP_STATUS_PERMANENT_REDIRECT 308 // Object permanently moved keep verb - - #define HTTP_STATUS_BAD_REQUEST 400 // invalid syntax - #define HTTP_STATUS_DENIED 401 // access denied - #define HTTP_STATUS_PAYMENT_REQ 402 // payment required - #define HTTP_STATUS_FORBIDDEN 403 // request forbidden - #define HTTP_STATUS_NOT_FOUND 404 // object not found - #define HTTP_STATUS_BAD_METHOD 405 // method is not allowed - #define HTTP_STATUS_NONE_ACCEPTABLE 406 // no response acceptable to client found - #define HTTP_STATUS_PROXY_AUTH_REQ 407 // proxy authentication required - #define HTTP_STATUS_REQUEST_TIMEOUT 408 // server timed out waiting for request - #define HTTP_STATUS_CONFLICT 409 // user should resubmit with more info - #define HTTP_STATUS_GONE 410 // the resource is no longer available - #define HTTP_STATUS_LENGTH_REQUIRED 411 // the server refused to accept request w/o a length - #define HTTP_STATUS_PRECOND_FAILED 412 // precondition given in request failed - #define HTTP_STATUS_REQUEST_TOO_LARGE 413 // request entity was too large - #define HTTP_STATUS_URI_TOO_LONG 414 // request URI too long - #define HTTP_STATUS_UNSUPPORTED_MEDIA 415 // unsupported media type - #define HTTP_STATUS_RETRY_WITH 449 // retry after doing the appropriate action. - - #define HTTP_STATUS_SERVER_ERROR 500 // internal server error - #define HTTP_STATUS_NOT_SUPPORTED 501 // required not supported - #define HTTP_STATUS_BAD_GATEWAY 502 // error response received from gateway - #define HTTP_STATUS_SERVICE_UNAVAIL 503 // temporarily overloaded - #define HTTP_STATUS_GATEWAY_TIMEOUT 504 // timed out waiting for gateway - #define HTTP_STATUS_VERSION_NOT_SUP 505 // HTTP version not supported - - #define HTTP_STATUS_FIRST HTTP_STATUS_CONTINUE - #define HTTP_STATUS_LAST HTTP_STATUS_VERSION_NOT_SUP - - #define WINHTTP_CALLBACK_STATUS_RESOLVING_NAME 0x00000001 - #define WINHTTP_CALLBACK_STATUS_NAME_RESOLVED 0x00000002 - #define WINHTTP_CALLBACK_STATUS_CONNECTING_TO_SERVER 0x00000004 - #define WINHTTP_CALLBACK_STATUS_CONNECTED_TO_SERVER 0x00000008 - #define WINHTTP_CALLBACK_STATUS_SENDING_REQUEST 0x00000010 - #define WINHTTP_CALLBACK_STATUS_REQUEST_SENT 0x00000020 - #define WINHTTP_CALLBACK_STATUS_RECEIVING_RESPONSE 0x00000040 - #define WINHTTP_CALLBACK_STATUS_RESPONSE_RECEIVED 0x00000080 - #define WINHTTP_CALLBACK_STATUS_CLOSING_CONNECTION 0x00000100 - #define WINHTTP_CALLBACK_STATUS_CONNECTION_CLOSED 0x00000200 - #define WINHTTP_CALLBACK_STATUS_HANDLE_CREATED 0x00000400 - #define WINHTTP_CALLBACK_STATUS_HANDLE_CLOSING 0x00000800 - #define WINHTTP_CALLBACK_STATUS_DETECTING_PROXY 0x00001000 - #define WINHTTP_CALLBACK_STATUS_REDIRECT 0x00004000 - #define WINHTTP_CALLBACK_STATUS_INTERMEDIATE_RESPONSE 0x00008000 - #define WINHTTP_CALLBACK_STATUS_SECURE_FAILURE 0x00010000 - #define WINHTTP_CALLBACK_STATUS_HEADERS_AVAILABLE 0x00020000 - #define WINHTTP_CALLBACK_STATUS_DATA_AVAILABLE 0x00040000 - #define WINHTTP_CALLBACK_STATUS_READ_COMPLETE 0x00080000 - #define WINHTTP_CALLBACK_STATUS_WRITE_COMPLETE 0x00100000 - #define WINHTTP_CALLBACK_STATUS_REQUEST_ERROR 0x00200000 - #define WINHTTP_CALLBACK_STATUS_SENDREQUEST_COMPLETE 0x00400000 - - #define WINHTTP_CALLBACK_STATUS_GETPROXYFORURL_COMPLETE 0x01000000 - #define WINHTTP_CALLBACK_STATUS_CLOSE_COMPLETE 0x02000000 - #define WINHTTP_CALLBACK_STATUS_SHUTDOWN_COMPLETE 0x04000000 - #define WINHTTP_CALLBACK_STATUS_SETTINGS_WRITE_COMPLETE 0x10000000 - #define WINHTTP_CALLBACK_STATUS_SETTINGS_READ_COMPLETE 0x20000000 - - #define WINHTTP_CALLBACK_FLAG_RESOLVE_NAME (WINHTTP_CALLBACK_STATUS_RESOLVING_NAME | WINHTTP_CALLBACK_STATUS_NAME_RESOLVED) - #define WINHTTP_CALLBACK_FLAG_CONNECT_TO_SERVER (WINHTTP_CALLBACK_STATUS_CONNECTING_TO_SERVER | WINHTTP_CALLBACK_STATUS_CONNECTED_TO_SERVER) - #define WINHTTP_CALLBACK_FLAG_SEND_REQUEST (WINHTTP_CALLBACK_STATUS_SENDING_REQUEST | WINHTTP_CALLBACK_STATUS_REQUEST_SENT) - #define WINHTTP_CALLBACK_FLAG_RECEIVE_RESPONSE (WINHTTP_CALLBACK_STATUS_RECEIVING_RESPONSE | WINHTTP_CALLBACK_STATUS_RESPONSE_RECEIVED) - #define WINHTTP_CALLBACK_FLAG_CLOSE_CONNECTION (WINHTTP_CALLBACK_STATUS_CLOSING_CONNECTION | WINHTTP_CALLBACK_STATUS_CONNECTION_CLOSED) - #define WINHTTP_CALLBACK_FLAG_HANDLES (WINHTTP_CALLBACK_STATUS_HANDLE_CREATED | WINHTTP_CALLBACK_STATUS_HANDLE_CLOSING) - #define WINHTTP_CALLBACK_FLAG_DETECTING_PROXY WINHTTP_CALLBACK_STATUS_DETECTING_PROXY - #define WINHTTP_CALLBACK_FLAG_REDIRECT WINHTTP_CALLBACK_STATUS_REDIRECT - #define WINHTTP_CALLBACK_FLAG_INTERMEDIATE_RESPONSE WINHTTP_CALLBACK_STATUS_INTERMEDIATE_RESPONSE - #define WINHTTP_CALLBACK_FLAG_SECURE_FAILURE WINHTTP_CALLBACK_STATUS_SECURE_FAILURE - #define WINHTTP_CALLBACK_FLAG_SENDREQUEST_COMPLETE WINHTTP_CALLBACK_STATUS_SENDREQUEST_COMPLETE - #define WINHTTP_CALLBACK_FLAG_HEADERS_AVAILABLE WINHTTP_CALLBACK_STATUS_HEADERS_AVAILABLE - #define WINHTTP_CALLBACK_FLAG_DATA_AVAILABLE WINHTTP_CALLBACK_STATUS_DATA_AVAILABLE - #define WINHTTP_CALLBACK_FLAG_READ_COMPLETE WINHTTP_CALLBACK_STATUS_READ_COMPLETE - #define WINHTTP_CALLBACK_FLAG_WRITE_COMPLETE WINHTTP_CALLBACK_STATUS_WRITE_COMPLETE - #define WINHTTP_CALLBACK_FLAG_REQUEST_ERROR WINHTTP_CALLBACK_STATUS_REQUEST_ERROR - - #define WINHTTP_CALLBACK_FLAG_GETPROXYFORURL_COMPLETE WINHTTP_CALLBACK_STATUS_GETPROXYFORURL_COMPLETE - - #define WINHTTP_CALLBACK_FLAG_ALL_COMPLETIONS (WINHTTP_CALLBACK_STATUS_SENDREQUEST_COMPLETE \ - | WINHTTP_CALLBACK_STATUS_HEADERS_AVAILABLE \ - | WINHTTP_CALLBACK_STATUS_DATA_AVAILABLE \ - | WINHTTP_CALLBACK_STATUS_READ_COMPLETE \ - | WINHTTP_CALLBACK_STATUS_WRITE_COMPLETE \ - | WINHTTP_CALLBACK_STATUS_REQUEST_ERROR \ - | WINHTTP_CALLBACK_STATUS_GETPROXYFORURL_COMPLETE) - - #define WINHTTP_CALLBACK_FLAG_ALL_NOTIFICATIONS 0xffffffff - #define WINHTTP_INVALID_STATUS_CALLBACK ((WINHTTP_STATUS_CALLBACK)(-1L)) - - typedef struct _WINHTTP_EXTENDED_HEADER - { - union - { - CHAR const *pwszName; - WCHAR const *pszName; - }; - union - { - WCHAR const *pwszValue; - CHAR const *pszValue; - }; - } WINHTTP_EXTENDED_HEADER, *PWINHTTP_EXTENDED_HEADER; - - typedef struct _WINHTTP_ASYNC_RESULT - { - DWORD *dwResult; // indicates which async API has encountered an error - DWORD dwError; // the error code if the API failed - } WINHTTP_ASYNC_RESULT, *LPWINHTTP_ASYNC_RESULT, *PWINHTTP_ASYNC_RESULT; - - typedef - VOID - (*WINHTTP_STATUS_CALLBACK)( - HINTERNET hInternet, - DWORD *dwContext, - DWORD dwInternetStatus, - VOID *lpvStatusInformation, - DWORD dwStatusInformationLength - ); - - extern "C" - { - __declspec(dllimport) HINTERNET __stdcall WinHttpOpen(WCHAR const *pszAgentW, DWORD dwAccessType, WCHAR const *pszProxyW, WCHAR const *pszProxyBypassW, DWORD dwFlags); - __declspec(dllimport) BOOL __stdcall WinHttpCloseHandle(HINTERNET hInternet); - __declspec(dllimport) HINTERNET __stdcall WinHttpConnect(HINTERNET hSession, WCHAR const *pswzServerName, INTERNET_PORT nServerPort, DWORD dwReserved); - __declspec(dllimport) BOOL __stdcall WinHttpReadData(HINTERNET hRequest, VOID *lpBuffer, DWORD dwNumberOfBytesToRead, DWORD *lpdwNumberOfBytesRead); - __declspec(dllimport) HINTERNET __stdcall WinHttpOpenRequest(HINTERNET hConnect, WCHAR const *pwszVerb, WCHAR const *pwszObjectName, WCHAR const *pwszVersion, WCHAR const *pwszReferrer, WCHAR const *ppwszAcceptTypes, DWORD dwFlags); - __declspec(dllimport) BOOL __stdcall WinHttpSendRequest(HINTERNET hRequest, WCHAR const *lpszHeaders, DWORD dwHeadersLength, VOID *lpOptional, DWORD dwOptionalLength, DWORD dwTotalLength, DWORD_PTR dwContext); - __declspec(dllimport) DWORD __stdcall WinHttpAddRequestHeadersEx(HINTERNET hRequest, DWORD dwModifiers, ULONGLONG ullFlags, ULONGLONG ullExtra, DWORD cHeaders, WINHTTP_EXTENDED_HEADER *pHeaders); - __declspec(dllimport) BOOL __stdcall WinHttpSetCredentials(HINTERNET hRequest, // HINTERNET handle returned by WinHttpOpenRequest. - DWORD AuthTargets, // Only WINHTTP_AUTH_TARGET_SERVER and WINHTTP_AUTH_TARGET_PROXY are supported in this version and they are mutually exclusive - DWORD AuthScheme, // must be one of the supported Auth Schemes returned from WinHttpQueryAuthSchemes() - WCHAR * pwszUserName, // 1) NULL if default creds is to be used, in which case pszPassword will be ignored - WCHAR * pwszPassword, // 1) "" == Blank Password; 2)Parameter ignored if pszUserName is NULL; 3) Invalid to pass in NULL if pszUserName is not NULL - VOID * pAuthParams); - __declspec(dllimport) BOOL __stdcall WinHttpQueryHeaders(HINTERNET hRequest, DWORD dwInfoLevel, WCHAR const *pwszName, VOID *lpBuffer, DWORD *lpdwBufferLength, DWORD *lpdwIndex); - __declspec(dllimport) BOOL __stdcall WinHttpReceiveResponse(HINTERNET hRequest, VOID *lpReserved); - __declspec(dllimport) WINHTTP_STATUS_CALLBACK __stdcall WinHttpSetStatusCallback(HINTERNET hInternet, WINHTTP_STATUS_CALLBACK lpfnInternetCallback, DWORD dwNotificationFlags, DWORD_PTR dwReserved); - } - - // NOTE: um/DbgHelp.h ////////////////////////////////////////////////////////////////////////// - #define SYMOPT_CASE_INSENSITIVE 0x00000001 - #define SYMOPT_UNDNAME 0x00000002 - #define SYMOPT_DEFERRED_LOADS 0x00000004 - #define SYMOPT_NO_CPP 0x00000008 - #define SYMOPT_LOAD_LINES 0x00000010 - #define SYMOPT_OMAP_FIND_NEAREST 0x00000020 - #define SYMOPT_LOAD_ANYTHING 0x00000040 - #define SYMOPT_IGNORE_CVREC 0x00000080 - #define SYMOPT_NO_UNQUALIFIED_LOADS 0x00000100 - #define SYMOPT_FAIL_CRITICAL_ERRORS 0x00000200 - #define SYMOPT_EXACT_SYMBOLS 0x00000400 - #define SYMOPT_ALLOW_ABSOLUTE_SYMBOLS 0x00000800 - #define SYMOPT_IGNORE_NT_SYMPATH 0x00001000 - #define SYMOPT_INCLUDE_32BIT_MODULES 0x00002000 - #define SYMOPT_PUBLICS_ONLY 0x00004000 - #define SYMOPT_NO_PUBLICS 0x00008000 - #define SYMOPT_AUTO_PUBLICS 0x00010000 - #define SYMOPT_NO_IMAGE_SEARCH 0x00020000 - #define SYMOPT_SECURE 0x00040000 - #define SYMOPT_NO_PROMPTS 0x00080000 - #define SYMOPT_OVERWRITE 0x00100000 - #define SYMOPT_IGNORE_IMAGEDIR 0x00200000 - #define SYMOPT_FLAT_DIRECTORY 0x00400000 - #define SYMOPT_FAVOR_COMPRESSED 0x00800000 - #define SYMOPT_ALLOW_ZERO_ADDRESS 0x01000000 - #define SYMOPT_DISABLE_SYMSRV_AUTODETECT 0x02000000 - #define SYMOPT_READONLY_CACHE 0x04000000 - #define SYMOPT_SYMPATH_LAST 0x08000000 - #define SYMOPT_DISABLE_FAST_SYMBOLS 0x10000000 - #define SYMOPT_DISABLE_SYMSRV_TIMEOUT 0x20000000 - #define SYMOPT_DISABLE_SRVSTAR_ON_STARTUP 0x40000000 - #define SYMOPT_DEBUG 0x80000000 - - #define MAX_SYM_NAME 2000 - - typedef enum { - AddrMode1616, - AddrMode1632, - AddrModeReal, - AddrModeFlat - } ADDRESS_MODE; - - typedef struct _tagADDRESS64 { - DWORD64 Offset; - WORD Segment; - ADDRESS_MODE Mode; - } ADDRESS64, *LPADDRESS64; - - - typedef struct _KDHELP64 { - DWORD64 Thread; - DWORD ThCallbackStack; - DWORD ThCallbackBStore; - DWORD NextCallback; - DWORD FramePointer; - DWORD64 KiCallUserMode; - DWORD64 KeUserCallbackDispatcher; - DWORD64 SystemRangeStart; - DWORD64 KiUserExceptionDispatcher; - DWORD64 StackBase; - DWORD64 StackLimit; - DWORD BuildVersion; - DWORD RetpolineStubFunctionTableSize; - DWORD64 RetpolineStubFunctionTable; - DWORD RetpolineStubOffset; - DWORD RetpolineStubSize; - DWORD64 Reserved0[2]; - } KDHELP64, *PKDHELP64; - - typedef struct _tagSTACKFRAME64 { - ADDRESS64 AddrPC; // program counter - ADDRESS64 AddrReturn; // return address - ADDRESS64 AddrFrame; // frame pointer - ADDRESS64 AddrStack; // stack pointer - ADDRESS64 AddrBStore; // backing store pointer - VOID *FuncTableEntry; // pointer to pdata/fpo or NULL - DWORD64 Params[4]; // possible arguments to the function - BOOL Far; // WOW far call - BOOL Virtual; // is this a virtual frame? - DWORD64 Reserved[3]; - KDHELP64 KdHelp; - } STACKFRAME64; - - typedef struct _IMAGEHLP_LINEW64 { - DWORD SizeOfStruct; // set to sizeof(IMAGEHLP_LINE64) - VOID *Key; // internal - DWORD LineNumber; // line number in file - WCHAR *FileName; // full filename - DWORD64 Address; // first instruction of line - } IMAGEHLP_LINEW64; - - typedef struct _SYMBOL_INFOW { - ULONG SizeOfStruct; - ULONG TypeIndex; // Type Index of symbol - ULONG64 Reserved[2]; - ULONG Index; - ULONG Size; - ULONG64 ModBase; // Base Address of module comtaining this symbol - ULONG Flags; - ULONG64 Value; // Value of symbol, ValuePresent should be 1 - ULONG64 Address; // Address of symbol including base address of module - ULONG Register; // register holding value or pointer to value - ULONG Scope; // scope of the symbol - ULONG Tag; // pdb classification - ULONG NameLen; // Actual length of name - ULONG MaxNameLen; - WCHAR Name[1]; // Name of symbol - } SYMBOL_INFOW; - - typedef BOOL (__stdcall READ_PROCESS_MEMORY_ROUTINE64)(HANDLE hProcess, DWORD64 qwBaseAddress, VOID *lpBuffer, DWORD nSize, DWORD *lpNumberOfBytesRead); - typedef VOID * (__stdcall FUNCTION_TABLE_ACCESS_ROUTINE64)(HANDLE ahProcess, DWORD64 AddrBase); - typedef DWORD64(__stdcall GET_MODULE_BASE_ROUTINE64)(HANDLE hProcess, DWORD64 Address); - typedef DWORD64(__stdcall TRANSLATE_ADDRESS_ROUTINE64)(HANDLE hProcess, HANDLE hThread, ADDRESS64 *lpaddr); - - extern "C" - { - __declspec(dllimport) BOOL __stdcall StackWalk64 (DWORD MachineType, HANDLE hProcess, HANDLE hThread, STACKFRAME64 *StackFrame, VOID *ContextRecord, READ_PROCESS_MEMORY_ROUTINE64 *ReadMemoryRoutine, FUNCTION_TABLE_ACCESS_ROUTINE64 *FunctionTableAccessRoutine, GET_MODULE_BASE_ROUTINE64 *GetModuleBaseRoutine, TRANSLATE_ADDRESS_ROUTINE64 *TranslateAddress); - __declspec(dllimport) BOOL __stdcall SymFromAddrW (HANDLE hProcess, DWORD64 Address, DWORD64 *Displacement, SYMBOL_INFOW *Symbol); - __declspec(dllimport) VOID * __stdcall SymFunctionTableAccess64(HANDLE hProcess, DWORD64 AddrBase); - __declspec(dllimport) BOOL __stdcall SymGetLineFromAddrW64 (HANDLE hProcess, DWORD64 dwAddr, DWORD *pdwDisplacement, IMAGEHLP_LINEW64 *Line); - __declspec(dllimport) DWORD64 __stdcall SymGetModuleBase64 (HANDLE hProcess, DWORD64 qwAddr); - __declspec(dllimport) BOOL __stdcall SymRefreshModuleList (HANDLE hProcess); - }; - - // NOTE: um/errhandlingapi.h /////////////////////////////////////////////////////////////////// - extern "C" - { - __declspec(dllimport) DWORD __stdcall GetLastError(VOID); - } - - // NOTE: um/libloaderapi.h ///////////////////////////////////////////////////////////////////// - extern "C" - { - __declspec(dllimport) HMODULE __stdcall LoadLibraryA (const CHAR *lpLibFileName); - __declspec(dllimport) BOOL __stdcall FreeLibrary (HMODULE hLibModule); - __declspec(dllimport) void * __stdcall GetProcAddress (HMODULE hModule, const CHAR *lpProcName); - __declspec(dllimport) HMODULE __stdcall GetModuleHandleA (const CHAR *lpModuleName); - __declspec(dllimport) DWORD __stdcall GetModuleFileNameW(HMODULE hModule, WCHAR *lpFilename, DWORD nSize); - } - - // NOTE: um/synchapi.h ///////////////////////////////////////////////////////////////////////// - typedef RTL_CONDITION_VARIABLE CONDITION_VARIABLE, *PCONDITION_VARIABLE; - - extern "C" - { - __declspec(dllimport) VOID __stdcall InitializeConditionVariable (CONDITION_VARIABLE *ConditionVariable); - __declspec(dllimport) VOID __stdcall WakeConditionVariable (CONDITION_VARIABLE *ConditionVariable); - __declspec(dllimport) VOID __stdcall WakeAllConditionVariable (CONDITION_VARIABLE *ConditionVariable); - __declspec(dllimport) BOOL __stdcall SleepConditionVariableCS (CONDITION_VARIABLE *ConditionVariable, CRITICAL_SECTION *CriticalSection, DWORD dwMilliseconds); - - __declspec(dllimport) VOID __stdcall InitializeCriticalSection (CRITICAL_SECTION *lpCriticalSection); - __declspec(dllimport) VOID __stdcall EnterCriticalSection (CRITICAL_SECTION *lpCriticalSection); - __declspec(dllimport) VOID __stdcall LeaveCriticalSection (CRITICAL_SECTION *lpCriticalSection); - __declspec(dllimport) BOOL __stdcall InitializeCriticalSectionAndSpinCount(CRITICAL_SECTION *lpCriticalSection, DWORD dwSpinCount); - __declspec(dllimport) BOOL __stdcall InitializeCriticalSectionEx (CRITICAL_SECTION *lpCriticalSection, DWORD dwSpinCount, DWORD Flags); - __declspec(dllimport) DWORD __stdcall SetCriticalSectionSpinCount (CRITICAL_SECTION *lpCriticalSection, DWORD dwSpinCount); - __declspec(dllimport) BOOL __stdcall TryEnterCriticalSection (CRITICAL_SECTION *lpCriticalSection); - __declspec(dllimport) VOID __stdcall DeleteCriticalSection (CRITICAL_SECTION *lpCriticalSection); - - __declspec(dllimport) DWORD __stdcall WaitForSingleObject (HANDLE hHandle, DWORD dwMilliseconds); - __declspec(dllimport) BOOL __stdcall ReleaseSemaphore (HANDLE hSemaphore, LONG lReleaseCount, LONG *lpPreviousCount); - __declspec(dllimport) VOID __stdcall Sleep (DWORD dwMilliseconds); - } - - // NOTE: um/profileapi.h /////////////////////////////////////////////////////////////////////// - extern "C" - { - __declspec(dllimport) BOOL __stdcall QueryPerformanceCounter (LARGE_INTEGER* lpPerformanceCount); - __declspec(dllimport) BOOL __stdcall QueryPerformanceFrequency(LARGE_INTEGER* lpFrequency); - } - - // NOTE: um/processthreadsapi.h //////////////////////////////////////////////////////////////// - typedef struct _PROCESS_INFORMATION { - HANDLE hProcess; - HANDLE hThread; - DWORD dwProcessId; - DWORD dwThreadId; - } PROCESS_INFORMATION, *PPROCESS_INFORMATION, *LPPROCESS_INFORMATION; - - typedef struct _STARTUPINFOW { - DWORD cb; - WCHAR *lpReserved; - WCHAR *lpDesktop; - WCHAR *lpTitle; - DWORD dwX; - DWORD dwY; - DWORD dwXSize; - DWORD dwYSize; - DWORD dwXCountChars; - DWORD dwYCountChars; - DWORD dwFillAttribute; - DWORD dwFlags; - WORD wShowWindow; - WORD cbReserved2; - BYTE *lpReserved2; - HANDLE hStdInput; - HANDLE hStdOutput; - HANDLE hStdError; - } STARTUPINFOW, *LPSTARTUPINFOW; - - typedef DWORD (__stdcall *PTHREAD_START_ROUTINE)( - VOID *lpThreadParameter - ); - typedef PTHREAD_START_ROUTINE LPTHREAD_START_ROUTINE; - - extern "C" - { - __declspec(dllimport) BOOL __stdcall CreateProcessW (WCHAR const *lpApplicationName, WCHAR *lpCommandLine, SECURITY_ATTRIBUTES *lpProcessAttributes, SECURITY_ATTRIBUTES *lpThreadAttributes, BOOL bInheritHandles, DWORD dwCreationFlags, VOID *lpEnvironment, WCHAR const *lpCurrentDirectory, STARTUPINFOW *lpStartupInfo, PROCESS_INFORMATION *lpProcessInformation); - __declspec(dllimport) HANDLE __stdcall CreateThread (SECURITY_ATTRIBUTES *lpThreadAttributes, SIZE_T dwStackSize, PTHREAD_START_ROUTINE lpStartAddress, VOID *lpParameter, DWORD dwCreationFlags, DWORD *lpThreadId); - __declspec(dllimport) DWORD __stdcall GetCurrentThreadId(VOID); - __declspec(dllimport) BOOL __stdcall GetExitCodeProcess(HANDLE hProcess, DWORD *lpExitCode); - __declspec(dllimport) void __stdcall ExitProcess (UINT uExitCode); - } - - // NOTE: um/memoryapi.h //////////////////////////////////////////////////////////////////////// - extern "C" - { - __declspec(dllimport) VOID * __stdcall VirtualAlloc (VOID *lpAddress, SIZE_T dwSize, DWORD flAllocationType, DWORD flProtect); - __declspec(dllimport) BOOL __stdcall VirtualProtect(VOID *lpAddress, SIZE_T dwSize, DWORD flNewProtect, DWORD *lpflOldProtect); - __declspec(dllimport) BOOL __stdcall VirtualFree (VOID *lpAddress, SIZE_T dwSize, DWORD dwFreeType); - } - - // NOTE: shared/bcrypt.h /////////////////////////////////////////////////////////////////////// - typedef VOID *BCRYPT_ALG_HANDLE; - typedef LONG NTSTATUS; - - extern "C" - { - __declspec(dllimport) NTSTATUS __stdcall BCryptOpenAlgorithmProvider(BCRYPT_ALG_HANDLE *phAlgorithm, const WCHAR *pszAlgId, const WCHAR *pszImplementation, ULONG dwFlags); - __declspec(dllimport) NTSTATUS __stdcall BCryptGenRandom (BCRYPT_ALG_HANDLE hAlgorithm, UCHAR *pbBuffer, ULONG cbBuffer, ULONG dwFlags); - } - - // NOTE: um/shellapi.h ///////////////////////////////////////////////////////////////////////// - extern "C" - { - __declspec(dllimport) HINSTANCE __stdcall ShellExecuteA(HWND hwnd, CHAR const *lpOperation, CHAR const *lpFile, CHAR const *lpParameters, CHAR const *lpDirectory, INT nShowCmd); - __declspec(dllimport) HINSTANCE __stdcall ShellExecuteW(HWND hwnd, WCHAR const *lpOperation, WCHAR const *lpFile, WCHAR const *lpParameters, WCHAR const *lpDirectory, INT nShowCmd); - } - - // NOTE: um/debugapi.h ///////////////////////////////////////////////////////////////////////// - extern "C" - { - __declspec(dllimport) BOOL __stdcall IsDebuggerPresent(); - } - - // NOTE: um/namedpipeapi.h ///////////////////////////////////////////////////////////////////// - extern "C" - { - __declspec(dllimport) BOOL __stdcall CreatePipe (HANDLE *hReadPipe, HANDLE *hWritePipe, LPSECURITY_ATTRIBUTES lpPipeAttributes, DWORD nSize); - __declspec(dllimport) BOOL __stdcall PeekNamedPipe(HANDLE hNamedPipe, VOID *lpBuffer, DWORD nBufferSize, DWORD *lpBytesRead, DWORD *lpTotalBytesAvail, DWORD *lpBytesLeftThisMessage); - } - - // NOTE: um/handleapi.h //////////////////////////////////////////////////////////////////////// - extern "C" - { - __declspec(dllimport) BOOL __stdcall SetHandleInformation(HANDLE hObject, DWORD dwMask, DWORD dwFlags); - } - - // NOTE: um/commdlg.h ////////////////////////////////////////////////////////////////////////// - typedef UINT_PTR (__stdcall *LPOFNHOOKPROC)(HWND, UINT, WPARAM, LPARAM); - typedef struct tagOFNW { - DWORD lStructSize; - HWND hwndOwner; - HINSTANCE hInstance; - WCHAR const * lpstrFilter; - LPWSTR lpstrCustomFilter; - DWORD nMaxCustFilter; - DWORD nFilterIndex; - LPWSTR lpstrFile; - DWORD nMaxFile; - LPWSTR lpstrFileTitle; - DWORD nMaxFileTitle; - WCHAR const * lpstrInitialDir; - WCHAR const * lpstrTitle; - DWORD Flags; - WORD nFileOffset; - WORD nFileExtension; - WCHAR const * lpstrDefExt; - LPARAM lCustData; - LPOFNHOOKPROC lpfnHook; - WCHAR const * lpTemplateName; - #ifdef _MAC - LPEDITMENU lpEditInfo; - LPCSTR lpstrPrompt; - #endif - #if (_WIN32_WINNT >= 0x0500) - void * pvReserved; - DWORD dwReserved; - DWORD FlagsEx; - #endif // (_WIN32_WINNT >= 0x0500) - } OPENFILENAMEW, *LPOPENFILENAMEW; - - - #define OFN_READONLY 0x00000001 - #define OFN_OVERWRITEPROMPT 0x00000002 - #define OFN_HIDEREADONLY 0x00000004 - #define OFN_NOCHANGEDIR 0x00000008 - #define OFN_SHOWHELP 0x00000010 - #define OFN_ENABLEHOOK 0x00000020 - #define OFN_ENABLETEMPLATE 0x00000040 - #define OFN_ENABLETEMPLATEHANDLE 0x00000080 - #define OFN_NOVALIDATE 0x00000100 - #define OFN_ALLOWMULTISELECT 0x00000200 - #define OFN_EXTENSIONDIFFERENT 0x00000400 - #define OFN_PATHMUSTEXIST 0x00000800 - #define OFN_FILEMUSTEXIST 0x00001000 - #define OFN_CREATEPROMPT 0x00002000 - #define OFN_SHAREAWARE 0x00004000 - #define OFN_NOREADONLYRETURN 0x00008000 - #define OFN_NOTESTFILECREATE 0x00010000 - #define OFN_NONETWORKBUTTON 0x00020000 - #define OFN_NOLONGNAMES 0x00040000 // force no long names for 4.x modules - #if(WINVER >= 0x0400) - #define OFN_EXPLORER 0x00080000 // new look commdlg - #define OFN_NODEREFERENCELINKS 0x00100000 - #define OFN_LONGNAMES 0x00200000 // force long names for 3.x modules - // OFN_ENABLEINCLUDENOTIFY and OFN_ENABLESIZING require - // Windows 2000 or higher to have any effect. - #define OFN_ENABLEINCLUDENOTIFY 0x00400000 // send include message to callback - #define OFN_ENABLESIZING 0x00800000 - #endif /* WINVER >= 0x0400 */ - #if (_WIN32_WINNT >= 0x0500) - #define OFN_DONTADDTORECENT 0x02000000 - #define OFN_FORCESHOWHIDDEN 0x10000000 // Show All files including System and hidden files - #endif // (_WIN32_WINNT >= 0x0500) - - //FlagsEx Values - #if (_WIN32_WINNT >= 0x0500) - #define OFN_EX_NOPLACESBAR 0x00000001 - #endif // (_WIN32_WINNT >= 0x0500) - - extern "C" - { - __declspec(dllimport) BOOL __stdcall GetSaveFileNameW(LPOPENFILENAMEW); - __declspec(dllimport) BOOL __stdcall GetOpenFileNameW(LPOPENFILENAMEW); - } - - // NOTE: um/shlwapi.h ////////////////////////////////////////////////////////////////////////// - extern "C" - { - __declspec(dllimport) BOOL __stdcall PathRelativePathToW(WCHAR *pszPath, WCHAR const *pszFrom, DWORD dwAttrFrom, WCHAR const *pszTo, DWORD dwAttrTo); - __declspec(dllimport) BOOL __stdcall PathIsRelativeW(WCHAR *pszPath); - } - - // NOTE: um/pathcch.h ////////////////////////////////////////////////////////////////////////// - typedef enum PATHCCH_OPTIONS - { - PATHCCH_NONE = 0x0, - - // This option allows applications to gain access to long paths. It has two - // different behaviors. For process configured to enable long paths it will allow - // the returned path to be longer than the max path limit that is normally imposed. - // For process that are not this option will convert long paths into the extended - // length DOS device form (with \\?\ prefix) when the path is longer than the limit. - // This form is not length limited by the Win32 file system API on all versions of Windows. - // This second behavior is the same behavior for OSes that don't have the long path feature. - // This can not be specified with PATHCCH_ENSURE_IS_EXTENDED_LENGTH_PATH. - PATHCCH_ALLOW_LONG_PATHS = 0x01, - - // Can only be used when PATHCCH_ALLOW_LONG_PATHS is specified. This - // Forces the API to treat the caller as long path enabled, independent of the - // process's long name enabled state. Cannot be used with PATHCCH_FORCE_DISABLE_LONG_NAME_PROCESS. - PATHCCH_FORCE_ENABLE_LONG_NAME_PROCESS = 0x02, - - // Can only be used when PATHCCH_ALLOW_LONG_PATHS is specified. This - // Forces the API to treat the caller as long path disabled, independent of the - // process's long name enabled state. Cannot be used with PATHCCH_FORCE_ENABLE_LONG_NAME_PROCESS. - PATHCCH_FORCE_DISABLE_LONG_NAME_PROCESS = 0x04, - - // Disable the normalization of path segments that includes removing trailing dots and spaces. - // This enables access to paths that win32 path normalization will block. - PATHCCH_DO_NOT_NORMALIZE_SEGMENTS = 0x08, - - // Convert the input path into the extended length DOS device path form (with the \\?\ prefix) - // if not already in that form. This enables access to paths that are otherwise not addressable - // due to Win32 normalization rules (that can strip trailing dots and spaces) and path - // length limitations. This option implies the same behavior of PATHCCH_DO_NOT_NORMALIZE_SEGMENTS. - // This can not be specified with PATHCCH_ALLOW_LONG_PATHS. - PATHCCH_ENSURE_IS_EXTENDED_LENGTH_PATH = 0x10, - - // When combining or normalizing a path ensure there is a trailing backslash. - PATHCCH_ENSURE_TRAILING_SLASH = 0x020, - - // Convert forward slashes to back slashes and collapse multiple slashes. - // This is needed to to support sub-path or identity comparisons. - PATHCCH_CANONICALIZE_SLASHES = 0x040, - } PATHCCH_OPTIONS; - - extern "C" - { - __declspec(dllimport) HRESULT __stdcall PathCchCanonicalizeEx(PWSTR pszPathOut, size_t cchPathOut, WCHAR const *pszPathIn, ULONG dwFlags); - }; - - // NOTE: um/errhandlingapi.h /////////////////////////////////////////////////////////////////// - extern "C" - { - __declspec(dllimport) VOID __stdcall RaiseException(DWORD dwExceptionCode, DWORD dwExceptionFlags, DWORD nNumberOfArguments, const ULONG_PTR* lpArguments); - }; - - // NOTE: include/excpt.h /////////////////////////////////////////////////////////////////// - #define EXCEPTION_EXECUTE_HANDLER 1 - #define EXCEPTION_CONTINUE_SEARCH 0 - #define EXCEPTION_CONTINUE_EXECUTION (-1) - - DN_MSVC_WARNING_POP -#endif // !defined(_INC_WINDOWS) -#endif // !defined(DN_OS_WINDOWS_H) -#endif - -struct DN_W32Error -{ - unsigned long code; - DN_Str8 msg; -}; - -struct DN_W32FolderIteratorW -{ - void *handle; - DN_Str16 file_name; - wchar_t file_name_buf[512]; -}; - -enum DN_W32SyncPrimitiveType -{ - DN_OSW32SyncPrimitiveType_Semaphore, - DN_OSW32SyncPrimitiveType_Mutex, - DN_OSW32SyncPrimitiveType_ConditionVariable, -}; - -struct DN_W32SyncPrimitive -{ - union - { - void *sem; - CRITICAL_SECTION mutex; - CONDITION_VARIABLE cv; - }; - - DN_W32SyncPrimitive *next; -}; - -typedef HRESULT DN_W32SetThreadDescriptionFunc(HANDLE hThread, PWSTR const lpThreadDescription); -struct DN_W32Core -{ - DN_W32SetThreadDescriptionFunc *set_thread_description; - LARGE_INTEGER qpc_frequency; - void *bcrypt_rng_handle; - bool bcrypt_init_success; - bool sym_initialised; - - CRITICAL_SECTION sync_primitive_free_list_mutex; - DN_W32SyncPrimitive *sync_primitive_free_list; -}; - -DN_API void DN_W32_ThreadSetName (DN_Str8 name); - -DN_API DN_Str16 DN_W32_ErrorCodeToMsg16Alloc(DN_U32 error_code); -DN_API DN_W32Error DN_W32_ErrorCodeToMsg (DN_Arena *arena, DN_U32 error_code); -DN_API DN_W32Error DN_W32_ErrorCodeToMsgAlloc (DN_U32 error_code); -DN_API DN_W32Error DN_W32_LastError (DN_Arena *arena); -DN_API DN_W32Error DN_W32_LastErrorAlloc (); -DN_API void DN_W32_MakeProcessDPIAware (); - -// NOTE: Windows Str8 <-> Str16 //////////////////////////////////////////////////////////////////// -DN_API DN_Str16 DN_W32_Str8ToStr16 (DN_Arena *arena, DN_Str8 src); -DN_API int DN_W32_Str8ToStr16Buffer (DN_Str16 src, char *dest, int dest_size); -DN_API DN_Str8 DN_W32_Str16ToStr8 (DN_Arena *arena, DN_Str16 src); -DN_API int DN_W32_Str16ToStr8Buffer (DN_Str16 src, char *dest, int dest_size); -DN_API DN_Str8 DN_W32_Str16ToStr8FromHeap(DN_Str16 src); - -// NOTE: Path navigation /////////////////////////////////////////////////////////////////////////// -DN_API DN_Str16 DN_W32_EXEPathW (DN_Arena *arena); -DN_API DN_Str16 DN_W32_EXEDirW (DN_Arena *arena); -DN_API DN_Str8 DN_W32_WorkingDir (DN_Arena *arena, DN_Str8 suffix); -DN_API DN_Str16 DN_W32_WorkingDirW (DN_Arena *arena, DN_Str16 suffix); -DN_API bool DN_W32_DirWIterate (DN_Str16 path, DN_W32FolderIteratorW *it); -#endif // !defined(DN_OS_WIN32) -#elif defined(DN_PLATFORM_POSIX) || defined(DN_PLATFORM_EMSCRIPTEN) - // DN: Single header generator commented out this header => #include "OS/dn_os_posix.h" -#if !defined(DN_OS_POSIX_H) -#define DN_OS_POSIX_H - -#if defined(_CLANGD) - // DN: Single header generator commented out this header => #include "../dn_base_inc.h" -#endif - -#include -#include - -/* -//////////////////////////////////////////////////////////////////////////////////////////////////// -// -// $$$$$$\ $$$$$$\ $$$$$$$\ $$$$$$\ $$$$$$\ $$$$$$\ $$\ $$\ -// $$ __$$\ $$ __$$\ $$ __$$\ $$ __$$\ $$ __$$\ \_$$ _|$$ | $$ | -// $$ / $$ |$$ / \__| $$ | $$ |$$ / $$ |$$ / \__| $$ | \$$\ $$ | -// $$ | $$ |\$$$$$$\ $$$$$$$ |$$ | $$ |\$$$$$$\ $$ | \$$$$ / -// $$ | $$ | \____$$\ $$ ____/ $$ | $$ | \____$$\ $$ | $$ $$< -// $$ | $$ |$$\ $$ | $$ | $$ | $$ |$$\ $$ | $$ | $$ /\$$\ -// $$$$$$ |\$$$$$$ | $$ | $$$$$$ |\$$$$$$ |$$$$$$\ $$ / $$ | -// \______/ \______/ \__| \______/ \______/ \______|\__| \__| -// -// dn_os_posix.h -// -//////////////////////////////////////////////////////////////////////////////////////////////////// -*/ - -struct DN_POSIXProcSelfStatus -{ - char name[64]; - DN_U8 name_size; - DN_U32 pid; - DN_U64 vm_peak; - DN_U32 vm_size; -}; - -// NOTE: The POSIX implementation disallows copies of synchronisation objects in -// general hence we have to dynamically allocate these primitives to maintain a -// consistent address. -// -// -// Source: The Open Group Base Specifications Issue 7, 2018 edition -// https://pubs.opengroup.org/onlinepubs/9699919799/functions/V2_chap02.html#tag_15_09_09 -// -// 2.9.9 Synchronization Object Copies and Alternative Mappings -// -// For barriers, condition variables, mutexes, and read-write locks, [TSH] -// [Option Start] if the process-shared attribute is set to -// PTHREAD_PROCESS_PRIVATE, [Option End] only the synchronization object at the -// address used to initialize it can be used for performing synchronization. The -// effect of referring to another mapping of the same object when locking, -// unlocking, or destroying the object is undefined. [...] The effect of -// referring to a copy of the object when locking, unlocking, or destroying it -// is undefined. - -enum DN_POSIXSyncPrimitiveType -{ - DN_OSPOSIXSyncPrimitiveType_Semaphore, - DN_OSPOSIXSyncPrimitiveType_Mutex, - DN_OSPOSIXSyncPrimitiveType_ConditionVariable, -}; - -struct DN_POSIXSyncPrimitive -{ - union - { - sem_t sem; - pthread_mutex_t mutex; - pthread_cond_t cv; - }; - DN_POSIXSyncPrimitive *next; -}; - -struct DN_POSIXCore -{ - DN_POSIXSyncPrimitive *sync_primitive_free_list; - pthread_mutex_t sync_primitive_free_list_mutex; - bool clock_monotonic_raw; -}; - -DN_API void DN_Posix_Init(DN_POSIXCore *posix); -DN_API void DN_Posix_ThreadSetName(DN_Str8 name); -DN_API DN_POSIXProcSelfStatus DN_Posix_ProcSelfStatus(); -#endif // !defined(DN_OS_POSIX_H) -#else - #error Please define a platform e.g. 'DN_PLATFORM_WIN32' to enable the correct implementation for platform APIs -#endif - -// DN: Single header generator commented out this header => #include "OS/dn_os_tls.h" -#if !defined(DN_OS_TLS_H) -#define DN_OS_TLS_H - -#if defined(_CLANGD) - // DN: Single header generator commented out this header => #include "../dn_base_inc.h" - // DN: Single header generator commented out this header => #include "../dn_os_inc.h" -#endif - -// NOTE: DN_OSErrSink -enum DN_OSErrSinkMode -{ - DN_OSErrSinkMode_Nil, // Default behaviour to accumulate errors into the sink - DN_OSErrSinkMode_DebugBreakOnEndAndLog, // Debug break (int3) when error is encountered and the sink is ended by the 'end and log' functions. - DN_OSErrSinkMode_ExitOnError, // When an error is encountered, exit the program with the error code of the error that was caught. -}; - -struct DN_OSErrSinkMsg -{ - DN_I32 error_code; - DN_Str8 msg; - DN_CallSite call_site; - DN_OSErrSinkMsg *next; - DN_OSErrSinkMsg *prev; -}; - -struct DN_OSErrSinkNode -{ - DN_CallSite call_site; // Call site that the node was created - DN_OSErrSinkMode mode; // Controls how the sink behaves when an error is registered onto the sink. - DN_OSErrSinkMsg *msg_sentinel; // List of error messages accumulated for the current scope - DN_U64 arena_pos; // Position to reset the arena when the scope is ended -}; - -struct DN_OSErrSink -{ - DN_Arena * arena; // Dedicated allocator from the thread's local storage - DN_OSErrSinkNode stack[128]; // Each entry contains errors accumulated between a [begin, end] region of the active sink. - DN_USize stack_size; -}; - -enum DN_OSTLSArena -{ - DN_OSTLSArena_Main, // NOTE: Arena for permanent allocations - DN_OSTLSArena_ErrorSink, // NOTE: Arena for logging error information for this thread - - // NOTE: Per-thread scratch arenas (2 to prevent aliasing) - DN_OSTLSArena_TMem0, - DN_OSTLSArena_TMem1, - - DN_OSTLSArena_Count, -}; - -struct DN_OSTLS -{ - DN_B32 init; // Flag to track if TLS has been initialised - DN_U64 thread_id; - DN_CallSite call_site; // Stores call-site information when requested by thread - DN_OSErrSink err_sink; // Error handling state - DN_Arena arenas[DN_OSTLSArena_Count]; // Default arenas that the thread has access to implicitly - DN_Arena * arena_stack[8]; // Active stack of arenas push/popped arenas on into the TLS - DN_USize arena_stack_index; - - DN_Arena * frame_arena; - char name[64]; - DN_U8 name_size; -}; - -// Push the temporary memory arena when retrieved, popped when the arena goes -// out of scope. Pushed arenas are used automatically as the allocator in TLS -// suffixed function. -enum DN_OSTLSPushTMem -{ - DN_OSTLSPushTMem_No, - DN_OSTLSPushTMem_Yes, -}; - -struct DN_OSTLSTMem -{ - DN_OSTLSTMem(DN_OSTLS *context, uint8_t context_index, DN_OSTLSPushTMem push_scratch); - ~DN_OSTLSTMem(); - DN_Arena *arena; - DN_B32 destructed; - DN_OSTLSPushTMem push_arena; - DN_ArenaTempMem temp_mem; -}; - -struct DN_OSTLSInitArgs -{ - DN_U64 reserve; - DN_U64 commit; - DN_U64 err_sink_reserve; - DN_U64 err_sink_commit; -}; - -DN_API void DN_OS_TLSInit (DN_OSTLS *tls, DN_OSTLSInitArgs args); -DN_API void DN_OS_TLSDeinit (DN_OSTLS *tls); -DN_API DN_OSTLS * DN_OS_TLSGet (); -DN_API void DN_OS_TLSSetCurrentThreadTLS (DN_OSTLS *tls); -DN_API DN_Arena * DN_OS_TLSArena (); -DN_API DN_OSTLSTMem DN_OS_TLSGetTMem (void const *conflict_arena, DN_OSTLSPushTMem push_tmp_mem); -DN_API void DN_OS_TLSPushArena (DN_Arena *arena); -DN_API void DN_OS_TLSPopArena (); -DN_API DN_Arena * DN_OS_TLSTopArena (); -DN_API void DN_OS_TLSBeginFrame (DN_Arena *frame_arena); -DN_API DN_Arena * DN_OS_TLSFrameArena (); -#define DN_OS_TLSSaveCallSite do { DN_OS_TLSGet()->call_site = DN_CALL_SITE; } while (0) -#define DN_OS_TLSTMem(...) DN_OS_TLSGetTMem(__VA_ARGS__, DN_OSTLSPushTMem_No) -#define DN_OS_TLSPushTMem(...) DN_OS_TLSGetTMem(__VA_ARGS__, DN_OSTLSPushTMem_Yes) - -DN_API DN_OSErrSink * DN_OS_ErrSinkBegin_ (DN_OSErrSinkMode mode, DN_CallSite call_site); -#define DN_OS_ErrSinkBegin(mode) DN_OS_ErrSinkBegin_(mode, DN_CALL_SITE) -#define DN_OS_ErrSinkBeginDefault() DN_OS_ErrSinkBegin(DN_OSErrSinkMode_Nil) -DN_API bool DN_OS_ErrSinkHasError (DN_OSErrSink *err); -DN_API DN_OSErrSinkMsg * DN_OS_ErrSinkEnd (DN_Arena *arena, DN_OSErrSink *err); -DN_API DN_Str8 DN_OS_ErrSinkEndStr8 (DN_Arena *arena, DN_OSErrSink *err); -DN_API void DN_OS_ErrSinkEndAndIgnore (DN_OSErrSink *err); -DN_API bool DN_OS_ErrSinkEndAndLogError_ (DN_OSErrSink *err, DN_CallSite call_site, DN_Str8 msg); -DN_API bool DN_OS_ErrSinkEndAndLogErrorFV_ (DN_OSErrSink *err, DN_CallSite call_site, DN_FMT_ATTRIB char const *fmt, va_list args); -DN_API bool DN_OS_ErrSinkEndAndLogErrorF_ (DN_OSErrSink *err, DN_CallSite call_site, DN_FMT_ATTRIB char const *fmt, ...); -DN_API void DN_OS_ErrSinkEndAndExitIfErrorF_ (DN_OSErrSink *err, DN_CallSite call_site, DN_U32 exit_val, DN_FMT_ATTRIB char const *fmt, ...); -DN_API void DN_OS_ErrSinkEndAndExitIfErrorFV_ (DN_OSErrSink *err, DN_CallSite call_site, DN_U32 exit_val, DN_FMT_ATTRIB char const *fmt, va_list args); -DN_API void DN_OS_ErrSinkAppendFV_ (DN_OSErrSink *err, DN_U32 error_code, DN_FMT_ATTRIB char const *fmt, va_list args); -DN_API void DN_OS_ErrSinkAppendF_ (DN_OSErrSink *err, DN_U32 error_code, DN_FMT_ATTRIB char const *fmt, ...); -#define DN_OS_ErrSinkEndAndLogError(err, err_msg) DN_OS_ErrSinkEndAndLogError_(err, DN_CALL_SITE, err_msg) -#define DN_OS_ErrSinkEndAndLogErrorFV(err, fmt, args) DN_OS_ErrSinkEndAndLogErrorFV_(err, DN_CALL_SITE, fmt, args) -#define DN_OS_ErrSinkEndAndLogErrorF(err, fmt, ...) DN_OS_ErrSinkEndAndLogErrorF_(err, DN_CALL_SITE, fmt, ##__VA_ARGS__) -#define DN_OS_ErrSinkEndAndExitIfErrorFV(err, exit_val, fmt, args) DN_OS_ErrSinkEndAndExitIfErrorFV_(err, DN_CALL_SITE, exit_val, fmt, args) -#define DN_OS_ErrSinkEndAndExitIfErrorF(err, exit_val, fmt, ...) DN_OS_ErrSinkEndAndExitIfErrorF_(err, DN_CALL_SITE, exit_val, fmt, ##__VA_ARGS__) - -#define DN_OS_ErrSinkAppendFV(error, error_code, fmt, args) \ - do { \ - DN_OS_TLSSaveCallSite; \ - DN_OS_ErrSinkAppendFV_(error, error_code, fmt, args); \ - } while (0) - -#define DN_OS_ErrSinkAppendF(error, error_code, fmt, ...) \ - do { \ - DN_OS_TLSSaveCallSite; \ - DN_OS_ErrSinkAppendF_(error, error_code, fmt, ##__VA_ARGS__); \ - } while (0) - -#endif // defined(DN_OS_TLS_H) -// DN: Single header generator commented out this header => #include "OS/dn_os.h" -#if !defined(DN_OS_H) -#define DN_OS_H - -#if defined(_CLANGD) - // DN: Single header generator commented out this header => #include "../dn_base_inc.h" - // DN: Single header generator commented out this header => #include "../dn_os_inc.h" -#endif - -#include // operator new - -#if !defined(DN_OS_WIN32) || defined(DN_OS_WIN32_USE_PTHREADS) - #include - #include -#endif - -#if defined(DN_PLATFORM_POSIX) || defined(DN_PLATFORM_EMSCRIPTEN) - #include // errno - #include // O_RDONLY ... etc - #include // ioctl - #include // mmap - #include // getrandom - #include // stat - #include // pid_t - #include // waitpid - #include // clock_gettime, nanosleep - #include // access, gettid, write - - #if !defined(DN_PLATFORM_EMSCRIPTEN) - #include // FICLONE - #include // sendfile - #endif -#endif - -#if defined(DN_PLATFORM_EMSCRIPTEN) - #include // emscripten_fetch (for DN_OSHttpResponse) -#endif - -extern DN_CPUFeatureDecl g_dn_cpu_feature_decl[DN_CPUFeature_Count]; - -struct DN_OSTimer /// Record time between two time-points using the OS's performance counter. -{ - DN_U64 start; - DN_U64 end; -}; - -// NOTE: DN_OSFile -enum DN_OSPathInfoType -{ - DN_OSPathInfoType_Unknown, - DN_OSPathInfoType_Directory, - DN_OSPathInfoType_File, -}; - -struct DN_OSPathInfo -{ - bool exists; - DN_OSPathInfoType type; - DN_U64 create_time_in_s; - DN_U64 last_write_time_in_s; - DN_U64 last_access_time_in_s; - DN_U64 size; -}; - -struct DN_OSDirIterator -{ - void *handle; - DN_Str8 file_name; - char buffer[512]; -}; - -// NOTE: R/W Stream API -struct DN_OSFileRead -{ - bool success; - DN_USize bytes_read; -}; - -struct DN_OSFile -{ - bool error; - void *handle; -}; - -enum DN_OSFileOpen -{ - DN_OSFileOpen_CreateAlways, // Create file if it does not exist, otherwise, zero out the file and open - DN_OSFileOpen_OpenIfExist, // Open file at path only if it exists - DN_OSFileOpen_OpenAlways, // Open file at path, create file if it does not exist -}; - -typedef DN_U32 DN_OSFileAccess; - -enum DN_OSFileAccess_ -{ - DN_OSFileAccess_Read = 1 << 0, - DN_OSFileAccess_Write = 1 << 1, - DN_OSFileAccess_Execute = 1 << 2, - DN_OSFileAccess_AppendOnly = 1 << 3, // This flag cannot be combined with any other access mode - DN_OSFileAccess_ReadWrite = DN_OSFileAccess_Read | DN_OSFileAccess_Write, - DN_OSFileAccess_All = DN_OSFileAccess_ReadWrite | DN_OSFileAccess_Execute | DN_OSFileAccess_AppendOnly, -}; - -// NOTE: DN_OSPath -#if !defined(DN_OSPathSeperator) - #if defined(DN_OS_WIN32) - #define DN_OSPathSeperator "\\" - #else - #define DN_OSPathSeperator "/" - #endif - #define DN_OSPathSeperatorString DN_Str8Lit(DN_OSPathSeperator) -#endif - -struct DN_OSPathLink -{ - DN_Str8 string; - DN_OSPathLink *next; - DN_OSPathLink *prev; -}; - -struct DN_OSPath -{ - bool has_prefix_path_separator; - DN_OSPathLink *head; - DN_OSPathLink *tail; - DN_USize string_size; - DN_U16 links_size; -}; - -// NOTE: DN_OSExec -typedef DN_U32 DN_OSExecFlags; - -enum DN_OSExecFlags_ -{ - DN_OSExecFlags_Nil = 0, - DN_OSExecFlags_SaveStdout = 1 << 0, - DN_OSExecFlags_SaveStderr = 1 << 1, - DN_OSExecFlags_SaveOutput = DN_OSExecFlags_SaveStdout | DN_OSExecFlags_SaveStderr, - DN_OSExecFlags_MergeStderrToStdout = 1 << 2 | DN_OSExecFlags_SaveOutput, -}; - -struct DN_OSExecAsyncHandle -{ - DN_OSExecFlags exec_flags; - DN_U32 os_error_code; - DN_U32 exit_code; - void *process; - void *stdout_read; - void *stdout_write; - void *stderr_read; - void *stderr_write; -}; - -struct DN_OSExecResult -{ - bool finished; - DN_Str8 stdout_text; - DN_Str8 stderr_text; - DN_U32 os_error_code; - DN_U32 exit_code; -}; - -struct DN_OSExecArgs -{ - DN_OSExecFlags flags; - DN_Str8 working_dir; - DN_Slice environment; -}; - -// NOTE: DN_OSSemaphore -DN_U32 const DN_OS_SEMAPHORE_INFINITE_TIMEOUT = UINT32_MAX; - -struct DN_OSSemaphore -{ - DN_U64 handle; -}; - -enum DN_OSSemaphoreWaitResult -{ - DN_OSSemaphoreWaitResult_Failed, - DN_OSSemaphoreWaitResult_Success, - DN_OSSemaphoreWaitResult_Timeout, -}; - -struct DN_OSMutex -{ - DN_U64 handle; -}; - -struct DN_OSConditionVariable -{ - DN_U64 handle; -}; - -// NOTE: DN_OSThread -typedef DN_I32(DN_OSThreadFunc)(struct DN_OSThread *); - -struct DN_OSThread -{ - DN_Str8x64 name; - DN_OSTLS tls; - DN_OSTLSInitArgs tls_init_args; - void *handle; - DN_U64 thread_id; - void *user_context; - DN_OSThreadFunc *func; - DN_OSSemaphore init_semaphore; -}; - -// NOTE: DN_OSHttp -enum DN_OSHttpRequestSecure -{ - DN_OSHttpRequestSecure_No, - DN_OSHttpRequestSecure_Yes, -}; - -struct DN_OSHttpResponse -{ - // NOTE: Response data - DN_U32 error_code; - DN_Str8 error_msg; - DN_U16 http_status; - DN_Str8 body; - DN_B32 done; - - // NOTE: Book-keeping - DN_Arena *arena; // Allocates memory for the response - - // NOTE: Async book-keeping - // Synchronous HTTP response uses the TLS scratch arena whereas async - // calls use their own dedicated arena. - DN_Arena tmp_arena; - DN_Arena *tmem_arena; - DN_Str8Builder builder; - DN_OSSemaphore on_complete_semaphore; - - #if defined(DN_PLATFORM_EMSCRIPTEN) - emscripten_fetch_t *em_handle; - #elif defined(DN_PLATFORM_WIN32) - HINTERNET w32_request_session; - HINTERNET w32_request_connection; - HINTERNET w32_request_handle; - #endif -}; - -struct DN_OSCore -{ - DN_CPUReport cpu_report; - DN_OSTLS tls; // Thread local storage state for the main thread. - - // NOTE: Logging - DN_LOGEmitFromTypeFVFunc * log_callback; // Set this pointer to override the logging routine - void * log_user_data; // User pointer passed into 'log_callback' - bool log_to_file; // Output logs to file as well as standard out - DN_OSFile log_file; // TODO(dn): Hmmm, how should we do this... ? - DN_TicketMutex log_file_mutex; // Is locked when instantiating the log_file for the first time - bool log_no_colour; // Disable colours in the logging output - - // NOTE: OS - DN_U32 logical_processor_count; - DN_U32 page_size; - DN_U32 alloc_granularity; - - // NOTE: Memory - // Total OS mem allocs in lifetime of program (e.g. malloc, VirtualAlloc, HeapAlloc ...). This - // only includes allocations routed through the library such as the growing nature of arenas or - // using the memory allocation routines in the library like DN_OS_MemCommit and so forth. - DN_U64 vmem_allocs_total; - DN_U64 vmem_allocs_frame; // Total OS virtual memory allocs since the last 'DN_Core_FrameBegin' was invoked - DN_U64 mem_allocs_total; - DN_U64 mem_allocs_frame; // Total OS heap allocs since the last 'DN_Core_FrameBegin' was invoked - - DN_Arena arena; - void *platform_context; -}; - -struct DN_OSDiskSpace -{ - bool success; - DN_U64 avail; - DN_U64 size; -}; - -DN_API void DN_OS_EmitLogsWithOSPrintFunctions (DN_OSCore *os); -DN_API void DN_OS_DumpThreadContextArenaStat (DN_Str8 file_path); - -DN_API DN_Str8 DN_OS_BytesFromHexPtrArenaFrame (void const *hex, DN_USize hex_count); -DN_API DN_Str8 DN_OS_BytesFromHexStr8ArenaFrame (DN_Str8 hex); -DN_API DN_Str8 DN_OS_HexFromBytesPtrArenaFrame (void const *bytes, DN_USize bytes_count); -DN_API DN_Str8 DN_OS_HexFromBytesPtrArenaTLS (void const *bytes, DN_USize bytes_count); - -DN_API void * DN_OS_MemReserve (DN_USize size, DN_MemCommit commit, DN_MemPage page_flags); -DN_API bool DN_OS_MemCommit (void *ptr, DN_USize size, DN_U32 page_flags); -DN_API void DN_OS_MemDecommit (void *ptr, DN_USize size); -DN_API void DN_OS_MemRelease (void *ptr, DN_USize size); -DN_API int DN_OS_MemProtect (void *ptr, DN_USize size, DN_U32 page_flags); - -DN_API void * DN_OS_MemAlloc (DN_USize size, DN_ZMem z_mem); -DN_API void DN_OS_MemDealloc (void *ptr); - -DN_API DN_Date DN_OS_DateLocalTimeNow (); -DN_API DN_Str8x32 DN_OS_DateLocalTimeStr8Now (char date_separator = '-', char hms_separator = ':'); -DN_API DN_Str8x32 DN_OS_DateLocalTimeStr8 (DN_Date time, char date_separator = '-', char hms_separator = ':'); -DN_API DN_U64 DN_OS_DateUnixTimeNs (); -#define DN_OS_DateUnixTimeUs() (DN_OS_DateUnixTimeNs() / 1000) -#define DN_OS_DateUnixTimeMs() (DN_OS_DateUnixTimeNs() / (1000 * 1000)) -#define DN_OS_DateUnixTimeS() (DN_OS_DateUnixTimeNs() / (1000 * 1000 * 1000)) -DN_API DN_U64 DN_OS_DateUnixTimeSFromLocalDate (DN_Date date); -DN_API DN_U64 DN_OS_DateLocalUnixTimeSFromUnixTimeS (DN_U64 unix_ts_s); - -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_Str8 DN_OS_EXEPath (DN_Arena *arena); -DN_API DN_Str8 DN_OS_EXEDir (DN_Arena *arena); -#define DN_OS_EXEDirFromTLS() DN_OS_EXEDir(DN_OS_TLSTopArena()) -DN_API void DN_OS_SleepMs (DN_UInt milliseconds); - -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_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 bool DN_OS_FileCopy (DN_Str8 src, DN_Str8 dest, bool overwrite, DN_OSErrSink *err); -DN_API bool DN_OS_FileMove (DN_Str8 src, DN_Str8 dest, bool overwrite, DN_OSErrSink *err); - -DN_API DN_OSFile DN_OS_FileOpen (DN_Str8 path, DN_OSFileOpen open_mode, DN_OSFileAccess access, DN_OSErrSink *err); -DN_API DN_OSFileRead DN_OS_FileRead (DN_OSFile *file, void *buffer, DN_USize size, DN_OSErrSink *err); -DN_API bool DN_OS_FileWritePtr (DN_OSFile *file, void const *data, DN_USize size, DN_OSErrSink *err); -DN_API bool DN_OS_FileWrite (DN_OSFile *file, DN_Str8 buffer, DN_OSErrSink *err); -DN_API bool DN_OS_FileWriteFV (DN_OSFile *file, DN_OSErrSink *err, DN_FMT_ATTRIB char const *fmt, va_list args); -DN_API bool DN_OS_FileWriteF (DN_OSFile *file, DN_OSErrSink *err, DN_FMT_ATTRIB char const *fmt, ...); -DN_API bool DN_OS_FileFlush (DN_OSFile *file, DN_OSErrSink *err); -DN_API void DN_OS_FileClose (DN_OSFile *file); - -DN_API DN_Str8 DN_OS_FileReadAll (DN_Allocator alloc_type, void *allocator, DN_Str8 path, DN_OSErrSink *err); -DN_API DN_Str8 DN_OS_FileReadAllArena (DN_Arena *arena, DN_Str8 path, DN_OSErrSink *err); -DN_API DN_Str8 DN_OS_FileReadAllPool (DN_Pool *pool, DN_Str8 path, DN_OSErrSink *err); -DN_API DN_Str8 DN_OS_FileReadAllTLS (DN_Str8 path, DN_OSErrSink *err); -DN_API bool DN_OS_FileWriteAll (DN_Str8 path, DN_Str8 buffer, DN_OSErrSink *err); -DN_API bool DN_OS_FileWriteAllFV (DN_Str8 path, DN_OSErrSink *err, DN_FMT_ATTRIB char const *fmt, va_list args); -DN_API bool DN_OS_FileWriteAllF (DN_Str8 path, DN_OSErrSink *err, DN_FMT_ATTRIB char const *fmt, ...); -DN_API bool DN_OS_FileWriteAllSafe (DN_Str8 path, DN_Str8 buffer, DN_OSErrSink *err); -DN_API bool DN_OS_FileWriteAllSafeFV (DN_Str8 path, DN_OSErrSink *err, DN_FMT_ATTRIB char const *fmt, va_list args); -DN_API bool DN_OS_FileWriteAllSafeF (DN_Str8 path, DN_OSErrSink *err, DN_FMT_ATTRIB char const *fmt, ...); - -DN_API DN_OSPathInfo DN_OS_PathInfo (DN_Str8 path); -DN_API bool DN_OS_PathIsOlderThan (DN_Str8 file, DN_Str8 check_against); -DN_API bool DN_OS_PathDelete (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_PathMakeDir (DN_Str8 path); -DN_API bool DN_OS_PathIterateDir (DN_Str8 path, DN_OSDirIterator *it); - -DN_API bool DN_OS_PathAddRef (DN_Arena *arena, DN_OSPath *fs_path, DN_Str8 path); -DN_API bool DN_OS_PathAddRefTLS (DN_OSPath *fs_path, DN_Str8 path); -DN_API bool DN_OS_PathAddRefFrame (DN_OSPath *fs_path, DN_Str8 path); -DN_API bool DN_OS_PathAdd (DN_Arena *arena, DN_OSPath *fs_path, DN_Str8 path); -#define DN_OS_PathAddFromTLS(...) DN_OS_PathAdd(DN_OS_TLSTopArena(), ##__VA_ARGS__) -#define DN_OS_PathAddFromFrame(...) DN_OS_PathAdd(DN_OS_TLSFrameArena(), ##__VA_ARGS__) -DN_API bool DN_OS_PathAddF (DN_Arena *arena, DN_OSPath *fs_path, DN_FMT_ATTRIB char const *fmt, ...); -#define DN_OS_PathAddFFromTLS(...) DN_OS_PathAddF(DN_OS_TLSTopArena(), ##__VA_ARGS__) -#define DN_OS_PathAddFFromFrame(...) DN_OS_PathAddF(DN_OS_TLSFrameArena(), ##__VA_ARGS__) -DN_API bool DN_OS_PathPop (DN_OSPath *fs_path); -DN_API DN_Str8 DN_OS_PathBuildWithSeparator (DN_Arena *arena, DN_OSPath const *fs_path, DN_Str8 path_separator); -#define DN_OS_PathBuildWithSeperatorFromTLS(...) DN_OS_PathBuildWithSeperator(DN_OS_TLSTopArena(), ##__VA_ARGS__) -#define DN_OS_PathBuildWithSeperatorFromFrame(...) DN_OS_PathBuildWithSeperator(DN_OS_TLSFrameArena(), ##__VA_ARGS__) -DN_API DN_Str8 DN_OS_PathTo (DN_Arena *arena, DN_Str8 path, DN_Str8 path_separtor); -#define DN_OS_PathToFromTLS(...) DN_OS_PathTo(DN_OS_TLSTopArena(), ##__VA_ARGS__) -#define DN_OS_PathToFromFrame(...) DN_OS_PathTo(DN_OS_TLSFrameArena(), ##__VA_ARGS__) -DN_API DN_Str8 DN_OS_PathToF (DN_Arena *arena, DN_Str8 path_separator, DN_FMT_ATTRIB char const *fmt, ...); -#define DN_OS_PathToFFromTLS(...) DN_OS_PathToF(DN_OS_TLSTopArena(), ##__VA_ARGS__) -#define DN_OS_PathToFFromFrame(...) DN_OS_PathToF(DN_OS_TLSFrameArena(), ##__VA_ARGS__) -DN_API DN_Str8 DN_OS_Path (DN_Arena *arena, DN_Str8 path); -#define DN_OS_PathFromTLS(...) DN_OS_Path(DN_OS_TLSTopArena(), ##__VA_ARGS__) -#define DN_OS_PathFromFrame(...) DN_OS_Path(DN_OS_TLSFrameArena(), ##__VA_ARGS__) -DN_API DN_Str8 DN_OS_PathF (DN_Arena *arena, DN_FMT_ATTRIB char const *fmt, ...); -#define DN_OS_PathFFromTLS(...) DN_OS_PathF(DN_OS_TLSTopArena(), ##__VA_ARGS__) -#define DN_OS_PathFFromFrame(...) DN_OS_PathF(DN_OS_TLSFrameArena(), ##__VA_ARGS__) - -#define DN_OS_PathBuildFwdSlash(allocator, fs_path) DN_OS_PathBuildWithSeparator(allocator, fs_path, DN_Str8Lit("/")) -#define DN_OS_PathBuildBackSlash(allocator, fs_path) DN_OS_PathBuildWithSeparator(allocator, fs_path, DN_Str8Lit("\\")) -#define DN_OS_PathBuild(allocator, fs_path) DN_OS_PathBuildWithSeparator(allocator, fs_path, DN_OSPathSeparatorString) - -DN_API void DN_OS_Exit (int32_t exit_code); -DN_API DN_OSExecResult DN_OS_ExecPump (DN_OSExecAsyncHandle handle, char *stdout_buffer, size_t *stdout_size, char *stderr_buffer, size_t *stderr_size, DN_U32 timeout_ms, DN_OSErrSink *err); -DN_API DN_OSExecResult DN_OS_ExecWait (DN_OSExecAsyncHandle handle, DN_Arena *arena, DN_OSErrSink *err); -DN_API DN_OSExecAsyncHandle DN_OS_ExecAsync (DN_Slice cmd_line, DN_OSExecArgs *args, DN_OSErrSink *err); -DN_API DN_OSExecResult DN_OS_Exec (DN_Slice cmd_line, DN_OSExecArgs *args, DN_Arena *arena, DN_OSErrSink *err); -DN_API DN_OSExecResult DN_OS_ExecOrAbort (DN_Slice cmd_line, DN_OSExecArgs *args, DN_Arena *arena); -#define DN_OS_ExecOrAbortFromTLS (...) DN_OS_ExecOrAbort(__VA_ARGS__, DN_OS_TLSTopArena()) - -DN_API DN_OSSemaphore DN_OS_SemaphoreInit (DN_U32 initial_count); -DN_API bool DN_OS_SemaphoreIsValid (DN_OSSemaphore *semaphore); -DN_API void DN_OS_SemaphoreDeinit (DN_OSSemaphore *semaphore); -DN_API void DN_OS_SemaphoreIncrement (DN_OSSemaphore *semaphore, DN_U32 amount); -DN_API DN_OSSemaphoreWaitResult DN_OS_SemaphoreWait (DN_OSSemaphore *semaphore, DN_U32 timeout_ms); - -DN_API DN_OSMutex DN_OS_MutexInit (); -DN_API void DN_OS_MutexDeinit (DN_OSMutex *mutex); -DN_API void DN_OS_MutexLock (DN_OSMutex *mutex); -DN_API void DN_OS_MutexUnlock (DN_OSMutex *mutex); -#define DN_OS_MutexScope(mutex) DN_DeferLoop(DN_OS_MutexLock(mutex), DN_OS_MutexUnlock(mutex)) - -DN_API DN_OSConditionVariable DN_OS_ConditionVariableInit (); -DN_API void DN_OS_ConditionVariableDeinit (DN_OSConditionVariable *cv); -DN_API bool DN_OS_ConditionVariableWait (DN_OSConditionVariable *cv, DN_OSMutex *mutex, DN_U64 sleep_ms); -DN_API bool DN_OS_ConditionVariableWaitUntil (DN_OSConditionVariable *cv, DN_OSMutex *mutex, DN_U64 end_ts_ms); -DN_API void DN_OS_ConditionVariableSignal (DN_OSConditionVariable *cv); -DN_API void DN_OS_ConditionVariableBroadcast (DN_OSConditionVariable *cv); - -DN_API bool DN_OS_ThreadInit (DN_OSThread *thread, DN_OSThreadFunc *func, void *user_context); -DN_API void DN_OS_ThreadDeinit (DN_OSThread *thread); -DN_API DN_U32 DN_OS_ThreadID (); -DN_API void DN_OS_ThreadSetName (DN_Str8 name); - -DN_API void DN_OS_HttpRequestAsync (DN_OSHttpResponse *response, DN_Arena *arena, DN_Str8 host, DN_Str8 path, DN_OSHttpRequestSecure secure, DN_Str8 method, DN_Str8 body, DN_Str8 headers); -DN_API void DN_OS_HttpRequestWait (DN_OSHttpResponse *response); -DN_API void DN_OS_HttpRequestFree (DN_OSHttpResponse *response); -DN_API DN_OSHttpResponse DN_OS_HttpRequest (DN_Arena *arena, DN_Str8 host, DN_Str8 path, DN_OSHttpRequestSecure secure, DN_Str8 method, DN_Str8 body, DN_Str8 headers); -#endif // !defined(DN_OS_H) -// DN: Single header generator commented out this header => #include "OS/dn_os_allocator.h" -#if !defined(DN_OS_ALLOCATOR_H) -#define DN_OS_ALLOCATOR_H - -#if defined(_CLANGD) - // DN: Single header generator commented out this header => #include "../dn_base_inc.h" -#endif - -DN_API DN_Arena DN_ArenaFromHeap(DN_U64 size, DN_ArenaFlags flags); -DN_API DN_Arena DN_ArenaFromVMem(DN_U64 reserve, DN_U64 commit, DN_ArenaFlags flags); - -#endif // !defined(DN_OS_ALLOCATOR_H) -// DN: Single header generator commented out this header => #include "OS/dn_os_containers.h" -#if !defined(DN_OS_CONTAINERS_H) -#define DN_OS_CONTAINERS_H - -#if defined(_CLANGD) - // DN: Single header generator commented out this header => #include "../dn_base_inc.h" -#endif - -// NOTE: DN_VArray -// TODO(doyle): Add an API for shrinking the array by decomitting pages back to the OS. -template struct DN_VArray -{ - T *data; // Pointer to the start of the array items in the block of memory - DN_USize size; // Number of items currently in the array - DN_USize max; // Maximum number of items this array can store - DN_USize commit; // Bytes committed - - T *begin() { return data; } - T *end () { return data + size; } - T const *begin() const { return data; } - T const *end () const { return data + size; } -}; - -template DN_VArray DN_VArray_InitByteSize (DN_USize byte_size); -template DN_VArray DN_VArray_Init (DN_USize max); -template DN_VArray DN_VArray_InitSlice (DN_Slice slice, DN_USize max); -template DN_VArray DN_VArray_InitCArray (T const (&items)[N], DN_USize max); -template void DN_VArray_Deinit (DN_VArray *array); -template bool DN_VArray_IsValid (DN_VArray const *array); -template DN_Slice DN_VArray_Slice (DN_VArray const *array); -template bool DN_VArray_Reserve (DN_VArray *array, DN_USize count); -template T * DN_VArray_AddArray (DN_VArray *array, T const *items, DN_USize count); -template T * DN_VArray_AddCArray (DN_VArray *array, T const (&items)[N]); -template T * DN_VArray_Add (DN_VArray *array, T const &item); -#define DN_VArray_AddArrayAssert(...) DN_HardAssert(DN_VArray_AddArray(__VA_ARGS__)) -#define DN_VArray_AddCArrayAssert(...) DN_HardAssert(DN_VArray_AddCArray(__VA_ARGS__)) -#define DN_VArray_AddAssert(...) DN_HardAssert(DN_VArray_Add(__VA_ARGS__)) -template T * DN_VArray_MakeArray (DN_VArray *array, DN_USize count, DN_ZMem z_mem); -template T * DN_VArray_Make (DN_VArray *array, DN_ZMem z_mem); -#define DN_VArray_MakeArrayAssert(...) DN_HardAssert(DN_VArray_MakeArray(__VA_ARGS__)) -#define DN_VArray_MakeAssert(...) DN_HardAssert(DN_VArray_Make(__VA_ARGS__)) -template T * DN_VArray_InsertArray (DN_VArray *array, DN_USize index, T const *items, DN_USize count); -template T * DN_VArray_InsertCArray (DN_VArray *array, DN_USize index, T const (&items)[N]); -template T * DN_VArray_Insert (DN_VArray *array, DN_USize index, T const &item); -#define DN_VArray_InsertArrayAssert(...) DN_HardAssert(DN_VArray_InsertArray(__VA_ARGS__)) -#define DN_VArray_InsertCArrayAssert(...) DN_HardAssert(DN_VArray_InsertCArray(__VA_ARGS__)) -#define DN_VArray_InsertAssert(...) DN_HardAssert(DN_VArray_Insert(__VA_ARGS__)) -template T DN_VArray_PopFront (DN_VArray *array, DN_USize count); -template T DN_VArray_PopBack (DN_VArray *array, DN_USize count); -template DN_ArrayEraseResult DN_VArray_EraseRange (DN_VArray *array, DN_USize begin_index, DN_ISize count, DN_ArrayErase erase); -template void DN_VArray_Clear (DN_VArray *array, DN_ZMem z_mem); -#endif // !defined(DN_OS_CONTAINERS_H) -// DN: Single header generator commented out this header => #include "OS/dn_os_print.h" -#if !defined(DN_OS_PRINT_H) -#define DN_OS_PRINT_H - -enum DN_OSPrintDest -{ - DN_OSPrintDest_Out, - DN_OSPrintDest_Err, -}; - -// NOTE: Print Macros -#define DN_OS_PrintOut(string) DN_OS_Print(DN_OSPrintDest_Out, string) -#define DN_OS_PrintOutF(fmt, ...) DN_OS_PrintF(DN_OSPrintDest_Out, fmt, ##__VA_ARGS__) -#define DN_OS_PrintOutFV(fmt, args) DN_OS_PrintFV(DN_OSPrintDest_Out, fmt, args) - -#define DN_OS_PrintOutStyle(style, string) DN_OS_PrintStyle(DN_OSPrintDest_Out, style, string) -#define DN_OS_PrintOutFStyle(style, fmt, ...) DN_OS_PrintFStyle(DN_OSPrintDest_Out, style, fmt, ##__VA_ARGS__) -#define DN_OS_PrintOutFVStyle(style, fmt, args, ...) DN_OS_PrintFVStyle(DN_OSPrintDest_Out, style, fmt, args) - -#define DN_OS_PrintOutLn(string) DN_OS_PrintLn(DN_OSPrintDest_Out, string) -#define DN_OS_PrintOutLnF(fmt, ...) DN_OS_PrintLnF(DN_OSPrintDest_Out, fmt, ##__VA_ARGS__) -#define DN_OS_PrintOutLnFV(fmt, args) DN_OS_PrintLnFV(DN_OSPrintDest_Out, fmt, args) - -#define DN_OS_PrintOutLnStyle(style, string) DN_OS_PrintLnStyle(DN_OSPrintDest_Out, style, string); -#define DN_OS_PrintOutLnFStyle(style, fmt, ...) DN_OS_PrintLnFStyle(DN_OSPrintDest_Out, style, fmt, ##__VA_ARGS__) -#define DN_OS_PrintOutLnFVStyle(style, fmt, args) DN_OS_PrintLnFVStyle(DN_OSPrintDest_Out, style, fmt, args); - -#define DN_OS_PrintErr(string) DN_OS_Print(DN_OSPrintDest_Err, string) -#define DN_OS_PrintErrF(fmt, ...) DN_OS_PrintF(DN_OSPrintDest_Err, fmt, ##__VA_ARGS__) -#define DN_OS_PrintErrFV(fmt, args) DN_OS_PrintFV(DN_OSPrintDest_Err, fmt, args) - -#define DN_OS_PrintErrStyle(style, string) DN_OS_PrintStyle(DN_OSPrintDest_Err, style, string) -#define DN_OS_PrintErrFStyle(style, fmt, ...) DN_OS_PrintFStyle(DN_OSPrintDest_Err, style, fmt, ##__VA_ARGS__) -#define DN_OS_PrintErrFVStyle(style, fmt, args, ...) DN_OS_PrintFVStyle(DN_OSPrintDest_Err, style, fmt, args) - -#define DN_OS_PrintErrLn(string) DN_OS_PrintLn(DN_OSPrintDest_Err, string) -#define DN_OS_PrintErrLnF(fmt, ...) DN_OS_PrintLnF(DN_OSPrintDest_Err, fmt, ##__VA_ARGS__) -#define DN_OS_PrintErrLnFV(fmt, args) DN_OS_PrintLnFV(DN_OSPrintDest_Err, fmt, args) - -#define DN_OS_PrintErrLnStyle(style, string) DN_OS_PrintLnStyle(DN_OSPrintDest_Err, style, string); -#define DN_OS_PrintErrLnFStyle(style, fmt, ...) DN_OS_PrintLnFStyle(DN_OSPrintDest_Err, style, fmt, ##__VA_ARGS__) -#define DN_OS_PrintErrLnFVStyle(style, fmt, args) DN_OS_PrintLnFVStyle(DN_OSPrintDest_Err, style, fmt, args); - -// NOTE: Print -DN_API void DN_OS_Print (DN_OSPrintDest dest, DN_Str8 string); -DN_API void DN_OS_PrintF (DN_OSPrintDest dest, DN_FMT_ATTRIB char const *fmt, ...); -DN_API void DN_OS_PrintFV (DN_OSPrintDest dest, DN_FMT_ATTRIB char const *fmt, va_list args); - -DN_API void DN_OS_PrintStyle (DN_OSPrintDest dest, DN_LOGStyle style, DN_Str8 string); -DN_API void DN_OS_PrintFStyle (DN_OSPrintDest dest, DN_LOGStyle style, DN_FMT_ATTRIB char const *fmt, ...); -DN_API void DN_OS_PrintFVStyle (DN_OSPrintDest dest, DN_LOGStyle style, DN_FMT_ATTRIB char const *fmt, va_list args); - -DN_API void DN_OS_PrintLn (DN_OSPrintDest dest, DN_Str8 string); -DN_API void DN_OS_PrintLnF (DN_OSPrintDest dest, DN_FMT_ATTRIB char const *fmt, ...); -DN_API void DN_OS_PrintLnFV (DN_OSPrintDest dest, DN_FMT_ATTRIB char const *fmt, va_list args); - -DN_API void DN_OS_PrintLnStyle (DN_OSPrintDest dest, DN_LOGStyle style, DN_Str8 string); -DN_API void DN_OS_PrintLnFStyle (DN_OSPrintDest dest, DN_LOGStyle style, DN_FMT_ATTRIB char const *fmt, ...); -DN_API void DN_OS_PrintLnFVStyle (DN_OSPrintDest dest, DN_LOGStyle style, DN_FMT_ATTRIB char const *fmt, va_list args); -#endif // !defined(DN_OS_PRINT_H) -// DN: Single header generator commented out this header => #include "OS/dn_os_string.h" -#if !defined(DN_OS_STRING_H) -#define DN_OS_STRING_H - -#if defined(_CLANGD) - // DN: Single header generator commented out this header => #include "../dn_base_inc.h" - // DN: Single header generator commented out this header => #include "../dn_os_inc.h" -#endif - -// NOTE: DN_Str8 - -DN_API DN_Str8 DN_Str8FromFmtVArenaFrame (DN_FMT_ATTRIB char const *fmt, va_list args); -DN_API DN_Str8 DN_Str8FromFmtArenaFrame (DN_FMT_ATTRIB char const *fmt, ...); -DN_API DN_Str8 DN_Str8FromArenaFrame (DN_USize size, DN_ZMem z_mem); -DN_API DN_Str8 DN_Str8FromHeapF (DN_FMT_ATTRIB char const *fmt, ...); -DN_API DN_Str8 DN_Str8FromHeap (DN_USize size, DN_ZMem z_mem); -DN_API DN_Str8 DN_Str8FromTLSFV (DN_FMT_ATTRIB char const *fmt, va_list args); -DN_API DN_Str8 DN_Str8FromTLSF (DN_FMT_ATTRIB char const *fmt, ...); -DN_API DN_Str8 DN_Str8FromTLS (DN_USize size, DN_ZMem z_mem); -DN_API DN_Str8 DN_Str8FromStr8Frame (DN_Str8 string); -DN_API DN_Str8 DN_Str8FromStr8TLS (DN_Str8 string); - -DN_API DN_Str8SplitResult DN_Str8SplitFromFrame (DN_Str8 string, DN_Str8 delimiter, DN_Str8SplitIncludeEmptyStrings mode); -DN_API DN_Str8SplitResult DN_Str8SplitFromTLS (DN_Str8 string, DN_Str8 delimiter, DN_Str8SplitIncludeEmptyStrings mode); - -DN_API DN_Str8 DN_Str8SegmentFromFrame (DN_Str8 src, DN_USize segment_size, char segment_char); -DN_API DN_Str8 DN_Str8SegmentFromTLS (DN_Str8 src, DN_USize segment_size, char segment_char); - -DN_API DN_Str8 DN_Str8ReverseSegmentFromFrame (DN_Str8 src, DN_USize segment_size, char segment_char); -DN_API DN_Str8 DN_Str8ReverseSegmentFromTLS (DN_Str8 src, DN_USize segment_size, char segment_char); - -DN_API DN_Str8 DN_Str8AppendFFromFrame (DN_Str8 string, char const *fmt, ...); -DN_API DN_Str8 DN_Str8AppendFFromTLS (DN_Str8 string, char const *fmt, ...); - -DN_API DN_Str8 DN_Str8FillFFromFrame (DN_Str8 string, char const *fmt, ...); -DN_API DN_Str8 DN_Str8FillFFromTLS (DN_Str8 string, char const *fmt, ...); - -DN_API DN_Str8TruncateResult DN_Str8TruncateMiddleArenaFrame (DN_Str8 str8, uint32_t side_size, DN_Str8 truncator); -DN_API DN_Str8TruncateResult DN_Str8TruncateMiddleArenaTLS (DN_Str8 str8, uint32_t side_size, DN_Str8 truncator); - -DN_API DN_Str8 DN_Str8PadNewLines (DN_Arena *arena, DN_Str8 src, DN_Str8 pad); -DN_API DN_Str8 DN_Str8PadNewLinesFromFrame (DN_Str8 src, DN_Str8 pad); -DN_API DN_Str8 DN_Str8PadNewLinesFromTLS (DN_Str8 src, DN_Str8 pad); - -DN_API DN_Str8 DN_Str8UpperFromFrame (DN_Str8 string); -DN_API DN_Str8 DN_Str8UpperFromTLS (DN_Str8 string); - -DN_API DN_Str8 DN_Str8LowerFromFrame (DN_Str8 string); -DN_API DN_Str8 DN_Str8LowerFromTLS (DN_Str8 string); - -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_Str8EqCase_Sensitive); -DN_API DN_Str8 DN_Str8ReplaceInsensitive (DN_Str8 string, DN_Str8 find, DN_Str8 replace, DN_USize start_index, DN_Arena *arena); - -// NOTE: DN_Str8Builder //////////////////////////////////////////////////////////////////////////// - -DN_API DN_Str8Builder DN_Str8BuilderFromArena () { return DN_Str8BuilderFromArena(DN_OS_TLSGet()->frame_arena); } -DN_API DN_Str8Builder DN_Str8BuilderFromTLS () { return DN_Str8BuilderFromArena(DN_OS_TLSTopArena()); } - -DN_API DN_Str8Builder DN_Str8BuilderFromStr8PtrRefFrame (DN_Str8 const *strings, DN_USize size) { return DN_Str8BuilderFromStr8PtrRef(DN_OS_TLSGet()->frame_arena, strings, size); } -DN_API DN_Str8Builder DN_Str8BuilderFromStr8PtrRefTLS (DN_Str8 const *strings, DN_USize size) { return DN_Str8BuilderFromStr8PtrRef(DN_OS_TLSTopArena(), strings, size); } -DN_API DN_Str8Builder DN_Str8BuilderFromStr8PtrCopyFrame (DN_Str8 const *strings, DN_USize size) { return DN_Str8BuilderFromStr8PtrCopy(DN_OS_TLSGet()->frame_arena, strings, size); } -DN_API DN_Str8Builder DN_Str8BuilderFromStr8PtrCopyTLS (DN_Str8 const *strings, DN_USize size) { return DN_Str8BuilderFromStr8PtrCopy(DN_OS_TLSTopArena(), strings, size); } - -DN_API DN_Str8Builder DN_Str8BuilderFromBuilderFrame (DN_Str8Builder const *builder) { return DN_Str8BuilderFromBuilder(DN_OS_TLSGet()->frame_arena, builder); } -DN_API DN_Str8Builder DN_Str8BuilderFromBuilderTLS (DN_Str8Builder const *builder) { return DN_Str8BuilderFromBuilder(DN_OS_TLSTopArena(), builder); } - -DN_API DN_Str8 DN_Str8BuilderBuildFromFrame (DN_Str8Builder const *builder) { return DN_Str8BuilderBuild(builder, DN_OS_TLSGet()->frame_arena); } -DN_API DN_Str8 DN_Str8BuilderBuildFromHeap (DN_Str8Builder const *builder, DN_Arena *arena); -DN_API DN_Str8 DN_Str8BuilderBuildFromTLS (DN_Str8Builder const *builder) { return DN_Str8BuilderBuild(builder, DN_OS_TLSTopArena()); } - -DN_API DN_Str8 DN_Str8BuilderBuildDelimitedFromFrame(DN_Str8Builder const *builder, DN_Str8 delimiter) { return DN_Str8BuilderBuildDelimited(builder, delimiter, DN_OS_TLSGet()->frame_arena); } -DN_API DN_Str8 DN_Str8BuilderBuildDelimitedFromTLS (DN_Str8Builder const *builder, DN_Str8 delimiter) { return DN_Str8BuilderBuildDelimited(builder, delimiter, DN_OS_TLSTopArena()); } - -DN_API DN_Slice DN_Str8BuilderBuildSliceFromFrame (DN_Str8Builder const *builder) { return DN_Str8BuilderBuildSlice(builder, DN_OS_TLSGet()->frame_arena); } -DN_API DN_Slice DN_Str8BuilderBuildSliceFromTLS (DN_Str8Builder const *builder) { return DN_Str8BuilderBuildSlice(builder, DN_OS_TLSTopArena()); } - -#endif // !defined(DN_OS_STRING_H) - -#endif // DN_OS_INC_H -#endif - -struct DN_InitArgs -{ - DN_U64 os_tls_reserve; - DN_U64 os_tls_commit; - DN_U64 os_tls_err_sink_reserve; - DN_U64 os_tls_err_sink_commit; -}; - -typedef DN_USize DN_InitFlags; -enum DN_InitFlags_ -{ - DN_InitFlags_Nil = 0, - DN_InitFlags_OS = 1 << 0, - DN_InitFlags_OSLeakTracker = 1 << 1, - DN_InitFlags_LogLibFeatures = 1 << 2, - DN_InitFlags_LogCPUFeatures = 1 << 3, - DN_InitFlags_LogAllFeatures = DN_InitFlags_LogLibFeatures | DN_InitFlags_LogCPUFeatures, -}; - -struct DN_Core -{ - DN_InitFlags init_flags; - DN_USize mem_allocs_frame; - DN_LeakTracker leak; - #if defined(DN_OS_H) - DN_OSCore os; - #endif -}; - -extern DN_Core *g_dn_; - -DN_API void DN_Init(DN_Core *dn, DN_InitFlags flags, DN_InitArgs *args); -DN_API void DN_BeginFrame(); - -#endif // !defined(DN_INC_H) -#endif - -DN_Core *g_dn_; - -static void DN_InitOS_(DN_OSCore *os, DN_InitArgs *args) -{ - #if defined(DN_OS_H) && defined(DN_OS_CPP) - // NOTE: OS - { - #if defined(DN_PLATFORM_WIN32) - SYSTEM_INFO system_info = {}; - GetSystemInfo(&system_info); - - os->logical_processor_count = system_info.dwNumberOfProcessors; - os->page_size = system_info.dwPageSize; - os->alloc_granularity = system_info.dwAllocationGranularity; - #else - #if defined(DN_PLATFORM_EMSCRIPTEN) - os->logical_processor_count = 1; - #else - os->logical_processor_count = get_nprocs(); - #endif - os->page_size = getpagesize(); - os->alloc_granularity = os->page_size; - #endif - } - - // NOTE: Setup logging - DN_OS_EmitLogsWithOSPrintFunctions(os); - - { - #if defined(DN_PLATFORM_EMSCRIPTEN) - os->arena = DN_ArenaFromHeap(DN_Megabytes(1), DN_ArenaFlags_NoAllocTrack); - #else - os->arena = DN_ArenaFromVMem(DN_Megabytes(1), DN_Kilobytes(4), DN_ArenaFlags_NoAllocTrack); - #endif - - #if defined(DN_PLATFORM_WIN32) - os->platform_context = DN_ArenaNew(&os->arena, DN_W32Core, DN_ZMem_Yes); - #elif defined(DN_PLATFORM_POSIX) || defined(DN_PLATFORM_EMSCRIPTEN) - os->platform_context = DN_ArenaNew(&os->arena, DN_POSIXCore, DN_ZMem_Yes); - #endif - - #if defined(DN_PLATFORM_WIN32) - DN_W32Core *w32 = DN_Cast(DN_W32Core *) os->platform_context; - InitializeCriticalSection(&w32->sync_primitive_free_list_mutex); - - QueryPerformanceFrequency(&w32->qpc_frequency); - HMODULE module = LoadLibraryA("kernel32.dll"); - if (module) { - w32->set_thread_description = DN_Cast(DN_W32SetThreadDescriptionFunc *) GetProcAddress(module, "SetThreadDescription"); - FreeLibrary(module); - } - - // 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_LOG_ErrorF("Failed to initialise Windows secure random number generator, error: %d", init_status); - #else - DN_Posix_Init(DN_Cast(DN_POSIXCore *)os->platform_context); - #endif - } - - // NOTE: Initialise tmem arenas which allocate memory and will be - // recorded to the now initialised allocation table. The initialisation - // of tmem memory may request tmem memory itself in leak tracing mode. - // This is supported as the tmem arenas defer allocation tracking until - // initialisation is done. - DN_OSTLSInitArgs tls_init_args = {}; - if (args) { - tls_init_args.commit = args->os_tls_commit; - tls_init_args.reserve = args->os_tls_reserve; - tls_init_args.err_sink_reserve = args->os_tls_err_sink_reserve; - tls_init_args.err_sink_commit = args->os_tls_err_sink_commit; - } - - DN_OS_TLSInit(&os->tls, tls_init_args); - DN_OS_TLSSetCurrentThreadTLS(&os->tls); - 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 - DN_Assert(g_dn_); - #endif // defined(DN_OS_H) && defined(DN_OS_CPP) -} - - -DN_API void DN_Init(DN_Core *dn, DN_InitFlags flags, DN_InitArgs *args) -{ - g_dn_ = dn; - dn->init_flags = flags; - - if (flags & DN_InitFlags_OS) { - #if defined(DN_OS_H) && defined(DN_OS_CPP) - DN_InitOS_(&dn->os, args); - if (flags & DN_InitFlags_OSLeakTracker) { - // NOTE: Setup the allocation table with allocation tracking turned off on - // the arena we're using to initialise the table. - dn->leak.alloc_table_arena = DN_ArenaFromVMem(DN_Megabytes(1), DN_Kilobytes(512), DN_ArenaFlags_NoAllocTrack | DN_ArenaFlags_AllocCanLeak); - dn->leak.alloc_table = DN_DSMap_Init(&dn->leak.alloc_table_arena, 4096, DN_DSMapFlags_Nil); - } - #endif - } - - // NOTE: Print out init features - char buf[4096]; - DN_USize buf_size = 0; - if (flags & DN_InitFlags_LogLibFeatures) { - DN_FmtAppendTruncate(buf, &buf_size, sizeof(buf), DN_Str8Lit("..."), "DN initialised:\n"); - #if defined(DN_OS_CPP) - DN_F32 page_size_kib = dn->os.page_size / 1024.0f; - DN_F32 alloc_granularity_kib = dn->os.alloc_granularity / 1024.0f; - DN_FmtAppendTruncate(buf, - &buf_size, - sizeof(buf), - DN_Str8Lit("..."), - " OS Page Size/Alloc Granularity: %.1f/%.1fKiB\n" - " Logical Processor Count: %u\n", - page_size_kib, - alloc_granularity_kib, - dn->os.logical_processor_count); - #endif - - #if DN_HAS_FEATURE(address_sanitizer) || defined(__SANITIZE_ADDRESS__) - if (DN_ASAN_POISON) { - DN_FmtAppendTruncate(buf, &buf_size, sizeof(buf), DN_Str8Lit("..."), " ASAN manual poisoning%s\n", DN_ASAN_VET_POISON ? " (+vet sanity checks)" : ""); - DN_FmtAppendTruncate(buf, &buf_size, sizeof(buf), DN_Str8Lit("..."), " ASAN poison guard size: %u\n", DN_ASAN_POISON_GUARD_SIZE); - } - #endif - - #if defined(DN_LEAK_TRACKING) - DN_FmtAppendTruncate(buf, &buf_size, sizeof(buf), DN_Str8Lit("..."), " Allocation leak tracing\n"); - #endif - - #if defined(DN_PLATFORM_EMSCRIPTEN) || defined(DN_PLATFORM_POSIX) - DN_POSIXCore *posix = DN_Cast(DN_POSIXCore *)g_dn_->os.platform_context; - DN_FmtAppendTruncate(buf, &buf_size, sizeof(buf), DN_Str8Lit("..."), " Clock GetTime: %S\n", posix->clock_monotonic_raw ? DN_Str8Lit("CLOCK_MONOTONIC_RAW") : DN_Str8Lit("CLOCK_MONOTONIC")); - #endif - // TODO(doyle): Add stacktrace feature log - } - - if (flags & DN_InitFlags_LogCPUFeatures) { - DN_CPUReport const *report = &dn->os.cpu_report; - DN_Str8 brand = DN_Str8TrimWhitespaceAround(DN_Str8FromPtr(report->brand, sizeof(report->brand) - 1)); - DN_MSVC_WARNING_PUSH - DN_MSVC_WARNING_DISABLE(6284) // Object passed as _Param_(3) when a string is required in call to 'DN_Str8BuilderAppendF' Actual type: 'struct DN_Str8'. - DN_FmtAppendTruncate(buf, &buf_size, sizeof(buf), DN_Str8Lit("..."), " CPU '%S' from '%s' detected:\n", brand, report->vendor); - DN_MSVC_WARNING_POP - - 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]; - longest_feature_name = DN_Max(longest_feature_name, feature_decl.label.size); - } - - 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), - DN_Str8Lit("..."), - " %.*s:%*s%s\n", - DN_Str8PrintFmt(feature_decl.label), - DN_Cast(int)(longest_feature_name - feature_decl.label.size), - "", - has_feature ? "available" : "not available"); - } - } - - if (buf_size) - DN_LOG_DebugF("%.*s", DN_Cast(int)buf_size, buf); -} - -DN_API void DN_BeginFrame() -{ - DN_AtomicSetValue64(&g_dn_->os.mem_allocs_frame, 0); -} -#define DN_MATH_CPP - -#if defined(_CLANGD) - // DN: Single header generator commented out this header => #include "dn_math.h" -#if !defined(DN_MATH_H) -#define DN_MATH_H - -#if defined(_CLANGD) - // DN: Single header generator commented out this header => #include "../dn_base_inc.h" -#endif - -DN_MSVC_WARNING_PUSH -DN_MSVC_WARNING_DISABLE(4201) // warning C4201: nonstandard extension used: nameless struct/union -union DN_V2I32 -{ - struct { DN_I32 x, y; }; - struct { DN_I32 w, h; }; - DN_I32 data[2]; -}; - -union DN_V2U16 -{ - struct { DN_U16 x, y; }; - struct { DN_U16 w, h; }; - DN_U16 data[2]; -}; - -union DN_V2U32 -{ - struct { DN_U32 x, y; }; - struct { DN_U32 w, h; }; - DN_U32 data[2]; -}; - -union DN_V2F32 -{ - struct { DN_F32 x, y; }; - struct { DN_F32 w, h; }; - DN_F32 data[2]; -}; - -union DN_V3F32 -{ - struct { DN_F32 x, y, z; }; - struct { DN_F32 r, g, b; }; - DN_F32 data[3]; -}; - - -union DN_V4F32 -{ - struct { DN_F32 x, y, z, w; }; - struct { DN_F32 r, g, b, a; }; - #if !defined(DN_NO_V3) - DN_V3F32 rgb; - DN_V3F32 xyz; - #endif - DN_F32 data[4]; -}; -DN_MSVC_WARNING_POP - -struct DN_M4 -{ - DN_F32 columns[4][4]; // Column major matrix -}; - -union DN_M2x3 -{ - DN_F32 e[6]; - DN_F32 row[2][3]; -}; - -struct DN_Rect -{ - DN_V2F32 pos, size; -}; - -struct DN_RectMinMax -{ - DN_V2F32 min, max; -}; - -enum DN_RectCutClip -{ - DN_RectCutClip_No, - DN_RectCutClip_Yes, -}; - -enum DN_RectCutSide -{ - DN_RectCutSide_Left, - DN_RectCutSide_Right, - DN_RectCutSide_Top, - DN_RectCutSide_Bottom, -}; - -struct DN_RectCut -{ - DN_Rect* rect; - DN_RectCutSide side; -}; - -struct DN_RaycastLineIntersectV2Result -{ - bool hit; // True if there was an intersection, false if the lines are parallel - DN_F32 t_a; // Distance along `dir_a` that the intersection occurred, e.g. `origin_a + (dir_a * t_a)` - DN_F32 t_b; // Distance along `dir_b` that the intersection occurred, e.g. `origin_b + (dir_b * t_b)` -}; - -#define DN_V2I32_Zero DN_Literal(DN_V2I32){{(int32_t)(0), (int32_t)(0)}} -#define DN_V2I32_One DN_Literal(DN_V2I32){{(int32_t)(1), (int32_t)(1)}} -#define DN_V2I32_From1N(x) DN_Literal(DN_V2I32){{(int32_t)(x), (int32_t)(x)}} -#define DN_V2I32_From2N(x, y) DN_Literal(DN_V2I32){{(int32_t)(x), (int32_t)(y)}} -#define DN_V2I32_InitV2(xy) DN_Literal(DN_V2I32){{(int32_t)(xy).x, (int32_t)(xy).y}} - -DN_API bool operator!= (DN_V2I32 lhs, DN_V2I32 rhs); -DN_API bool operator== (DN_V2I32 lhs, DN_V2I32 rhs); -DN_API bool operator>= (DN_V2I32 lhs, DN_V2I32 rhs); -DN_API bool operator<= (DN_V2I32 lhs, DN_V2I32 rhs); -DN_API bool operator< (DN_V2I32 lhs, DN_V2I32 rhs); -DN_API bool operator> (DN_V2I32 lhs, DN_V2I32 rhs); -DN_API DN_V2I32 operator- (DN_V2I32 lhs, DN_V2I32 rhs); -DN_API DN_V2I32 operator- (DN_V2I32 lhs); -DN_API DN_V2I32 operator+ (DN_V2I32 lhs, DN_V2I32 rhs); -DN_API DN_V2I32 operator* (DN_V2I32 lhs, DN_V2I32 rhs); -DN_API DN_V2I32 operator* (DN_V2I32 lhs, DN_F32 rhs); -DN_API DN_V2I32 operator* (DN_V2I32 lhs, int32_t rhs); -DN_API DN_V2I32 operator/ (DN_V2I32 lhs, DN_V2I32 rhs); -DN_API DN_V2I32 operator/ (DN_V2I32 lhs, DN_F32 rhs); -DN_API DN_V2I32 operator/ (DN_V2I32 lhs, int32_t rhs); -DN_API DN_V2I32 & operator*= (DN_V2I32& lhs, DN_V2I32 rhs); -DN_API DN_V2I32 & operator*= (DN_V2I32& lhs, DN_F32 rhs); -DN_API DN_V2I32 & operator*= (DN_V2I32& lhs, int32_t rhs); -DN_API DN_V2I32 & operator/= (DN_V2I32& lhs, DN_V2I32 rhs); -DN_API DN_V2I32 & operator/= (DN_V2I32& lhs, DN_F32 rhs); -DN_API DN_V2I32 & operator/= (DN_V2I32& lhs, int32_t rhs); -DN_API DN_V2I32 & operator-= (DN_V2I32& lhs, DN_V2I32 rhs); -DN_API DN_V2I32 & operator+= (DN_V2I32& lhs, DN_V2I32 rhs); - -DN_API DN_V2I32 DN_V2I32_Min (DN_V2I32 a, DN_V2I32 b); -DN_API DN_V2I32 DN_V2I32_Max (DN_V2I32 a, DN_V2I32 b); -DN_API DN_V2I32 DN_V2I32_Abs (DN_V2I32 a); - -#define DN_V2U16_Zero DN_Literal(DN_V2U16){{(uint16_t)(0), (uint16_t)(0)}} -#define DN_V2U16_One DN_Literal(DN_V2U16){{(uint16_t)(1), (uint16_t)(1)}} -#define DN_V2U16_From1N(x) DN_Literal(DN_V2U16){{(uint16_t)(x), (uint16_t)(x)}} -#define DN_V2U16_From2N(x, y) DN_Literal(DN_V2U16){{(uint16_t)(x), (uint16_t)(y)}} - -DN_API bool operator!= (DN_V2U16 lhs, DN_V2U16 rhs); -DN_API bool operator== (DN_V2U16 lhs, DN_V2U16 rhs); -DN_API bool operator>= (DN_V2U16 lhs, DN_V2U16 rhs); -DN_API bool operator<= (DN_V2U16 lhs, DN_V2U16 rhs); -DN_API bool operator< (DN_V2U16 lhs, DN_V2U16 rhs); -DN_API bool operator> (DN_V2U16 lhs, DN_V2U16 rhs); -DN_API DN_V2U16 operator- (DN_V2U16 lhs, DN_V2U16 rhs); -DN_API DN_V2U16 operator+ (DN_V2U16 lhs, DN_V2U16 rhs); -DN_API DN_V2U16 operator* (DN_V2U16 lhs, DN_V2U16 rhs); -DN_API DN_V2U16 operator* (DN_V2U16 lhs, DN_F32 rhs); -DN_API DN_V2U16 operator* (DN_V2U16 lhs, int32_t rhs); -DN_API DN_V2U16 operator/ (DN_V2U16 lhs, DN_V2U16 rhs); -DN_API DN_V2U16 operator/ (DN_V2U16 lhs, DN_F32 rhs); -DN_API DN_V2U16 operator/ (DN_V2U16 lhs, int32_t rhs); -DN_API DN_V2U16 & operator*= (DN_V2U16& lhs, DN_V2U16 rhs); -DN_API DN_V2U16 & operator*= (DN_V2U16& lhs, DN_F32 rhs); -DN_API DN_V2U16 & operator*= (DN_V2U16& lhs, int32_t rhs); -DN_API DN_V2U16 & operator/= (DN_V2U16& lhs, DN_V2U16 rhs); -DN_API DN_V2U16 & operator/= (DN_V2U16& lhs, DN_F32 rhs); -DN_API DN_V2U16 & operator/= (DN_V2U16& lhs, int32_t rhs); -DN_API DN_V2U16 & operator-= (DN_V2U16& lhs, DN_V2U16 rhs); -DN_API DN_V2U16 & operator+= (DN_V2U16& lhs, DN_V2U16 rhs); - -#define DN_V2F32_Zero DN_Literal(DN_V2F32){{(DN_F32)(0), (DN_F32)(0)}} -#define DN_V2F32_One DN_Literal(DN_V2F32){{(DN_F32)(1), (DN_F32)(1)}} -#define DN_V2F32_From1N(x) DN_Literal(DN_V2F32){{(DN_F32)(x), (DN_F32)(x)}} -#define DN_V2F32_From2N(x, y) DN_Literal(DN_V2F32){{(DN_F32)(x), (DN_F32)(y)}} -#define DN_V2F32_FromV2I32(xy) DN_Literal(DN_V2F32){{(DN_F32)(xy).x, (DN_F32)(xy).y}} -#define DN_V2F32_FromV2U32(xy) DN_Literal(DN_V2F32){{(DN_F32)(xy).x, (DN_F32)(xy).y}} - -DN_API bool operator!= (DN_V2F32 lhs, DN_V2F32 rhs); -DN_API bool operator== (DN_V2F32 lhs, DN_V2F32 rhs); -DN_API bool operator>= (DN_V2F32 lhs, DN_V2F32 rhs); -DN_API bool operator<= (DN_V2F32 lhs, DN_V2F32 rhs); -DN_API bool operator< (DN_V2F32 lhs, DN_V2F32 rhs); -DN_API bool operator> (DN_V2F32 lhs, DN_V2F32 rhs); - -DN_API DN_V2F32 operator- (DN_V2F32 lhs); -DN_API DN_V2F32 operator- (DN_V2F32 lhs, DN_V2F32 rhs); -DN_API DN_V2F32 operator- (DN_V2F32 lhs, DN_V2I32 rhs); -DN_API DN_V2F32 operator- (DN_V2F32 lhs, DN_F32 rhs); -DN_API DN_V2F32 operator- (DN_V2F32 lhs, int32_t rhs); - -DN_API DN_V2F32 operator+ (DN_V2F32 lhs, DN_V2F32 rhs); -DN_API DN_V2F32 operator+ (DN_V2F32 lhs, DN_V2I32 rhs); -DN_API DN_V2F32 operator+ (DN_V2F32 lhs, DN_F32 rhs); -DN_API DN_V2F32 operator+ (DN_V2F32 lhs, int32_t rhs); - -DN_API DN_V2F32 operator* (DN_V2F32 lhs, DN_V2F32 rhs); -DN_API DN_V2F32 operator* (DN_V2F32 lhs, DN_V2I32 rhs); -DN_API DN_V2F32 operator* (DN_V2F32 lhs, DN_F32 rhs); -DN_API DN_V2F32 operator* (DN_V2F32 lhs, int32_t rhs); - -DN_API DN_V2F32 operator/ (DN_V2F32 lhs, DN_V2F32 rhs); -DN_API DN_V2F32 operator/ (DN_V2F32 lhs, DN_V2I32 rhs); -DN_API DN_V2F32 operator/ (DN_V2F32 lhs, DN_F32 rhs); -DN_API DN_V2F32 operator/ (DN_V2F32 lhs, int32_t rhs); - -DN_API DN_V2F32 & operator*= (DN_V2F32& lhs, DN_V2F32 rhs); -DN_API DN_V2F32 & operator*= (DN_V2F32& lhs, DN_V2I32 rhs); -DN_API DN_V2F32 & operator*= (DN_V2F32& lhs, DN_F32 rhs); -DN_API DN_V2F32 & operator*= (DN_V2F32& lhs, int32_t rhs); - -DN_API DN_V2F32 & operator/= (DN_V2F32& lhs, DN_V2F32 rhs); -DN_API DN_V2F32 & operator/= (DN_V2F32& lhs, DN_V2I32 rhs); -DN_API DN_V2F32 & operator/= (DN_V2F32& lhs, DN_F32 rhs); -DN_API DN_V2F32 & operator/= (DN_V2F32& lhs, int32_t rhs); - -DN_API DN_V2F32 & operator-= (DN_V2F32& lhs, DN_V2F32 rhs); -DN_API DN_V2F32 & operator-= (DN_V2F32& lhs, DN_V2I32 rhs); -DN_API DN_V2F32 & operator-= (DN_V2F32& lhs, DN_F32 rhs); -DN_API DN_V2F32 & operator-= (DN_V2F32& lhs, int32_t rhs); - -DN_API DN_V2F32 & operator+= (DN_V2F32& lhs, DN_V2F32 rhs); -DN_API DN_V2F32 & operator+= (DN_V2F32& lhs, DN_V2I32 rhs); -DN_API DN_V2F32 & operator+= (DN_V2F32& lhs, DN_F32 rhs); -DN_API DN_V2F32 & operator+= (DN_V2F32& lhs, int32_t rhs); - -DN_API DN_V2F32 DN_V2F32_Min (DN_V2F32 a, DN_V2F32 b); -DN_API DN_V2F32 DN_V2F32_Max (DN_V2F32 a, DN_V2F32 b); -DN_API DN_V2F32 DN_V2F32_Abs (DN_V2F32 a); -DN_API DN_F32 DN_V2F32_Dot (DN_V2F32 a, DN_V2F32 b); -DN_API DN_F32 DN_V2F32_LengthSq2V2 (DN_V2F32 lhs, DN_V2F32 rhs); -DN_API bool DN_V2F32_LengthSqIsWithin2V2 (DN_V2F32 lhs, DN_V2F32 rhs, DN_F32 within_amount_sq); -DN_API DN_F32 DN_V2F32_Length2V2 (DN_V2F32 lhs, DN_V2F32 rhs); -DN_API DN_F32 DN_V2F32_LengthSq (DN_V2F32 lhs); -DN_API DN_F32 DN_V2F32_Length (DN_V2F32 lhs); -DN_API DN_V2F32 DN_V2F32_Normalise (DN_V2F32 a); -DN_API DN_V2F32 DN_V2F32_Perpendicular (DN_V2F32 a); -DN_API DN_V2F32 DN_V2F32_Reflect (DN_V2F32 in, DN_V2F32 surface); -DN_API DN_F32 DN_V2F32_Area (DN_V2F32 a); - -#define DN_V3F32_From1N(x) DN_Literal(DN_V3F32){{(DN_F32)(x), (DN_F32)(x), (DN_F32)(x)}} -#define DN_V3F32_From3N(x, y, z) DN_Literal(DN_V3F32){{(DN_F32)(x), (DN_F32)(y), (DN_F32)(z)}} -#define DN_V3F32_FromV2F32And1N(xy, z) DN_Literal(DN_V3F32){{(DN_F32)(xy.x), (DN_F32)(xy.y), (DN_F32)(z)}} - -DN_API bool operator== (DN_V3F32 lhs, DN_V3F32 rhs); -DN_API bool operator!= (DN_V3F32 lhs, DN_V3F32 rhs); -DN_API bool operator>= (DN_V3F32 lhs, DN_V3F32 rhs); -DN_API bool operator<= (DN_V3F32 lhs, DN_V3F32 rhs); -DN_API bool operator< (DN_V3F32 lhs, DN_V3F32 rhs); -DN_API bool operator> (DN_V3F32 lhs, DN_V3F32 rhs); -DN_API DN_V3F32 operator- (DN_V3F32 lhs, DN_V3F32 rhs); -DN_API DN_V3F32 operator- (DN_V3F32 lhs); -DN_API DN_V3F32 operator+ (DN_V3F32 lhs, DN_V3F32 rhs); -DN_API DN_V3F32 operator* (DN_V3F32 lhs, DN_V3F32 rhs); -DN_API DN_V3F32 operator* (DN_V3F32 lhs, DN_F32 rhs); -DN_API DN_V3F32 operator* (DN_V3F32 lhs, int32_t rhs); -DN_API DN_V3F32 operator/ (DN_V3F32 lhs, DN_V3F32 rhs); -DN_API DN_V3F32 operator/ (DN_V3F32 lhs, DN_F32 rhs); -DN_API DN_V3F32 operator/ (DN_V3F32 lhs, int32_t rhs); -DN_API DN_V3F32 & operator*= (DN_V3F32 &lhs, DN_V3F32 rhs); -DN_API DN_V3F32 & operator*= (DN_V3F32 &lhs, DN_F32 rhs); -DN_API DN_V3F32 & operator*= (DN_V3F32 &lhs, int32_t rhs); -DN_API DN_V3F32 & operator/= (DN_V3F32 &lhs, DN_V3F32 rhs); -DN_API DN_V3F32 & operator/= (DN_V3F32 &lhs, DN_F32 rhs); -DN_API DN_V3F32 & operator/= (DN_V3F32 &lhs, int32_t rhs); -DN_API DN_V3F32 & operator-= (DN_V3F32 &lhs, DN_V3F32 rhs); -DN_API DN_V3F32 & operator+= (DN_V3F32 &lhs, DN_V3F32 rhs); -DN_API DN_F32 DN_V3F32_LengthSq (DN_V3F32 a); -DN_API DN_F32 DN_V3F32_Length (DN_V3F32 a); -DN_API DN_V3F32 DN_V3F32_Normalise (DN_V3F32 a); - -#define DN_V4F32_From1N(x) DN_Literal(DN_V4F32){{(DN_F32)(x), (DN_F32)(x), (DN_F32)(x), (DN_F32)(x)}} -#define DN_V4F32_From4N(x, y, z, w) DN_Literal(DN_V4F32){{(DN_F32)(x), (DN_F32)(y), (DN_F32)(z), (DN_F32)(w)}} -#define DN_V4F32_FromV3And1N(xyz, w) DN_Literal(DN_V4F32){{xyz.x, xyz.y, xyz.z, w}} -#define DN_V4F32_FromRGBAU8(r, g, b, a) DN_Literal(DN_V4F32){{r / 255.f, g / 255.f, b / 255.f, a / 255.f}} -#define DN_V4F32_FromRGBU8(r, g, b) DN_Literal(DN_V4F32){{r / 255.f, g / 255.f, b / 255.f, 1.f}} -DN_API DN_V4F32 DN_V4F32_FromRGBU32(DN_U32 u32); -DN_API DN_V4F32 DN_V4F32_FromRGBAU32(DN_U32 u32); -#define DN_V4F32_FromV4Alpha(v4, alpha) DN_V4F32_FromV3And1N(v4.xyz, alpha) -DN_API bool operator== (DN_V4F32 lhs, DN_V4F32 rhs); -DN_API bool operator!= (DN_V4F32 lhs, DN_V4F32 rhs); -DN_API bool operator<= (DN_V4F32 lhs, DN_V4F32 rhs); -DN_API bool operator< (DN_V4F32 lhs, DN_V4F32 rhs); -DN_API bool operator> (DN_V4F32 lhs, DN_V4F32 rhs); -DN_API DN_V4F32 operator- (DN_V4F32 lhs, DN_V4F32 rhs); -DN_API DN_V4F32 operator- (DN_V4F32 lhs); -DN_API DN_V4F32 operator+ (DN_V4F32 lhs, DN_V4F32 rhs); -DN_API DN_V4F32 operator* (DN_V4F32 lhs, DN_V4F32 rhs); -DN_API DN_V4F32 operator* (DN_V4F32 lhs, DN_F32 rhs); -DN_API DN_V4F32 operator* (DN_V4F32 lhs, int32_t rhs); -DN_API DN_V4F32 operator/ (DN_V4F32 lhs, DN_F32 rhs); -DN_API DN_V4F32 & operator*= (DN_V4F32 &lhs, DN_V4F32 rhs); -DN_API DN_V4F32 & operator*= (DN_V4F32 &lhs, DN_F32 rhs); -DN_API DN_V4F32 & operator*= (DN_V4F32 &lhs, int32_t rhs); -DN_API DN_V4F32 & operator-= (DN_V4F32 &lhs, DN_V4F32 rhs); -DN_API DN_V4F32 & operator+= (DN_V4F32 &lhs, DN_V4F32 rhs); -DN_API DN_F32 DN_V4F32_Dot (DN_V4F32 a, DN_V4F32 b); - -DN_API DN_M4 DN_M4_Identity (); -DN_API DN_M4 DN_M4_ScaleF (DN_F32 x, DN_F32 y, DN_F32 z); -DN_API DN_M4 DN_M4_Scale (DN_V3F32 xyz); -DN_API DN_M4 DN_M4_TranslateF (DN_F32 x, DN_F32 y, DN_F32 z); -DN_API DN_M4 DN_M4_Translate (DN_V3F32 xyz); -DN_API DN_M4 DN_M4_Transpose (DN_M4 mat); -DN_API DN_M4 DN_M4_Rotate (DN_V3F32 axis, DN_F32 radians); -DN_API DN_M4 DN_M4_Orthographic (DN_F32 left, DN_F32 right, DN_F32 bottom, DN_F32 top, DN_F32 z_near, DN_F32 z_far); -DN_API DN_M4 DN_M4_Perspective (DN_F32 fov /*radians*/, DN_F32 aspect, DN_F32 z_near, DN_F32 z_far); -DN_API DN_M4 DN_M4_Add (DN_M4 lhs, DN_M4 rhs); -DN_API DN_M4 DN_M4_Sub (DN_M4 lhs, DN_M4 rhs); -DN_API DN_M4 DN_M4_Mul (DN_M4 lhs, DN_M4 rhs); -DN_API DN_M4 DN_M4_Div (DN_M4 lhs, DN_M4 rhs); -DN_API DN_M4 DN_M4_AddF (DN_M4 lhs, DN_F32 rhs); -DN_API DN_M4 DN_M4_SubF (DN_M4 lhs, DN_F32 rhs); -DN_API DN_M4 DN_M4_MulF (DN_M4 lhs, DN_F32 rhs); -DN_API DN_M4 DN_M4_DivF (DN_M4 lhs, DN_F32 rhs); -DN_API DN_Str8x256 DN_M4_ColumnMajorString (DN_M4 mat); - -DN_API bool operator== (DN_M2x3 const &lhs, DN_M2x3 const &rhs); -DN_API bool operator!= (DN_M2x3 const &lhs, DN_M2x3 const &rhs); -DN_API DN_M2x3 DN_M2x3_Identity (); -DN_API DN_M2x3 DN_M2x3_Translate (DN_V2F32 offset); -DN_API DN_M2x3 DN_M2x3_Scale (DN_V2F32 scale); -DN_API DN_M2x3 DN_M2x3_Rotate (DN_F32 radians); -DN_API DN_M2x3 DN_M2x3_Mul (DN_M2x3 m1, DN_M2x3 m2); -DN_API DN_V2F32 DN_M2x3_Mul2F32 (DN_M2x3 m1, DN_F32 x, DN_F32 y); -DN_API DN_V2F32 DN_M2x3_MulV2 (DN_M2x3 m1, DN_V2F32 v2); - -#define DN_Rect_From2V2(pos, size) DN_Literal(DN_Rect){(pos), (size)} -#define DN_Rect_From4N(x, y, w, h) DN_Literal(DN_Rect){DN_Literal(DN_V2F32){{x, y}}, DN_Literal(DN_V2F32){{w, h}}} - -DN_API bool operator== (const DN_Rect& lhs, const DN_Rect& rhs); -DN_API DN_V2F32 DN_Rect_Center (DN_Rect rect); -DN_API bool DN_Rect_ContainsPoint (DN_Rect rect, DN_V2F32 p); -DN_API bool DN_Rect_ContainsRect (DN_Rect a, DN_Rect b); -DN_API DN_Rect DN_Rect_Expand (DN_Rect a, DN_F32 amount); -DN_API DN_Rect DN_Rect_ExpandV2 (DN_Rect a, DN_V2F32 amount); -DN_API bool DN_Rect_Intersects (DN_Rect a, DN_Rect b); -DN_API DN_Rect DN_Rect_Intersection (DN_Rect a, DN_Rect b); -DN_API DN_Rect DN_Rect_Union (DN_Rect a, DN_Rect b); -DN_API DN_RectMinMax DN_Rect_MinMax (DN_Rect a); -DN_API DN_F32 DN_Rect_Area (DN_Rect a); -DN_API DN_V2F32 DN_Rect_InterpolatedPoint (DN_Rect rect, DN_V2F32 t01); -DN_API DN_V2F32 DN_Rect_TopLeft (DN_Rect rect); -DN_API DN_V2F32 DN_Rect_TopRight (DN_Rect rect); -DN_API DN_V2F32 DN_Rect_BottomLeft (DN_Rect rect); -DN_API DN_V2F32 DN_Rect_BottomRight (DN_Rect rect); - -DN_API DN_Rect DN_Rect_CutLeftClip (DN_Rect *rect, DN_F32 amount, DN_RectCutClip clip); -DN_API DN_Rect DN_Rect_CutRightClip (DN_Rect *rect, DN_F32 amount, DN_RectCutClip clip); -DN_API DN_Rect DN_Rect_CutTopClip (DN_Rect *rect, DN_F32 amount, DN_RectCutClip clip); -DN_API DN_Rect DN_Rect_CutBottomClip (DN_Rect *rect, DN_F32 amount, DN_RectCutClip clip); - -#define DN_Rect_CutLeft(rect, amount) DN_Rect_CutLeftClip(rect, amount, DN_RectCutClip_Yes) -#define DN_Rect_CutRight(rect, amount) DN_Rect_CutRightClip(rect, amount, DN_RectCutClip_Yes) -#define DN_Rect_CutTop(rect, amount) DN_Rect_CutTopClip(rect, amount, DN_RectCutClip_Yes) -#define DN_Rect_CutBottom(rect, amount) DN_Rect_CutBottomClip(rect, amount, DN_RectCutClip_Yes) - -#define DN_Rect_CutLeftNoClip(rect, amount) DN_Rect_CutLeftClip(rect, amount, DN_RectCutClip_No) -#define DN_Rect_CutRightNoClip(rect, amount) DN_Rect_CutRightClip(rect, amount, DN_RectCutClip_No) -#define DN_Rect_CutTopNoClip(rect, amount) DN_Rect_CutTopClip(rect, amount, DN_RectCutClip_No) -#define DN_Rect_CutBottomNoClip(rect, amount) DN_Rect_CutBottomClip(rect, amount, DN_RectCutClip_No) - -DN_API DN_Rect DN_RectCut_Cut (DN_RectCut rect_cut, DN_V2F32 size, DN_RectCutClip clip); -#define DN_RectCut_Init(rect, side) DN_Literal(DN_RectCut){rect, side} -#define DN_RectCut_Left(rect) DN_Literal(DN_RectCut){rect, DN_RectCutSide_Left} -#define DN_RectCut_Right(rect) DN_Literal(DN_RectCut){rect, DN_RectCutSide_Right} -#define DN_RectCut_Top(rect) DN_Literal(DN_RectCut){rect, DN_RectCutSide_Top} -#define DN_RectCut_Bottom(rect) DN_Literal(DN_RectCut){rect, DN_RectCutSide_Bottom} - -DN_API DN_RaycastLineIntersectV2Result DN_Raycast_LineIntersectV2(DN_V2F32 origin_a, DN_V2F32 dir_a, DN_V2F32 origin_b, DN_V2F32 dir_b); -DN_API DN_V2F32 DN_Lerp_V2F32 (DN_V2F32 a, DN_F32 t, DN_V2F32 b); -DN_API DN_F32 DN_Lerp_F32 (DN_F32 a, DN_F32 t, DN_F32 b); -#endif // !defined(DN_MATH_H) +#if (_CLANGD) + #define DN_H_WITH_OS 1 + #include "dn.h" #endif - -DN_API bool operator==(DN_V2I32 lhs, DN_V2I32 rhs) -{ - bool result = (lhs.x == rhs.x) && (lhs.y == rhs.y); - return result; -} - -DN_API bool operator!=(DN_V2I32 lhs, DN_V2I32 rhs) -{ - bool result = !(lhs == rhs); - return result; -} - -DN_API bool operator>=(DN_V2I32 lhs, DN_V2I32 rhs) -{ - bool result = (lhs.x >= rhs.x) && (lhs.y >= rhs.y); - return result; -} - -DN_API bool operator<=(DN_V2I32 lhs, DN_V2I32 rhs) -{ - bool result = (lhs.x <= rhs.x) && (lhs.y <= rhs.y); - return result; -} - -DN_API bool operator<(DN_V2I32 lhs, DN_V2I32 rhs) -{ - bool result = (lhs.x < rhs.x) && (lhs.y < rhs.y); - return result; -} - -DN_API bool operator>(DN_V2I32 lhs, DN_V2I32 rhs) -{ - bool result = (lhs.x > rhs.x) && (lhs.y > rhs.y); - return result; -} - -DN_API DN_V2I32 operator-(DN_V2I32 lhs, DN_V2I32 rhs) -{ - DN_V2I32 result = DN_V2I32_From2N(lhs.x - rhs.x, lhs.y - rhs.y); - return result; -} - -DN_API DN_V2I32 operator-(DN_V2I32 lhs) -{ - DN_V2I32 result = DN_V2I32_From2N(-lhs.x, -lhs.y); - return result; -} - -DN_API DN_V2I32 operator+(DN_V2I32 lhs, DN_V2I32 rhs) -{ - DN_V2I32 result = DN_V2I32_From2N(lhs.x + rhs.x, lhs.y + rhs.y); - return result; -} - -DN_API DN_V2I32 operator*(DN_V2I32 lhs, DN_V2I32 rhs) -{ - DN_V2I32 result = DN_V2I32_From2N(lhs.x * rhs.x, lhs.y * rhs.y); - return result; -} - -DN_API DN_V2I32 operator*(DN_V2I32 lhs, DN_F32 rhs) -{ - DN_V2I32 result = DN_V2I32_From2N(lhs.x * rhs, lhs.y * rhs); - return result; -} - -DN_API DN_V2I32 operator*(DN_V2I32 lhs, int32_t rhs) -{ - DN_V2I32 result = DN_V2I32_From2N(lhs.x * rhs, lhs.y * rhs); - return result; -} - -DN_API DN_V2I32 operator/(DN_V2I32 lhs, DN_V2I32 rhs) -{ - DN_V2I32 result = DN_V2I32_From2N(lhs.x / rhs.x, lhs.y / rhs.y); - return result; -} - -DN_API DN_V2I32 operator/(DN_V2I32 lhs, DN_F32 rhs) -{ - DN_V2I32 result = DN_V2I32_From2N(lhs.x / rhs, lhs.y / rhs); - return result; -} - -DN_API DN_V2I32 operator/(DN_V2I32 lhs, int32_t rhs) -{ - DN_V2I32 result = DN_V2I32_From2N(lhs.x / rhs, lhs.y / rhs); - return result; -} - -DN_API DN_V2I32 &operator*=(DN_V2I32 &lhs, DN_V2I32 rhs) -{ - lhs = lhs * rhs; - return lhs; -} - -DN_API DN_V2I32 &operator*=(DN_V2I32 &lhs, DN_F32 rhs) -{ - lhs = lhs * rhs; - return lhs; -} - -DN_API DN_V2I32 &operator*=(DN_V2I32 &lhs, int32_t rhs) -{ - lhs = lhs * rhs; - return lhs; -} - -DN_API DN_V2I32 &operator/=(DN_V2I32 &lhs, DN_V2I32 rhs) -{ - lhs = lhs / rhs; - return lhs; -} - -DN_API DN_V2I32 &operator/=(DN_V2I32 &lhs, DN_F32 rhs) -{ - lhs = lhs / rhs; - return lhs; -} - -DN_API DN_V2I32 &operator/=(DN_V2I32 &lhs, int32_t rhs) -{ - lhs = lhs / rhs; - return lhs; -} - -DN_API DN_V2I32 &operator-=(DN_V2I32 &lhs, DN_V2I32 rhs) -{ - lhs = lhs - rhs; - return lhs; -} - -DN_API DN_V2I32 &operator+=(DN_V2I32 &lhs, DN_V2I32 rhs) -{ - lhs = lhs + rhs; - return lhs; -} - -DN_API DN_V2I32 DN_V2I32_Min(DN_V2I32 a, DN_V2I32 b) -{ - DN_V2I32 result = DN_V2I32_From2N(DN_Min(a.x, b.x), DN_Min(a.y, b.y)); - return result; -} - -DN_API DN_V2I32 DN_V2I32_Max(DN_V2I32 a, DN_V2I32 b) -{ - DN_V2I32 result = DN_V2I32_From2N(DN_Max(a.x, b.x), DN_Max(a.y, b.y)); - return result; -} - -DN_API DN_V2I32 DN_V2I32_Abs(DN_V2I32 a) -{ - DN_V2I32 result = DN_V2I32_From2N(DN_Abs(a.x), DN_Abs(a.y)); - return result; -} - -DN_API bool operator!=(DN_V2U16 lhs, DN_V2U16 rhs) -{ - bool result = !(lhs == rhs); - return result; -} - -DN_API bool operator==(DN_V2U16 lhs, DN_V2U16 rhs) -{ - bool result = (lhs.x == rhs.x) && (lhs.y == rhs.y); - return result; -} - -DN_API bool operator>=(DN_V2U16 lhs, DN_V2U16 rhs) -{ - bool result = (lhs.x >= rhs.x) && (lhs.y >= rhs.y); - return result; -} - -DN_API bool operator<=(DN_V2U16 lhs, DN_V2U16 rhs) -{ - bool result = (lhs.x <= rhs.x) && (lhs.y <= rhs.y); - return result; -} - -DN_API bool operator<(DN_V2U16 lhs, DN_V2U16 rhs) -{ - bool result = (lhs.x < rhs.x) && (lhs.y < rhs.y); - return result; -} - -DN_API bool operator>(DN_V2U16 lhs, DN_V2U16 rhs) -{ - bool result = (lhs.x > rhs.x) && (lhs.y > rhs.y); - return result; -} - -DN_API DN_V2U16 operator-(DN_V2U16 lhs, DN_V2U16 rhs) -{ - DN_V2U16 result = DN_V2U16_From2N(lhs.x - rhs.x, lhs.y - rhs.y); - return result; -} - -DN_API DN_V2U16 operator+(DN_V2U16 lhs, DN_V2U16 rhs) -{ - DN_V2U16 result = DN_V2U16_From2N(lhs.x + rhs.x, lhs.y + rhs.y); - return result; -} - -DN_API DN_V2U16 operator*(DN_V2U16 lhs, DN_V2U16 rhs) -{ - DN_V2U16 result = DN_V2U16_From2N(lhs.x * rhs.x, lhs.y * rhs.y); - return result; -} - -DN_API DN_V2U16 operator*(DN_V2U16 lhs, DN_F32 rhs) -{ - DN_V2U16 result = DN_V2U16_From2N(lhs.x * rhs, lhs.y * rhs); - return result; -} - -DN_API DN_V2U16 operator*(DN_V2U16 lhs, int32_t rhs) -{ - DN_V2U16 result = DN_V2U16_From2N(lhs.x * rhs, lhs.y * rhs); - return result; -} - -DN_API DN_V2U16 operator/(DN_V2U16 lhs, DN_V2U16 rhs) -{ - DN_V2U16 result = DN_V2U16_From2N(lhs.x / rhs.x, lhs.y / rhs.y); - return result; -} - -DN_API DN_V2U16 operator/(DN_V2U16 lhs, DN_F32 rhs) -{ - DN_V2U16 result = DN_V2U16_From2N(lhs.x / rhs, lhs.y / rhs); - return result; -} - -DN_API DN_V2U16 operator/(DN_V2U16 lhs, int32_t rhs) -{ - DN_V2U16 result = DN_V2U16_From2N(lhs.x / rhs, lhs.y / rhs); - return result; -} - -DN_API DN_V2U16 &operator*=(DN_V2U16 &lhs, DN_V2U16 rhs) -{ - lhs = lhs * rhs; - return lhs; -} - -DN_API DN_V2U16 &operator*=(DN_V2U16 &lhs, DN_F32 rhs) -{ - lhs = lhs * rhs; - return lhs; -} - -DN_API DN_V2U16 &operator*=(DN_V2U16 &lhs, int32_t rhs) -{ - lhs = lhs * rhs; - return lhs; -} - -DN_API DN_V2U16 &operator/=(DN_V2U16 &lhs, DN_V2U16 rhs) -{ - lhs = lhs / rhs; - return lhs; -} - -DN_API DN_V2U16 &operator/=(DN_V2U16 &lhs, DN_F32 rhs) -{ - lhs = lhs / rhs; - return lhs; -} - -DN_API DN_V2U16 &operator/=(DN_V2U16 &lhs, int32_t rhs) -{ - lhs = lhs / rhs; - return lhs; -} - -DN_API DN_V2U16 &operator-=(DN_V2U16 &lhs, DN_V2U16 rhs) -{ - lhs = lhs - rhs; - return lhs; -} - -DN_API DN_V2U16 &operator+=(DN_V2U16 &lhs, DN_V2U16 rhs) -{ - lhs = lhs + rhs; - return lhs; -} - -DN_API bool operator!=(DN_V2F32 lhs, DN_V2F32 rhs) -{ - bool result = !(lhs == rhs); - return result; -} - -DN_API bool operator==(DN_V2F32 lhs, DN_V2F32 rhs) -{ - bool result = (lhs.x == rhs.x) && (lhs.y == rhs.y); - return result; -} - -DN_API bool operator>=(DN_V2F32 lhs, DN_V2F32 rhs) -{ - bool result = (lhs.x >= rhs.x) && (lhs.y >= rhs.y); - return result; -} - -DN_API bool operator<=(DN_V2F32 lhs, DN_V2F32 rhs) -{ - bool result = (lhs.x <= rhs.x) && (lhs.y <= rhs.y); - return result; -} - -DN_API bool operator<(DN_V2F32 lhs, DN_V2F32 rhs) -{ - bool result = (lhs.x < rhs.x) && (lhs.y < rhs.y); - return result; -} - -DN_API bool operator>(DN_V2F32 lhs, DN_V2F32 rhs) -{ - bool result = (lhs.x > rhs.x) && (lhs.y > rhs.y); - return result; -} - -DN_API DN_V2F32 operator-(DN_V2F32 lhs) -{ - DN_V2F32 result = DN_V2F32_From2N(-lhs.x, -lhs.y); - return result; -} - -DN_API DN_V2F32 operator-(DN_V2F32 lhs, DN_V2F32 rhs) -{ - DN_V2F32 result = DN_V2F32_From2N(lhs.x - rhs.x, lhs.y - rhs.y); - return result; -} - -DN_API DN_V2F32 operator-(DN_V2F32 lhs, DN_V2I32 rhs) -{ - DN_V2F32 result = DN_V2F32_From2N(lhs.x - rhs.x, lhs.y - rhs.y); - return result; -} - -DN_API DN_V2F32 operator-(DN_V2F32 lhs, DN_F32 rhs) -{ - DN_V2F32 result = DN_V2F32_From2N(lhs.x - rhs, lhs.y - rhs); - return result; -} - -DN_API DN_V2F32 operator-(DN_V2F32 lhs, int32_t rhs) -{ - DN_V2F32 result = DN_V2F32_From2N(lhs.x - rhs, lhs.y - rhs); - return result; -} - -DN_API DN_V2F32 operator+(DN_V2F32 lhs, DN_V2F32 rhs) -{ - DN_V2F32 result = DN_V2F32_From2N(lhs.x + rhs.x, lhs.y + rhs.y); - return result; -} - -DN_API DN_V2F32 operator+(DN_V2F32 lhs, DN_V2I32 rhs) -{ - DN_V2F32 result = DN_V2F32_From2N(lhs.x + rhs.x, lhs.y + rhs.y); - return result; -} - -DN_API DN_V2F32 operator+(DN_V2F32 lhs, DN_F32 rhs) -{ - DN_V2F32 result = DN_V2F32_From2N(lhs.x + rhs, lhs.y + rhs); - return result; -} - -DN_API DN_V2F32 operator+(DN_V2F32 lhs, int32_t rhs) -{ - DN_V2F32 result = DN_V2F32_From2N(lhs.x + rhs, lhs.y + rhs); - return result; -} - -DN_API DN_V2F32 operator*(DN_V2F32 lhs, DN_V2F32 rhs) -{ - DN_V2F32 result = DN_V2F32_From2N(lhs.x * rhs.x, lhs.y * rhs.y); - return result; -} - -DN_API DN_V2F32 operator*(DN_V2F32 lhs, DN_V2I32 rhs) -{ - DN_V2F32 result = DN_V2F32_From2N(lhs.x * rhs.x, lhs.y * rhs.y); - return result; -} - -DN_API DN_V2F32 operator*(DN_V2F32 lhs, DN_F32 rhs) -{ - DN_V2F32 result = DN_V2F32_From2N(lhs.x * rhs, lhs.y * rhs); - return result; -} - -DN_API DN_V2F32 operator*(DN_V2F32 lhs, int32_t rhs) -{ - DN_V2F32 result = DN_V2F32_From2N(lhs.x * rhs, lhs.y * rhs); - return result; -} - -DN_API DN_V2F32 operator/(DN_V2F32 lhs, DN_V2F32 rhs) -{ - DN_V2F32 result = DN_V2F32_From2N(lhs.x / rhs.x, lhs.y / rhs.y); - return result; -} - -DN_API DN_V2F32 operator/(DN_V2F32 lhs, DN_V2I32 rhs) -{ - DN_V2F32 result = DN_V2F32_From2N(lhs.x / rhs.x, lhs.y / rhs.y); - return result; -} - -DN_API DN_V2F32 operator/(DN_V2F32 lhs, DN_F32 rhs) -{ - DN_V2F32 result = DN_V2F32_From2N(lhs.x / rhs, lhs.y / rhs); - return result; -} - -DN_API DN_V2F32 operator/(DN_V2F32 lhs, int32_t rhs) -{ - DN_V2F32 result = DN_V2F32_From2N(lhs.x / rhs, lhs.y / rhs); - return result; -} - -DN_API DN_V2F32 &operator*=(DN_V2F32 &lhs, DN_V2F32 rhs) -{ - lhs = lhs * rhs; - return lhs; -} - -DN_API DN_V2F32 &operator*=(DN_V2F32 &lhs, DN_V2I32 rhs) -{ - lhs = lhs * rhs; - return lhs; -} - -DN_API DN_V2F32 &operator*=(DN_V2F32 &lhs, DN_F32 rhs) -{ - lhs = lhs * rhs; - return lhs; -} - -DN_API DN_V2F32 &operator*=(DN_V2F32 &lhs, int32_t rhs) -{ - lhs = lhs * rhs; - return lhs; -} - -DN_API DN_V2F32 &operator/=(DN_V2F32 &lhs, DN_V2F32 rhs) -{ - lhs = lhs / rhs; - return lhs; -} - -DN_API DN_V2F32 &operator/=(DN_V2F32 &lhs, DN_V2I32 rhs) -{ - lhs = lhs / rhs; - return lhs; -} - -DN_API DN_V2F32 &operator/=(DN_V2F32 &lhs, DN_F32 rhs) -{ - lhs = lhs / rhs; - return lhs; -} - -DN_API DN_V2F32 &operator/=(DN_V2F32 &lhs, int32_t rhs) -{ - lhs = lhs / rhs; - return lhs; -} - -DN_API DN_V2F32 &operator-=(DN_V2F32 &lhs, DN_V2F32 rhs) -{ - lhs = lhs - rhs; - return lhs; -} - -DN_API DN_V2F32 &operator-=(DN_V2F32 &lhs, DN_V2I32 rhs) -{ - lhs = lhs - rhs; - return lhs; -} - -DN_API DN_V2F32 &operator-=(DN_V2F32 &lhs, DN_F32 rhs) -{ - lhs = lhs - rhs; - return lhs; -} - -DN_API DN_V2F32 &operator-=(DN_V2F32 &lhs, int32_t rhs) -{ - lhs = lhs - rhs; - return lhs; -} - -DN_API DN_V2F32 &operator+=(DN_V2F32 &lhs, DN_V2F32 rhs) -{ - lhs = lhs + rhs; - return lhs; -} - -DN_API DN_V2F32 &operator+=(DN_V2F32 &lhs, DN_V2I32 rhs) -{ - lhs = lhs + rhs; - return lhs; -} - -DN_API DN_V2F32 &operator+=(DN_V2F32 &lhs, DN_F32 rhs) -{ - lhs = lhs + rhs; - return lhs; -} - -DN_API DN_V2F32 &operator+=(DN_V2F32 &lhs, int32_t rhs) -{ - lhs = lhs + rhs; - return lhs; -} - -DN_API DN_V2F32 DN_V2F32_Min(DN_V2F32 a, DN_V2F32 b) -{ - DN_V2F32 result = DN_V2F32_From2N(DN_Min(a.x, b.x), DN_Min(a.y, b.y)); - return result; -} - -DN_API DN_V2F32 DN_V2F32_Max(DN_V2F32 a, DN_V2F32 b) -{ - DN_V2F32 result = DN_V2F32_From2N(DN_Max(a.x, b.x), DN_Max(a.y, b.y)); - return result; -} - -DN_API DN_V2F32 DN_V2F32_Abs(DN_V2F32 a) -{ - DN_V2F32 result = DN_V2F32_From2N(DN_Abs(a.x), DN_Abs(a.y)); - return result; -} - -DN_API DN_F32 DN_V2F32_Dot(DN_V2F32 a, DN_V2F32 b) -{ - // NOTE: Scalar projection of B onto A ///////////////////////////////////////////////////////// - // - // Scalar projection calculates the signed distance between `b` and `a` - // where `a` is a unit vector then, the dot product calculates the projection - // of `b` onto the infinite line that the direction of `a` represents. This - // calculation is the signed distance. - // - // signed_distance = dot_product(a, b) = (a.x * b.x) + (a.y * b.y) - // - // Y - // ^ b - // | /| - // | / | - // | / | - // | / | Projection - // | / | - // |/ V - // +--->--------> X - // . a . - // . . - // |------| <- Calculated signed distance - // - // The signed-ness of the result indicates the relationship: - // - // Distance <0 means `b` is behind `a` - // Distance >0 means `b` is in-front of `a` - // Distance ==0 means `b` is perpendicular to `a` - // - // If `a` is not normalized then the signed-ness of the result still holds - // however result no longer represents the actual distance between the - // 2 objects. One of the vectors must be normalised (e.g. turned into a unit - // vector). - // - // NOTE: DN_V projection ///////////////////////////////////////////////////////////////////// - // - // DN_V projection calculates the exact X,Y coordinates of where `b` meets - // `a` when it was projected. This is calculated by multipying the - // 'scalar projection' result by the unit vector of `a` - // - // vector_projection = a * signed_distance = a * dot_product(a, b) - - DN_F32 result = (a.x * b.x) + (a.y * b.y); - return result; -} - -DN_API DN_F32 DN_V2F32_LengthSq2V2(DN_V2F32 lhs, DN_V2F32 rhs) -{ - // NOTE: Pythagoras's theorem (a^2 + b^2 = c^2) without the square root - DN_F32 a = rhs.x - lhs.x; - DN_F32 b = rhs.y - lhs.y; - DN_F32 c_squared = DN_Squared(a) + DN_Squared(b); - DN_F32 result = c_squared; - return result; -} - -DN_API bool DN_V2F32_LengthSqIsWithin2V2(DN_V2F32 lhs, DN_V2F32 rhs, DN_F32 within_amount_sq) -{ - DN_F32 dist = DN_V2F32_LengthSq2V2(lhs, rhs); - bool result = dist <= within_amount_sq; - return result; -} - -DN_API DN_F32 DN_V2F32_Length2V2(DN_V2F32 lhs, DN_V2F32 rhs) -{ - DN_F32 result_squared = DN_V2F32_LengthSq2V2(lhs, rhs); - DN_F32 result = DN_SqrtF32(result_squared); - return result; -} - -DN_API DN_F32 DN_V2F32_LengthSq(DN_V2F32 lhs) -{ - // NOTE: Pythagoras's theorem without the square root - DN_F32 c_squared = DN_Squared(lhs.x) + DN_Squared(lhs.y); - DN_F32 result = c_squared; - return result; -} - -DN_API DN_F32 DN_V2F32_Length(DN_V2F32 lhs) -{ - DN_F32 c_squared = DN_V2F32_LengthSq(lhs); - DN_F32 result = DN_SqrtF32(c_squared); - return result; -} - -DN_API DN_V2F32 DN_V2F32_Normalise(DN_V2F32 a) -{ - DN_F32 length = DN_V2F32_Length(a); - DN_V2F32 result = a / length; - return result; -} - -DN_API DN_V2F32 DN_V2F32_Perpendicular(DN_V2F32 a) -{ - // NOTE: Matrix form of a 2D vector can be defined as - // - // x' = x cos(t) - y sin(t) - // y' = x sin(t) + y cos(t) - // - // Calculate a line perpendicular to a vector means rotating the vector by - // 90 degrees - // - // x' = x cos(90) - y sin(90) - // y' = x sin(90) + y cos(90) - // - // Where `cos(90) = 0` and `sin(90) = 1` then, - // - // x' = -y - // y' = +x - - DN_V2F32 result = DN_V2F32_From2N(-a.y, a.x); - return result; -} - -DN_API DN_V2F32 DN_V2F32_Reflect(DN_V2F32 in, DN_V2F32 surface) -{ - DN_V2F32 normal = DN_V2F32_Perpendicular(surface); - DN_V2F32 normal_norm = DN_V2F32_Normalise(normal); - DN_F32 signed_dist = DN_V2F32_Dot(in, normal_norm); - DN_V2F32 result = DN_V2F32_From2N(in.x, in.y + (-signed_dist * 2.f)); - return result; -} - -DN_API DN_F32 DN_V2F32_Area(DN_V2F32 a) -{ - DN_F32 result = a.w * a.h; - return result; -} - -DN_API bool operator!=(DN_V3F32 lhs, DN_V3F32 rhs) -{ - bool result = !(lhs == rhs); - return result; -} - -DN_API bool operator==(DN_V3F32 lhs, DN_V3F32 rhs) -{ - bool result = (lhs.x == rhs.x) && (lhs.y == rhs.y) && (lhs.z == rhs.z); - return result; -} - -DN_API bool operator>=(DN_V3F32 lhs, DN_V3F32 rhs) -{ - bool result = (lhs.x >= rhs.x) && (lhs.y >= rhs.y) && (lhs.z >= rhs.z); - return result; -} - -DN_API bool operator<=(DN_V3F32 lhs, DN_V3F32 rhs) -{ - bool result = (lhs.x <= rhs.x) && (lhs.y <= rhs.y) && (lhs.z <= rhs.z); - return result; -} - -DN_API bool operator<(DN_V3F32 lhs, DN_V3F32 rhs) -{ - bool result = (lhs.x < rhs.x) && (lhs.y < rhs.y) && (lhs.z < rhs.z); - return result; -} - -DN_API bool operator>(DN_V3F32 lhs, DN_V3F32 rhs) -{ - bool result = (lhs.x > rhs.x) && (lhs.y > rhs.y) && (lhs.z > rhs.z); - return result; -} - -DN_API DN_V3F32 operator-(DN_V3F32 lhs, DN_V3F32 rhs) -{ - DN_V3F32 result = DN_V3F32_From3N(lhs.x - rhs.x, lhs.y - rhs.y, lhs.z - rhs.z); - return result; -} - -DN_API DN_V3F32 operator-(DN_V3F32 lhs) -{ - DN_V3F32 result = DN_V3F32_From3N(-lhs.x, -lhs.y, -lhs.z); - return result; -} - -DN_API DN_V3F32 operator+(DN_V3F32 lhs, DN_V3F32 rhs) -{ - DN_V3F32 result = DN_V3F32_From3N(lhs.x + rhs.x, lhs.y + rhs.y, lhs.z + rhs.z); - return result; -} - -DN_API DN_V3F32 operator*(DN_V3F32 lhs, DN_V3F32 rhs) -{ - DN_V3F32 result = DN_V3F32_From3N(lhs.x * rhs.x, lhs.y * rhs.y, lhs.z * rhs.z); - return result; -} - -DN_API DN_V3F32 operator*(DN_V3F32 lhs, DN_F32 rhs) -{ - DN_V3F32 result = DN_V3F32_From3N(lhs.x * rhs, lhs.y * rhs, lhs.z * rhs); - return result; -} - -DN_API DN_V3F32 operator*(DN_V3F32 lhs, int32_t rhs) -{ - DN_V3F32 result = DN_V3F32_From3N(lhs.x * rhs, lhs.y * rhs, lhs.z * rhs); - return result; -} - -DN_API DN_V3F32 operator/(DN_V3F32 lhs, DN_V3F32 rhs) -{ - DN_V3F32 result = DN_V3F32_From3N(lhs.x / rhs.x, lhs.y / rhs.y, lhs.z / rhs.z); - return result; -} - -DN_API DN_V3F32 operator/(DN_V3F32 lhs, DN_F32 rhs) -{ - DN_V3F32 result = DN_V3F32_From3N(lhs.x / rhs, lhs.y / rhs, lhs.z / rhs); - return result; -} - -DN_API DN_V3F32 operator/(DN_V3F32 lhs, int32_t rhs) -{ - DN_V3F32 result = DN_V3F32_From3N(lhs.x / rhs, lhs.y / rhs, lhs.z / rhs); - return result; -} - -DN_API DN_V3F32 &operator*=(DN_V3F32 &lhs, DN_V3F32 rhs) -{ - lhs = lhs * rhs; - return lhs; -} - -DN_API DN_V3F32 &operator*=(DN_V3F32 &lhs, DN_F32 rhs) -{ - lhs = lhs * rhs; - return lhs; -} - -DN_API DN_V3F32 &operator*=(DN_V3F32 &lhs, int32_t rhs) -{ - lhs = lhs * rhs; - return lhs; -} - -DN_API DN_V3F32 &operator/=(DN_V3F32 &lhs, DN_V3F32 rhs) -{ - lhs = lhs / rhs; - return lhs; -} - -DN_API DN_V3F32 &operator/=(DN_V3F32 &lhs, DN_F32 rhs) -{ - lhs = lhs / rhs; - return lhs; -} - -DN_API DN_V3F32 &operator/=(DN_V3F32 &lhs, int32_t rhs) -{ - lhs = lhs / rhs; - return lhs; -} - -DN_API DN_V3F32 &operator-=(DN_V3F32 &lhs, DN_V3F32 rhs) -{ - lhs = lhs - rhs; - return lhs; -} - -DN_API DN_V3F32 &operator+=(DN_V3F32 &lhs, DN_V3F32 rhs) -{ - lhs = lhs + rhs; - return lhs; -} - -DN_API DN_F32 DN_V3_LengthSq(DN_V3F32 a) -{ - DN_F32 result = DN_Squared(a.x) + DN_Squared(a.y) + DN_Squared(a.z); - return result; -} - -DN_API DN_F32 DN_V3_Length(DN_V3F32 a) -{ - DN_F32 length_sq = DN_Squared(a.x) + DN_Squared(a.y) + DN_Squared(a.z); - DN_F32 result = DN_SqrtF32(length_sq); - return result; -} - -DN_API DN_V3F32 DN_V3_Normalise(DN_V3F32 a) -{ - DN_F32 length = DN_V3_Length(a); - DN_V3F32 result = a / length; - return result; -} - -DN_API DN_V4F32 DN_V4F32_FromRGBU32(DN_U32 u32) -{ - DN_U8 r = (DN_U8)((u32 & 0x00FF0000) >> 16); - DN_U8 g = (DN_U8)((u32 & 0x0000FF00) >> 8); - DN_U8 b = (DN_U8)((u32 & 0x000000FF) >> 0); - DN_V4F32 result = DN_V4F32_FromRGBU8(r, g, b); - return result; -} - -DN_API DN_V4F32 DN_V4F32_FromRGBAU32(DN_U32 u32) -{ - DN_U8 r = (DN_U8)((u32 & 0xFF000000) >> 24); - DN_U8 g = (DN_U8)((u32 & 0x00FF0000) >> 16); - DN_U8 b = (DN_U8)((u32 & 0x0000FF00) >> 8); - DN_U8 a = (DN_U8)((u32 & 0x000000FF) >> 0); - DN_V4F32 result = DN_V4F32_FromRGBAU8(r, g, b, a); - return result; -} - -DN_API bool operator==(DN_V4F32 lhs, DN_V4F32 rhs) -{ - bool result = (lhs.x == rhs.x) && (lhs.y == rhs.y) && (lhs.z == rhs.z) && (lhs.w == rhs.w); - return result; -} - -DN_API bool operator!=(DN_V4F32 lhs, DN_V4F32 rhs) -{ - bool result = !(lhs == rhs); - return result; -} - -DN_API bool operator>=(DN_V4F32 lhs, DN_V4F32 rhs) -{ - bool result = (lhs.x >= rhs.x) && (lhs.y >= rhs.y) && (lhs.z >= rhs.z) && (lhs.w >= rhs.w); - return result; -} - -DN_API bool operator<=(DN_V4F32 lhs, DN_V4F32 rhs) -{ - bool result = (lhs.x <= rhs.x) && (lhs.y <= rhs.y) && (lhs.z <= rhs.z) && (lhs.w <= rhs.w); - return result; -} - -DN_API bool operator<(DN_V4F32 lhs, DN_V4F32 rhs) -{ - bool result = (lhs.x < rhs.x) && (lhs.y < rhs.y) && (lhs.z < rhs.z) && (lhs.w < rhs.w); - return result; -} - -DN_API bool operator>(DN_V4F32 lhs, DN_V4F32 rhs) -{ - bool result = (lhs.x > rhs.x) && (lhs.y > rhs.y) && (lhs.z > rhs.z) && (lhs.w > rhs.w); - return result; -} - -DN_API DN_V4F32 operator-(DN_V4F32 lhs, DN_V4F32 rhs) -{ - DN_V4F32 result = DN_V4F32_From4N(lhs.x - rhs.x, lhs.y - rhs.y, lhs.z - rhs.z, lhs.w - rhs.w); - return result; -} - -DN_API DN_V4F32 operator-(DN_V4F32 lhs) -{ - DN_V4F32 result = DN_V4F32_From4N(-lhs.x, -lhs.y, -lhs.z, -lhs.w); - return result; -} - -DN_API DN_V4F32 operator+(DN_V4F32 lhs, DN_V4F32 rhs) -{ - DN_V4F32 result = DN_V4F32_From4N(lhs.x + rhs.x, lhs.y + rhs.y, lhs.z + rhs.z, lhs.w + rhs.w); - return result; -} - -DN_API DN_V4F32 operator*(DN_V4F32 lhs, DN_V4F32 rhs) -{ - DN_V4F32 result = DN_V4F32_From4N(lhs.x * rhs.x, lhs.y * rhs.y, lhs.z * rhs.z, lhs.w * rhs.w); - return result; -} - -DN_API DN_V4F32 operator*(DN_V4F32 lhs, DN_F32 rhs) -{ - DN_V4F32 result = DN_V4F32_From4N(lhs.x * rhs, lhs.y * rhs, lhs.z * rhs, lhs.w * rhs); - return result; -} - -DN_API DN_V4F32 operator*(DN_V4F32 lhs, int32_t rhs) -{ - DN_V4F32 result = DN_V4F32_From4N(lhs.x * rhs, lhs.y * rhs, lhs.z * rhs, lhs.w * rhs); - return result; -} - -DN_API DN_V4F32 operator/(DN_V4F32 lhs, DN_F32 rhs) -{ - DN_V4F32 result = DN_V4F32_From4N(lhs.x / rhs, lhs.y / rhs, lhs.z / rhs, lhs.w / rhs); - return result; -} - -DN_API DN_V4F32 &operator*=(DN_V4F32 &lhs, DN_V4F32 rhs) -{ - lhs = lhs * rhs; - return lhs; -} - -DN_API DN_V4F32 &operator*=(DN_V4F32 &lhs, DN_F32 rhs) -{ - lhs = lhs * rhs; - return lhs; -} - -DN_API DN_V4F32 &operator*=(DN_V4F32 &lhs, int32_t rhs) -{ - lhs = lhs * rhs; - return lhs; -} - -DN_API DN_V4F32 &operator-=(DN_V4F32 &lhs, DN_V4F32 rhs) -{ - lhs = lhs - rhs; - return lhs; -} - -DN_API DN_V4F32 &operator+=(DN_V4F32 &lhs, DN_V4F32 rhs) -{ - lhs = lhs + rhs; - return lhs; -} - -DN_API DN_F32 DN_V4F32Dot(DN_V4F32 a, DN_V4F32 b) -{ - DN_F32 result = (a.x * b.x) + (a.y * b.y) + (a.z * b.z) + (a.w * b.w); - return result; -} - -DN_API DN_M4 DN_M4_Identity() -{ - DN_M4 result = - { - { - {1, 0, 0, 0}, - {0, 1, 0, 0}, - {0, 0, 1, 0}, - {0, 0, 0, 1}, - } - }; - - return result; -} - -DN_API DN_M4 DN_M4_ScaleF(DN_F32 x, DN_F32 y, DN_F32 z) -{ - DN_M4 result = - { - { - {x, 0, 0, 0}, - {0, y, 0, 0}, - {0, 0, z, 0}, - {0, 0, 0, 1}, - } - }; - - return result; -} - -DN_API DN_M4 DN_M4_Scale(DN_V3F32 xyz) -{ - DN_M4 result = - { - { - {xyz.x, 0, 0, 0}, - {0, xyz.y, 0, 0}, - {0, 0, xyz.z, 0}, - {0, 0, 0, 1}, - } - }; - - return result; -} - -DN_API DN_M4 DN_M4_TranslateF(DN_F32 x, DN_F32 y, DN_F32 z) -{ - DN_M4 result = - { - { - {1, 0, 0, 0}, - {0, 1, 0, 0}, - {0, 0, 1, 0}, - {x, y, z, 1}, - } - }; - - return result; -} - -DN_API DN_M4 DN_M4_Translate(DN_V3F32 xyz) -{ - DN_M4 result = - { - { - {1, 0, 0, 0}, - {0, 1, 0, 0}, - {0, 0, 1, 0}, - {xyz.x, xyz.y, xyz.z, 1}, - } - }; - - return result; -} - -DN_API DN_M4 DN_M4_Transpose(DN_M4 mat) -{ - DN_M4 result = {}; - for (int col = 0; col < 4; col++) - for (int row = 0; row < 4; row++) - result.columns[col][row] = mat.columns[row][col]; - return result; -} - -DN_API DN_M4 DN_M4_Rotate(DN_V3F32 axis01, DN_F32 radians) -{ - DN_AssertF(DN_Abs(DN_V3_Length(axis01) - 1.f) <= 0.01f, - "Rotation axis must be normalised, length = %f", - DN_V3_Length(axis01)); - - DN_F32 sin = DN_SinF32(radians); - DN_F32 cos = DN_CosF32(radians); - DN_F32 one_minus_cos = 1.f - cos; - - DN_F32 x = axis01.x; - DN_F32 y = axis01.y; - DN_F32 z = axis01.z; - DN_F32 x2 = DN_Squared(x); - DN_F32 y2 = DN_Squared(y); - DN_F32 z2 = DN_Squared(z); - - DN_M4 result = - { - { - {cos + x2 * one_minus_cos, y * x * one_minus_cos + z * sin, z * x * one_minus_cos - y * sin, 0}, // Col 1 - {x * y * one_minus_cos - z * sin, cos + y2 * one_minus_cos, z * y * one_minus_cos + x * sin, 0}, // Col 2 - {x * z * one_minus_cos + y * sin, y * z * one_minus_cos - x * sin, cos + z2 * one_minus_cos, 0}, // Col 3 - {0, 0, 0, 1}, // Col 4 - } - }; - - return result; -} - -DN_API DN_M4 DN_M4_Orthographic(DN_F32 left, DN_F32 right, DN_F32 bottom, DN_F32 top, DN_F32 z_near, DN_F32 z_far) -{ - // NOTE: Here is the matrix in column major for readability. Below it's - // transposed due to how you have to declare column major matrices in C/C++. - // - // m = [2/r-l, 0, 0, -1*(r+l)/(r-l)] - // [0, 2/t-b, 0, 1*(t+b)/(t-b)] - // [0, 0, -2/f-n, -1*(f+n)/(f-n)] - // [0, 0, 0, 1 ] - - DN_M4 result = - { - { - {2.f / (right - left), 0.f, 0.f, 0.f}, - {0.f, 2.f / (top - bottom), 0.f, 0.f}, - {0.f, 0.f, -2.f / (z_far - z_near), 0.f}, - {(-1.f * (right + left)) / (right - left), (-1.f * (top + bottom)) / (top - bottom), (-1.f * (z_far + z_near)) / (z_far - z_near), 1.f}, - } - }; - - return result; -} - -DN_API DN_M4 DN_M4_Perspective(DN_F32 fov /*radians*/, DN_F32 aspect, DN_F32 z_near, DN_F32 z_far) -{ - DN_F32 tan_fov = DN_TanF32(fov / 2.f); - DN_M4 result = - { - { - {1.f / (aspect * tan_fov), 0.f, 0.f, 0.f}, - {0, 1.f / tan_fov, 0.f, 0.f}, - {0.f, 0.f, (z_near + z_far) / (z_near - z_far), -1.f}, - {0.f, 0.f, (2.f * z_near * z_far) / (z_near - z_far), 0.f}, - } - }; - - return result; -} - -DN_API DN_M4 DN_M4_Add(DN_M4 lhs, DN_M4 rhs) -{ - DN_M4 result; - for (int col = 0; col < 4; col++) - for (int it = 0; it < 4; it++) - result.columns[col][it] = lhs.columns[col][it] + rhs.columns[col][it]; - return result; -} - -DN_API DN_M4 DN_M4_Sub(DN_M4 lhs, DN_M4 rhs) -{ - DN_M4 result; - for (int col = 0; col < 4; col++) - for (int it = 0; it < 4; it++) - result.columns[col][it] = lhs.columns[col][it] - rhs.columns[col][it]; - return result; -} - -DN_API DN_M4 DN_M4_Mul(DN_M4 lhs, DN_M4 rhs) -{ - DN_M4 result; - for (int col = 0; col < 4; col++) { - for (int row = 0; row < 4; row++) { - DN_F32 sum = 0; - for (int f32_it = 0; f32_it < 4; f32_it++) - sum += lhs.columns[f32_it][row] * rhs.columns[col][f32_it]; - - result.columns[col][row] = sum; - } - } - return result; -} - -DN_API DN_M4 DN_M4_Div(DN_M4 lhs, DN_M4 rhs) -{ - DN_M4 result; - for (int col = 0; col < 4; col++) - for (int it = 0; it < 4; it++) - result.columns[col][it] = lhs.columns[col][it] / rhs.columns[col][it]; - return result; -} - -DN_API DN_M4 DN_M4_AddF(DN_M4 lhs, DN_F32 rhs) -{ - DN_M4 result; - for (int col = 0; col < 4; col++) - for (int it = 0; it < 4; it++) - result.columns[col][it] = lhs.columns[col][it] + rhs; - return result; -} - -DN_API DN_M4 DN_M4_SubF(DN_M4 lhs, DN_F32 rhs) -{ - DN_M4 result; - for (int col = 0; col < 4; col++) - for (int it = 0; it < 4; it++) - result.columns[col][it] = lhs.columns[col][it] - rhs; - return result; -} - -DN_API DN_M4 DN_M4_MulF(DN_M4 lhs, DN_F32 rhs) -{ - DN_M4 result; - for (int col = 0; col < 4; col++) - for (int it = 0; it < 4; it++) - result.columns[col][it] = lhs.columns[col][it] * rhs; - return result; -} - -DN_API DN_M4 DN_M4_DivF(DN_M4 lhs, DN_F32 rhs) -{ - DN_M4 result; - for (int col = 0; col < 4; col++) - for (int it = 0; it < 4; it++) - result.columns[col][it] = lhs.columns[col][it] / rhs; - return result; -} - -DN_API DN_Str8x256 DN_M4_ColumnMajorString(DN_M4 mat) -{ - DN_Str8x256 result = {}; - for (int row = 0; row < 4; row++) { - for (int it = 0; it < 4; it++) { - if (it == 0) - DN_FmtAppend(result.data, &result.size, sizeof(result.data), "|"); - DN_FmtAppend(result.data, &result.size, sizeof(result.data), "%.5f", mat.columns[it][row]); - if (it != 3) - DN_FmtAppend(result.data, &result.size, sizeof(result.data), ", "); - else - DN_FmtAppend(result.data, &result.size, sizeof(result.data), "|\n"); - } - } - return result; -} - -DN_API bool operator==(DN_M2x3 const &lhs, DN_M2x3 const &rhs) -{ - bool result = DN_Memcmp(lhs.e, rhs.e, sizeof(lhs.e[0]) * DN_ArrayCountU(lhs.e)) == 0; - return result; -} - -DN_API bool operator!=(DN_M2x3 const &lhs, DN_M2x3 const &rhs) -{ - bool result = !(lhs == rhs); - return result; -} - -DN_API DN_M2x3 DN_M2x3_Identity() -{ - DN_M2x3 result = { - { - 1, - 0, - 0, - 0, - 1, - 0, - } - }; - return result; -} - -DN_API DN_M2x3 DN_M2x3_Translate(DN_V2F32 offset) -{ - DN_M2x3 result = { - { - 1, - 0, - offset.x, - 0, - 1, - offset.y, - } - }; - return result; -} - -DN_API DN_M2x3 DN_M2x3_Scale(DN_V2F32 scale) -{ - DN_M2x3 result = { - { - scale.x, - 0, - 0, - 0, - scale.y, - 0, - } - }; - return result; -} - -DN_API DN_M2x3 DN_M2x3_Rotate(DN_F32 radians) -{ - DN_M2x3 result = { - { - DN_CosF32(radians), - DN_SinF32(radians), - 0, - -DN_SinF32(radians), - DN_CosF32(radians), - 0, - } - }; - return result; -} - -DN_API DN_M2x3 DN_M2x3_Mul(DN_M2x3 m1, DN_M2x3 m2) -{ - // NOTE: Ordinarily you can't multiply M2x3 with M2x3 because column count - // (3) != row count (2). We pretend we have two 3x3 matrices with the last - // row set to [0 0 1] and perform a 3x3 matrix multiply. - // - // | (0)a (1)b (2)c | | (0)g (1)h (2)i | - // | (3)d (4)e (5)f | x | (3)j (4)k (5)l | - // | (6)0 (7)0 (8)1 | | (6)0 (7)0 (8)1 | - - DN_M2x3 result = { - { - m1.e[0] * m2.e[0] + m1.e[1] * m2.e[3], // a*g + b*j + c*0[omitted], - m1.e[0] * m2.e[1] + m1.e[1] * m2.e[4], // a*h + b*k + c*0[omitted], - m1.e[0] * m2.e[2] + m1.e[1] * m2.e[5] + m1.e[2], // a*i + b*l + c*1, - - m1.e[3] * m2.e[0] + m1.e[4] * m2.e[3], // d*g + e*j + f*0[omitted], - m1.e[3] * m2.e[1] + m1.e[4] * m2.e[4], // d*h + e*k + f*0[omitted], - m1.e[3] * m2.e[2] + m1.e[4] * m2.e[5] + m1.e[5], // d*i + e*l + f*1, - } - }; - - return result; -} - -DN_API DN_V2F32 DN_M2x3_Mul2F32(DN_M2x3 m1, DN_F32 x, DN_F32 y) -{ - // NOTE: Ordinarily you can't multiply M2x3 with V2 because column count (3) - // != row count (2). We pretend we have a V3 with `z` set to `1`. - // - // | (0)a (1)b (2)c | | x | - // | (3)d (4)e (5)f | x | y | - // | 1 | - - DN_V2F32 result = { - { - m1.e[0] * x + m1.e[1] * y + m1.e[2], // a*x + b*y + c*1 - m1.e[3] * x + m1.e[4] * y + m1.e[5], // d*x + e*y + f*1 - } - }; - return result; -} - -DN_API DN_V2F32 DN_M2x3_MulV2(DN_M2x3 m1, DN_V2F32 v2) -{ - DN_V2F32 result = DN_M2x3_Mul2F32(m1, v2.x, v2.y); - return result; -} - -DN_API bool operator==(const DN_Rect &lhs, const DN_Rect &rhs) -{ - bool result = (lhs.pos == rhs.pos) && (lhs.size == rhs.size); - return result; -} - -DN_API DN_V2F32 DN_Rect_Center(DN_Rect rect) -{ - DN_V2F32 result = rect.pos + (rect.size * .5f); - return result; -} - -DN_API bool DN_Rect_ContainsPoint(DN_Rect rect, DN_V2F32 p) -{ - DN_V2F32 min = rect.pos; - DN_V2F32 max = rect.pos + rect.size; - bool result = (p.x >= min.x && p.x <= max.x && p.y >= min.y && p.y <= max.y); - return result; -} - -DN_API bool DN_Rect_ContainsRect(DN_Rect a, DN_Rect b) -{ - DN_V2F32 a_min = a.pos; - DN_V2F32 a_max = a.pos + a.size; - DN_V2F32 b_min = b.pos; - DN_V2F32 b_max = b.pos + b.size; - bool result = (b_min >= a_min && b_max <= a_max); - return result; -} - -DN_API DN_Rect DN_Rect_Expand(DN_Rect a, DN_F32 amount) -{ - DN_Rect result = a; - result.pos -= amount; - result.size += (amount * 2.f); - return result; -} - -DN_API DN_Rect DN_Rect_ExpandV2(DN_Rect a, DN_V2F32 amount) -{ - DN_Rect result = a; - result.pos -= amount; - result.size += (amount * 2.f); - return result; -} - -DN_API bool DN_Rect_Intersects(DN_Rect a, DN_Rect b) -{ - DN_V2F32 a_min = a.pos; - DN_V2F32 a_max = a.pos + a.size; - DN_V2F32 b_min = b.pos; - DN_V2F32 b_max = b.pos + b.size; - bool has_size = a.size.x && a.size.y && b.size.x && b.size.y; - bool result = false; - if (has_size) - result = (a_min.x <= b_max.x && a_max.x >= b_min.x) && - (a_min.y <= b_max.y && a_max.y >= b_min.y); - return result; -} - -DN_API DN_Rect DN_Rect_Intersection(DN_Rect a, DN_Rect b) -{ - DN_Rect result = DN_Rect_From2V2(a.pos, DN_V2F32_From1N(0)); - if (DN_Rect_Intersects(a, b)) { - DN_V2F32 a_min = a.pos; - DN_V2F32 a_max = a.pos + a.size; - DN_V2F32 b_min = b.pos; - DN_V2F32 b_max = b.pos + b.size; - - DN_V2F32 min = {}; - DN_V2F32 max = {}; - min.x = DN_Max(a_min.x, b_min.x); - min.y = DN_Max(a_min.y, b_min.y); - max.x = DN_Min(a_max.x, b_max.x); - max.y = DN_Min(a_max.y, b_max.y); - result = DN_Rect_From2V2(min, max - min); - } - return result; -} - -DN_API DN_Rect DN_Rect_Union(DN_Rect a, DN_Rect b) -{ - DN_V2F32 a_min = a.pos; - DN_V2F32 a_max = a.pos + a.size; - DN_V2F32 b_min = b.pos; - DN_V2F32 b_max = b.pos + b.size; - - DN_V2F32 min, max; - min.x = DN_Min(a_min.x, b_min.x); - min.y = DN_Min(a_min.y, b_min.y); - max.x = DN_Max(a_max.x, b_max.x); - max.y = DN_Max(a_max.y, b_max.y); - DN_Rect result = DN_Rect_From2V2(min, max - min); - return result; -} - -DN_API DN_RectMinMax DN_Rect_MinMax(DN_Rect a) -{ - DN_RectMinMax result = {}; - result.min = a.pos; - result.max = a.pos + a.size; - return result; -} - -DN_API DN_F32 DN_Rect_Area(DN_Rect a) -{ - DN_F32 result = a.size.w * a.size.h; - return result; -} - -DN_API DN_Rect DN_Rect_CutLeftClip(DN_Rect *rect, DN_F32 amount, DN_RectCutClip clip) -{ - DN_F32 min_x = rect->pos.x; - DN_F32 max_x = rect->pos.x + rect->size.w; - DN_F32 result_max_x = min_x + amount; - if (clip) - result_max_x = DN_Min(result_max_x, max_x); - DN_Rect result = DN_Rect_From4N(min_x, rect->pos.y, result_max_x - min_x, rect->size.h); - rect->pos.x = result_max_x; - rect->size.w = max_x - result_max_x; - return result; -} - -DN_API DN_Rect DN_Rect_CutRightClip(DN_Rect *rect, DN_F32 amount, DN_RectCutClip clip) -{ - DN_F32 min_x = rect->pos.x; - DN_F32 max_x = rect->pos.x + rect->size.w; - DN_F32 result_min_x = max_x - amount; - if (clip) - result_min_x = DN_Max(result_min_x, 0); - DN_Rect result = DN_Rect_From4N(result_min_x, rect->pos.y, max_x - result_min_x, rect->size.h); - rect->size.w = result_min_x - min_x; - return result; -} - -DN_API DN_Rect DN_Rect_CutTopClip(DN_Rect *rect, DN_F32 amount, DN_RectCutClip clip) -{ - DN_F32 min_y = rect->pos.y; - DN_F32 max_y = rect->pos.y + rect->size.h; - DN_F32 result_max_y = min_y + amount; - if (clip) - result_max_y = DN_Min(result_max_y, max_y); - DN_Rect result = DN_Rect_From4N(rect->pos.x, min_y, rect->size.w, result_max_y - min_y); - rect->pos.y = result_max_y; - rect->size.h = max_y - result_max_y; - return result; -} - -DN_API DN_Rect DN_Rect_CutBottomClip(DN_Rect *rect, DN_F32 amount, DN_RectCutClip clip) -{ - DN_F32 min_y = rect->pos.y; - DN_F32 max_y = rect->pos.y + rect->size.h; - DN_F32 result_min_y = max_y - amount; - if (clip) - result_min_y = DN_Max(result_min_y, 0); - DN_Rect result = DN_Rect_From4N(rect->pos.x, result_min_y, rect->size.w, max_y - result_min_y); - rect->size.h = result_min_y - min_y; - return result; -} - -DN_API DN_Rect DN_RectCut_Cut(DN_RectCut rect_cut, DN_V2F32 size, DN_RectCutClip clip) -{ - DN_Rect result = {}; - if (rect_cut.rect) { - switch (rect_cut.side) { - case DN_RectCutSide_Left: result = DN_Rect_CutLeftClip(rect_cut.rect, size.w, clip); break; - case DN_RectCutSide_Right: result = DN_Rect_CutRightClip(rect_cut.rect, size.w, clip); break; - case DN_RectCutSide_Top: result = DN_Rect_CutTopClip(rect_cut.rect, size.h, clip); break; - case DN_RectCutSide_Bottom: result = DN_Rect_CutBottomClip(rect_cut.rect, size.h, clip); break; - } - } - return result; -} - -DN_API DN_V2F32 DN_Rect_InterpolatedPoint(DN_Rect rect, DN_V2F32 t01) -{ - DN_V2F32 result = DN_V2F32_From2N(rect.pos.w + (rect.size.w * t01.x), - rect.pos.h + (rect.size.h * t01.y)); - return result; -} - -DN_API DN_V2F32 DN_Rect_TopLeft(DN_Rect rect) -{ - DN_V2F32 result = DN_Rect_InterpolatedPoint(rect, DN_V2F32_From2N(0, 0)); - return result; -} - -DN_API DN_V2F32 DN_Rect_TopRight(DN_Rect rect) -{ - DN_V2F32 result = DN_Rect_InterpolatedPoint(rect, DN_V2F32_From2N(1, 0)); - return result; -} - -DN_API DN_V2F32 DN_Rect_BottomLeft(DN_Rect rect) -{ - DN_V2F32 result = DN_Rect_InterpolatedPoint(rect, DN_V2F32_From2N(0, 1)); - return result; -} - -DN_API DN_V2F32 DN_Rect_BottomRight(DN_Rect rect) -{ - DN_V2F32 result = DN_Rect_InterpolatedPoint(rect, DN_V2F32_From2N(1, 1)); - return result; -} - -DN_API DN_RaycastLineIntersectV2Result DN_Raycast_LineIntersectV2(DN_V2F32 origin_a, DN_V2F32 dir_a, DN_V2F32 origin_b, DN_V2F32 dir_b) -{ - // NOTE: Parametric equation of a line - // - // p = o + (t*d) - // - // - o is the starting 2d point - // - d is the direction of the line - // - t is a scalar that scales along the direction of the point - // - // To determine if a ray intersections a ray, we want to solve - // - // (o_a + (t_a * d_a)) = (o_b + (t_b * d_b)) - // - // Where '_a' and '_b' represent the 1st and 2nd point's origin, direction - // and 't' components respectively. This is 2 equations with 2 unknowns - // (`t_a` and `t_b`) which we can solve for by expressing the equation in - // terms of `t_a` and `t_b`. - // - // Working that math out produces the formula below for 't'. - - DN_RaycastLineIntersectV2Result result = {}; - DN_F32 denominator = ((dir_b.y * dir_a.x) - (dir_b.x * dir_a.y)); - if (denominator != 0.0f) { - result.t_a = (((origin_a.y - origin_b.y) * dir_b.x) + ((origin_b.x - origin_a.x) * dir_b.y)) / denominator; - result.t_b = (((origin_a.y - origin_b.y) * dir_a.x) + ((origin_b.x - origin_a.x) * dir_a.y)) / denominator; - result.hit = true; - } - return result; -} - -DN_API DN_V2F32 DN_Lerp_V2F32(DN_V2F32 a, DN_F32 t, DN_V2F32 b) -{ - DN_V2F32 result = {}; - result.x = a.x + ((b.x - a.x) * t); - result.y = a.y + ((b.y - a.y) * t); - return result; -} - -DN_API DN_F32 DN_Lerp_F32(DN_F32 a, DN_F32 t, DN_F32 b) -{ - DN_F32 result = a + ((b - a) * t); - return result; -} #define DN_ASYNC_CPP -#if defined(_CLANGD) - // DN: Single header generator commented out this header => #include "../dn_base_inc.h" - // DN: Single header generator commented out this header => #include "../dn_os_inc.h" - // DN: Single header generator commented out this header => #include "dn_async.h" -#if !defined(DN_ASYNC_H) -#define DN_ASYNC_H - -#if defined(_CLANGD) - // DN: Single header generator commented out this header => #include "../dn_base_inc.h" - // DN: Single header generator commented out this header => #include "../dn_os_inc.h" -#endif - -enum DN_ASYNCPriority -{ - DN_ASYNCPriority_Low, - DN_ASYNCPriority_High, - DN_ASYNCPriority_Count, -}; - -struct DN_ASYNCCore -{ - DN_OSMutex ring_mutex; - DN_OSConditionVariable ring_write_cv; - DN_OSSemaphore worker_sem; - DN_Ring ring; - DN_OSThread *threads; - DN_U32 thread_count; - DN_U32 busy_threads; - DN_U32 join_threads; -}; - -struct DN_ASYNCWorkArgs -{ - DN_OSThread *thread; - void *input; -}; - -typedef void(DN_ASYNCWorkFunc)(DN_ASYNCWorkArgs work_args); - -struct DN_ASYNCWork -{ - DN_ASYNCWorkFunc *func; - void *input; - void *output; -}; - -struct DN_ASYNCTask -{ - bool queued; - DN_ASYNCWork work; - DN_OSSemaphore completion_sem; -}; - -DN_API void DN_ASYNC_Init (DN_ASYNCCore *async, char *base, DN_USize base_size, DN_OSThread *threads, DN_U32 threads_size); -DN_API void DN_ASYNC_Deinit (DN_ASYNCCore *async); -DN_API bool DN_ASYNC_QueueWork(DN_ASYNCCore *async, DN_ASYNCWorkFunc *func, void *input, DN_U64 wait_time_ms); -DN_API DN_ASYNCTask DN_ASYNC_QueueTask(DN_ASYNCCore *async, DN_ASYNCWorkFunc *func, void *input, DN_U64 wait_time_ms); -DN_API void DN_ASYNC_WaitTask (DN_OSSemaphore *sem, DN_U32 timeout_ms); - -#endif // DN_ASYNC_H -#endif +// DN: Single header generator commented out => #if defined(_CLANGD) +// #define DN_H_WITH_OS 1 +// #include "../dn.h" +// #include "dn_async.h" +// #endif static DN_I32 DN_ASYNC_ThreadEntryPoint_(DN_OSThread *thread) { - DN_OS_ThreadSetName(DN_Str8FromPtr(thread->name.data, thread->name.size)); + DN_OS_ThreadSetNameFmt("%.*s", DN_Str8PrintFmt(thread->name)); DN_ASYNCCore *async = DN_Cast(DN_ASYNCCore *) thread->user_context; DN_Ring *ring = &async->ring; for (;;) { @@ -20568,8 +24,8 @@ static DN_I32 DN_ASYNC_ThreadEntryPoint_(DN_OSThread *thread) DN_ASYNCTask task = {}; for (DN_OS_MutexScope(&async->ring_mutex)) { - if (DN_Ring_HasData(ring, sizeof(task))) - DN_Ring_Read(ring, &task, sizeof(task)); + if (DN_RingHasData(ring, sizeof(task))) + DN_RingRead(ring, &task, sizeof(task)); } if (task.work.func) { @@ -20602,9 +58,8 @@ DN_API void DN_ASYNC_Init(DN_ASYNCCore *async, char *base, DN_USize base_size, D async->thread_count = threads_size; async->threads = threads; for (DN_ForIndexU(index, async->thread_count)) { - DN_OSThread *thread = async->threads + index; - DN_FmtAppend(thread->name.data, &thread->name.size, DN_ArrayCountU(thread->name.data), "ASYNC W%zu", index); - DN_OS_ThreadInit(thread, DN_ASYNC_ThreadEntryPoint_, async); + DN_OSThread *thread = async->threads + index; + DN_OS_ThreadInit(thread, DN_ASYNC_ThreadEntryPoint_, nullptr, async); } } @@ -20614,7 +69,7 @@ DN_API void DN_ASYNC_Deinit(DN_ASYNCCore *async) DN_AtomicSetValue32(&async->join_threads, true); DN_OS_SemaphoreIncrement(&async->worker_sem, async->thread_count); for (DN_ForItSize(it, DN_OSThread, async->threads, async->thread_count)) - DN_OS_ThreadDeinit(it.data); + DN_OS_ThreadJoin(it.data, DN_TCDeinitArenas_Yes); } static bool DN_ASYNC_QueueTask_(DN_ASYNCCore *async, DN_ASYNCTask const *task, DN_U64 wait_time_ms) { @@ -20622,8 +77,8 @@ static bool DN_ASYNC_QueueTask_(DN_ASYNCCore *async, DN_ASYNCTask const *task, D bool result = false; for (DN_OS_MutexScope(&async->ring_mutex)) { for (;;) { - if (DN_Ring_HasSpace(&async->ring, sizeof(*task))) { - DN_Ring_WriteStruct(&async->ring, task); + if (DN_RingHasSpace(&async->ring, sizeof(*task))) { + DN_RingWriteStruct(&async->ring, task); result = true; break; } @@ -20675,60 +130,9 @@ DN_API bool DN_ASYNC_WaitTask(DN_ASYNCTask *task, DN_U32 timeout_ms) #define DN_BIN_PACK_CPP -#if defined(_CLANGD) - // DN: Single header generator commented out this header => #include "dn_bin_pack.h" -#if !defined(DN_BIN_PACK_H) -#define DN_BIN_PACK_H - -#if defined(_CLANGD) - // DN: Single header generator commented out this header => #include "../dn_base_inc.h" -#endif - -#if !defined(DN_BASE_INC_H) - #error dn_base_inc.h must be included before this -#endif - -enum DN_BinPackMode -{ - DN_BinPackMode_Serialise, - DN_BinPackMode_Deserialise, -}; - -struct DN_BinPack -{ - DN_Str8Builder writer; - DN_Str8 read; - DN_USize read_index; -}; - -DN_API bool DN_BinPackIsEndOfReadStream(DN_BinPack const *pack); -DN_API void DN_BinPackUSize (DN_BinPack *pack, DN_BinPackMode mode, DN_USize *item); -DN_API void DN_BinPackU64 (DN_BinPack *pack, DN_BinPackMode mode, DN_U64 *item); -DN_API void DN_BinPackU32 (DN_BinPack *pack, DN_BinPackMode mode, DN_U32 *item); -DN_API void DN_BinPackU16 (DN_BinPack *pack, DN_BinPackMode mode, DN_U16 *item); -DN_API void DN_BinPackU8 (DN_BinPack *pack, DN_BinPackMode mode, DN_U8 *item); -DN_API void DN_BinPackI64 (DN_BinPack *pack, DN_BinPackMode mode, DN_I64 *item); -DN_API void DN_BinPackI32 (DN_BinPack *pack, DN_BinPackMode mode, DN_I32 *item); -DN_API void DN_BinPackI16 (DN_BinPack *pack, DN_BinPackMode mode, DN_I16 *item); -DN_API void DN_BinPackI8 (DN_BinPack *pack, DN_BinPackMode mode, DN_I8 *item); -DN_API void DN_BinPackF64 (DN_BinPack *pack, DN_BinPackMode mode, DN_F64 *item); -DN_API void DN_BinPackF32 (DN_BinPack *pack, DN_BinPackMode mode, DN_F32 *item); -#if defined (DN_MATH_H) -DN_API void DN_BinPackV2 (DN_BinPack *pack, DN_BinPackMode mode, DN_V2F32 *item); -DN_API void DN_BinPackV4 (DN_BinPack *pack, DN_BinPackMode mode, DN_V4F32 *item); -#endif -DN_API void DN_BinPackBool (DN_BinPack *pack, DN_BinPackMode mode, bool *item); -DN_API void DN_BinPackStr8FromArena (DN_BinPack *pack, DN_Arena *arena, DN_BinPackMode mode, DN_Str8 *string); -DN_API void DN_BinPackStr8FromPool (DN_BinPack *pack, DN_Pool *pool, DN_BinPackMode mode, DN_Str8 *string); -DN_API DN_Str8 DN_BinPackStr8FromBuffer (DN_BinPack *pack, DN_BinPackMode mode, char *ptr, DN_USize *size, DN_USize max); -DN_API void DN_BinPackBytesFromArena (DN_BinPack *pack, DN_Arena *arena, DN_BinPackMode mode, void **ptr, DN_USize *size); -DN_API void DN_BinPackBytesFromPool (DN_BinPack *pack, DN_Pool *pool, DN_BinPackMode mode, void **ptr, DN_USize *size); -DN_API void DN_BinPackCArray (DN_BinPack *pack, DN_BinPackMode mode, void *ptr, DN_USize size); -DN_API void DN_BinPackCBuffer (DN_BinPack *pack, DN_BinPackMode mode, char *ptr, DN_USize *size, DN_USize max); -DN_API DN_Str8 DN_BinPackBuild (DN_BinPack const *pack, DN_Arena *arena); - -#endif // !defined(DN_BIN_PACK_H) -#endif +// DN: Single header generator commented out => #if defined(_CLANGD) +// #include "dn_bin_pack.h" +// #endif DN_API void DN_BinPackU64(DN_BinPack *pack, DN_BinPackMode mode, DN_U64 *item) { @@ -20854,8 +258,8 @@ DN_API void DN_BinPackStr8FromArena(DN_BinPack *pack, DN_Arena *arena, DN_BinPac if (mode == DN_BinPackMode_Serialise) { DN_Str8BuilderAppendBytesCopy(&pack->writer, string->data, string->size); } else { - DN_Str8 src = DN_Str8Slice(pack->read, pack->read_index, string->size); - *string = DN_Str8FromStr8Arena(arena, src); + DN_Str8 src = DN_Str8Subset(pack->read, pack->read_index, string->size); + *string = DN_Str8FromStr8Arena(src, arena); pack->read_index += src.size; } } @@ -20866,8 +270,8 @@ DN_API void DN_BinPackStr8FromPool(DN_BinPack *pack, DN_Pool *pool, DN_BinPackMo if (mode == DN_BinPackMode_Serialise) { DN_Str8BuilderAppendBytesCopy(&pack->writer, string->data, string->size); } else { - DN_Str8 src = DN_Str8Slice(pack->read, pack->read_index, string->size); - *string = DN_Str8FromStr8Pool(pool, src); + DN_Str8 src = DN_Str8Subset(pack->read, pack->read_index, string->size); + *string = DN_Str8FromStr8Pool(src, pool); pack->read_index += src.size; } } @@ -20901,7 +305,7 @@ DN_API void DN_BinPackCArray(DN_BinPack *pack, DN_BinPackMode mode, void *ptr, D if (mode == DN_BinPackMode_Serialise) { DN_Str8BuilderAppendBytesCopy(&pack->writer, ptr, size); } else { - DN_Str8 src = DN_Str8Slice(pack->read, pack->read_index, size); + DN_Str8 src = DN_Str8Subset(pack->read, pack->read_index, size); DN_Assert(src.size == size); DN_Memcpy(ptr, src.data, DN_Min(src.size, size)); pack->read_index += src.size; @@ -20932,14 +336,22 @@ DN_API DN_Str8 DN_BinPackBuild(DN_BinPack const *pack, DN_Arena *arena) } #define DN_CSV_CPP -#if defined(_CLANGD) - // DN: Single header generator commented out this header => #include "dn_csv.h" +// DN: Single header generator commented out => #include "dn_csv.h" #if !defined(DN_CSV_H) #define DN_CSV_H -#if defined(_CLANGD) - // DN: Single header generator commented out this header => #include "../dn_base_inc.h" -#endif +// NOTE: Data structures to create and parse CSV files, supports Python style escaped quotes (e.g. +// Using "" to escape quotes inside a quoted string). +// +// API +// DN_CSV_TokeniserNextN: Reads the next N consecutive fields from the parser. If `column_iterator` +// is `false` then the read of the N consecutive fields does not proceed past the end of the +// current CSV row. If `true` then it reads the next N fields even if reading would progress onto +// the next row. + + // DN: Single header generator commented out => #if defined(_CLANGD) +// #include "../dn.h" +// #endif enum DN_CSVSerialise { @@ -20963,10 +375,32 @@ struct DN_CSVPack DN_CSVTokeniser read_tokeniser; }; -#endif // !defined(DN_CSV_H) -#endif +DN_CSVTokeniser DN_CSV_TokeniserInit (DN_Str8 string, char delimiter); +bool DN_CSV_TokeniserValid (DN_CSVTokeniser *tokeniser); +bool DN_CSV_TokeniserNextRow (DN_CSVTokeniser *tokeniser); +DN_Str8 DN_CSV_TokeniserNextField (DN_CSVTokeniser *tokeniser); +DN_Str8 DN_CSV_TokeniserNextColumn (DN_CSVTokeniser *tokeniser); +void DN_CSV_TokeniserSkipLine (DN_CSVTokeniser *tokeniser); +int DN_CSV_TokeniserNextN (DN_CSVTokeniser *tokeniser, DN_Str8 *fields, int fields_size, bool column_iterator); +int DN_CSV_TokeniserNextColumnN(DN_CSVTokeniser *tokeniser, DN_Str8 *fields, int fields_size); +int DN_CSV_TokeniserNextFieldN (DN_CSVTokeniser *tokeniser, DN_Str8 *fields, int fields_size); +void DN_CSV_TokeniserSkipLineN (DN_CSVTokeniser *tokeniser, int count); +void DN_CSV_PackU64 (DN_CSVPack *pack, DN_CSVSerialise serialise, DN_U64 *value); +void DN_CSV_PackI64 (DN_CSVPack *pack, DN_CSVSerialise serialise, DN_I64 *value); +void DN_CSV_PackI32 (DN_CSVPack *pack, DN_CSVSerialise serialise, DN_I32 *value); +void DN_CSV_PackI16 (DN_CSVPack *pack, DN_CSVSerialise serialise, DN_I16 *value); +void DN_CSV_PackI8 (DN_CSVPack *pack, DN_CSVSerialise serialise, DN_I8 *value); +void DN_CSV_PackU32 (DN_CSVPack *pack, DN_CSVSerialise serialise, DN_U32 *value); +void DN_CSV_PackU16 (DN_CSVPack *pack, DN_CSVSerialise serialise, DN_U16 *value); +void DN_CSV_PackBoolAsU64 (DN_CSVPack *pack, DN_CSVSerialise serialise, bool *value); +void DN_CSV_PackStr8 (DN_CSVPack *pack, DN_CSVSerialise serialise, DN_Str8 *str8, DN_Arena *arena); +void DN_CSV_PackBuffer (DN_CSVPack *pack, DN_CSVSerialise serialise, void *dest, size_t *size); +void DN_CSV_PackBufferWithMax (DN_CSVPack *pack, DN_CSVSerialise serialise, void *dest, size_t *size, size_t max); +bool DN_CSV_PackNewLine (DN_CSVPack *pack, DN_CSVSerialise serialise); -static DN_CSVTokeniser DN_CSV_TokeniserInit(DN_Str8 string, char delimiter) +#endif // !defined(DN_CSV_H) + +DN_CSVTokeniser DN_CSV_TokeniserInit(DN_Str8 string, char delimiter) { DN_CSVTokeniser result = {}; result.string = string; @@ -20974,13 +408,21 @@ static DN_CSVTokeniser DN_CSV_TokeniserInit(DN_Str8 string, char delimiter) return result; } -static bool DN_CSV_TokeniserValid(DN_CSVTokeniser *tokeniser) +bool DN_CSV_TokeniserValid(DN_CSVTokeniser *tokeniser) { bool result = tokeniser && !tokeniser->bad; return result; } -static bool DN_CSV_TokeniserNextRow(DN_CSVTokeniser *tokeniser) +static void DN_CSV_TokeniserEatNewLines_(DN_CSVTokeniser *tokeniser) +{ + char const *end = tokeniser->string.data + tokeniser->string.size; + while (tokeniser->it[0] == '\n' || tokeniser->it[0] == '\r') + if (++tokeniser->it == end) + break; +} + +bool DN_CSV_TokeniserNextRow(DN_CSVTokeniser *tokeniser) { bool result = false; if (DN_CSV_TokeniserValid(tokeniser) && tokeniser->string.size) { @@ -20999,7 +441,7 @@ static bool DN_CSV_TokeniserNextRow(DN_CSVTokeniser *tokeniser) return result; } -static DN_Str8 DN_CSV_TokeniserNextField(DN_CSVTokeniser *tokeniser) +DN_Str8 DN_CSV_TokeniserNextField(DN_CSVTokeniser *tokeniser) { DN_Str8 result = {}; if (!DN_CSV_TokeniserValid(tokeniser)) @@ -21014,10 +456,7 @@ static DN_Str8 DN_CSV_TokeniserNextField(DN_CSVTokeniser *tokeniser) char const *string_end = tokeniser->string.data + tokeniser->string.size; if (!tokeniser->it) { tokeniser->it = tokeniser->string.data; - // NOTE: Skip any leading new lines - while (tokeniser->it[0] == '\n' || tokeniser->it[0] == '\r') - if (++tokeniser->it == string_end) - break; + DN_CSV_TokeniserEatNewLines_(tokeniser); // NOTE: Skip any leading new lines } // NOTE: Tokeniser pointing at end, no more valid data to parse. @@ -21030,8 +469,8 @@ static DN_Str8 DN_CSV_TokeniserNextField(DN_CSVTokeniser *tokeniser) // 3. '\n' Last field in record, extract everything leading up the the new line. char const *begin = tokeniser->it; while (tokeniser->it != string_end && (tokeniser->it[0] != '"' && - tokeniser->it[0] != tokeniser->delimiter && - tokeniser->it[0] != '\n')) + tokeniser->it[0] != tokeniser->delimiter && + tokeniser->it[0] != '\n')) tokeniser->it++; bool quoted_field = (tokeniser->it != string_end) && tokeniser->it[0] == '"'; @@ -21068,8 +507,7 @@ static DN_Str8 DN_CSV_TokeniserNextField(DN_CSVTokeniser *tokeniser) // NOTE: Quoted fields may have whitespace after the closing quote, we skip // until we reach the field terminator. if (quoted_field) - while (tokeniser->it != string_end && (tokeniser->it[0] != tokeniser->delimiter && - tokeniser->it[0] != '\n')) + while (tokeniser->it != string_end && (tokeniser->it[0] != tokeniser->delimiter && tokeniser->it[0] != '\n')) tokeniser->it++; // NOTE: Advance the tokeniser past the field terminator. @@ -21082,7 +520,7 @@ static DN_Str8 DN_CSV_TokeniserNextField(DN_CSVTokeniser *tokeniser) return result; } -static DN_Str8 DN_CSV_TokeniserNextColumn(DN_CSVTokeniser *tokeniser) +DN_Str8 DN_CSV_TokeniserNextColumn(DN_CSVTokeniser *tokeniser) { DN_Str8 result = {}; if (!DN_CSV_TokeniserValid(tokeniser)) @@ -21097,14 +535,14 @@ static DN_Str8 DN_CSV_TokeniserNextColumn(DN_CSVTokeniser *tokeniser) return result; } -static void DN_CSV_TokeniserSkipLine(DN_CSVTokeniser *tokeniser) +void DN_CSV_TokeniserSkipLine(DN_CSVTokeniser *tokeniser) { while (DN_CSV_TokeniserValid(tokeniser) && !tokeniser->end_of_line) DN_CSV_TokeniserNextColumn(tokeniser); DN_CSV_TokeniserNextRow(tokeniser); } -static int DN_CSV_TokeniserNextN(DN_CSVTokeniser *tokeniser, DN_Str8 *fields, int fields_size, bool column_iterator) +int DN_CSV_TokeniserNextN(DN_CSVTokeniser *tokeniser, DN_Str8 *fields, int fields_size, bool column_iterator) { if (!DN_CSV_TokeniserValid(tokeniser) || !fields || fields_size <= 0) return 0; @@ -21112,34 +550,32 @@ static int DN_CSV_TokeniserNextN(DN_CSVTokeniser *tokeniser, DN_Str8 *fields, in int result = 0; for (; result < fields_size; result++) { fields[result] = column_iterator ? DN_CSV_TokeniserNextColumn(tokeniser) : DN_CSV_TokeniserNextField(tokeniser); - if (!DN_CSV_TokeniserValid(tokeniser) || fields[result].size == 0) + if (!DN_CSV_TokeniserValid(tokeniser) || !fields[result].data) break; } return result; } -DN_MSVC_WARNING_PUSH -DN_MSVC_WARNING_DISABLE(4505) // 'x': unreferenced function with internal linkage has been removed -static int DN_CSV_TokeniserNextColumnN(DN_CSVTokeniser *tokeniser, DN_Str8 *fields, int fields_size) +int DN_CSV_TokeniserNextColumnN(DN_CSVTokeniser *tokeniser, DN_Str8 *fields, int fields_size) { int result = DN_CSV_TokeniserNextN(tokeniser, fields, fields_size, true /*column_iterator*/); return result; } -static int DN_CSV_TokeniserNextFieldN(DN_CSVTokeniser *tokeniser, DN_Str8 *fields, int fields_size) +int DN_CSV_TokeniserNextFieldN(DN_CSVTokeniser *tokeniser, DN_Str8 *fields, int fields_size) { int result = DN_CSV_TokeniserNextN(tokeniser, fields, fields_size, false /*column_iterator*/); return result; } -static void DN_CSV_TokeniserSkipLineN(DN_CSVTokeniser *tokeniser, int count) +void DN_CSV_TokeniserSkipLineN(DN_CSVTokeniser *tokeniser, int count) { for (int i = 0; i < count && DN_CSV_TokeniserValid(tokeniser); i++) DN_CSV_TokeniserSkipLine(tokeniser); } -static void DN_CSV_PackU64(DN_CSVPack *pack, DN_CSVSerialise serialise, DN_U64 *value) +void DN_CSV_PackU64(DN_CSVPack *pack, DN_CSVSerialise serialise, DN_U64 *value) { if (serialise == DN_CSVSerialise_Read) { DN_Str8 csv_value = DN_CSV_TokeniserNextColumn(&pack->read_tokeniser); @@ -21151,7 +587,7 @@ static void DN_CSV_PackU64(DN_CSVPack *pack, DN_CSVSerialise serialise, DN_U64 * } } -static void DN_CSV_PackI64(DN_CSVPack *pack, DN_CSVSerialise serialise, DN_I64 *value) +void DN_CSV_PackI64(DN_CSVPack *pack, DN_CSVSerialise serialise, DN_I64 *value) { if (serialise == DN_CSVSerialise_Read) { DN_Str8 csv_value = DN_CSV_TokeniserNextColumn(&pack->read_tokeniser); @@ -21163,7 +599,7 @@ static void DN_CSV_PackI64(DN_CSVPack *pack, DN_CSVSerialise serialise, DN_I64 * } } -static void DN_CSV_PackI32(DN_CSVPack *pack, DN_CSVSerialise serialise, DN_I32 *value) +void DN_CSV_PackI32(DN_CSVPack *pack, DN_CSVSerialise serialise, DN_I32 *value) { DN_I64 u64 = *value; DN_CSV_PackI64(pack, serialise, &u64); @@ -21171,7 +607,7 @@ static void DN_CSV_PackI32(DN_CSVPack *pack, DN_CSVSerialise serialise, DN_I32 * *value = DN_SaturateCastI64ToI32(u64); } -static void DN_CSV_PackI16(DN_CSVPack *pack, DN_CSVSerialise serialise, DN_I16 *value) +void DN_CSV_PackI16(DN_CSVPack *pack, DN_CSVSerialise serialise, DN_I16 *value) { DN_I64 u64 = *value; DN_CSV_PackI64(pack, serialise, &u64); @@ -21179,7 +615,7 @@ static void DN_CSV_PackI16(DN_CSVPack *pack, DN_CSVSerialise serialise, DN_I16 * *value = DN_SaturateCastI64ToI16(u64); } -static void DN_CSV_PackI8(DN_CSVPack *pack, DN_CSVSerialise serialise, DN_I8 *value) +void DN_CSV_PackI8(DN_CSVPack *pack, DN_CSVSerialise serialise, DN_I8 *value) { DN_I64 u64 = *value; DN_CSV_PackI64(pack, serialise, &u64); @@ -21187,8 +623,7 @@ static void DN_CSV_PackI8(DN_CSVPack *pack, DN_CSVSerialise serialise, DN_I8 *va *value = DN_SaturateCastI64ToI8(u64); } - -static void DN_CSV_PackU32(DN_CSVPack *pack, DN_CSVSerialise serialise, DN_U32 *value) +void DN_CSV_PackU32(DN_CSVPack *pack, DN_CSVSerialise serialise, DN_U32 *value) { DN_U64 u64 = *value; DN_CSV_PackU64(pack, serialise, &u64); @@ -21196,7 +631,7 @@ static void DN_CSV_PackU32(DN_CSVPack *pack, DN_CSVSerialise serialise, DN_U32 * *value = DN_SaturateCastU64ToU32(u64); } -static void DN_CSV_PackU16(DN_CSVPack *pack, DN_CSVSerialise serialise, DN_U16 *value) +void DN_CSV_PackU16(DN_CSVPack *pack, DN_CSVSerialise serialise, DN_U16 *value) { DN_U64 u64 = *value; DN_CSV_PackU64(pack, serialise, &u64); @@ -21204,7 +639,7 @@ static void DN_CSV_PackU16(DN_CSVPack *pack, DN_CSVSerialise serialise, DN_U16 * *value = DN_SaturateCastU64ToU16(u64); } -static void DN_CSV_PackBoolAsU64(DN_CSVPack *pack, DN_CSVSerialise serialise, bool *value) +void DN_CSV_PackBoolAsU64(DN_CSVPack *pack, DN_CSVSerialise serialise, bool *value) { DN_U64 u64 = *value; DN_CSV_PackU64(pack, serialise, &u64); @@ -21212,17 +647,17 @@ static void DN_CSV_PackBoolAsU64(DN_CSVPack *pack, DN_CSVSerialise serialise, bo *value = u64 ? 1 : 0; } -static void DN_CSV_PackStr8(DN_CSVPack *pack, DN_CSVSerialise serialise, DN_Str8 *str8, DN_Arena *arena) +void DN_CSV_PackStr8(DN_CSVPack *pack, DN_CSVSerialise serialise, DN_Str8 *str8, DN_Arena *arena) { if (serialise == DN_CSVSerialise_Read) { DN_Str8 csv_value = DN_CSV_TokeniserNextColumn(&pack->read_tokeniser); - *str8 = DN_Str8FromStr8Arena(arena, csv_value); + *str8 = DN_Str8FromStr8Arena(csv_value, arena); } else { DN_Str8BuilderAppendF(&pack->write_builder, "%s%.*s", pack->write_column++ ? "," : "", DN_Str8PrintFmt(*str8)); } } -static void DN_CSV_PackBuffer(DN_CSVPack *pack, DN_CSVSerialise serialise, void *dest, size_t *size) +void DN_CSV_PackBuffer(DN_CSVPack *pack, DN_CSVSerialise serialise, void *dest, size_t *size) { if (serialise == DN_CSVSerialise_Read) { DN_Str8 csv_value = DN_CSV_TokeniserNextColumn(&pack->read_tokeniser); @@ -21233,14 +668,14 @@ static void DN_CSV_PackBuffer(DN_CSVPack *pack, DN_CSVSerialise serialise, void } } -static void DN_CSV_PackBufferWithMax(DN_CSVPack *pack, DN_CSVSerialise serialise, void *dest, size_t *size, size_t max) +void DN_CSV_PackBufferWithMax(DN_CSVPack *pack, DN_CSVSerialise serialise, void *dest, size_t *size, size_t max) { if (serialise == DN_CSVSerialise_Read) *size = max; DN_CSV_PackBuffer(pack, serialise, dest, size); } -static bool DN_CSV_PackNewLine(DN_CSVPack *pack, DN_CSVSerialise serialise) +bool DN_CSV_PackNewLine(DN_CSVPack *pack, DN_CSVSerialise serialise) { bool result = true; if (serialise == DN_CSVSerialise_Read) { @@ -21251,1227 +686,4 @@ static bool DN_CSV_PackNewLine(DN_CSVPack *pack, DN_CSVSerialise serialise) } return result; } -DN_MSVC_WARNING_POP -#define DN_HASH_CPP - -#if defined(_CLANGD) - // DN: Single header generator commented out this header => #include "dn_hash.h" -#if !defined(DN_HASH_H) -#define DN_HASH_H - -#if defined(_CLANGD) - // DN: Single header generator commented out this header => #include "../dn_base_inc.h" -#endif - -/* -//////////////////////////////////////////////////////////////////////////////////////////////////// -// -// $$\ $$\ $$$$$$\ $$$$$$\ $$\ $$\ -// $$ | $$ |$$ __$$\ $$ __$$\ $$ | $$ | -// $$ | $$ |$$ / $$ |$$ / \__|$$ | $$ | -// $$$$$$$$ |$$$$$$$$ |\$$$$$$\ $$$$$$$$ | -// $$ __$$ |$$ __$$ | \____$$\ $$ __$$ | -// $$ | $$ |$$ | $$ |$$\ $$ |$$ | $$ | -// $$ | $$ |$$ | $$ |\$$$$$$ |$$ | $$ | -// \__| \__|\__| \__| \______/ \__| \__| -// -// dn_hash.h -- Hashing functions -// -//////////////////////////////////////////////////////////////////////////////////////////////////// -*/ - -// NOTE: DN_FNV1A ////////////////////////////////////////////////////////////////////////////////// -#if !defined(DN_FNV1A32_SEED) - #define DN_FNV1A32_SEED 2166136261U -#endif - -#if !defined(DN_FNV1A64_SEED) - #define DN_FNV1A64_SEED 14695981039346656037ULL -#endif - -// NOTE: DN_MurmurHash3 //////////////////////////////////////////////////////////////////////////// -struct DN_MurmurHash3 { uint64_t e[2]; }; - -// NOTE: DN_FNV1A ////////////////////////////////////////////////////////////////////////////////// -DN_API uint32_t DN_FNV1A32_Hash (void const *bytes, DN_USize size); -DN_API uint64_t DN_FNV1A64_Hash (void const *bytes, DN_USize size); -DN_API uint32_t DN_FNV1A32_Iterate (void const *bytes, DN_USize size, uint32_t hash); -DN_API uint64_t DN_FNV1A64_Iterate (void const *bytes, DN_USize size, uint64_t hash); - -// NOTE: DN_MurmurHash3 //////////////////////////////////////////////////////////////////////////// -DN_API uint32_t DN_MurmurHash3_x86U32 (void const *key, int len, uint32_t seed); -DN_API DN_MurmurHash3 DN_MurmurHash3_x64U128 (void const *key, int len, uint32_t seed); -#define DN_MurmurHash3_x64U128AsU64(key, len, seed) (DN_MurmurHash3_x64U128(key, len, seed).e[0]) -#define DN_MurmurHash3_x64U128AsU32(key, len, seed) (DN_Cast(uint32_t)DN_MurmurHash3_x64U128(key, len, seed).e[0]) - -#endif // !defined(DN_HASH_H) -#endif - -/* -//////////////////////////////////////////////////////////////////////////////////////////////////// -// -// $$\ $$\ $$$$$$\ $$$$$$\ $$\ $$\ -// $$ | $$ |$$ __$$\ $$ __$$\ $$ | $$ | -// $$ | $$ |$$ / $$ |$$ / \__|$$ | $$ | -// $$$$$$$$ |$$$$$$$$ |\$$$$$$\ $$$$$$$$ | -// $$ __$$ |$$ __$$ | \____$$\ $$ __$$ | -// $$ | $$ |$$ | $$ |$$\ $$ |$$ | $$ | -// $$ | $$ |$$ | $$ |\$$$$$$ |$$ | $$ | -// \__| \__|\__| \__| \______/ \__| \__| -// -// dn_hash.cpp -// -//////////////////////////////////////////////////////////////////////////////////////////////////// -*/ - -// NOTE: DN_FNV1A -// Default values recommended by: http://isthe.com/chongo/tech/comp/fnv/ -DN_API DN_U32 DN_FNV1A32_Iterate(void const *bytes, DN_USize size, DN_U32 hash) -{ - auto buffer = DN_Cast(DN_U8 const *)bytes; - for (DN_USize i = 0; i < size; i++) - hash = (buffer[i] ^ hash) * 16777619 /*FNV Prime*/; - return hash; -} - -DN_API DN_U32 DN_FNV1A32_Hash(void const *bytes, DN_USize size) -{ - DN_U32 result = DN_FNV1A32_Iterate(bytes, size, DN_FNV1A32_SEED); - return result; -} - -DN_API DN_U64 DN_FNV1A64_Iterate(void const *bytes, DN_USize size, DN_U64 hash) -{ - auto buffer = DN_Cast(DN_U8 const *)bytes; - for (DN_USize i = 0; i < size; i++) - hash = (buffer[i] ^ hash) * 1099511628211 /*FNV Prime*/; - return hash; -} - -DN_API DN_U64 DN_FNV1A64_Hash(void const *bytes, DN_USize size) -{ - DN_U64 result = DN_FNV1A64_Iterate(bytes, size, DN_FNV1A64_SEED); - return result; -} - -// NOTE: DN_MurmurHash3 //////////////////////////////////////////////////////////////////////////// -#if defined(DN_COMPILER_MSVC) || defined(DN_COMPILER_CLANG_CL) - #define DN_MMH3_ROTL32(x, y) _rotl(x, y) - #define DN_MMH3_ROTL64(x, y) _rotl64(x, y) -#else - #define DN_MMH3_ROTL32(x, y) ((x) << (y)) | ((x) >> (32 - (y))) - #define DN_MMH3_ROTL64(x, y) ((x) << (y)) | ((x) >> (64 - (y))) -#endif - -//----------------------------------------------------------------------------- -// Block read - if your platform needs to do endian-swapping or can only -// handle aligned reads, do the conversion here - -DN_FORCE_INLINE DN_U32 DN_MurmurHash3_GetBlock32(DN_U32 const *p, int i) -{ - return p[i]; -} - -DN_FORCE_INLINE DN_U64 DN_MurmurHash3_GetBlock64(DN_U64 const *p, int i) -{ - return p[i]; -} - -//----------------------------------------------------------------------------- -// Finalization mix - force all bits of a hash block to avalanche - -DN_FORCE_INLINE DN_U32 DN_MurmurHash3_FMix32(DN_U32 h) -{ - h ^= h >> 16; - h *= 0x85ebca6b; - h ^= h >> 13; - h *= 0xc2b2ae35; - h ^= h >> 16; - return h; -} - -DN_FORCE_INLINE DN_U64 DN_MurmurHash3_FMix64(DN_U64 k) -{ - k ^= k >> 33; - k *= 0xff51afd7ed558ccd; - k ^= k >> 33; - k *= 0xc4ceb9fe1a85ec53; - k ^= k >> 33; - return k; -} - -DN_API DN_U32 DN_MurmurHash3_x86U32(void const *key, int len, DN_U32 seed) -{ - const DN_U8 *data = (const DN_U8 *)key; - const int nblocks = len / 4; - - DN_U32 h1 = seed; - - const DN_U32 c1 = 0xcc9e2d51; - const DN_U32 c2 = 0x1b873593; - - //---------- - // body - - const DN_U32 *blocks = (const DN_U32 *)(data + nblocks * 4); - - for (int i = -nblocks; i; i++) - { - DN_U32 k1 = DN_MurmurHash3_GetBlock32(blocks, i); - - k1 *= c1; - k1 = DN_MMH3_ROTL32(k1, 15); - k1 *= c2; - - h1 ^= k1; - h1 = DN_MMH3_ROTL32(h1, 13); - h1 = h1 * 5 + 0xe6546b64; - } - - //---------- - // tail - - const DN_U8 *tail = (const DN_U8 *)(data + nblocks * 4); - - DN_U32 k1 = 0; - - switch (len & 3) - { - case 3: - k1 ^= tail[2] << 16; - case 2: - k1 ^= tail[1] << 8; - case 1: - k1 ^= tail[0]; - k1 *= c1; - k1 = DN_MMH3_ROTL32(k1, 15); - k1 *= c2; - h1 ^= k1; - }; - - //---------- - // finalization - - h1 ^= len; - - h1 = DN_MurmurHash3_FMix32(h1); - - return h1; -} - -DN_API DN_MurmurHash3 DN_MurmurHash3_x64U128(void const *key, int len, DN_U32 seed) -{ - const DN_U8 *data = (const DN_U8 *)key; - const int nblocks = len / 16; - - DN_U64 h1 = seed; - DN_U64 h2 = seed; - - const DN_U64 c1 = 0x87c37b91114253d5; - const DN_U64 c2 = 0x4cf5ad432745937f; - - //---------- - // body - - const DN_U64 *blocks = (const DN_U64 *)(data); - - for (int i = 0; i < nblocks; i++) - { - DN_U64 k1 = DN_MurmurHash3_GetBlock64(blocks, i * 2 + 0); - DN_U64 k2 = DN_MurmurHash3_GetBlock64(blocks, i * 2 + 1); - - k1 *= c1; - k1 = DN_MMH3_ROTL64(k1, 31); - k1 *= c2; - h1 ^= k1; - - h1 = DN_MMH3_ROTL64(h1, 27); - h1 += h2; - h1 = h1 * 5 + 0x52dce729; - - k2 *= c2; - k2 = DN_MMH3_ROTL64(k2, 33); - k2 *= c1; - h2 ^= k2; - - h2 = DN_MMH3_ROTL64(h2, 31); - h2 += h1; - h2 = h2 * 5 + 0x38495ab5; - } - - //---------- - // tail - - const DN_U8 *tail = (const DN_U8 *)(data + nblocks * 16); - - DN_U64 k1 = 0; - DN_U64 k2 = 0; - - switch (len & 15) - { - case 15: - k2 ^= ((DN_U64)tail[14]) << 48; - case 14: - k2 ^= ((DN_U64)tail[13]) << 40; - case 13: - k2 ^= ((DN_U64)tail[12]) << 32; - case 12: - k2 ^= ((DN_U64)tail[11]) << 24; - case 11: - k2 ^= ((DN_U64)tail[10]) << 16; - case 10: - k2 ^= ((DN_U64)tail[9]) << 8; - case 9: - k2 ^= ((DN_U64)tail[8]) << 0; - k2 *= c2; - k2 = DN_MMH3_ROTL64(k2, 33); - k2 *= c1; - h2 ^= k2; - - case 8: - k1 ^= ((DN_U64)tail[7]) << 56; - case 7: - k1 ^= ((DN_U64)tail[6]) << 48; - case 6: - k1 ^= ((DN_U64)tail[5]) << 40; - case 5: - k1 ^= ((DN_U64)tail[4]) << 32; - case 4: - k1 ^= ((DN_U64)tail[3]) << 24; - case 3: - k1 ^= ((DN_U64)tail[2]) << 16; - case 2: - k1 ^= ((DN_U64)tail[1]) << 8; - case 1: - k1 ^= ((DN_U64)tail[0]) << 0; - k1 *= c1; - k1 = DN_MMH3_ROTL64(k1, 31); - k1 *= c2; - h1 ^= k1; - }; - - //---------- - // finalization - - h1 ^= len; - h2 ^= len; - - h1 += h2; - h2 += h1; - - h1 = DN_MurmurHash3_FMix64(h1); - h2 = DN_MurmurHash3_FMix64(h2); - - h1 += h2; - h2 += h1; - - DN_MurmurHash3 result = {}; - result.e[0] = h1; - result.e[1] = h2; - return result; -} -#define DN_HELPERS_CPP - -#if defined(_CLANGD) - // DN: Single header generator commented out this header => #include "dn_helpers.h" -#if !defined(DN_HELPERS_H) -#define DN_HELPERS_H - -#if defined(_CLANGD) - // DN: Single header generator commented out this header => #include "../dn_base_inc.h" - // DN: Single header generator commented out this header => #include "dn_math.h" -#if !defined(DN_MATH_H) -#define DN_MATH_H - -#if defined(_CLANGD) - // DN: Single header generator commented out this header => #include "../dn_base_inc.h" -#endif - -DN_MSVC_WARNING_PUSH -DN_MSVC_WARNING_DISABLE(4201) // warning C4201: nonstandard extension used: nameless struct/union -union DN_V2I32 -{ - struct { DN_I32 x, y; }; - struct { DN_I32 w, h; }; - DN_I32 data[2]; -}; - -union DN_V2U16 -{ - struct { DN_U16 x, y; }; - struct { DN_U16 w, h; }; - DN_U16 data[2]; -}; - -union DN_V2U32 -{ - struct { DN_U32 x, y; }; - struct { DN_U32 w, h; }; - DN_U32 data[2]; -}; - -union DN_V2F32 -{ - struct { DN_F32 x, y; }; - struct { DN_F32 w, h; }; - DN_F32 data[2]; -}; - -union DN_V3F32 -{ - struct { DN_F32 x, y, z; }; - struct { DN_F32 r, g, b; }; - DN_F32 data[3]; -}; - - -union DN_V4F32 -{ - struct { DN_F32 x, y, z, w; }; - struct { DN_F32 r, g, b, a; }; - #if !defined(DN_NO_V3) - DN_V3F32 rgb; - DN_V3F32 xyz; - #endif - DN_F32 data[4]; -}; -DN_MSVC_WARNING_POP - -struct DN_M4 -{ - DN_F32 columns[4][4]; // Column major matrix -}; - -union DN_M2x3 -{ - DN_F32 e[6]; - DN_F32 row[2][3]; -}; - -struct DN_Rect -{ - DN_V2F32 pos, size; -}; - -struct DN_RectMinMax -{ - DN_V2F32 min, max; -}; - -enum DN_RectCutClip -{ - DN_RectCutClip_No, - DN_RectCutClip_Yes, -}; - -enum DN_RectCutSide -{ - DN_RectCutSide_Left, - DN_RectCutSide_Right, - DN_RectCutSide_Top, - DN_RectCutSide_Bottom, -}; - -struct DN_RectCut -{ - DN_Rect* rect; - DN_RectCutSide side; -}; - -struct DN_RaycastLineIntersectV2Result -{ - bool hit; // True if there was an intersection, false if the lines are parallel - DN_F32 t_a; // Distance along `dir_a` that the intersection occurred, e.g. `origin_a + (dir_a * t_a)` - DN_F32 t_b; // Distance along `dir_b` that the intersection occurred, e.g. `origin_b + (dir_b * t_b)` -}; - -#define DN_V2I32_Zero DN_Literal(DN_V2I32){{(int32_t)(0), (int32_t)(0)}} -#define DN_V2I32_One DN_Literal(DN_V2I32){{(int32_t)(1), (int32_t)(1)}} -#define DN_V2I32_From1N(x) DN_Literal(DN_V2I32){{(int32_t)(x), (int32_t)(x)}} -#define DN_V2I32_From2N(x, y) DN_Literal(DN_V2I32){{(int32_t)(x), (int32_t)(y)}} -#define DN_V2I32_InitV2(xy) DN_Literal(DN_V2I32){{(int32_t)(xy).x, (int32_t)(xy).y}} - -DN_API bool operator!= (DN_V2I32 lhs, DN_V2I32 rhs); -DN_API bool operator== (DN_V2I32 lhs, DN_V2I32 rhs); -DN_API bool operator>= (DN_V2I32 lhs, DN_V2I32 rhs); -DN_API bool operator<= (DN_V2I32 lhs, DN_V2I32 rhs); -DN_API bool operator< (DN_V2I32 lhs, DN_V2I32 rhs); -DN_API bool operator> (DN_V2I32 lhs, DN_V2I32 rhs); -DN_API DN_V2I32 operator- (DN_V2I32 lhs, DN_V2I32 rhs); -DN_API DN_V2I32 operator- (DN_V2I32 lhs); -DN_API DN_V2I32 operator+ (DN_V2I32 lhs, DN_V2I32 rhs); -DN_API DN_V2I32 operator* (DN_V2I32 lhs, DN_V2I32 rhs); -DN_API DN_V2I32 operator* (DN_V2I32 lhs, DN_F32 rhs); -DN_API DN_V2I32 operator* (DN_V2I32 lhs, int32_t rhs); -DN_API DN_V2I32 operator/ (DN_V2I32 lhs, DN_V2I32 rhs); -DN_API DN_V2I32 operator/ (DN_V2I32 lhs, DN_F32 rhs); -DN_API DN_V2I32 operator/ (DN_V2I32 lhs, int32_t rhs); -DN_API DN_V2I32 & operator*= (DN_V2I32& lhs, DN_V2I32 rhs); -DN_API DN_V2I32 & operator*= (DN_V2I32& lhs, DN_F32 rhs); -DN_API DN_V2I32 & operator*= (DN_V2I32& lhs, int32_t rhs); -DN_API DN_V2I32 & operator/= (DN_V2I32& lhs, DN_V2I32 rhs); -DN_API DN_V2I32 & operator/= (DN_V2I32& lhs, DN_F32 rhs); -DN_API DN_V2I32 & operator/= (DN_V2I32& lhs, int32_t rhs); -DN_API DN_V2I32 & operator-= (DN_V2I32& lhs, DN_V2I32 rhs); -DN_API DN_V2I32 & operator+= (DN_V2I32& lhs, DN_V2I32 rhs); - -DN_API DN_V2I32 DN_V2I32_Min (DN_V2I32 a, DN_V2I32 b); -DN_API DN_V2I32 DN_V2I32_Max (DN_V2I32 a, DN_V2I32 b); -DN_API DN_V2I32 DN_V2I32_Abs (DN_V2I32 a); - -#define DN_V2U16_Zero DN_Literal(DN_V2U16){{(uint16_t)(0), (uint16_t)(0)}} -#define DN_V2U16_One DN_Literal(DN_V2U16){{(uint16_t)(1), (uint16_t)(1)}} -#define DN_V2U16_From1N(x) DN_Literal(DN_V2U16){{(uint16_t)(x), (uint16_t)(x)}} -#define DN_V2U16_From2N(x, y) DN_Literal(DN_V2U16){{(uint16_t)(x), (uint16_t)(y)}} - -DN_API bool operator!= (DN_V2U16 lhs, DN_V2U16 rhs); -DN_API bool operator== (DN_V2U16 lhs, DN_V2U16 rhs); -DN_API bool operator>= (DN_V2U16 lhs, DN_V2U16 rhs); -DN_API bool operator<= (DN_V2U16 lhs, DN_V2U16 rhs); -DN_API bool operator< (DN_V2U16 lhs, DN_V2U16 rhs); -DN_API bool operator> (DN_V2U16 lhs, DN_V2U16 rhs); -DN_API DN_V2U16 operator- (DN_V2U16 lhs, DN_V2U16 rhs); -DN_API DN_V2U16 operator+ (DN_V2U16 lhs, DN_V2U16 rhs); -DN_API DN_V2U16 operator* (DN_V2U16 lhs, DN_V2U16 rhs); -DN_API DN_V2U16 operator* (DN_V2U16 lhs, DN_F32 rhs); -DN_API DN_V2U16 operator* (DN_V2U16 lhs, int32_t rhs); -DN_API DN_V2U16 operator/ (DN_V2U16 lhs, DN_V2U16 rhs); -DN_API DN_V2U16 operator/ (DN_V2U16 lhs, DN_F32 rhs); -DN_API DN_V2U16 operator/ (DN_V2U16 lhs, int32_t rhs); -DN_API DN_V2U16 & operator*= (DN_V2U16& lhs, DN_V2U16 rhs); -DN_API DN_V2U16 & operator*= (DN_V2U16& lhs, DN_F32 rhs); -DN_API DN_V2U16 & operator*= (DN_V2U16& lhs, int32_t rhs); -DN_API DN_V2U16 & operator/= (DN_V2U16& lhs, DN_V2U16 rhs); -DN_API DN_V2U16 & operator/= (DN_V2U16& lhs, DN_F32 rhs); -DN_API DN_V2U16 & operator/= (DN_V2U16& lhs, int32_t rhs); -DN_API DN_V2U16 & operator-= (DN_V2U16& lhs, DN_V2U16 rhs); -DN_API DN_V2U16 & operator+= (DN_V2U16& lhs, DN_V2U16 rhs); - -#define DN_V2F32_Zero DN_Literal(DN_V2F32){{(DN_F32)(0), (DN_F32)(0)}} -#define DN_V2F32_One DN_Literal(DN_V2F32){{(DN_F32)(1), (DN_F32)(1)}} -#define DN_V2F32_From1N(x) DN_Literal(DN_V2F32){{(DN_F32)(x), (DN_F32)(x)}} -#define DN_V2F32_From2N(x, y) DN_Literal(DN_V2F32){{(DN_F32)(x), (DN_F32)(y)}} -#define DN_V2F32_FromV2I32(xy) DN_Literal(DN_V2F32){{(DN_F32)(xy).x, (DN_F32)(xy).y}} -#define DN_V2F32_FromV2U32(xy) DN_Literal(DN_V2F32){{(DN_F32)(xy).x, (DN_F32)(xy).y}} - -DN_API bool operator!= (DN_V2F32 lhs, DN_V2F32 rhs); -DN_API bool operator== (DN_V2F32 lhs, DN_V2F32 rhs); -DN_API bool operator>= (DN_V2F32 lhs, DN_V2F32 rhs); -DN_API bool operator<= (DN_V2F32 lhs, DN_V2F32 rhs); -DN_API bool operator< (DN_V2F32 lhs, DN_V2F32 rhs); -DN_API bool operator> (DN_V2F32 lhs, DN_V2F32 rhs); - -DN_API DN_V2F32 operator- (DN_V2F32 lhs); -DN_API DN_V2F32 operator- (DN_V2F32 lhs, DN_V2F32 rhs); -DN_API DN_V2F32 operator- (DN_V2F32 lhs, DN_V2I32 rhs); -DN_API DN_V2F32 operator- (DN_V2F32 lhs, DN_F32 rhs); -DN_API DN_V2F32 operator- (DN_V2F32 lhs, int32_t rhs); - -DN_API DN_V2F32 operator+ (DN_V2F32 lhs, DN_V2F32 rhs); -DN_API DN_V2F32 operator+ (DN_V2F32 lhs, DN_V2I32 rhs); -DN_API DN_V2F32 operator+ (DN_V2F32 lhs, DN_F32 rhs); -DN_API DN_V2F32 operator+ (DN_V2F32 lhs, int32_t rhs); - -DN_API DN_V2F32 operator* (DN_V2F32 lhs, DN_V2F32 rhs); -DN_API DN_V2F32 operator* (DN_V2F32 lhs, DN_V2I32 rhs); -DN_API DN_V2F32 operator* (DN_V2F32 lhs, DN_F32 rhs); -DN_API DN_V2F32 operator* (DN_V2F32 lhs, int32_t rhs); - -DN_API DN_V2F32 operator/ (DN_V2F32 lhs, DN_V2F32 rhs); -DN_API DN_V2F32 operator/ (DN_V2F32 lhs, DN_V2I32 rhs); -DN_API DN_V2F32 operator/ (DN_V2F32 lhs, DN_F32 rhs); -DN_API DN_V2F32 operator/ (DN_V2F32 lhs, int32_t rhs); - -DN_API DN_V2F32 & operator*= (DN_V2F32& lhs, DN_V2F32 rhs); -DN_API DN_V2F32 & operator*= (DN_V2F32& lhs, DN_V2I32 rhs); -DN_API DN_V2F32 & operator*= (DN_V2F32& lhs, DN_F32 rhs); -DN_API DN_V2F32 & operator*= (DN_V2F32& lhs, int32_t rhs); - -DN_API DN_V2F32 & operator/= (DN_V2F32& lhs, DN_V2F32 rhs); -DN_API DN_V2F32 & operator/= (DN_V2F32& lhs, DN_V2I32 rhs); -DN_API DN_V2F32 & operator/= (DN_V2F32& lhs, DN_F32 rhs); -DN_API DN_V2F32 & operator/= (DN_V2F32& lhs, int32_t rhs); - -DN_API DN_V2F32 & operator-= (DN_V2F32& lhs, DN_V2F32 rhs); -DN_API DN_V2F32 & operator-= (DN_V2F32& lhs, DN_V2I32 rhs); -DN_API DN_V2F32 & operator-= (DN_V2F32& lhs, DN_F32 rhs); -DN_API DN_V2F32 & operator-= (DN_V2F32& lhs, int32_t rhs); - -DN_API DN_V2F32 & operator+= (DN_V2F32& lhs, DN_V2F32 rhs); -DN_API DN_V2F32 & operator+= (DN_V2F32& lhs, DN_V2I32 rhs); -DN_API DN_V2F32 & operator+= (DN_V2F32& lhs, DN_F32 rhs); -DN_API DN_V2F32 & operator+= (DN_V2F32& lhs, int32_t rhs); - -DN_API DN_V2F32 DN_V2F32_Min (DN_V2F32 a, DN_V2F32 b); -DN_API DN_V2F32 DN_V2F32_Max (DN_V2F32 a, DN_V2F32 b); -DN_API DN_V2F32 DN_V2F32_Abs (DN_V2F32 a); -DN_API DN_F32 DN_V2F32_Dot (DN_V2F32 a, DN_V2F32 b); -DN_API DN_F32 DN_V2F32_LengthSq2V2 (DN_V2F32 lhs, DN_V2F32 rhs); -DN_API bool DN_V2F32_LengthSqIsWithin2V2 (DN_V2F32 lhs, DN_V2F32 rhs, DN_F32 within_amount_sq); -DN_API DN_F32 DN_V2F32_Length2V2 (DN_V2F32 lhs, DN_V2F32 rhs); -DN_API DN_F32 DN_V2F32_LengthSq (DN_V2F32 lhs); -DN_API DN_F32 DN_V2F32_Length (DN_V2F32 lhs); -DN_API DN_V2F32 DN_V2F32_Normalise (DN_V2F32 a); -DN_API DN_V2F32 DN_V2F32_Perpendicular (DN_V2F32 a); -DN_API DN_V2F32 DN_V2F32_Reflect (DN_V2F32 in, DN_V2F32 surface); -DN_API DN_F32 DN_V2F32_Area (DN_V2F32 a); - -#define DN_V3F32_From1N(x) DN_Literal(DN_V3F32){{(DN_F32)(x), (DN_F32)(x), (DN_F32)(x)}} -#define DN_V3F32_From3N(x, y, z) DN_Literal(DN_V3F32){{(DN_F32)(x), (DN_F32)(y), (DN_F32)(z)}} -#define DN_V3F32_FromV2F32And1N(xy, z) DN_Literal(DN_V3F32){{(DN_F32)(xy.x), (DN_F32)(xy.y), (DN_F32)(z)}} - -DN_API bool operator== (DN_V3F32 lhs, DN_V3F32 rhs); -DN_API bool operator!= (DN_V3F32 lhs, DN_V3F32 rhs); -DN_API bool operator>= (DN_V3F32 lhs, DN_V3F32 rhs); -DN_API bool operator<= (DN_V3F32 lhs, DN_V3F32 rhs); -DN_API bool operator< (DN_V3F32 lhs, DN_V3F32 rhs); -DN_API bool operator> (DN_V3F32 lhs, DN_V3F32 rhs); -DN_API DN_V3F32 operator- (DN_V3F32 lhs, DN_V3F32 rhs); -DN_API DN_V3F32 operator- (DN_V3F32 lhs); -DN_API DN_V3F32 operator+ (DN_V3F32 lhs, DN_V3F32 rhs); -DN_API DN_V3F32 operator* (DN_V3F32 lhs, DN_V3F32 rhs); -DN_API DN_V3F32 operator* (DN_V3F32 lhs, DN_F32 rhs); -DN_API DN_V3F32 operator* (DN_V3F32 lhs, int32_t rhs); -DN_API DN_V3F32 operator/ (DN_V3F32 lhs, DN_V3F32 rhs); -DN_API DN_V3F32 operator/ (DN_V3F32 lhs, DN_F32 rhs); -DN_API DN_V3F32 operator/ (DN_V3F32 lhs, int32_t rhs); -DN_API DN_V3F32 & operator*= (DN_V3F32 &lhs, DN_V3F32 rhs); -DN_API DN_V3F32 & operator*= (DN_V3F32 &lhs, DN_F32 rhs); -DN_API DN_V3F32 & operator*= (DN_V3F32 &lhs, int32_t rhs); -DN_API DN_V3F32 & operator/= (DN_V3F32 &lhs, DN_V3F32 rhs); -DN_API DN_V3F32 & operator/= (DN_V3F32 &lhs, DN_F32 rhs); -DN_API DN_V3F32 & operator/= (DN_V3F32 &lhs, int32_t rhs); -DN_API DN_V3F32 & operator-= (DN_V3F32 &lhs, DN_V3F32 rhs); -DN_API DN_V3F32 & operator+= (DN_V3F32 &lhs, DN_V3F32 rhs); -DN_API DN_F32 DN_V3F32_LengthSq (DN_V3F32 a); -DN_API DN_F32 DN_V3F32_Length (DN_V3F32 a); -DN_API DN_V3F32 DN_V3F32_Normalise (DN_V3F32 a); - -#define DN_V4F32_From1N(x) DN_Literal(DN_V4F32){{(DN_F32)(x), (DN_F32)(x), (DN_F32)(x), (DN_F32)(x)}} -#define DN_V4F32_From4N(x, y, z, w) DN_Literal(DN_V4F32){{(DN_F32)(x), (DN_F32)(y), (DN_F32)(z), (DN_F32)(w)}} -#define DN_V4F32_FromV3And1N(xyz, w) DN_Literal(DN_V4F32){{xyz.x, xyz.y, xyz.z, w}} -#define DN_V4F32_FromRGBAU8(r, g, b, a) DN_Literal(DN_V4F32){{r / 255.f, g / 255.f, b / 255.f, a / 255.f}} -#define DN_V4F32_FromRGBU8(r, g, b) DN_Literal(DN_V4F32){{r / 255.f, g / 255.f, b / 255.f, 1.f}} -DN_API DN_V4F32 DN_V4F32_FromRGBU32(DN_U32 u32); -DN_API DN_V4F32 DN_V4F32_FromRGBAU32(DN_U32 u32); -#define DN_V4F32_FromV4Alpha(v4, alpha) DN_V4F32_FromV3And1N(v4.xyz, alpha) -DN_API bool operator== (DN_V4F32 lhs, DN_V4F32 rhs); -DN_API bool operator!= (DN_V4F32 lhs, DN_V4F32 rhs); -DN_API bool operator<= (DN_V4F32 lhs, DN_V4F32 rhs); -DN_API bool operator< (DN_V4F32 lhs, DN_V4F32 rhs); -DN_API bool operator> (DN_V4F32 lhs, DN_V4F32 rhs); -DN_API DN_V4F32 operator- (DN_V4F32 lhs, DN_V4F32 rhs); -DN_API DN_V4F32 operator- (DN_V4F32 lhs); -DN_API DN_V4F32 operator+ (DN_V4F32 lhs, DN_V4F32 rhs); -DN_API DN_V4F32 operator* (DN_V4F32 lhs, DN_V4F32 rhs); -DN_API DN_V4F32 operator* (DN_V4F32 lhs, DN_F32 rhs); -DN_API DN_V4F32 operator* (DN_V4F32 lhs, int32_t rhs); -DN_API DN_V4F32 operator/ (DN_V4F32 lhs, DN_F32 rhs); -DN_API DN_V4F32 & operator*= (DN_V4F32 &lhs, DN_V4F32 rhs); -DN_API DN_V4F32 & operator*= (DN_V4F32 &lhs, DN_F32 rhs); -DN_API DN_V4F32 & operator*= (DN_V4F32 &lhs, int32_t rhs); -DN_API DN_V4F32 & operator-= (DN_V4F32 &lhs, DN_V4F32 rhs); -DN_API DN_V4F32 & operator+= (DN_V4F32 &lhs, DN_V4F32 rhs); -DN_API DN_F32 DN_V4F32_Dot (DN_V4F32 a, DN_V4F32 b); - -DN_API DN_M4 DN_M4_Identity (); -DN_API DN_M4 DN_M4_ScaleF (DN_F32 x, DN_F32 y, DN_F32 z); -DN_API DN_M4 DN_M4_Scale (DN_V3F32 xyz); -DN_API DN_M4 DN_M4_TranslateF (DN_F32 x, DN_F32 y, DN_F32 z); -DN_API DN_M4 DN_M4_Translate (DN_V3F32 xyz); -DN_API DN_M4 DN_M4_Transpose (DN_M4 mat); -DN_API DN_M4 DN_M4_Rotate (DN_V3F32 axis, DN_F32 radians); -DN_API DN_M4 DN_M4_Orthographic (DN_F32 left, DN_F32 right, DN_F32 bottom, DN_F32 top, DN_F32 z_near, DN_F32 z_far); -DN_API DN_M4 DN_M4_Perspective (DN_F32 fov /*radians*/, DN_F32 aspect, DN_F32 z_near, DN_F32 z_far); -DN_API DN_M4 DN_M4_Add (DN_M4 lhs, DN_M4 rhs); -DN_API DN_M4 DN_M4_Sub (DN_M4 lhs, DN_M4 rhs); -DN_API DN_M4 DN_M4_Mul (DN_M4 lhs, DN_M4 rhs); -DN_API DN_M4 DN_M4_Div (DN_M4 lhs, DN_M4 rhs); -DN_API DN_M4 DN_M4_AddF (DN_M4 lhs, DN_F32 rhs); -DN_API DN_M4 DN_M4_SubF (DN_M4 lhs, DN_F32 rhs); -DN_API DN_M4 DN_M4_MulF (DN_M4 lhs, DN_F32 rhs); -DN_API DN_M4 DN_M4_DivF (DN_M4 lhs, DN_F32 rhs); -DN_API DN_Str8x256 DN_M4_ColumnMajorString (DN_M4 mat); - -DN_API bool operator== (DN_M2x3 const &lhs, DN_M2x3 const &rhs); -DN_API bool operator!= (DN_M2x3 const &lhs, DN_M2x3 const &rhs); -DN_API DN_M2x3 DN_M2x3_Identity (); -DN_API DN_M2x3 DN_M2x3_Translate (DN_V2F32 offset); -DN_API DN_M2x3 DN_M2x3_Scale (DN_V2F32 scale); -DN_API DN_M2x3 DN_M2x3_Rotate (DN_F32 radians); -DN_API DN_M2x3 DN_M2x3_Mul (DN_M2x3 m1, DN_M2x3 m2); -DN_API DN_V2F32 DN_M2x3_Mul2F32 (DN_M2x3 m1, DN_F32 x, DN_F32 y); -DN_API DN_V2F32 DN_M2x3_MulV2 (DN_M2x3 m1, DN_V2F32 v2); - -#define DN_Rect_From2V2(pos, size) DN_Literal(DN_Rect){(pos), (size)} -#define DN_Rect_From4N(x, y, w, h) DN_Literal(DN_Rect){DN_Literal(DN_V2F32){{x, y}}, DN_Literal(DN_V2F32){{w, h}}} - -DN_API bool operator== (const DN_Rect& lhs, const DN_Rect& rhs); -DN_API DN_V2F32 DN_Rect_Center (DN_Rect rect); -DN_API bool DN_Rect_ContainsPoint (DN_Rect rect, DN_V2F32 p); -DN_API bool DN_Rect_ContainsRect (DN_Rect a, DN_Rect b); -DN_API DN_Rect DN_Rect_Expand (DN_Rect a, DN_F32 amount); -DN_API DN_Rect DN_Rect_ExpandV2 (DN_Rect a, DN_V2F32 amount); -DN_API bool DN_Rect_Intersects (DN_Rect a, DN_Rect b); -DN_API DN_Rect DN_Rect_Intersection (DN_Rect a, DN_Rect b); -DN_API DN_Rect DN_Rect_Union (DN_Rect a, DN_Rect b); -DN_API DN_RectMinMax DN_Rect_MinMax (DN_Rect a); -DN_API DN_F32 DN_Rect_Area (DN_Rect a); -DN_API DN_V2F32 DN_Rect_InterpolatedPoint (DN_Rect rect, DN_V2F32 t01); -DN_API DN_V2F32 DN_Rect_TopLeft (DN_Rect rect); -DN_API DN_V2F32 DN_Rect_TopRight (DN_Rect rect); -DN_API DN_V2F32 DN_Rect_BottomLeft (DN_Rect rect); -DN_API DN_V2F32 DN_Rect_BottomRight (DN_Rect rect); - -DN_API DN_Rect DN_Rect_CutLeftClip (DN_Rect *rect, DN_F32 amount, DN_RectCutClip clip); -DN_API DN_Rect DN_Rect_CutRightClip (DN_Rect *rect, DN_F32 amount, DN_RectCutClip clip); -DN_API DN_Rect DN_Rect_CutTopClip (DN_Rect *rect, DN_F32 amount, DN_RectCutClip clip); -DN_API DN_Rect DN_Rect_CutBottomClip (DN_Rect *rect, DN_F32 amount, DN_RectCutClip clip); - -#define DN_Rect_CutLeft(rect, amount) DN_Rect_CutLeftClip(rect, amount, DN_RectCutClip_Yes) -#define DN_Rect_CutRight(rect, amount) DN_Rect_CutRightClip(rect, amount, DN_RectCutClip_Yes) -#define DN_Rect_CutTop(rect, amount) DN_Rect_CutTopClip(rect, amount, DN_RectCutClip_Yes) -#define DN_Rect_CutBottom(rect, amount) DN_Rect_CutBottomClip(rect, amount, DN_RectCutClip_Yes) - -#define DN_Rect_CutLeftNoClip(rect, amount) DN_Rect_CutLeftClip(rect, amount, DN_RectCutClip_No) -#define DN_Rect_CutRightNoClip(rect, amount) DN_Rect_CutRightClip(rect, amount, DN_RectCutClip_No) -#define DN_Rect_CutTopNoClip(rect, amount) DN_Rect_CutTopClip(rect, amount, DN_RectCutClip_No) -#define DN_Rect_CutBottomNoClip(rect, amount) DN_Rect_CutBottomClip(rect, amount, DN_RectCutClip_No) - -DN_API DN_Rect DN_RectCut_Cut (DN_RectCut rect_cut, DN_V2F32 size, DN_RectCutClip clip); -#define DN_RectCut_Init(rect, side) DN_Literal(DN_RectCut){rect, side} -#define DN_RectCut_Left(rect) DN_Literal(DN_RectCut){rect, DN_RectCutSide_Left} -#define DN_RectCut_Right(rect) DN_Literal(DN_RectCut){rect, DN_RectCutSide_Right} -#define DN_RectCut_Top(rect) DN_Literal(DN_RectCut){rect, DN_RectCutSide_Top} -#define DN_RectCut_Bottom(rect) DN_Literal(DN_RectCut){rect, DN_RectCutSide_Bottom} - -DN_API DN_RaycastLineIntersectV2Result DN_Raycast_LineIntersectV2(DN_V2F32 origin_a, DN_V2F32 dir_a, DN_V2F32 origin_b, DN_V2F32 dir_b); -DN_API DN_V2F32 DN_Lerp_V2F32 (DN_V2F32 a, DN_F32 t, DN_V2F32 b); -DN_API DN_F32 DN_Lerp_F32 (DN_F32 a, DN_F32 t, DN_F32 b); -#endif // !defined(DN_MATH_H) -#endif - -#if !defined(DN_BASE_H) - #error dn_base_inc.h must be included before this -#endif - -#if !defined(DN_MATH_H) - #error dn_math.h must be included before this -#endif - -/* -//////////////////////////////////////////////////////////////////////////////////////////////////// -// -// $$\ $$\ $$$$$$$$\ $$\ $$$$$$$\ $$$$$$$$\ $$$$$$$\ $$$$$$\ -// $$ | $$ |$$ _____|$$ | $$ __$$\ $$ _____|$$ __$$\ $$ __$$\ -// $$ | $$ |$$ | $$ | $$ | $$ |$$ | $$ | $$ |$$ / \__| -// $$$$$$$$ |$$$$$\ $$ | $$$$$$$ |$$$$$\ $$$$$$$ |\$$$$$$\ -// $$ __$$ |$$ __| $$ | $$ ____/ $$ __| $$ __$$< \____$$\ -// $$ | $$ |$$ | $$ | $$ | $$ | $$ | $$ |$$\ $$ | -// $$ | $$ |$$$$$$$$\ $$$$$$$$\ $$ | $$$$$$$$\ $$ | $$ |\$$$$$$ | -// \__| \__|\________|\________|\__| \________|\__| \__| \______/ -// -// dn_helpers.h -- Helper functions/data structures -// -//////////////////////////////////////////////////////////////////////////////////////////////////// -*/ - -// NOTE: DN_PCG32 ////////////////////////////////////////////////////////////////////////////////// -struct DN_PCG32 { uint64_t state; }; - -#if !defined(DN_NO_JSON_BUILDER) -// NOTE: DN_JSONBuilder //////////////////////////////////////////////////////////////////////////// -enum DN_JSONBuilderItem -{ - DN_JSONBuilderItem_Empty, - DN_JSONBuilderItem_OpenContainer, - DN_JSONBuilderItem_CloseContainer, - DN_JSONBuilderItem_KeyValue, -}; - -struct DN_JSONBuilder -{ - bool use_stdout; // When set, ignore the string builder and dump immediately to stdout - DN_Str8Builder string_builder; // (Internal) - int indent_level; // (Internal) - int spaces_per_indent; // The number of spaces per indent level - DN_JSONBuilderItem last_item; -}; -#endif // !defined(DN_NO_JSON_BUIDLER) - -// NOTE: DN_BinarySearch /////////////////////////////////////////////////////////////////////////// -template -using DN_BinarySearchLessThanProc = bool(T const &lhs, T const &rhs); - -template -bool DN_BinarySearch_DefaultLessThan(T const &lhs, T const &rhs); - -enum DN_BinarySearchType -{ - // Index of the match. If no match is found, found is set to false and the - // index is set to the index where the match should be inserted/exist, if - // it were in the array - DN_BinarySearchType_Match, - - // Index of the first element in the array that is `element >= find`. If no such - // item is found or the array is empty, then, the index is set to the array - // size and found is set to `false`. - // - // For example: - // int array[] = {0, 1, 2, 3, 4, 5}; - // DN_BinarySearchResult result = DN_BinarySearch(array, DN_ArrayCountU(array), 4, DN_BinarySearchType_LowerBound); - // printf("%zu\n", result.index); // Prints index '4' - - DN_BinarySearchType_LowerBound, - - // Index of the first element in the array that is `element > find`. If no such - // item is found or the array is empty, then, the index is set to the array - // size and found is set to `false`. - // - // For example: - // int array[] = {0, 1, 2, 3, 4, 5}; - // DN_BinarySearchResult result = DN_BinarySearch(array, DN_ArrayCountU(array), 4, DN_BinarySearchType_UpperBound); - // printf("%zu\n", result.index); // Prints index '5' - - DN_BinarySearchType_UpperBound, -}; - -struct DN_BinarySearchResult -{ - bool found; - DN_USize index; -}; - -template -using DN_QSortLessThanProc = bool(T const &a, T const &b, void *user_context); - -// NOTE: DN_PCG32 ////////////////////////////////////////////////////////////////////////////////// -DN_API DN_PCG32 DN_PCG32_Init (uint64_t seed); -DN_API uint32_t DN_PCG32_Next (DN_PCG32 *rng); -DN_API uint64_t DN_PCG32_Next64 (DN_PCG32 *rng); -DN_API uint32_t DN_PCG32_Range (DN_PCG32 *rng, uint32_t low, uint32_t high); -DN_API DN_F32 DN_PCG32_NextF32 (DN_PCG32 *rng); -DN_API DN_F64 DN_PCG32_NextF64 (DN_PCG32 *rng); -DN_API void DN_PCG32_Advance (DN_PCG32 *rng, uint64_t delta); - -#if !defined(DN_NO_JSON_BUILDER) -// NOTE: DN_JSONBuilder //////////////////////////////////////////////////////////////////////////// -#define DN_JSONBuilder_Object(builder) \ - DN_DeferLoop(DN_JSONBuilder_ObjectBegin(builder), \ - DN_JSONBuilder_ObjectEnd(builder)) - -#define DN_JSONBuilder_ObjectNamed(builder, name) \ - DN_DeferLoop(DN_JSONBuilder_ObjectBeginNamed(builder, name), \ - DN_JSONBuilder_ObjectEnd(builder)) - -#define DN_JSONBuilder_Array(builder) \ - DN_DeferLoop(DN_JSONBuilder_ArrayBegin(builder), \ - DN_JSONBuilder_ArrayEnd(builder)) - -#define DN_JSONBuilder_ArrayNamed(builder, name) \ - DN_DeferLoop(DN_JSONBuilder_ArrayBeginNamed(builder, name), \ - DN_JSONBuilder_ArrayEnd(builder)) - -DN_API DN_JSONBuilder DN_JSONBuilder_Init (DN_Arena *arena, int spaces_per_indent); -DN_API DN_Str8 DN_JSONBuilder_Build (DN_JSONBuilder const *builder, DN_Arena *arena); -DN_API void DN_JSONBuilder_KeyValue (DN_JSONBuilder *builder, DN_Str8 key, DN_Str8 value); -DN_API void DN_JSONBuilder_KeyValueF (DN_JSONBuilder *builder, DN_Str8 key, char const *value_fmt, ...); -DN_API void DN_JSONBuilder_ObjectBeginNamed (DN_JSONBuilder *builder, DN_Str8 name); -DN_API void DN_JSONBuilder_ObjectEnd (DN_JSONBuilder *builder); -DN_API void DN_JSONBuilder_ArrayBeginNamed (DN_JSONBuilder *builder, DN_Str8 name); -DN_API void DN_JSONBuilder_ArrayEnd (DN_JSONBuilder *builder); -DN_API void DN_JSONBuilder_Str8Named (DN_JSONBuilder *builder, DN_Str8 key, DN_Str8 value); -DN_API void DN_JSONBuilder_LiteralNamed (DN_JSONBuilder *builder, DN_Str8 key, DN_Str8 value); -DN_API void DN_JSONBuilder_U64Named (DN_JSONBuilder *builder, DN_Str8 key, uint64_t value); -DN_API void DN_JSONBuilder_I64Named (DN_JSONBuilder *builder, DN_Str8 key, int64_t value); -DN_API void DN_JSONBuilder_F64Named (DN_JSONBuilder *builder, DN_Str8 key, double value, int decimal_places); -DN_API void DN_JSONBuilder_BoolNamed (DN_JSONBuilder *builder, DN_Str8 key, bool value); - -#define DN_JSONBuilder_ObjectBegin(builder) DN_JSONBuilder_ObjectBeginNamed(builder, DN_Str8Lit("")) -#define DN_JSONBuilder_ArrayBegin(builder) DN_JSONBuilder_ArrayBeginNamed(builder, DN_Str8Lit("")) -#define DN_JSONBuilder_Str8(builder, value) DN_JSONBuilder_Str8Named(builder, DN_Str8Lit(""), value) -#define DN_JSONBuilder_Literal(builder, value) DN_JSONBuilder_LiteralNamed(builder, DN_Str8Lit(""), value) -#define DN_JSONBuilder_U64(builder, value) DN_JSONBuilder_U64Named(builder, DN_Str8Lit(""), value) -#define DN_JSONBuilder_I64(builder, value) DN_JSONBuilder_I64Named(builder, DN_Str8Lit(""), value) -#define DN_JSONBuilder_F64(builder, value) DN_JSONBuilder_F64Named(builder, DN_Str8Lit(""), value) -#define DN_JSONBuilder_Bool(builder, value) DN_JSONBuilder_BoolNamed(builder, DN_Str8Lit(""), value) -#endif // !defined(DN_NO_JSON_BUILDER) - -// NOTE: DN_BinarySearch -template bool DN_BinarySearch_DefaultLessThan(T const &lhs, T const &rhs); -template DN_BinarySearchResult DN_BinarySearch (T const *array, DN_USize array_size, T const &find, DN_BinarySearchType type = DN_BinarySearchType_Match, DN_BinarySearchLessThanProc less_than = DN_BinarySearch_DefaultLessThan); - -// NOTE: DN_QSort -template bool DN_QSort_DefaultLessThan(T const &lhs, T const &rhs, void *user_context); -template void DN_QSort (T *array, DN_USize array_size, void *user_context, DN_QSortLessThanProc less_than = DN_QSort_DefaultLessThan); - -// NOTE: DN_BinarySearch -template -bool DN_BinarySearch_DefaultLessThan(T const &lhs, T const &rhs) -{ - bool result = lhs < rhs; - return result; -} - -template -DN_BinarySearchResult DN_BinarySearch(T const *array, - DN_USize array_size, - T const &find, - DN_BinarySearchType type, - DN_BinarySearchLessThanProc less_than) -{ - DN_BinarySearchResult result = {}; - if (!array || array_size <= 0 || !less_than) - return result; - - T const *end = array + array_size; - T const *first = array; - T const *last = end; - while (first != last) { - DN_USize count = last - first; - T const *it = first + (count / 2); - - bool advance_first = false; - if (type == DN_BinarySearchType_UpperBound) - advance_first = !less_than(find, it[0]); - else - advance_first = less_than(it[0], find); - - if (advance_first) - first = it + 1; - else - last = it; - } - - switch (type) { - case DN_BinarySearchType_Match: { - result.found = first != end && !less_than(find, *first); - } break; - - case DN_BinarySearchType_LowerBound: /*FALLTHRU*/ - case DN_BinarySearchType_UpperBound: { - result.found = first != end; - } break; - } - - result.index = first - array; - return result; -} - -// NOTE: DN_QSort ////////////////////////////////////////////////////////////////////////////////// -template -bool DN_QSort_DefaultLessThan(T const &lhs, T const &rhs, void *user_context) -{ - (void)user_context; - bool result = lhs < rhs; - return result; -} - -template -void DN_QSort(T *array, DN_USize array_size, void *user_context, DN_QSortLessThanProc less_than) -{ - if (!array || array_size <= 1 || !less_than) - return; - - // NOTE: Insertion Sort, under 24->32 is an optimal amount ///////////////////////////////////// - const DN_USize QSORT_THRESHOLD = 24; - if (array_size < QSORT_THRESHOLD) { - for (DN_USize item_to_insert_index = 1; item_to_insert_index < array_size; item_to_insert_index++) { - for (DN_USize index = 0; index < item_to_insert_index; index++) { - if (!less_than(array[index], array[item_to_insert_index], user_context)) { - T item_to_insert = array[item_to_insert_index]; - for (DN_USize i = item_to_insert_index; i > index; i--) - array[i] = array[i - 1]; - - array[index] = item_to_insert; - break; - } - } - } - 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; - - // Swap pivot with last index, so pivot is always at the end of the array. - // This makes logic much simpler. - DN_Swap(array[last_index], array[pivot_index]); - pivot_index = last_index; - - // 4^, 8, 7, 5, 2, 3, 6 - if (less_than(array[start_index], array[pivot_index], 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 (less_than(array[index], array[pivot_index], user_context)) { - DN_Swap(array[partition_index], array[index]); - partition_index++; - } - } - - // Move pivot to right of partition - // 4, 5, 2, 3, |6, 8, ^7* - DN_Swap(array[partition_index], array[pivot_index]); - DN_QSort(array, partition_index, user_context, less_than); - - // 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 + one_after_partition_index, (array_size - one_after_partition_index), user_context, less_than); -} - -#endif // !defined(DN_HELPERS_H) -#endif - -/* -//////////////////////////////////////////////////////////////////////////////////////////////////// -// -// $$\ $$\ $$$$$$$$\ $$\ $$$$$$$\ $$$$$$$$\ $$$$$$$\ $$$$$$\ -// $$ | $$ |$$ _____|$$ | $$ __$$\ $$ _____|$$ __$$\ $$ __$$\ -// $$ | $$ |$$ | $$ | $$ | $$ |$$ | $$ | $$ |$$ / \__| -// $$$$$$$$ |$$$$$\ $$ | $$$$$$$ |$$$$$\ $$$$$$$ |\$$$$$$\ -// $$ __$$ |$$ __| $$ | $$ ____/ $$ __| $$ __$$< \____$$\ -// $$ | $$ |$$ | $$ | $$ | $$ | $$ | $$ |$$\ $$ | -// $$ | $$ |$$$$$$$$\ $$$$$$$$\ $$ | $$$$$$$$\ $$ | $$ |\$$$$$$ | -// \__| \__|\________|\________|\__| \________|\__| \__| \______/ -// -// dn_helpers.cpp -// -//////////////////////////////////////////////////////////////////////////////////////////////////// -*/ - -// NOTE: DN_PCG32 ////////////////////////////////////////////////////////////////////////////////// -#define DN_PCG_DEFAULT_MULTIPLIER_64 6364136223846793005ULL -#define DN_PCG_DEFAULT_INCREMENT_64 1442695040888963407ULL - -DN_API DN_PCG32 DN_PCG32_Init(uint64_t seed) -{ - DN_PCG32 result = {}; - DN_PCG32_Next(&result); - result.state += seed; - DN_PCG32_Next(&result); - return result; -} - -DN_API uint32_t DN_PCG32_Next(DN_PCG32 *rng) -{ - uint64_t state = rng->state; - rng->state = state * DN_PCG_DEFAULT_MULTIPLIER_64 + DN_PCG_DEFAULT_INCREMENT_64; - - // XSH-RR - uint32_t value = (uint32_t)((state ^ (state >> 18)) >> 27); - int rot = state >> 59; - return rot ? (value >> rot) | (value << (32 - rot)) : value; -} - -DN_API uint64_t DN_PCG32_Next64(DN_PCG32 *rng) -{ - uint64_t value = DN_PCG32_Next(rng); - value <<= 32; - value |= DN_PCG32_Next(rng); - return value; -} - -DN_API uint32_t DN_PCG32_Range(DN_PCG32 *rng, uint32_t low, uint32_t high) -{ - uint32_t bound = high - low; - uint32_t threshold = -(int32_t)bound % bound; - - for (;;) { - uint32_t r = DN_PCG32_Next(rng); - if (r >= threshold) - return low + (r % bound); - } -} - -DN_API float DN_PCG32_NextF32(DN_PCG32 *rng) -{ - uint32_t x = DN_PCG32_Next(rng); - return (float)(int32_t)(x >> 8) * 0x1.0p-24f; -} - -DN_API double DN_PCG32_NextF64(DN_PCG32 *rng) -{ - uint64_t x = DN_PCG32_Next64(rng); - return (double)(int64_t)(x >> 11) * 0x1.0p-53; -} - -DN_API void DN_PCG32_Advance(DN_PCG32 *rng, uint64_t delta) -{ - uint64_t cur_mult = DN_PCG_DEFAULT_MULTIPLIER_64; - uint64_t cur_plus = DN_PCG_DEFAULT_INCREMENT_64; - - uint64_t acc_mult = 1; - uint64_t acc_plus = 0; - - while (delta != 0) { - if (delta & 1) { - acc_mult *= cur_mult; - acc_plus = acc_plus * cur_mult + cur_plus; - } - cur_plus = (cur_mult + 1) * cur_plus; - cur_mult *= cur_mult; - delta >>= 1; - } - - rng->state = acc_mult * rng->state + acc_plus; -} - -#if !defined(DN_NO_JSON_BUILDER) -// NOTE: DN_JSONBuilder //////////////////////////////////////////////////////////////////////////// -DN_API DN_JSONBuilder DN_JSONBuilder_Init(DN_Arena *arena, int spaces_per_indent) -{ - DN_JSONBuilder result = {}; - result.spaces_per_indent = spaces_per_indent; - result.string_builder.arena = arena; - return result; -} - -DN_API DN_Str8 DN_JSONBuilder_Build(DN_JSONBuilder const *builder, DN_Arena *arena) -{ - DN_Str8 result = DN_Str8BuilderBuild(&builder->string_builder, arena); - return result; -} - -DN_API void DN_JSONBuilder_KeyValue(DN_JSONBuilder *builder, DN_Str8 key, DN_Str8 value) -{ - if (key.size == 0 && value.size == 0) - return; - - DN_JSONBuilderItem item = DN_JSONBuilderItem_KeyValue; - if (value.size >= 1) { - if (value.data[0] == '{' || value.data[0] == '[') - item = DN_JSONBuilderItem_OpenContainer; - else if (value.data[0] == '}' || value.data[0] == ']') - item = DN_JSONBuilderItem_CloseContainer; - } - - bool adding_to_container_with_items = - item != DN_JSONBuilderItem_CloseContainer && (builder->last_item == DN_JSONBuilderItem_KeyValue || - builder->last_item == DN_JSONBuilderItem_CloseContainer); - - uint8_t prefix_size = 0; - char prefix[2] = {0}; - if (adding_to_container_with_items) - prefix[prefix_size++] = ','; - - if (builder->last_item != DN_JSONBuilderItem_Empty) - prefix[prefix_size++] = '\n'; - - if (item == DN_JSONBuilderItem_CloseContainer) - builder->indent_level--; - - int spaces_per_indent = builder->spaces_per_indent ? builder->spaces_per_indent : 2; - int spaces = builder->indent_level * spaces_per_indent; - - if (key.size) - DN_Str8BuilderAppendF(&builder->string_builder, - "%.*s%*c\"%.*s\": %.*s", - prefix_size, - prefix, - spaces, - ' ', - DN_Str8PrintFmt(key), - DN_Str8PrintFmt(value)); - else if (spaces == 0) - DN_Str8BuilderAppendF(&builder->string_builder, "%.*s%.*s", prefix_size, prefix, DN_Str8PrintFmt(value)); - else - DN_Str8BuilderAppendF(&builder->string_builder, "%.*s%*c%.*s", prefix_size, prefix, spaces, ' ', DN_Str8PrintFmt(value)); - - if (item == DN_JSONBuilderItem_OpenContainer) - builder->indent_level++; - - builder->last_item = item; -} - -DN_API void DN_JSONBuilder_KeyValueFV(DN_JSONBuilder *builder, DN_Str8 key, char const *value_fmt, va_list args) -{ - DN_OSTLSTMem tmem = DN_OS_TLSTMem(builder->string_builder.arena); - DN_Str8 value = DN_Str8FromFmtVArena(tmem.arena, value_fmt, args); - DN_JSONBuilder_KeyValue(builder, key, value); -} - -DN_API void DN_JSONBuilder_KeyValueF(DN_JSONBuilder *builder, DN_Str8 key, char const *value_fmt, ...) -{ - va_list args; - va_start(args, value_fmt); - DN_JSONBuilder_KeyValueFV(builder, key, value_fmt, args); - va_end(args); -} - -DN_API void DN_JSONBuilder_ObjectBeginNamed(DN_JSONBuilder *builder, DN_Str8 name) -{ - DN_JSONBuilder_KeyValue(builder, name, DN_Str8Lit("{")); -} - -DN_API void DN_JSONBuilder_ObjectEnd(DN_JSONBuilder *builder) -{ - DN_JSONBuilder_KeyValue(builder, DN_Str8Lit(""), DN_Str8Lit("}")); -} - -DN_API void DN_JSONBuilder_ArrayBeginNamed(DN_JSONBuilder *builder, DN_Str8 name) -{ - DN_JSONBuilder_KeyValue(builder, name, DN_Str8Lit("[")); -} - -DN_API void DN_JSONBuilder_ArrayEnd(DN_JSONBuilder *builder) -{ - DN_JSONBuilder_KeyValue(builder, DN_Str8Lit(""), DN_Str8Lit("]")); -} - -DN_API void DN_JSONBuilder_Str8Named(DN_JSONBuilder *builder, DN_Str8 key, DN_Str8 value) -{ - DN_JSONBuilder_KeyValueF(builder, key, "\"%.*s\"", value.size, value.data); -} - -DN_API void DN_JSONBuilder_LiteralNamed(DN_JSONBuilder *builder, DN_Str8 key, DN_Str8 value) -{ - DN_JSONBuilder_KeyValueF(builder, key, "%.*s", value.size, value.data); -} - -DN_API void DN_JSONBuilder_U64Named(DN_JSONBuilder *builder, DN_Str8 key, uint64_t value) -{ - DN_JSONBuilder_KeyValueF(builder, key, "%I64u", value); -} - -DN_API void DN_JSONBuilder_I64Named(DN_JSONBuilder *builder, DN_Str8 key, int64_t value) -{ - DN_JSONBuilder_KeyValueF(builder, key, "%I64d", value); -} - -DN_API void DN_JSONBuilder_F64Named(DN_JSONBuilder *builder, DN_Str8 key, double value, int decimal_places) -{ - if (!builder) - return; - - if (decimal_places >= 16) - decimal_places = 16; - - // NOTE: Generate the format string for the float, depending on how many - // decimals places it wants. - char float_fmt[16]; - if (decimal_places > 0) { - // NOTE: Emit the format string "%.f" i.e. %.1f - DN_SNPrintF(float_fmt, sizeof(float_fmt), "%%.%df", decimal_places); - } else { - // NOTE: Emit the format string "%f" - DN_SNPrintF(float_fmt, sizeof(float_fmt), "%%f"); - } - DN_JSONBuilder_KeyValueF(builder, key, float_fmt, value); -} - -DN_API void DN_JSONBuilder_BoolNamed(DN_JSONBuilder *builder, DN_Str8 key, bool value) -{ - DN_Str8 value_string = value ? DN_Str8Lit("true") : DN_Str8Lit("false"); - DN_JSONBuilder_KeyValueF(builder, key, "%.*s", value_string.size, value_string.data); -} -#endif // !defined(DN_NO_JSON_BUILDER) \ No newline at end of file +#define DN_HELPERS_CPP \ No newline at end of file diff --git a/Single-Header/dn_single_header.h b/Single-Header/dn_single_header.h index abcb21a..08a475c 100644 --- a/Single-Header/dn_single_header.h +++ b/Single-Header/dn_single_header.h @@ -1,62 +1,156 @@ -// Generated by the DN single header generator 2025-11-30 21:32:49 +// Generated by the DN single header generator 2026-05-18 11:16:15 -#if !defined(DN_BASE_INC_H) -#define DN_BASE_INC_H +#if !defined(DN_H) +#define DN_H -// NOTE: DN configuration -// All the following configuration options are optional. If omitted, DN has default behaviours to -// handle the various options. +// NOTE: DN +// Getting Started +// Include this mega header `dn.h` and define the following symbols to `1` to conditionally +// enable the interfaces for those features. Additionally in the same or different translation +// unit, include `dn.cpp` with the same symbols defined to enable the implementation of these +// features. // -// Platform Target -// Define one of the following directives to configure this library to compile for that platform. -// By default, the library will auto-detect the current host platform and select that as the -// target platform. +// See the configuration section for more information on other symbols that can be defined. // -// DN_PLATFORM_EMSCRIPTEN -// DN_PLATFORM_POSIX -// DN_PLATFORM_WIN32 -// -// For example -// -// #define DN_PLATFORM_WIN32 -// -// Will ensure that is included and the OS layer is implemented using Win32 -// primitives. -// -// Static functions -// All public functions in the DN library are prefixed with the macro '#define DN_API'. By -// default 'DN_API' is not defined to anything. Define -// -// DN_STATIC_API -// -// To replace all the prefixed with 'static' ensuring that the functions in the library do not -// export an entry into the linking table and thereby optimise compilation times as the linker -// will not try to resolve symbols from other translation units from the the unit including the -// DN library. -// -// Using the in-built replacement header for (requires dn_os_inc.h) -// If you are building DN for the Windows platform, is a large legacy header that -// applications have to link to use Windows syscalls. By default DN library uses a replacement -// header for all the Windows functions that it uses in the OS layer removing the need to include -// to improve compilation times. This can be disabled by defining: -// -// DN_NO_WINDOWS_H_REPLACEMENT_HEADER -// -// To instead use . DN automatically detects if is included in an earlier -// translation unit and will automatically disable the in-built replacement header in which case -// this does not need to be defined. -// -// Freestanding -// 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. +// The following is a single translation unit example: +/* + #define DN_H_WITH_OS 1 + #define DN_H_WITH_CORE 1 + #define DN_H_WITH_HELPERS 1 + #define DN_H_WITH_ASYNC 1 + #define DN_H_WITH_NET 1 + #include "dn.h" -// DN: Single header generator inlined this file => #include "Base/dn_base_compiler.h" -#if !defined(DN_BASE_COMPILER_H) -#define DN_BASE_COMPILER_H + #define DN_CPP_WITH_TESTS 1 + #define DN_CPP_WITH_DEMO 1 + #include "dn.cpp" +*/ +// Then initialise the library at runtime by calling DN_Init(...). The library is laid out as: +// +// - The base layer (dn_base.h) which provides primitives that do not require a host operating +// system (e.g. freestanding) such as string manipulation, compiler intrinsics and containers. +// This layer is unconditionallly always available by compiling with this library. +// +// - The OS layer (dn_os.h) which provides primitives that use the OS such as file IO, threading +// synchronisation, memory allocation. This layer is OPTIONAL. +// +// - Extra layer provides helper utilities that are opt-in. These layers are OPTIONAL. +// +// Configuration +// Platform Target +// Define one of the following directives to configure this library to compile for that +// platform. By default, the library will auto-detect the current host platform and select that +// as the target platform. +// +// DN_PLATFORM_EMSCRIPTEN +// DN_PLATFORM_POSIX +// DN_PLATFORM_WIN32 +// +// For example +// +// #define DN_PLATFORM_WIN32 +// +// Will ensure that is included and the OS layer is implemented using Win32 +// primitives. +// +// Static functions +// All public functions in the DN library are prefixed with the macro '#define DN_API'. By +// default 'DN_API' is not defined to anything. Define +// +// DN_STATIC_API +// +// To replace all the functions prefixed with DN_API to be prefixed with 'static' ensuring that +// the functions in the library do not export an entry into the linking table. +// translation units. +// +// Disabling the in-built (if #define DN_H_WITH_OS 1) +// If you are building DN for the Windows platform, is a large legacy header that +// applications have to include to use Windows APIs. By default this library uses a replacement +// header for all the Windows functions that it uses in the OS layer removing the need to +// include to improve compilation times. This mini header will conflict with +// if it needs to be included in your project. The mini header can be disabled by +// defining: +// +// DN_NO_WINDOWS_H_REPLACEMENT_HEADER +// +// To instead use . DN automatically detects if is included in an earlier +// translation unit and will automatically disable the in-built replacement header in which case +// this does not need to be defined. +// +// Freestanding +// 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 +// +// #define DN_ASAN_POISON 1 +// +// Since arenas manage their own block of memory it does not automatically benefit from ASAN's +// memory markup that ASAN does and so it is implemented manually by using the ASAN user-level +// poisoning APIs. Similarly, since the arena recycles its own memory rather than release back +// to the OS, poisoning is not as effective for arenas but every little bit helps. +// +// Scrub Uninitialised Memory +// If this macro is defined, temp memory that is returned to an arena, or allocations freed by +// a pool are scrubbed to this specified byte, in absence of this bytes returned to the +// allocators are left as-is or memset to 0. For example to scrub bytes to 0xCD (MSVC's +// pattern) define as follows: +// +// #define DN_SCRUB_UNINIT_MEM_BYTE 0xCD +// +// Due to the recycling of memory in arenas and pool, similarly to ASAN poisoning this reduces +// the window in which a use-after-free can be detected using this guard, however every little +// bit helps. +// +// Arena temp memory use-after-free (UAF) tooling +// UAF Guard +// Set the following preprocessor value to 1 to enable UAF protection when using +// scratch/temporary memory functionality. Defaults to off, or 0 if not specified +// +// #define DN_ARENA_TEMP_MEM_UAF_GUARD 1 +// +// This enables arenas to markup itself with the active memory region and subsequent +// allocations check if the allocation belongs to the same or different region. Different +// regions cause a UAF violation. +// +// More detailed diagnostics can be enabled by setting the flag DN_ArenaFlags_TempMemUAFGuard +// on the affected arenas. Note that this incurs a performance penalty as each memory region +// will store a stacktrace of its creation. It's recommended in development builds to always +// run with temp-memory guarding, if a violation occurs, then enable tracing on the arena to +// pinpoint the issue. +// +// Enabling memory guard incurs additional memory requirements from the arena's backing +// memory block and additional book-keeping fields on each arena and their temp memory +// instances. +// +// UAF Tracing +// Set the following preprocessor value to 1 to enable tracing when the UAF guard triggers. +// Defaults to off, or 0 if not specified. +// +// #define DN_ARENA_TEMP_MEM_UAF_TRACE_ON_BY_DEFAULT 1 +// +// This opts in all arenas to tracing functionality by default globally. Arenas can opt out +// by setting the flag DN_ArenaFlags_TempMemUAFTraceDisable on the arena. The disable flag +// takes precedence over all other settings including the global preprocessor macro and the +// enablement flag (DN_ArenaFlags_TempMemUAFTrace). +// +// Tracing incurs an additional much heavier performance penalty than the UAF guard due to +// the stacktrace that is stored per region to report to the user when a UAF guard violation +// occurs. + +// DN: Single header generator commented out => #include "Base/dn_base.h" +#if !defined(DN_BASE_H) +#define DN_BASE_H + +// DN: Single header generator commented out => #if defined(_CLANGD) +// #include "../dn.h" +// #endif // NOTE: Compiler identification // Warning! Order is important here, clang-cl on Windows defines _MSC_VER @@ -93,9 +187,11 @@ #if defined(DN_COMPILER_MSVC) #define DN_MSVC_WARNING_PUSH __pragma(warning(push)) #define DN_MSVC_WARNING_DISABLE(...) __pragma(warning(disable :##__VA_ARGS__)) + #define DN_MSVC_WARNING_ENABLE(...) __pragma(warning(default :##__VA_ARGS__)) #define DN_MSVC_WARNING_POP __pragma(warning(pop)) #else #define DN_MSVC_WARNING_PUSH + #define DN_MSVC_WARNING_ENABLE(...) #define DN_MSVC_WARNING_DISABLE(...) #define DN_MSVC_WARNING_POP #endif @@ -214,13 +310,18 @@ #if DN_HAS_FEATURE(address_sanitizer) || defined(__SANITIZE_ADDRESS__) #include #endif -#endif // !defined(DN_BASE_COMPILER_H) -// DN: Single header generator inlined this file => #include "Base/dn_base.h" -#if !defined(DN_BASE_H) -#define DN_BASE_H -#if defined(_CLANGD) - // DN: Single header generator commented out this header => #include "../dn_base_inc.h" +// NOTE: Memory +#if !defined(DN_ARENA_TEMP_MEM_UAF_GUARD) + #define DN_ARENA_TEMP_MEM_UAF_GUARD 0 +#endif + +#if !defined(DN_ARENA_TEMP_MEM_UAF_TRACE_ON_BY_DEFAULT) + #define DN_ARENA_TEMP_MEM_UAF_TRACE_ON_BY_DEFAULT 0 +#endif + +#if !defined(DN_SCRUB_UNINIT_MEM_BYTE) + #define DN_SCRUB_UNINIT_MEM_BYTE 0 #endif // NOTE: Macros @@ -228,6 +329,12 @@ #define DN_TokenCombine2(x, y) x ## y #define DN_TokenCombine(x, y) DN_TokenCombine2(x, y) +#if defined(__aarch64__) || defined(_M_X64) || defined(__x86_64__) || defined(__x86_64) + #define DN_64_BIT +#else + #define DN_32_BIT +#endif + #include // va_list #include #include @@ -246,10 +353,10 @@ #define DN_ForLinkedListIt(it, T, list) struct { DN_USize index; T *data; } it = {0, list}; it.data; it.index++, it.data = ((it).data->next) #define DN_ForItCArray(it, T, array) struct { DN_USize index; T *data; } it = {0, &(array)[0]}; it.index < DN_ArrayCountU(array); it.index++, it.data = (array) + it.index -#define DN_AlignUpPowerOfTwo(value, pot) (((uintptr_t)(value) + ((uintptr_t)(pot) - 1)) & ~((uintptr_t)(pot) - 1)) -#define DN_AlignDownPowerOfTwo(value, pot) ((uintptr_t)(value) & ~((uintptr_t)(pot) - 1)) -#define DN_IsPowerOfTwo(value) ((((uintptr_t)(value)) & (((uintptr_t)(value)) - 1)) == 0) -#define DN_IsPowerOfTwoAligned(value, pot) ((((uintptr_t)value) & (((uintptr_t)pot) - 1)) == 0) +#define DN_AlignUpPowerOfTwo(value, pot) (((uintptr_t)(value) + ((uintptr_t)(pot) - 1)) & ~((uintptr_t)(pot) - 1)) +#define DN_AlignDownPowerOfTwo(value, pot) ((uintptr_t)(value) & ~((uintptr_t)(pot) - 1)) +#define DN_IsPowerOfTwo(value) ((((uintptr_t)(value)) & (((uintptr_t)(value)) - 1)) == 0) +#define DN_IsPowerOfTwoAligned(value, pot) ((((uintptr_t)value) & (((uintptr_t)pot) - 1)) == 0) // NOTE: String.h Dependencies #if !defined(DN_Memcpy) || !defined(DN_Memset) || !defined(DN_Memcmp) || !defined(DN_Memmove) @@ -283,13 +390,16 @@ #if !defined(DN_TanF32) #define DN_TanF32(val) tanf(val) #endif + #if !defined(DN_PowF32) + #define DN_PowF32(val, exp) powf(val, exp) + #endif #endif // NOTE: Math #define DN_PiF32 3.14159265359f -#define DN_DegreesToRadians(degrees) ((degrees) * (DN_PI / 180.0f)) -#define DN_RadiansToDegrees(radians) ((radians) * (180.f * DN_PI)) +#define DN_DegreesToRadsF32(degrees) ((degrees) * (DN_PiF32 / 180.0f)) +#define DN_RadsToDegreesF32(radians) ((radians) * (180.f * DN_PiF32)) #define DN_Abs(val) (((val) < 0) ? (-(val)) : (val)) #define DN_Max(a, b) (((a) > (b)) ? (a) : (b)) @@ -346,15 +456,22 @@ #endif #endif -// NOTE: Byte swaps -#define DN_ByteSwap64(u64) (((((u64) >> 56) & 0xFF) << 0) | \ - ((((u64) >> 48) & 0xFF) << 8) | \ - ((((u64) >> 40) & 0xFF) << 16) | \ - ((((u64) >> 32) & 0xFF) << 24) | \ - ((((u64) >> 24) & 0xFF) << 32) | \ - ((((u64) >> 16) & 0xFF) << 40) | \ - ((((u64) >> 8) & 0xFF) << 48) | \ - ((((u64) >> 0) & 0xFF) << 56)) +// NOTE: Helper macros to declare an array data structure for a given `Type` +#define DN_DArrayStructDecl(Type) \ + struct Type##Array \ + { \ + Type* data; \ + DN_USize count; \ + DN_USize max; \ + } + +#define DN_FixedArrayStructDecl(Type, capacity) \ + struct Type##x##capacity##Array \ + { \ + Type data[capacity]; \ + DN_USize count; \ + DN_USize max; \ + } // NOTE: Types typedef intptr_t DN_ISize; @@ -384,97 +501,6 @@ typedef DN_I32 DN_B32; #define DN_ISIZE_MAX INTPTR_MAX #define DN_ISIZE_MIN INTPTR_MIN -enum DN_ZMem -{ - DN_ZMem_No, // Memory can be handed out without zero-ing it out - DN_ZMem_Yes, // Memory should be zero-ed out before giving to the callee -}; - -struct DN_Str8 -{ - char *data; // The bytes of the string - DN_USize size; // The number of bytes in the string -}; - -struct DN_Str8x16 { char data[16]; DN_USize size; }; -struct DN_Str8x32 { char data[32]; DN_USize size; }; -struct DN_Str8x64 { char data[64]; DN_USize size; }; -struct DN_Str8x128 { char data[128]; DN_USize size; }; -struct DN_Str8x256 { char data[256]; DN_USize size; }; - -struct DN_Hex32 { char data[32]; }; -struct DN_Hex64 { char data[64]; }; -struct DN_Hex128 { char data[128]; }; - -struct DN_HexU64Str8 -{ - char data[(sizeof(DN_U64) * 2) + 1 /*null-terminator*/]; - DN_U8 size; -}; - -enum DN_HexFromU64Type -{ - DN_HexFromU64Type_Nil, - DN_HexFromU64Type_Uppercase, -}; - -struct DN_Str16 // A pointer and length style string that holds slices to UTF16 bytes. -{ - wchar_t *data; // The UTF16 bytes of the string - DN_USize size; // The number of characters in the string -}; - -struct DN_U8x16 { DN_U8 data[16]; }; -struct DN_U8x32 { DN_U8 data[32]; }; -struct DN_U8x64 { DN_U8 data[64]; }; - -template -struct DN_Slice // A pointer and length container of data -{ - T *data; - DN_USize size; - - T *begin() { return data; } - T *end() { return data + size; } - T const *begin() const { return data; } - T const *end() const { return data + size; } -}; - -struct DN_CallSite -{ - DN_Str8 file; - DN_Str8 function; - DN_U32 line; -}; - -#define DN_CALL_SITE DN_CallSite { DN_Str8Lit(__FILE__), DN_Str8Lit(__func__), __LINE__ } - -// NOTE: Defer Macro -#if defined(__cplusplus) -template -struct DN_Defer -{ - Procedure proc; - DN_Defer(Procedure p) : proc(p) {} - ~DN_Defer() { proc(); } -}; - -struct DN_DeferHelper -{ - template - DN_Defer operator+(Lambda lambda) { return DN_Defer(lambda); }; -}; - -#define DN_UniqueName(prefix) DN_TokenCombine(prefix, __LINE__) -#define DN_DEFER const auto DN_UniqueName(defer_lambda_) = DN_DeferHelper() + [&]() -#endif // defined(__cplusplus) - -#define DN_DeferLoop(begin, end) \ - bool DN_UniqueName(once) = (begin, true); \ - DN_UniqueName(once); \ - end, DN_UniqueName(once) = false - - // NOTE: Intrinsics // NOTE: DN_AtomicAdd/Exchange return the previous value store in the target #if defined(DN_COMPILER_MSVC) || defined(DN_COMPILER_CLANG_CL) @@ -532,12 +558,50 @@ struct DN_DeferHelper #error "Compiler not supported" #endif -#if defined(__aarch64__) || defined(_M_X64) || defined(__x86_64__) || defined(__x86_64) +#if defined(DN_64_BIT) #define DN_CountLeadingZerosUSize(value) DN_CountLeadingZerosU64(value) #else #define DN_CountLeadingZerosUSize(value) DN_CountLeadingZerosU32(value) #endif +enum DN_ZMem +{ + DN_ZMem_No, // Memory can be handed out without zero-ing it out + DN_ZMem_Yes, // Memory should be zero-ed out before giving to the callee +}; + +struct DN_Str8 +{ + char *data; // The bytes of the string + DN_USize size; // The number of bytes in the string +}; + +struct DN_Str8Slice +{ + DN_Str8 *data; + DN_USize count; +}; + +struct DN_Str8x16 { char data[16]; DN_USize size; }; +struct DN_Str8x32 { char data[32]; DN_USize size; }; +struct DN_Str8x64 { char data[64]; DN_USize size; }; +struct DN_Str8x128 { char data[128]; DN_USize size; }; +struct DN_Str8x256 { char data[256]; DN_USize size; }; +struct DN_Str8x512 { char data[512]; DN_USize size; }; +struct DN_Str8x1024 { char data[1024]; DN_USize size; }; + +struct DN_Str16 // A pointer and length style string that holds slices to UTF16 bytes. +{ + wchar_t *data; // The UTF16 bytes of the string + DN_USize size; // The number of characters in the string +}; + +struct DN_Str16Slice +{ + DN_Str16 *data; + DN_USize count; +}; + struct DN_CPURegisters { int eax; @@ -643,7464 +707,10 @@ struct DN_TicketMutex unsigned int volatile serving; // The ticket ID to block the mutex on until it is returned }; -struct DN_U64FromResult -{ - bool success; - DN_U64 value; -}; -struct DN_I64FromResult -{ - bool success; - DN_I64 value; -}; - -enum DN_MemCommit -{ - DN_MemCommit_No, - DN_MemCommit_Yes, -}; - -typedef DN_U32 DN_MemPage; -enum DN_MemPage_ -{ - // Exception on read/write with a page. This flag overrides the read/write - // access. - DN_MemPage_NoAccess = 1 << 0, - - DN_MemPage_Read = 1 << 1, // Only read permitted on the page. - - // Only write permitted on the page. On Windows this is not supported and - // will be promoted to read+write permissions. - DN_MemPage_Write = 1 << 2, - - DN_MemPage_ReadWrite = DN_MemPage_Read | DN_MemPage_Write, - - // Modifier used in conjunction with previous flags. Raises exception on - // first access to the page, then, the underlying protection flags are - // active. This is supported on Windows, on other OS's using this flag will - // set the OS equivalent of DN_MemPage_NoAccess. - // This flag must only be used in DN_Mem_Protect - DN_MemPage_Guard = 1 << 3, - - // If leak tracing is enabled, this flag will allow the allocation recorded - // from the reserve call to be leaked, e.g. not printed when leaks are - // dumped to the console. - DN_MemPage_AllocRecordLeakPermitted = 1 << 4, - - // If leak tracing is enabled this flag will prevent any allocation record - // from being created in the allocation table at all. If this flag is - // enabled, 'OSMemPage_AllocRecordLeakPermitted' has no effect since the - // record will never be created. - DN_MemPage_NoAllocRecordEntry = 1 << 5, - - // [INTERNAL] Do not use. All flags together do not constitute a correct - // configuration of pages. - DN_MemPage_All = DN_MemPage_NoAccess | - DN_MemPage_ReadWrite | - DN_MemPage_Guard | - DN_MemPage_AllocRecordLeakPermitted | - DN_MemPage_NoAllocRecordEntry, -}; - -#if !defined(DN_ARENA_RESERVE_SIZE) - #define DN_ARENA_RESERVE_SIZE DN_Megabytes(64) -#endif - -#if !defined(DN_ARENA_COMMIT_SIZE) - #define DN_ARENA_COMMIT_SIZE DN_Kilobytes(64) -#endif - -enum DN_Allocator -{ - DN_Allocator_Arena, - DN_Allocator_Pool, -}; - -struct DN_ArenaBlock -{ - DN_ArenaBlock *prev; - DN_U64 used; - DN_U64 commit; - DN_U64 reserve; - DN_U64 reserve_sum; -}; - -typedef DN_U32 DN_ArenaFlags; -enum DN_ArenaFlags_ -{ - DN_ArenaFlags_Nil = 0, - DN_ArenaFlags_NoGrow = 1 << 0, - DN_ArenaFlags_NoPoison = 1 << 1, - DN_ArenaFlags_NoAllocTrack = 1 << 2, - DN_ArenaFlags_AllocCanLeak = 1 << 3, - - // NOTE: Internal flags. Do not use - DN_ArenaFlags_UserBuffer = 1 << 4, - DN_ArenaFlags_MemFuncs = 1 << 5, -}; - -struct DN_ArenaInfo -{ - DN_U64 used; - DN_U64 commit; - DN_U64 reserve; - DN_U64 blocks; -}; - -struct DN_ArenaStats -{ - DN_ArenaInfo info; - DN_ArenaInfo hwm; -}; - -struct DN_ArenaStatsStr8x64 -{ - DN_Str8x64 info; - DN_Str8x64 hwm; -}; - -enum DN_ArenaMemFuncType -{ - DN_ArenaMemFuncType_Nil, - DN_ArenaMemFuncType_Basic, - DN_ArenaMemFuncType_VMem, -}; - -typedef void *(DN_ArenaMemBasicAllocFunc)(DN_USize size); -typedef void (DN_ArenaMemBasicDeallocFunc)(void *ptr); -typedef void *(DN_ArenaMemVMemReserveFunc)(DN_USize size, DN_MemCommit commit, DN_MemPage page_flags); -typedef bool (DN_ArenaMemVMemCommitFunc)(void *ptr, DN_USize size, DN_U32 page_flags); -typedef void (DN_ArenaMemVMemReleaseFunc)(void *ptr, DN_USize size); -struct DN_ArenaMemFuncs -{ - DN_ArenaMemFuncType type; - DN_ArenaMemBasicAllocFunc *basic_alloc; - DN_ArenaMemBasicDeallocFunc *basic_dealloc; - - DN_U32 vmem_page_size; - DN_ArenaMemVMemReserveFunc *vmem_reserve; - DN_ArenaMemVMemCommitFunc *vmem_commit; - DN_ArenaMemVMemReleaseFunc *vmem_release; -}; - -struct DN_Arena -{ - DN_ArenaMemFuncs mem_funcs; - DN_ArenaBlock *curr; - DN_ArenaStats stats; - DN_ArenaFlags flags; - DN_Str8 label; - DN_Arena *prev, *next; -}; - -struct DN_ArenaTempMem -{ - DN_Arena *arena; - DN_U64 used_sum; -}; - -struct DN_ArenaTempMemScope -{ - DN_ArenaTempMemScope(DN_Arena *arena); - ~DN_ArenaTempMemScope(); - DN_ArenaTempMem mem; -}; - -DN_USize const DN_ARENA_HEADER_SIZE = DN_AlignUpPowerOfTwo(sizeof(DN_Arena), 64); - -#if !defined(DN_POOL_DEFAULT_ALIGN) - #define DN_POOL_DEFAULT_ALIGN 16 -#endif - -struct DN_PoolSlot -{ - void *data; - DN_PoolSlot *next; -}; - -enum DN_PoolSlotSize -{ - DN_PoolSlotSize_32B, - DN_PoolSlotSize_64B, - DN_PoolSlotSize_128B, - DN_PoolSlotSize_256B, - DN_PoolSlotSize_512B, - DN_PoolSlotSize_1KiB, - DN_PoolSlotSize_2KiB, - DN_PoolSlotSize_4KiB, - DN_PoolSlotSize_8KiB, - DN_PoolSlotSize_16KiB, - DN_PoolSlotSize_32KiB, - DN_PoolSlotSize_64KiB, - DN_PoolSlotSize_128KiB, - DN_PoolSlotSize_256KiB, - DN_PoolSlotSize_512KiB, - DN_PoolSlotSize_1MiB, - DN_PoolSlotSize_2MiB, - DN_PoolSlotSize_4MiB, - DN_PoolSlotSize_8MiB, - DN_PoolSlotSize_16MiB, - DN_PoolSlotSize_32MiB, - DN_PoolSlotSize_64MiB, - DN_PoolSlotSize_128MiB, - DN_PoolSlotSize_256MiB, - DN_PoolSlotSize_512MiB, - DN_PoolSlotSize_1GiB, - DN_PoolSlotSize_2GiB, - DN_PoolSlotSize_4GiB, - DN_PoolSlotSize_8GiB, - DN_PoolSlotSize_16GiB, - DN_PoolSlotSize_32GiB, - DN_PoolSlotSize_Count, -}; - -struct DN_Pool -{ - DN_Arena *arena; - DN_PoolSlot *slots[DN_PoolSlotSize_Count]; - DN_U8 align; -}; - -struct DN_NibbleFromU8Result -{ - char nibble0; - char nibble1; -}; - -enum DN_Str8EqCase -{ - DN_Str8EqCase_Sensitive, - DN_Str8EqCase_Insensitive, -}; - -enum DN_Str8IsAllType -{ - DN_Str8IsAllType_Digits, - DN_Str8IsAllType_Hex, -}; - -struct DN_Str8BSplitResult -{ - DN_Str8 lhs; - DN_Str8 rhs; -}; - -struct DN_Str8FindResult -{ - bool found; // True if string was found. If false, the subsequent fields below are not set. - DN_USize index; // Index in the buffer where the found string starts - DN_Str8 match; // Matching string in the buffer that was searched - DN_Str8 match_to_end_of_buffer; // Substring containing the found string to the end of the buffer - DN_Str8 after_match_to_end_of_buffer; // Substring starting after the found string to the end of the buffer - DN_Str8 start_to_before_match; // Substring from the start of the buffer up until the found string, not including it -}; - -enum DN_Str8FindFlag -{ - DN_Str8FindFlag_Digit = 1 << 0, // 0-9 - DN_Str8FindFlag_Whitespace = 1 << 1, // '\r', '\t', '\n', ' ' - DN_Str8FindFlag_Alphabet = 1 << 2, // A-Z, a-z - DN_Str8FindFlag_Plus = 1 << 3, // + - DN_Str8FindFlag_Minus = 1 << 4, // - - DN_Str8FindFlag_AlphaNum = DN_Str8FindFlag_Alphabet | DN_Str8FindFlag_Digit, -}; - -enum DN_Str8SplitIncludeEmptyStrings -{ - DN_Str8SplitIncludeEmptyStrings_No, - DN_Str8SplitIncludeEmptyStrings_Yes, -}; - -struct DN_Str8TruncateResult -{ - bool truncated; - DN_Str8 str8; -}; - -struct DN_Str8SplitResult -{ - DN_Str8 *data; - DN_USize count; -}; - -struct DN_Str8Link -{ - DN_Str8 string; // The string - DN_Str8Link *next; // The next string in the linked list - DN_Str8Link *prev; // The prev string in the linked list -}; - -struct DN_Str8Builder -{ - DN_Arena *arena; // Allocator to use to back the string list - DN_Str8Link *head; // First string in the linked list of strings - DN_Str8Link *tail; // Last string in the linked list of strings - DN_USize string_size; // The size in bytes necessary to construct the current string - DN_USize count; // The number of links in the linked list of strings -}; - -enum DN_Str8BuilderAdd -{ - DN_Str8BuilderAdd_Append, - DN_Str8BuilderAdd_Prepend, -}; - -typedef DN_U32 DN_AgeUnit; -enum DN_AgeUnit_ -{ - DN_AgeUnit_Ms = 1 << 0, - DN_AgeUnit_Sec = 1 << 1, - DN_AgeUnit_Min = 1 << 2, - DN_AgeUnit_Hr = 1 << 3, - DN_AgeUnit_Day = 1 << 4, - DN_AgeUnit_Week = 1 << 5, - DN_AgeUnit_Year = 1 << 6, - DN_AgeUnit_FractionalSec = 1 << 7, - DN_AgeUnit_HMS = DN_AgeUnit_Sec | DN_AgeUnit_Min | DN_AgeUnit_Hr, - DN_AgeUnit_All = DN_AgeUnit_Ms | DN_AgeUnit_HMS | DN_AgeUnit_Day | DN_AgeUnit_Week | DN_AgeUnit_Year, -}; - -enum DN_ByteCountType -{ - DN_ByteCountType_B, - DN_ByteCountType_KiB, - DN_ByteCountType_MiB, - DN_ByteCountType_GiB, - DN_ByteCountType_TiB, - DN_ByteCountType_Count, - DN_ByteCountType_Auto, -}; - -struct DN_ByteCountResult -{ - DN_ByteCountType type; - DN_Str8 suffix; // "KiB", "MiB", "GiB" .. e.t.c - DN_F64 bytes; -}; - -struct DN_Date -{ - DN_U8 day; - DN_U8 month; - DN_U16 year; - DN_U8 hour; - DN_U8 minutes; - DN_U8 seconds; - DN_U16 milliseconds; -}; - -struct DN_FmtAppendResult -{ - DN_USize size_req; - DN_Str8 str8; - bool truncated; -}; - -struct DN_ProfilerAnchor -{ - // Inclusive refers to the time spent to complete the function call - // including all children functions. - // - // Exclusive refers to the time spent in the function, not including any - // time spent in children functions that we call that are also being - // profiled. If we recursively call into ourselves, the time we spent in - // our function is accumulated. - DN_U64 tsc_inclusive; - DN_U64 tsc_exclusive; - DN_U16 hit_count; - DN_Str8 name; -}; - -struct DN_ProfilerZone -{ - DN_U16 anchor_index; - DN_U64 begin_tsc; - DN_U16 parent_zone; - DN_U64 elapsed_tsc_at_zone_start; -}; - -struct DN_ProfilerAnchorArray -{ - DN_ProfilerAnchor *data; - DN_USize count; -}; - -typedef DN_U64 (DN_ProfilerTSCNowFunc)(); -struct DN_Profiler -{ - DN_USize frame_index; - DN_ProfilerAnchor *anchors; - DN_USize anchors_count; - DN_USize anchors_per_frame; - DN_U16 parent_zone; - bool paused; - DN_ProfilerTSCNowFunc *tsc_now; - DN_U64 tsc_frequency; - DN_ProfilerZone frame_zone; - DN_F64 frame_avg_tsc; -}; - -#if !defined(DN_STB_SPRINTF_HEADER_ONLY) - #define STB_SPRINTF_IMPLEMENTATION - #define STB_SPRINTF_STATIC -#endif - -DN_MSVC_WARNING_PUSH -DN_MSVC_WARNING_DISABLE(4505) // Unused function warning -DN_GCC_WARNING_PUSH -DN_GCC_WARNING_DISABLE(-Wunused-function) -// DN: Single header generator commented out this header => #include "../External/stb_sprintf.h" -// NOTE: Additional *unofficial* changes -// - Adding STBSP__ASAN to STBSP__PUBLICDEC so that MSVC's ASAN does not trigger (https://github.com/nothings/stb/pull/1350) -// - Adding __attribute__((no_sanitize("undefined"))) to STBSP__ASAN for CLANG so that UBSAN does not trigger (https://github.com/nothings/stb/pull/1477) -// - Adding '%S' for DN_Str8 -// - Using defined(__wasm64__) to correctly assign stbsp__uintptr to stbsp__uint64 for a 64bit WASM target. - -// stb_sprintf - v1.10 - public domain snprintf() implementation -// originally by Jeff Roberts / RAD Game Tools, 2015/10/20 -// http://github.com/nothings/stb -// -// allowed types: sc uidBboXx p AaGgEef n -// lengths : hh h ll j z t I64 I32 I -// -// Contributors: -// Fabian "ryg" Giesen (reformatting) -// github:aganm (attribute format) -// -// Contributors (bugfixes): -// github:d26435 -// github:trex78 -// github:account-login -// Jari Komppa (SI suffixes) -// Rohit Nirmal -// Marcin Wojdyr -// Leonard Ritter -// Stefano Zanotti -// Adam Allison -// Arvid Gerstmann -// Markus Kolb -// -// LICENSE: -// -// See end of file for license information. - -#ifndef STB_SPRINTF_H_INCLUDE -#define STB_SPRINTF_H_INCLUDE - -/* -Single file sprintf replacement. - -Originally written by Jeff Roberts at RAD Game Tools - 2015/10/20. -Hereby placed in public domain. - -This is a full sprintf replacement that supports everything that -the C runtime sprintfs support, including float/double, 64-bit integers, -hex floats, field parameters (%*.*d stuff), length reads backs, etc. - -Why would you need this if sprintf already exists? Well, first off, -it's *much* faster (see below). It's also much smaller than the CRT -versions code-space-wise. We've also added some simple improvements -that are super handy (commas in thousands, callbacks at buffer full, -for example). Finally, the format strings for MSVC and GCC differ -for 64-bit integers (among other small things), so this lets you use -the same format strings in cross platform code. - -It uses the standard single file trick of being both the header file -and the source itself. If you just include it normally, you just get -the header file function definitions. To get the code, you include -it from a C or C++ file and define STB_SPRINTF_IMPLEMENTATION first. - -It only uses va_args macros from the C runtime to do it's work. It -does cast doubles to S64s and shifts and divides U64s, which does -drag in CRT code on most platforms. - -It compiles to roughly 8K with float support, and 4K without. -As a comparison, when using MSVC static libs, calling sprintf drags -in 16K. - -API: -==== -int stbsp_sprintf( char * buf, char const * fmt, ... ) -int stbsp_snprintf( char * buf, int count, char const * fmt, ... ) - Convert an arg list into a buffer. stbsp_snprintf always returns - a zero-terminated string (unlike regular snprintf). - -int stbsp_vsprintf( char * buf, char const * fmt, va_list va ) -int stbsp_vsnprintf( char * buf, int count, char const * fmt, va_list va ) - Convert a va_list arg list into a buffer. stbsp_vsnprintf always returns - a zero-terminated string (unlike regular snprintf). - -int stbsp_vsprintfcb( STBSP_SPRINTFCB * callback, void * user, char * buf, char const * fmt, va_list va ) - typedef char * STBSP_SPRINTFCB( char const * buf, void * user, int len ); - Convert into a buffer, calling back every STB_SPRINTF_MIN chars. - Your callback can then copy the chars out, print them or whatever. - This function is actually the workhorse for everything else. - The buffer you pass in must hold at least STB_SPRINTF_MIN characters. - // you return the next buffer to use or 0 to stop converting - -void stbsp_set_separators( char comma, char period ) - Set the comma and period characters to use. - -FLOATS/DOUBLES: -=============== -This code uses a internal float->ascii conversion method that uses -doubles with error correction (double-doubles, for ~105 bits of -precision). This conversion is round-trip perfect - that is, an atof -of the values output here will give you the bit-exact double back. - -One difference is that our insignificant digits will be different than -with MSVC or GCC (but they don't match each other either). We also -don't attempt to find the minimum length matching float (pre-MSVC15 -doesn't either). - -If you don't need float or doubles at all, define STB_SPRINTF_NOFLOAT -and you'll save 4K of code space. - -64-BIT INTS: -============ -This library also supports 64-bit integers and you can use MSVC style or -GCC style indicators (%I64d or %lld). It supports the C99 specifiers -for size_t and ptr_diff_t (%jd %zd) as well. - -EXTRAS: -======= -Like some GCCs, for integers and floats, you can use a ' (single quote) -specifier and commas will be inserted on the thousands: "%'d" on 12345 -would print 12,345. - -For integers and floats, you can use a "$" specifier and the number -will be converted to float and then divided to get kilo, mega, giga or -tera and then printed, so "%$d" 1000 is "1.0 k", "%$.2d" 2536000 is -"2.53 M", etc. For byte values, use two $:s, like "%$$d" to turn -2536000 to "2.42 Mi". If you prefer JEDEC suffixes to SI ones, use three -$:s: "%$$$d" -> "2.42 M". To remove the space between the number and the -suffix, add "_" specifier: "%_$d" -> "2.53M". - -In addition to octal and hexadecimal conversions, you can print -integers in binary: "%b" for 256 would print 100. - -PERFORMANCE vs MSVC 2008 32-/64-bit (GCC is even slower than MSVC): -=================================================================== -"%d" across all 32-bit ints (4.8x/4.0x faster than 32-/64-bit MSVC) -"%24d" across all 32-bit ints (4.5x/4.2x faster) -"%x" across all 32-bit ints (4.5x/3.8x faster) -"%08x" across all 32-bit ints (4.3x/3.8x faster) -"%f" across e-10 to e+10 floats (7.3x/6.0x faster) -"%e" across e-10 to e+10 floats (8.1x/6.0x faster) -"%g" across e-10 to e+10 floats (10.0x/7.1x faster) -"%f" for values near e-300 (7.9x/6.5x faster) -"%f" for values near e+300 (10.0x/9.1x faster) -"%e" for values near e-300 (10.1x/7.0x faster) -"%e" for values near e+300 (9.2x/6.0x faster) -"%.320f" for values near e-300 (12.6x/11.2x faster) -"%a" for random values (8.6x/4.3x faster) -"%I64d" for 64-bits with 32-bit values (4.8x/3.4x faster) -"%I64d" for 64-bits > 32-bit values (4.9x/5.5x faster) -"%s%s%s" for 64 char strings (7.1x/7.3x faster) -"...512 char string..." ( 35.0x/32.5x faster!) -*/ - -#if defined(__clang__) - #if defined(__has_feature) && defined(__has_attribute) - #if __has_feature(address_sanitizer) - #if __has_attribute(__no_sanitize__) - #define STBSP__ASAN __attribute__((__no_sanitize__("address"))) - #elif __has_attribute(__no_sanitize_address__) - #define STBSP__ASAN __attribute__((__no_sanitize_address__)) - #elif __has_attribute(__no_address_safety_analysis__) - #define STBSP__ASAN __attribute__((__no_address_safety_analysis__)) - #endif - #endif - #endif -#elif defined(__GNUC__) && (__GNUC__ >= 5 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8)) - #if defined(__SANITIZE_ADDRESS__) && __SANITIZE_ADDRESS__ - #define STBSP__ASAN __attribute__((__no_sanitize_address__)) - #endif -#elif defined(_MSC_VER) - #if defined(__SANITIZE_ADDRESS__) - #define STBSP__ASAN __declspec(no_sanitize_address) - #endif -#endif - -#ifndef STBSP__ASAN -#define STBSP__ASAN -#endif - -#ifdef STB_SPRINTF_STATIC -#define STBSP__PUBLICDEC static STBSP__ASAN -#define STBSP__PUBLICDEF static STBSP__ASAN -#else -#ifdef __cplusplus -#define STBSP__PUBLICDEC extern "C" STBSP__ASAN -#define STBSP__PUBLICDEF extern "C" STBSP__ASAN -#else -#define STBSP__PUBLICDEC extern STBSP__ASAN -#define STBSP__PUBLICDEF STBSP__ASAN -#endif -#endif - -#if defined(__has_attribute) - #if __has_attribute(format) - #define STBSP__ATTRIBUTE_FORMAT(fmt,va) __attribute__((format(printf,fmt,va))) - #endif -#endif - -#ifndef STBSP__ATTRIBUTE_FORMAT -#define STBSP__ATTRIBUTE_FORMAT(fmt,va) -#endif - -#ifdef _MSC_VER -#define STBSP__NOTUSED(v) (void)(v) -#else -#define STBSP__NOTUSED(v) (void)sizeof(v) -#endif - -#include // for va_arg(), va_list() -#include // size_t, ptrdiff_t - -#ifndef STB_SPRINTF_MIN -#define STB_SPRINTF_MIN 512 // how many characters per callback -#endif -typedef char *STBSP_SPRINTFCB(const char *buf, void *user, int len); - -#ifndef STB_SPRINTF_DECORATE -#define STB_SPRINTF_DECORATE(name) stbsp_##name // define this before including if you want to change the names -#endif - -STBSP__PUBLICDEC int STB_SPRINTF_DECORATE(vsprintf)(char *buf, char const *fmt, va_list va); -STBSP__PUBLICDEC int STB_SPRINTF_DECORATE(vsnprintf)(char *buf, int count, char const *fmt, va_list va); -STBSP__PUBLICDEC int STB_SPRINTF_DECORATE(sprintf)(char *buf, char const *fmt, ...) STBSP__ATTRIBUTE_FORMAT(2,3); -STBSP__PUBLICDEC int STB_SPRINTF_DECORATE(snprintf)(char *buf, int count, char const *fmt, ...) STBSP__ATTRIBUTE_FORMAT(3,4); - -STBSP__PUBLICDEC int STB_SPRINTF_DECORATE(vsprintfcb)(STBSP_SPRINTFCB *callback, void *user, char *buf, char const *fmt, va_list va); -STBSP__PUBLICDEC void STB_SPRINTF_DECORATE(set_separators)(char comma, char period); - -#endif // STB_SPRINTF_H_INCLUDE - -#ifdef STB_SPRINTF_IMPLEMENTATION - -#define stbsp__uint32 unsigned int -#define stbsp__int32 signed int - -#ifdef _MSC_VER -#define stbsp__uint64 unsigned __int64 -#define stbsp__int64 signed __int64 -#else -#define stbsp__uint64 unsigned long long -#define stbsp__int64 signed long long -#endif -#define stbsp__uint16 unsigned short - -#ifndef stbsp__uintptr -#if defined(__ppc64__) || defined(__powerpc64__) || defined(__aarch64__) || defined(_M_X64) || defined(__x86_64__) || defined(__x86_64) || defined(__s390x__) || defined(__wasm64__) -#define stbsp__uintptr stbsp__uint64 -#else -#define stbsp__uintptr stbsp__uint32 -#endif -#endif - -#ifndef STB_SPRINTF_MSVC_MODE // used for MSVC2013 and earlier (MSVC2015 matches GCC) -#if defined(_MSC_VER) && (_MSC_VER < 1900) -#define STB_SPRINTF_MSVC_MODE -#endif -#endif - -#ifdef STB_SPRINTF_NOUNALIGNED // define this before inclusion to force stbsp_sprintf to always use aligned accesses -#define STBSP__UNALIGNED(code) -#else -#define STBSP__UNALIGNED(code) code -#endif - -#ifndef STB_SPRINTF_NOFLOAT -// internal float utility functions -static stbsp__int32 stbsp__real_to_str(char const **start, stbsp__uint32 *len, char *out, stbsp__int32 *decimal_pos, double value, stbsp__uint32 frac_digits); -static stbsp__int32 stbsp__real_to_parts(stbsp__int64 *bits, stbsp__int32 *expo, double value); -#define STBSP__SPECIAL 0x7000 -#endif - -static char stbsp__period = '.'; -static char stbsp__comma = ','; -static struct -{ - short temp; // force next field to be 2-byte aligned - char pair[201]; -} stbsp__digitpair = -{ - 0, - "00010203040506070809101112131415161718192021222324" - "25262728293031323334353637383940414243444546474849" - "50515253545556575859606162636465666768697071727374" - "75767778798081828384858687888990919293949596979899" -}; - -STBSP__PUBLICDEF void STB_SPRINTF_DECORATE(set_separators)(char pcomma, char pperiod) -{ - stbsp__period = pperiod; - stbsp__comma = pcomma; -} - -#define STBSP__LEFTJUST 1 -#define STBSP__LEADINGPLUS 2 -#define STBSP__LEADINGSPACE 4 -#define STBSP__LEADING_0X 8 -#define STBSP__LEADINGZERO 16 -#define STBSP__INTMAX 32 -#define STBSP__TRIPLET_COMMA 64 -#define STBSP__NEGATIVE 128 -#define STBSP__METRIC_SUFFIX 256 -#define STBSP__HALFWIDTH 512 -#define STBSP__METRIC_NOSPACE 1024 -#define STBSP__METRIC_1024 2048 -#define STBSP__METRIC_JEDEC 4096 - -static void stbsp__lead_sign(stbsp__uint32 fl, char *sign) -{ - sign[0] = 0; - if (fl & STBSP__NEGATIVE) { - sign[0] = 1; - sign[1] = '-'; - } else if (fl & STBSP__LEADINGSPACE) { - sign[0] = 1; - sign[1] = ' '; - } else if (fl & STBSP__LEADINGPLUS) { - sign[0] = 1; - sign[1] = '+'; - } -} - -static STBSP__ASAN stbsp__uint32 stbsp__strlen_limited(char const *s, stbsp__uint32 limit) -{ - char const * sn = s; - - // get up to 4-byte alignment - for (;;) { - if (((stbsp__uintptr)sn & 3) == 0) - break; - - if (!limit || *sn == 0) - return (stbsp__uint32)(sn - s); - - ++sn; - --limit; - } - - // scan over 4 bytes at a time to find terminating 0 - // this will intentionally scan up to 3 bytes past the end of buffers, - // but becase it works 4B aligned, it will never cross page boundaries - // (hence the STBSP__ASAN markup; the over-read here is intentional - // and harmless) - while (limit >= 4) { - stbsp__uint32 v = *(stbsp__uint32 *)sn; - // bit hack to find if there's a 0 byte in there - if ((v - 0x01010101) & (~v) & 0x80808080UL) - break; - - sn += 4; - limit -= 4; - } - - // handle the last few characters to find actual size - while (limit && *sn) { - ++sn; - --limit; - } - - return (stbsp__uint32)(sn - s); -} - -STBSP__PUBLICDEF int STB_SPRINTF_DECORATE(vsprintfcb)(STBSP_SPRINTFCB *callback, void *user, char *buf, char const *fmt, va_list va) -{ - static char hex[] = "0123456789abcdefxp"; - static char hexu[] = "0123456789ABCDEFXP"; - char *bf; - char const *f; - int tlen = 0; - - bf = buf; - f = fmt; - for (;;) { - stbsp__int32 fw, pr, tz; - stbsp__uint32 fl; - - // macros for the callback buffer stuff - #define stbsp__chk_cb_bufL(bytes) \ - { \ - int len = (int)(bf - buf); \ - if ((len + (bytes)) >= STB_SPRINTF_MIN) { \ - tlen += len; \ - if (0 == (bf = buf = callback(buf, user, len))) \ - goto done; \ - } \ - } - #define stbsp__chk_cb_buf(bytes) \ - { \ - if (callback) { \ - stbsp__chk_cb_bufL(bytes); \ - } \ - } - #define stbsp__flush_cb() \ - { \ - stbsp__chk_cb_bufL(STB_SPRINTF_MIN - 1); \ - } // flush if there is even one byte in the buffer - #define stbsp__cb_buf_clamp(cl, v) \ - cl = v; \ - if (callback) { \ - int lg = STB_SPRINTF_MIN - (int)(bf - buf); \ - if (cl > lg) \ - cl = lg; \ - } - - // fast copy everything up to the next % (or end of string) - for (;;) { - while (((stbsp__uintptr)f) & 3) { - schk1: - if (f[0] == '%') - goto scandd; - schk2: - if (f[0] == 0) - goto endfmt; - stbsp__chk_cb_buf(1); - *bf++ = f[0]; - ++f; - } - for (;;) { - // Check if the next 4 bytes contain %(0x25) or end of string. - // Using the 'hasless' trick: - // https://graphics.stanford.edu/~seander/bithacks.html#HasLessInWord - stbsp__uint32 v, c; - v = *(stbsp__uint32 *)f; - c = (~v) & 0x80808080; - if (((v ^ 0x25252525) - 0x01010101) & c) - goto schk1; - if ((v - 0x01010101) & c) - goto schk2; - if (callback) - if ((STB_SPRINTF_MIN - (int)(bf - buf)) < 4) - goto schk1; - #ifdef STB_SPRINTF_NOUNALIGNED - if(((stbsp__uintptr)bf) & 3) { - bf[0] = f[0]; - bf[1] = f[1]; - bf[2] = f[2]; - bf[3] = f[3]; - } else - #endif - { - *(stbsp__uint32 *)bf = v; - } - bf += 4; - f += 4; - } - } - scandd: - - ++f; - - // ok, we have a percent, read the modifiers first - fw = 0; - pr = -1; - fl = 0; - tz = 0; - - // flags - for (;;) { - switch (f[0]) { - // if we have left justify - case '-': - fl |= STBSP__LEFTJUST; - ++f; - continue; - // if we have leading plus - case '+': - fl |= STBSP__LEADINGPLUS; - ++f; - continue; - // if we have leading space - case ' ': - fl |= STBSP__LEADINGSPACE; - ++f; - continue; - // if we have leading 0x - case '#': - fl |= STBSP__LEADING_0X; - ++f; - continue; - // if we have thousand commas - case '\'': - fl |= STBSP__TRIPLET_COMMA; - ++f; - continue; - // if we have kilo marker (none->kilo->kibi->jedec) - case '$': - if (fl & STBSP__METRIC_SUFFIX) { - if (fl & STBSP__METRIC_1024) { - fl |= STBSP__METRIC_JEDEC; - } else { - fl |= STBSP__METRIC_1024; - } - } else { - fl |= STBSP__METRIC_SUFFIX; - } - ++f; - continue; - // if we don't want space between metric suffix and number - case '_': - fl |= STBSP__METRIC_NOSPACE; - ++f; - continue; - // if we have leading zero - case '0': - fl |= STBSP__LEADINGZERO; - ++f; - goto flags_done; - default: goto flags_done; - } - } - flags_done: - - // get the field width - if (f[0] == '*') { - fw = va_arg(va, stbsp__uint32); - ++f; - } else { - while ((f[0] >= '0') && (f[0] <= '9')) { - fw = fw * 10 + f[0] - '0'; - f++; - } - } - // get the precision - if (f[0] == '.') { - ++f; - if (f[0] == '*') { - pr = va_arg(va, stbsp__uint32); - ++f; - } else { - pr = 0; - while ((f[0] >= '0') && (f[0] <= '9')) { - pr = pr * 10 + f[0] - '0'; - f++; - } - } - } - - // handle integer size overrides - switch (f[0]) { - // are we halfwidth? - case 'h': - fl |= STBSP__HALFWIDTH; - ++f; - if (f[0] == 'h') - ++f; // QUARTERWIDTH - break; - // are we 64-bit (unix style) - case 'l': - fl |= ((sizeof(long) == 8) ? STBSP__INTMAX : 0); - ++f; - if (f[0] == 'l') { - fl |= STBSP__INTMAX; - ++f; - } - break; - // are we 64-bit on intmax? (c99) - case 'j': - fl |= (sizeof(size_t) == 8) ? STBSP__INTMAX : 0; - ++f; - break; - // are we 64-bit on size_t or ptrdiff_t? (c99) - case 'z': - fl |= (sizeof(ptrdiff_t) == 8) ? STBSP__INTMAX : 0; - ++f; - break; - case 't': - fl |= (sizeof(ptrdiff_t) == 8) ? STBSP__INTMAX : 0; - ++f; - break; - // are we 64-bit (msft style) - case 'I': - if ((f[1] == '6') && (f[2] == '4')) { - fl |= STBSP__INTMAX; - f += 3; - } else if ((f[1] == '3') && (f[2] == '2')) { - f += 3; - } else { - fl |= ((sizeof(void *) == 8) ? STBSP__INTMAX : 0); - ++f; - } - break; - default: break; - } - - // handle each replacement - switch (f[0]) { - #define STBSP__NUMSZ 512 // big enough for e308 (with commas) or e-307 - char num[STBSP__NUMSZ]; - char lead[8]; - char tail[8]; - char *s; - char const *h; - stbsp__uint32 l, n, cs; - stbsp__uint64 n64; -#ifndef STB_SPRINTF_NOFLOAT - double fv; -#endif - stbsp__int32 dp; - char const *sn; - - case 's': - // get the string - s = va_arg(va, char *); - if (s == 0) - s = (char *)"null"; - // get the length, limited to desired precision - // always limit to ~0u chars since our counts are 32b - l = stbsp__strlen_limited(s, (pr >= 0) ? pr : ~0u); - lead[0] = 0; - tail[0] = 0; - pr = 0; - dp = 0; - cs = 0; - // copy the string in - goto scopy; - - case 'S': - { - DN_Str8 str8 = va_arg(va, DN_Str8); - s = (char *)str8.data; - l = (uint32_t)str8.size; - lead[0] = 0; - tail[0] = 0; - pr = 0; - dp = 0; - cs = 0; - }goto scopy; - - case 'c': // char - // get the character - s = num + STBSP__NUMSZ - 1; - *s = (char)va_arg(va, int); - l = 1; - lead[0] = 0; - tail[0] = 0; - pr = 0; - dp = 0; - cs = 0; - goto scopy; - - case 'n': // weird write-bytes specifier - { - int *d = va_arg(va, int *); - *d = tlen + (int)(bf - buf); - } break; - -#ifdef STB_SPRINTF_NOFLOAT - case 'A': // float - case 'a': // hex float - case 'G': // float - case 'g': // float - case 'E': // float - case 'e': // float - case 'f': // float - va_arg(va, double); // eat it - s = (char *)"No float"; - l = 8; - lead[0] = 0; - tail[0] = 0; - pr = 0; - cs = 0; - STBSP__NOTUSED(dp); - goto scopy; -#else - case 'A': // hex float - case 'a': // hex float - h = (f[0] == 'A') ? hexu : hex; - fv = va_arg(va, double); - if (pr == -1) - pr = 6; // default is 6 - // read the double into a string - if (stbsp__real_to_parts((stbsp__int64 *)&n64, &dp, fv)) - fl |= STBSP__NEGATIVE; - - s = num + 64; - - stbsp__lead_sign(fl, lead); - - if (dp == -1023) - dp = (n64) ? -1022 : 0; - else - n64 |= (((stbsp__uint64)1) << 52); - n64 <<= (64 - 56); - if (pr < 15) - n64 += ((((stbsp__uint64)8) << 56) >> (pr * 4)); -// add leading chars - -#ifdef STB_SPRINTF_MSVC_MODE - *s++ = '0'; - *s++ = 'x'; -#else - lead[1 + lead[0]] = '0'; - lead[2 + lead[0]] = 'x'; - lead[0] += 2; -#endif - *s++ = h[(n64 >> 60) & 15]; - n64 <<= 4; - if (pr) - *s++ = stbsp__period; - sn = s; - - // print the bits - n = pr; - if (n > 13) - n = 13; - if (pr > (stbsp__int32)n) - tz = pr - n; - pr = 0; - while (n--) { - *s++ = h[(n64 >> 60) & 15]; - n64 <<= 4; - } - - // print the expo - tail[1] = h[17]; - if (dp < 0) { - tail[2] = '-'; - dp = -dp; - } else - tail[2] = '+'; - n = (dp >= 1000) ? 6 : ((dp >= 100) ? 5 : ((dp >= 10) ? 4 : 3)); - tail[0] = (char)n; - for (;;) { - tail[n] = '0' + dp % 10; - if (n <= 3) - break; - --n; - dp /= 10; - } - - dp = (int)(s - sn); - l = (int)(s - (num + 64)); - s = num + 64; - cs = 1 + (3 << 24); - goto scopy; - - case 'G': // float - case 'g': // float - h = (f[0] == 'G') ? hexu : hex; - fv = va_arg(va, double); - if (pr == -1) - pr = 6; - else if (pr == 0) - pr = 1; // default is 6 - // read the double into a string - if (stbsp__real_to_str(&sn, &l, num, &dp, fv, (pr - 1) | 0x80000000)) - fl |= STBSP__NEGATIVE; - - // clamp the precision and delete extra zeros after clamp - n = pr; - if (l > (stbsp__uint32)pr) - l = pr; - while ((l > 1) && (pr) && (sn[l - 1] == '0')) { - --pr; - --l; - } - - // should we use %e - if ((dp <= -4) || (dp > (stbsp__int32)n)) { - if (pr > (stbsp__int32)l) - pr = l - 1; - else if (pr) - --pr; // when using %e, there is one digit before the decimal - goto doexpfromg; - } - // this is the insane action to get the pr to match %g semantics for %f - if (dp > 0) { - pr = (dp < (stbsp__int32)l) ? l - dp : 0; - } else { - pr = -dp + ((pr > (stbsp__int32)l) ? (stbsp__int32) l : pr); - } - goto dofloatfromg; - - case 'E': // float - case 'e': // float - h = (f[0] == 'E') ? hexu : hex; - fv = va_arg(va, double); - if (pr == -1) - pr = 6; // default is 6 - // read the double into a string - if (stbsp__real_to_str(&sn, &l, num, &dp, fv, pr | 0x80000000)) - fl |= STBSP__NEGATIVE; - doexpfromg: - tail[0] = 0; - stbsp__lead_sign(fl, lead); - if (dp == STBSP__SPECIAL) { - s = (char *)sn; - cs = 0; - pr = 0; - goto scopy; - } - s = num + 64; - // handle leading chars - *s++ = sn[0]; - - if (pr) - *s++ = stbsp__period; - - // handle after decimal - if ((l - 1) > (stbsp__uint32)pr) - l = pr + 1; - for (n = 1; n < l; n++) - *s++ = sn[n]; - // trailing zeros - tz = pr - (l - 1); - pr = 0; - // dump expo - tail[1] = h[0xe]; - dp -= 1; - if (dp < 0) { - tail[2] = '-'; - dp = -dp; - } else - tail[2] = '+'; -#ifdef STB_SPRINTF_MSVC_MODE - n = 5; -#else - n = (dp >= 100) ? 5 : 4; -#endif - tail[0] = (char)n; - for (;;) { - tail[n] = '0' + dp % 10; - if (n <= 3) - break; - --n; - dp /= 10; - } - cs = 1 + (3 << 24); // how many tens - goto flt_lead; - - case 'f': // float - fv = va_arg(va, double); - doafloat: - // do kilos - if (fl & STBSP__METRIC_SUFFIX) { - double divisor; - divisor = 1000.0f; - if (fl & STBSP__METRIC_1024) - divisor = 1024.0; - while (fl < 0x4000000) { - if ((fv < divisor) && (fv > -divisor)) - break; - fv /= divisor; - fl += 0x1000000; - } - } - if (pr == -1) - pr = 6; // default is 6 - // read the double into a string - if (stbsp__real_to_str(&sn, &l, num, &dp, fv, pr)) - fl |= STBSP__NEGATIVE; - dofloatfromg: - tail[0] = 0; - stbsp__lead_sign(fl, lead); - if (dp == STBSP__SPECIAL) { - s = (char *)sn; - cs = 0; - pr = 0; - goto scopy; - } - s = num + 64; - - // handle the three decimal varieties - if (dp <= 0) { - stbsp__int32 i; - // handle 0.000*000xxxx - *s++ = '0'; - if (pr) - *s++ = stbsp__period; - n = -dp; - if ((stbsp__int32)n > pr) - n = pr; - i = n; - while (i) { - if ((((stbsp__uintptr)s) & 3) == 0) - break; - *s++ = '0'; - --i; - } - while (i >= 4) { - *(stbsp__uint32 *)s = 0x30303030; - s += 4; - i -= 4; - } - while (i) { - *s++ = '0'; - --i; - } - if ((stbsp__int32)(l + n) > pr) - l = pr - n; - i = l; - while (i) { - *s++ = *sn++; - --i; - } - tz = pr - (n + l); - cs = 1 + (3 << 24); // how many tens did we write (for commas below) - } else { - cs = (fl & STBSP__TRIPLET_COMMA) ? ((600 - (stbsp__uint32)dp) % 3) : 0; - if ((stbsp__uint32)dp >= l) { - // handle xxxx000*000.0 - n = 0; - for (;;) { - if ((fl & STBSP__TRIPLET_COMMA) && (++cs == 4)) { - cs = 0; - *s++ = stbsp__comma; - } else { - *s++ = sn[n]; - ++n; - if (n >= l) - break; - } - } - if (n < (stbsp__uint32)dp) { - n = dp - n; - if ((fl & STBSP__TRIPLET_COMMA) == 0) { - while (n) { - if ((((stbsp__uintptr)s) & 3) == 0) - break; - *s++ = '0'; - --n; - } - while (n >= 4) { - *(stbsp__uint32 *)s = 0x30303030; - s += 4; - n -= 4; - } - } - while (n) { - if ((fl & STBSP__TRIPLET_COMMA) && (++cs == 4)) { - cs = 0; - *s++ = stbsp__comma; - } else { - *s++ = '0'; - --n; - } - } - } - cs = (int)(s - (num + 64)) + (3 << 24); // cs is how many tens - if (pr) { - *s++ = stbsp__period; - tz = pr; - } - } else { - // handle xxxxx.xxxx000*000 - n = 0; - for (;;) { - if ((fl & STBSP__TRIPLET_COMMA) && (++cs == 4)) { - cs = 0; - *s++ = stbsp__comma; - } else { - *s++ = sn[n]; - ++n; - if (n >= (stbsp__uint32)dp) - break; - } - } - cs = (int)(s - (num + 64)) + (3 << 24); // cs is how many tens - if (pr) - *s++ = stbsp__period; - if ((l - dp) > (stbsp__uint32)pr) - l = pr + dp; - while (n < l) { - *s++ = sn[n]; - ++n; - } - tz = pr - (l - dp); - } - } - pr = 0; - - // handle k,m,g,t - if (fl & STBSP__METRIC_SUFFIX) { - char idx; - idx = 1; - if (fl & STBSP__METRIC_NOSPACE) - idx = 0; - tail[0] = idx; - tail[1] = ' '; - { - if (fl >> 24) { // SI kilo is 'k', JEDEC and SI kibits are 'K'. - if (fl & STBSP__METRIC_1024) - tail[idx + 1] = "_KMGT"[fl >> 24]; - else - tail[idx + 1] = "_kMGT"[fl >> 24]; - idx++; - // If printing kibits and not in jedec, add the 'i'. - if (fl & STBSP__METRIC_1024 && !(fl & STBSP__METRIC_JEDEC)) { - tail[idx + 1] = 'i'; - idx++; - } - tail[0] = idx; - } - } - }; - - flt_lead: - // get the length that we copied - l = (stbsp__uint32)(s - (num + 64)); - s = num + 64; - goto scopy; -#endif - - case 'B': // upper binary - case 'b': // lower binary - h = (f[0] == 'B') ? hexu : hex; - lead[0] = 0; - if (fl & STBSP__LEADING_0X) { - lead[0] = 2; - lead[1] = '0'; - lead[2] = h[0xb]; - } - l = (8 << 4) | (1 << 8); - goto radixnum; - - case 'o': // octal - h = hexu; - lead[0] = 0; - if (fl & STBSP__LEADING_0X) { - lead[0] = 1; - lead[1] = '0'; - } - l = (3 << 4) | (3 << 8); - goto radixnum; - - case 'p': // pointer - fl |= (sizeof(void *) == 8) ? STBSP__INTMAX : 0; - pr = sizeof(void *) * 2; - fl &= ~STBSP__LEADINGZERO; // 'p' only prints the pointer with zeros - // fall through - to X - - case 'X': // upper hex - case 'x': // lower hex - h = (f[0] == 'X') ? hexu : hex; - l = (4 << 4) | (4 << 8); - lead[0] = 0; - if (fl & STBSP__LEADING_0X) { - lead[0] = 2; - lead[1] = '0'; - lead[2] = h[16]; - } - radixnum: - // get the number - if (fl & STBSP__INTMAX) - n64 = va_arg(va, stbsp__uint64); - else - n64 = va_arg(va, stbsp__uint32); - - s = num + STBSP__NUMSZ; - dp = 0; - // clear tail, and clear leading if value is zero - tail[0] = 0; - if (n64 == 0) { - lead[0] = 0; - if (pr == 0) { - l = 0; - cs = 0; - goto scopy; - } - } - // convert to string - for (;;) { - *--s = h[n64 & ((1 << (l >> 8)) - 1)]; - n64 >>= (l >> 8); - if (!((n64) || ((stbsp__int32)((num + STBSP__NUMSZ) - s) < pr))) - break; - if (fl & STBSP__TRIPLET_COMMA) { - ++l; - if ((l & 15) == ((l >> 4) & 15)) { - l &= ~15; - *--s = stbsp__comma; - } - } - }; - // get the tens and the comma pos - cs = (stbsp__uint32)((num + STBSP__NUMSZ) - s) + ((((l >> 4) & 15)) << 24); - // get the length that we copied - l = (stbsp__uint32)((num + STBSP__NUMSZ) - s); - // copy it - goto scopy; - - case 'u': // unsigned - case 'i': - case 'd': // integer - // get the integer and abs it - if (fl & STBSP__INTMAX) { - stbsp__int64 i64 = va_arg(va, stbsp__int64); - n64 = (stbsp__uint64)i64; - if ((f[0] != 'u') && (i64 < 0)) { - n64 = (stbsp__uint64)-i64; - fl |= STBSP__NEGATIVE; - } - } else { - stbsp__int32 i = va_arg(va, stbsp__int32); - n64 = (stbsp__uint32)i; - if ((f[0] != 'u') && (i < 0)) { - n64 = (stbsp__uint32)-i; - fl |= STBSP__NEGATIVE; - } - } - -#ifndef STB_SPRINTF_NOFLOAT - if (fl & STBSP__METRIC_SUFFIX) { - if (n64 < 1024) - pr = 0; - else if (pr == -1) - pr = 1; - fv = (double)(stbsp__int64)n64; - goto doafloat; - } -#endif - - // convert to string - s = num + STBSP__NUMSZ; - l = 0; - - for (;;) { - // do in 32-bit chunks (avoid lots of 64-bit divides even with constant denominators) - char *o = s - 8; - if (n64 >= 100000000) { - n = (stbsp__uint32)(n64 % 100000000); - n64 /= 100000000; - } else { - n = (stbsp__uint32)n64; - n64 = 0; - } - if ((fl & STBSP__TRIPLET_COMMA) == 0) { - do { - s -= 2; - *(stbsp__uint16 *)s = *(stbsp__uint16 *)&stbsp__digitpair.pair[(n % 100) * 2]; - n /= 100; - } while (n); - } - while (n) { - if ((fl & STBSP__TRIPLET_COMMA) && (l++ == 3)) { - l = 0; - *--s = stbsp__comma; - --o; - } else { - *--s = (char)(n % 10) + '0'; - n /= 10; - } - } - if (n64 == 0) { - if ((s[0] == '0') && (s != (num + STBSP__NUMSZ))) - ++s; - break; - } - while (s != o) - if ((fl & STBSP__TRIPLET_COMMA) && (l++ == 3)) { - l = 0; - *--s = stbsp__comma; - --o; - } else { - *--s = '0'; - } - } - - tail[0] = 0; - stbsp__lead_sign(fl, lead); - - // get the length that we copied - l = (stbsp__uint32)((num + STBSP__NUMSZ) - s); - if (l == 0) { - *--s = '0'; - l = 1; - } - cs = l + (3 << 24); - if (pr < 0) - pr = 0; - - scopy: - // get fw=leading/trailing space, pr=leading zeros - if (pr < (stbsp__int32)l) - pr = l; - n = pr + lead[0] + tail[0] + tz; - if (fw < (stbsp__int32)n) - fw = n; - fw -= n; - pr -= l; - - // handle right justify and leading zeros - if ((fl & STBSP__LEFTJUST) == 0) { - if (fl & STBSP__LEADINGZERO) // if leading zeros, everything is in pr - { - pr = (fw > pr) ? fw : pr; - fw = 0; - } else { - fl &= ~STBSP__TRIPLET_COMMA; // if no leading zeros, then no commas - } - } - - // copy the spaces and/or zeros - if (fw + pr) { - stbsp__int32 i; - stbsp__uint32 c; - - // copy leading spaces (or when doing %8.4d stuff) - if ((fl & STBSP__LEFTJUST) == 0) - while (fw > 0) { - stbsp__cb_buf_clamp(i, fw); - fw -= i; - while (i) { - if ((((stbsp__uintptr)bf) & 3) == 0) - break; - *bf++ = ' '; - --i; - } - while (i >= 4) { - *(stbsp__uint32 *)bf = 0x20202020; - bf += 4; - i -= 4; - } - while (i) { - *bf++ = ' '; - --i; - } - stbsp__chk_cb_buf(1); - } - - // copy leader - sn = lead + 1; - while (lead[0]) { - stbsp__cb_buf_clamp(i, lead[0]); - lead[0] -= (char)i; - while (i) { - *bf++ = *sn++; - --i; - } - stbsp__chk_cb_buf(1); - } - - // copy leading zeros - c = cs >> 24; - cs &= 0xffffff; - cs = (fl & STBSP__TRIPLET_COMMA) ? ((stbsp__uint32)(c - ((pr + cs) % (c + 1)))) : 0; - while (pr > 0) { - stbsp__cb_buf_clamp(i, pr); - pr -= i; - if ((fl & STBSP__TRIPLET_COMMA) == 0) { - while (i) { - if ((((stbsp__uintptr)bf) & 3) == 0) - break; - *bf++ = '0'; - --i; - } - while (i >= 4) { - *(stbsp__uint32 *)bf = 0x30303030; - bf += 4; - i -= 4; - } - } - while (i) { - if ((fl & STBSP__TRIPLET_COMMA) && (cs++ == c)) { - cs = 0; - *bf++ = stbsp__comma; - } else - *bf++ = '0'; - --i; - } - stbsp__chk_cb_buf(1); - } - } - - // copy leader if there is still one - sn = lead + 1; - while (lead[0]) { - stbsp__int32 i; - stbsp__cb_buf_clamp(i, lead[0]); - lead[0] -= (char)i; - while (i) { - *bf++ = *sn++; - --i; - } - stbsp__chk_cb_buf(1); - } - - // copy the string - n = l; - while (n) { - stbsp__int32 i; - stbsp__cb_buf_clamp(i, n); - n -= i; - STBSP__UNALIGNED(while (i >= 4) { - *(stbsp__uint32 volatile *)bf = *(stbsp__uint32 volatile *)s; - bf += 4; - s += 4; - i -= 4; - }) - while (i) { - *bf++ = *s++; - --i; - } - stbsp__chk_cb_buf(1); - } - - // copy trailing zeros - while (tz) { - stbsp__int32 i; - stbsp__cb_buf_clamp(i, tz); - tz -= i; - while (i) { - if ((((stbsp__uintptr)bf) & 3) == 0) - break; - *bf++ = '0'; - --i; - } - while (i >= 4) { - *(stbsp__uint32 *)bf = 0x30303030; - bf += 4; - i -= 4; - } - while (i) { - *bf++ = '0'; - --i; - } - stbsp__chk_cb_buf(1); - } - - // copy tail if there is one - sn = tail + 1; - while (tail[0]) { - stbsp__int32 i; - stbsp__cb_buf_clamp(i, tail[0]); - tail[0] -= (char)i; - while (i) { - *bf++ = *sn++; - --i; - } - stbsp__chk_cb_buf(1); - } - - // handle the left justify - if (fl & STBSP__LEFTJUST) - if (fw > 0) { - while (fw) { - stbsp__int32 i; - stbsp__cb_buf_clamp(i, fw); - fw -= i; - while (i) { - if ((((stbsp__uintptr)bf) & 3) == 0) - break; - *bf++ = ' '; - --i; - } - while (i >= 4) { - *(stbsp__uint32 *)bf = 0x20202020; - bf += 4; - i -= 4; - } - while (i--) - *bf++ = ' '; - stbsp__chk_cb_buf(1); - } - } - break; - - default: // unknown, just copy code - s = num + STBSP__NUMSZ - 1; - *s = f[0]; - l = 1; - fw = fl = 0; - lead[0] = 0; - tail[0] = 0; - pr = 0; - dp = 0; - cs = 0; - goto scopy; - } - ++f; - } -endfmt: - - if (!callback) - *bf = 0; - else - stbsp__flush_cb(); - -done: - return tlen + (int)(bf - buf); -} - -// cleanup -#undef STBSP__LEFTJUST -#undef STBSP__LEADINGPLUS -#undef STBSP__LEADINGSPACE -#undef STBSP__LEADING_0X -#undef STBSP__LEADINGZERO -#undef STBSP__INTMAX -#undef STBSP__TRIPLET_COMMA -#undef STBSP__NEGATIVE -#undef STBSP__METRIC_SUFFIX -#undef STBSP__NUMSZ -#undef stbsp__chk_cb_bufL -#undef stbsp__chk_cb_buf -#undef stbsp__flush_cb -#undef stbsp__cb_buf_clamp - -// ============================================================================ -// wrapper functions - -STBSP__PUBLICDEF int STB_SPRINTF_DECORATE(sprintf)(char *buf, char const *fmt, ...) -{ - int result; - va_list va; - va_start(va, fmt); - result = STB_SPRINTF_DECORATE(vsprintfcb)(0, 0, buf, fmt, va); - va_end(va); - return result; -} - -typedef struct stbsp__context { - char *buf; - int count; - int length; - char tmp[STB_SPRINTF_MIN]; -} stbsp__context; - -static char *stbsp__clamp_callback(const char *buf, void *user, int len) -{ - stbsp__context *c = (stbsp__context *)user; - c->length += len; - - if (len > c->count) - len = c->count; - - if (len) { - if (buf != c->buf) { - const char *s, *se; - char *d; - d = c->buf; - s = buf; - se = buf + len; - do { - *d++ = *s++; - } while (s < se); - } - c->buf += len; - c->count -= len; - } - - if (c->count <= 0) - return c->tmp; - return (c->count >= STB_SPRINTF_MIN) ? c->buf : c->tmp; // go direct into buffer if you can -} - -static char * stbsp__count_clamp_callback( const char * buf, void * user, int len ) -{ - stbsp__context * c = (stbsp__context*)user; - (void) sizeof(buf); - - c->length += len; - return c->tmp; // go direct into buffer if you can -} - -STBSP__PUBLICDEF int STB_SPRINTF_DECORATE( vsnprintf )( char * buf, int count, char const * fmt, va_list va ) -{ - stbsp__context c; - - if ( (count == 0) && !buf ) - { - c.length = 0; - - STB_SPRINTF_DECORATE( vsprintfcb )( stbsp__count_clamp_callback, &c, c.tmp, fmt, va ); - } - else - { - int l; - - c.buf = buf; - c.count = count; - c.length = 0; - - STB_SPRINTF_DECORATE( vsprintfcb )( stbsp__clamp_callback, &c, stbsp__clamp_callback(0,&c,0), fmt, va ); - - // zero-terminate - l = (int)( c.buf - buf ); - if ( l >= count ) // should never be greater, only equal (or less) than count - l = count - 1; - buf[l] = 0; - } - - return c.length; -} - -STBSP__PUBLICDEF int STB_SPRINTF_DECORATE(snprintf)(char *buf, int count, char const *fmt, ...) -{ - int result; - va_list va; - va_start(va, fmt); - - result = STB_SPRINTF_DECORATE(vsnprintf)(buf, count, fmt, va); - va_end(va); - - return result; -} - -STBSP__PUBLICDEF int STB_SPRINTF_DECORATE(vsprintf)(char *buf, char const *fmt, va_list va) -{ - return STB_SPRINTF_DECORATE(vsprintfcb)(0, 0, buf, fmt, va); -} - -// ======================================================================= -// low level float utility functions - -#ifndef STB_SPRINTF_NOFLOAT - -// copies d to bits w/ strict aliasing (this compiles to nothing on /Ox) -#define STBSP__COPYFP(dest, src) \ - { \ - int cn; \ - for (cn = 0; cn < 8; cn++) \ - ((char *)&dest)[cn] = ((char *)&src)[cn]; \ - } - -// get float info -static stbsp__int32 stbsp__real_to_parts(stbsp__int64 *bits, stbsp__int32 *expo, double value) -{ - double d; - stbsp__int64 b = 0; - - // load value and round at the frac_digits - d = value; - - STBSP__COPYFP(b, d); - - *bits = b & ((((stbsp__uint64)1) << 52) - 1); - *expo = (stbsp__int32)(((b >> 52) & 2047) - 1023); - - return (stbsp__int32)((stbsp__uint64) b >> 63); -} - -static double const stbsp__bot[23] = { - 1e+000, 1e+001, 1e+002, 1e+003, 1e+004, 1e+005, 1e+006, 1e+007, 1e+008, 1e+009, 1e+010, 1e+011, - 1e+012, 1e+013, 1e+014, 1e+015, 1e+016, 1e+017, 1e+018, 1e+019, 1e+020, 1e+021, 1e+022 -}; -static double const stbsp__negbot[22] = { - 1e-001, 1e-002, 1e-003, 1e-004, 1e-005, 1e-006, 1e-007, 1e-008, 1e-009, 1e-010, 1e-011, - 1e-012, 1e-013, 1e-014, 1e-015, 1e-016, 1e-017, 1e-018, 1e-019, 1e-020, 1e-021, 1e-022 -}; -static double const stbsp__negboterr[22] = { - -5.551115123125783e-018, -2.0816681711721684e-019, -2.0816681711721686e-020, -4.7921736023859299e-021, -8.1803053914031305e-022, 4.5251888174113741e-023, - 4.5251888174113739e-024, -2.0922560830128471e-025, -6.2281591457779853e-026, -3.6432197315497743e-027, 6.0503030718060191e-028, 2.0113352370744385e-029, - -3.0373745563400371e-030, 1.1806906454401013e-032, -7.7705399876661076e-032, 2.0902213275965398e-033, -7.1542424054621921e-034, -7.1542424054621926e-035, - 2.4754073164739869e-036, 5.4846728545790429e-037, 9.2462547772103625e-038, -4.8596774326570872e-039 -}; -static double const stbsp__top[13] = { - 1e+023, 1e+046, 1e+069, 1e+092, 1e+115, 1e+138, 1e+161, 1e+184, 1e+207, 1e+230, 1e+253, 1e+276, 1e+299 -}; -static double const stbsp__negtop[13] = { - 1e-023, 1e-046, 1e-069, 1e-092, 1e-115, 1e-138, 1e-161, 1e-184, 1e-207, 1e-230, 1e-253, 1e-276, 1e-299 -}; -static double const stbsp__toperr[13] = { - 8388608, - 6.8601809640529717e+028, - -7.253143638152921e+052, - -4.3377296974619174e+075, - -1.5559416129466825e+098, - -3.2841562489204913e+121, - -3.7745893248228135e+144, - -1.7356668416969134e+167, - -3.8893577551088374e+190, - -9.9566444326005119e+213, - 6.3641293062232429e+236, - -5.2069140800249813e+259, - -5.2504760255204387e+282 -}; -static double const stbsp__negtoperr[13] = { - 3.9565301985100693e-040, -2.299904345391321e-063, 3.6506201437945798e-086, 1.1875228833981544e-109, - -5.0644902316928607e-132, -6.7156837247865426e-155, -2.812077463003139e-178, -5.7778912386589953e-201, - 7.4997100559334532e-224, -4.6439668915134491e-247, -6.3691100762962136e-270, -9.436808465446358e-293, - 8.0970921678014997e-317 -}; - -#if defined(_MSC_VER) && (_MSC_VER <= 1200) -static stbsp__uint64 const stbsp__powten[20] = { - 1, - 10, - 100, - 1000, - 10000, - 100000, - 1000000, - 10000000, - 100000000, - 1000000000, - 10000000000, - 100000000000, - 1000000000000, - 10000000000000, - 100000000000000, - 1000000000000000, - 10000000000000000, - 100000000000000000, - 1000000000000000000, - 10000000000000000000U -}; -#define stbsp__tento19th ((stbsp__uint64)1000000000000000000) -#else -static stbsp__uint64 const stbsp__powten[20] = { - 1, - 10, - 100, - 1000, - 10000, - 100000, - 1000000, - 10000000, - 100000000, - 1000000000, - 10000000000ULL, - 100000000000ULL, - 1000000000000ULL, - 10000000000000ULL, - 100000000000000ULL, - 1000000000000000ULL, - 10000000000000000ULL, - 100000000000000000ULL, - 1000000000000000000ULL, - 10000000000000000000ULL -}; -#define stbsp__tento19th (1000000000000000000ULL) -#endif - -#define stbsp__ddmulthi(oh, ol, xh, yh) \ - { \ - double ahi = 0, alo, bhi = 0, blo; \ - stbsp__int64 bt; \ - oh = xh * yh; \ - STBSP__COPYFP(bt, xh); \ - bt &= ((~(stbsp__uint64)0) << 27); \ - STBSP__COPYFP(ahi, bt); \ - alo = xh - ahi; \ - STBSP__COPYFP(bt, yh); \ - bt &= ((~(stbsp__uint64)0) << 27); \ - STBSP__COPYFP(bhi, bt); \ - blo = yh - bhi; \ - ol = ((ahi * bhi - oh) + ahi * blo + alo * bhi) + alo * blo; \ - } - -#define stbsp__ddtoS64(ob, xh, xl) \ - { \ - double ahi = 0, alo, vh, t; \ - ob = (stbsp__int64)xh; \ - vh = (double)ob; \ - ahi = (xh - vh); \ - t = (ahi - xh); \ - alo = (xh - (ahi - t)) - (vh + t); \ - ob += (stbsp__int64)(ahi + alo + xl); \ - } - -#define stbsp__ddrenorm(oh, ol) \ - { \ - double s; \ - s = oh + ol; \ - ol = ol - (s - oh); \ - oh = s; \ - } - -#define stbsp__ddmultlo(oh, ol, xh, xl, yh, yl) ol = ol + (xh * yl + xl * yh); - -#define stbsp__ddmultlos(oh, ol, xh, yl) ol = ol + (xh * yl); - -static void stbsp__raise_to_power10(double *ohi, double *olo, double d, stbsp__int32 power) // power can be -323 to +350 -{ - double ph, pl; - if ((power >= 0) && (power <= 22)) { - stbsp__ddmulthi(ph, pl, d, stbsp__bot[power]); - } else { - stbsp__int32 e, et, eb; - double p2h, p2l; - - e = power; - if (power < 0) - e = -e; - et = (e * 0x2c9) >> 14; /* %23 */ - if (et > 13) - et = 13; - eb = e - (et * 23); - - ph = d; - pl = 0.0; - if (power < 0) { - if (eb) { - --eb; - stbsp__ddmulthi(ph, pl, d, stbsp__negbot[eb]); - stbsp__ddmultlos(ph, pl, d, stbsp__negboterr[eb]); - } - if (et) { - stbsp__ddrenorm(ph, pl); - --et; - stbsp__ddmulthi(p2h, p2l, ph, stbsp__negtop[et]); - stbsp__ddmultlo(p2h, p2l, ph, pl, stbsp__negtop[et], stbsp__negtoperr[et]); - ph = p2h; - pl = p2l; - } - } else { - if (eb) { - e = eb; - if (eb > 22) - eb = 22; - e -= eb; - stbsp__ddmulthi(ph, pl, d, stbsp__bot[eb]); - if (e) { - stbsp__ddrenorm(ph, pl); - stbsp__ddmulthi(p2h, p2l, ph, stbsp__bot[e]); - stbsp__ddmultlos(p2h, p2l, stbsp__bot[e], pl); - ph = p2h; - pl = p2l; - } - } - if (et) { - stbsp__ddrenorm(ph, pl); - --et; - stbsp__ddmulthi(p2h, p2l, ph, stbsp__top[et]); - stbsp__ddmultlo(p2h, p2l, ph, pl, stbsp__top[et], stbsp__toperr[et]); - ph = p2h; - pl = p2l; - } - } - } - stbsp__ddrenorm(ph, pl); - *ohi = ph; - *olo = pl; -} - -// given a float value, returns the significant bits in bits, and the position of the -// decimal point in decimal_pos. +/-INF and NAN are specified by special values -// returned in the decimal_pos parameter. -// frac_digits is absolute normally, but if you want from first significant digits (got %g and %e), or in 0x80000000 -static stbsp__int32 stbsp__real_to_str(char const **start, stbsp__uint32 *len, char *out, stbsp__int32 *decimal_pos, double value, stbsp__uint32 frac_digits) -{ - double d; - stbsp__int64 bits = 0; - stbsp__int32 expo, e, ng, tens; - - d = value; - STBSP__COPYFP(bits, d); - expo = (stbsp__int32)((bits >> 52) & 2047); - ng = (stbsp__int32)((stbsp__uint64) bits >> 63); - if (ng) - d = -d; - - if (expo == 2047) // is nan or inf? - { - *start = (bits & ((((stbsp__uint64)1) << 52) - 1)) ? "NaN" : "Inf"; - *decimal_pos = STBSP__SPECIAL; - *len = 3; - return ng; - } - - if (expo == 0) // is zero or denormal - { - if (((stbsp__uint64) bits << 1) == 0) // do zero - { - *decimal_pos = 1; - *start = out; - out[0] = '0'; - *len = 1; - return ng; - } - // find the right expo for denormals - { - stbsp__int64 v = ((stbsp__uint64)1) << 51; - while ((bits & v) == 0) { - --expo; - v >>= 1; - } - } - } - - // find the decimal exponent as well as the decimal bits of the value - { - double ph, pl; - - // log10 estimate - very specifically tweaked to hit or undershoot by no more than 1 of log10 of all expos 1..2046 - tens = expo - 1023; - tens = (tens < 0) ? ((tens * 617) / 2048) : (((tens * 1233) / 4096) + 1); - - // move the significant bits into position and stick them into an int - stbsp__raise_to_power10(&ph, &pl, d, 18 - tens); - - // get full as much precision from double-double as possible - stbsp__ddtoS64(bits, ph, pl); - - // check if we undershot - if (((stbsp__uint64)bits) >= stbsp__tento19th) - ++tens; - } - - // now do the rounding in integer land - frac_digits = (frac_digits & 0x80000000) ? ((frac_digits & 0x7ffffff) + 1) : (tens + frac_digits); - if ((frac_digits < 24)) { - stbsp__uint32 dg = 1; - if ((stbsp__uint64)bits >= stbsp__powten[9]) - dg = 10; - while ((stbsp__uint64)bits >= stbsp__powten[dg]) { - ++dg; - if (dg == 20) - goto noround; - } - if (frac_digits < dg) { - stbsp__uint64 r; - // add 0.5 at the right position and round - e = dg - frac_digits; - if ((stbsp__uint32)e >= 24) - goto noround; - r = stbsp__powten[e]; - bits = bits + (r / 2); - if ((stbsp__uint64)bits >= stbsp__powten[dg]) - ++tens; - bits /= r; - } - noround:; - } - - // kill long trailing runs of zeros - if (bits) { - stbsp__uint32 n; - for (;;) { - if (bits <= 0xffffffff) - break; - if (bits % 1000) - goto donez; - bits /= 1000; - } - n = (stbsp__uint32)bits; - while ((n % 1000) == 0) - n /= 1000; - bits = n; - donez:; - } - - // convert to string - out += 64; - e = 0; - for (;;) { - stbsp__uint32 n; - char *o = out - 8; - // do the conversion in chunks of U32s (avoid most 64-bit divides, worth it, constant denomiators be damned) - if (bits >= 100000000) { - n = (stbsp__uint32)(bits % 100000000); - bits /= 100000000; - } else { - n = (stbsp__uint32)bits; - bits = 0; - } - while (n) { - out -= 2; - *(stbsp__uint16 *)out = *(stbsp__uint16 *)&stbsp__digitpair.pair[(n % 100) * 2]; - n /= 100; - e += 2; - } - if (bits == 0) { - if ((e) && (out[0] == '0')) { - ++out; - --e; - } - break; - } - while (out != o) { - *--out = '0'; - ++e; - } - } - - *decimal_pos = tens; - *start = out; - *len = e; - return ng; -} - -#undef stbsp__ddmulthi -#undef stbsp__ddrenorm -#undef stbsp__ddmultlo -#undef stbsp__ddmultlos -#undef STBSP__SPECIAL -#undef STBSP__COPYFP - -#endif // STB_SPRINTF_NOFLOAT - -// clean up -#undef stbsp__uint16 -#undef stbsp__uint32 -#undef stbsp__int32 -#undef stbsp__uint64 -#undef stbsp__int64 -#undef STBSP__UNALIGNED - -#endif // STB_SPRINTF_IMPLEMENTATION - -/* ------------------------------------------------------------------------------- -This software is available under 2 licenses -- choose whichever you prefer. ------------------------------------------------------------------------------- -ALTERNATIVE A - MIT License -Copyright (c) 2017 Sean Barrett -Permission is hereby granted, free of charge, to any person obtaining a copy of -this software and associated documentation files (the "Software"), to deal in -the Software without restriction, including without limitation the rights to -use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies -of the Software, and to permit persons to whom the Software is furnished to do -so, subject to the following conditions: -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. ------------------------------------------------------------------------------- -ALTERNATIVE B - Public Domain (www.unlicense.org) -This is free and unencumbered software released into the public domain. -Anyone is free to copy, modify, publish, use, compile, sell, or distribute this -software, either in source code form or as a compiled binary, for any purpose, -commercial or non-commercial, and by any means. -In jurisdictions that recognize copyright laws, the author or authors of this -software dedicate any and all copyright interest in the software to the public -domain. We make this dedication for the benefit of the public at large and to -the detriment of our heirs and successors. We intend this dedication to be an -overt act of relinquishment in perpetuity of all present and future rights to -this software under copyright law. -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN -ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ------------------------------------------------------------------------------- -*/ -DN_GCC_WARNING_POP -DN_MSVC_WARNING_POP - -DN_API void DN_BeginFrame (); - -#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_MemEq (void const *lhs, DN_USize lhs_size, void const *rhs, DN_USize rhs_size); - -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_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 void DN_TicketMutex_Begin (DN_TicketMutex *mutex); -DN_API void DN_TicketMutex_End (DN_TicketMutex *mutex); -DN_API DN_UInt DN_TicketMutex_MakeTicket (DN_TicketMutex *mutex); -DN_API void DN_TicketMutex_BeginTicket (DN_TicketMutex const *mutex, DN_UInt ticket); -DN_API bool DN_TicketMutex_CanLock (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); -#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_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 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 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 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_UInt DN_SaturateCastI64ToUInt (DN_I64 val); -DN_API DN_ISize 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 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_Arena DN_ArenaFromBuffer (void *buffer, DN_USize size, DN_ArenaFlags flags); -DN_API DN_Arena DN_ArenaFromMemFuncs (DN_U64 reserve, DN_U64 commit, DN_ArenaFlags flags, DN_ArenaMemFuncs mem_funcs); -DN_API void DN_ArenaDeinit (DN_Arena *arena); -DN_API bool DN_ArenaCommit (DN_Arena *arena, DN_U64 size); -DN_API bool DN_ArenaCommitTo (DN_Arena *arena, DN_U64 pos); -DN_API bool DN_ArenaGrow (DN_Arena *arena, DN_U64 reserve, DN_U64 commit); -DN_API void * DN_ArenaAlloc (DN_Arena *arena, DN_U64 size, uint8_t align, DN_ZMem zmem); -DN_API void * DN_ArenaAllocContiguous (DN_Arena *arena, DN_U64 size, uint8_t align, DN_ZMem zmem); -DN_API void * DN_ArenaCopy (DN_Arena *arena, void const *data, DN_U64 size, uint8_t align); -DN_API void DN_ArenaPopTo (DN_Arena *arena, DN_U64 init_used); -DN_API void DN_ArenaPop (DN_Arena *arena, DN_U64 amount); -DN_API DN_U64 DN_ArenaPos (DN_Arena const *arena); -DN_API void DN_ArenaClear (DN_Arena *arena); -DN_API bool DN_ArenaOwnsPtr (DN_Arena const *arena, void *ptr); -DN_API DN_Str8x64 DN_ArenaInfoStr8x64 (DN_ArenaInfo info); -DN_API DN_ArenaStats DN_ArenaSumStatsArray (DN_ArenaStats const *array, DN_USize size); -DN_API DN_ArenaStats DN_ArenaSumStats (DN_ArenaStats lhs, DN_ArenaStats rhs); -DN_API DN_ArenaStats DN_ArenaSumArenaArrayToStats(DN_Arena const *array, DN_USize size); -DN_API DN_ArenaTempMem DN_ArenaTempMemBegin (DN_Arena *arena); -DN_API void DN_ArenaTempMemEnd (DN_ArenaTempMem mem); -#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_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)) - -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 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_U64FromStr8 (DN_Str8 string, char separator); -DN_API DN_U64FromResult DN_U64FromPtr (void const *data, DN_USize size, char separator); -DN_API DN_U64 DN_U64FromPtrUnsafe (void const *data, DN_USize size, char separator); -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_I64FromResult DN_I64FromStr8 (DN_Str8 string, char separator); -DN_API DN_I64FromResult DN_I64FromPtr (void const *data, DN_USize size, char separator); -DN_API DN_I64 DN_I64FromPtrUnsafe (void const *data, DN_USize size, char separator); - -DN_API DN_USize DN_FmtVSize (DN_FMT_ATTRIB char const *fmt, va_list args); -DN_API DN_USize DN_FmtSize (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_CStr8Size (char const *src); -DN_API DN_USize DN_CStr16Size (wchar_t const *src); - -#define DN_Str16Lit(string) DN_Str16{(wchar_t *)(string), sizeof(string)/sizeof(string[0]) - 1} -#define DN_Str8Lit(c_str) DN_Literal(DN_Str8){(char *)(c_str), sizeof(c_str) - 1} -#define DN_Str8PrintFmt(string) (int)((string).size), (string).data -#define DN_Str8FromPtr(data, size) DN_Literal(DN_Str8){(char *)(data), (DN_USize)(size)} -#define DN_Str8FromStruct(ptr) DN_Str8FromPtr((ptr)->data, (ptr)->size) -DN_API DN_Str8 DN_Str8FromCStr8 (char const *src); -DN_API DN_Str8 DN_Str8FromArena (DN_Arena *arena, DN_USize size, DN_ZMem z_mem); -DN_API DN_Str8 DN_Str8FromPool (DN_Pool *pool, DN_USize size); -DN_API DN_Str8 DN_Str8FromPtrArena (DN_Arena *arena, void const *data, DN_USize size); -DN_API DN_Str8 DN_Str8FromPtrPool (DN_Pool *pool, void const *data, DN_USize size); -DN_API DN_Str8 DN_Str8FromStr8Arena (DN_Arena *arena, DN_Str8 string); -DN_API DN_Str8 DN_Str8FromStr8Pool (DN_Pool *pool, DN_Str8 string); -DN_API DN_Str8 DN_Str8FromFmtArena (DN_Arena *arena, DN_FMT_ATTRIB char const *fmt, ...); -DN_API DN_Str8 DN_Str8FromFmtVArena (DN_Arena *arena, DN_FMT_ATTRIB char const *fmt, va_list args); -DN_API DN_Str8 DN_Str8FromFmtPool (DN_Pool *pool, DN_FMT_ATTRIB char const *fmt, ...); -DN_API DN_Str8 DN_Str8FromByteCountType (DN_ByteCountType type); -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_Str8x32 DN_Str8x32FromU64 (DN_U64 val, char separator); -DN_API bool DN_Str8IsAll (DN_Str8 string, DN_Str8IsAllType is_all); -DN_API char * DN_Str8End (DN_Str8 string); -DN_API DN_Str8 DN_Str8Slice (DN_Str8 string, DN_USize offset, DN_USize size); -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_Str8SplitIncludeEmptyStrings mode); -DN_API DN_Str8SplitResult DN_Str8SplitArena (DN_Arena *arena, DN_Str8 string, DN_Str8 delimiter, DN_Str8SplitIncludeEmptyStrings mode); -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, uint32_t 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_Str8EqCase_Sensitive); -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_Str8EqCase_Sensitive); -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_Str8EqCase_Sensitive); -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_Str8EqCase_Sensitive); -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_Str8EqCase_Sensitive); -DN_API DN_Str8 DN_Str8TrimAround (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 size); -DN_API DN_Str8TruncateResult DN_Str8TruncateMiddle (DN_Arena *arena, DN_Str8 str8, DN_U32 side_size, DN_Str8 truncator); -DN_API DN_Str8 DN_Str8Lower (DN_Arena *arena, DN_Str8 string); -DN_API DN_Str8 DN_Str8Upper (DN_Arena *arena, DN_Str8 string); - -DN_API DN_Str8Builder DN_Str8BuilderFromArena (DN_Arena *arena); -DN_API DN_Str8Builder DN_Str8BuilderFromStr8PtrRef (DN_Arena *arena, DN_Str8 const *strings, DN_USize size); -DN_API DN_Str8Builder DN_Str8BuilderFromStr8PtrCopy (DN_Arena *arena, DN_Str8 const *strings, DN_USize size); -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 size, DN_Str8BuilderAdd add); -DN_API bool DN_Str8BuilderAddArrayCopy (DN_Str8Builder *builder, DN_Str8 const *strings, DN_USize size, DN_Str8BuilderAdd add); -DN_API bool DN_Str8BuilderAddFV (DN_Str8Builder *builder, DN_Str8BuilderAdd add, DN_FMT_ATTRIB char const *fmt, va_list args); -#define DN_Str8BuilderAppendArrayRef(builder, strings, size) DN_Str8BuilderAddArrayRef(builder, strings, size, DN_Str8BuilderAdd_Append) -#define DN_Str8BuilderAppendArrayCopy(builder, strings, size) DN_Str8BuilderAddArrayCopy(builder, strings, size, DN_Str8BuilderAdd_Append) -#define DN_Str8BuilderAppendSliceRef(builder, slice) DN_Str8BuilderAddArrayRef(builder, slice.data, slice.size, DN_Str8BuilderAdd_Append) -#define DN_Str8BuilderAppendSliceCopy(builder, slice) DN_Str8BuilderAddArrayCopy(builder, slice.data, slice.size, DN_Str8BuilderAdd_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_Str8BuilderAdd_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 size); -DN_API bool DN_Str8BuilderAppendBytesCopy (DN_Str8Builder *builder, void const *ptr, DN_USize size); -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_Str8BuilderAdd_Prepend) -#define DN_Str8BuilderPrependArrayCopy(builder, strings, size) DN_Str8BuilderAddArrayCopy(builder, strings, size, DN_Str8BuilderAdd_Prepend) -#define DN_Str8BuilderPrependSliceRef(builder, slice) DN_Str8BuilderAddArrayRef(builder, slice.data, slice.size, DN_Str8BuilderAdd_Prepend) -#define DN_Str8BuilderPrependSliceCopy(builder, slice) DN_Str8BuilderAddArrayCopy(builder, slice.data, slice.size, DN_Str8BuilderAdd_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_Str8BuilderAdd_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_Str8BuilderBuild (DN_Str8Builder const *builder, DN_Arena *arena); -DN_API DN_Str8 DN_Str8BuilderBuildDelimited (DN_Str8Builder const *builder, DN_Str8 delimiter, DN_Arena *arena); -DN_API DN_Slice DN_Str8BuilderBuildSlice (DN_Str8Builder const *builder, DN_Arena *arena); - -DN_API int DN_EncodeUTF8Codepoint (uint8_t utf8[4], uint32_t codepoint); -DN_API int DN_EncodeUTF16Codepoint (uint16_t utf16[2], uint32_t codepoint); - -DN_API DN_U8 DN_U8FromHexNibble (char hex); -DN_API DN_NibbleFromU8Result DN_NibbleFromU8 (DN_U8 u8); - -DN_API DN_USize DN_BytesFromHexPtr (void const *hex, DN_USize hex_count, void *dest, DN_USize dest_count); -DN_API DN_Str8 DN_BytesFromHexPtrArena (void const *hex, DN_USize hex_count, DN_Arena *arena); -DN_API DN_USize DN_BytesFromHexStr8 (DN_Str8 hex, void *dest, DN_USize dest_count); -DN_API DN_Str8 DN_BytesFromHexStr8Arena (DN_Str8 hex, DN_Arena *arena); -DN_API DN_U8x16 DN_BytesFromHex32Ptr (void const *hex, DN_USize hex_count); -DN_API DN_U8x32 DN_BytesFromHex64Ptr (void const *hex, DN_USize hex_count); - -DN_API DN_HexU64Str8 DN_HexFromU64 (DN_U64 value, DN_HexFromU64Type type); -DN_API DN_USize DN_HexFromBytesPtr (void const *bytes, DN_USize bytes_count, void *hex, DN_USize hex_count); -DN_API DN_Str8 DN_HexFromBytesPtrArena (void const *bytes, DN_USize bytes_count, DN_Arena *arena); -DN_API DN_Hex32 DN_HexFromBytes16Ptr (void const *bytes, DN_USize bytes_count); -DN_API DN_Hex64 DN_HexFromBytes32Ptr (void const *bytes, DN_USize bytes_count); -DN_API DN_Hex128 DN_HexFromBytes64Ptr (void const *bytes, DN_USize bytes_count); - -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 DN_ByteCountResult DN_ByteCountFromType (DN_U64 bytes, DN_ByteCountType type); -#define DN_ByteCount(bytes) DN_ByteCountFromType(bytes, DN_ByteCountType_Auto) -DN_API DN_Str8x32 DN_ByteCountStr8x32FromType (DN_U64 bytes, DN_ByteCountType type); -#define DN_ByteCountStr8x32(bytes) DN_ByteCountStr8x32FromType(bytes, DN_ByteCountType_Auto) - -#define DN_ProfilerZoneLoop(prof, name, index) \ - DN_ProfilerZone DN_UniqueName(zone_) = DN_ProfilerBeginZone(prof, DN_Str8Lit(name), index), DN_UniqueName(dummy_) = {}; \ - DN_UniqueName(dummy_).begin_tsc == 0; \ - DN_ProfilerEndZone(prof, DN_UniqueName(zone_)), DN_UniqueName(dummy_).begin_tsc = 1 - -#define DN_ProfilerZoneLoopAuto(prof, name) DN_ProfilerZoneLoop(prof, name, __COUNTER__ + 1) -DN_API DN_Profiler DN_ProfilerInit (DN_ProfilerAnchor *anchors, DN_USize count, DN_USize anchors_per_frame, DN_ProfilerTSCNowFunc *tsc_now, DN_U64 tsc_frequency); -DN_API DN_ProfilerZone DN_ProfilerBeginZone (DN_Profiler *profiler, DN_Str8 name, DN_U16 anchor_index); -#define DN_ProfilerBeginZoneAuto(prof, name) DN_ProfilerBeginZone(prof, DN_Str8Lit(name), __COUNTER__ + 1) -DN_API void DN_ProfilerEndZone (DN_Profiler *profiler, DN_ProfilerZone zone); -DN_API DN_USize DN_ProfilerFrameCount (DN_Profiler const *profiler); -DN_API DN_ProfilerAnchorArray DN_ProfilerFrameAnchorsFromIndex (DN_Profiler *profiler, DN_USize frame_index); -DN_API DN_ProfilerAnchorArray DN_ProfilerFrameAnchors (DN_Profiler *profiler); -DN_API void DN_ProfilerNewFrame (DN_Profiler *profiler); -DN_API void DN_ProfilerDump (DN_Profiler *profiler); -DN_API DN_F64 DN_ProfilerSecFromTSC (DN_Profiler *profiler, DN_U64 duration_tsc); -DN_API DN_F64 DN_ProfilerMsFromTSC (DN_Profiler *profiler, DN_U64 duration_tsc); - -#endif // !defined(DN_BASE_H) -// DN: Single header generator inlined this file => #include "Base/dn_base_os.h" -#if !defined(DN_BASE_OS_H) -#define DN_BASE_OS_H - -// DN: Single header generator commented out this header => #include "../dn_base_inc.h" - -// NOTE: OS primitives that the OS layer can provide for the base layer but is optional. - -struct DN_StackTraceFrame -{ - DN_U64 address; - DN_U64 line_number; - DN_Str8 file_name; - DN_Str8 function_name; -}; - -struct DN_StackTraceRawFrame -{ - void *process; - DN_U64 base_addr; -}; - -struct DN_StackTraceWalkResult -{ - void *process; // [Internal] Windows handle to the process - DN_U64 *base_addr; // The addresses of the functions in the stack trace - DN_U16 size; // The number of `base_addr`'s stored from the walk -}; - -struct DN_StackTraceWalkResultIterator -{ - DN_StackTraceRawFrame raw_frame; - DN_U16 index; -}; - - -#if defined(DN_FREESTANDING) -#define DN_StackTraceWalkStr8FromHeap(...) DN_Str8Lit("N/A") -#define DN_StackTraceWalk(...) -#define DN_StackTraceWalkResultIterate(...) -#define DN_StackTraceWalkResultToStr8(...) DN_Str8Lit("N/A") -#define DN_StackTraceWalkStr8(...) DN_Str8Lit("N/A") -#define DN_StackTraceWalkStr8FromHeap(...) DN_Str8Lit("N/A") -#define DN_StackTraceGetFrames(...) -#define DN_StackTraceRawFrameToFrame(...) -#define DN_StackTracePrint(...) -#define DN_StackTraceReloadSymbols(...) -#else -DN_API DN_StackTraceWalkResult DN_StackTraceWalk (struct DN_Arena *arena, DN_U16 limit); -DN_API bool DN_StackTraceWalkResultIterate(DN_StackTraceWalkResultIterator *it, DN_StackTraceWalkResult const *walk); -DN_API DN_Str8 DN_StackTraceWalkResultToStr8 (struct DN_Arena *arena, DN_StackTraceWalkResult const *walk, DN_U16 skip); -DN_API DN_Str8 DN_StackTraceWalkStr8 (struct DN_Arena *arena, DN_U16 limit, DN_U16 skip); -DN_API DN_Str8 DN_StackTraceWalkStr8FromHeap (DN_U16 limit, DN_U16 skip); -DN_API DN_Slice DN_StackTraceGetFrames (struct DN_Arena *arena, DN_U16 limit); -DN_API DN_StackTraceFrame DN_StackTraceRawFrameToFrame (struct DN_Arena *arena, DN_StackTraceRawFrame raw_frame); -DN_API void DN_StackTracePrint (DN_U16 limit); -DN_API void DN_StackTraceReloadSymbols (); -#endif -#endif // !defined(DN_BASE_OS_H) -// DN: Single header generator inlined this file => #include "Base/dn_base_assert.h" -#if !defined(DN_BASE_ASSERT_H) -#define DN_BASE_ASSERT_H - -#define DN_HardAssertF(expr, fmt, ...) \ - do { \ - if (!(expr)) { \ - DN_Str8 stack_trace_ = DN_StackTraceWalkStr8FromHeap(128 /*limit*/, 2 /*skip*/); \ - DN_LOG_ErrorF("Hard assertion [" #expr "], stack trace was:\n\n%.*s\n\n" fmt, \ - DN_Str8PrintFmt(stack_trace_), \ - ##__VA_ARGS__); \ - DN_DebugBreak; \ - } \ - } while (0) -#define DN_HardAssert(expr) DN_HardAssertF(expr, "") - -// NOTE: Our default assert requires stack traces which has a bit of a chicken-and-egg problem if -// we're trying to detect some code related to the DN startup sequence. If we try to assert before -// the OS layer is initialised stack-traces will try to use temporary memory which requires TLS to -// be setup which belongs to the OS. -// -// This causes recursion errors as they call into each other. We use RawAsserts for these kind of -// checks. -#if defined(DN_NO_ASSERT) - #define DN_RawAssert(...) - #define DN_Assert(...) - #define DN_AssertOnce(...) - #define DN_AssertF(...) - #define DN_AssertFOnce(...) -#else - #define DN_RawAssert(expr) do { if (!(expr)) DN_DebugBreak; } while (0) - - #define DN_AssertF(expr, fmt, ...) \ - do { \ - if (!(expr)) { \ - DN_Str8 stack_trace_ = DN_StackTraceWalkStr8FromHeap(128 /*limit*/, 2 /*skip*/); \ - DN_LOG_ErrorF("Assertion [" #expr "], stack trace was:\n\n%.*s\n\n" fmt, \ - DN_Str8PrintFmt(stack_trace_), \ - ##__VA_ARGS__); \ - DN_DebugBreak; \ - } \ - } while (0) - - #define DN_AssertFOnce(expr, fmt, ...) \ - do { \ - static bool once = true; \ - if (!(expr) && once) { \ - once = false; \ - DN_Str8 stack_trace_ = DN_StackTraceWalkStr8FromHeap(128 /*limit*/, 2 /*skip*/); \ - DN_LOG_ErrorF("Assertion [" #expr "], stack trace was:\n\n%.*s\n\n" fmt, \ - DN_Str8PrintFmt(stack_trace_), \ - ##__VA_ARGS__); \ - DN_DebugBreak; \ - } \ - } while (0) - - #define DN_Assert(expr) DN_AssertF((expr), "") - #define DN_AssertOnce(expr) DN_AssertFOnce((expr), "") -#endif - -#define DN_InvalidCodePathF(fmt, ...) DN_HardAssertF(0, fmt, ##__VA_ARGS__) -#define DN_InvalidCodePath DN_InvalidCodePathF("Invalid code path triggered") -#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_Check(expr) DN_CheckF(expr, "") -#if defined(DN_NO_CHECK_BREAK) - #define DN_CheckF(expr, fmt, ...) \ - ((expr) ? true : (DN_LOG_WarningF(fmt, ##__VA_ARGS__), false)) -#else - #define DN_CheckF(expr, fmt, ...) \ - ((expr) ? true : (DN_LOG_ErrorF(fmt, ##__VA_ARGS__), DN_StackTracePrint(128 /*limit*/), DN_DebugBreak, false)) -#endif - -#endif -// DN: Single header generator inlined this file => #include "Base/dn_base_log.h" -#if !defined(DN_BASE_LOG_H) -#define DN_BASE_LOG_H - -// DN: Single header generator commented out this header => #include "../dn_base_inc.h" - -enum DN_LOGType -{ - DN_LOGType_Debug, - DN_LOGType_Info, - DN_LOGType_Warning, - DN_LOGType_Error, - DN_LOGType_Count, -}; - -enum DN_LOGBold -{ - DN_LOGBold_No, - DN_LOGBold_Yes, -}; - -struct DN_LOGStyle -{ - DN_LOGBold bold; - bool colour; - DN_U8 r, g, b; -}; - -struct DN_LOGTypeParam -{ - bool is_u32_enum; - DN_U32 u32; - DN_Str8 str8; -}; - -enum DN_LOGColourType -{ - DN_LOGColourType_Fg, - DN_LOGColourType_Bg, -}; - -struct DN_LOGDate -{ - DN_U16 year; - DN_U8 month; - DN_U8 day; - - DN_U8 hour; - DN_U8 minute; - DN_U8 second; -}; - -struct DN_LOGPrefixSize -{ - DN_USize size; - DN_USize padding; -}; - -typedef void DN_LOGEmitFromTypeFVFunc(DN_LOGTypeParam type, void *user_data, DN_CallSite call_site, DN_FMT_ATTRIB char const *fmt, va_list args); - -#define DN_LOG_ResetEscapeCode "\x1b[0m" -#define DN_LOG_BoldEscapeCode "\x1b[1m" -DN_API DN_Str8 DN_LOG_ColourEscapeCodeStr8FromRGB(DN_LOGColourType colour, DN_U8 r, DN_U8 g, DN_U8 b); -DN_API DN_Str8 DN_LOG_ColourEscapeCodeStr8FromU32(DN_LOGColourType colour, DN_U32 value); -DN_API DN_LOGPrefixSize DN_LOG_MakePrefix (DN_LOGStyle style, DN_LOGTypeParam type, DN_CallSite call_site, DN_LOGDate date, char *dest, DN_USize dest_size); -DN_API void DN_LOG_SetEmitFromTypeFVFunc (DN_LOGEmitFromTypeFVFunc *print_func, void *user_data); -DN_API void DN_LOG_EmitFromType (DN_LOGTypeParam type, DN_CallSite call_site, DN_FMT_ATTRIB char const *fmt, ...); -DN_API DN_LOGTypeParam DN_LOG_MakeU32LogTypeParam (DN_LOGType type); -#define DN_LOG_DebugF(fmt, ...) DN_LOG_EmitFromType(DN_LOG_MakeU32LogTypeParam(DN_LOGType_Debug), DN_CALL_SITE, fmt, ##__VA_ARGS__) -#define DN_LOG_InfoF(fmt, ...) DN_LOG_EmitFromType(DN_LOG_MakeU32LogTypeParam(DN_LOGType_Info), DN_CALL_SITE, fmt, ##__VA_ARGS__) -#define DN_LOG_WarningF(fmt, ...) DN_LOG_EmitFromType(DN_LOG_MakeU32LogTypeParam(DN_LOGType_Warning), DN_CALL_SITE, fmt, ##__VA_ARGS__) -#define DN_LOG_ErrorF(fmt, ...) DN_LOG_EmitFromType(DN_LOG_MakeU32LogTypeParam(DN_LOGType_Error), DN_CALL_SITE, fmt, ##__VA_ARGS__) -#endif // !defined(DN_BASE_LOG_H) -// DN: Single header generator inlined this file => #include "Base/dn_base_containers.h" -#if !defined(DN_CONTAINERS_H) -#define DN_CONTAINERS_H - -// DN: Single header generator commented out this header => #include "../dn_base_inc.h" - -struct DN_Ring -{ - DN_U64 size; - char *base; - DN_U64 write_pos; - DN_U64 read_pos; -}; - -// NOTE: DN_CArray ///////////////////////////////////////////////////////////////////////////////// -enum DN_ArrayErase -{ - DN_ArrayErase_Unstable, - DN_ArrayErase_Stable, -}; - -enum DN_ArrayAdd -{ - DN_ArrayAdd_Append, - DN_ArrayAdd_Prepend, -}; - -struct DN_ArrayEraseResult -{ - // The next index your for-index should be set to such that you can continue - // to iterate the remainder of the array, e.g: - // - // for (DN_USize index = 0; index < array.size; index++) { - // if (erase) - // index = DN_FArray_EraseRange(&array, index, -3, DN_ArrayErase_Unstable); - // } - DN_USize it_index; - DN_USize items_erased; // The number of items erased -}; - -template struct DN_ArrayFindResult -{ - T *data; // Pointer to the value if a match is found, null pointer otherwise - DN_USize index; // Index to the value if a match is found, 0 otherwise -}; - -#if !defined(DN_NO_SARRAY) -// NOTE: DN_SArray ///////////////////////////////////////////////////////////////////////////////// -template struct DN_SArray -{ - T *data; // Pointer to the start of the array items in the block of memory - DN_USize size; // Number of items currently in the array - DN_USize max; // Maximum number of items this array can store - - T *begin() { return data; } - T *end () { return data + size; } - T const *begin() const { return data; } - T const *end () const { return data + size; } -}; -#endif // !defined(DN_NO_SARRAY) - -#if !defined(DN_NO_FARRAY) -// NOTE: DN_FArray ///////////////////////////////////////////////////////////////////////////////// -template struct DN_FArray -{ - T data[N]; // Pointer to the start of the array items in the block of memory - DN_USize size; // Number of items currently in the array - - T *begin() { return data; } - T *end () { return data + size; } - T const *begin() const { return data; } - T const *end () const { return data + size; } -}; - -template using DN_FArray8 = DN_FArray; -template using DN_FArray16 = DN_FArray; -template using DN_FArray32 = DN_FArray; -template using DN_FArray64 = DN_FArray; -#endif // !defined(DN_NO_FARRAY) - -#if !defined(DN_NO_DSMAP) -// NOTE: DN_DSMap ////////////////////////////////////////////////////////////////////////////////// -enum DN_DSMapKeyType -{ - // Key | Key Hash | Map Index - DN_DSMapKeyType_Invalid, - DN_DSMapKeyType_U64, // U64 | Hash(U64) | Hash(U64) % map_size - DN_DSMapKeyType_U64NoHash, // U64 | U64 | U64 % map_size - DN_DSMapKeyType_Buffer, // Buffer | Hash(buffer) | Hash(buffer) % map_size - DN_DSMapKeyType_BufferAsU64NoHash, // Buffer | U64(buffer[0:4]) | U64(buffer[0:4]) % map_size -}; - -struct DN_DSMapKey -{ - DN_DSMapKeyType type; - DN_U32 hash; // Hash to lookup in the map. If it equals, we check that the original key payload matches - void const *buffer_data; - DN_U32 buffer_size; - DN_U64 u64; - bool no_copy_buffer; -}; - -template -struct DN_DSMapSlot -{ - DN_DSMapKey key; // Hash table lookup key - T value; // Hash table value -}; - -typedef DN_U32 DN_DSMapFlags; -enum DN_DSMapFlags_ -{ - DN_DSMapFlags_Nil = 0, - DN_DSMapFlags_DontFreeArenaOnResize = 1 << 0, -}; - -using DN_DSMapHashFunction = DN_U32(DN_DSMapKey key, DN_U32 seed); -template struct DN_DSMap -{ - DN_U32 *hash_to_slot; // Mapping from hash to a index in the slots array - DN_DSMapSlot *slots; // Values of the array stored contiguously, non-sorted order - DN_U32 size; // Total capacity of the map and is a power of two - DN_U32 occupied; // Number of slots used in the hash table - DN_Arena *arena; // Backing arena for the hash table - DN_Pool pool; // Allocator for keys that are variable-sized buffers - DN_U32 initial_size; // Initial map size, map cannot shrink on erase below this size - DN_DSMapHashFunction *hash_function; // Custom hashing function to use if field is set - DN_U32 hash_seed; // Seed for the hashing function, when 0, DN_DS_MAP_DEFAULT_HASH_SEED is used - DN_DSMapFlags flags; -}; - -template struct DN_DSMapResult -{ - bool found; - DN_DSMapSlot *slot; - T *value; -}; -#endif // !defined(DN_NO_DSMAP) - -#if !defined(DN_NO_LIST) -// NOTE: DN_List /////////////////////////////////////////////////////////////////////////////////// -template struct DN_ListChunk -{ - T *data; - DN_USize size; - DN_USize count; - DN_ListChunk *next; - DN_ListChunk *prev; -}; - -template struct DN_ListIterator -{ - DN_B32 init; // True if DN_List_Iterate has been called at-least once on this iterator - DN_ListChunk *chunk; // The chunk that the iterator is reading from - DN_USize chunk_data_index; // The index in the chunk the iterator is referencing - DN_USize index; // The index of the item in the list as if it was flat array - T *data; // Pointer to the data the iterator is referencing. Nullptr if invalid. -}; - -template struct DN_List -{ - DN_USize count; // Cumulative count of all items made across all list chunks - DN_USize chunk_size; // When new ListChunk's are required, the minimum 'data' entries to allocate for that node. - DN_ListChunk *head; - DN_ListChunk *tail; -}; -#endif // !defined(DN_NO_LIST) - -// NOTE: Macros for operating on data structures that are embedded into a C style struct or from a -// set of defined variables from the available scope. Keep it stupid simple, structs and functions. -// Minimal amount of container types with flexible construction leads to less duplicated container -// code and less template meta-programming. -// -// LArray => Literal Array -// Define a C array and size: -// -// ``` -// MyStruct buffer[TB_ASType_Count] = {}; -// DN_USize size = 0; -// MyStruct *item = DN_LArray_Make(buffer, size, DN_ArrayCountU(buffer), DN_ZMem_No); -// ``` -// -// IArray => Intrusive Array -// Define a struct with the members 'data', 'size' and 'max': -// -// ``` -// struct MyArray { -// MyStruct *data; -// DN_USize size; -// DN_USize max; -// } my_array = {}; -// -// MyStruct *item = DN_IArray_Make(&my_array, MyArray, DN_ZMem_No); -// ``` -// ISLList => Intrusive Singly Linked List -// Define a struct with the members 'next': -// -// ``` -// struct MyLinkItem { -// int data; -// MyLinkItem *next; -// } my_link = {}; -// -// MyLinkItem *first_item = DN_ISLList_Detach(&my_link, MyLinkItem); -// ``` - -#define DN_DLList_Init(list) \ - (list)->next = (list)->prev = (list) - -#define DN_DLList_IsSentinel(list, item) ((list) == (item)) - -#define DN_DLList_InitArena(list, T, arena) \ - do { \ - (list) = DN_ArenaNew(arena, T, DN_ZMem_Yes); \ - DN_DLList_Init(list); \ - } while (0) - -#define DN_DLList_InitPool(list, T, pool) \ - do { \ - (list) = DN_PoolNew(pool, T); \ - DN_DLList_Init(list); \ - } while (0) - -#define DN_DLList_Detach(item) \ - do { \ - if (item) { \ - (item)->prev->next = (item)->next; \ - (item)->next->prev = (item)->prev; \ - (item)->next = nullptr; \ - (item)->prev = nullptr; \ - } \ - } while (0) - -#define DN_DLList_Dequeue(list, dest_ptr) \ - if (DN_DLList_HasItems(list)) { \ - dest_ptr = (list)->next; \ - DN_DLList_Detach(dest_ptr); \ - } - -#define DN_DLList_Append(list, item) \ - do { \ - if (item) { \ - if ((item)->next) \ - DN_DLList_Detach(item); \ - (item)->next = (list)->next; \ - (item)->prev = (list); \ - (item)->next->prev = (item); \ - (item)->prev->next = (item); \ - } \ - } while (0) - -#define DN_DLList_Prepend(list, item) \ - do { \ - if (item) { \ - if ((item)->next) \ - DN_DLList_Detach(item); \ - (item)->next = (list); \ - (item)->prev = (list)->prev; \ - (item)->next->prev = (item); \ - (item)->prev->next = (item); \ - } \ - } while (0) - -#define DN_DLList_IsEmpty(list) \ - (!(list) || ((list) == (list)->next)) - -#define DN_DLList_IsInit(list) \ - ((list)->next && (list)->prev) - -#define DN_DLList_HasItems(list) \ - ((list) && ((list) != (list)->next)) - -#define DN_DLList_ForEach(it, list) \ - auto *it = (list)->next; (it) != (list); (it) = (it)->next - -#define DN_DoublyLLDetach(head, ptr) \ - do { \ - if ((head) && (head) == (ptr)) \ - (head) = (head)->next; \ - if ((ptr)) { \ - if ((ptr)->next) \ - (ptr)->next->prev = (ptr)->prev; \ - if ((ptr)->prev) \ - (ptr)->prev->next = (ptr)->next; \ - (ptr)->prev = (ptr)->next = 0; \ - } \ - } while (0) - -#define DN_DoublyLLAppend(head, ptr) \ - do { \ - if ((ptr)) { \ - DN_AssertF((ptr)->prev == 0 && (ptr)->next == 0, "Detach the pointer first"); \ - (ptr)->prev = (head); \ - (ptr)->next = 0; \ - if ((head)) { \ - (ptr)->next = (head)->next; \ - (head)->next = (ptr); \ - } else { \ - (head) = (ptr); \ - } \ - } \ - } while (0) - -#define DN_DoublyLLPrepend(head, ptr) \ - do { \ - if ((ptr)) { \ - DN_AssertF((ptr)->prev == 0 && (ptr)->next == 0, "Detach the pointer first"); \ - (ptr)->prev = nullptr; \ - (ptr)->next = (head); \ - if ((head)) { \ - (ptr)->prev = (head)->prev; \ - (head)->prev = (ptr); \ - } else { \ - (head) = (ptr); \ - } \ - } \ - } while (0) - -#define DN_ISLList_Detach(list) (decltype(list))DN_CSLList_Detach((void **)&(list), (void **)&(list)->next) - -#define DN_LArray_ResizeFromPool(c_array, size, max, pool, new_max) DN_CArray2_ResizeFromPool((void **)&(c_array), size, max, sizeof((c_array)[0]), pool, new_max) -#define DN_LArray_GrowFromPool(c_array, size, max, pool, new_max) DN_CArray2_GrowFromPool((void **)&(c_array), size, max, sizeof((c_array)[0]), pool, new_max) -#define DN_LArray_GrowIfNeededFromPool(c_array, size, max, pool, add_count) DN_CArray2_GrowIfNeededFromPool((void **)(c_array), size, max, sizeof((c_array)[0]), pool, add_count) -#define DN_LArray_MakeArray(c_array, size, max, count, z_mem) (decltype(&(c_array)[0]))DN_CArray2_MakeArray(c_array, size, max, sizeof((c_array)[0]), count, z_mem) -#define DN_LArray_MakeArrayZ(c_array, size, max, count) (decltype(&(c_array)[0]))DN_CArray2_MakeArray(c_array, size, max, sizeof((c_array)[0]), count, DN_ZMem_Yes) -#define DN_LArray_Make(c_array, size, max, z_mem) (decltype(&(c_array)[0]))DN_CArray2_MakeArray(c_array, size, max, sizeof((c_array)[0]), 1, z_mem) -#define DN_LArray_MakeZ(c_array, size, max) (decltype(&(c_array)[0]))DN_CArray2_MakeArray(c_array, size, max, sizeof((c_array)[0]), 1, DN_ZMem_Yes) -#define DN_LArray_AddArray(c_array, size, max, items, count, add) (decltype(&(c_array)[0]))DN_CArray2_AddArray(c_array, size, max, sizeof((c_array)[0]), items, count, add) -#define DN_LArray_Add(c_array, size, max, item, add) (decltype(&(c_array)[0]))DN_CArray2_AddArray(c_array, size, max, sizeof((c_array)[0]), &item, 1, add) -#define DN_LArray_AppendArray(c_array, size, max, items, count) (decltype(&(c_array)[0]))DN_CArray2_AddArray(c_array, size, max, sizeof((c_array)[0]), items, count, DN_ArrayAdd_Append) -#define DN_LArray_Append(c_array, size, max, item) (decltype(&(c_array)[0]))DN_CArray2_AddArray(c_array, size, max, sizeof((c_array)[0]), &item, 1, DN_ArrayAdd_Append) -#define DN_LArray_PrependArray(c_array, size, max, items, count) (decltype(&(c_array)[0]))DN_CArray2_AddArray(c_array, size, max, sizeof((c_array)[0]), items, count, DN_ArrayAdd_Prepend) -#define DN_LArray_Prepend(c_array, size, max, item) (decltype(&(c_array)[0]))DN_CArray2_AddArray(c_array, size, max, sizeof((c_array)[0]), &item, 1, DN_ArrayAdd_Prepend) -#define DN_LArray_EraseRange(c_array, size, begin_index, count, erase) DN_CArray2_EraseRange(c_array, size, sizeof((c_array)[0]), begin_index, count, erase) -#define DN_LArray_Erase(c_array, size, index, erase) DN_CArray2_EraseRange(c_array, size, sizeof((c_array)[0]), index, 1, erase) -#define DN_LArray_InsertArray(c_array, size, max, index, items, count) (decltype(&(c_array)[0]))DN_CArray2_InsertArray(c_array, size, max, sizeof((c_array)[0]), index, items, count) -#define DN_LArray_Insert(c_array, size, max, index, item) (decltype(&(c_array)[0]))DN_CArray2_InsertArray(c_array, size, max, sizeof((c_array)[0]), index, &item, 1) - -#define DN_IArray_ResizeFromPool(array, pool, new_max) DN_CArray2_ResizeFromPool((void **)(&(array)->data), &(array)->size, &(array)->max, sizeof((array)->data[0]), pool, new_max) -#define DN_IArray_GrowFromPool(array, pool, new_max) DN_CArray2_GrowFromPool((void **)(&(array)->data), &(array)->size, &(array)->max, sizeof((array)->data[0]), pool, new_max) -#define DN_IArray_GrowIfNeededFromPool(array, pool, add_count) DN_CArray2_GrowIfNeededFromPool((void **)(&(array)->data), (array)->size, &(array)->max, sizeof((array)->data[0]), pool, add_count) -#define DN_IArray_MakeArray(array, count, z_mem) (decltype(&((array)->data)[0]))DN_CArray2_MakeArray((array)->data, &(array)->size, (array)->max, sizeof(((array)->data)[0]), count, z_mem) -#define DN_IArray_MakeArrayZ(array, count) (decltype(&((array)->data)[0]))DN_CArray2_MakeArray((array)->data, &(array)->size, (array)->max, sizeof(((array)->data)[0]), count, DN_ZMem_Yes) -#define DN_IArray_Make(array, z_mem) (decltype(&((array)->data)[0]))DN_CArray2_MakeArray((array)->data, &(array)->size, (array)->max, sizeof(((array)->data)[0]), 1, z_mem) -#define DN_IArray_MakeZ(array) (decltype(&((array)->data)[0]))DN_CArray2_MakeArray((array)->data, &(array)->size, (array)->max, sizeof(((array)->data)[0]), 1, DN_ZMem_Yes) -#define DN_IArray_AddArray(array, items, count, add) (decltype(&((array)->data)[0]))DN_CArray2_AddArray((array)->data, &(array)->size, (array)->max, sizeof(((array)->data)[0]), items, count, add) -#define DN_IArray_Add(array, item, add) (decltype(&((array)->data)[0]))DN_CArray2_AddArray((array)->data, &(array)->size, (array)->max, sizeof(((array)->data)[0]), &item, 1, add) -#define DN_IArray_AppendArray(array, items, count) (decltype(&((array)->data)[0]))DN_CArray2_AddArray((array)->data, &(array)->size, (array)->max, sizeof(((array)->data)[0]), items, count, DN_ArrayAdd_Append) -#define DN_IArray_Append(array, item) (decltype(&((array)->data)[0]))DN_CArray2_AddArray((array)->data, &(array)->size, (array)->max, sizeof(((array)->data)[0]), &item, 1, DN_ArrayAdd_Append) -#define DN_IArray_PrependArray(array, items, count) (decltype(&((array)->data)[0]))DN_CArray2_AddArray((array)->data, &(array)->size, (array)->max, sizeof(((array)->data)[0]), items, count, DN_ArrayAdd_Prepend) -#define DN_IArray_Prepend(array, item) (decltype(&((array)->data)[0]))DN_CArray2_AddArray((array)->data, &(array)->size, (array)->max, sizeof(((array)->data)[0]), &item, 1, DN_ArrayAdd_Prepend) -#define DN_IArray_EraseRange(array, begin_index, count, erase) DN_CArray2_EraseRange((array)->data, &(array)->size, sizeof(((array)->data)[0]), begin_index, count, erase) -#define DN_IArray_Erase(array, index, erase) DN_CArray2_EraseRange((array)->data, &(array)->size, sizeof(((array)->data)[0]), index, 1, erase) -#define DN_IArray_InsertArray(array, index, items, count) (decltype(&((array)->data)[0]))DN_CArray2_InsertArray((array)->data, &(array)->size, (array)->max, sizeof(((array)->data)[0]), index, items, count) -#define DN_IArray_Insert(array, index, item, count) (decltype(&((array)->data)[0]))DN_CArray2_InsertArray((array)->data, &(array)->size, (array)->max, sizeof(((array)->data)[0]), index, &item, 1) - -DN_API DN_ArrayEraseResult DN_CArray2_EraseRange (void *data, DN_USize *size, DN_USize elem_size, DN_USize begin_index, DN_ISize count, DN_ArrayErase erase); -DN_API void *DN_CArray2_MakeArray (void *data, DN_USize *size, DN_USize max, DN_USize data_size, DN_USize make_size, DN_ZMem z_mem); -DN_API void *DN_CArray2_AddArray (void *data, DN_USize *size, DN_USize max, DN_USize data_size, void const *elems, DN_USize elems_count, DN_ArrayAdd add); -DN_API bool DN_CArray2_Resize (void **data, DN_USize *size, DN_USize *max, DN_USize data_size, DN_Pool *pool, DN_USize new_max); -DN_API bool DN_CArray2_Grow (void **data, DN_USize *size, DN_USize *max, DN_USize data_size, DN_Pool *pool, DN_USize new_max); -DN_API bool DN_CArray2_GrowIfNeededFromPool (void **data, DN_USize size, DN_USize *max, DN_USize data_size, DN_Pool *pool); -DN_API void *DN_CSLList_Detach (void **link, void **next); - -DN_API bool DN_Ring_HasSpace (DN_Ring const *ring, DN_U64 size); -DN_API bool DN_Ring_HasData (DN_Ring const *ring, DN_U64 size); -DN_API void DN_Ring_Write (DN_Ring *ring, void const *src, DN_U64 src_size); -#define DN_Ring_WriteStruct(ring, item) DN_Ring_Write((ring), (item), sizeof(*(item))) -DN_API void DN_Ring_Read (DN_Ring *ring, void *dest, DN_U64 dest_size); -#define DN_Ring_ReadStruct(ring, dest) DN_Ring_Read((ring), (dest), sizeof(*(dest))) - -template DN_ArrayEraseResult DN_CArray_EraseRange (T *data, DN_USize *size, DN_USize begin_index, DN_ISize count, DN_ArrayErase erase); -template T * DN_CArray_MakeArray (T *data, DN_USize *size, DN_USize max, DN_USize count, DN_ZMem z_mem); -template T * DN_CArray_InsertArray (T *data, DN_USize *size, DN_USize max, DN_USize index, T const *items, DN_USize count); -template T DN_CArray_PopFront (T *data, DN_USize *size, DN_USize count); -template T DN_CArray_PopBack (T *data, DN_USize *size, DN_USize count); -template DN_ArrayFindResult DN_CArray_Find (T *data, DN_USize size, T const &value); - -// NOTE: DN_SArray ///////////////////////////////////////////////////////////////////////////////// -#if !defined(DN_NO_SARRAY) -template DN_SArray DN_SArray_Init (DN_Arena *arena, DN_USize size, DN_ZMem z_mem); -template DN_SArray DN_SArray_InitSlice (DN_Arena *arena, DN_Slice slice, DN_USize size, DN_ZMem z_mem); -template DN_SArray DN_SArray_InitCArray (DN_Arena *arena, T const (&array)[N], DN_USize size, DN_ZMem); -template DN_SArray DN_SArray_InitBuffer (T* buffer, DN_USize size); -template bool DN_SArray_IsValid (DN_SArray const *array); -template DN_Slice DN_SArray_Slice (DN_SArray const *array); -template T * DN_SArray_AddArray (DN_SArray *array, T const *items, DN_USize count); -template T * DN_SArray_AddCArray (DN_SArray *array, T const (&items)[N]); -template T * DN_SArray_Add (DN_SArray *array, T const &item); -#define DN_SArray_AddArrayAssert(...) DN_HardAssert(DN_SArray_AddArray(__VA_ARGS__)) -#define DN_SArray_AddCArrayAssert(...) DN_HardAssert(DN_SArray_AddCArray(__VA_ARGS__)) -#define DN_SArray_AddAssert(...) DN_HardAssert(DN_SArray_Add(__VA_ARGS__)) -template T * DN_SArray_MakeArray (DN_SArray *array, DN_USize count, DN_ZMem z_mem); -template T * DN_SArray_Make (DN_SArray *array, DN_ZMem z_mem); -#define DN_SArray_MakeArrayAssert(...) DN_HardAssert(DN_SArray_MakeArray(__VA_ARGS__)) -#define DN_SArray_MakeAssert(...) DN_HardAssert(DN_SArray_Make(__VA_ARGS__)) -template T * DN_SArray_InsertArray (DN_SArray *array, DN_USize index, T const *items, DN_USize count); -template T * DN_SArray_InsertCArray (DN_SArray *array, DN_USize index, T const (&items)[N]); -template T * DN_SArray_Insert (DN_SArray *array, DN_USize index, T const &item); -#define DN_SArray_InsertArrayAssert(...) DN_HardAssert(DN_SArray_InsertArray(__VA_ARGS__)) -#define DN_SArray_InsertCArrayAssert(...) DN_HardAssert(DN_SArray_InsertCArray(__VA_ARGS__)) -#define DN_SArray_InsertAssert(...) DN_HardAssert(DN_SArray_Insert(__VA_ARGS__)) -template T DN_SArray_PopFront (DN_SArray *array, DN_USize count); -template T DN_SArray_PopBack (DN_SArray *array, DN_USize count); -template DN_ArrayEraseResult DN_SArray_EraseRange (DN_SArray *array, DN_USize begin_index, DN_ISize count, DN_ArrayErase erase); -template void DN_SArray_Clear (DN_SArray *array); -#endif // !defined(DN_NO_SARRAY) - -#if !defined(DN_NO_FARRAY) -#define DN_FArray_ToSArray(array) DN_SArray_InitBuffer((array)->data, DN_ArrayCountU((array)->data)) -template DN_FArray DN_FArray_Init (T const *array, DN_USize count); -#define DN_FArray_HasData(array) ((array).data && (array).size) -template DN_FArray DN_FArray_InitSlice (DN_Slice slice); -template DN_FArray DN_FArray_InitCArray (T const (&items)[K]); -template bool DN_FArray_IsValid (DN_FArray const *array); -template DN_USize DN_FArray_Max (DN_FArray const *) { return N; } -template DN_Slice DN_FArray_Slice (DN_FArray const *array); -template T * DN_FArray_AddArray (DN_FArray *array, T const *items, DN_USize count); -template T * DN_FArray_AddCArray (DN_FArray *array, T const (&items)[K]); -template T * DN_FArray_Add (DN_FArray *array, T const &item); -#define DN_FArray_AddArrayAssert(...) DN_HardAssert(DN_FArray_AddArray(__VA_ARGS__)) -#define DN_FArray_AddCArrayAssert(...) DN_HardAssert(DN_FArray_AddCArray(__VA_ARGS__)) -#define DN_FArray_AddAssert(...) DN_HardAssert(DN_FArray_Add(__VA_ARGS__)) -template T * DN_FArray_MakeArray (DN_FArray *array, DN_USize count, DN_ZMem z_mem); -template T * DN_FArray_Make (DN_FArray *array, DN_ZMem z_mem); -#define DN_FArray_MakeArrayAssert(...) DN_HardAssert(DN_FArray_MakeArray(__VA_ARGS__)) -#define DN_FArray_MakeAssert(...) DN_HardAssert(DN_FArray_Make(__VA_ARGS__)) -template T * DN_FArray_InsertArray (DN_FArray *array, T const &item, DN_USize index); -template T * DN_FArray_InsertCArray (DN_FArray *array, DN_USize index, T const (&items)[K]); -template T * DN_FArray_Insert (DN_FArray *array, DN_USize index, T const &item); -#define DN_FArray_InsertArrayAssert(...) DN_HardAssert(DN_FArray_InsertArray(__VA_ARGS__)) -#define DN_FArray_InsertAssert(...) DN_HardAssert(DN_FArray_Insert(__VA_ARGS__)) -template T DN_FArray_PopFront (DN_FArray *array, DN_USize count); -template T DN_FArray_PopBack (DN_FArray *array, DN_USize count); -template DN_ArrayFindResult DN_FArray_Find (DN_FArray *array, T const &find); -template DN_ArrayEraseResult DN_FArray_EraseRange (DN_FArray *array, DN_USize begin_index, DN_ISize count, DN_ArrayErase erase); -template void DN_FArray_Clear (DN_FArray *array); -#endif // !defined(DN_NO_FARRAY) - -#if !defined(DN_NO_SLICE) -#define DN_TO_SLICE(val) DN_Slice_Init((val)->data, (val)->size) -#define DN_Slice_InitCArray(array) DN_Slice_Init(array, DN_ArrayCountU(array)) -template DN_Slice DN_Slice_Init (T* const data, DN_USize size); -template DN_Slice DN_Slice_InitCArrayCopy (DN_Arena *arena, T const (&array)[N]); -template DN_Slice DN_Slice_Copy (DN_Arena *arena, DN_Slice slice); -template DN_Slice DN_Slice_CopyPtr (DN_Arena *arena, T* const data, DN_USize size); -template DN_Slice DN_Slice_Alloc (DN_Arena *arena, DN_USize size, DN_ZMem z_mem); - DN_Str8 DN_Slice_Str8Render (DN_Arena *arena, DN_Slice array, DN_Str8 separator); - DN_Str8 DN_Slice_Str8RenderSpaceSeparated (DN_Arena *arena, DN_Slice array); - DN_Str16 DN_Slice_Str16Render (DN_Arena *arena, DN_Slice array, DN_Str16 separator); - DN_Str16 DN_Slice_Str16RenderSpaceSeparated(DN_Arena *arena, DN_Slice array); -#endif // !defined(DN_NO_SLICE) - -#if !defined(DN_NO_DSMAP) -template DN_DSMap DN_DSMap_Init (DN_Arena *arena, DN_U32 size, DN_DSMapFlags flags); -template void DN_DSMap_Deinit (DN_DSMap *map, DN_ZMem z_mem); -template bool DN_DSMap_IsValid (DN_DSMap const *map); -template DN_U32 DN_DSMap_Hash (DN_DSMap const *map, DN_DSMapKey key); -template DN_U32 DN_DSMap_HashToSlotIndex (DN_DSMap const *map, DN_DSMapKey key); -template DN_DSMapResult DN_DSMap_Find (DN_DSMap const *map, DN_DSMapKey key); -template DN_DSMapResult DN_DSMap_Make (DN_DSMap *map, DN_DSMapKey key); -template DN_DSMapResult DN_DSMap_Set (DN_DSMap *map, DN_DSMapKey key, T const &value); -template DN_DSMapResult DN_DSMap_FindKeyU64 (DN_DSMap const *map, DN_U64 key); -template DN_DSMapResult DN_DSMap_MakeKeyU64 (DN_DSMap *map, DN_U64 key); -template DN_DSMapResult DN_DSMap_SetKeyU64 (DN_DSMap *map, DN_U64 key, T const &value); -template DN_DSMapResult DN_DSMap_FindKeyStr8 (DN_DSMap const *map, DN_Str8 key); -template DN_DSMapResult DN_DSMap_MakeKeyStr8 (DN_DSMap *map, DN_Str8 key); -template DN_DSMapResult DN_DSMap_SetKeyStr8 (DN_DSMap *map, DN_Str8 key, T const &value); -template bool DN_DSMap_Resize (DN_DSMap *map, DN_U32 size); -template bool DN_DSMap_Erase (DN_DSMap *map, DN_DSMapKey key); -template bool DN_DSMap_EraseKeyU64 (DN_DSMap *map, DN_U64 key); -template bool DN_DSMap_EraseKeyStr8 (DN_DSMap *map, DN_Str8 key); -template DN_DSMapKey DN_DSMap_KeyBuffer (DN_DSMap const *map, void const *data, DN_U32 size); -template DN_DSMapKey DN_DSMap_KeyBufferAsU64NoHash (DN_DSMap const *map, void const *data, DN_U32 size); -template DN_DSMapKey DN_DSMap_KeyU64 (DN_DSMap const *map, DN_U64 u64); -template DN_DSMapKey DN_DSMap_KeyStr8 (DN_DSMap const *map, DN_Str8 string); -#define DN_DSMap_KeyCStr8(map, string) DN_DSMap_KeyBuffer(map, string, sizeof((string))/sizeof((string)[0]) - 1) -DN_API DN_DSMapKey DN_DSMap_KeyU64NoHash (DN_U64 u64); -DN_API bool DN_DSMap_KeyEquals (DN_DSMapKey lhs, DN_DSMapKey rhs); -DN_API bool operator== (DN_DSMapKey lhs, DN_DSMapKey rhs); -#endif // !defined(DN_NO_DSMAP) - -#if !defined(DN_NO_LIST) -template DN_List DN_List_Init (DN_USize chunk_size); -template DN_List DN_List_InitCArray (DN_Arena *arena, DN_USize chunk_size, T const (&array)[N]); -template T * DN_List_At (DN_List *list, DN_USize index, DN_ListChunk **at_chunk); -template void DN_List_Clear (DN_List *list); -template bool DN_List_Iterate (DN_List *list, DN_ListIterator *it, DN_USize start_index); -template T * DN_List_MakeArena (DN_List *list, DN_Arena *arena, DN_USize count); -template T * DN_List_MakePool (DN_List *list, DN_Pool *pool, DN_USize count); -template T * DN_List_AddArena (DN_List *list, DN_Arena *arena, T const &value); -template T * DN_List_AddPool (DN_List *list, DN_Pool *pool, T const &value); -template void DN_List_AddListArena (DN_List *list, DN_Arena *arena, DN_List other); -template void DN_List_AddListArena (DN_List *list, DN_Pool *pool, DN_List other); -template DN_Slice DN_List_ToSliceCopy (DN_List const *list, DN_Arena* arena); -#endif // !defined(DN_NO_LIST) -#endif // !defined(DN_CONTAINER_H) -// DN: Single header generator inlined this file => #include "Base/dn_base_leak.h" -// DN: Single header generator commented out this header => #include "../dn_base_inc.h" - -enum DN_LeakAllocFlag -{ - DN_LeakAllocFlag_Freed = 1 << 0, - DN_LeakAllocFlag_LeakPermitted = 1 << 1, -}; - -struct DN_LeakAlloc -{ - void *ptr; // 8 Pointer to the allocation being tracked - DN_USize size; // 16 Size of the allocation - DN_USize freed_size; // 24 Store the size of the allocation when it is freed - DN_Str8 stack_trace; // 40 Stack trace at the point of allocation - DN_Str8 freed_stack_trace; // 56 Stack trace of where the allocation was freed - DN_U16 flags; // 72 Bit flags from `DN_LeakAllocFlag` -}; - -// NOTE: We aim to keep the allocation record as light as possible as memory tracking can get -// expensive. Enforce that there is no unexpected padding. -DN_StaticAssert(sizeof(DN_LeakAlloc) == 64 || sizeof(DN_LeakAlloc) == 32); // NOTE: 64 bit vs 32 bit pointers respectively - -struct DN_LeakTracker -{ - DN_DSMap alloc_table; - DN_TicketMutex alloc_table_mutex; - DN_Arena alloc_table_arena; - DN_U64 alloc_table_bytes_allocated_for_stack_traces; -}; - -DN_API void DN_LeakTrackAlloc_ (DN_LeakTracker *leak, void *ptr, DN_USize size, bool alloc_can_leak); -DN_API void DN_LeakTrackDealloc_(DN_LeakTracker *leak, void *ptr); -DN_API void DN_LeakDump_ (DN_LeakTracker *leak); - -#if defined(DN_LEAK_TRACKING) -#define DN_LeakTrackAlloc(leak, ptr, size, alloc_can_leak) DN_LeakTrackAlloc_(leak, ptr, size, alloc_can_leak) -#define DN_LeakTrackDealloc(leak, ptr) DN_LeakTrackDealloc_(leak, ptr) -#define DN_LeakDump(leak) DN_LeakDump_(leak) -#else -#define DN_LeakTrackAlloc(leak, ptr, size, alloc_can_leak) do { (void)ptr; (void)size; (void)alloc_can_leak; } while (0) -#define DN_LeakTrackDealloc(leak, ptr) do { (void)ptr; } while (0) -#define DN_LeakDump(leak) do { } while (0) -#endif - - -#endif // !defined(DN_BASE_INC_H) -#if !defined(DN_OS_INC_H) -#define DN_OS_INC_H - -#if defined(DN_PLATFORM_WIN32) - // DN: Single header generator inlined this file => #include "OS/dn_os_windows.h" -#if !defined(DN_OS_WINDOWS_H) -#define DN_OS_WINDOWS_H - -#if defined(_CLANGD) - // DN: Single header generator commented out this header => #include "../dn_base_inc.h" -#endif - -#if defined(DN_COMPILER_MSVC) || defined(DN_COMPILER_CLANG_CL) - #pragma comment(lib, "bcrypt") - #pragma comment(lib, "winhttp") - #pragma comment(lib, "dbghelp") - #pragma comment(lib, "comdlg32") - #pragma comment(lib, "pathcch") - #pragma comment(lib, "Shell32") // ShellExecuteW - #pragma comment(lib, "shlwapi") -#endif - -#if defined(DN_NO_WINDOWS_H_REPLACEMENT_HEADER) || defined(_INC_WINDOWS) - #define WIN32_LEAN_AND_MEAN - #include // LONG - #include // DN_OS_SecureRNGBytes -> BCryptOpenAlgorithmProvider ... etc - #include // DN_Win_MakeProcessDPIAware -> SetProcessDpiAwareProc - #include // PathRelativePathTO - #include // PathCchCanonicalizeEx - #include // WinHttp* - #include // PROCESS_MEMORY_COUNTERS_EX2 - #include // OPENFILENAMEW - #include -#else - DN_MSVC_WARNING_PUSH - DN_MSVC_WARNING_DISABLE(4201) // warning C4201: nonstandard extension used: nameless struct/union - - // NOTE: basetsd.h ///////////////////////////////////////////////////////////////////////////// - typedef unsigned __int64 ULONG_PTR, *PULONG_PTR; - typedef unsigned __int64 UINT_PTR, *PUINT_PTR; - typedef ULONG_PTR SIZE_T, *PSIZE_T; - typedef __int64 LONG_PTR, *PLONG_PTR; - typedef ULONG_PTR DWORD_PTR, *PDWORD_PTR; - typedef unsigned __int64 ULONG64, *PULONG64; - typedef unsigned __int64 DWORD64, *PDWORD64; - - // NOTE: shared/minwindef.h //////////////////////////////////////////////////////////////////// - struct HINSTANCE__ { - int unused; - }; - typedef struct HINSTANCE__ *HINSTANCE; - - typedef unsigned long DWORD; - typedef int BOOL; - typedef int INT; - typedef unsigned long ULONG; - typedef unsigned int UINT; - typedef unsigned short WORD; - typedef unsigned char BYTE; - typedef unsigned char UCHAR; - typedef HINSTANCE HMODULE; /* HMODULEs can be used in place of HINSTANCEs */ - typedef void * HANDLE; - typedef HANDLE HLOCAL; - - typedef unsigned __int64 WPARAM; - typedef LONG_PTR LPARAM; - typedef LONG_PTR LRESULT; - - #define MAX_PATH 260 - - typedef struct _FILETIME { - DWORD dwLowDateTime; - DWORD dwHighDateTime; - } FILETIME, *PFILETIME, *LPFILETIME; - - // NOTE: shared/winerror.h ///////////////////////////////////////////////////////////////////// - // NOTE: GetModuleFileNameW - #define ERROR_INSUFFICIENT_BUFFER 122L // dderror - - // NOTE: um/winnls.h /////////////////////////////////////////////////////////////////////////// - // NOTE: MultiByteToWideChar - #define CP_UTF8 65001 // UTF-8 translation - - // NOTE: um/winnt.h //////////////////////////////////////////////////////////////////////////// - typedef void VOID; - typedef __int64 LONGLONG; - typedef unsigned __int64 ULONGLONG; - typedef void * HANDLE; - typedef char CHAR; - typedef short SHORT; - typedef long LONG; - typedef wchar_t WCHAR; // wc, 16-bit UNICODE character - typedef CHAR * NPSTR, *LPSTR, *PSTR; - typedef WCHAR * NWPSTR, *LPWSTR, *PWSTR; - typedef long HRESULT; - - // NOTE: VirtualAlloc: Allocation Type - #define MEM_RESERVE 0x00002000 - #define MEM_COMMIT 0x00001000 - #define MEM_DECOMMIT 0x00004000 - #define MEM_RELEASE 0x00008000 - - // NOTE: VirtualAlloc: Page Permissions - #define PAGE_NOACCESS 0x01 - #define PAGE_READONLY 0x02 - #define PAGE_READWRITE 0x04 - #define PAGE_GUARD 0x100 - - // NOTE: HeapAlloc - #define HEAP_ZERO_MEMORY 0x00000008 - #define HEAP_NO_SERIALIZE 0x00000001 - #define HEAP_GROWABLE 0x00000002 - #define HEAP_GENERATE_EXCEPTIONS 0x00000004 - #define HEAP_ZERO_MEMORY 0x00000008 - #define HEAP_REALLOC_IN_PLACE_ONLY 0x00000010 - #define HEAP_TAIL_CHECKING_ENABLED 0x00000020 - #define HEAP_FREE_CHECKING_ENABLED 0x00000040 - #define HEAP_DISABLE_COALESCE_ON_FREE 0x00000080 - #define HEAP_CREATE_ALIGN_16 0x00010000 - #define HEAP_CREATE_ENABLE_TRACING 0x00020000 - #define HEAP_CREATE_ENABLE_EXECUTE 0x00040000 - #define HEAP_MAXIMUM_TAG 0x0FFF - #define HEAP_PSEUDO_TAG_FLAG 0x8000 - #define HEAP_TAG_SHIFT 18 - #define HEAP_CREATE_SEGMENT_HEAP 0x00000100 - #define HEAP_CREATE_HARDENED 0x00000200 - - // NOTE: FormatMessageA - #define MAKELANGID(p, s) ((((WORD )(s)) << 10) | (WORD )(p)) - #define LANG_NEUTRAL 0x00 - #define SUBLANG_DEFAULT 0x01 // user default - - // NOTE: CreateFile - #define GENERIC_READ (0x80000000L) - #define GENERIC_WRITE (0x40000000L) - #define GENERIC_EXECUTE (0x20000000L) - #define GENERIC_ALL (0x10000000L) - - #define FILE_APPEND_DATA (0x0004) // file - - // NOTE: CreateFile/FindFirstFile - #define FILE_SHARE_READ 0x00000001 - #define FILE_SHARE_WRITE 0x00000002 - #define FILE_SHARE_DELETE 0x00000004 - - #define FILE_ATTRIBUTE_READONLY 0x00000001 - #define FILE_ATTRIBUTE_HIDDEN 0x00000002 - #define FILE_ATTRIBUTE_SYSTEM 0x00000004 - #define FILE_ATTRIBUTE_DIRECTORY 0x00000010 - #define FILE_ATTRIBUTE_NORMAL 0x00000080 - - // NOTE: STACKFRAME64 - #define IMAGE_FILE_MACHINE_AMD64 0x8664 // AMD64 (K8) - - // NOTE: WaitForSingleObject - #define WAIT_TIMEOUT 258L // dderror - #define STATUS_WAIT_0 ((DWORD )0x00000000L) - #define STATUS_ABANDONED_WAIT_0 ((DWORD )0x00000080L) - - #define S_OK ((HRESULT)0L) - #define S_FALSE ((HRESULT)1L) - - typedef union _ULARGE_INTEGER { - struct { - DWORD LowPart; - DWORD HighPart; - } DUMMYSTRUCTNAME; - struct { - DWORD LowPart; - DWORD HighPart; - } u; - ULONGLONG QuadPart; - } ULARGE_INTEGER; - - typedef union _LARGE_INTEGER { - struct { - DWORD LowPart; - LONG HighPart; - } DUMMYSTRUCTNAME; - struct { - DWORD LowPart; - LONG HighPart; - } u; - LONGLONG QuadPart; - } LARGE_INTEGER; - - typedef struct __declspec(align(16)) _M128A { - ULONGLONG Low; - LONGLONG High; - } M128A, *PM128A; - - typedef struct __declspec(align(16)) _XSAVE_FORMAT { - WORD ControlWord; - WORD StatusWord; - BYTE TagWord; - BYTE Reserved1; - WORD ErrorOpcode; - DWORD ErrorOffset; - WORD ErrorSelector; - WORD Reserved2; - DWORD DataOffset; - WORD DataSelector; - WORD Reserved3; - DWORD MxCsr; - DWORD MxCsr_Mask; - M128A FloatRegisters[8]; - #if defined(_WIN64) - M128A XmmRegisters[16]; - BYTE Reserved4[96]; - #else - M128A XmmRegisters[8]; - BYTE Reserved4[224]; - #endif - } XSAVE_FORMAT, *PXSAVE_FORMAT; - typedef XSAVE_FORMAT XMM_SAVE_AREA32, *PXMM_SAVE_AREA32; - - typedef struct __declspec(align(16)) _CONTEXT { - DWORD64 P1Home; - DWORD64 P2Home; - DWORD64 P3Home; - DWORD64 P4Home; - DWORD64 P5Home; - DWORD64 P6Home; - DWORD ContextFlags; - DWORD MxCsr; - WORD SegCs; - WORD SegDs; - WORD SegEs; - WORD SegFs; - WORD SegGs; - WORD SegSs; - DWORD EFlags; - DWORD64 Dr0; - DWORD64 Dr1; - DWORD64 Dr2; - DWORD64 Dr3; - DWORD64 Dr6; - DWORD64 Dr7; - DWORD64 Rax; - DWORD64 Rcx; - DWORD64 Rdx; - DWORD64 Rbx; - DWORD64 Rsp; - DWORD64 Rbp; - DWORD64 Rsi; - DWORD64 Rdi; - DWORD64 R8; - DWORD64 R9; - DWORD64 R10; - DWORD64 R11; - DWORD64 R12; - DWORD64 R13; - DWORD64 R14; - DWORD64 R15; - DWORD64 Rip; - - union { - XMM_SAVE_AREA32 FltSave; - - struct { - M128A Header[2]; - M128A Legacy[8]; - M128A Xmm0; - M128A Xmm1; - M128A Xmm2; - M128A Xmm3; - M128A Xmm4; - M128A Xmm5; - M128A Xmm6; - M128A Xmm7; - M128A Xmm8; - M128A Xmm9; - M128A Xmm10; - M128A Xmm11; - M128A Xmm12; - M128A Xmm13; - M128A Xmm14; - M128A Xmm15; - } DUMMYSTRUCTNAME; - } DUMMYUNIONNAME; - - M128A VectorRegister[26]; - DWORD64 VectorControl; - DWORD64 DebugControl; - DWORD64 LastBranchToRip; - DWORD64 LastBranchFromRip; - DWORD64 LastExceptionToRip; - DWORD64 LastExceptionFromRip; - } CONTEXT; - - typedef struct _LIST_ENTRY { - struct _LIST_ENTRY *Flink; - struct _LIST_ENTRY *Blink; - } LIST_ENTRY, *PLIST_ENTRY, PRLIST_ENTRY; - - typedef struct _RTL_CRITICAL_SECTION_DEBUG { - WORD Type; - WORD CreatorBackTraceIndex; - struct _RTL_CRITICAL_SECTION *CriticalSection; - LIST_ENTRY ProcessLocksList; - DWORD EntryCount; - DWORD ContentionCount; - DWORD Flags; - WORD CreatorBackTraceIndexHigh; - WORD Identifier; - } RTL_CRITICAL_SECTION_DEBUG, *PRTL_CRITICAL_SECTION_DEBUG, RTL_RESOURCE_DEBUG, *PRTL_RESOURCE_DEBUG; - - typedef struct _RTL_CONDITION_VARIABLE { - VOID *Ptr; - } RTL_CONDITION_VARIABLE, *PRTL_CONDITION_VARIABLE; - - #pragma pack(push, 8) - typedef struct _RTL_CRITICAL_SECTION { - PRTL_CRITICAL_SECTION_DEBUG DebugInfo; - - // - // The following three fields control entering and exiting the critical - // section for the resource - // - - LONG LockCount; - LONG RecursionCount; - HANDLE OwningThread; // from the thread's ClientId->UniqueThread - HANDLE LockSemaphore; - ULONG_PTR SpinCount; // force size on 64-bit systems when packed - } RTL_CRITICAL_SECTION, *PRTL_CRITICAL_SECTION; - #pragma pack(pop) - - typedef struct _MODLOAD_DATA { - DWORD ssize; // size of this struct - DWORD ssig; // signature identifying the passed data - VOID *data; // pointer to passed data - DWORD size; // size of passed data - DWORD flags; // options - } MODLOAD_DATA, *PMODLOAD_DATA; - - #define SLMFLAG_VIRTUAL 0x1 - #define SLMFLAG_ALT_INDEX 0x2 - #define SLMFLAG_NO_SYMBOLS 0x4 - - extern "C" - { - __declspec(dllimport) VOID __stdcall RtlCaptureContext(CONTEXT *ContextRecord); - __declspec(dllimport) HANDLE __stdcall GetCurrentProcess(void); - __declspec(dllimport) HANDLE __stdcall GetCurrentThread(void); - __declspec(dllimport) DWORD __stdcall SymSetOptions(DWORD SymOptions); - __declspec(dllimport) BOOL __stdcall SymInitialize(HANDLE hProcess, const CHAR* UserSearchPath, BOOL fInvadeProcess); - __declspec(dllimport) DWORD64 __stdcall SymLoadModuleEx(HANDLE hProcess, HANDLE hFile, CHAR const *ImageName, CHAR const *ModuleName, DWORD64 BaseOfDll, DWORD DllSize, MODLOAD_DATA *Data, DWORD Flags); - __declspec(dllimport) BOOL __stdcall SymUnloadModule64(HANDLE hProcess, DWORD64 BaseOfDll); - } - - // NOTE: um/heapapi.h //////////////////////////////////////////////////////////////////// - extern "C" - { - __declspec(dllimport) HANDLE __stdcall HeapCreate(DWORD flOptions, SIZE_T dwInitialSize, SIZE_T dwMaximumSize); - __declspec(dllimport) BOOL __stdcall HeapDestroy(HANDLE hHeap); - __declspec(dllimport) VOID * __stdcall HeapAlloc(HANDLE hHeap, DWORD dwFlags,SIZE_T dwBytes); - __declspec(dllimport) VOID * __stdcall HeapReAlloc(HANDLE hHeap, DWORD dwFlags, VOID *lpMem, SIZE_T dwBytes); - __declspec(dllimport) BOOL __stdcall HeapFree(HANDLE hHeap, DWORD dwFlags, VOID *lpMem); - __declspec(dllimport) SIZE_T __stdcall HeapSize(HANDLE hHeap, DWORD dwFlags, VOID const *lpMem); - __declspec(dllimport) HANDLE __stdcall GetProcessHeap(VOID); - __declspec(dllimport) SIZE_T __stdcall HeapCompact(HANDLE hHeap, DWORD dwFlags); - } - - // NOTE: shared/windef.h //////////////////////////////////////////////////////////////////// - typedef struct tagPOINT - { - LONG x; - LONG y; - } POINT, *PPOINT, *NPPOINT, *LPPOINT; - - // NOTE: handleapi.h /////////////////////////////////////////////////////////////////////////// - #define INVALID_HANDLE_VALUE ((HANDLE)(LONG_PTR)-1) - - extern "C" - { - __declspec(dllimport) BOOL __stdcall CloseHandle(HANDLE hObject); - } - - // NOTE: consoleapi.h /////////////////////////////////////////////////////////////////////////// - extern "C" - { - __declspec(dllimport) BOOL __stdcall WriteConsoleA(HANDLE hConsoleOutput, const VOID* lpBuffer, DWORD nNumberOfCharsToWrite, DWORD *lpNumberOfCharsWritten, VOID *lpReserved); - __declspec(dllimport) BOOL __stdcall AllocConsole(VOID); - __declspec(dllimport) BOOL __stdcall FreeConsole(VOID); - __declspec(dllimport) BOOL __stdcall AttachConsole(DWORD dwProcessId); - __declspec(dllimport) BOOL __stdcall GetConsoleMode(HANDLE hConsoleHandle, DWORD *lpMode); - } - - // NOTE: um/minwinbase.h /////////////////////////////////////////////////////////////////////// - // NOTE: FindFirstFile - #define FIND_FIRST_EX_CASE_SENSITIVE 0x00000001 - #define FIND_FIRST_EX_LARGE_FETCH 0x00000002 - - // NOTE: WaitFor.. - #define WAIT_FAILED ((DWORD)0xFFFFFFFF) - #define WAIT_OBJECT_0 ((STATUS_WAIT_0 ) + 0 ) - #define WAIT_ABANDONED ((STATUS_ABANDONED_WAIT_0 ) + 0 ) - #define WAIT_ABANDONED_0 ((STATUS_ABANDONED_WAIT_0 ) + 0 ) - - // NOTE: CreateProcessW - #define CREATE_UNICODE_ENVIRONMENT 0x00000400 - #define CREATE_NO_WINDOW 0x08000000 - - typedef enum _GET_FILEEX_INFO_LEVELS { - GetFileExInfoStandard, - GetFileExMaxInfoLevel - } GET_FILEEX_INFO_LEVELS; - - typedef struct _SECURITY_ATTRIBUTES { - DWORD nLength; - VOID *lpSecurityDescriptor; - BOOL bInheritHandle; - } SECURITY_ATTRIBUTES, *PSECURITY_ATTRIBUTES, *LPSECURITY_ATTRIBUTES; - - typedef enum _FINDEX_INFO_LEVELS { - FindExInfoStandard, - FindExInfoBasic, - FindExInfoMaxInfoLevel - } FINDEX_INFO_LEVELS; - - typedef enum _FINDEX_SEARCH_OPS { - FindExSearchNameMatch, - FindExSearchLimitToDirectories, - FindExSearchLimitToDevices, - FindExSearchMaxSearchOp - } FINDEX_SEARCH_OPS; - - typedef struct _WIN32_FIND_DATAW { - DWORD dwFileAttributes; - FILETIME ftCreationTime; - FILETIME ftLastAccessTime; - FILETIME ftLastWriteTime; - DWORD nFileSizeHigh; - DWORD nFileSizeLow; - DWORD dwReserved0; - DWORD dwReserved1; - WCHAR cFileName[ MAX_PATH ]; - WCHAR cAlternateFileName[ 14 ]; - #ifdef _MAC - DWORD dwFileType; - DWORD dwCreatorType; - WORD wFinderFlags; - #endif - } WIN32_FIND_DATAW, *PWIN32_FIND_DATAW, *LPWIN32_FIND_DATAW; - - typedef struct _SYSTEMTIME { - WORD wYear; - WORD wMonth; - WORD wDayOfWeek; - WORD wDay; - WORD wHour; - WORD wMinute; - WORD wSecond; - WORD wMilliseconds; - } SYSTEMTIME, *PSYSTEMTIME, *LPSYSTEMTIME; - - typedef struct _OVERLAPPED { - ULONG_PTR Internal; - ULONG_PTR InternalHigh; - union { - struct { - DWORD Offset; - DWORD OffsetHigh; - } DUMMYSTRUCTNAME; - VOID *Pointer; - } DUMMYUNIONNAME; - - HANDLE hEvent; - } OVERLAPPED, *LPOVERLAPPED; - - typedef RTL_CRITICAL_SECTION CRITICAL_SECTION; - - #define WAIT_FAILED ((DWORD)0xFFFFFFFF) - #define WAIT_OBJECT_0 ((STATUS_WAIT_0 ) + 0 ) - - #define INFINITE 0xFFFFFFFF // Wait/Synchronisation: Infinite timeout - - #define STD_INPUT_HANDLE ((DWORD)-10) - #define STD_OUTPUT_HANDLE ((DWORD)-11) - #define STD_ERROR_HANDLE ((DWORD)-12) - - #define HANDLE_FLAG_INHERIT 0x00000001 - #define HANDLE_FLAG_PROTECT_FROM_CLOSE 0x00000002 - - // NOTE: MoveFile - #define MOVEFILE_REPLACE_EXISTING 0x00000001 - #define MOVEFILE_COPY_ALLOWED 0x00000002 - - // NOTE: FormatMessageA - #define FORMAT_MESSAGE_ALLOCATE_BUFFER 0x00000100 - #define FORMAT_MESSAGE_IGNORE_INSERTS 0x00000200 - #define FORMAT_MESSAGE_FROM_HMODULE 0x00000800 - #define FORMAT_MESSAGE_FROM_SYSTEM 0x00001000 - - // NOTE: CreateProcessW - #define STARTF_USESTDHANDLES 0x00000100 - - extern "C" - { - __declspec(dllimport) BOOL __stdcall MoveFileExW (const WCHAR *lpExistingFileName, const WCHAR *lpNewFileName, DWORD dwFlags); - __declspec(dllimport) BOOL __stdcall CopyFileW (const WCHAR *lpExistingFileName, const WCHAR *lpNewFileName, BOOL bFailIfExists); - __declspec(dllimport) HANDLE __stdcall CreateSemaphoreA(SECURITY_ATTRIBUTES *lpSemaphoreAttributes, LONG lInitialCount, LONG lMaximumCount, const CHAR *lpName); - __declspec(dllimport) DWORD __stdcall FormatMessageW (DWORD dwFlags, VOID const *lpSource, DWORD dwMessageId, DWORD dwLanguageId, LPWSTR lpBuffer, DWORD nSize, va_list *Arguments); - __declspec(dllimport) HLOCAL __stdcall LocalFree (HLOCAL hMem); - } - - // NOTE: um/stringapiset.h ///////////////////////////////////////////////////////////////////// - extern "C" - { - __declspec(dllimport) int __stdcall MultiByteToWideChar(UINT CodePage, DWORD dwFlags, const CHAR *lpMultiByteStr, int cbMultiByte, WCHAR *lpWideCharStr, int cchWideChar); - __declspec(dllimport) int __stdcall WideCharToMultiByte(UINT CodePage, DWORD dwFlags, const WCHAR *lpWideCharStr, int cchWideChar, LPSTR lpMultiByteStr, int cbMultiByte, const CHAR *lpDefaultChar, BOOL *lpUsedDefaultChar); - } - - // NOTE: um/fileapi.h ////////////////////////////////////////////////////////////////////////// - #define INVALID_FILE_SIZE ((DWORD)0xFFFFFFFF) - #define INVALID_FILE_ATTRIBUTES ((DWORD)-1) - - // NOTE: CreateFile - #define CREATE_NEW 1 - #define CREATE_ALWAYS 2 - #define OPEN_EXISTING 3 - #define OPEN_ALWAYS 4 - #define TRUNCATE_EXISTING 5 - - typedef struct _WIN32_FILE_ATTRIBUTE_DATA { - DWORD dwFileAttributes; - FILETIME ftCreationTime; - FILETIME ftLastAccessTime; - FILETIME ftLastWriteTime; - DWORD nFileSizeHigh; - DWORD nFileSizeLow; - } WIN32_FILE_ATTRIBUTE_DATA, *LPWIN32_FILE_ATTRIBUTE_DATA; - - extern "C" - { - __declspec(dllimport) BOOL __stdcall FlushFileBuffers (HANDLE hFile); - __declspec(dllimport) BOOL __stdcall CreateDirectoryW (const WCHAR *lpPathName, SECURITY_ATTRIBUTES *lpSecurityAttributes); - __declspec(dllimport) BOOL __stdcall RemoveDirectoryW (const WCHAR *lpPathName); - __declspec(dllimport) BOOL __stdcall FindNextFileW (HANDLE hFindFile, WIN32_FIND_DATAW *lpFindFileData); - __declspec(dllimport) BOOL __stdcall FindClose (HANDLE hFindFile); - __declspec(dllimport) BOOL __stdcall FileTimeToLocalFileTime(const FILETIME *lpFileTime, FILETIME *lpLocalFileTime); - - __declspec(dllimport) HANDLE __stdcall FindFirstFileExW (const WCHAR *lpFileName, FINDEX_INFO_LEVELS fInfoLevelId, VOID *lpFindFileData, FINDEX_SEARCH_OPS fSearchOp, VOID *lpSearchFilter, DWORD dwAdditionalFlags); - __declspec(dllimport) BOOL __stdcall GetFileAttributesExW (const WCHAR *lpFileName, GET_FILEEX_INFO_LEVELS fInfoLevelId, VOID *lpFileInformation); - __declspec(dllimport) BOOL __stdcall GetFileSizeEx (HANDLE hFile, LARGE_INTEGER *lpFileSize); - __declspec(dllimport) BOOL __stdcall DeleteFileW (const WCHAR *lpFileName); - __declspec(dllimport) HANDLE __stdcall CreateFileW (const WCHAR *lpFileName, DWORD dwDesiredAccess, DWORD dwShareMode, SECURITY_ATTRIBUTES *lpSecurityAttributes, DWORD dwCreationDisposition, DWORD dwFlagsAndAttributes, HANDLE hTemplateFile); - __declspec(dllimport) BOOL __stdcall ReadFile (HANDLE hFile, VOID *lpBuffer, DWORD nNumberOfBytesToRead, DWORD *lpNumberOfBytesRead, OVERLAPPED *lpOverlapped); - __declspec(dllimport) BOOL __stdcall WriteFile (HANDLE hFile, const VOID *lpBuffer, DWORD nNumberOfBytesToWrite, DWORD *lpNumberOfBytesWritten, OVERLAPPED *lpOverlapped); - __declspec(dllimport) BOOL __stdcall GetDiskFreeSpaceExW (WCHAR const *lpDirectoryName, ULARGE_INTEGER *lpFreeBytesAvailableToCaller, ULARGE_INTEGER *lpTotalNumberOfBytes, ULARGE_INTEGER *lpTotalNumberOfFreeBytes); - } - - // NOTE: um/processenv.h /////////////////////////////////////////////////////////////////////// - extern "C" - { - __declspec(dllimport) DWORD __stdcall GetCurrentDirectoryW (DWORD nBufferLength, WCHAR *lpBuffer); - __declspec(dllimport) HANDLE __stdcall GetStdHandle (DWORD nStdHandle); - __declspec(dllimport) WCHAR* __stdcall GetEnvironmentStringsW (); - __declspec(dllimport) BOOL __stdcall FreeEnvironmentStringsW(WCHAR *penv); - __declspec(dllimport) DWORD __stdcall GetEnvironmentVariableW(WCHAR const *lpName, WCHAR *lpBuffer, DWORD nSize); - __declspec(dllimport) BOOL __stdcall SetEnvironmentVariableW(WCHAR const *lpName, WCHAR const *lpValue); - } - - // NOTE: um/psapi.h //////////////////////////////////////////////////////////////////////////// - typedef struct _PROCESS_MEMORY_COUNTERS { - 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; - } PROCESS_MEMORY_COUNTERS; - typedef PROCESS_MEMORY_COUNTERS *PPROCESS_MEMORY_COUNTERS; - - extern "C" - { - __declspec(dllimport) BOOL __stdcall GetProcessMemoryInfo(HANDLE Process, PPROCESS_MEMORY_COUNTERS ppsmemCounters, DWORD cb); - } - - // NOTE: um/sysinfoapi.h /////////////////////////////////////////////////////////////////////// - typedef struct _SYSTEM_INFO { - union { - DWORD dwOemId; // Obsolete field...do not use - struct { - WORD wProcessorArchitecture; - WORD wReserved; - } DUMMYSTRUCTNAME; - } DUMMYUNIONNAME; - DWORD dwPageSize; - VOID *lpMinimumApplicationAddress; - VOID *lpMaximumApplicationAddress; - DWORD_PTR dwActiveProcessorMask; - DWORD dwNumberOfProcessors; - DWORD dwProcessorType; - DWORD dwAllocationGranularity; - WORD wProcessorLevel; - WORD wProcessorRevision; - } SYSTEM_INFO, *LPSYSTEM_INFO; - - extern "C" - { - __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); - } - - // NOTE: um/timezoneapi.h ////////////////////////////////////////////////////////////////////// - typedef struct _TIME_ZONE_INFORMATION { - LONG Bias; - WCHAR StandardName[32]; - SYSTEMTIME StandardDate; - LONG StandardBias; - WCHAR DaylightName[32]; - SYSTEMTIME DaylightDate; - LONG DaylightBias; - } TIME_ZONE_INFORMATION, *PTIME_ZONE_INFORMATION, *LPTIME_ZONE_INFORMATION; - - extern "C" - { - __declspec(dllimport) BOOL __stdcall FileTimeToSystemTime (const FILETIME* lpFileTime, SYSTEMTIME *lpSystemTime); - __declspec(dllimport) BOOL __stdcall SystemTimeToFileTime (const SYSTEMTIME* lpSystemTime, FILETIME *lpFileTime); - __declspec(dllimport) BOOL __stdcall TzSpecificLocalTimeToSystemTime(const TIME_ZONE_INFORMATION* lpTimeZoneInformation, const SYSTEMTIME* lpLocalTime, const LPSYSTEMTIME lpUniversalTime); - } - - // NOTE: shared/windef.h /////////////////////////////////////////////////////////////////////// - typedef struct tagRECT { - LONG left; - LONG top; - LONG right; - LONG bottom; - } RECT; - - struct HWND__ { - int unused; - }; - typedef struct HWND__ *HWND; - - struct DPI_AWARENESS_CONTEXT__ { - int unused; - }; - typedef struct DPI_AWARENESS_CONTEXT__ *DPI_AWARENESS_CONTEXT; - - typedef enum DPI_AWARENESS { - DPI_AWARENESS_INVALID = -1, - DPI_AWARENESS_UNAWARE = 0, - DPI_AWARENESS_SYSTEM_AWARE = 1, - DPI_AWARENESS_PER_MONITOR_AWARE = 2 - } DPI_AWARENESS; - - #define DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2 ((DPI_AWARENESS_CONTEXT)-4) - - // NOTE: um/winuser.h ////////////////////////////////////////////////////////////////////////// - typedef struct tagWINDOWPLACEMENT { - UINT length; - UINT flags; - UINT showCmd; - POINT ptMinPosition; - POINT ptMaxPosition; - RECT rcNormalPosition; - #ifdef _MAC - RECT rcDevice; - #endif - } WINDOWPLACEMENT; - typedef WINDOWPLACEMENT *PWINDOWPLACEMENT, *LPWINDOWPLACEMENT; - - #define SW_HIDE 0 - #define SW_NORMAL 1 - #define SW_MAXIMIZE 3 - #define SW_SHOWNOACTIVATE 4 - #define SW_SHOW 5 - #define SW_FORCEMINIMIZE 11 - - extern "C" - { - __declspec(dllimport) BOOL __stdcall GetWindowRect (HWND hWnd, RECT *lpRect); - __declspec(dllimport) BOOL __stdcall SetWindowPos (HWND hWnd, HWND hWndInsertAfter, int X, int Y, int cx, int cy, UINT uFlags); - __declspec(dllimport) UINT __stdcall GetWindowModuleFileNameA(HWND hwnd, LPSTR pszFileName, UINT cchFileNameMax); - __declspec(dllimport) BOOL __stdcall ShowWindow (HWND hWnd, int nCmdShow); - __declspec(dllimport) BOOL __stdcall GetWindowPlacement (HWND hWnd, WINDOWPLACEMENT *lpwndpl); - - } - - // NOTE: um/wininet.h ////////////////////////////////////////////////////////////////////////// - typedef WORD INTERNET_PORT; - typedef VOID *HINTERNET; - - // NOTE: um/winhttp.h ////////////////////////////////////////////////////////////////////////// - #define WINHTTP_ACCESS_TYPE_DEFAULT_PROXY 0 - #define WINHTTP_ACCESS_TYPE_NO_PROXY 1 - #define WINHTTP_ACCESS_TYPE_NAMED_PROXY 3 - #define WINHTTP_ACCESS_TYPE_AUTOMATIC_PROXY 4 - - #define INTERNET_DEFAULT_PORT 0 // use the protocol-specific default - #define INTERNET_DEFAULT_HTTP_PORT 80 // " " HTTP " - #define INTERNET_DEFAULT_HTTPS_PORT 443 // " " HTTPS " - - // NOTE: WinHttpOpen - #define WINHTTP_FLAG_ASYNC 0x10000000 // this session is asynchronous (where supported) - #define WINHTTP_FLAG_SECURE_DEFAULTS 0x30000000 // note that this flag also forces async - - // NOTE: WinHttpOpenRequest - #define WINHTTP_FLAG_SECURE 0x00800000 // use SSL if applicable (HTTPS) - #define WINHTTP_FLAG_ESCAPE_PERCENT 0x00000004 // if escaping enabled, escape percent as well - #define WINHTTP_FLAG_NULL_CODEPAGE 0x00000008 // assume all symbols are ASCII, use fast convertion - #define WINHTTP_FLAG_ESCAPE_DISABLE 0x00000040 // disable escaping - #define WINHTTP_FLAG_ESCAPE_DISABLE_QUERY 0x00000080 // if escaping enabled escape path part, but do not escape query - #define WINHTTP_FLAG_BYPASS_PROXY_CACHE 0x00000100 // add "pragma: no-cache" request header - #define WINHTTP_FLAG_REFRESH WINHTTP_FLAG_BYPASS_PROXY_CACHE - #define WINHTTP_FLAG_AUTOMATIC_CHUNKING 0x00000200 // Send request without content-length header or chunked TE - - #define WINHTTP_NO_PROXY_NAME NULL - #define WINHTTP_NO_PROXY_BYPASS NULL - - // - // WINHTTP_QUERY_FLAG_NUMBER - if this bit is set in the dwInfoLevel parameter of - // HttpQueryHeader(), then the value of the header will be converted to a number - // before being returned to the caller, if applicable - // - #define WINHTTP_QUERY_FLAG_NUMBER 0x20000000 - - #define WINHTTP_QUERY_MIME_VERSION 0 - #define WINHTTP_QUERY_CONTENT_TYPE 1 - #define WINHTTP_QUERY_CONTENT_TRANSFER_ENCODING 2 - #define WINHTTP_QUERY_CONTENT_ID 3 - #define WINHTTP_QUERY_CONTENT_DESCRIPTION 4 - #define WINHTTP_QUERY_CONTENT_LENGTH 5 - #define WINHTTP_QUERY_CONTENT_LANGUAGE 6 - #define WINHTTP_QUERY_ALLOW 7 - #define WINHTTP_QUERY_PUBLIC 8 - #define WINHTTP_QUERY_DATE 9 - #define WINHTTP_QUERY_EXPIRES 10 - #define WINHTTP_QUERY_LAST_MODIFIED 11 - #define WINHTTP_QUERY_MESSAGE_ID 12 - #define WINHTTP_QUERY_URI 13 - #define WINHTTP_QUERY_DERIVED_FROM 14 - #define WINHTTP_QUERY_COST 15 - #define WINHTTP_QUERY_LINK 16 - #define WINHTTP_QUERY_PRAGMA 17 - #define WINHTTP_QUERY_VERSION 18 // special: part of status line - #define WINHTTP_QUERY_STATUS_CODE 19 // special: part of status line - #define WINHTTP_QUERY_STATUS_TEXT 20 // special: part of status line - #define WINHTTP_QUERY_RAW_HEADERS 21 // special: all headers as ASCIIZ - #define WINHTTP_QUERY_RAW_HEADERS_CRLF 22 // special: all headers - #define WINHTTP_QUERY_CONNECTION 23 - #define WINHTTP_QUERY_ACCEPT 24 - #define WINHTTP_QUERY_ACCEPT_CHARSET 25 - #define WINHTTP_QUERY_ACCEPT_ENCODING 26 - #define WINHTTP_QUERY_ACCEPT_LANGUAGE 27 - #define WINHTTP_QUERY_AUTHORIZATION 28 - #define WINHTTP_QUERY_CONTENT_ENCODING 29 - #define WINHTTP_QUERY_FORWARDED 30 - #define WINHTTP_QUERY_FROM 31 - #define WINHTTP_QUERY_IF_MODIFIED_SINCE 32 - #define WINHTTP_QUERY_LOCATION 33 - #define WINHTTP_QUERY_ORIG_URI 34 - #define WINHTTP_QUERY_REFERER 35 - #define WINHTTP_QUERY_RETRY_AFTER 36 - #define WINHTTP_QUERY_SERVER 37 - #define WINHTTP_QUERY_TITLE 38 - #define WINHTTP_QUERY_USER_AGENT 39 - #define WINHTTP_QUERY_WWW_AUTHENTICATE 40 - #define WINHTTP_QUERY_PROXY_AUTHENTICATE 41 - #define WINHTTP_QUERY_ACCEPT_RANGES 42 - #define WINHTTP_QUERY_SET_COOKIE 43 - #define WINHTTP_QUERY_COOKIE 44 - #define WINHTTP_QUERY_REQUEST_METHOD 45 // special: GET/POST etc. - #define WINHTTP_QUERY_REFRESH 46 - #define WINHTTP_QUERY_CONTENT_DISPOSITION 47 - - // NOTE: WinHttpQueryHeaders prettifiers for optional parameters. - #define WINHTTP_HEADER_NAME_BY_INDEX NULL - #define WINHTTP_NO_OUTPUT_BUFFER NULL - #define WINHTTP_NO_HEADER_INDEX NULL - - // NOTE: Http Response Status Codes - #define HTTP_STATUS_CONTINUE 100 // OK to continue with request - #define HTTP_STATUS_SWITCH_PROTOCOLS 101 // server has switched protocols in upgrade header - - #define HTTP_STATUS_OK 200 // request completed - #define HTTP_STATUS_CREATED 201 // object created, reason = new URI - #define HTTP_STATUS_ACCEPTED 202 // async completion (TBS) - #define HTTP_STATUS_PARTIAL 203 // partial completion - #define HTTP_STATUS_NO_CONTENT 204 // no info to return - #define HTTP_STATUS_RESET_CONTENT 205 // request completed, but clear form - #define HTTP_STATUS_PARTIAL_CONTENT 206 // partial GET fulfilled - #define HTTP_STATUS_WEBDAV_MULTI_STATUS 207 // WebDAV Multi-Status - - #define HTTP_STATUS_AMBIGUOUS 300 // server couldn't decide what to return - #define HTTP_STATUS_MOVED 301 // object permanently moved - #define HTTP_STATUS_REDIRECT 302 // object temporarily moved - #define HTTP_STATUS_REDIRECT_METHOD 303 // redirection w/ new access method - #define HTTP_STATUS_NOT_MODIFIED 304 // if-modified-since was not modified - #define HTTP_STATUS_USE_PROXY 305 // redirection to proxy, location header specifies proxy to use - #define HTTP_STATUS_REDIRECT_KEEP_VERB 307 // HTTP/1.1: keep same verb - #define HTTP_STATUS_PERMANENT_REDIRECT 308 // Object permanently moved keep verb - - #define HTTP_STATUS_BAD_REQUEST 400 // invalid syntax - #define HTTP_STATUS_DENIED 401 // access denied - #define HTTP_STATUS_PAYMENT_REQ 402 // payment required - #define HTTP_STATUS_FORBIDDEN 403 // request forbidden - #define HTTP_STATUS_NOT_FOUND 404 // object not found - #define HTTP_STATUS_BAD_METHOD 405 // method is not allowed - #define HTTP_STATUS_NONE_ACCEPTABLE 406 // no response acceptable to client found - #define HTTP_STATUS_PROXY_AUTH_REQ 407 // proxy authentication required - #define HTTP_STATUS_REQUEST_TIMEOUT 408 // server timed out waiting for request - #define HTTP_STATUS_CONFLICT 409 // user should resubmit with more info - #define HTTP_STATUS_GONE 410 // the resource is no longer available - #define HTTP_STATUS_LENGTH_REQUIRED 411 // the server refused to accept request w/o a length - #define HTTP_STATUS_PRECOND_FAILED 412 // precondition given in request failed - #define HTTP_STATUS_REQUEST_TOO_LARGE 413 // request entity was too large - #define HTTP_STATUS_URI_TOO_LONG 414 // request URI too long - #define HTTP_STATUS_UNSUPPORTED_MEDIA 415 // unsupported media type - #define HTTP_STATUS_RETRY_WITH 449 // retry after doing the appropriate action. - - #define HTTP_STATUS_SERVER_ERROR 500 // internal server error - #define HTTP_STATUS_NOT_SUPPORTED 501 // required not supported - #define HTTP_STATUS_BAD_GATEWAY 502 // error response received from gateway - #define HTTP_STATUS_SERVICE_UNAVAIL 503 // temporarily overloaded - #define HTTP_STATUS_GATEWAY_TIMEOUT 504 // timed out waiting for gateway - #define HTTP_STATUS_VERSION_NOT_SUP 505 // HTTP version not supported - - #define HTTP_STATUS_FIRST HTTP_STATUS_CONTINUE - #define HTTP_STATUS_LAST HTTP_STATUS_VERSION_NOT_SUP - - #define WINHTTP_CALLBACK_STATUS_RESOLVING_NAME 0x00000001 - #define WINHTTP_CALLBACK_STATUS_NAME_RESOLVED 0x00000002 - #define WINHTTP_CALLBACK_STATUS_CONNECTING_TO_SERVER 0x00000004 - #define WINHTTP_CALLBACK_STATUS_CONNECTED_TO_SERVER 0x00000008 - #define WINHTTP_CALLBACK_STATUS_SENDING_REQUEST 0x00000010 - #define WINHTTP_CALLBACK_STATUS_REQUEST_SENT 0x00000020 - #define WINHTTP_CALLBACK_STATUS_RECEIVING_RESPONSE 0x00000040 - #define WINHTTP_CALLBACK_STATUS_RESPONSE_RECEIVED 0x00000080 - #define WINHTTP_CALLBACK_STATUS_CLOSING_CONNECTION 0x00000100 - #define WINHTTP_CALLBACK_STATUS_CONNECTION_CLOSED 0x00000200 - #define WINHTTP_CALLBACK_STATUS_HANDLE_CREATED 0x00000400 - #define WINHTTP_CALLBACK_STATUS_HANDLE_CLOSING 0x00000800 - #define WINHTTP_CALLBACK_STATUS_DETECTING_PROXY 0x00001000 - #define WINHTTP_CALLBACK_STATUS_REDIRECT 0x00004000 - #define WINHTTP_CALLBACK_STATUS_INTERMEDIATE_RESPONSE 0x00008000 - #define WINHTTP_CALLBACK_STATUS_SECURE_FAILURE 0x00010000 - #define WINHTTP_CALLBACK_STATUS_HEADERS_AVAILABLE 0x00020000 - #define WINHTTP_CALLBACK_STATUS_DATA_AVAILABLE 0x00040000 - #define WINHTTP_CALLBACK_STATUS_READ_COMPLETE 0x00080000 - #define WINHTTP_CALLBACK_STATUS_WRITE_COMPLETE 0x00100000 - #define WINHTTP_CALLBACK_STATUS_REQUEST_ERROR 0x00200000 - #define WINHTTP_CALLBACK_STATUS_SENDREQUEST_COMPLETE 0x00400000 - - #define WINHTTP_CALLBACK_STATUS_GETPROXYFORURL_COMPLETE 0x01000000 - #define WINHTTP_CALLBACK_STATUS_CLOSE_COMPLETE 0x02000000 - #define WINHTTP_CALLBACK_STATUS_SHUTDOWN_COMPLETE 0x04000000 - #define WINHTTP_CALLBACK_STATUS_SETTINGS_WRITE_COMPLETE 0x10000000 - #define WINHTTP_CALLBACK_STATUS_SETTINGS_READ_COMPLETE 0x20000000 - - #define WINHTTP_CALLBACK_FLAG_RESOLVE_NAME (WINHTTP_CALLBACK_STATUS_RESOLVING_NAME | WINHTTP_CALLBACK_STATUS_NAME_RESOLVED) - #define WINHTTP_CALLBACK_FLAG_CONNECT_TO_SERVER (WINHTTP_CALLBACK_STATUS_CONNECTING_TO_SERVER | WINHTTP_CALLBACK_STATUS_CONNECTED_TO_SERVER) - #define WINHTTP_CALLBACK_FLAG_SEND_REQUEST (WINHTTP_CALLBACK_STATUS_SENDING_REQUEST | WINHTTP_CALLBACK_STATUS_REQUEST_SENT) - #define WINHTTP_CALLBACK_FLAG_RECEIVE_RESPONSE (WINHTTP_CALLBACK_STATUS_RECEIVING_RESPONSE | WINHTTP_CALLBACK_STATUS_RESPONSE_RECEIVED) - #define WINHTTP_CALLBACK_FLAG_CLOSE_CONNECTION (WINHTTP_CALLBACK_STATUS_CLOSING_CONNECTION | WINHTTP_CALLBACK_STATUS_CONNECTION_CLOSED) - #define WINHTTP_CALLBACK_FLAG_HANDLES (WINHTTP_CALLBACK_STATUS_HANDLE_CREATED | WINHTTP_CALLBACK_STATUS_HANDLE_CLOSING) - #define WINHTTP_CALLBACK_FLAG_DETECTING_PROXY WINHTTP_CALLBACK_STATUS_DETECTING_PROXY - #define WINHTTP_CALLBACK_FLAG_REDIRECT WINHTTP_CALLBACK_STATUS_REDIRECT - #define WINHTTP_CALLBACK_FLAG_INTERMEDIATE_RESPONSE WINHTTP_CALLBACK_STATUS_INTERMEDIATE_RESPONSE - #define WINHTTP_CALLBACK_FLAG_SECURE_FAILURE WINHTTP_CALLBACK_STATUS_SECURE_FAILURE - #define WINHTTP_CALLBACK_FLAG_SENDREQUEST_COMPLETE WINHTTP_CALLBACK_STATUS_SENDREQUEST_COMPLETE - #define WINHTTP_CALLBACK_FLAG_HEADERS_AVAILABLE WINHTTP_CALLBACK_STATUS_HEADERS_AVAILABLE - #define WINHTTP_CALLBACK_FLAG_DATA_AVAILABLE WINHTTP_CALLBACK_STATUS_DATA_AVAILABLE - #define WINHTTP_CALLBACK_FLAG_READ_COMPLETE WINHTTP_CALLBACK_STATUS_READ_COMPLETE - #define WINHTTP_CALLBACK_FLAG_WRITE_COMPLETE WINHTTP_CALLBACK_STATUS_WRITE_COMPLETE - #define WINHTTP_CALLBACK_FLAG_REQUEST_ERROR WINHTTP_CALLBACK_STATUS_REQUEST_ERROR - - #define WINHTTP_CALLBACK_FLAG_GETPROXYFORURL_COMPLETE WINHTTP_CALLBACK_STATUS_GETPROXYFORURL_COMPLETE - - #define WINHTTP_CALLBACK_FLAG_ALL_COMPLETIONS (WINHTTP_CALLBACK_STATUS_SENDREQUEST_COMPLETE \ - | WINHTTP_CALLBACK_STATUS_HEADERS_AVAILABLE \ - | WINHTTP_CALLBACK_STATUS_DATA_AVAILABLE \ - | WINHTTP_CALLBACK_STATUS_READ_COMPLETE \ - | WINHTTP_CALLBACK_STATUS_WRITE_COMPLETE \ - | WINHTTP_CALLBACK_STATUS_REQUEST_ERROR \ - | WINHTTP_CALLBACK_STATUS_GETPROXYFORURL_COMPLETE) - - #define WINHTTP_CALLBACK_FLAG_ALL_NOTIFICATIONS 0xffffffff - #define WINHTTP_INVALID_STATUS_CALLBACK ((WINHTTP_STATUS_CALLBACK)(-1L)) - - typedef struct _WINHTTP_EXTENDED_HEADER - { - union - { - CHAR const *pwszName; - WCHAR const *pszName; - }; - union - { - WCHAR const *pwszValue; - CHAR const *pszValue; - }; - } WINHTTP_EXTENDED_HEADER, *PWINHTTP_EXTENDED_HEADER; - - typedef struct _WINHTTP_ASYNC_RESULT - { - DWORD *dwResult; // indicates which async API has encountered an error - DWORD dwError; // the error code if the API failed - } WINHTTP_ASYNC_RESULT, *LPWINHTTP_ASYNC_RESULT, *PWINHTTP_ASYNC_RESULT; - - typedef - VOID - (*WINHTTP_STATUS_CALLBACK)( - HINTERNET hInternet, - DWORD *dwContext, - DWORD dwInternetStatus, - VOID *lpvStatusInformation, - DWORD dwStatusInformationLength - ); - - extern "C" - { - __declspec(dllimport) HINTERNET __stdcall WinHttpOpen(WCHAR const *pszAgentW, DWORD dwAccessType, WCHAR const *pszProxyW, WCHAR const *pszProxyBypassW, DWORD dwFlags); - __declspec(dllimport) BOOL __stdcall WinHttpCloseHandle(HINTERNET hInternet); - __declspec(dllimport) HINTERNET __stdcall WinHttpConnect(HINTERNET hSession, WCHAR const *pswzServerName, INTERNET_PORT nServerPort, DWORD dwReserved); - __declspec(dllimport) BOOL __stdcall WinHttpReadData(HINTERNET hRequest, VOID *lpBuffer, DWORD dwNumberOfBytesToRead, DWORD *lpdwNumberOfBytesRead); - __declspec(dllimport) HINTERNET __stdcall WinHttpOpenRequest(HINTERNET hConnect, WCHAR const *pwszVerb, WCHAR const *pwszObjectName, WCHAR const *pwszVersion, WCHAR const *pwszReferrer, WCHAR const *ppwszAcceptTypes, DWORD dwFlags); - __declspec(dllimport) BOOL __stdcall WinHttpSendRequest(HINTERNET hRequest, WCHAR const *lpszHeaders, DWORD dwHeadersLength, VOID *lpOptional, DWORD dwOptionalLength, DWORD dwTotalLength, DWORD_PTR dwContext); - __declspec(dllimport) DWORD __stdcall WinHttpAddRequestHeadersEx(HINTERNET hRequest, DWORD dwModifiers, ULONGLONG ullFlags, ULONGLONG ullExtra, DWORD cHeaders, WINHTTP_EXTENDED_HEADER *pHeaders); - __declspec(dllimport) BOOL __stdcall WinHttpSetCredentials(HINTERNET hRequest, // HINTERNET handle returned by WinHttpOpenRequest. - DWORD AuthTargets, // Only WINHTTP_AUTH_TARGET_SERVER and WINHTTP_AUTH_TARGET_PROXY are supported in this version and they are mutually exclusive - DWORD AuthScheme, // must be one of the supported Auth Schemes returned from WinHttpQueryAuthSchemes() - WCHAR * pwszUserName, // 1) NULL if default creds is to be used, in which case pszPassword will be ignored - WCHAR * pwszPassword, // 1) "" == Blank Password; 2)Parameter ignored if pszUserName is NULL; 3) Invalid to pass in NULL if pszUserName is not NULL - VOID * pAuthParams); - __declspec(dllimport) BOOL __stdcall WinHttpQueryHeaders(HINTERNET hRequest, DWORD dwInfoLevel, WCHAR const *pwszName, VOID *lpBuffer, DWORD *lpdwBufferLength, DWORD *lpdwIndex); - __declspec(dllimport) BOOL __stdcall WinHttpReceiveResponse(HINTERNET hRequest, VOID *lpReserved); - __declspec(dllimport) WINHTTP_STATUS_CALLBACK __stdcall WinHttpSetStatusCallback(HINTERNET hInternet, WINHTTP_STATUS_CALLBACK lpfnInternetCallback, DWORD dwNotificationFlags, DWORD_PTR dwReserved); - } - - // NOTE: um/DbgHelp.h ////////////////////////////////////////////////////////////////////////// - #define SYMOPT_CASE_INSENSITIVE 0x00000001 - #define SYMOPT_UNDNAME 0x00000002 - #define SYMOPT_DEFERRED_LOADS 0x00000004 - #define SYMOPT_NO_CPP 0x00000008 - #define SYMOPT_LOAD_LINES 0x00000010 - #define SYMOPT_OMAP_FIND_NEAREST 0x00000020 - #define SYMOPT_LOAD_ANYTHING 0x00000040 - #define SYMOPT_IGNORE_CVREC 0x00000080 - #define SYMOPT_NO_UNQUALIFIED_LOADS 0x00000100 - #define SYMOPT_FAIL_CRITICAL_ERRORS 0x00000200 - #define SYMOPT_EXACT_SYMBOLS 0x00000400 - #define SYMOPT_ALLOW_ABSOLUTE_SYMBOLS 0x00000800 - #define SYMOPT_IGNORE_NT_SYMPATH 0x00001000 - #define SYMOPT_INCLUDE_32BIT_MODULES 0x00002000 - #define SYMOPT_PUBLICS_ONLY 0x00004000 - #define SYMOPT_NO_PUBLICS 0x00008000 - #define SYMOPT_AUTO_PUBLICS 0x00010000 - #define SYMOPT_NO_IMAGE_SEARCH 0x00020000 - #define SYMOPT_SECURE 0x00040000 - #define SYMOPT_NO_PROMPTS 0x00080000 - #define SYMOPT_OVERWRITE 0x00100000 - #define SYMOPT_IGNORE_IMAGEDIR 0x00200000 - #define SYMOPT_FLAT_DIRECTORY 0x00400000 - #define SYMOPT_FAVOR_COMPRESSED 0x00800000 - #define SYMOPT_ALLOW_ZERO_ADDRESS 0x01000000 - #define SYMOPT_DISABLE_SYMSRV_AUTODETECT 0x02000000 - #define SYMOPT_READONLY_CACHE 0x04000000 - #define SYMOPT_SYMPATH_LAST 0x08000000 - #define SYMOPT_DISABLE_FAST_SYMBOLS 0x10000000 - #define SYMOPT_DISABLE_SYMSRV_TIMEOUT 0x20000000 - #define SYMOPT_DISABLE_SRVSTAR_ON_STARTUP 0x40000000 - #define SYMOPT_DEBUG 0x80000000 - - #define MAX_SYM_NAME 2000 - - typedef enum { - AddrMode1616, - AddrMode1632, - AddrModeReal, - AddrModeFlat - } ADDRESS_MODE; - - typedef struct _tagADDRESS64 { - DWORD64 Offset; - WORD Segment; - ADDRESS_MODE Mode; - } ADDRESS64, *LPADDRESS64; - - - typedef struct _KDHELP64 { - DWORD64 Thread; - DWORD ThCallbackStack; - DWORD ThCallbackBStore; - DWORD NextCallback; - DWORD FramePointer; - DWORD64 KiCallUserMode; - DWORD64 KeUserCallbackDispatcher; - DWORD64 SystemRangeStart; - DWORD64 KiUserExceptionDispatcher; - DWORD64 StackBase; - DWORD64 StackLimit; - DWORD BuildVersion; - DWORD RetpolineStubFunctionTableSize; - DWORD64 RetpolineStubFunctionTable; - DWORD RetpolineStubOffset; - DWORD RetpolineStubSize; - DWORD64 Reserved0[2]; - } KDHELP64, *PKDHELP64; - - typedef struct _tagSTACKFRAME64 { - ADDRESS64 AddrPC; // program counter - ADDRESS64 AddrReturn; // return address - ADDRESS64 AddrFrame; // frame pointer - ADDRESS64 AddrStack; // stack pointer - ADDRESS64 AddrBStore; // backing store pointer - VOID *FuncTableEntry; // pointer to pdata/fpo or NULL - DWORD64 Params[4]; // possible arguments to the function - BOOL Far; // WOW far call - BOOL Virtual; // is this a virtual frame? - DWORD64 Reserved[3]; - KDHELP64 KdHelp; - } STACKFRAME64; - - typedef struct _IMAGEHLP_LINEW64 { - DWORD SizeOfStruct; // set to sizeof(IMAGEHLP_LINE64) - VOID *Key; // internal - DWORD LineNumber; // line number in file - WCHAR *FileName; // full filename - DWORD64 Address; // first instruction of line - } IMAGEHLP_LINEW64; - - typedef struct _SYMBOL_INFOW { - ULONG SizeOfStruct; - ULONG TypeIndex; // Type Index of symbol - ULONG64 Reserved[2]; - ULONG Index; - ULONG Size; - ULONG64 ModBase; // Base Address of module comtaining this symbol - ULONG Flags; - ULONG64 Value; // Value of symbol, ValuePresent should be 1 - ULONG64 Address; // Address of symbol including base address of module - ULONG Register; // register holding value or pointer to value - ULONG Scope; // scope of the symbol - ULONG Tag; // pdb classification - ULONG NameLen; // Actual length of name - ULONG MaxNameLen; - WCHAR Name[1]; // Name of symbol - } SYMBOL_INFOW; - - typedef BOOL (__stdcall READ_PROCESS_MEMORY_ROUTINE64)(HANDLE hProcess, DWORD64 qwBaseAddress, VOID *lpBuffer, DWORD nSize, DWORD *lpNumberOfBytesRead); - typedef VOID * (__stdcall FUNCTION_TABLE_ACCESS_ROUTINE64)(HANDLE ahProcess, DWORD64 AddrBase); - typedef DWORD64(__stdcall GET_MODULE_BASE_ROUTINE64)(HANDLE hProcess, DWORD64 Address); - typedef DWORD64(__stdcall TRANSLATE_ADDRESS_ROUTINE64)(HANDLE hProcess, HANDLE hThread, ADDRESS64 *lpaddr); - - extern "C" - { - __declspec(dllimport) BOOL __stdcall StackWalk64 (DWORD MachineType, HANDLE hProcess, HANDLE hThread, STACKFRAME64 *StackFrame, VOID *ContextRecord, READ_PROCESS_MEMORY_ROUTINE64 *ReadMemoryRoutine, FUNCTION_TABLE_ACCESS_ROUTINE64 *FunctionTableAccessRoutine, GET_MODULE_BASE_ROUTINE64 *GetModuleBaseRoutine, TRANSLATE_ADDRESS_ROUTINE64 *TranslateAddress); - __declspec(dllimport) BOOL __stdcall SymFromAddrW (HANDLE hProcess, DWORD64 Address, DWORD64 *Displacement, SYMBOL_INFOW *Symbol); - __declspec(dllimport) VOID * __stdcall SymFunctionTableAccess64(HANDLE hProcess, DWORD64 AddrBase); - __declspec(dllimport) BOOL __stdcall SymGetLineFromAddrW64 (HANDLE hProcess, DWORD64 dwAddr, DWORD *pdwDisplacement, IMAGEHLP_LINEW64 *Line); - __declspec(dllimport) DWORD64 __stdcall SymGetModuleBase64 (HANDLE hProcess, DWORD64 qwAddr); - __declspec(dllimport) BOOL __stdcall SymRefreshModuleList (HANDLE hProcess); - }; - - // NOTE: um/errhandlingapi.h /////////////////////////////////////////////////////////////////// - extern "C" - { - __declspec(dllimport) DWORD __stdcall GetLastError(VOID); - } - - // NOTE: um/libloaderapi.h ///////////////////////////////////////////////////////////////////// - extern "C" - { - __declspec(dllimport) HMODULE __stdcall LoadLibraryA (const CHAR *lpLibFileName); - __declspec(dllimport) BOOL __stdcall FreeLibrary (HMODULE hLibModule); - __declspec(dllimport) void * __stdcall GetProcAddress (HMODULE hModule, const CHAR *lpProcName); - __declspec(dllimport) HMODULE __stdcall GetModuleHandleA (const CHAR *lpModuleName); - __declspec(dllimport) DWORD __stdcall GetModuleFileNameW(HMODULE hModule, WCHAR *lpFilename, DWORD nSize); - } - - // NOTE: um/synchapi.h ///////////////////////////////////////////////////////////////////////// - typedef RTL_CONDITION_VARIABLE CONDITION_VARIABLE, *PCONDITION_VARIABLE; - - extern "C" - { - __declspec(dllimport) VOID __stdcall InitializeConditionVariable (CONDITION_VARIABLE *ConditionVariable); - __declspec(dllimport) VOID __stdcall WakeConditionVariable (CONDITION_VARIABLE *ConditionVariable); - __declspec(dllimport) VOID __stdcall WakeAllConditionVariable (CONDITION_VARIABLE *ConditionVariable); - __declspec(dllimport) BOOL __stdcall SleepConditionVariableCS (CONDITION_VARIABLE *ConditionVariable, CRITICAL_SECTION *CriticalSection, DWORD dwMilliseconds); - - __declspec(dllimport) VOID __stdcall InitializeCriticalSection (CRITICAL_SECTION *lpCriticalSection); - __declspec(dllimport) VOID __stdcall EnterCriticalSection (CRITICAL_SECTION *lpCriticalSection); - __declspec(dllimport) VOID __stdcall LeaveCriticalSection (CRITICAL_SECTION *lpCriticalSection); - __declspec(dllimport) BOOL __stdcall InitializeCriticalSectionAndSpinCount(CRITICAL_SECTION *lpCriticalSection, DWORD dwSpinCount); - __declspec(dllimport) BOOL __stdcall InitializeCriticalSectionEx (CRITICAL_SECTION *lpCriticalSection, DWORD dwSpinCount, DWORD Flags); - __declspec(dllimport) DWORD __stdcall SetCriticalSectionSpinCount (CRITICAL_SECTION *lpCriticalSection, DWORD dwSpinCount); - __declspec(dllimport) BOOL __stdcall TryEnterCriticalSection (CRITICAL_SECTION *lpCriticalSection); - __declspec(dllimport) VOID __stdcall DeleteCriticalSection (CRITICAL_SECTION *lpCriticalSection); - - __declspec(dllimport) DWORD __stdcall WaitForSingleObject (HANDLE hHandle, DWORD dwMilliseconds); - __declspec(dllimport) BOOL __stdcall ReleaseSemaphore (HANDLE hSemaphore, LONG lReleaseCount, LONG *lpPreviousCount); - __declspec(dllimport) VOID __stdcall Sleep (DWORD dwMilliseconds); - } - - // NOTE: um/profileapi.h /////////////////////////////////////////////////////////////////////// - extern "C" - { - __declspec(dllimport) BOOL __stdcall QueryPerformanceCounter (LARGE_INTEGER* lpPerformanceCount); - __declspec(dllimport) BOOL __stdcall QueryPerformanceFrequency(LARGE_INTEGER* lpFrequency); - } - - // NOTE: um/processthreadsapi.h //////////////////////////////////////////////////////////////// - typedef struct _PROCESS_INFORMATION { - HANDLE hProcess; - HANDLE hThread; - DWORD dwProcessId; - DWORD dwThreadId; - } PROCESS_INFORMATION, *PPROCESS_INFORMATION, *LPPROCESS_INFORMATION; - - typedef struct _STARTUPINFOW { - DWORD cb; - WCHAR *lpReserved; - WCHAR *lpDesktop; - WCHAR *lpTitle; - DWORD dwX; - DWORD dwY; - DWORD dwXSize; - DWORD dwYSize; - DWORD dwXCountChars; - DWORD dwYCountChars; - DWORD dwFillAttribute; - DWORD dwFlags; - WORD wShowWindow; - WORD cbReserved2; - BYTE *lpReserved2; - HANDLE hStdInput; - HANDLE hStdOutput; - HANDLE hStdError; - } STARTUPINFOW, *LPSTARTUPINFOW; - - typedef DWORD (__stdcall *PTHREAD_START_ROUTINE)( - VOID *lpThreadParameter - ); - typedef PTHREAD_START_ROUTINE LPTHREAD_START_ROUTINE; - - extern "C" - { - __declspec(dllimport) BOOL __stdcall CreateProcessW (WCHAR const *lpApplicationName, WCHAR *lpCommandLine, SECURITY_ATTRIBUTES *lpProcessAttributes, SECURITY_ATTRIBUTES *lpThreadAttributes, BOOL bInheritHandles, DWORD dwCreationFlags, VOID *lpEnvironment, WCHAR const *lpCurrentDirectory, STARTUPINFOW *lpStartupInfo, PROCESS_INFORMATION *lpProcessInformation); - __declspec(dllimport) HANDLE __stdcall CreateThread (SECURITY_ATTRIBUTES *lpThreadAttributes, SIZE_T dwStackSize, PTHREAD_START_ROUTINE lpStartAddress, VOID *lpParameter, DWORD dwCreationFlags, DWORD *lpThreadId); - __declspec(dllimport) DWORD __stdcall GetCurrentThreadId(VOID); - __declspec(dllimport) BOOL __stdcall GetExitCodeProcess(HANDLE hProcess, DWORD *lpExitCode); - __declspec(dllimport) void __stdcall ExitProcess (UINT uExitCode); - } - - // NOTE: um/memoryapi.h //////////////////////////////////////////////////////////////////////// - extern "C" - { - __declspec(dllimport) VOID * __stdcall VirtualAlloc (VOID *lpAddress, SIZE_T dwSize, DWORD flAllocationType, DWORD flProtect); - __declspec(dllimport) BOOL __stdcall VirtualProtect(VOID *lpAddress, SIZE_T dwSize, DWORD flNewProtect, DWORD *lpflOldProtect); - __declspec(dllimport) BOOL __stdcall VirtualFree (VOID *lpAddress, SIZE_T dwSize, DWORD dwFreeType); - } - - // NOTE: shared/bcrypt.h /////////////////////////////////////////////////////////////////////// - typedef VOID *BCRYPT_ALG_HANDLE; - typedef LONG NTSTATUS; - - extern "C" - { - __declspec(dllimport) NTSTATUS __stdcall BCryptOpenAlgorithmProvider(BCRYPT_ALG_HANDLE *phAlgorithm, const WCHAR *pszAlgId, const WCHAR *pszImplementation, ULONG dwFlags); - __declspec(dllimport) NTSTATUS __stdcall BCryptGenRandom (BCRYPT_ALG_HANDLE hAlgorithm, UCHAR *pbBuffer, ULONG cbBuffer, ULONG dwFlags); - } - - // NOTE: um/shellapi.h ///////////////////////////////////////////////////////////////////////// - extern "C" - { - __declspec(dllimport) HINSTANCE __stdcall ShellExecuteA(HWND hwnd, CHAR const *lpOperation, CHAR const *lpFile, CHAR const *lpParameters, CHAR const *lpDirectory, INT nShowCmd); - __declspec(dllimport) HINSTANCE __stdcall ShellExecuteW(HWND hwnd, WCHAR const *lpOperation, WCHAR const *lpFile, WCHAR const *lpParameters, WCHAR const *lpDirectory, INT nShowCmd); - } - - // NOTE: um/debugapi.h ///////////////////////////////////////////////////////////////////////// - extern "C" - { - __declspec(dllimport) BOOL __stdcall IsDebuggerPresent(); - } - - // NOTE: um/namedpipeapi.h ///////////////////////////////////////////////////////////////////// - extern "C" - { - __declspec(dllimport) BOOL __stdcall CreatePipe (HANDLE *hReadPipe, HANDLE *hWritePipe, LPSECURITY_ATTRIBUTES lpPipeAttributes, DWORD nSize); - __declspec(dllimport) BOOL __stdcall PeekNamedPipe(HANDLE hNamedPipe, VOID *lpBuffer, DWORD nBufferSize, DWORD *lpBytesRead, DWORD *lpTotalBytesAvail, DWORD *lpBytesLeftThisMessage); - } - - // NOTE: um/handleapi.h //////////////////////////////////////////////////////////////////////// - extern "C" - { - __declspec(dllimport) BOOL __stdcall SetHandleInformation(HANDLE hObject, DWORD dwMask, DWORD dwFlags); - } - - // NOTE: um/commdlg.h ////////////////////////////////////////////////////////////////////////// - typedef UINT_PTR (__stdcall *LPOFNHOOKPROC)(HWND, UINT, WPARAM, LPARAM); - typedef struct tagOFNW { - DWORD lStructSize; - HWND hwndOwner; - HINSTANCE hInstance; - WCHAR const * lpstrFilter; - LPWSTR lpstrCustomFilter; - DWORD nMaxCustFilter; - DWORD nFilterIndex; - LPWSTR lpstrFile; - DWORD nMaxFile; - LPWSTR lpstrFileTitle; - DWORD nMaxFileTitle; - WCHAR const * lpstrInitialDir; - WCHAR const * lpstrTitle; - DWORD Flags; - WORD nFileOffset; - WORD nFileExtension; - WCHAR const * lpstrDefExt; - LPARAM lCustData; - LPOFNHOOKPROC lpfnHook; - WCHAR const * lpTemplateName; - #ifdef _MAC - LPEDITMENU lpEditInfo; - LPCSTR lpstrPrompt; - #endif - #if (_WIN32_WINNT >= 0x0500) - void * pvReserved; - DWORD dwReserved; - DWORD FlagsEx; - #endif // (_WIN32_WINNT >= 0x0500) - } OPENFILENAMEW, *LPOPENFILENAMEW; - - - #define OFN_READONLY 0x00000001 - #define OFN_OVERWRITEPROMPT 0x00000002 - #define OFN_HIDEREADONLY 0x00000004 - #define OFN_NOCHANGEDIR 0x00000008 - #define OFN_SHOWHELP 0x00000010 - #define OFN_ENABLEHOOK 0x00000020 - #define OFN_ENABLETEMPLATE 0x00000040 - #define OFN_ENABLETEMPLATEHANDLE 0x00000080 - #define OFN_NOVALIDATE 0x00000100 - #define OFN_ALLOWMULTISELECT 0x00000200 - #define OFN_EXTENSIONDIFFERENT 0x00000400 - #define OFN_PATHMUSTEXIST 0x00000800 - #define OFN_FILEMUSTEXIST 0x00001000 - #define OFN_CREATEPROMPT 0x00002000 - #define OFN_SHAREAWARE 0x00004000 - #define OFN_NOREADONLYRETURN 0x00008000 - #define OFN_NOTESTFILECREATE 0x00010000 - #define OFN_NONETWORKBUTTON 0x00020000 - #define OFN_NOLONGNAMES 0x00040000 // force no long names for 4.x modules - #if(WINVER >= 0x0400) - #define OFN_EXPLORER 0x00080000 // new look commdlg - #define OFN_NODEREFERENCELINKS 0x00100000 - #define OFN_LONGNAMES 0x00200000 // force long names for 3.x modules - // OFN_ENABLEINCLUDENOTIFY and OFN_ENABLESIZING require - // Windows 2000 or higher to have any effect. - #define OFN_ENABLEINCLUDENOTIFY 0x00400000 // send include message to callback - #define OFN_ENABLESIZING 0x00800000 - #endif /* WINVER >= 0x0400 */ - #if (_WIN32_WINNT >= 0x0500) - #define OFN_DONTADDTORECENT 0x02000000 - #define OFN_FORCESHOWHIDDEN 0x10000000 // Show All files including System and hidden files - #endif // (_WIN32_WINNT >= 0x0500) - - //FlagsEx Values - #if (_WIN32_WINNT >= 0x0500) - #define OFN_EX_NOPLACESBAR 0x00000001 - #endif // (_WIN32_WINNT >= 0x0500) - - extern "C" - { - __declspec(dllimport) BOOL __stdcall GetSaveFileNameW(LPOPENFILENAMEW); - __declspec(dllimport) BOOL __stdcall GetOpenFileNameW(LPOPENFILENAMEW); - } - - // NOTE: um/shlwapi.h ////////////////////////////////////////////////////////////////////////// - extern "C" - { - __declspec(dllimport) BOOL __stdcall PathRelativePathToW(WCHAR *pszPath, WCHAR const *pszFrom, DWORD dwAttrFrom, WCHAR const *pszTo, DWORD dwAttrTo); - __declspec(dllimport) BOOL __stdcall PathIsRelativeW(WCHAR *pszPath); - } - - // NOTE: um/pathcch.h ////////////////////////////////////////////////////////////////////////// - typedef enum PATHCCH_OPTIONS - { - PATHCCH_NONE = 0x0, - - // This option allows applications to gain access to long paths. It has two - // different behaviors. For process configured to enable long paths it will allow - // the returned path to be longer than the max path limit that is normally imposed. - // For process that are not this option will convert long paths into the extended - // length DOS device form (with \\?\ prefix) when the path is longer than the limit. - // This form is not length limited by the Win32 file system API on all versions of Windows. - // This second behavior is the same behavior for OSes that don't have the long path feature. - // This can not be specified with PATHCCH_ENSURE_IS_EXTENDED_LENGTH_PATH. - PATHCCH_ALLOW_LONG_PATHS = 0x01, - - // Can only be used when PATHCCH_ALLOW_LONG_PATHS is specified. This - // Forces the API to treat the caller as long path enabled, independent of the - // process's long name enabled state. Cannot be used with PATHCCH_FORCE_DISABLE_LONG_NAME_PROCESS. - PATHCCH_FORCE_ENABLE_LONG_NAME_PROCESS = 0x02, - - // Can only be used when PATHCCH_ALLOW_LONG_PATHS is specified. This - // Forces the API to treat the caller as long path disabled, independent of the - // process's long name enabled state. Cannot be used with PATHCCH_FORCE_ENABLE_LONG_NAME_PROCESS. - PATHCCH_FORCE_DISABLE_LONG_NAME_PROCESS = 0x04, - - // Disable the normalization of path segments that includes removing trailing dots and spaces. - // This enables access to paths that win32 path normalization will block. - PATHCCH_DO_NOT_NORMALIZE_SEGMENTS = 0x08, - - // Convert the input path into the extended length DOS device path form (with the \\?\ prefix) - // if not already in that form. This enables access to paths that are otherwise not addressable - // due to Win32 normalization rules (that can strip trailing dots and spaces) and path - // length limitations. This option implies the same behavior of PATHCCH_DO_NOT_NORMALIZE_SEGMENTS. - // This can not be specified with PATHCCH_ALLOW_LONG_PATHS. - PATHCCH_ENSURE_IS_EXTENDED_LENGTH_PATH = 0x10, - - // When combining or normalizing a path ensure there is a trailing backslash. - PATHCCH_ENSURE_TRAILING_SLASH = 0x020, - - // Convert forward slashes to back slashes and collapse multiple slashes. - // This is needed to to support sub-path or identity comparisons. - PATHCCH_CANONICALIZE_SLASHES = 0x040, - } PATHCCH_OPTIONS; - - extern "C" - { - __declspec(dllimport) HRESULT __stdcall PathCchCanonicalizeEx(PWSTR pszPathOut, size_t cchPathOut, WCHAR const *pszPathIn, ULONG dwFlags); - }; - - // NOTE: um/errhandlingapi.h /////////////////////////////////////////////////////////////////// - extern "C" - { - __declspec(dllimport) VOID __stdcall RaiseException(DWORD dwExceptionCode, DWORD dwExceptionFlags, DWORD nNumberOfArguments, const ULONG_PTR* lpArguments); - }; - - // NOTE: include/excpt.h /////////////////////////////////////////////////////////////////// - #define EXCEPTION_EXECUTE_HANDLER 1 - #define EXCEPTION_CONTINUE_SEARCH 0 - #define EXCEPTION_CONTINUE_EXECUTION (-1) - - DN_MSVC_WARNING_POP -#endif // !defined(_INC_WINDOWS) -#endif // !defined(DN_OS_WINDOWS_H) - // DN: Single header generator inlined this file => #include "OS/dn_os_w32.h" -#if !defined(DN_OS_WIN32_H) -#define DN_OS_WIN32_H - -#if defined(_CLANGD) - // DN: Single header generator commented out this header => #include "../dn_base_inc.h" - // DN: Single header generator commented out this header => #include "dn_os_windows.h" -#if !defined(DN_OS_WINDOWS_H) -#define DN_OS_WINDOWS_H - -#if defined(_CLANGD) - // DN: Single header generator commented out this header => #include "../dn_base_inc.h" -#endif - -#if defined(DN_COMPILER_MSVC) || defined(DN_COMPILER_CLANG_CL) - #pragma comment(lib, "bcrypt") - #pragma comment(lib, "winhttp") - #pragma comment(lib, "dbghelp") - #pragma comment(lib, "comdlg32") - #pragma comment(lib, "pathcch") - #pragma comment(lib, "Shell32") // ShellExecuteW - #pragma comment(lib, "shlwapi") -#endif - -#if defined(DN_NO_WINDOWS_H_REPLACEMENT_HEADER) || defined(_INC_WINDOWS) - #define WIN32_LEAN_AND_MEAN - #include // LONG - #include // DN_OS_SecureRNGBytes -> BCryptOpenAlgorithmProvider ... etc - #include // DN_Win_MakeProcessDPIAware -> SetProcessDpiAwareProc - #include // PathRelativePathTO - #include // PathCchCanonicalizeEx - #include // WinHttp* - #include // PROCESS_MEMORY_COUNTERS_EX2 - #include // OPENFILENAMEW - #include -#else - DN_MSVC_WARNING_PUSH - DN_MSVC_WARNING_DISABLE(4201) // warning C4201: nonstandard extension used: nameless struct/union - - // NOTE: basetsd.h ///////////////////////////////////////////////////////////////////////////// - typedef unsigned __int64 ULONG_PTR, *PULONG_PTR; - typedef unsigned __int64 UINT_PTR, *PUINT_PTR; - typedef ULONG_PTR SIZE_T, *PSIZE_T; - typedef __int64 LONG_PTR, *PLONG_PTR; - typedef ULONG_PTR DWORD_PTR, *PDWORD_PTR; - typedef unsigned __int64 ULONG64, *PULONG64; - typedef unsigned __int64 DWORD64, *PDWORD64; - - // NOTE: shared/minwindef.h //////////////////////////////////////////////////////////////////// - struct HINSTANCE__ { - int unused; - }; - typedef struct HINSTANCE__ *HINSTANCE; - - typedef unsigned long DWORD; - typedef int BOOL; - typedef int INT; - typedef unsigned long ULONG; - typedef unsigned int UINT; - typedef unsigned short WORD; - typedef unsigned char BYTE; - typedef unsigned char UCHAR; - typedef HINSTANCE HMODULE; /* HMODULEs can be used in place of HINSTANCEs */ - typedef void * HANDLE; - typedef HANDLE HLOCAL; - - typedef unsigned __int64 WPARAM; - typedef LONG_PTR LPARAM; - typedef LONG_PTR LRESULT; - - #define MAX_PATH 260 - - typedef struct _FILETIME { - DWORD dwLowDateTime; - DWORD dwHighDateTime; - } FILETIME, *PFILETIME, *LPFILETIME; - - // NOTE: shared/winerror.h ///////////////////////////////////////////////////////////////////// - // NOTE: GetModuleFileNameW - #define ERROR_INSUFFICIENT_BUFFER 122L // dderror - - // NOTE: um/winnls.h /////////////////////////////////////////////////////////////////////////// - // NOTE: MultiByteToWideChar - #define CP_UTF8 65001 // UTF-8 translation - - // NOTE: um/winnt.h //////////////////////////////////////////////////////////////////////////// - typedef void VOID; - typedef __int64 LONGLONG; - typedef unsigned __int64 ULONGLONG; - typedef void * HANDLE; - typedef char CHAR; - typedef short SHORT; - typedef long LONG; - typedef wchar_t WCHAR; // wc, 16-bit UNICODE character - typedef CHAR * NPSTR, *LPSTR, *PSTR; - typedef WCHAR * NWPSTR, *LPWSTR, *PWSTR; - typedef long HRESULT; - - // NOTE: VirtualAlloc: Allocation Type - #define MEM_RESERVE 0x00002000 - #define MEM_COMMIT 0x00001000 - #define MEM_DECOMMIT 0x00004000 - #define MEM_RELEASE 0x00008000 - - // NOTE: VirtualAlloc: Page Permissions - #define PAGE_NOACCESS 0x01 - #define PAGE_READONLY 0x02 - #define PAGE_READWRITE 0x04 - #define PAGE_GUARD 0x100 - - // NOTE: HeapAlloc - #define HEAP_ZERO_MEMORY 0x00000008 - #define HEAP_NO_SERIALIZE 0x00000001 - #define HEAP_GROWABLE 0x00000002 - #define HEAP_GENERATE_EXCEPTIONS 0x00000004 - #define HEAP_ZERO_MEMORY 0x00000008 - #define HEAP_REALLOC_IN_PLACE_ONLY 0x00000010 - #define HEAP_TAIL_CHECKING_ENABLED 0x00000020 - #define HEAP_FREE_CHECKING_ENABLED 0x00000040 - #define HEAP_DISABLE_COALESCE_ON_FREE 0x00000080 - #define HEAP_CREATE_ALIGN_16 0x00010000 - #define HEAP_CREATE_ENABLE_TRACING 0x00020000 - #define HEAP_CREATE_ENABLE_EXECUTE 0x00040000 - #define HEAP_MAXIMUM_TAG 0x0FFF - #define HEAP_PSEUDO_TAG_FLAG 0x8000 - #define HEAP_TAG_SHIFT 18 - #define HEAP_CREATE_SEGMENT_HEAP 0x00000100 - #define HEAP_CREATE_HARDENED 0x00000200 - - // NOTE: FormatMessageA - #define MAKELANGID(p, s) ((((WORD )(s)) << 10) | (WORD )(p)) - #define LANG_NEUTRAL 0x00 - #define SUBLANG_DEFAULT 0x01 // user default - - // NOTE: CreateFile - #define GENERIC_READ (0x80000000L) - #define GENERIC_WRITE (0x40000000L) - #define GENERIC_EXECUTE (0x20000000L) - #define GENERIC_ALL (0x10000000L) - - #define FILE_APPEND_DATA (0x0004) // file - - // NOTE: CreateFile/FindFirstFile - #define FILE_SHARE_READ 0x00000001 - #define FILE_SHARE_WRITE 0x00000002 - #define FILE_SHARE_DELETE 0x00000004 - - #define FILE_ATTRIBUTE_READONLY 0x00000001 - #define FILE_ATTRIBUTE_HIDDEN 0x00000002 - #define FILE_ATTRIBUTE_SYSTEM 0x00000004 - #define FILE_ATTRIBUTE_DIRECTORY 0x00000010 - #define FILE_ATTRIBUTE_NORMAL 0x00000080 - - // NOTE: STACKFRAME64 - #define IMAGE_FILE_MACHINE_AMD64 0x8664 // AMD64 (K8) - - // NOTE: WaitForSingleObject - #define WAIT_TIMEOUT 258L // dderror - #define STATUS_WAIT_0 ((DWORD )0x00000000L) - #define STATUS_ABANDONED_WAIT_0 ((DWORD )0x00000080L) - - #define S_OK ((HRESULT)0L) - #define S_FALSE ((HRESULT)1L) - - typedef union _ULARGE_INTEGER { - struct { - DWORD LowPart; - DWORD HighPart; - } DUMMYSTRUCTNAME; - struct { - DWORD LowPart; - DWORD HighPart; - } u; - ULONGLONG QuadPart; - } ULARGE_INTEGER; - - typedef union _LARGE_INTEGER { - struct { - DWORD LowPart; - LONG HighPart; - } DUMMYSTRUCTNAME; - struct { - DWORD LowPart; - LONG HighPart; - } u; - LONGLONG QuadPart; - } LARGE_INTEGER; - - typedef struct __declspec(align(16)) _M128A { - ULONGLONG Low; - LONGLONG High; - } M128A, *PM128A; - - typedef struct __declspec(align(16)) _XSAVE_FORMAT { - WORD ControlWord; - WORD StatusWord; - BYTE TagWord; - BYTE Reserved1; - WORD ErrorOpcode; - DWORD ErrorOffset; - WORD ErrorSelector; - WORD Reserved2; - DWORD DataOffset; - WORD DataSelector; - WORD Reserved3; - DWORD MxCsr; - DWORD MxCsr_Mask; - M128A FloatRegisters[8]; - #if defined(_WIN64) - M128A XmmRegisters[16]; - BYTE Reserved4[96]; - #else - M128A XmmRegisters[8]; - BYTE Reserved4[224]; - #endif - } XSAVE_FORMAT, *PXSAVE_FORMAT; - typedef XSAVE_FORMAT XMM_SAVE_AREA32, *PXMM_SAVE_AREA32; - - typedef struct __declspec(align(16)) _CONTEXT { - DWORD64 P1Home; - DWORD64 P2Home; - DWORD64 P3Home; - DWORD64 P4Home; - DWORD64 P5Home; - DWORD64 P6Home; - DWORD ContextFlags; - DWORD MxCsr; - WORD SegCs; - WORD SegDs; - WORD SegEs; - WORD SegFs; - WORD SegGs; - WORD SegSs; - DWORD EFlags; - DWORD64 Dr0; - DWORD64 Dr1; - DWORD64 Dr2; - DWORD64 Dr3; - DWORD64 Dr6; - DWORD64 Dr7; - DWORD64 Rax; - DWORD64 Rcx; - DWORD64 Rdx; - DWORD64 Rbx; - DWORD64 Rsp; - DWORD64 Rbp; - DWORD64 Rsi; - DWORD64 Rdi; - DWORD64 R8; - DWORD64 R9; - DWORD64 R10; - DWORD64 R11; - DWORD64 R12; - DWORD64 R13; - DWORD64 R14; - DWORD64 R15; - DWORD64 Rip; - - union { - XMM_SAVE_AREA32 FltSave; - - struct { - M128A Header[2]; - M128A Legacy[8]; - M128A Xmm0; - M128A Xmm1; - M128A Xmm2; - M128A Xmm3; - M128A Xmm4; - M128A Xmm5; - M128A Xmm6; - M128A Xmm7; - M128A Xmm8; - M128A Xmm9; - M128A Xmm10; - M128A Xmm11; - M128A Xmm12; - M128A Xmm13; - M128A Xmm14; - M128A Xmm15; - } DUMMYSTRUCTNAME; - } DUMMYUNIONNAME; - - M128A VectorRegister[26]; - DWORD64 VectorControl; - DWORD64 DebugControl; - DWORD64 LastBranchToRip; - DWORD64 LastBranchFromRip; - DWORD64 LastExceptionToRip; - DWORD64 LastExceptionFromRip; - } CONTEXT; - - typedef struct _LIST_ENTRY { - struct _LIST_ENTRY *Flink; - struct _LIST_ENTRY *Blink; - } LIST_ENTRY, *PLIST_ENTRY, PRLIST_ENTRY; - - typedef struct _RTL_CRITICAL_SECTION_DEBUG { - WORD Type; - WORD CreatorBackTraceIndex; - struct _RTL_CRITICAL_SECTION *CriticalSection; - LIST_ENTRY ProcessLocksList; - DWORD EntryCount; - DWORD ContentionCount; - DWORD Flags; - WORD CreatorBackTraceIndexHigh; - WORD Identifier; - } RTL_CRITICAL_SECTION_DEBUG, *PRTL_CRITICAL_SECTION_DEBUG, RTL_RESOURCE_DEBUG, *PRTL_RESOURCE_DEBUG; - - typedef struct _RTL_CONDITION_VARIABLE { - VOID *Ptr; - } RTL_CONDITION_VARIABLE, *PRTL_CONDITION_VARIABLE; - - #pragma pack(push, 8) - typedef struct _RTL_CRITICAL_SECTION { - PRTL_CRITICAL_SECTION_DEBUG DebugInfo; - - // - // The following three fields control entering and exiting the critical - // section for the resource - // - - LONG LockCount; - LONG RecursionCount; - HANDLE OwningThread; // from the thread's ClientId->UniqueThread - HANDLE LockSemaphore; - ULONG_PTR SpinCount; // force size on 64-bit systems when packed - } RTL_CRITICAL_SECTION, *PRTL_CRITICAL_SECTION; - #pragma pack(pop) - - typedef struct _MODLOAD_DATA { - DWORD ssize; // size of this struct - DWORD ssig; // signature identifying the passed data - VOID *data; // pointer to passed data - DWORD size; // size of passed data - DWORD flags; // options - } MODLOAD_DATA, *PMODLOAD_DATA; - - #define SLMFLAG_VIRTUAL 0x1 - #define SLMFLAG_ALT_INDEX 0x2 - #define SLMFLAG_NO_SYMBOLS 0x4 - - extern "C" - { - __declspec(dllimport) VOID __stdcall RtlCaptureContext(CONTEXT *ContextRecord); - __declspec(dllimport) HANDLE __stdcall GetCurrentProcess(void); - __declspec(dllimport) HANDLE __stdcall GetCurrentThread(void); - __declspec(dllimport) DWORD __stdcall SymSetOptions(DWORD SymOptions); - __declspec(dllimport) BOOL __stdcall SymInitialize(HANDLE hProcess, const CHAR* UserSearchPath, BOOL fInvadeProcess); - __declspec(dllimport) DWORD64 __stdcall SymLoadModuleEx(HANDLE hProcess, HANDLE hFile, CHAR const *ImageName, CHAR const *ModuleName, DWORD64 BaseOfDll, DWORD DllSize, MODLOAD_DATA *Data, DWORD Flags); - __declspec(dllimport) BOOL __stdcall SymUnloadModule64(HANDLE hProcess, DWORD64 BaseOfDll); - } - - // NOTE: um/heapapi.h //////////////////////////////////////////////////////////////////// - extern "C" - { - __declspec(dllimport) HANDLE __stdcall HeapCreate(DWORD flOptions, SIZE_T dwInitialSize, SIZE_T dwMaximumSize); - __declspec(dllimport) BOOL __stdcall HeapDestroy(HANDLE hHeap); - __declspec(dllimport) VOID * __stdcall HeapAlloc(HANDLE hHeap, DWORD dwFlags,SIZE_T dwBytes); - __declspec(dllimport) VOID * __stdcall HeapReAlloc(HANDLE hHeap, DWORD dwFlags, VOID *lpMem, SIZE_T dwBytes); - __declspec(dllimport) BOOL __stdcall HeapFree(HANDLE hHeap, DWORD dwFlags, VOID *lpMem); - __declspec(dllimport) SIZE_T __stdcall HeapSize(HANDLE hHeap, DWORD dwFlags, VOID const *lpMem); - __declspec(dllimport) HANDLE __stdcall GetProcessHeap(VOID); - __declspec(dllimport) SIZE_T __stdcall HeapCompact(HANDLE hHeap, DWORD dwFlags); - } - - // NOTE: shared/windef.h //////////////////////////////////////////////////////////////////// - typedef struct tagPOINT - { - LONG x; - LONG y; - } POINT, *PPOINT, *NPPOINT, *LPPOINT; - - // NOTE: handleapi.h /////////////////////////////////////////////////////////////////////////// - #define INVALID_HANDLE_VALUE ((HANDLE)(LONG_PTR)-1) - - extern "C" - { - __declspec(dllimport) BOOL __stdcall CloseHandle(HANDLE hObject); - } - - // NOTE: consoleapi.h /////////////////////////////////////////////////////////////////////////// - extern "C" - { - __declspec(dllimport) BOOL __stdcall WriteConsoleA(HANDLE hConsoleOutput, const VOID* lpBuffer, DWORD nNumberOfCharsToWrite, DWORD *lpNumberOfCharsWritten, VOID *lpReserved); - __declspec(dllimport) BOOL __stdcall AllocConsole(VOID); - __declspec(dllimport) BOOL __stdcall FreeConsole(VOID); - __declspec(dllimport) BOOL __stdcall AttachConsole(DWORD dwProcessId); - __declspec(dllimport) BOOL __stdcall GetConsoleMode(HANDLE hConsoleHandle, DWORD *lpMode); - } - - // NOTE: um/minwinbase.h /////////////////////////////////////////////////////////////////////// - // NOTE: FindFirstFile - #define FIND_FIRST_EX_CASE_SENSITIVE 0x00000001 - #define FIND_FIRST_EX_LARGE_FETCH 0x00000002 - - // NOTE: WaitFor.. - #define WAIT_FAILED ((DWORD)0xFFFFFFFF) - #define WAIT_OBJECT_0 ((STATUS_WAIT_0 ) + 0 ) - #define WAIT_ABANDONED ((STATUS_ABANDONED_WAIT_0 ) + 0 ) - #define WAIT_ABANDONED_0 ((STATUS_ABANDONED_WAIT_0 ) + 0 ) - - // NOTE: CreateProcessW - #define CREATE_UNICODE_ENVIRONMENT 0x00000400 - #define CREATE_NO_WINDOW 0x08000000 - - typedef enum _GET_FILEEX_INFO_LEVELS { - GetFileExInfoStandard, - GetFileExMaxInfoLevel - } GET_FILEEX_INFO_LEVELS; - - typedef struct _SECURITY_ATTRIBUTES { - DWORD nLength; - VOID *lpSecurityDescriptor; - BOOL bInheritHandle; - } SECURITY_ATTRIBUTES, *PSECURITY_ATTRIBUTES, *LPSECURITY_ATTRIBUTES; - - typedef enum _FINDEX_INFO_LEVELS { - FindExInfoStandard, - FindExInfoBasic, - FindExInfoMaxInfoLevel - } FINDEX_INFO_LEVELS; - - typedef enum _FINDEX_SEARCH_OPS { - FindExSearchNameMatch, - FindExSearchLimitToDirectories, - FindExSearchLimitToDevices, - FindExSearchMaxSearchOp - } FINDEX_SEARCH_OPS; - - typedef struct _WIN32_FIND_DATAW { - DWORD dwFileAttributes; - FILETIME ftCreationTime; - FILETIME ftLastAccessTime; - FILETIME ftLastWriteTime; - DWORD nFileSizeHigh; - DWORD nFileSizeLow; - DWORD dwReserved0; - DWORD dwReserved1; - WCHAR cFileName[ MAX_PATH ]; - WCHAR cAlternateFileName[ 14 ]; - #ifdef _MAC - DWORD dwFileType; - DWORD dwCreatorType; - WORD wFinderFlags; - #endif - } WIN32_FIND_DATAW, *PWIN32_FIND_DATAW, *LPWIN32_FIND_DATAW; - - typedef struct _SYSTEMTIME { - WORD wYear; - WORD wMonth; - WORD wDayOfWeek; - WORD wDay; - WORD wHour; - WORD wMinute; - WORD wSecond; - WORD wMilliseconds; - } SYSTEMTIME, *PSYSTEMTIME, *LPSYSTEMTIME; - - typedef struct _OVERLAPPED { - ULONG_PTR Internal; - ULONG_PTR InternalHigh; - union { - struct { - DWORD Offset; - DWORD OffsetHigh; - } DUMMYSTRUCTNAME; - VOID *Pointer; - } DUMMYUNIONNAME; - - HANDLE hEvent; - } OVERLAPPED, *LPOVERLAPPED; - - typedef RTL_CRITICAL_SECTION CRITICAL_SECTION; - - #define WAIT_FAILED ((DWORD)0xFFFFFFFF) - #define WAIT_OBJECT_0 ((STATUS_WAIT_0 ) + 0 ) - - #define INFINITE 0xFFFFFFFF // Wait/Synchronisation: Infinite timeout - - #define STD_INPUT_HANDLE ((DWORD)-10) - #define STD_OUTPUT_HANDLE ((DWORD)-11) - #define STD_ERROR_HANDLE ((DWORD)-12) - - #define HANDLE_FLAG_INHERIT 0x00000001 - #define HANDLE_FLAG_PROTECT_FROM_CLOSE 0x00000002 - - // NOTE: MoveFile - #define MOVEFILE_REPLACE_EXISTING 0x00000001 - #define MOVEFILE_COPY_ALLOWED 0x00000002 - - // NOTE: FormatMessageA - #define FORMAT_MESSAGE_ALLOCATE_BUFFER 0x00000100 - #define FORMAT_MESSAGE_IGNORE_INSERTS 0x00000200 - #define FORMAT_MESSAGE_FROM_HMODULE 0x00000800 - #define FORMAT_MESSAGE_FROM_SYSTEM 0x00001000 - - // NOTE: CreateProcessW - #define STARTF_USESTDHANDLES 0x00000100 - - extern "C" - { - __declspec(dllimport) BOOL __stdcall MoveFileExW (const WCHAR *lpExistingFileName, const WCHAR *lpNewFileName, DWORD dwFlags); - __declspec(dllimport) BOOL __stdcall CopyFileW (const WCHAR *lpExistingFileName, const WCHAR *lpNewFileName, BOOL bFailIfExists); - __declspec(dllimport) HANDLE __stdcall CreateSemaphoreA(SECURITY_ATTRIBUTES *lpSemaphoreAttributes, LONG lInitialCount, LONG lMaximumCount, const CHAR *lpName); - __declspec(dllimport) DWORD __stdcall FormatMessageW (DWORD dwFlags, VOID const *lpSource, DWORD dwMessageId, DWORD dwLanguageId, LPWSTR lpBuffer, DWORD nSize, va_list *Arguments); - __declspec(dllimport) HLOCAL __stdcall LocalFree (HLOCAL hMem); - } - - // NOTE: um/stringapiset.h ///////////////////////////////////////////////////////////////////// - extern "C" - { - __declspec(dllimport) int __stdcall MultiByteToWideChar(UINT CodePage, DWORD dwFlags, const CHAR *lpMultiByteStr, int cbMultiByte, WCHAR *lpWideCharStr, int cchWideChar); - __declspec(dllimport) int __stdcall WideCharToMultiByte(UINT CodePage, DWORD dwFlags, const WCHAR *lpWideCharStr, int cchWideChar, LPSTR lpMultiByteStr, int cbMultiByte, const CHAR *lpDefaultChar, BOOL *lpUsedDefaultChar); - } - - // NOTE: um/fileapi.h ////////////////////////////////////////////////////////////////////////// - #define INVALID_FILE_SIZE ((DWORD)0xFFFFFFFF) - #define INVALID_FILE_ATTRIBUTES ((DWORD)-1) - - // NOTE: CreateFile - #define CREATE_NEW 1 - #define CREATE_ALWAYS 2 - #define OPEN_EXISTING 3 - #define OPEN_ALWAYS 4 - #define TRUNCATE_EXISTING 5 - - typedef struct _WIN32_FILE_ATTRIBUTE_DATA { - DWORD dwFileAttributes; - FILETIME ftCreationTime; - FILETIME ftLastAccessTime; - FILETIME ftLastWriteTime; - DWORD nFileSizeHigh; - DWORD nFileSizeLow; - } WIN32_FILE_ATTRIBUTE_DATA, *LPWIN32_FILE_ATTRIBUTE_DATA; - - extern "C" - { - __declspec(dllimport) BOOL __stdcall FlushFileBuffers (HANDLE hFile); - __declspec(dllimport) BOOL __stdcall CreateDirectoryW (const WCHAR *lpPathName, SECURITY_ATTRIBUTES *lpSecurityAttributes); - __declspec(dllimport) BOOL __stdcall RemoveDirectoryW (const WCHAR *lpPathName); - __declspec(dllimport) BOOL __stdcall FindNextFileW (HANDLE hFindFile, WIN32_FIND_DATAW *lpFindFileData); - __declspec(dllimport) BOOL __stdcall FindClose (HANDLE hFindFile); - __declspec(dllimport) BOOL __stdcall FileTimeToLocalFileTime(const FILETIME *lpFileTime, FILETIME *lpLocalFileTime); - - __declspec(dllimport) HANDLE __stdcall FindFirstFileExW (const WCHAR *lpFileName, FINDEX_INFO_LEVELS fInfoLevelId, VOID *lpFindFileData, FINDEX_SEARCH_OPS fSearchOp, VOID *lpSearchFilter, DWORD dwAdditionalFlags); - __declspec(dllimport) BOOL __stdcall GetFileAttributesExW (const WCHAR *lpFileName, GET_FILEEX_INFO_LEVELS fInfoLevelId, VOID *lpFileInformation); - __declspec(dllimport) BOOL __stdcall GetFileSizeEx (HANDLE hFile, LARGE_INTEGER *lpFileSize); - __declspec(dllimport) BOOL __stdcall DeleteFileW (const WCHAR *lpFileName); - __declspec(dllimport) HANDLE __stdcall CreateFileW (const WCHAR *lpFileName, DWORD dwDesiredAccess, DWORD dwShareMode, SECURITY_ATTRIBUTES *lpSecurityAttributes, DWORD dwCreationDisposition, DWORD dwFlagsAndAttributes, HANDLE hTemplateFile); - __declspec(dllimport) BOOL __stdcall ReadFile (HANDLE hFile, VOID *lpBuffer, DWORD nNumberOfBytesToRead, DWORD *lpNumberOfBytesRead, OVERLAPPED *lpOverlapped); - __declspec(dllimport) BOOL __stdcall WriteFile (HANDLE hFile, const VOID *lpBuffer, DWORD nNumberOfBytesToWrite, DWORD *lpNumberOfBytesWritten, OVERLAPPED *lpOverlapped); - __declspec(dllimport) BOOL __stdcall GetDiskFreeSpaceExW (WCHAR const *lpDirectoryName, ULARGE_INTEGER *lpFreeBytesAvailableToCaller, ULARGE_INTEGER *lpTotalNumberOfBytes, ULARGE_INTEGER *lpTotalNumberOfFreeBytes); - } - - // NOTE: um/processenv.h /////////////////////////////////////////////////////////////////////// - extern "C" - { - __declspec(dllimport) DWORD __stdcall GetCurrentDirectoryW (DWORD nBufferLength, WCHAR *lpBuffer); - __declspec(dllimport) HANDLE __stdcall GetStdHandle (DWORD nStdHandle); - __declspec(dllimport) WCHAR* __stdcall GetEnvironmentStringsW (); - __declspec(dllimport) BOOL __stdcall FreeEnvironmentStringsW(WCHAR *penv); - __declspec(dllimport) DWORD __stdcall GetEnvironmentVariableW(WCHAR const *lpName, WCHAR *lpBuffer, DWORD nSize); - __declspec(dllimport) BOOL __stdcall SetEnvironmentVariableW(WCHAR const *lpName, WCHAR const *lpValue); - } - - // NOTE: um/psapi.h //////////////////////////////////////////////////////////////////////////// - typedef struct _PROCESS_MEMORY_COUNTERS { - 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; - } PROCESS_MEMORY_COUNTERS; - typedef PROCESS_MEMORY_COUNTERS *PPROCESS_MEMORY_COUNTERS; - - extern "C" - { - __declspec(dllimport) BOOL __stdcall GetProcessMemoryInfo(HANDLE Process, PPROCESS_MEMORY_COUNTERS ppsmemCounters, DWORD cb); - } - - // NOTE: um/sysinfoapi.h /////////////////////////////////////////////////////////////////////// - typedef struct _SYSTEM_INFO { - union { - DWORD dwOemId; // Obsolete field...do not use - struct { - WORD wProcessorArchitecture; - WORD wReserved; - } DUMMYSTRUCTNAME; - } DUMMYUNIONNAME; - DWORD dwPageSize; - VOID *lpMinimumApplicationAddress; - VOID *lpMaximumApplicationAddress; - DWORD_PTR dwActiveProcessorMask; - DWORD dwNumberOfProcessors; - DWORD dwProcessorType; - DWORD dwAllocationGranularity; - WORD wProcessorLevel; - WORD wProcessorRevision; - } SYSTEM_INFO, *LPSYSTEM_INFO; - - extern "C" - { - __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); - } - - // NOTE: um/timezoneapi.h ////////////////////////////////////////////////////////////////////// - typedef struct _TIME_ZONE_INFORMATION { - LONG Bias; - WCHAR StandardName[32]; - SYSTEMTIME StandardDate; - LONG StandardBias; - WCHAR DaylightName[32]; - SYSTEMTIME DaylightDate; - LONG DaylightBias; - } TIME_ZONE_INFORMATION, *PTIME_ZONE_INFORMATION, *LPTIME_ZONE_INFORMATION; - - extern "C" - { - __declspec(dllimport) BOOL __stdcall FileTimeToSystemTime (const FILETIME* lpFileTime, SYSTEMTIME *lpSystemTime); - __declspec(dllimport) BOOL __stdcall SystemTimeToFileTime (const SYSTEMTIME* lpSystemTime, FILETIME *lpFileTime); - __declspec(dllimport) BOOL __stdcall TzSpecificLocalTimeToSystemTime(const TIME_ZONE_INFORMATION* lpTimeZoneInformation, const SYSTEMTIME* lpLocalTime, const LPSYSTEMTIME lpUniversalTime); - } - - // NOTE: shared/windef.h /////////////////////////////////////////////////////////////////////// - typedef struct tagRECT { - LONG left; - LONG top; - LONG right; - LONG bottom; - } RECT; - - struct HWND__ { - int unused; - }; - typedef struct HWND__ *HWND; - - struct DPI_AWARENESS_CONTEXT__ { - int unused; - }; - typedef struct DPI_AWARENESS_CONTEXT__ *DPI_AWARENESS_CONTEXT; - - typedef enum DPI_AWARENESS { - DPI_AWARENESS_INVALID = -1, - DPI_AWARENESS_UNAWARE = 0, - DPI_AWARENESS_SYSTEM_AWARE = 1, - DPI_AWARENESS_PER_MONITOR_AWARE = 2 - } DPI_AWARENESS; - - #define DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2 ((DPI_AWARENESS_CONTEXT)-4) - - // NOTE: um/winuser.h ////////////////////////////////////////////////////////////////////////// - typedef struct tagWINDOWPLACEMENT { - UINT length; - UINT flags; - UINT showCmd; - POINT ptMinPosition; - POINT ptMaxPosition; - RECT rcNormalPosition; - #ifdef _MAC - RECT rcDevice; - #endif - } WINDOWPLACEMENT; - typedef WINDOWPLACEMENT *PWINDOWPLACEMENT, *LPWINDOWPLACEMENT; - - #define SW_HIDE 0 - #define SW_NORMAL 1 - #define SW_MAXIMIZE 3 - #define SW_SHOWNOACTIVATE 4 - #define SW_SHOW 5 - #define SW_FORCEMINIMIZE 11 - - extern "C" - { - __declspec(dllimport) BOOL __stdcall GetWindowRect (HWND hWnd, RECT *lpRect); - __declspec(dllimport) BOOL __stdcall SetWindowPos (HWND hWnd, HWND hWndInsertAfter, int X, int Y, int cx, int cy, UINT uFlags); - __declspec(dllimport) UINT __stdcall GetWindowModuleFileNameA(HWND hwnd, LPSTR pszFileName, UINT cchFileNameMax); - __declspec(dllimport) BOOL __stdcall ShowWindow (HWND hWnd, int nCmdShow); - __declspec(dllimport) BOOL __stdcall GetWindowPlacement (HWND hWnd, WINDOWPLACEMENT *lpwndpl); - - } - - // NOTE: um/wininet.h ////////////////////////////////////////////////////////////////////////// - typedef WORD INTERNET_PORT; - typedef VOID *HINTERNET; - - // NOTE: um/winhttp.h ////////////////////////////////////////////////////////////////////////// - #define WINHTTP_ACCESS_TYPE_DEFAULT_PROXY 0 - #define WINHTTP_ACCESS_TYPE_NO_PROXY 1 - #define WINHTTP_ACCESS_TYPE_NAMED_PROXY 3 - #define WINHTTP_ACCESS_TYPE_AUTOMATIC_PROXY 4 - - #define INTERNET_DEFAULT_PORT 0 // use the protocol-specific default - #define INTERNET_DEFAULT_HTTP_PORT 80 // " " HTTP " - #define INTERNET_DEFAULT_HTTPS_PORT 443 // " " HTTPS " - - // NOTE: WinHttpOpen - #define WINHTTP_FLAG_ASYNC 0x10000000 // this session is asynchronous (where supported) - #define WINHTTP_FLAG_SECURE_DEFAULTS 0x30000000 // note that this flag also forces async - - // NOTE: WinHttpOpenRequest - #define WINHTTP_FLAG_SECURE 0x00800000 // use SSL if applicable (HTTPS) - #define WINHTTP_FLAG_ESCAPE_PERCENT 0x00000004 // if escaping enabled, escape percent as well - #define WINHTTP_FLAG_NULL_CODEPAGE 0x00000008 // assume all symbols are ASCII, use fast convertion - #define WINHTTP_FLAG_ESCAPE_DISABLE 0x00000040 // disable escaping - #define WINHTTP_FLAG_ESCAPE_DISABLE_QUERY 0x00000080 // if escaping enabled escape path part, but do not escape query - #define WINHTTP_FLAG_BYPASS_PROXY_CACHE 0x00000100 // add "pragma: no-cache" request header - #define WINHTTP_FLAG_REFRESH WINHTTP_FLAG_BYPASS_PROXY_CACHE - #define WINHTTP_FLAG_AUTOMATIC_CHUNKING 0x00000200 // Send request without content-length header or chunked TE - - #define WINHTTP_NO_PROXY_NAME NULL - #define WINHTTP_NO_PROXY_BYPASS NULL - - // - // WINHTTP_QUERY_FLAG_NUMBER - if this bit is set in the dwInfoLevel parameter of - // HttpQueryHeader(), then the value of the header will be converted to a number - // before being returned to the caller, if applicable - // - #define WINHTTP_QUERY_FLAG_NUMBER 0x20000000 - - #define WINHTTP_QUERY_MIME_VERSION 0 - #define WINHTTP_QUERY_CONTENT_TYPE 1 - #define WINHTTP_QUERY_CONTENT_TRANSFER_ENCODING 2 - #define WINHTTP_QUERY_CONTENT_ID 3 - #define WINHTTP_QUERY_CONTENT_DESCRIPTION 4 - #define WINHTTP_QUERY_CONTENT_LENGTH 5 - #define WINHTTP_QUERY_CONTENT_LANGUAGE 6 - #define WINHTTP_QUERY_ALLOW 7 - #define WINHTTP_QUERY_PUBLIC 8 - #define WINHTTP_QUERY_DATE 9 - #define WINHTTP_QUERY_EXPIRES 10 - #define WINHTTP_QUERY_LAST_MODIFIED 11 - #define WINHTTP_QUERY_MESSAGE_ID 12 - #define WINHTTP_QUERY_URI 13 - #define WINHTTP_QUERY_DERIVED_FROM 14 - #define WINHTTP_QUERY_COST 15 - #define WINHTTP_QUERY_LINK 16 - #define WINHTTP_QUERY_PRAGMA 17 - #define WINHTTP_QUERY_VERSION 18 // special: part of status line - #define WINHTTP_QUERY_STATUS_CODE 19 // special: part of status line - #define WINHTTP_QUERY_STATUS_TEXT 20 // special: part of status line - #define WINHTTP_QUERY_RAW_HEADERS 21 // special: all headers as ASCIIZ - #define WINHTTP_QUERY_RAW_HEADERS_CRLF 22 // special: all headers - #define WINHTTP_QUERY_CONNECTION 23 - #define WINHTTP_QUERY_ACCEPT 24 - #define WINHTTP_QUERY_ACCEPT_CHARSET 25 - #define WINHTTP_QUERY_ACCEPT_ENCODING 26 - #define WINHTTP_QUERY_ACCEPT_LANGUAGE 27 - #define WINHTTP_QUERY_AUTHORIZATION 28 - #define WINHTTP_QUERY_CONTENT_ENCODING 29 - #define WINHTTP_QUERY_FORWARDED 30 - #define WINHTTP_QUERY_FROM 31 - #define WINHTTP_QUERY_IF_MODIFIED_SINCE 32 - #define WINHTTP_QUERY_LOCATION 33 - #define WINHTTP_QUERY_ORIG_URI 34 - #define WINHTTP_QUERY_REFERER 35 - #define WINHTTP_QUERY_RETRY_AFTER 36 - #define WINHTTP_QUERY_SERVER 37 - #define WINHTTP_QUERY_TITLE 38 - #define WINHTTP_QUERY_USER_AGENT 39 - #define WINHTTP_QUERY_WWW_AUTHENTICATE 40 - #define WINHTTP_QUERY_PROXY_AUTHENTICATE 41 - #define WINHTTP_QUERY_ACCEPT_RANGES 42 - #define WINHTTP_QUERY_SET_COOKIE 43 - #define WINHTTP_QUERY_COOKIE 44 - #define WINHTTP_QUERY_REQUEST_METHOD 45 // special: GET/POST etc. - #define WINHTTP_QUERY_REFRESH 46 - #define WINHTTP_QUERY_CONTENT_DISPOSITION 47 - - // NOTE: WinHttpQueryHeaders prettifiers for optional parameters. - #define WINHTTP_HEADER_NAME_BY_INDEX NULL - #define WINHTTP_NO_OUTPUT_BUFFER NULL - #define WINHTTP_NO_HEADER_INDEX NULL - - // NOTE: Http Response Status Codes - #define HTTP_STATUS_CONTINUE 100 // OK to continue with request - #define HTTP_STATUS_SWITCH_PROTOCOLS 101 // server has switched protocols in upgrade header - - #define HTTP_STATUS_OK 200 // request completed - #define HTTP_STATUS_CREATED 201 // object created, reason = new URI - #define HTTP_STATUS_ACCEPTED 202 // async completion (TBS) - #define HTTP_STATUS_PARTIAL 203 // partial completion - #define HTTP_STATUS_NO_CONTENT 204 // no info to return - #define HTTP_STATUS_RESET_CONTENT 205 // request completed, but clear form - #define HTTP_STATUS_PARTIAL_CONTENT 206 // partial GET fulfilled - #define HTTP_STATUS_WEBDAV_MULTI_STATUS 207 // WebDAV Multi-Status - - #define HTTP_STATUS_AMBIGUOUS 300 // server couldn't decide what to return - #define HTTP_STATUS_MOVED 301 // object permanently moved - #define HTTP_STATUS_REDIRECT 302 // object temporarily moved - #define HTTP_STATUS_REDIRECT_METHOD 303 // redirection w/ new access method - #define HTTP_STATUS_NOT_MODIFIED 304 // if-modified-since was not modified - #define HTTP_STATUS_USE_PROXY 305 // redirection to proxy, location header specifies proxy to use - #define HTTP_STATUS_REDIRECT_KEEP_VERB 307 // HTTP/1.1: keep same verb - #define HTTP_STATUS_PERMANENT_REDIRECT 308 // Object permanently moved keep verb - - #define HTTP_STATUS_BAD_REQUEST 400 // invalid syntax - #define HTTP_STATUS_DENIED 401 // access denied - #define HTTP_STATUS_PAYMENT_REQ 402 // payment required - #define HTTP_STATUS_FORBIDDEN 403 // request forbidden - #define HTTP_STATUS_NOT_FOUND 404 // object not found - #define HTTP_STATUS_BAD_METHOD 405 // method is not allowed - #define HTTP_STATUS_NONE_ACCEPTABLE 406 // no response acceptable to client found - #define HTTP_STATUS_PROXY_AUTH_REQ 407 // proxy authentication required - #define HTTP_STATUS_REQUEST_TIMEOUT 408 // server timed out waiting for request - #define HTTP_STATUS_CONFLICT 409 // user should resubmit with more info - #define HTTP_STATUS_GONE 410 // the resource is no longer available - #define HTTP_STATUS_LENGTH_REQUIRED 411 // the server refused to accept request w/o a length - #define HTTP_STATUS_PRECOND_FAILED 412 // precondition given in request failed - #define HTTP_STATUS_REQUEST_TOO_LARGE 413 // request entity was too large - #define HTTP_STATUS_URI_TOO_LONG 414 // request URI too long - #define HTTP_STATUS_UNSUPPORTED_MEDIA 415 // unsupported media type - #define HTTP_STATUS_RETRY_WITH 449 // retry after doing the appropriate action. - - #define HTTP_STATUS_SERVER_ERROR 500 // internal server error - #define HTTP_STATUS_NOT_SUPPORTED 501 // required not supported - #define HTTP_STATUS_BAD_GATEWAY 502 // error response received from gateway - #define HTTP_STATUS_SERVICE_UNAVAIL 503 // temporarily overloaded - #define HTTP_STATUS_GATEWAY_TIMEOUT 504 // timed out waiting for gateway - #define HTTP_STATUS_VERSION_NOT_SUP 505 // HTTP version not supported - - #define HTTP_STATUS_FIRST HTTP_STATUS_CONTINUE - #define HTTP_STATUS_LAST HTTP_STATUS_VERSION_NOT_SUP - - #define WINHTTP_CALLBACK_STATUS_RESOLVING_NAME 0x00000001 - #define WINHTTP_CALLBACK_STATUS_NAME_RESOLVED 0x00000002 - #define WINHTTP_CALLBACK_STATUS_CONNECTING_TO_SERVER 0x00000004 - #define WINHTTP_CALLBACK_STATUS_CONNECTED_TO_SERVER 0x00000008 - #define WINHTTP_CALLBACK_STATUS_SENDING_REQUEST 0x00000010 - #define WINHTTP_CALLBACK_STATUS_REQUEST_SENT 0x00000020 - #define WINHTTP_CALLBACK_STATUS_RECEIVING_RESPONSE 0x00000040 - #define WINHTTP_CALLBACK_STATUS_RESPONSE_RECEIVED 0x00000080 - #define WINHTTP_CALLBACK_STATUS_CLOSING_CONNECTION 0x00000100 - #define WINHTTP_CALLBACK_STATUS_CONNECTION_CLOSED 0x00000200 - #define WINHTTP_CALLBACK_STATUS_HANDLE_CREATED 0x00000400 - #define WINHTTP_CALLBACK_STATUS_HANDLE_CLOSING 0x00000800 - #define WINHTTP_CALLBACK_STATUS_DETECTING_PROXY 0x00001000 - #define WINHTTP_CALLBACK_STATUS_REDIRECT 0x00004000 - #define WINHTTP_CALLBACK_STATUS_INTERMEDIATE_RESPONSE 0x00008000 - #define WINHTTP_CALLBACK_STATUS_SECURE_FAILURE 0x00010000 - #define WINHTTP_CALLBACK_STATUS_HEADERS_AVAILABLE 0x00020000 - #define WINHTTP_CALLBACK_STATUS_DATA_AVAILABLE 0x00040000 - #define WINHTTP_CALLBACK_STATUS_READ_COMPLETE 0x00080000 - #define WINHTTP_CALLBACK_STATUS_WRITE_COMPLETE 0x00100000 - #define WINHTTP_CALLBACK_STATUS_REQUEST_ERROR 0x00200000 - #define WINHTTP_CALLBACK_STATUS_SENDREQUEST_COMPLETE 0x00400000 - - #define WINHTTP_CALLBACK_STATUS_GETPROXYFORURL_COMPLETE 0x01000000 - #define WINHTTP_CALLBACK_STATUS_CLOSE_COMPLETE 0x02000000 - #define WINHTTP_CALLBACK_STATUS_SHUTDOWN_COMPLETE 0x04000000 - #define WINHTTP_CALLBACK_STATUS_SETTINGS_WRITE_COMPLETE 0x10000000 - #define WINHTTP_CALLBACK_STATUS_SETTINGS_READ_COMPLETE 0x20000000 - - #define WINHTTP_CALLBACK_FLAG_RESOLVE_NAME (WINHTTP_CALLBACK_STATUS_RESOLVING_NAME | WINHTTP_CALLBACK_STATUS_NAME_RESOLVED) - #define WINHTTP_CALLBACK_FLAG_CONNECT_TO_SERVER (WINHTTP_CALLBACK_STATUS_CONNECTING_TO_SERVER | WINHTTP_CALLBACK_STATUS_CONNECTED_TO_SERVER) - #define WINHTTP_CALLBACK_FLAG_SEND_REQUEST (WINHTTP_CALLBACK_STATUS_SENDING_REQUEST | WINHTTP_CALLBACK_STATUS_REQUEST_SENT) - #define WINHTTP_CALLBACK_FLAG_RECEIVE_RESPONSE (WINHTTP_CALLBACK_STATUS_RECEIVING_RESPONSE | WINHTTP_CALLBACK_STATUS_RESPONSE_RECEIVED) - #define WINHTTP_CALLBACK_FLAG_CLOSE_CONNECTION (WINHTTP_CALLBACK_STATUS_CLOSING_CONNECTION | WINHTTP_CALLBACK_STATUS_CONNECTION_CLOSED) - #define WINHTTP_CALLBACK_FLAG_HANDLES (WINHTTP_CALLBACK_STATUS_HANDLE_CREATED | WINHTTP_CALLBACK_STATUS_HANDLE_CLOSING) - #define WINHTTP_CALLBACK_FLAG_DETECTING_PROXY WINHTTP_CALLBACK_STATUS_DETECTING_PROXY - #define WINHTTP_CALLBACK_FLAG_REDIRECT WINHTTP_CALLBACK_STATUS_REDIRECT - #define WINHTTP_CALLBACK_FLAG_INTERMEDIATE_RESPONSE WINHTTP_CALLBACK_STATUS_INTERMEDIATE_RESPONSE - #define WINHTTP_CALLBACK_FLAG_SECURE_FAILURE WINHTTP_CALLBACK_STATUS_SECURE_FAILURE - #define WINHTTP_CALLBACK_FLAG_SENDREQUEST_COMPLETE WINHTTP_CALLBACK_STATUS_SENDREQUEST_COMPLETE - #define WINHTTP_CALLBACK_FLAG_HEADERS_AVAILABLE WINHTTP_CALLBACK_STATUS_HEADERS_AVAILABLE - #define WINHTTP_CALLBACK_FLAG_DATA_AVAILABLE WINHTTP_CALLBACK_STATUS_DATA_AVAILABLE - #define WINHTTP_CALLBACK_FLAG_READ_COMPLETE WINHTTP_CALLBACK_STATUS_READ_COMPLETE - #define WINHTTP_CALLBACK_FLAG_WRITE_COMPLETE WINHTTP_CALLBACK_STATUS_WRITE_COMPLETE - #define WINHTTP_CALLBACK_FLAG_REQUEST_ERROR WINHTTP_CALLBACK_STATUS_REQUEST_ERROR - - #define WINHTTP_CALLBACK_FLAG_GETPROXYFORURL_COMPLETE WINHTTP_CALLBACK_STATUS_GETPROXYFORURL_COMPLETE - - #define WINHTTP_CALLBACK_FLAG_ALL_COMPLETIONS (WINHTTP_CALLBACK_STATUS_SENDREQUEST_COMPLETE \ - | WINHTTP_CALLBACK_STATUS_HEADERS_AVAILABLE \ - | WINHTTP_CALLBACK_STATUS_DATA_AVAILABLE \ - | WINHTTP_CALLBACK_STATUS_READ_COMPLETE \ - | WINHTTP_CALLBACK_STATUS_WRITE_COMPLETE \ - | WINHTTP_CALLBACK_STATUS_REQUEST_ERROR \ - | WINHTTP_CALLBACK_STATUS_GETPROXYFORURL_COMPLETE) - - #define WINHTTP_CALLBACK_FLAG_ALL_NOTIFICATIONS 0xffffffff - #define WINHTTP_INVALID_STATUS_CALLBACK ((WINHTTP_STATUS_CALLBACK)(-1L)) - - typedef struct _WINHTTP_EXTENDED_HEADER - { - union - { - CHAR const *pwszName; - WCHAR const *pszName; - }; - union - { - WCHAR const *pwszValue; - CHAR const *pszValue; - }; - } WINHTTP_EXTENDED_HEADER, *PWINHTTP_EXTENDED_HEADER; - - typedef struct _WINHTTP_ASYNC_RESULT - { - DWORD *dwResult; // indicates which async API has encountered an error - DWORD dwError; // the error code if the API failed - } WINHTTP_ASYNC_RESULT, *LPWINHTTP_ASYNC_RESULT, *PWINHTTP_ASYNC_RESULT; - - typedef - VOID - (*WINHTTP_STATUS_CALLBACK)( - HINTERNET hInternet, - DWORD *dwContext, - DWORD dwInternetStatus, - VOID *lpvStatusInformation, - DWORD dwStatusInformationLength - ); - - extern "C" - { - __declspec(dllimport) HINTERNET __stdcall WinHttpOpen(WCHAR const *pszAgentW, DWORD dwAccessType, WCHAR const *pszProxyW, WCHAR const *pszProxyBypassW, DWORD dwFlags); - __declspec(dllimport) BOOL __stdcall WinHttpCloseHandle(HINTERNET hInternet); - __declspec(dllimport) HINTERNET __stdcall WinHttpConnect(HINTERNET hSession, WCHAR const *pswzServerName, INTERNET_PORT nServerPort, DWORD dwReserved); - __declspec(dllimport) BOOL __stdcall WinHttpReadData(HINTERNET hRequest, VOID *lpBuffer, DWORD dwNumberOfBytesToRead, DWORD *lpdwNumberOfBytesRead); - __declspec(dllimport) HINTERNET __stdcall WinHttpOpenRequest(HINTERNET hConnect, WCHAR const *pwszVerb, WCHAR const *pwszObjectName, WCHAR const *pwszVersion, WCHAR const *pwszReferrer, WCHAR const *ppwszAcceptTypes, DWORD dwFlags); - __declspec(dllimport) BOOL __stdcall WinHttpSendRequest(HINTERNET hRequest, WCHAR const *lpszHeaders, DWORD dwHeadersLength, VOID *lpOptional, DWORD dwOptionalLength, DWORD dwTotalLength, DWORD_PTR dwContext); - __declspec(dllimport) DWORD __stdcall WinHttpAddRequestHeadersEx(HINTERNET hRequest, DWORD dwModifiers, ULONGLONG ullFlags, ULONGLONG ullExtra, DWORD cHeaders, WINHTTP_EXTENDED_HEADER *pHeaders); - __declspec(dllimport) BOOL __stdcall WinHttpSetCredentials(HINTERNET hRequest, // HINTERNET handle returned by WinHttpOpenRequest. - DWORD AuthTargets, // Only WINHTTP_AUTH_TARGET_SERVER and WINHTTP_AUTH_TARGET_PROXY are supported in this version and they are mutually exclusive - DWORD AuthScheme, // must be one of the supported Auth Schemes returned from WinHttpQueryAuthSchemes() - WCHAR * pwszUserName, // 1) NULL if default creds is to be used, in which case pszPassword will be ignored - WCHAR * pwszPassword, // 1) "" == Blank Password; 2)Parameter ignored if pszUserName is NULL; 3) Invalid to pass in NULL if pszUserName is not NULL - VOID * pAuthParams); - __declspec(dllimport) BOOL __stdcall WinHttpQueryHeaders(HINTERNET hRequest, DWORD dwInfoLevel, WCHAR const *pwszName, VOID *lpBuffer, DWORD *lpdwBufferLength, DWORD *lpdwIndex); - __declspec(dllimport) BOOL __stdcall WinHttpReceiveResponse(HINTERNET hRequest, VOID *lpReserved); - __declspec(dllimport) WINHTTP_STATUS_CALLBACK __stdcall WinHttpSetStatusCallback(HINTERNET hInternet, WINHTTP_STATUS_CALLBACK lpfnInternetCallback, DWORD dwNotificationFlags, DWORD_PTR dwReserved); - } - - // NOTE: um/DbgHelp.h ////////////////////////////////////////////////////////////////////////// - #define SYMOPT_CASE_INSENSITIVE 0x00000001 - #define SYMOPT_UNDNAME 0x00000002 - #define SYMOPT_DEFERRED_LOADS 0x00000004 - #define SYMOPT_NO_CPP 0x00000008 - #define SYMOPT_LOAD_LINES 0x00000010 - #define SYMOPT_OMAP_FIND_NEAREST 0x00000020 - #define SYMOPT_LOAD_ANYTHING 0x00000040 - #define SYMOPT_IGNORE_CVREC 0x00000080 - #define SYMOPT_NO_UNQUALIFIED_LOADS 0x00000100 - #define SYMOPT_FAIL_CRITICAL_ERRORS 0x00000200 - #define SYMOPT_EXACT_SYMBOLS 0x00000400 - #define SYMOPT_ALLOW_ABSOLUTE_SYMBOLS 0x00000800 - #define SYMOPT_IGNORE_NT_SYMPATH 0x00001000 - #define SYMOPT_INCLUDE_32BIT_MODULES 0x00002000 - #define SYMOPT_PUBLICS_ONLY 0x00004000 - #define SYMOPT_NO_PUBLICS 0x00008000 - #define SYMOPT_AUTO_PUBLICS 0x00010000 - #define SYMOPT_NO_IMAGE_SEARCH 0x00020000 - #define SYMOPT_SECURE 0x00040000 - #define SYMOPT_NO_PROMPTS 0x00080000 - #define SYMOPT_OVERWRITE 0x00100000 - #define SYMOPT_IGNORE_IMAGEDIR 0x00200000 - #define SYMOPT_FLAT_DIRECTORY 0x00400000 - #define SYMOPT_FAVOR_COMPRESSED 0x00800000 - #define SYMOPT_ALLOW_ZERO_ADDRESS 0x01000000 - #define SYMOPT_DISABLE_SYMSRV_AUTODETECT 0x02000000 - #define SYMOPT_READONLY_CACHE 0x04000000 - #define SYMOPT_SYMPATH_LAST 0x08000000 - #define SYMOPT_DISABLE_FAST_SYMBOLS 0x10000000 - #define SYMOPT_DISABLE_SYMSRV_TIMEOUT 0x20000000 - #define SYMOPT_DISABLE_SRVSTAR_ON_STARTUP 0x40000000 - #define SYMOPT_DEBUG 0x80000000 - - #define MAX_SYM_NAME 2000 - - typedef enum { - AddrMode1616, - AddrMode1632, - AddrModeReal, - AddrModeFlat - } ADDRESS_MODE; - - typedef struct _tagADDRESS64 { - DWORD64 Offset; - WORD Segment; - ADDRESS_MODE Mode; - } ADDRESS64, *LPADDRESS64; - - - typedef struct _KDHELP64 { - DWORD64 Thread; - DWORD ThCallbackStack; - DWORD ThCallbackBStore; - DWORD NextCallback; - DWORD FramePointer; - DWORD64 KiCallUserMode; - DWORD64 KeUserCallbackDispatcher; - DWORD64 SystemRangeStart; - DWORD64 KiUserExceptionDispatcher; - DWORD64 StackBase; - DWORD64 StackLimit; - DWORD BuildVersion; - DWORD RetpolineStubFunctionTableSize; - DWORD64 RetpolineStubFunctionTable; - DWORD RetpolineStubOffset; - DWORD RetpolineStubSize; - DWORD64 Reserved0[2]; - } KDHELP64, *PKDHELP64; - - typedef struct _tagSTACKFRAME64 { - ADDRESS64 AddrPC; // program counter - ADDRESS64 AddrReturn; // return address - ADDRESS64 AddrFrame; // frame pointer - ADDRESS64 AddrStack; // stack pointer - ADDRESS64 AddrBStore; // backing store pointer - VOID *FuncTableEntry; // pointer to pdata/fpo or NULL - DWORD64 Params[4]; // possible arguments to the function - BOOL Far; // WOW far call - BOOL Virtual; // is this a virtual frame? - DWORD64 Reserved[3]; - KDHELP64 KdHelp; - } STACKFRAME64; - - typedef struct _IMAGEHLP_LINEW64 { - DWORD SizeOfStruct; // set to sizeof(IMAGEHLP_LINE64) - VOID *Key; // internal - DWORD LineNumber; // line number in file - WCHAR *FileName; // full filename - DWORD64 Address; // first instruction of line - } IMAGEHLP_LINEW64; - - typedef struct _SYMBOL_INFOW { - ULONG SizeOfStruct; - ULONG TypeIndex; // Type Index of symbol - ULONG64 Reserved[2]; - ULONG Index; - ULONG Size; - ULONG64 ModBase; // Base Address of module comtaining this symbol - ULONG Flags; - ULONG64 Value; // Value of symbol, ValuePresent should be 1 - ULONG64 Address; // Address of symbol including base address of module - ULONG Register; // register holding value or pointer to value - ULONG Scope; // scope of the symbol - ULONG Tag; // pdb classification - ULONG NameLen; // Actual length of name - ULONG MaxNameLen; - WCHAR Name[1]; // Name of symbol - } SYMBOL_INFOW; - - typedef BOOL (__stdcall READ_PROCESS_MEMORY_ROUTINE64)(HANDLE hProcess, DWORD64 qwBaseAddress, VOID *lpBuffer, DWORD nSize, DWORD *lpNumberOfBytesRead); - typedef VOID * (__stdcall FUNCTION_TABLE_ACCESS_ROUTINE64)(HANDLE ahProcess, DWORD64 AddrBase); - typedef DWORD64(__stdcall GET_MODULE_BASE_ROUTINE64)(HANDLE hProcess, DWORD64 Address); - typedef DWORD64(__stdcall TRANSLATE_ADDRESS_ROUTINE64)(HANDLE hProcess, HANDLE hThread, ADDRESS64 *lpaddr); - - extern "C" - { - __declspec(dllimport) BOOL __stdcall StackWalk64 (DWORD MachineType, HANDLE hProcess, HANDLE hThread, STACKFRAME64 *StackFrame, VOID *ContextRecord, READ_PROCESS_MEMORY_ROUTINE64 *ReadMemoryRoutine, FUNCTION_TABLE_ACCESS_ROUTINE64 *FunctionTableAccessRoutine, GET_MODULE_BASE_ROUTINE64 *GetModuleBaseRoutine, TRANSLATE_ADDRESS_ROUTINE64 *TranslateAddress); - __declspec(dllimport) BOOL __stdcall SymFromAddrW (HANDLE hProcess, DWORD64 Address, DWORD64 *Displacement, SYMBOL_INFOW *Symbol); - __declspec(dllimport) VOID * __stdcall SymFunctionTableAccess64(HANDLE hProcess, DWORD64 AddrBase); - __declspec(dllimport) BOOL __stdcall SymGetLineFromAddrW64 (HANDLE hProcess, DWORD64 dwAddr, DWORD *pdwDisplacement, IMAGEHLP_LINEW64 *Line); - __declspec(dllimport) DWORD64 __stdcall SymGetModuleBase64 (HANDLE hProcess, DWORD64 qwAddr); - __declspec(dllimport) BOOL __stdcall SymRefreshModuleList (HANDLE hProcess); - }; - - // NOTE: um/errhandlingapi.h /////////////////////////////////////////////////////////////////// - extern "C" - { - __declspec(dllimport) DWORD __stdcall GetLastError(VOID); - } - - // NOTE: um/libloaderapi.h ///////////////////////////////////////////////////////////////////// - extern "C" - { - __declspec(dllimport) HMODULE __stdcall LoadLibraryA (const CHAR *lpLibFileName); - __declspec(dllimport) BOOL __stdcall FreeLibrary (HMODULE hLibModule); - __declspec(dllimport) void * __stdcall GetProcAddress (HMODULE hModule, const CHAR *lpProcName); - __declspec(dllimport) HMODULE __stdcall GetModuleHandleA (const CHAR *lpModuleName); - __declspec(dllimport) DWORD __stdcall GetModuleFileNameW(HMODULE hModule, WCHAR *lpFilename, DWORD nSize); - } - - // NOTE: um/synchapi.h ///////////////////////////////////////////////////////////////////////// - typedef RTL_CONDITION_VARIABLE CONDITION_VARIABLE, *PCONDITION_VARIABLE; - - extern "C" - { - __declspec(dllimport) VOID __stdcall InitializeConditionVariable (CONDITION_VARIABLE *ConditionVariable); - __declspec(dllimport) VOID __stdcall WakeConditionVariable (CONDITION_VARIABLE *ConditionVariable); - __declspec(dllimport) VOID __stdcall WakeAllConditionVariable (CONDITION_VARIABLE *ConditionVariable); - __declspec(dllimport) BOOL __stdcall SleepConditionVariableCS (CONDITION_VARIABLE *ConditionVariable, CRITICAL_SECTION *CriticalSection, DWORD dwMilliseconds); - - __declspec(dllimport) VOID __stdcall InitializeCriticalSection (CRITICAL_SECTION *lpCriticalSection); - __declspec(dllimport) VOID __stdcall EnterCriticalSection (CRITICAL_SECTION *lpCriticalSection); - __declspec(dllimport) VOID __stdcall LeaveCriticalSection (CRITICAL_SECTION *lpCriticalSection); - __declspec(dllimport) BOOL __stdcall InitializeCriticalSectionAndSpinCount(CRITICAL_SECTION *lpCriticalSection, DWORD dwSpinCount); - __declspec(dllimport) BOOL __stdcall InitializeCriticalSectionEx (CRITICAL_SECTION *lpCriticalSection, DWORD dwSpinCount, DWORD Flags); - __declspec(dllimport) DWORD __stdcall SetCriticalSectionSpinCount (CRITICAL_SECTION *lpCriticalSection, DWORD dwSpinCount); - __declspec(dllimport) BOOL __stdcall TryEnterCriticalSection (CRITICAL_SECTION *lpCriticalSection); - __declspec(dllimport) VOID __stdcall DeleteCriticalSection (CRITICAL_SECTION *lpCriticalSection); - - __declspec(dllimport) DWORD __stdcall WaitForSingleObject (HANDLE hHandle, DWORD dwMilliseconds); - __declspec(dllimport) BOOL __stdcall ReleaseSemaphore (HANDLE hSemaphore, LONG lReleaseCount, LONG *lpPreviousCount); - __declspec(dllimport) VOID __stdcall Sleep (DWORD dwMilliseconds); - } - - // NOTE: um/profileapi.h /////////////////////////////////////////////////////////////////////// - extern "C" - { - __declspec(dllimport) BOOL __stdcall QueryPerformanceCounter (LARGE_INTEGER* lpPerformanceCount); - __declspec(dllimport) BOOL __stdcall QueryPerformanceFrequency(LARGE_INTEGER* lpFrequency); - } - - // NOTE: um/processthreadsapi.h //////////////////////////////////////////////////////////////// - typedef struct _PROCESS_INFORMATION { - HANDLE hProcess; - HANDLE hThread; - DWORD dwProcessId; - DWORD dwThreadId; - } PROCESS_INFORMATION, *PPROCESS_INFORMATION, *LPPROCESS_INFORMATION; - - typedef struct _STARTUPINFOW { - DWORD cb; - WCHAR *lpReserved; - WCHAR *lpDesktop; - WCHAR *lpTitle; - DWORD dwX; - DWORD dwY; - DWORD dwXSize; - DWORD dwYSize; - DWORD dwXCountChars; - DWORD dwYCountChars; - DWORD dwFillAttribute; - DWORD dwFlags; - WORD wShowWindow; - WORD cbReserved2; - BYTE *lpReserved2; - HANDLE hStdInput; - HANDLE hStdOutput; - HANDLE hStdError; - } STARTUPINFOW, *LPSTARTUPINFOW; - - typedef DWORD (__stdcall *PTHREAD_START_ROUTINE)( - VOID *lpThreadParameter - ); - typedef PTHREAD_START_ROUTINE LPTHREAD_START_ROUTINE; - - extern "C" - { - __declspec(dllimport) BOOL __stdcall CreateProcessW (WCHAR const *lpApplicationName, WCHAR *lpCommandLine, SECURITY_ATTRIBUTES *lpProcessAttributes, SECURITY_ATTRIBUTES *lpThreadAttributes, BOOL bInheritHandles, DWORD dwCreationFlags, VOID *lpEnvironment, WCHAR const *lpCurrentDirectory, STARTUPINFOW *lpStartupInfo, PROCESS_INFORMATION *lpProcessInformation); - __declspec(dllimport) HANDLE __stdcall CreateThread (SECURITY_ATTRIBUTES *lpThreadAttributes, SIZE_T dwStackSize, PTHREAD_START_ROUTINE lpStartAddress, VOID *lpParameter, DWORD dwCreationFlags, DWORD *lpThreadId); - __declspec(dllimport) DWORD __stdcall GetCurrentThreadId(VOID); - __declspec(dllimport) BOOL __stdcall GetExitCodeProcess(HANDLE hProcess, DWORD *lpExitCode); - __declspec(dllimport) void __stdcall ExitProcess (UINT uExitCode); - } - - // NOTE: um/memoryapi.h //////////////////////////////////////////////////////////////////////// - extern "C" - { - __declspec(dllimport) VOID * __stdcall VirtualAlloc (VOID *lpAddress, SIZE_T dwSize, DWORD flAllocationType, DWORD flProtect); - __declspec(dllimport) BOOL __stdcall VirtualProtect(VOID *lpAddress, SIZE_T dwSize, DWORD flNewProtect, DWORD *lpflOldProtect); - __declspec(dllimport) BOOL __stdcall VirtualFree (VOID *lpAddress, SIZE_T dwSize, DWORD dwFreeType); - } - - // NOTE: shared/bcrypt.h /////////////////////////////////////////////////////////////////////// - typedef VOID *BCRYPT_ALG_HANDLE; - typedef LONG NTSTATUS; - - extern "C" - { - __declspec(dllimport) NTSTATUS __stdcall BCryptOpenAlgorithmProvider(BCRYPT_ALG_HANDLE *phAlgorithm, const WCHAR *pszAlgId, const WCHAR *pszImplementation, ULONG dwFlags); - __declspec(dllimport) NTSTATUS __stdcall BCryptGenRandom (BCRYPT_ALG_HANDLE hAlgorithm, UCHAR *pbBuffer, ULONG cbBuffer, ULONG dwFlags); - } - - // NOTE: um/shellapi.h ///////////////////////////////////////////////////////////////////////// - extern "C" - { - __declspec(dllimport) HINSTANCE __stdcall ShellExecuteA(HWND hwnd, CHAR const *lpOperation, CHAR const *lpFile, CHAR const *lpParameters, CHAR const *lpDirectory, INT nShowCmd); - __declspec(dllimport) HINSTANCE __stdcall ShellExecuteW(HWND hwnd, WCHAR const *lpOperation, WCHAR const *lpFile, WCHAR const *lpParameters, WCHAR const *lpDirectory, INT nShowCmd); - } - - // NOTE: um/debugapi.h ///////////////////////////////////////////////////////////////////////// - extern "C" - { - __declspec(dllimport) BOOL __stdcall IsDebuggerPresent(); - } - - // NOTE: um/namedpipeapi.h ///////////////////////////////////////////////////////////////////// - extern "C" - { - __declspec(dllimport) BOOL __stdcall CreatePipe (HANDLE *hReadPipe, HANDLE *hWritePipe, LPSECURITY_ATTRIBUTES lpPipeAttributes, DWORD nSize); - __declspec(dllimport) BOOL __stdcall PeekNamedPipe(HANDLE hNamedPipe, VOID *lpBuffer, DWORD nBufferSize, DWORD *lpBytesRead, DWORD *lpTotalBytesAvail, DWORD *lpBytesLeftThisMessage); - } - - // NOTE: um/handleapi.h //////////////////////////////////////////////////////////////////////// - extern "C" - { - __declspec(dllimport) BOOL __stdcall SetHandleInformation(HANDLE hObject, DWORD dwMask, DWORD dwFlags); - } - - // NOTE: um/commdlg.h ////////////////////////////////////////////////////////////////////////// - typedef UINT_PTR (__stdcall *LPOFNHOOKPROC)(HWND, UINT, WPARAM, LPARAM); - typedef struct tagOFNW { - DWORD lStructSize; - HWND hwndOwner; - HINSTANCE hInstance; - WCHAR const * lpstrFilter; - LPWSTR lpstrCustomFilter; - DWORD nMaxCustFilter; - DWORD nFilterIndex; - LPWSTR lpstrFile; - DWORD nMaxFile; - LPWSTR lpstrFileTitle; - DWORD nMaxFileTitle; - WCHAR const * lpstrInitialDir; - WCHAR const * lpstrTitle; - DWORD Flags; - WORD nFileOffset; - WORD nFileExtension; - WCHAR const * lpstrDefExt; - LPARAM lCustData; - LPOFNHOOKPROC lpfnHook; - WCHAR const * lpTemplateName; - #ifdef _MAC - LPEDITMENU lpEditInfo; - LPCSTR lpstrPrompt; - #endif - #if (_WIN32_WINNT >= 0x0500) - void * pvReserved; - DWORD dwReserved; - DWORD FlagsEx; - #endif // (_WIN32_WINNT >= 0x0500) - } OPENFILENAMEW, *LPOPENFILENAMEW; - - - #define OFN_READONLY 0x00000001 - #define OFN_OVERWRITEPROMPT 0x00000002 - #define OFN_HIDEREADONLY 0x00000004 - #define OFN_NOCHANGEDIR 0x00000008 - #define OFN_SHOWHELP 0x00000010 - #define OFN_ENABLEHOOK 0x00000020 - #define OFN_ENABLETEMPLATE 0x00000040 - #define OFN_ENABLETEMPLATEHANDLE 0x00000080 - #define OFN_NOVALIDATE 0x00000100 - #define OFN_ALLOWMULTISELECT 0x00000200 - #define OFN_EXTENSIONDIFFERENT 0x00000400 - #define OFN_PATHMUSTEXIST 0x00000800 - #define OFN_FILEMUSTEXIST 0x00001000 - #define OFN_CREATEPROMPT 0x00002000 - #define OFN_SHAREAWARE 0x00004000 - #define OFN_NOREADONLYRETURN 0x00008000 - #define OFN_NOTESTFILECREATE 0x00010000 - #define OFN_NONETWORKBUTTON 0x00020000 - #define OFN_NOLONGNAMES 0x00040000 // force no long names for 4.x modules - #if(WINVER >= 0x0400) - #define OFN_EXPLORER 0x00080000 // new look commdlg - #define OFN_NODEREFERENCELINKS 0x00100000 - #define OFN_LONGNAMES 0x00200000 // force long names for 3.x modules - // OFN_ENABLEINCLUDENOTIFY and OFN_ENABLESIZING require - // Windows 2000 or higher to have any effect. - #define OFN_ENABLEINCLUDENOTIFY 0x00400000 // send include message to callback - #define OFN_ENABLESIZING 0x00800000 - #endif /* WINVER >= 0x0400 */ - #if (_WIN32_WINNT >= 0x0500) - #define OFN_DONTADDTORECENT 0x02000000 - #define OFN_FORCESHOWHIDDEN 0x10000000 // Show All files including System and hidden files - #endif // (_WIN32_WINNT >= 0x0500) - - //FlagsEx Values - #if (_WIN32_WINNT >= 0x0500) - #define OFN_EX_NOPLACESBAR 0x00000001 - #endif // (_WIN32_WINNT >= 0x0500) - - extern "C" - { - __declspec(dllimport) BOOL __stdcall GetSaveFileNameW(LPOPENFILENAMEW); - __declspec(dllimport) BOOL __stdcall GetOpenFileNameW(LPOPENFILENAMEW); - } - - // NOTE: um/shlwapi.h ////////////////////////////////////////////////////////////////////////// - extern "C" - { - __declspec(dllimport) BOOL __stdcall PathRelativePathToW(WCHAR *pszPath, WCHAR const *pszFrom, DWORD dwAttrFrom, WCHAR const *pszTo, DWORD dwAttrTo); - __declspec(dllimport) BOOL __stdcall PathIsRelativeW(WCHAR *pszPath); - } - - // NOTE: um/pathcch.h ////////////////////////////////////////////////////////////////////////// - typedef enum PATHCCH_OPTIONS - { - PATHCCH_NONE = 0x0, - - // This option allows applications to gain access to long paths. It has two - // different behaviors. For process configured to enable long paths it will allow - // the returned path to be longer than the max path limit that is normally imposed. - // For process that are not this option will convert long paths into the extended - // length DOS device form (with \\?\ prefix) when the path is longer than the limit. - // This form is not length limited by the Win32 file system API on all versions of Windows. - // This second behavior is the same behavior for OSes that don't have the long path feature. - // This can not be specified with PATHCCH_ENSURE_IS_EXTENDED_LENGTH_PATH. - PATHCCH_ALLOW_LONG_PATHS = 0x01, - - // Can only be used when PATHCCH_ALLOW_LONG_PATHS is specified. This - // Forces the API to treat the caller as long path enabled, independent of the - // process's long name enabled state. Cannot be used with PATHCCH_FORCE_DISABLE_LONG_NAME_PROCESS. - PATHCCH_FORCE_ENABLE_LONG_NAME_PROCESS = 0x02, - - // Can only be used when PATHCCH_ALLOW_LONG_PATHS is specified. This - // Forces the API to treat the caller as long path disabled, independent of the - // process's long name enabled state. Cannot be used with PATHCCH_FORCE_ENABLE_LONG_NAME_PROCESS. - PATHCCH_FORCE_DISABLE_LONG_NAME_PROCESS = 0x04, - - // Disable the normalization of path segments that includes removing trailing dots and spaces. - // This enables access to paths that win32 path normalization will block. - PATHCCH_DO_NOT_NORMALIZE_SEGMENTS = 0x08, - - // Convert the input path into the extended length DOS device path form (with the \\?\ prefix) - // if not already in that form. This enables access to paths that are otherwise not addressable - // due to Win32 normalization rules (that can strip trailing dots and spaces) and path - // length limitations. This option implies the same behavior of PATHCCH_DO_NOT_NORMALIZE_SEGMENTS. - // This can not be specified with PATHCCH_ALLOW_LONG_PATHS. - PATHCCH_ENSURE_IS_EXTENDED_LENGTH_PATH = 0x10, - - // When combining or normalizing a path ensure there is a trailing backslash. - PATHCCH_ENSURE_TRAILING_SLASH = 0x020, - - // Convert forward slashes to back slashes and collapse multiple slashes. - // This is needed to to support sub-path or identity comparisons. - PATHCCH_CANONICALIZE_SLASHES = 0x040, - } PATHCCH_OPTIONS; - - extern "C" - { - __declspec(dllimport) HRESULT __stdcall PathCchCanonicalizeEx(PWSTR pszPathOut, size_t cchPathOut, WCHAR const *pszPathIn, ULONG dwFlags); - }; - - // NOTE: um/errhandlingapi.h /////////////////////////////////////////////////////////////////// - extern "C" - { - __declspec(dllimport) VOID __stdcall RaiseException(DWORD dwExceptionCode, DWORD dwExceptionFlags, DWORD nNumberOfArguments, const ULONG_PTR* lpArguments); - }; - - // NOTE: include/excpt.h /////////////////////////////////////////////////////////////////// - #define EXCEPTION_EXECUTE_HANDLER 1 - #define EXCEPTION_CONTINUE_SEARCH 0 - #define EXCEPTION_CONTINUE_EXECUTION (-1) - - DN_MSVC_WARNING_POP -#endif // !defined(_INC_WINDOWS) -#endif // !defined(DN_OS_WINDOWS_H) -#endif - -struct DN_W32Error -{ - unsigned long code; - DN_Str8 msg; -}; - -struct DN_W32FolderIteratorW -{ - void *handle; - DN_Str16 file_name; - wchar_t file_name_buf[512]; -}; - -enum DN_W32SyncPrimitiveType -{ - DN_OSW32SyncPrimitiveType_Semaphore, - DN_OSW32SyncPrimitiveType_Mutex, - DN_OSW32SyncPrimitiveType_ConditionVariable, -}; - -struct DN_W32SyncPrimitive -{ - union - { - void *sem; - CRITICAL_SECTION mutex; - CONDITION_VARIABLE cv; - }; - - DN_W32SyncPrimitive *next; -}; - -typedef HRESULT DN_W32SetThreadDescriptionFunc(HANDLE hThread, PWSTR const lpThreadDescription); -struct DN_W32Core -{ - DN_W32SetThreadDescriptionFunc *set_thread_description; - LARGE_INTEGER qpc_frequency; - void *bcrypt_rng_handle; - bool bcrypt_init_success; - bool sym_initialised; - - CRITICAL_SECTION sync_primitive_free_list_mutex; - DN_W32SyncPrimitive *sync_primitive_free_list; -}; - -DN_API void DN_W32_ThreadSetName (DN_Str8 name); - -DN_API DN_Str16 DN_W32_ErrorCodeToMsg16Alloc(DN_U32 error_code); -DN_API DN_W32Error DN_W32_ErrorCodeToMsg (DN_Arena *arena, DN_U32 error_code); -DN_API DN_W32Error DN_W32_ErrorCodeToMsgAlloc (DN_U32 error_code); -DN_API DN_W32Error DN_W32_LastError (DN_Arena *arena); -DN_API DN_W32Error DN_W32_LastErrorAlloc (); -DN_API void DN_W32_MakeProcessDPIAware (); - -// NOTE: Windows Str8 <-> Str16 //////////////////////////////////////////////////////////////////// -DN_API DN_Str16 DN_W32_Str8ToStr16 (DN_Arena *arena, DN_Str8 src); -DN_API int DN_W32_Str8ToStr16Buffer (DN_Str16 src, char *dest, int dest_size); -DN_API DN_Str8 DN_W32_Str16ToStr8 (DN_Arena *arena, DN_Str16 src); -DN_API int DN_W32_Str16ToStr8Buffer (DN_Str16 src, char *dest, int dest_size); -DN_API DN_Str8 DN_W32_Str16ToStr8FromHeap(DN_Str16 src); - -// NOTE: Path navigation /////////////////////////////////////////////////////////////////////////// -DN_API DN_Str16 DN_W32_EXEPathW (DN_Arena *arena); -DN_API DN_Str16 DN_W32_EXEDirW (DN_Arena *arena); -DN_API DN_Str8 DN_W32_WorkingDir (DN_Arena *arena, DN_Str8 suffix); -DN_API DN_Str16 DN_W32_WorkingDirW (DN_Arena *arena, DN_Str16 suffix); -DN_API bool DN_W32_DirWIterate (DN_Str16 path, DN_W32FolderIteratorW *it); -#endif // !defined(DN_OS_WIN32) -#elif defined(DN_PLATFORM_POSIX) || defined(DN_PLATFORM_EMSCRIPTEN) - // DN: Single header generator inlined this file => #include "OS/dn_os_posix.h" -#if !defined(DN_OS_POSIX_H) -#define DN_OS_POSIX_H - -#if defined(_CLANGD) - // DN: Single header generator commented out this header => #include "../dn_base_inc.h" -#endif - -#include -#include - -/* -//////////////////////////////////////////////////////////////////////////////////////////////////// -// -// $$$$$$\ $$$$$$\ $$$$$$$\ $$$$$$\ $$$$$$\ $$$$$$\ $$\ $$\ -// $$ __$$\ $$ __$$\ $$ __$$\ $$ __$$\ $$ __$$\ \_$$ _|$$ | $$ | -// $$ / $$ |$$ / \__| $$ | $$ |$$ / $$ |$$ / \__| $$ | \$$\ $$ | -// $$ | $$ |\$$$$$$\ $$$$$$$ |$$ | $$ |\$$$$$$\ $$ | \$$$$ / -// $$ | $$ | \____$$\ $$ ____/ $$ | $$ | \____$$\ $$ | $$ $$< -// $$ | $$ |$$\ $$ | $$ | $$ | $$ |$$\ $$ | $$ | $$ /\$$\ -// $$$$$$ |\$$$$$$ | $$ | $$$$$$ |\$$$$$$ |$$$$$$\ $$ / $$ | -// \______/ \______/ \__| \______/ \______/ \______|\__| \__| -// -// dn_os_posix.h -// -//////////////////////////////////////////////////////////////////////////////////////////////////// -*/ - -struct DN_POSIXProcSelfStatus -{ - char name[64]; - DN_U8 name_size; - DN_U32 pid; - DN_U64 vm_peak; - DN_U32 vm_size; -}; - -// NOTE: The POSIX implementation disallows copies of synchronisation objects in -// general hence we have to dynamically allocate these primitives to maintain a -// consistent address. -// -// -// Source: The Open Group Base Specifications Issue 7, 2018 edition -// https://pubs.opengroup.org/onlinepubs/9699919799/functions/V2_chap02.html#tag_15_09_09 -// -// 2.9.9 Synchronization Object Copies and Alternative Mappings -// -// For barriers, condition variables, mutexes, and read-write locks, [TSH] -// [Option Start] if the process-shared attribute is set to -// PTHREAD_PROCESS_PRIVATE, [Option End] only the synchronization object at the -// address used to initialize it can be used for performing synchronization. The -// effect of referring to another mapping of the same object when locking, -// unlocking, or destroying the object is undefined. [...] The effect of -// referring to a copy of the object when locking, unlocking, or destroying it -// is undefined. - -enum DN_POSIXSyncPrimitiveType -{ - DN_OSPOSIXSyncPrimitiveType_Semaphore, - DN_OSPOSIXSyncPrimitiveType_Mutex, - DN_OSPOSIXSyncPrimitiveType_ConditionVariable, -}; - -struct DN_POSIXSyncPrimitive -{ - union - { - sem_t sem; - pthread_mutex_t mutex; - pthread_cond_t cv; - }; - DN_POSIXSyncPrimitive *next; -}; - -struct DN_POSIXCore -{ - DN_POSIXSyncPrimitive *sync_primitive_free_list; - pthread_mutex_t sync_primitive_free_list_mutex; - bool clock_monotonic_raw; -}; - -DN_API void DN_Posix_Init(DN_POSIXCore *posix); -DN_API void DN_Posix_ThreadSetName(DN_Str8 name); -DN_API DN_POSIXProcSelfStatus DN_Posix_ProcSelfStatus(); -#endif // !defined(DN_OS_POSIX_H) -#else - #error Please define a platform e.g. 'DN_PLATFORM_WIN32' to enable the correct implementation for platform APIs -#endif - -// DN: Single header generator inlined this file => #include "OS/dn_os_tls.h" -#if !defined(DN_OS_TLS_H) -#define DN_OS_TLS_H - -#if defined(_CLANGD) - // DN: Single header generator commented out this header => #include "../dn_base_inc.h" - // DN: Single header generator commented out this header => #include "../dn_os_inc.h" -#endif - -// NOTE: DN_OSErrSink -enum DN_OSErrSinkMode -{ - DN_OSErrSinkMode_Nil, // Default behaviour to accumulate errors into the sink - DN_OSErrSinkMode_DebugBreakOnEndAndLog, // Debug break (int3) when error is encountered and the sink is ended by the 'end and log' functions. - DN_OSErrSinkMode_ExitOnError, // When an error is encountered, exit the program with the error code of the error that was caught. -}; - -struct DN_OSErrSinkMsg -{ - DN_I32 error_code; - DN_Str8 msg; - DN_CallSite call_site; - DN_OSErrSinkMsg *next; - DN_OSErrSinkMsg *prev; -}; - -struct DN_OSErrSinkNode -{ - DN_CallSite call_site; // Call site that the node was created - DN_OSErrSinkMode mode; // Controls how the sink behaves when an error is registered onto the sink. - DN_OSErrSinkMsg *msg_sentinel; // List of error messages accumulated for the current scope - DN_U64 arena_pos; // Position to reset the arena when the scope is ended -}; - -struct DN_OSErrSink -{ - DN_Arena * arena; // Dedicated allocator from the thread's local storage - DN_OSErrSinkNode stack[128]; // Each entry contains errors accumulated between a [begin, end] region of the active sink. - DN_USize stack_size; -}; - -enum DN_OSTLSArena -{ - DN_OSTLSArena_Main, // NOTE: Arena for permanent allocations - DN_OSTLSArena_ErrorSink, // NOTE: Arena for logging error information for this thread - - // NOTE: Per-thread scratch arenas (2 to prevent aliasing) - DN_OSTLSArena_TMem0, - DN_OSTLSArena_TMem1, - - DN_OSTLSArena_Count, -}; - -struct DN_OSTLS -{ - DN_B32 init; // Flag to track if TLS has been initialised - DN_U64 thread_id; - DN_CallSite call_site; // Stores call-site information when requested by thread - DN_OSErrSink err_sink; // Error handling state - DN_Arena arenas[DN_OSTLSArena_Count]; // Default arenas that the thread has access to implicitly - DN_Arena * arena_stack[8]; // Active stack of arenas push/popped arenas on into the TLS - DN_USize arena_stack_index; - - DN_Arena * frame_arena; - char name[64]; - DN_U8 name_size; -}; - -// Push the temporary memory arena when retrieved, popped when the arena goes -// out of scope. Pushed arenas are used automatically as the allocator in TLS -// suffixed function. -enum DN_OSTLSPushTMem -{ - DN_OSTLSPushTMem_No, - DN_OSTLSPushTMem_Yes, -}; - -struct DN_OSTLSTMem -{ - DN_OSTLSTMem(DN_OSTLS *context, uint8_t context_index, DN_OSTLSPushTMem push_scratch); - ~DN_OSTLSTMem(); - DN_Arena *arena; - DN_B32 destructed; - DN_OSTLSPushTMem push_arena; - DN_ArenaTempMem temp_mem; -}; - -struct DN_OSTLSInitArgs -{ - DN_U64 reserve; - DN_U64 commit; - DN_U64 err_sink_reserve; - DN_U64 err_sink_commit; -}; - -DN_API void DN_OS_TLSInit (DN_OSTLS *tls, DN_OSTLSInitArgs args); -DN_API void DN_OS_TLSDeinit (DN_OSTLS *tls); -DN_API DN_OSTLS * DN_OS_TLSGet (); -DN_API void DN_OS_TLSSetCurrentThreadTLS (DN_OSTLS *tls); -DN_API DN_Arena * DN_OS_TLSArena (); -DN_API DN_OSTLSTMem DN_OS_TLSGetTMem (void const *conflict_arena, DN_OSTLSPushTMem push_tmp_mem); -DN_API void DN_OS_TLSPushArena (DN_Arena *arena); -DN_API void DN_OS_TLSPopArena (); -DN_API DN_Arena * DN_OS_TLSTopArena (); -DN_API void DN_OS_TLSBeginFrame (DN_Arena *frame_arena); -DN_API DN_Arena * DN_OS_TLSFrameArena (); -#define DN_OS_TLSSaveCallSite do { DN_OS_TLSGet()->call_site = DN_CALL_SITE; } while (0) -#define DN_OS_TLSTMem(...) DN_OS_TLSGetTMem(__VA_ARGS__, DN_OSTLSPushTMem_No) -#define DN_OS_TLSPushTMem(...) DN_OS_TLSGetTMem(__VA_ARGS__, DN_OSTLSPushTMem_Yes) - -DN_API DN_OSErrSink * DN_OS_ErrSinkBegin_ (DN_OSErrSinkMode mode, DN_CallSite call_site); -#define DN_OS_ErrSinkBegin(mode) DN_OS_ErrSinkBegin_(mode, DN_CALL_SITE) -#define DN_OS_ErrSinkBeginDefault() DN_OS_ErrSinkBegin(DN_OSErrSinkMode_Nil) -DN_API bool DN_OS_ErrSinkHasError (DN_OSErrSink *err); -DN_API DN_OSErrSinkMsg * DN_OS_ErrSinkEnd (DN_Arena *arena, DN_OSErrSink *err); -DN_API DN_Str8 DN_OS_ErrSinkEndStr8 (DN_Arena *arena, DN_OSErrSink *err); -DN_API void DN_OS_ErrSinkEndAndIgnore (DN_OSErrSink *err); -DN_API bool DN_OS_ErrSinkEndAndLogError_ (DN_OSErrSink *err, DN_CallSite call_site, DN_Str8 msg); -DN_API bool DN_OS_ErrSinkEndAndLogErrorFV_ (DN_OSErrSink *err, DN_CallSite call_site, DN_FMT_ATTRIB char const *fmt, va_list args); -DN_API bool DN_OS_ErrSinkEndAndLogErrorF_ (DN_OSErrSink *err, DN_CallSite call_site, DN_FMT_ATTRIB char const *fmt, ...); -DN_API void DN_OS_ErrSinkEndAndExitIfErrorF_ (DN_OSErrSink *err, DN_CallSite call_site, DN_U32 exit_val, DN_FMT_ATTRIB char const *fmt, ...); -DN_API void DN_OS_ErrSinkEndAndExitIfErrorFV_ (DN_OSErrSink *err, DN_CallSite call_site, DN_U32 exit_val, DN_FMT_ATTRIB char const *fmt, va_list args); -DN_API void DN_OS_ErrSinkAppendFV_ (DN_OSErrSink *err, DN_U32 error_code, DN_FMT_ATTRIB char const *fmt, va_list args); -DN_API void DN_OS_ErrSinkAppendF_ (DN_OSErrSink *err, DN_U32 error_code, DN_FMT_ATTRIB char const *fmt, ...); -#define DN_OS_ErrSinkEndAndLogError(err, err_msg) DN_OS_ErrSinkEndAndLogError_(err, DN_CALL_SITE, err_msg) -#define DN_OS_ErrSinkEndAndLogErrorFV(err, fmt, args) DN_OS_ErrSinkEndAndLogErrorFV_(err, DN_CALL_SITE, fmt, args) -#define DN_OS_ErrSinkEndAndLogErrorF(err, fmt, ...) DN_OS_ErrSinkEndAndLogErrorF_(err, DN_CALL_SITE, fmt, ##__VA_ARGS__) -#define DN_OS_ErrSinkEndAndExitIfErrorFV(err, exit_val, fmt, args) DN_OS_ErrSinkEndAndExitIfErrorFV_(err, DN_CALL_SITE, exit_val, fmt, args) -#define DN_OS_ErrSinkEndAndExitIfErrorF(err, exit_val, fmt, ...) DN_OS_ErrSinkEndAndExitIfErrorF_(err, DN_CALL_SITE, exit_val, fmt, ##__VA_ARGS__) - -#define DN_OS_ErrSinkAppendFV(error, error_code, fmt, args) \ - do { \ - DN_OS_TLSSaveCallSite; \ - DN_OS_ErrSinkAppendFV_(error, error_code, fmt, args); \ - } while (0) - -#define DN_OS_ErrSinkAppendF(error, error_code, fmt, ...) \ - do { \ - DN_OS_TLSSaveCallSite; \ - DN_OS_ErrSinkAppendF_(error, error_code, fmt, ##__VA_ARGS__); \ - } while (0) - -#endif // defined(DN_OS_TLS_H) -// DN: Single header generator inlined this file => #include "OS/dn_os.h" -#if !defined(DN_OS_H) -#define DN_OS_H - -#if defined(_CLANGD) - // DN: Single header generator commented out this header => #include "../dn_base_inc.h" - // DN: Single header generator commented out this header => #include "../dn_os_inc.h" -#endif - -#include // operator new - -#if !defined(DN_OS_WIN32) || defined(DN_OS_WIN32_USE_PTHREADS) - #include - #include -#endif - -#if defined(DN_PLATFORM_POSIX) || defined(DN_PLATFORM_EMSCRIPTEN) - #include // errno - #include // O_RDONLY ... etc - #include // ioctl - #include // mmap - #include // getrandom - #include // stat - #include // pid_t - #include // waitpid - #include // clock_gettime, nanosleep - #include // access, gettid, write - - #if !defined(DN_PLATFORM_EMSCRIPTEN) - #include // FICLONE - #include // sendfile - #endif -#endif - -#if defined(DN_PLATFORM_EMSCRIPTEN) - #include // emscripten_fetch (for DN_OSHttpResponse) -#endif - -extern DN_CPUFeatureDecl g_dn_cpu_feature_decl[DN_CPUFeature_Count]; - -struct DN_OSTimer /// Record time between two time-points using the OS's performance counter. -{ - DN_U64 start; - DN_U64 end; -}; - -// NOTE: DN_OSFile -enum DN_OSPathInfoType -{ - DN_OSPathInfoType_Unknown, - DN_OSPathInfoType_Directory, - DN_OSPathInfoType_File, -}; - -struct DN_OSPathInfo -{ - bool exists; - DN_OSPathInfoType type; - DN_U64 create_time_in_s; - DN_U64 last_write_time_in_s; - DN_U64 last_access_time_in_s; - DN_U64 size; -}; - -struct DN_OSDirIterator -{ - void *handle; - DN_Str8 file_name; - char buffer[512]; -}; - -// NOTE: R/W Stream API -struct DN_OSFileRead -{ - bool success; - DN_USize bytes_read; -}; - -struct DN_OSFile -{ - bool error; - void *handle; -}; - -enum DN_OSFileOpen -{ - DN_OSFileOpen_CreateAlways, // Create file if it does not exist, otherwise, zero out the file and open - DN_OSFileOpen_OpenIfExist, // Open file at path only if it exists - DN_OSFileOpen_OpenAlways, // Open file at path, create file if it does not exist -}; - -typedef DN_U32 DN_OSFileAccess; - -enum DN_OSFileAccess_ -{ - DN_OSFileAccess_Read = 1 << 0, - DN_OSFileAccess_Write = 1 << 1, - DN_OSFileAccess_Execute = 1 << 2, - DN_OSFileAccess_AppendOnly = 1 << 3, // This flag cannot be combined with any other access mode - DN_OSFileAccess_ReadWrite = DN_OSFileAccess_Read | DN_OSFileAccess_Write, - DN_OSFileAccess_All = DN_OSFileAccess_ReadWrite | DN_OSFileAccess_Execute | DN_OSFileAccess_AppendOnly, -}; - -// NOTE: DN_OSPath -#if !defined(DN_OSPathSeperator) - #if defined(DN_OS_WIN32) - #define DN_OSPathSeperator "\\" - #else - #define DN_OSPathSeperator "/" - #endif - #define DN_OSPathSeperatorString DN_Str8Lit(DN_OSPathSeperator) -#endif - -struct DN_OSPathLink -{ - DN_Str8 string; - DN_OSPathLink *next; - DN_OSPathLink *prev; -}; - -struct DN_OSPath -{ - bool has_prefix_path_separator; - DN_OSPathLink *head; - DN_OSPathLink *tail; - DN_USize string_size; - DN_U16 links_size; -}; - -// NOTE: DN_OSExec -typedef DN_U32 DN_OSExecFlags; - -enum DN_OSExecFlags_ -{ - DN_OSExecFlags_Nil = 0, - DN_OSExecFlags_SaveStdout = 1 << 0, - DN_OSExecFlags_SaveStderr = 1 << 1, - DN_OSExecFlags_SaveOutput = DN_OSExecFlags_SaveStdout | DN_OSExecFlags_SaveStderr, - DN_OSExecFlags_MergeStderrToStdout = 1 << 2 | DN_OSExecFlags_SaveOutput, -}; - -struct DN_OSExecAsyncHandle -{ - DN_OSExecFlags exec_flags; - DN_U32 os_error_code; - DN_U32 exit_code; - void *process; - void *stdout_read; - void *stdout_write; - void *stderr_read; - void *stderr_write; -}; - -struct DN_OSExecResult -{ - bool finished; - DN_Str8 stdout_text; - DN_Str8 stderr_text; - DN_U32 os_error_code; - DN_U32 exit_code; -}; - -struct DN_OSExecArgs -{ - DN_OSExecFlags flags; - DN_Str8 working_dir; - DN_Slice environment; -}; - -// NOTE: DN_OSSemaphore -DN_U32 const DN_OS_SEMAPHORE_INFINITE_TIMEOUT = UINT32_MAX; - -struct DN_OSSemaphore -{ - DN_U64 handle; -}; - -enum DN_OSSemaphoreWaitResult -{ - DN_OSSemaphoreWaitResult_Failed, - DN_OSSemaphoreWaitResult_Success, - DN_OSSemaphoreWaitResult_Timeout, -}; - -struct DN_OSMutex -{ - DN_U64 handle; -}; - -struct DN_OSConditionVariable -{ - DN_U64 handle; -}; - -// NOTE: DN_OSThread -typedef DN_I32(DN_OSThreadFunc)(struct DN_OSThread *); - -struct DN_OSThread -{ - DN_Str8x64 name; - DN_OSTLS tls; - DN_OSTLSInitArgs tls_init_args; - void *handle; - DN_U64 thread_id; - void *user_context; - DN_OSThreadFunc *func; - DN_OSSemaphore init_semaphore; -}; - -// NOTE: DN_OSHttp -enum DN_OSHttpRequestSecure -{ - DN_OSHttpRequestSecure_No, - DN_OSHttpRequestSecure_Yes, -}; - -struct DN_OSHttpResponse -{ - // NOTE: Response data - DN_U32 error_code; - DN_Str8 error_msg; - DN_U16 http_status; - DN_Str8 body; - DN_B32 done; - - // NOTE: Book-keeping - DN_Arena *arena; // Allocates memory for the response - - // NOTE: Async book-keeping - // Synchronous HTTP response uses the TLS scratch arena whereas async - // calls use their own dedicated arena. - DN_Arena tmp_arena; - DN_Arena *tmem_arena; - DN_Str8Builder builder; - DN_OSSemaphore on_complete_semaphore; - - #if defined(DN_PLATFORM_EMSCRIPTEN) - emscripten_fetch_t *em_handle; - #elif defined(DN_PLATFORM_WIN32) - HINTERNET w32_request_session; - HINTERNET w32_request_connection; - HINTERNET w32_request_handle; - #endif -}; - -struct DN_OSCore -{ - DN_CPUReport cpu_report; - DN_OSTLS tls; // Thread local storage state for the main thread. - - // NOTE: Logging - DN_LOGEmitFromTypeFVFunc * log_callback; // Set this pointer to override the logging routine - void * log_user_data; // User pointer passed into 'log_callback' - bool log_to_file; // Output logs to file as well as standard out - DN_OSFile log_file; // TODO(dn): Hmmm, how should we do this... ? - DN_TicketMutex log_file_mutex; // Is locked when instantiating the log_file for the first time - bool log_no_colour; // Disable colours in the logging output - - // NOTE: OS - DN_U32 logical_processor_count; - DN_U32 page_size; - DN_U32 alloc_granularity; - - // NOTE: Memory - // Total OS mem allocs in lifetime of program (e.g. malloc, VirtualAlloc, HeapAlloc ...). This - // only includes allocations routed through the library such as the growing nature of arenas or - // using the memory allocation routines in the library like DN_OS_MemCommit and so forth. - DN_U64 vmem_allocs_total; - DN_U64 vmem_allocs_frame; // Total OS virtual memory allocs since the last 'DN_Core_FrameBegin' was invoked - DN_U64 mem_allocs_total; - DN_U64 mem_allocs_frame; // Total OS heap allocs since the last 'DN_Core_FrameBegin' was invoked - - DN_Arena arena; - void *platform_context; -}; - -struct DN_OSDiskSpace -{ - bool success; - DN_U64 avail; - DN_U64 size; -}; - -DN_API void DN_OS_EmitLogsWithOSPrintFunctions (DN_OSCore *os); -DN_API void DN_OS_DumpThreadContextArenaStat (DN_Str8 file_path); - -DN_API DN_Str8 DN_OS_BytesFromHexPtrArenaFrame (void const *hex, DN_USize hex_count); -DN_API DN_Str8 DN_OS_BytesFromHexStr8ArenaFrame (DN_Str8 hex); -DN_API DN_Str8 DN_OS_HexFromBytesPtrArenaFrame (void const *bytes, DN_USize bytes_count); -DN_API DN_Str8 DN_OS_HexFromBytesPtrArenaTLS (void const *bytes, DN_USize bytes_count); - -DN_API void * DN_OS_MemReserve (DN_USize size, DN_MemCommit commit, DN_MemPage page_flags); -DN_API bool DN_OS_MemCommit (void *ptr, DN_USize size, DN_U32 page_flags); -DN_API void DN_OS_MemDecommit (void *ptr, DN_USize size); -DN_API void DN_OS_MemRelease (void *ptr, DN_USize size); -DN_API int DN_OS_MemProtect (void *ptr, DN_USize size, DN_U32 page_flags); - -DN_API void * DN_OS_MemAlloc (DN_USize size, DN_ZMem z_mem); -DN_API void DN_OS_MemDealloc (void *ptr); - -DN_API DN_Date DN_OS_DateLocalTimeNow (); -DN_API DN_Str8x32 DN_OS_DateLocalTimeStr8Now (char date_separator = '-', char hms_separator = ':'); -DN_API DN_Str8x32 DN_OS_DateLocalTimeStr8 (DN_Date time, char date_separator = '-', char hms_separator = ':'); -DN_API DN_U64 DN_OS_DateUnixTimeNs (); -#define DN_OS_DateUnixTimeUs() (DN_OS_DateUnixTimeNs() / 1000) -#define DN_OS_DateUnixTimeMs() (DN_OS_DateUnixTimeNs() / (1000 * 1000)) -#define DN_OS_DateUnixTimeS() (DN_OS_DateUnixTimeNs() / (1000 * 1000 * 1000)) -DN_API DN_U64 DN_OS_DateUnixTimeSFromLocalDate (DN_Date date); -DN_API DN_U64 DN_OS_DateLocalUnixTimeSFromUnixTimeS (DN_U64 unix_ts_s); - -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_Str8 DN_OS_EXEPath (DN_Arena *arena); -DN_API DN_Str8 DN_OS_EXEDir (DN_Arena *arena); -#define DN_OS_EXEDirFromTLS() DN_OS_EXEDir(DN_OS_TLSTopArena()) -DN_API void DN_OS_SleepMs (DN_UInt milliseconds); - -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_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 bool DN_OS_FileCopy (DN_Str8 src, DN_Str8 dest, bool overwrite, DN_OSErrSink *err); -DN_API bool DN_OS_FileMove (DN_Str8 src, DN_Str8 dest, bool overwrite, DN_OSErrSink *err); - -DN_API DN_OSFile DN_OS_FileOpen (DN_Str8 path, DN_OSFileOpen open_mode, DN_OSFileAccess access, DN_OSErrSink *err); -DN_API DN_OSFileRead DN_OS_FileRead (DN_OSFile *file, void *buffer, DN_USize size, DN_OSErrSink *err); -DN_API bool DN_OS_FileWritePtr (DN_OSFile *file, void const *data, DN_USize size, DN_OSErrSink *err); -DN_API bool DN_OS_FileWrite (DN_OSFile *file, DN_Str8 buffer, DN_OSErrSink *err); -DN_API bool DN_OS_FileWriteFV (DN_OSFile *file, DN_OSErrSink *err, DN_FMT_ATTRIB char const *fmt, va_list args); -DN_API bool DN_OS_FileWriteF (DN_OSFile *file, DN_OSErrSink *err, DN_FMT_ATTRIB char const *fmt, ...); -DN_API bool DN_OS_FileFlush (DN_OSFile *file, DN_OSErrSink *err); -DN_API void DN_OS_FileClose (DN_OSFile *file); - -DN_API DN_Str8 DN_OS_FileReadAll (DN_Allocator alloc_type, void *allocator, DN_Str8 path, DN_OSErrSink *err); -DN_API DN_Str8 DN_OS_FileReadAllArena (DN_Arena *arena, DN_Str8 path, DN_OSErrSink *err); -DN_API DN_Str8 DN_OS_FileReadAllPool (DN_Pool *pool, DN_Str8 path, DN_OSErrSink *err); -DN_API DN_Str8 DN_OS_FileReadAllTLS (DN_Str8 path, DN_OSErrSink *err); -DN_API bool DN_OS_FileWriteAll (DN_Str8 path, DN_Str8 buffer, DN_OSErrSink *err); -DN_API bool DN_OS_FileWriteAllFV (DN_Str8 path, DN_OSErrSink *err, DN_FMT_ATTRIB char const *fmt, va_list args); -DN_API bool DN_OS_FileWriteAllF (DN_Str8 path, DN_OSErrSink *err, DN_FMT_ATTRIB char const *fmt, ...); -DN_API bool DN_OS_FileWriteAllSafe (DN_Str8 path, DN_Str8 buffer, DN_OSErrSink *err); -DN_API bool DN_OS_FileWriteAllSafeFV (DN_Str8 path, DN_OSErrSink *err, DN_FMT_ATTRIB char const *fmt, va_list args); -DN_API bool DN_OS_FileWriteAllSafeF (DN_Str8 path, DN_OSErrSink *err, DN_FMT_ATTRIB char const *fmt, ...); - -DN_API DN_OSPathInfo DN_OS_PathInfo (DN_Str8 path); -DN_API bool DN_OS_PathIsOlderThan (DN_Str8 file, DN_Str8 check_against); -DN_API bool DN_OS_PathDelete (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_PathMakeDir (DN_Str8 path); -DN_API bool DN_OS_PathIterateDir (DN_Str8 path, DN_OSDirIterator *it); - -DN_API bool DN_OS_PathAddRef (DN_Arena *arena, DN_OSPath *fs_path, DN_Str8 path); -DN_API bool DN_OS_PathAddRefTLS (DN_OSPath *fs_path, DN_Str8 path); -DN_API bool DN_OS_PathAddRefFrame (DN_OSPath *fs_path, DN_Str8 path); -DN_API bool DN_OS_PathAdd (DN_Arena *arena, DN_OSPath *fs_path, DN_Str8 path); -#define DN_OS_PathAddFromTLS(...) DN_OS_PathAdd(DN_OS_TLSTopArena(), ##__VA_ARGS__) -#define DN_OS_PathAddFromFrame(...) DN_OS_PathAdd(DN_OS_TLSFrameArena(), ##__VA_ARGS__) -DN_API bool DN_OS_PathAddF (DN_Arena *arena, DN_OSPath *fs_path, DN_FMT_ATTRIB char const *fmt, ...); -#define DN_OS_PathAddFFromTLS(...) DN_OS_PathAddF(DN_OS_TLSTopArena(), ##__VA_ARGS__) -#define DN_OS_PathAddFFromFrame(...) DN_OS_PathAddF(DN_OS_TLSFrameArena(), ##__VA_ARGS__) -DN_API bool DN_OS_PathPop (DN_OSPath *fs_path); -DN_API DN_Str8 DN_OS_PathBuildWithSeparator (DN_Arena *arena, DN_OSPath const *fs_path, DN_Str8 path_separator); -#define DN_OS_PathBuildWithSeperatorFromTLS(...) DN_OS_PathBuildWithSeperator(DN_OS_TLSTopArena(), ##__VA_ARGS__) -#define DN_OS_PathBuildWithSeperatorFromFrame(...) DN_OS_PathBuildWithSeperator(DN_OS_TLSFrameArena(), ##__VA_ARGS__) -DN_API DN_Str8 DN_OS_PathTo (DN_Arena *arena, DN_Str8 path, DN_Str8 path_separtor); -#define DN_OS_PathToFromTLS(...) DN_OS_PathTo(DN_OS_TLSTopArena(), ##__VA_ARGS__) -#define DN_OS_PathToFromFrame(...) DN_OS_PathTo(DN_OS_TLSFrameArena(), ##__VA_ARGS__) -DN_API DN_Str8 DN_OS_PathToF (DN_Arena *arena, DN_Str8 path_separator, DN_FMT_ATTRIB char const *fmt, ...); -#define DN_OS_PathToFFromTLS(...) DN_OS_PathToF(DN_OS_TLSTopArena(), ##__VA_ARGS__) -#define DN_OS_PathToFFromFrame(...) DN_OS_PathToF(DN_OS_TLSFrameArena(), ##__VA_ARGS__) -DN_API DN_Str8 DN_OS_Path (DN_Arena *arena, DN_Str8 path); -#define DN_OS_PathFromTLS(...) DN_OS_Path(DN_OS_TLSTopArena(), ##__VA_ARGS__) -#define DN_OS_PathFromFrame(...) DN_OS_Path(DN_OS_TLSFrameArena(), ##__VA_ARGS__) -DN_API DN_Str8 DN_OS_PathF (DN_Arena *arena, DN_FMT_ATTRIB char const *fmt, ...); -#define DN_OS_PathFFromTLS(...) DN_OS_PathF(DN_OS_TLSTopArena(), ##__VA_ARGS__) -#define DN_OS_PathFFromFrame(...) DN_OS_PathF(DN_OS_TLSFrameArena(), ##__VA_ARGS__) - -#define DN_OS_PathBuildFwdSlash(allocator, fs_path) DN_OS_PathBuildWithSeparator(allocator, fs_path, DN_Str8Lit("/")) -#define DN_OS_PathBuildBackSlash(allocator, fs_path) DN_OS_PathBuildWithSeparator(allocator, fs_path, DN_Str8Lit("\\")) -#define DN_OS_PathBuild(allocator, fs_path) DN_OS_PathBuildWithSeparator(allocator, fs_path, DN_OSPathSeparatorString) - -DN_API void DN_OS_Exit (int32_t exit_code); -DN_API DN_OSExecResult DN_OS_ExecPump (DN_OSExecAsyncHandle handle, char *stdout_buffer, size_t *stdout_size, char *stderr_buffer, size_t *stderr_size, DN_U32 timeout_ms, DN_OSErrSink *err); -DN_API DN_OSExecResult DN_OS_ExecWait (DN_OSExecAsyncHandle handle, DN_Arena *arena, DN_OSErrSink *err); -DN_API DN_OSExecAsyncHandle DN_OS_ExecAsync (DN_Slice cmd_line, DN_OSExecArgs *args, DN_OSErrSink *err); -DN_API DN_OSExecResult DN_OS_Exec (DN_Slice cmd_line, DN_OSExecArgs *args, DN_Arena *arena, DN_OSErrSink *err); -DN_API DN_OSExecResult DN_OS_ExecOrAbort (DN_Slice cmd_line, DN_OSExecArgs *args, DN_Arena *arena); -#define DN_OS_ExecOrAbortFromTLS (...) DN_OS_ExecOrAbort(__VA_ARGS__, DN_OS_TLSTopArena()) - -DN_API DN_OSSemaphore DN_OS_SemaphoreInit (DN_U32 initial_count); -DN_API bool DN_OS_SemaphoreIsValid (DN_OSSemaphore *semaphore); -DN_API void DN_OS_SemaphoreDeinit (DN_OSSemaphore *semaphore); -DN_API void DN_OS_SemaphoreIncrement (DN_OSSemaphore *semaphore, DN_U32 amount); -DN_API DN_OSSemaphoreWaitResult DN_OS_SemaphoreWait (DN_OSSemaphore *semaphore, DN_U32 timeout_ms); - -DN_API DN_OSMutex DN_OS_MutexInit (); -DN_API void DN_OS_MutexDeinit (DN_OSMutex *mutex); -DN_API void DN_OS_MutexLock (DN_OSMutex *mutex); -DN_API void DN_OS_MutexUnlock (DN_OSMutex *mutex); -#define DN_OS_MutexScope(mutex) DN_DeferLoop(DN_OS_MutexLock(mutex), DN_OS_MutexUnlock(mutex)) - -DN_API DN_OSConditionVariable DN_OS_ConditionVariableInit (); -DN_API void DN_OS_ConditionVariableDeinit (DN_OSConditionVariable *cv); -DN_API bool DN_OS_ConditionVariableWait (DN_OSConditionVariable *cv, DN_OSMutex *mutex, DN_U64 sleep_ms); -DN_API bool DN_OS_ConditionVariableWaitUntil (DN_OSConditionVariable *cv, DN_OSMutex *mutex, DN_U64 end_ts_ms); -DN_API void DN_OS_ConditionVariableSignal (DN_OSConditionVariable *cv); -DN_API void DN_OS_ConditionVariableBroadcast (DN_OSConditionVariable *cv); - -DN_API bool DN_OS_ThreadInit (DN_OSThread *thread, DN_OSThreadFunc *func, void *user_context); -DN_API void DN_OS_ThreadDeinit (DN_OSThread *thread); -DN_API DN_U32 DN_OS_ThreadID (); -DN_API void DN_OS_ThreadSetName (DN_Str8 name); - -DN_API void DN_OS_HttpRequestAsync (DN_OSHttpResponse *response, DN_Arena *arena, DN_Str8 host, DN_Str8 path, DN_OSHttpRequestSecure secure, DN_Str8 method, DN_Str8 body, DN_Str8 headers); -DN_API void DN_OS_HttpRequestWait (DN_OSHttpResponse *response); -DN_API void DN_OS_HttpRequestFree (DN_OSHttpResponse *response); -DN_API DN_OSHttpResponse DN_OS_HttpRequest (DN_Arena *arena, DN_Str8 host, DN_Str8 path, DN_OSHttpRequestSecure secure, DN_Str8 method, DN_Str8 body, DN_Str8 headers); -#endif // !defined(DN_OS_H) -// DN: Single header generator inlined this file => #include "OS/dn_os_allocator.h" -#if !defined(DN_OS_ALLOCATOR_H) -#define DN_OS_ALLOCATOR_H - -#if defined(_CLANGD) - // DN: Single header generator commented out this header => #include "../dn_base_inc.h" -#endif - -DN_API DN_Arena DN_ArenaFromHeap(DN_U64 size, DN_ArenaFlags flags); -DN_API DN_Arena DN_ArenaFromVMem(DN_U64 reserve, DN_U64 commit, DN_ArenaFlags flags); - -#endif // !defined(DN_OS_ALLOCATOR_H) -// DN: Single header generator inlined this file => #include "OS/dn_os_containers.h" -#if !defined(DN_OS_CONTAINERS_H) -#define DN_OS_CONTAINERS_H - -#if defined(_CLANGD) - // DN: Single header generator commented out this header => #include "../dn_base_inc.h" -#endif - -// NOTE: DN_VArray -// TODO(doyle): Add an API for shrinking the array by decomitting pages back to the OS. -template struct DN_VArray -{ - T *data; // Pointer to the start of the array items in the block of memory - DN_USize size; // Number of items currently in the array - DN_USize max; // Maximum number of items this array can store - DN_USize commit; // Bytes committed - - T *begin() { return data; } - T *end () { return data + size; } - T const *begin() const { return data; } - T const *end () const { return data + size; } -}; - -template DN_VArray DN_VArray_InitByteSize (DN_USize byte_size); -template DN_VArray DN_VArray_Init (DN_USize max); -template DN_VArray DN_VArray_InitSlice (DN_Slice slice, DN_USize max); -template DN_VArray DN_VArray_InitCArray (T const (&items)[N], DN_USize max); -template void DN_VArray_Deinit (DN_VArray *array); -template bool DN_VArray_IsValid (DN_VArray const *array); -template DN_Slice DN_VArray_Slice (DN_VArray const *array); -template bool DN_VArray_Reserve (DN_VArray *array, DN_USize count); -template T * DN_VArray_AddArray (DN_VArray *array, T const *items, DN_USize count); -template T * DN_VArray_AddCArray (DN_VArray *array, T const (&items)[N]); -template T * DN_VArray_Add (DN_VArray *array, T const &item); -#define DN_VArray_AddArrayAssert(...) DN_HardAssert(DN_VArray_AddArray(__VA_ARGS__)) -#define DN_VArray_AddCArrayAssert(...) DN_HardAssert(DN_VArray_AddCArray(__VA_ARGS__)) -#define DN_VArray_AddAssert(...) DN_HardAssert(DN_VArray_Add(__VA_ARGS__)) -template T * DN_VArray_MakeArray (DN_VArray *array, DN_USize count, DN_ZMem z_mem); -template T * DN_VArray_Make (DN_VArray *array, DN_ZMem z_mem); -#define DN_VArray_MakeArrayAssert(...) DN_HardAssert(DN_VArray_MakeArray(__VA_ARGS__)) -#define DN_VArray_MakeAssert(...) DN_HardAssert(DN_VArray_Make(__VA_ARGS__)) -template T * DN_VArray_InsertArray (DN_VArray *array, DN_USize index, T const *items, DN_USize count); -template T * DN_VArray_InsertCArray (DN_VArray *array, DN_USize index, T const (&items)[N]); -template T * DN_VArray_Insert (DN_VArray *array, DN_USize index, T const &item); -#define DN_VArray_InsertArrayAssert(...) DN_HardAssert(DN_VArray_InsertArray(__VA_ARGS__)) -#define DN_VArray_InsertCArrayAssert(...) DN_HardAssert(DN_VArray_InsertCArray(__VA_ARGS__)) -#define DN_VArray_InsertAssert(...) DN_HardAssert(DN_VArray_Insert(__VA_ARGS__)) -template T DN_VArray_PopFront (DN_VArray *array, DN_USize count); -template T DN_VArray_PopBack (DN_VArray *array, DN_USize count); -template DN_ArrayEraseResult DN_VArray_EraseRange (DN_VArray *array, DN_USize begin_index, DN_ISize count, DN_ArrayErase erase); -template void DN_VArray_Clear (DN_VArray *array, DN_ZMem z_mem); -#endif // !defined(DN_OS_CONTAINERS_H) -// DN: Single header generator inlined this file => #include "OS/dn_os_print.h" -#if !defined(DN_OS_PRINT_H) -#define DN_OS_PRINT_H - -enum DN_OSPrintDest -{ - DN_OSPrintDest_Out, - DN_OSPrintDest_Err, -}; - -// NOTE: Print Macros -#define DN_OS_PrintOut(string) DN_OS_Print(DN_OSPrintDest_Out, string) -#define DN_OS_PrintOutF(fmt, ...) DN_OS_PrintF(DN_OSPrintDest_Out, fmt, ##__VA_ARGS__) -#define DN_OS_PrintOutFV(fmt, args) DN_OS_PrintFV(DN_OSPrintDest_Out, fmt, args) - -#define DN_OS_PrintOutStyle(style, string) DN_OS_PrintStyle(DN_OSPrintDest_Out, style, string) -#define DN_OS_PrintOutFStyle(style, fmt, ...) DN_OS_PrintFStyle(DN_OSPrintDest_Out, style, fmt, ##__VA_ARGS__) -#define DN_OS_PrintOutFVStyle(style, fmt, args, ...) DN_OS_PrintFVStyle(DN_OSPrintDest_Out, style, fmt, args) - -#define DN_OS_PrintOutLn(string) DN_OS_PrintLn(DN_OSPrintDest_Out, string) -#define DN_OS_PrintOutLnF(fmt, ...) DN_OS_PrintLnF(DN_OSPrintDest_Out, fmt, ##__VA_ARGS__) -#define DN_OS_PrintOutLnFV(fmt, args) DN_OS_PrintLnFV(DN_OSPrintDest_Out, fmt, args) - -#define DN_OS_PrintOutLnStyle(style, string) DN_OS_PrintLnStyle(DN_OSPrintDest_Out, style, string); -#define DN_OS_PrintOutLnFStyle(style, fmt, ...) DN_OS_PrintLnFStyle(DN_OSPrintDest_Out, style, fmt, ##__VA_ARGS__) -#define DN_OS_PrintOutLnFVStyle(style, fmt, args) DN_OS_PrintLnFVStyle(DN_OSPrintDest_Out, style, fmt, args); - -#define DN_OS_PrintErr(string) DN_OS_Print(DN_OSPrintDest_Err, string) -#define DN_OS_PrintErrF(fmt, ...) DN_OS_PrintF(DN_OSPrintDest_Err, fmt, ##__VA_ARGS__) -#define DN_OS_PrintErrFV(fmt, args) DN_OS_PrintFV(DN_OSPrintDest_Err, fmt, args) - -#define DN_OS_PrintErrStyle(style, string) DN_OS_PrintStyle(DN_OSPrintDest_Err, style, string) -#define DN_OS_PrintErrFStyle(style, fmt, ...) DN_OS_PrintFStyle(DN_OSPrintDest_Err, style, fmt, ##__VA_ARGS__) -#define DN_OS_PrintErrFVStyle(style, fmt, args, ...) DN_OS_PrintFVStyle(DN_OSPrintDest_Err, style, fmt, args) - -#define DN_OS_PrintErrLn(string) DN_OS_PrintLn(DN_OSPrintDest_Err, string) -#define DN_OS_PrintErrLnF(fmt, ...) DN_OS_PrintLnF(DN_OSPrintDest_Err, fmt, ##__VA_ARGS__) -#define DN_OS_PrintErrLnFV(fmt, args) DN_OS_PrintLnFV(DN_OSPrintDest_Err, fmt, args) - -#define DN_OS_PrintErrLnStyle(style, string) DN_OS_PrintLnStyle(DN_OSPrintDest_Err, style, string); -#define DN_OS_PrintErrLnFStyle(style, fmt, ...) DN_OS_PrintLnFStyle(DN_OSPrintDest_Err, style, fmt, ##__VA_ARGS__) -#define DN_OS_PrintErrLnFVStyle(style, fmt, args) DN_OS_PrintLnFVStyle(DN_OSPrintDest_Err, style, fmt, args); - -// NOTE: Print -DN_API void DN_OS_Print (DN_OSPrintDest dest, DN_Str8 string); -DN_API void DN_OS_PrintF (DN_OSPrintDest dest, DN_FMT_ATTRIB char const *fmt, ...); -DN_API void DN_OS_PrintFV (DN_OSPrintDest dest, DN_FMT_ATTRIB char const *fmt, va_list args); - -DN_API void DN_OS_PrintStyle (DN_OSPrintDest dest, DN_LOGStyle style, DN_Str8 string); -DN_API void DN_OS_PrintFStyle (DN_OSPrintDest dest, DN_LOGStyle style, DN_FMT_ATTRIB char const *fmt, ...); -DN_API void DN_OS_PrintFVStyle (DN_OSPrintDest dest, DN_LOGStyle style, DN_FMT_ATTRIB char const *fmt, va_list args); - -DN_API void DN_OS_PrintLn (DN_OSPrintDest dest, DN_Str8 string); -DN_API void DN_OS_PrintLnF (DN_OSPrintDest dest, DN_FMT_ATTRIB char const *fmt, ...); -DN_API void DN_OS_PrintLnFV (DN_OSPrintDest dest, DN_FMT_ATTRIB char const *fmt, va_list args); - -DN_API void DN_OS_PrintLnStyle (DN_OSPrintDest dest, DN_LOGStyle style, DN_Str8 string); -DN_API void DN_OS_PrintLnFStyle (DN_OSPrintDest dest, DN_LOGStyle style, DN_FMT_ATTRIB char const *fmt, ...); -DN_API void DN_OS_PrintLnFVStyle (DN_OSPrintDest dest, DN_LOGStyle style, DN_FMT_ATTRIB char const *fmt, va_list args); -#endif // !defined(DN_OS_PRINT_H) -// DN: Single header generator inlined this file => #include "OS/dn_os_string.h" -#if !defined(DN_OS_STRING_H) -#define DN_OS_STRING_H - -#if defined(_CLANGD) - // DN: Single header generator commented out this header => #include "../dn_base_inc.h" - // DN: Single header generator commented out this header => #include "../dn_os_inc.h" -#endif - -// NOTE: DN_Str8 - -DN_API DN_Str8 DN_Str8FromFmtVArenaFrame (DN_FMT_ATTRIB char const *fmt, va_list args); -DN_API DN_Str8 DN_Str8FromFmtArenaFrame (DN_FMT_ATTRIB char const *fmt, ...); -DN_API DN_Str8 DN_Str8FromArenaFrame (DN_USize size, DN_ZMem z_mem); -DN_API DN_Str8 DN_Str8FromHeapF (DN_FMT_ATTRIB char const *fmt, ...); -DN_API DN_Str8 DN_Str8FromHeap (DN_USize size, DN_ZMem z_mem); -DN_API DN_Str8 DN_Str8FromTLSFV (DN_FMT_ATTRIB char const *fmt, va_list args); -DN_API DN_Str8 DN_Str8FromTLSF (DN_FMT_ATTRIB char const *fmt, ...); -DN_API DN_Str8 DN_Str8FromTLS (DN_USize size, DN_ZMem z_mem); -DN_API DN_Str8 DN_Str8FromStr8Frame (DN_Str8 string); -DN_API DN_Str8 DN_Str8FromStr8TLS (DN_Str8 string); - -DN_API DN_Str8SplitResult DN_Str8SplitFromFrame (DN_Str8 string, DN_Str8 delimiter, DN_Str8SplitIncludeEmptyStrings mode); -DN_API DN_Str8SplitResult DN_Str8SplitFromTLS (DN_Str8 string, DN_Str8 delimiter, DN_Str8SplitIncludeEmptyStrings mode); - -DN_API DN_Str8 DN_Str8SegmentFromFrame (DN_Str8 src, DN_USize segment_size, char segment_char); -DN_API DN_Str8 DN_Str8SegmentFromTLS (DN_Str8 src, DN_USize segment_size, char segment_char); - -DN_API DN_Str8 DN_Str8ReverseSegmentFromFrame (DN_Str8 src, DN_USize segment_size, char segment_char); -DN_API DN_Str8 DN_Str8ReverseSegmentFromTLS (DN_Str8 src, DN_USize segment_size, char segment_char); - -DN_API DN_Str8 DN_Str8AppendFFromFrame (DN_Str8 string, char const *fmt, ...); -DN_API DN_Str8 DN_Str8AppendFFromTLS (DN_Str8 string, char const *fmt, ...); - -DN_API DN_Str8 DN_Str8FillFFromFrame (DN_Str8 string, char const *fmt, ...); -DN_API DN_Str8 DN_Str8FillFFromTLS (DN_Str8 string, char const *fmt, ...); - -DN_API DN_Str8TruncateResult DN_Str8TruncateMiddleArenaFrame (DN_Str8 str8, uint32_t side_size, DN_Str8 truncator); -DN_API DN_Str8TruncateResult DN_Str8TruncateMiddleArenaTLS (DN_Str8 str8, uint32_t side_size, DN_Str8 truncator); - -DN_API DN_Str8 DN_Str8PadNewLines (DN_Arena *arena, DN_Str8 src, DN_Str8 pad); -DN_API DN_Str8 DN_Str8PadNewLinesFromFrame (DN_Str8 src, DN_Str8 pad); -DN_API DN_Str8 DN_Str8PadNewLinesFromTLS (DN_Str8 src, DN_Str8 pad); - -DN_API DN_Str8 DN_Str8UpperFromFrame (DN_Str8 string); -DN_API DN_Str8 DN_Str8UpperFromTLS (DN_Str8 string); - -DN_API DN_Str8 DN_Str8LowerFromFrame (DN_Str8 string); -DN_API DN_Str8 DN_Str8LowerFromTLS (DN_Str8 string); - -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_Str8EqCase_Sensitive); -DN_API DN_Str8 DN_Str8ReplaceInsensitive (DN_Str8 string, DN_Str8 find, DN_Str8 replace, DN_USize start_index, DN_Arena *arena); - -// NOTE: DN_Str8Builder //////////////////////////////////////////////////////////////////////////// - -DN_API DN_Str8Builder DN_Str8BuilderFromArena () { return DN_Str8BuilderFromArena(DN_OS_TLSGet()->frame_arena); } -DN_API DN_Str8Builder DN_Str8BuilderFromTLS () { return DN_Str8BuilderFromArena(DN_OS_TLSTopArena()); } - -DN_API DN_Str8Builder DN_Str8BuilderFromStr8PtrRefFrame (DN_Str8 const *strings, DN_USize size) { return DN_Str8BuilderFromStr8PtrRef(DN_OS_TLSGet()->frame_arena, strings, size); } -DN_API DN_Str8Builder DN_Str8BuilderFromStr8PtrRefTLS (DN_Str8 const *strings, DN_USize size) { return DN_Str8BuilderFromStr8PtrRef(DN_OS_TLSTopArena(), strings, size); } -DN_API DN_Str8Builder DN_Str8BuilderFromStr8PtrCopyFrame (DN_Str8 const *strings, DN_USize size) { return DN_Str8BuilderFromStr8PtrCopy(DN_OS_TLSGet()->frame_arena, strings, size); } -DN_API DN_Str8Builder DN_Str8BuilderFromStr8PtrCopyTLS (DN_Str8 const *strings, DN_USize size) { return DN_Str8BuilderFromStr8PtrCopy(DN_OS_TLSTopArena(), strings, size); } - -DN_API DN_Str8Builder DN_Str8BuilderFromBuilderFrame (DN_Str8Builder const *builder) { return DN_Str8BuilderFromBuilder(DN_OS_TLSGet()->frame_arena, builder); } -DN_API DN_Str8Builder DN_Str8BuilderFromBuilderTLS (DN_Str8Builder const *builder) { return DN_Str8BuilderFromBuilder(DN_OS_TLSTopArena(), builder); } - -DN_API DN_Str8 DN_Str8BuilderBuildFromFrame (DN_Str8Builder const *builder) { return DN_Str8BuilderBuild(builder, DN_OS_TLSGet()->frame_arena); } -DN_API DN_Str8 DN_Str8BuilderBuildFromHeap (DN_Str8Builder const *builder, DN_Arena *arena); -DN_API DN_Str8 DN_Str8BuilderBuildFromTLS (DN_Str8Builder const *builder) { return DN_Str8BuilderBuild(builder, DN_OS_TLSTopArena()); } - -DN_API DN_Str8 DN_Str8BuilderBuildDelimitedFromFrame(DN_Str8Builder const *builder, DN_Str8 delimiter) { return DN_Str8BuilderBuildDelimited(builder, delimiter, DN_OS_TLSGet()->frame_arena); } -DN_API DN_Str8 DN_Str8BuilderBuildDelimitedFromTLS (DN_Str8Builder const *builder, DN_Str8 delimiter) { return DN_Str8BuilderBuildDelimited(builder, delimiter, DN_OS_TLSTopArena()); } - -DN_API DN_Slice DN_Str8BuilderBuildSliceFromFrame (DN_Str8Builder const *builder) { return DN_Str8BuilderBuildSlice(builder, DN_OS_TLSGet()->frame_arena); } -DN_API DN_Slice DN_Str8BuilderBuildSliceFromTLS (DN_Str8Builder const *builder) { return DN_Str8BuilderBuildSlice(builder, DN_OS_TLSTopArena()); } - -#endif // !defined(DN_OS_STRING_H) - -#endif // DN_OS_INC_H -#if !defined(DN_INC_H) -#define DN_INC_H - -#if defined(_CLANGD) - // DN: Single header generator inlined this file => #include "dn_base_inc.h" -#if !defined(DN_BASE_INC_H) -#define DN_BASE_INC_H - -// NOTE: DN configuration -// All the following configuration options are optional. If omitted, DN has default behaviours to -// handle the various options. -// -// Platform Target -// Define one of the following directives to configure this library to compile for that platform. -// By default, the library will auto-detect the current host platform and select that as the -// target platform. -// -// DN_PLATFORM_EMSCRIPTEN -// DN_PLATFORM_POSIX -// DN_PLATFORM_WIN32 -// -// For example -// -// #define DN_PLATFORM_WIN32 -// -// Will ensure that is included and the OS layer is implemented using Win32 -// primitives. -// -// Static functions -// All public functions in the DN library are prefixed with the macro '#define DN_API'. By -// default 'DN_API' is not defined to anything. Define -// -// DN_STATIC_API -// -// To replace all the prefixed with 'static' ensuring that the functions in the library do not -// export an entry into the linking table and thereby optimise compilation times as the linker -// will not try to resolve symbols from other translation units from the the unit including the -// DN library. -// -// Using the in-built replacement header for (requires dn_os_inc.h) -// If you are building DN for the Windows platform, is a large legacy header that -// applications have to link to use Windows syscalls. By default DN library uses a replacement -// header for all the Windows functions that it uses in the OS layer removing the need to include -// to improve compilation times. This can be disabled by defining: -// -// DN_NO_WINDOWS_H_REPLACEMENT_HEADER -// -// To instead use . DN automatically detects if is included in an earlier -// translation unit and will automatically disable the in-built replacement header in which case -// this does not need to be defined. -// -// Freestanding -// 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. - -// DN: Single header generator commented out this header => #include "Base/dn_base_compiler.h" -#if !defined(DN_BASE_COMPILER_H) -#define DN_BASE_COMPILER_H - -// NOTE: Compiler identification -// Warning! Order is important here, clang-cl on Windows defines _MSC_VER -#if defined(_MSC_VER) - #if defined(__clang__) - #define DN_COMPILER_CLANG_CL - #define DN_COMPILER_CLANG - #else - #define DN_COMPILER_MSVC - #endif -#elif defined(__clang__) - #define DN_COMPILER_CLANG -#elif defined(__GNUC__) - #define DN_COMPILER_GCC -#endif - -// NOTE: __has_feature -// MSVC for example does not support the feature detection macro for instance so we compile it out -#if defined(__has_feature) - #define DN_HAS_FEATURE(expr) __has_feature(expr) -#else - #define DN_HAS_FEATURE(expr) 0 -#endif - -// NOTE: __has_builtin -// MSVC for example does not support the feature detection macro for instance so we compile it out -#if defined(__has_builtin) - #define DN_HAS_BUILTIN(expr) __has_builtin(expr) -#else - #define DN_HAS_BUILTIN(expr) 0 -#endif - -// NOTE: Warning suppression macros -#if defined(DN_COMPILER_MSVC) - #define DN_MSVC_WARNING_PUSH __pragma(warning(push)) - #define DN_MSVC_WARNING_DISABLE(...) __pragma(warning(disable :##__VA_ARGS__)) - #define DN_MSVC_WARNING_POP __pragma(warning(pop)) -#else - #define DN_MSVC_WARNING_PUSH - #define DN_MSVC_WARNING_DISABLE(...) - #define DN_MSVC_WARNING_POP -#endif - -#if defined(DN_COMPILER_CLANG) || defined(DN_COMPILER_GCC) || defined(DN_COMPILER_CLANG_CL) - #define DN_GCC_WARNING_PUSH _Pragma("GCC diagnostic push") - #define DN_GCC_WARNING_DISABLE_HELPER_0(x) #x - #define DN_GCC_WARNING_DISABLE_HELPER_1(y) DN_GCC_WARNING_DISABLE_HELPER_0(GCC diagnostic ignored #y) - #define DN_GCC_WARNING_DISABLE(warning) _Pragma(DN_GCC_WARNING_DISABLE_HELPER_1(warning)) - #define DN_GCC_WARNING_POP _Pragma("GCC diagnostic pop") -#else - #define DN_GCC_WARNING_PUSH - #define DN_GCC_WARNING_DISABLE(...) - #define DN_GCC_WARNING_POP -#endif - -// NOTE: Host OS identification -#if defined(_WIN32) - #define DN_OS_WIN32 -#elif defined(__gnu_linux__) || defined(__linux__) - #define DN_OS_UNIX -#endif - -// NOTE: Platform identification -#if !defined(DN_PLATFORM_EMSCRIPTEN) && \ - !defined(DN_PLATFORM_POSIX) && \ - !defined(DN_PLATFORM_WIN32) - #if defined(__aarch64__) || defined(_M_ARM64) - #define DN_PLATFORM_ARM64 - #elif defined(__EMSCRIPTEN__) - #define DN_PLATFORM_EMSCRIPTEN - #elif defined(DN_OS_WIN32) - #define DN_PLATFORM_WIN32 - #else - #define DN_PLATFORM_POSIX - #endif -#endif - -// NOTE: Windows crap -#if defined(DN_COMPILER_MSVC) || defined(DN_COMPILER_CLANG_CL) - #if defined(_CRT_SECURE_NO_WARNINGS) - #define DN_CRT_SECURE_NO_WARNINGS_PREVIOUSLY_DEFINED - #else - #define _CRT_SECURE_NO_WARNINGS - #endif -#endif - -// NOTE: Force Inline -#if defined(DN_COMPILER_MSVC) || defined(DN_COMPILER_CLANG_CL) - #define DN_FORCE_INLINE __forceinline -#else - #define DN_FORCE_INLINE inline __attribute__((always_inline)) -#endif - -// NOTE: Function/Variable Annotations -#if defined(DN_STATIC_API) - #define DN_API static -#else - #define DN_API -#endif - -// NOTE: C/CPP Literals -// Declare struct literals that work in both C and C++ because the syntax is different between -// languages. -#if 0 - struct Foo { int a; } - struct Foo foo = DN_LITERAL(Foo){32}; // Works on both C and C++ -#endif - -#if defined(__cplusplus) - #define DN_Literal(T) T -#else - #define DN_Literal(T) (T) -#endif - -// NOTE: Thread Locals -#if defined(__cplusplus) - #define DN_THREAD_LOCAL thread_local -#else - #define DN_THREAD_LOCAL _Thread_local -#endif - -// NOTE: C variadic argument annotations -// TODO: Other compilers -#if defined(DN_COMPILER_MSVC) - #define DN_FMT_ATTRIB _Printf_format_string_ -#else - #define DN_FMT_ATTRIB -#endif - -// NOTE: Type Cast -#define DN_Cast(val) (val) - -// NOTE: Zero initialisation macro -#if defined(__cplusplus) - #define DN_ZeroInit {} -#else - #define DN_ZeroInit {0} -#endif - -// NOTE: Address sanitizer -#if !defined(DN_ASAN_POISON) - #define DN_ASAN_POISON 0 -#endif - -#if !defined(DN_ASAN_VET_POISON) - #define DN_ASAN_VET_POISON 0 -#endif - -#define DN_ASAN_POISON_ALIGNMENT 8 - -#if !defined(DN_ASAN_POISON_GUARD_SIZE) - #define DN_ASAN_POISON_GUARD_SIZE 128 -#endif - -#if DN_HAS_FEATURE(address_sanitizer) || defined(__SANITIZE_ADDRESS__) - #include -#endif -#endif // !defined(DN_BASE_COMPILER_H) -// DN: Single header generator commented out this header => #include "Base/dn_base.h" -#if !defined(DN_BASE_H) -#define DN_BASE_H - -#if defined(_CLANGD) - // DN: Single header generator commented out this header => #include "../dn_base_inc.h" -#endif - -// NOTE: Macros -#define DN_Stringify(x) #x -#define DN_TokenCombine2(x, y) x ## y -#define DN_TokenCombine(x, y) DN_TokenCombine2(x, y) - -#include // va_list -#include -#include -#include -#include // PRIu64... - -#if !defined(DN_OS_WIN32) -#include // exit() -#endif - -#define DN_ForIndexU(index, size) DN_USize index = 0; index < size; index++ -#define DN_ForIndexI(index, size) DN_ISize index = 0; index < size; index++ -#define DN_ForItSize(it, T, array, size) struct { DN_USize index; T *data; } it = {0, &(array)[0]}; it.index < (size); it.index++, it.data = (array) + it.index -#define DN_ForItSizeReverse(it, T, array, size) struct { DN_USize index; T *data; } it = {(size) - 1, &(array)[size - 1]}; it.index < (size); it.index--, it.data = (array) + it.index -#define DN_ForIt(it, T, array) struct { DN_USize index; T *data; } it = {0, &(array)->data[0]}; it.index < (array)->size; it.index++, it.data = ((array)->data) + it.index -#define DN_ForLinkedListIt(it, T, list) struct { DN_USize index; T *data; } it = {0, list}; it.data; it.index++, it.data = ((it).data->next) -#define DN_ForItCArray(it, T, array) struct { DN_USize index; T *data; } it = {0, &(array)[0]}; it.index < DN_ArrayCountU(array); it.index++, it.data = (array) + it.index - -#define DN_AlignUpPowerOfTwo(value, pot) (((uintptr_t)(value) + ((uintptr_t)(pot) - 1)) & ~((uintptr_t)(pot) - 1)) -#define DN_AlignDownPowerOfTwo(value, pot) ((uintptr_t)(value) & ~((uintptr_t)(pot) - 1)) -#define DN_IsPowerOfTwo(value) ((((uintptr_t)(value)) & (((uintptr_t)(value)) - 1)) == 0) -#define DN_IsPowerOfTwoAligned(value, pot) ((((uintptr_t)value) & (((uintptr_t)pot) - 1)) == 0) - -// NOTE: String.h Dependencies -#if !defined(DN_Memcpy) || !defined(DN_Memset) || !defined(DN_Memcmp) || !defined(DN_Memmove) - #include - #if !defined(DN_Memcpy) - #define DN_Memcpy(dest, src, count) memcpy((dest), (src), (count)) - #endif - #if !defined(DN_Memset) - #define DN_Memset(dest, value, count) memset((dest), (value), (count)) - #endif - #if !defined(DN_Memcmp) - #define DN_Memcmp(lhs, rhs, count) memcmp((lhs), (rhs), (count)) - #endif - #if !defined(DN_Memmove) - #define DN_Memmove(dest, src, count) memmove((dest), (src), (count)) - #endif -#endif - -// NOTE: Math.h Dependencies -#if !defined(DN_SqrtF32) || !defined(DN_SinF32) || !defined(DN_CosF32) || !defined(DN_TanF32) - #include - #if !defined(DN_SqrtF32) - #define DN_SqrtF32(val) sqrtf(val) - #endif - #if !defined(DN_SinF32) - #define DN_SinF32(val) sinf(val) - #endif - #if !defined(DN_CosF32) - #define DN_CosF32(val) cosf(val) - #endif - #if !defined(DN_TanF32) - #define DN_TanF32(val) tanf(val) - #endif -#endif - -// NOTE: Math -#define DN_PiF32 3.14159265359f - -#define DN_DegreesToRadians(degrees) ((degrees) * (DN_PI / 180.0f)) -#define DN_RadiansToDegrees(radians) ((radians) * (180.f * DN_PI)) - -#define DN_Abs(val) (((val) < 0) ? (-(val)) : (val)) -#define DN_Max(a, b) (((a) > (b)) ? (a) : (b)) -#define DN_Min(a, b) (((a) < (b)) ? (a) : (b)) -#define DN_Clamp(val, lo, hi) DN_Max(DN_Min(val, hi), lo) -#define DN_Squared(val) ((val) * (val)) - -#define DN_Swap(a, b) \ - do { \ - auto temp = a; \ - a = b; \ - b = temp; \ - } while (0) - -// NOTE: Size -#define DN_SizeOfI(val) DN_Cast(ptrdiff_t)sizeof(val) -#define DN_ArrayCountU(array) (sizeof(array)/(sizeof((array)[0]))) -#define DN_ArrayCountI(array) (DN_ISize)DN_ArrayCountU(array) -#define DN_CharCountU(string) (sizeof(string) - 1) - -// NOTE: SI Byte -#define DN_Bytes(val) ((DN_U64)val) -#define DN_Kilobytes(val) ((DN_U64)1024 * DN_Bytes(val)) -#define DN_Megabytes(val) ((DN_U64)1024 * DN_Kilobytes(val)) -#define DN_Gigabytes(val) ((DN_U64)1024 * DN_Megabytes(val)) - -// NOTE: Time -#define DN_MsFromSec(val) ((val) * 1000ULL) -#define DN_SecFromMins(val) ((val) * 60ULL) -#define DN_SecFromHours(val) (DN_SecFromMins(val) * 60ULL) -#define DN_SecFromDays(val) (DN_SecFromHours(val) * 24ULL) -#define DN_SecFromWeeks(val) (DN_SecFromDays(val) * 7ULL) -#define DN_SecFromYears(val) (DN_SecFromWeeks(val) * 52ULL) - -// NOTE: Debug Break -#if !defined(DN_DebugBreak) - #if defined(NDEBUG) - #define DN_DebugBreak - #else - #if defined(DN_COMPILER_MSVC) || defined(DN_COMPILER_CLANG_CL) - #define DN_DebugBreak __debugbreak() - #elif DN_HAS_BUILTIN(__builtin_debugtrap) - #define DN_DebugBreak __builtin_debugtrap() - #elif DN_HAS_BUILTIN(__builtin_trap) || defined(DN_COMPILER_GCC) - #define DN_DebugBreak __builtin_trap() - #else - #include - #if defined(SIGTRAP) - #define DN_DebugBreak raise(SIGTRAP) - #else - #define DN_DebugBreak raise(SIGABRT) - #endif - #endif - #endif -#endif - -// NOTE: Byte swaps -#define DN_ByteSwap64(u64) (((((u64) >> 56) & 0xFF) << 0) | \ - ((((u64) >> 48) & 0xFF) << 8) | \ - ((((u64) >> 40) & 0xFF) << 16) | \ - ((((u64) >> 32) & 0xFF) << 24) | \ - ((((u64) >> 24) & 0xFF) << 32) | \ - ((((u64) >> 16) & 0xFF) << 40) | \ - ((((u64) >> 8) & 0xFF) << 48) | \ - ((((u64) >> 0) & 0xFF) << 56)) - -// NOTE: Types -typedef intptr_t DN_ISize; -typedef uintptr_t DN_USize; - -typedef int8_t DN_I8; -typedef int16_t DN_I16; -typedef int32_t DN_I32; -typedef int64_t DN_I64; - -typedef uint8_t DN_U8; -typedef uint16_t DN_U16; -typedef uint32_t DN_U32; -typedef uint64_t DN_U64; - -typedef uintptr_t DN_UPtr; -typedef float DN_F32; -typedef double DN_F64; -typedef unsigned int DN_UInt; -typedef DN_I32 DN_B32; - -#define DN_F32_MAX 3.402823466e+38F -#define DN_F32_MIN 1.175494351e-38F -#define DN_F64_MAX 1.7976931348623158e+308 -#define DN_F64_MIN 2.2250738585072014e-308 -#define DN_USIZE_MAX UINTPTR_MAX -#define DN_ISIZE_MAX INTPTR_MAX -#define DN_ISIZE_MIN INTPTR_MIN - -enum DN_ZMem -{ - DN_ZMem_No, // Memory can be handed out without zero-ing it out - DN_ZMem_Yes, // Memory should be zero-ed out before giving to the callee -}; - -struct DN_Str8 -{ - char *data; // The bytes of the string - DN_USize size; // The number of bytes in the string -}; - -struct DN_Str8x16 { char data[16]; DN_USize size; }; -struct DN_Str8x32 { char data[32]; DN_USize size; }; -struct DN_Str8x64 { char data[64]; DN_USize size; }; -struct DN_Str8x128 { char data[128]; DN_USize size; }; -struct DN_Str8x256 { char data[256]; DN_USize size; }; - -struct DN_Hex32 { char data[32]; }; -struct DN_Hex64 { char data[64]; }; -struct DN_Hex128 { char data[128]; }; +struct DN_Hex32 { char data[32 + 1]; DN_USize size; }; +struct DN_Hex64 { char data[64 + 1]; DN_USize size; }; +struct DN_Hex128 { char data[128 + 1]; DN_USize size; }; struct DN_HexU64Str8 { @@ -8114,28 +724,37 @@ enum DN_HexFromU64Type DN_HexFromU64Type_Uppercase, }; -struct DN_Str16 // A pointer and length style string that holds slices to UTF16 bytes. +enum DN_TrimLeadingZero { - wchar_t *data; // The UTF16 bytes of the string - DN_USize size; // The number of characters in the string + DN_TrimLeadingZero_No, + DN_TrimLeadingZero_Yes, }; struct DN_U8x16 { DN_U8 data[16]; }; struct DN_U8x32 { DN_U8 data[32]; }; struct DN_U8x64 { DN_U8 data[64]; }; -template -struct DN_Slice // A pointer and length container of data +DN_MSVC_WARNING_PUSH +DN_MSVC_WARNING_DISABLE(4201) // warning C4201: nonstandard extension used: nameless struct/union +union DN_V2USize { - T *data; - DN_USize size; - - T *begin() { return data; } - T *end() { return data + size; } - T const *begin() const { return data; } - T const *end() const { return data + size; } + struct { DN_USize x, y; }; + struct { DN_USize w, h; }; + struct { DN_USize min, max; }; + struct { DN_USize begin, end; }; + DN_USize data[2]; }; +union DN_V2U64 +{ + struct { DN_U64 x, y; }; + struct { DN_U64 w, h; }; + struct { DN_U64 min, max; }; + struct { DN_U64 begin, end; }; + DN_U64 data[2]; +}; +DN_MSVC_WARNING_POP + struct DN_CallSite { DN_Str8 file; @@ -8145,7 +764,6 @@ struct DN_CallSite #define DN_CALL_SITE DN_CallSite { DN_Str8Lit(__FILE__), DN_Str8Lit(__func__), __LINE__ } -// NOTE: Defer Macro #if defined(__cplusplus) template struct DN_Defer @@ -8170,187 +788,63 @@ struct DN_DeferHelper DN_UniqueName(once); \ end, DN_UniqueName(once) = false - -// NOTE: Intrinsics -// NOTE: DN_AtomicAdd/Exchange return the previous value store in the target -#if defined(DN_COMPILER_MSVC) || defined(DN_COMPILER_CLANG_CL) - #include - #define DN_AtomicCompareExchange64(dest, desired_val, prev_val) _InterlockedCompareExchange64((__int64 volatile *)dest, desired_val, prev_val) - #define DN_AtomicCompareExchange32(dest, desired_val, prev_val) _InterlockedCompareExchange((long volatile *)dest, desired_val, prev_val) - - #define DN_AtomicLoadU64(target) *(target) - #define DN_AtomicLoadU32(target) *(target) - #define DN_AtomicAddU32(target, value) _InterlockedExchangeAdd((long volatile *)target, value) - #define DN_AtomicAddU64(target, value) _InterlockedExchangeAdd64((__int64 volatile *)target, value) - #define DN_AtomicSubU32(target, value) DN_AtomicAddU32(DN_Cast(long volatile *) target, (long)-value) - #define DN_AtomicSubU64(target, value) DN_AtomicAddU64(target, (DN_U64) - value) - - #define DN_CountLeadingZerosU64(value) __lzcnt64(value) - #define DN_CountLeadingZerosU32(value) __lzcnt(value) - #define DN_CPUGetTSC() __rdtsc() - #define DN_CompilerReadBarrierAndCPUReadFence _ReadBarrier(); _mm_lfence() - #define DN_CompilerWriteBarrierAndCPUWriteFence _WriteBarrier(); _mm_sfence() -#elif defined(DN_COMPILER_GCC) || defined(DN_COMPILER_CLANG) - #if defined(__ANDROID__) - #elif defined(DN_PLATFORM_EMSCRIPTEN) - #if !defined(__wasm_simd128__) - #error DN_Base requires -msse2 to be passed to Emscripten - #endif - #include - #else - #include - #endif - - #define DN_AtomicLoadU64(target) __atomic_load_n(x, __ATOMIC_SEQ_CST) - #define DN_AtomicLoadU32(target) __atomic_load_n(x, __ATOMIC_SEQ_CST) - #define DN_AtomicAddU32(target, value) __atomic_fetch_add(target, value, __ATOMIC_ACQ_REL) - #define DN_AtomicAddU64(target, value) __atomic_fetch_add(target, value, __ATOMIC_ACQ_REL) - #define DN_AtomicSubU32(target, value) __atomic_fetch_sub(target, value, __ATOMIC_ACQ_REL) - #define DN_AtomicSubU64(target, value) __atomic_fetch_sub(target, value, __ATOMIC_ACQ_REL) - - #define DN_CountLeadingZerosU64(value) __builtin_clzll(value) - #define DN_CountLeadingZerosU32(value) __builtin_clzl(value) - - #if defined(DN_COMPILER_GCC) - #define DN_CPUGetTSC() __rdtsc() - #else - #define DN_CPUGetTSC() __builtin_readcyclecounter() - #endif - - #if defined(DN_PLATFORM_EMSCRIPTEN) - #define DN_CompilerReadBarrierAndCPUReadFence - #define DN_CompilerWriteBarrierAndCPUWriteFence - #else - #define DN_CompilerReadBarrierAndCPUReadFence asm volatile("lfence" ::: "memory") - #define DN_CompilerWriteBarrierAndCPUWriteFence asm volatile("sfence" ::: "memory") - #endif -#else - #error "Compiler not supported" -#endif - -#if defined(__aarch64__) || defined(_M_X64) || defined(__x86_64__) || defined(__x86_64) - #define DN_CountLeadingZerosUSize(value) DN_CountLeadingZerosU64(value) -#else - #define DN_CountLeadingZerosUSize(value) DN_CountLeadingZerosU32(value) -#endif - -struct DN_CPURegisters -{ - int eax; - int ebx; - int ecx; - int edx; -}; - -union DN_CPUIDResult -{ - DN_CPURegisters reg; - int values[4]; -}; - -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) - -enum DN_CPUFeature -{ - #define DN_CPU_FEAT_XENTRY(label) DN_CPUFeature_##label, - DN_CPU_FEAT_XMACRO - #undef DN_CPU_FEAT_XENTRY - DN_CPUFeature_Count, -}; - -struct DN_CPUFeatureDecl -{ - DN_CPUFeature value; - DN_Str8 label; -}; - -struct DN_CPUFeatureQuery -{ - DN_CPUFeature feature; - bool available; -}; - -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]; -}; - -struct DN_TicketMutex -{ - unsigned int volatile ticket; // The next ticket to give out to the thread taking the mutex - unsigned int volatile serving; // The ticket ID to block the mutex on until it is returned -}; - struct DN_U64FromResult { bool success; DN_U64 value; }; +struct DN_USizeFromResult +{ + bool success; + DN_USize value; +}; + struct DN_I64FromResult { bool success; DN_I64 value; }; +struct DN_U8x32FromResult +{ + bool success; + DN_U8x32 value; +}; + +struct DN_StackTraceFrame +{ + DN_U64 address; + DN_U64 line_number; + DN_Str8 file_name; + DN_Str8 function_name; +}; + +struct DN_StackTraceFrameSlice +{ + DN_StackTraceFrame *data; + DN_USize count; +}; + +struct DN_StackTraceRawFrame +{ + void *process; + DN_U64 base_addr; +}; + +struct DN_StackTraceWalkResult +{ + void *process; // [Internal] Windows handle to the process + DN_U64 *base_addr; // The addresses of the functions in the stack trace + DN_U16 size; // The number of `base_addr`'s stored from the walk +}; + +struct DN_StackTraceWalkResultIterator +{ + DN_StackTraceRawFrame raw_frame; + DN_U16 index; +}; + enum DN_MemCommit { DN_MemCommit_No, @@ -8407,36 +901,40 @@ enum DN_MemPage_ #define DN_ARENA_COMMIT_SIZE DN_Kilobytes(64) #endif -enum DN_Allocator +enum DN_MemFuncsType { - DN_Allocator_Arena, - DN_Allocator_Pool, + DN_MemFuncsType_Nil, + DN_MemFuncsType_Heap, + DN_MemFuncsType_Virtual, }; -struct DN_ArenaBlock +typedef void *(DN_MemHeapAllocFunc)(DN_USize size); +typedef void (DN_MemHeapDeallocFunc)(void *ptr); +typedef void *(DN_MemVirtualReserveFunc)(DN_USize size, DN_MemCommit commit, DN_MemPage page_flags); +typedef bool (DN_MemVirtualCommitFunc)(void *ptr, DN_USize size, DN_U32 page_flags); +typedef void (DN_MemVirtualReleaseFunc)(void *ptr, DN_USize size); +struct DN_MemFuncs { - DN_ArenaBlock *prev; - DN_U64 used; - DN_U64 commit; - DN_U64 reserve; - DN_U64 reserve_sum; + DN_MemFuncsType type; + DN_MemHeapAllocFunc *heap_alloc; + DN_MemHeapDeallocFunc *heap_dealloc; + + DN_U32 virtual_page_size; + DN_MemVirtualReserveFunc *virtual_reserve; + DN_MemVirtualCommitFunc *virtual_commit; + DN_MemVirtualReleaseFunc *virtual_release; }; -typedef DN_U32 DN_ArenaFlags; -enum DN_ArenaFlags_ +struct DN_MemBlock { - DN_ArenaFlags_Nil = 0, - DN_ArenaFlags_NoGrow = 1 << 0, - DN_ArenaFlags_NoPoison = 1 << 1, - DN_ArenaFlags_NoAllocTrack = 1 << 2, - DN_ArenaFlags_AllocCanLeak = 1 << 3, - - // NOTE: Internal flags. Do not use - DN_ArenaFlags_UserBuffer = 1 << 4, - DN_ArenaFlags_MemFuncs = 1 << 5, + DN_MemBlock* prev; + DN_U64 used; + DN_U64 commit; + DN_U64 reserve; + DN_U64 reserve_sum; }; -struct DN_ArenaInfo +struct DN_MemListInfo { DN_U64 used; DN_U64 commit; @@ -8444,10 +942,80 @@ struct DN_ArenaInfo DN_U64 blocks; }; -struct DN_ArenaStats +struct DN_MemStats { - DN_ArenaInfo info; - DN_ArenaInfo hwm; + DN_MemListInfo info; + DN_MemListInfo hwm; +}; + +typedef DN_U32 DN_MemFlags; +enum DN_MemFlags_ +{ + DN_MemFlags_Nil = 0, + DN_MemFlags_NoGrow = 1 << 0, + DN_MemFlags_NoPoison = 1 << 1, + DN_MemFlags_NoAllocTrack = 1 << 2, + DN_MemFlags_AllocCanLeak = 1 << 3, + DN_MemFlags_SimAlloc = 1 << 4, + + // NOTE: Records stack traces of temp memory regions on construction to provide more diagnostics + // when UAF violation occurs in the use of a region (e.g. nested regions A and B, with A + // allocating whilst B is active would result in A's memory being wiped at the end of B). Tracing + // has a heavy performance penalty as each scratch/temp memory region triggers and stores the + // stack trace. + // + // Ignored if UAF guard is disabled at the preprocessor level + // (e.g.: #define DN_ARENA_TEMP_MEM_UAF_GUARD 0) + DN_MemFlags_TempMemUAFTrace = 1 << 5, + + // NOTE: Forcibly disables TempMemUAFTrace for the arena irrespective of global settings. Globally + // UAF tracing can be enabled across all arenas via the preprocessor which turns the tracing + // feature (e.g.: #define DN_ARENA_TEMP_MEM_UAF_TRACE_ON_BY_DEFAULT 1) into an opt-out situation + // where arenas have to specify this flag, specifically to not be traced. + // + // If both TempMemUAFTrace, TempMemUAFTraceDisable and or the global preprocessor flag is set + // disabling takes precedence, always if it is set. + DN_MemFlags_TempMemUAFTraceDisable = 1 << 6, + + // NOTE: Internal flags. Do not use + DN_MemFlags_UserBuffer = 1 << 7, + DN_MemFlags_MemFuncs = 1 << 8, +}; + +struct DN_MemList +{ + DN_MemBlock* curr; + DN_MemFlags flags; + DN_MemFuncs funcs; + DN_MemStats stats; + DN_Str8 label; + + #if DN_ARENA_TEMP_MEM_UAF_GUARD + DN_U32 uaf_guard_next_id; + DN_U32 uaf_guard_active_id; + struct DN_MemListTemp* uaf_guard_active_temp_mem; + #endif +}; + +struct DN_MemListTemp +{ + DN_MemList* mem; + DN_U64 used_sum; + #if DN_ARENA_TEMP_MEM_UAF_GUARD + DN_StackTraceWalkResult trace; + #endif +}; + +enum DN_AllocatorType +{ + DN_AllocatorType_Arena, + DN_AllocatorType_Pool, +}; + +struct DN_Allocator +{ + DN_AllocatorType type; + void* context; }; struct DN_ArenaStatsStr8x64 @@ -8456,51 +1024,24 @@ struct DN_ArenaStatsStr8x64 DN_Str8x64 hwm; }; -enum DN_ArenaMemFuncType +enum DN_ArenaReset { - DN_ArenaMemFuncType_Nil, - DN_ArenaMemFuncType_Basic, - DN_ArenaMemFuncType_VMem, -}; - -typedef void *(DN_ArenaMemBasicAllocFunc)(DN_USize size); -typedef void (DN_ArenaMemBasicDeallocFunc)(void *ptr); -typedef void *(DN_ArenaMemVMemReserveFunc)(DN_USize size, DN_MemCommit commit, DN_MemPage page_flags); -typedef bool (DN_ArenaMemVMemCommitFunc)(void *ptr, DN_USize size, DN_U32 page_flags); -typedef void (DN_ArenaMemVMemReleaseFunc)(void *ptr, DN_USize size); -struct DN_ArenaMemFuncs -{ - DN_ArenaMemFuncType type; - DN_ArenaMemBasicAllocFunc *basic_alloc; - DN_ArenaMemBasicDeallocFunc *basic_dealloc; - - DN_U32 vmem_page_size; - DN_ArenaMemVMemReserveFunc *vmem_reserve; - DN_ArenaMemVMemCommitFunc *vmem_commit; - DN_ArenaMemVMemReleaseFunc *vmem_release; + DN_ArenaReset_No, + DN_ArenaReset_Yes, }; struct DN_Arena { - DN_ArenaMemFuncs mem_funcs; - DN_ArenaBlock *curr; - DN_ArenaStats stats; - DN_ArenaFlags flags; - DN_Str8 label; - DN_Arena *prev, *next; -}; - -struct DN_ArenaTempMem -{ - DN_Arena *arena; - DN_U64 used_sum; -}; - -struct DN_ArenaTempMemScope -{ - DN_ArenaTempMemScope(DN_Arena *arena); - ~DN_ArenaTempMemScope(); - DN_ArenaTempMem mem; + DN_MemList* mem; + #if DN_ARENA_TEMP_MEM_UAF_GUARD + DN_U32 uaf_guard_id; + DN_MemListTemp* uaf_guard_temp_mem; + DN_U32 uaf_guard_prev_id; + DN_MemListTemp* uaf_guard_prev_temp_mem; + bool uaf_guard_is_being_checked; + #else + DN_MemListTemp temp_mem; + #endif }; DN_USize const DN_ARENA_HEADER_SIZE = DN_AlignUpPowerOfTwo(sizeof(DN_Arena), 64); @@ -8558,6 +1099,29 @@ struct DN_Pool DN_U8 align; }; +struct DN_UTF8DecodeResult +{ + bool success; + DN_Str8 remaining; + DN_U32 codepoint; +}; + +struct DN_UTF8DecodeIterator +{ + bool init; + bool success; + DN_Str8 remaining; + DN_USize codepoint_index; + DN_U32 codepoint; +}; + +typedef DN_U32 DN_CodepointCountFlags; +enum DN_CodepointCountFlags_ +{ + DN_CodepointCountFlags_Nil = 0, + DN_CodepointCountFlags_SkipANSICode = 1 << 0, +}; + struct DN_NibbleFromU8Result { char nibble0; @@ -8578,8 +1142,11 @@ enum DN_Str8IsAllType struct DN_Str8BSplitResult { - DN_Str8 lhs; - DN_Str8 rhs; + // If there are multiple strings passed to split against, this is the index into that array of + // which the string was split on. If no array was passed this is always 0. + DN_USize input_index; + DN_Str8 lhs; + DN_Str8 rhs; }; struct DN_Str8FindResult @@ -8592,7 +1159,8 @@ struct DN_Str8FindResult DN_Str8 start_to_before_match; // Substring from the start of the buffer up until the found string, not including it }; -enum DN_Str8FindFlag +typedef DN_USize DN_Str8FindFlag; +enum DN_Str8FindFlag_ { DN_Str8FindFlag_Digit = 1 << 0, // 0-9 DN_Str8FindFlag_Whitespace = 1 << 1, // '\r', '\t', '\n', ' ' @@ -8602,16 +1170,18 @@ enum DN_Str8FindFlag DN_Str8FindFlag_AlphaNum = DN_Str8FindFlag_Alphabet | DN_Str8FindFlag_Digit, }; -enum DN_Str8SplitIncludeEmptyStrings +typedef DN_USize DN_Str8SplitFlags; +enum DN_Str8SplitFlags_ { - DN_Str8SplitIncludeEmptyStrings_No, - DN_Str8SplitIncludeEmptyStrings_Yes, + DN_Str8SplitFlags_ExcludeEmptyStrings = 1 << 0, + DN_Str8SplitFlags_HandleQuotedStrings = 1 << 1, }; -struct DN_Str8TruncateResult +struct DN_Str8TruncResult { - bool truncated; - DN_Str8 str8; + bool truncated; + DN_Str8 str8; + DN_USize size_req; // Not including null-terminator }; struct DN_Str8SplitResult @@ -8620,6 +1190,14 @@ struct DN_Str8SplitResult DN_USize count; }; +typedef DN_USize DN_Str8TableFlags; +enum DN_Str8TableFlags_ +{ + DN_Str8TableFlags_None = 0, + DN_Str8TableFlags_HasHeader = 1 << 0, + DN_Str8TableFlags_RowLines = 1 << 1, +}; + struct DN_Str8Link { DN_Str8 string; // The string @@ -8629,9 +1207,9 @@ struct DN_Str8Link struct DN_Str8Builder { - DN_Arena *arena; // Allocator to use to back the string list - DN_Str8Link *head; // First string in the linked list of strings - DN_Str8Link *tail; // Last string in the linked list of strings + DN_Arena* arena; // Allocator to use to back the string list + DN_Str8Link* head; // First string in the linked list of strings + DN_Str8Link* tail; // Last string in the linked list of strings DN_USize string_size; // The size in bytes necessary to construct the current string DN_USize count; // The number of links in the linked list of strings }; @@ -8737,2449 +1315,134 @@ struct DN_Profiler DN_F64 frame_avg_tsc; }; -#if !defined(DN_STB_SPRINTF_HEADER_ONLY) - #define STB_SPRINTF_IMPLEMENTATION - #define STB_SPRINTF_STATIC -#endif - -DN_MSVC_WARNING_PUSH -DN_MSVC_WARNING_DISABLE(4505) // Unused function warning -DN_GCC_WARNING_PUSH -DN_GCC_WARNING_DISABLE(-Wunused-function) -// DN: Single header generator commented out this header => #include "../External/stb_sprintf.h" -// NOTE: Additional *unofficial* changes -// - Adding STBSP__ASAN to STBSP__PUBLICDEC so that MSVC's ASAN does not trigger (https://github.com/nothings/stb/pull/1350) -// - Adding __attribute__((no_sanitize("undefined"))) to STBSP__ASAN for CLANG so that UBSAN does not trigger (https://github.com/nothings/stb/pull/1477) -// - Adding '%S' for DN_Str8 -// - Using defined(__wasm64__) to correctly assign stbsp__uintptr to stbsp__uint64 for a 64bit WASM target. - -// stb_sprintf - v1.10 - public domain snprintf() implementation -// originally by Jeff Roberts / RAD Game Tools, 2015/10/20 -// http://github.com/nothings/stb -// -// allowed types: sc uidBboXx p AaGgEef n -// lengths : hh h ll j z t I64 I32 I -// -// Contributors: -// Fabian "ryg" Giesen (reformatting) -// github:aganm (attribute format) -// -// Contributors (bugfixes): -// github:d26435 -// github:trex78 -// github:account-login -// Jari Komppa (SI suffixes) -// Rohit Nirmal -// Marcin Wojdyr -// Leonard Ritter -// Stefano Zanotti -// Adam Allison -// Arvid Gerstmann -// Markus Kolb -// -// LICENSE: -// -// See end of file for license information. - -#ifndef STB_SPRINTF_H_INCLUDE -#define STB_SPRINTF_H_INCLUDE - -/* -Single file sprintf replacement. - -Originally written by Jeff Roberts at RAD Game Tools - 2015/10/20. -Hereby placed in public domain. - -This is a full sprintf replacement that supports everything that -the C runtime sprintfs support, including float/double, 64-bit integers, -hex floats, field parameters (%*.*d stuff), length reads backs, etc. - -Why would you need this if sprintf already exists? Well, first off, -it's *much* faster (see below). It's also much smaller than the CRT -versions code-space-wise. We've also added some simple improvements -that are super handy (commas in thousands, callbacks at buffer full, -for example). Finally, the format strings for MSVC and GCC differ -for 64-bit integers (among other small things), so this lets you use -the same format strings in cross platform code. - -It uses the standard single file trick of being both the header file -and the source itself. If you just include it normally, you just get -the header file function definitions. To get the code, you include -it from a C or C++ file and define STB_SPRINTF_IMPLEMENTATION first. - -It only uses va_args macros from the C runtime to do it's work. It -does cast doubles to S64s and shifts and divides U64s, which does -drag in CRT code on most platforms. - -It compiles to roughly 8K with float support, and 4K without. -As a comparison, when using MSVC static libs, calling sprintf drags -in 16K. - -API: -==== -int stbsp_sprintf( char * buf, char const * fmt, ... ) -int stbsp_snprintf( char * buf, int count, char const * fmt, ... ) - Convert an arg list into a buffer. stbsp_snprintf always returns - a zero-terminated string (unlike regular snprintf). - -int stbsp_vsprintf( char * buf, char const * fmt, va_list va ) -int stbsp_vsnprintf( char * buf, int count, char const * fmt, va_list va ) - Convert a va_list arg list into a buffer. stbsp_vsnprintf always returns - a zero-terminated string (unlike regular snprintf). - -int stbsp_vsprintfcb( STBSP_SPRINTFCB * callback, void * user, char * buf, char const * fmt, va_list va ) - typedef char * STBSP_SPRINTFCB( char const * buf, void * user, int len ); - Convert into a buffer, calling back every STB_SPRINTF_MIN chars. - Your callback can then copy the chars out, print them or whatever. - This function is actually the workhorse for everything else. - The buffer you pass in must hold at least STB_SPRINTF_MIN characters. - // you return the next buffer to use or 0 to stop converting - -void stbsp_set_separators( char comma, char period ) - Set the comma and period characters to use. - -FLOATS/DOUBLES: -=============== -This code uses a internal float->ascii conversion method that uses -doubles with error correction (double-doubles, for ~105 bits of -precision). This conversion is round-trip perfect - that is, an atof -of the values output here will give you the bit-exact double back. - -One difference is that our insignificant digits will be different than -with MSVC or GCC (but they don't match each other either). We also -don't attempt to find the minimum length matching float (pre-MSVC15 -doesn't either). - -If you don't need float or doubles at all, define STB_SPRINTF_NOFLOAT -and you'll save 4K of code space. - -64-BIT INTS: -============ -This library also supports 64-bit integers and you can use MSVC style or -GCC style indicators (%I64d or %lld). It supports the C99 specifiers -for size_t and ptr_diff_t (%jd %zd) as well. - -EXTRAS: -======= -Like some GCCs, for integers and floats, you can use a ' (single quote) -specifier and commas will be inserted on the thousands: "%'d" on 12345 -would print 12,345. - -For integers and floats, you can use a "$" specifier and the number -will be converted to float and then divided to get kilo, mega, giga or -tera and then printed, so "%$d" 1000 is "1.0 k", "%$.2d" 2536000 is -"2.53 M", etc. For byte values, use two $:s, like "%$$d" to turn -2536000 to "2.42 Mi". If you prefer JEDEC suffixes to SI ones, use three -$:s: "%$$$d" -> "2.42 M". To remove the space between the number and the -suffix, add "_" specifier: "%_$d" -> "2.53M". - -In addition to octal and hexadecimal conversions, you can print -integers in binary: "%b" for 256 would print 100. - -PERFORMANCE vs MSVC 2008 32-/64-bit (GCC is even slower than MSVC): -=================================================================== -"%d" across all 32-bit ints (4.8x/4.0x faster than 32-/64-bit MSVC) -"%24d" across all 32-bit ints (4.5x/4.2x faster) -"%x" across all 32-bit ints (4.5x/3.8x faster) -"%08x" across all 32-bit ints (4.3x/3.8x faster) -"%f" across e-10 to e+10 floats (7.3x/6.0x faster) -"%e" across e-10 to e+10 floats (8.1x/6.0x faster) -"%g" across e-10 to e+10 floats (10.0x/7.1x faster) -"%f" for values near e-300 (7.9x/6.5x faster) -"%f" for values near e+300 (10.0x/9.1x faster) -"%e" for values near e-300 (10.1x/7.0x faster) -"%e" for values near e+300 (9.2x/6.0x faster) -"%.320f" for values near e-300 (12.6x/11.2x faster) -"%a" for random values (8.6x/4.3x faster) -"%I64d" for 64-bits with 32-bit values (4.8x/3.4x faster) -"%I64d" for 64-bits > 32-bit values (4.9x/5.5x faster) -"%s%s%s" for 64 char strings (7.1x/7.3x faster) -"...512 char string..." ( 35.0x/32.5x faster!) -*/ - -#if defined(__clang__) - #if defined(__has_feature) && defined(__has_attribute) - #if __has_feature(address_sanitizer) - #if __has_attribute(__no_sanitize__) - #define STBSP__ASAN __attribute__((__no_sanitize__("address"))) - #elif __has_attribute(__no_sanitize_address__) - #define STBSP__ASAN __attribute__((__no_sanitize_address__)) - #elif __has_attribute(__no_address_safety_analysis__) - #define STBSP__ASAN __attribute__((__no_address_safety_analysis__)) - #endif - #endif - #endif -#elif defined(__GNUC__) && (__GNUC__ >= 5 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8)) - #if defined(__SANITIZE_ADDRESS__) && __SANITIZE_ADDRESS__ - #define STBSP__ASAN __attribute__((__no_sanitize_address__)) - #endif -#elif defined(_MSC_VER) - #if defined(__SANITIZE_ADDRESS__) - #define STBSP__ASAN __declspec(no_sanitize_address) - #endif -#endif - -#ifndef STBSP__ASAN -#define STBSP__ASAN -#endif - -#ifdef STB_SPRINTF_STATIC -#define STBSP__PUBLICDEC static STBSP__ASAN -#define STBSP__PUBLICDEF static STBSP__ASAN -#else -#ifdef __cplusplus -#define STBSP__PUBLICDEC extern "C" STBSP__ASAN -#define STBSP__PUBLICDEF extern "C" STBSP__ASAN -#else -#define STBSP__PUBLICDEC extern STBSP__ASAN -#define STBSP__PUBLICDEF STBSP__ASAN -#endif -#endif - -#if defined(__has_attribute) - #if __has_attribute(format) - #define STBSP__ATTRIBUTE_FORMAT(fmt,va) __attribute__((format(printf,fmt,va))) - #endif -#endif - -#ifndef STBSP__ATTRIBUTE_FORMAT -#define STBSP__ATTRIBUTE_FORMAT(fmt,va) -#endif - -#ifdef _MSC_VER -#define STBSP__NOTUSED(v) (void)(v) -#else -#define STBSP__NOTUSED(v) (void)sizeof(v) -#endif - -#include // for va_arg(), va_list() -#include // size_t, ptrdiff_t - -#ifndef STB_SPRINTF_MIN -#define STB_SPRINTF_MIN 512 // how many characters per callback -#endif -typedef char *STBSP_SPRINTFCB(const char *buf, void *user, int len); - -#ifndef STB_SPRINTF_DECORATE -#define STB_SPRINTF_DECORATE(name) stbsp_##name // define this before including if you want to change the names -#endif - -STBSP__PUBLICDEC int STB_SPRINTF_DECORATE(vsprintf)(char *buf, char const *fmt, va_list va); -STBSP__PUBLICDEC int STB_SPRINTF_DECORATE(vsnprintf)(char *buf, int count, char const *fmt, va_list va); -STBSP__PUBLICDEC int STB_SPRINTF_DECORATE(sprintf)(char *buf, char const *fmt, ...) STBSP__ATTRIBUTE_FORMAT(2,3); -STBSP__PUBLICDEC int STB_SPRINTF_DECORATE(snprintf)(char *buf, int count, char const *fmt, ...) STBSP__ATTRIBUTE_FORMAT(3,4); - -STBSP__PUBLICDEC int STB_SPRINTF_DECORATE(vsprintfcb)(STBSP_SPRINTFCB *callback, void *user, char *buf, char const *fmt, va_list va); -STBSP__PUBLICDEC void STB_SPRINTF_DECORATE(set_separators)(char comma, char period); - -#endif // STB_SPRINTF_H_INCLUDE - -#ifdef STB_SPRINTF_IMPLEMENTATION - -#define stbsp__uint32 unsigned int -#define stbsp__int32 signed int - -#ifdef _MSC_VER -#define stbsp__uint64 unsigned __int64 -#define stbsp__int64 signed __int64 -#else -#define stbsp__uint64 unsigned long long -#define stbsp__int64 signed long long -#endif -#define stbsp__uint16 unsigned short - -#ifndef stbsp__uintptr -#if defined(__ppc64__) || defined(__powerpc64__) || defined(__aarch64__) || defined(_M_X64) || defined(__x86_64__) || defined(__x86_64) || defined(__s390x__) || defined(__wasm64__) -#define stbsp__uintptr stbsp__uint64 -#else -#define stbsp__uintptr stbsp__uint32 -#endif -#endif - -#ifndef STB_SPRINTF_MSVC_MODE // used for MSVC2013 and earlier (MSVC2015 matches GCC) -#if defined(_MSC_VER) && (_MSC_VER < 1900) -#define STB_SPRINTF_MSVC_MODE -#endif -#endif - -#ifdef STB_SPRINTF_NOUNALIGNED // define this before inclusion to force stbsp_sprintf to always use aligned accesses -#define STBSP__UNALIGNED(code) -#else -#define STBSP__UNALIGNED(code) code -#endif - -#ifndef STB_SPRINTF_NOFLOAT -// internal float utility functions -static stbsp__int32 stbsp__real_to_str(char const **start, stbsp__uint32 *len, char *out, stbsp__int32 *decimal_pos, double value, stbsp__uint32 frac_digits); -static stbsp__int32 stbsp__real_to_parts(stbsp__int64 *bits, stbsp__int32 *expo, double value); -#define STBSP__SPECIAL 0x7000 -#endif - -static char stbsp__period = '.'; -static char stbsp__comma = ','; -static struct +enum DN_ErrSinkMode { - short temp; // force next field to be 2-byte aligned - char pair[201]; -} stbsp__digitpair = -{ - 0, - "00010203040506070809101112131415161718192021222324" - "25262728293031323334353637383940414243444546474849" - "50515253545556575859606162636465666768697071727374" - "75767778798081828384858687888990919293949596979899" + DN_ErrSinkMode_Nil, // Default behaviour to accumulate errors into the sink + DN_ErrSinkMode_DebugBreakOnErrorLog, // Debug break (int3) when error is encountered and the sink is ended by the 'end and log' functions. + DN_ErrSinkMode_ExitOnError, // When an error is encountered, exit the program with the error code of the error that was caught. }; -STBSP__PUBLICDEF void STB_SPRINTF_DECORATE(set_separators)(char pcomma, char pperiod) +struct DN_ErrSinkMsg { - stbsp__period = pperiod; - stbsp__comma = pcomma; -} + DN_I32 error_code; + DN_Str8 msg; + DN_CallSite call_site; + DN_ErrSinkMsg *next; + DN_ErrSinkMsg *prev; +}; -#define STBSP__LEFTJUST 1 -#define STBSP__LEADINGPLUS 2 -#define STBSP__LEADINGSPACE 4 -#define STBSP__LEADING_0X 8 -#define STBSP__LEADINGZERO 16 -#define STBSP__INTMAX 32 -#define STBSP__TRIPLET_COMMA 64 -#define STBSP__NEGATIVE 128 -#define STBSP__METRIC_SUFFIX 256 -#define STBSP__HALFWIDTH 512 -#define STBSP__METRIC_NOSPACE 1024 -#define STBSP__METRIC_1024 2048 -#define STBSP__METRIC_JEDEC 4096 - -static void stbsp__lead_sign(stbsp__uint32 fl, char *sign) +struct DN_ErrSinkNode { - sign[0] = 0; - if (fl & STBSP__NEGATIVE) { - sign[0] = 1; - sign[1] = '-'; - } else if (fl & STBSP__LEADINGSPACE) { - sign[0] = 1; - sign[1] = ' '; - } else if (fl & STBSP__LEADINGPLUS) { - sign[0] = 1; - sign[1] = '+'; - } -} + DN_CallSite call_site; // Call site that the node was created + DN_ErrSinkMode mode; // Controls how the sink behaves when an error is registered onto the sink. + DN_ErrSinkMsg *msg_sentinel; // List of error messages accumulated for the current scope + DN_U64 arena_pos; // Position to reset the arena when the scope is ended +}; -static STBSP__ASAN stbsp__uint32 stbsp__strlen_limited(char const *s, stbsp__uint32 limit) +struct DN_ErrSink { - char const * sn = s; + DN_Arena* arena; // Dedicated allocator from the thread's local storage + DN_ErrSinkNode stack[128]; // Each entry contains errors accumulated between a [begin, end] region of the active sink. + DN_USize stack_size; +}; - // get up to 4-byte alignment - for (;;) { - if (((stbsp__uintptr)sn & 3) == 0) - break; - - if (!limit || *sn == 0) - return (stbsp__uint32)(sn - s); - - ++sn; - --limit; - } - - // scan over 4 bytes at a time to find terminating 0 - // this will intentionally scan up to 3 bytes past the end of buffers, - // but becase it works 4B aligned, it will never cross page boundaries - // (hence the STBSP__ASAN markup; the over-read here is intentional - // and harmless) - while (limit >= 4) { - stbsp__uint32 v = *(stbsp__uint32 *)sn; - // bit hack to find if there's a 0 byte in there - if ((v - 0x01010101) & (~v) & 0x80808080UL) - break; - - sn += 4; - limit -= 4; - } - - // handle the last few characters to find actual size - while (limit && *sn) { - ++sn; - --limit; - } - - return (stbsp__uint32)(sn - s); -} - -STBSP__PUBLICDEF int STB_SPRINTF_DECORATE(vsprintfcb)(STBSP_SPRINTFCB *callback, void *user, char *buf, char const *fmt, va_list va) +struct DN_TCScratch { - static char hex[] = "0123456789abcdefxp"; - static char hexu[] = "0123456789ABCDEFXP"; - char *bf; - char const *f; - int tlen = 0; + DN_Arena arena; + DN_B32 destructed; +}; - bf = buf; - f = fmt; - for (;;) { - stbsp__int32 fw, pr, tz; - stbsp__uint32 fl; - - // macros for the callback buffer stuff - #define stbsp__chk_cb_bufL(bytes) \ - { \ - int len = (int)(bf - buf); \ - if ((len + (bytes)) >= STB_SPRINTF_MIN) { \ - tlen += len; \ - if (0 == (bf = buf = callback(buf, user, len))) \ - goto done; \ - } \ - } - #define stbsp__chk_cb_buf(bytes) \ - { \ - if (callback) { \ - stbsp__chk_cb_bufL(bytes); \ - } \ - } - #define stbsp__flush_cb() \ - { \ - stbsp__chk_cb_bufL(STB_SPRINTF_MIN - 1); \ - } // flush if there is even one byte in the buffer - #define stbsp__cb_buf_clamp(cl, v) \ - cl = v; \ - if (callback) { \ - int lg = STB_SPRINTF_MIN - (int)(bf - buf); \ - if (cl > lg) \ - cl = lg; \ - } - - // fast copy everything up to the next % (or end of string) - for (;;) { - while (((stbsp__uintptr)f) & 3) { - schk1: - if (f[0] == '%') - goto scandd; - schk2: - if (f[0] == 0) - goto endfmt; - stbsp__chk_cb_buf(1); - *bf++ = f[0]; - ++f; - } - for (;;) { - // Check if the next 4 bytes contain %(0x25) or end of string. - // Using the 'hasless' trick: - // https://graphics.stanford.edu/~seander/bithacks.html#HasLessInWord - stbsp__uint32 v, c; - v = *(stbsp__uint32 *)f; - c = (~v) & 0x80808080; - if (((v ^ 0x25252525) - 0x01010101) & c) - goto schk1; - if ((v - 0x01010101) & c) - goto schk2; - if (callback) - if ((STB_SPRINTF_MIN - (int)(bf - buf)) < 4) - goto schk1; - #ifdef STB_SPRINTF_NOUNALIGNED - if(((stbsp__uintptr)bf) & 3) { - bf[0] = f[0]; - bf[1] = f[1]; - bf[2] = f[2]; - bf[3] = f[3]; - } else - #endif - { - *(stbsp__uint32 *)bf = v; - } - bf += 4; - f += 4; - } - } - scandd: - - ++f; - - // ok, we have a percent, read the modifiers first - fw = 0; - pr = -1; - fl = 0; - tz = 0; - - // flags - for (;;) { - switch (f[0]) { - // if we have left justify - case '-': - fl |= STBSP__LEFTJUST; - ++f; - continue; - // if we have leading plus - case '+': - fl |= STBSP__LEADINGPLUS; - ++f; - continue; - // if we have leading space - case ' ': - fl |= STBSP__LEADINGSPACE; - ++f; - continue; - // if we have leading 0x - case '#': - fl |= STBSP__LEADING_0X; - ++f; - continue; - // if we have thousand commas - case '\'': - fl |= STBSP__TRIPLET_COMMA; - ++f; - continue; - // if we have kilo marker (none->kilo->kibi->jedec) - case '$': - if (fl & STBSP__METRIC_SUFFIX) { - if (fl & STBSP__METRIC_1024) { - fl |= STBSP__METRIC_JEDEC; - } else { - fl |= STBSP__METRIC_1024; - } - } else { - fl |= STBSP__METRIC_SUFFIX; - } - ++f; - continue; - // if we don't want space between metric suffix and number - case '_': - fl |= STBSP__METRIC_NOSPACE; - ++f; - continue; - // if we have leading zero - case '0': - fl |= STBSP__LEADINGZERO; - ++f; - goto flags_done; - default: goto flags_done; - } - } - flags_done: - - // get the field width - if (f[0] == '*') { - fw = va_arg(va, stbsp__uint32); - ++f; - } else { - while ((f[0] >= '0') && (f[0] <= '9')) { - fw = fw * 10 + f[0] - '0'; - f++; - } - } - // get the precision - if (f[0] == '.') { - ++f; - if (f[0] == '*') { - pr = va_arg(va, stbsp__uint32); - ++f; - } else { - pr = 0; - while ((f[0] >= '0') && (f[0] <= '9')) { - pr = pr * 10 + f[0] - '0'; - f++; - } - } - } - - // handle integer size overrides - switch (f[0]) { - // are we halfwidth? - case 'h': - fl |= STBSP__HALFWIDTH; - ++f; - if (f[0] == 'h') - ++f; // QUARTERWIDTH - break; - // are we 64-bit (unix style) - case 'l': - fl |= ((sizeof(long) == 8) ? STBSP__INTMAX : 0); - ++f; - if (f[0] == 'l') { - fl |= STBSP__INTMAX; - ++f; - } - break; - // are we 64-bit on intmax? (c99) - case 'j': - fl |= (sizeof(size_t) == 8) ? STBSP__INTMAX : 0; - ++f; - break; - // are we 64-bit on size_t or ptrdiff_t? (c99) - case 'z': - fl |= (sizeof(ptrdiff_t) == 8) ? STBSP__INTMAX : 0; - ++f; - break; - case 't': - fl |= (sizeof(ptrdiff_t) == 8) ? STBSP__INTMAX : 0; - ++f; - break; - // are we 64-bit (msft style) - case 'I': - if ((f[1] == '6') && (f[2] == '4')) { - fl |= STBSP__INTMAX; - f += 3; - } else if ((f[1] == '3') && (f[2] == '2')) { - f += 3; - } else { - fl |= ((sizeof(void *) == 8) ? STBSP__INTMAX : 0); - ++f; - } - break; - default: break; - } - - // handle each replacement - switch (f[0]) { - #define STBSP__NUMSZ 512 // big enough for e308 (with commas) or e-307 - char num[STBSP__NUMSZ]; - char lead[8]; - char tail[8]; - char *s; - char const *h; - stbsp__uint32 l, n, cs; - stbsp__uint64 n64; -#ifndef STB_SPRINTF_NOFLOAT - double fv; -#endif - stbsp__int32 dp; - char const *sn; - - case 's': - // get the string - s = va_arg(va, char *); - if (s == 0) - s = (char *)"null"; - // get the length, limited to desired precision - // always limit to ~0u chars since our counts are 32b - l = stbsp__strlen_limited(s, (pr >= 0) ? pr : ~0u); - lead[0] = 0; - tail[0] = 0; - pr = 0; - dp = 0; - cs = 0; - // copy the string in - goto scopy; - - case 'S': - { - DN_Str8 str8 = va_arg(va, DN_Str8); - s = (char *)str8.data; - l = (uint32_t)str8.size; - lead[0] = 0; - tail[0] = 0; - pr = 0; - dp = 0; - cs = 0; - }goto scopy; - - case 'c': // char - // get the character - s = num + STBSP__NUMSZ - 1; - *s = (char)va_arg(va, int); - l = 1; - lead[0] = 0; - tail[0] = 0; - pr = 0; - dp = 0; - cs = 0; - goto scopy; - - case 'n': // weird write-bytes specifier - { - int *d = va_arg(va, int *); - *d = tlen + (int)(bf - buf); - } break; - -#ifdef STB_SPRINTF_NOFLOAT - case 'A': // float - case 'a': // hex float - case 'G': // float - case 'g': // float - case 'E': // float - case 'e': // float - case 'f': // float - va_arg(va, double); // eat it - s = (char *)"No float"; - l = 8; - lead[0] = 0; - tail[0] = 0; - pr = 0; - cs = 0; - STBSP__NOTUSED(dp); - goto scopy; -#else - case 'A': // hex float - case 'a': // hex float - h = (f[0] == 'A') ? hexu : hex; - fv = va_arg(va, double); - if (pr == -1) - pr = 6; // default is 6 - // read the double into a string - if (stbsp__real_to_parts((stbsp__int64 *)&n64, &dp, fv)) - fl |= STBSP__NEGATIVE; - - s = num + 64; - - stbsp__lead_sign(fl, lead); - - if (dp == -1023) - dp = (n64) ? -1022 : 0; - else - n64 |= (((stbsp__uint64)1) << 52); - n64 <<= (64 - 56); - if (pr < 15) - n64 += ((((stbsp__uint64)8) << 56) >> (pr * 4)); -// add leading chars - -#ifdef STB_SPRINTF_MSVC_MODE - *s++ = '0'; - *s++ = 'x'; -#else - lead[1 + lead[0]] = '0'; - lead[2 + lead[0]] = 'x'; - lead[0] += 2; -#endif - *s++ = h[(n64 >> 60) & 15]; - n64 <<= 4; - if (pr) - *s++ = stbsp__period; - sn = s; - - // print the bits - n = pr; - if (n > 13) - n = 13; - if (pr > (stbsp__int32)n) - tz = pr - n; - pr = 0; - while (n--) { - *s++ = h[(n64 >> 60) & 15]; - n64 <<= 4; - } - - // print the expo - tail[1] = h[17]; - if (dp < 0) { - tail[2] = '-'; - dp = -dp; - } else - tail[2] = '+'; - n = (dp >= 1000) ? 6 : ((dp >= 100) ? 5 : ((dp >= 10) ? 4 : 3)); - tail[0] = (char)n; - for (;;) { - tail[n] = '0' + dp % 10; - if (n <= 3) - break; - --n; - dp /= 10; - } - - dp = (int)(s - sn); - l = (int)(s - (num + 64)); - s = num + 64; - cs = 1 + (3 << 24); - goto scopy; - - case 'G': // float - case 'g': // float - h = (f[0] == 'G') ? hexu : hex; - fv = va_arg(va, double); - if (pr == -1) - pr = 6; - else if (pr == 0) - pr = 1; // default is 6 - // read the double into a string - if (stbsp__real_to_str(&sn, &l, num, &dp, fv, (pr - 1) | 0x80000000)) - fl |= STBSP__NEGATIVE; - - // clamp the precision and delete extra zeros after clamp - n = pr; - if (l > (stbsp__uint32)pr) - l = pr; - while ((l > 1) && (pr) && (sn[l - 1] == '0')) { - --pr; - --l; - } - - // should we use %e - if ((dp <= -4) || (dp > (stbsp__int32)n)) { - if (pr > (stbsp__int32)l) - pr = l - 1; - else if (pr) - --pr; // when using %e, there is one digit before the decimal - goto doexpfromg; - } - // this is the insane action to get the pr to match %g semantics for %f - if (dp > 0) { - pr = (dp < (stbsp__int32)l) ? l - dp : 0; - } else { - pr = -dp + ((pr > (stbsp__int32)l) ? (stbsp__int32) l : pr); - } - goto dofloatfromg; - - case 'E': // float - case 'e': // float - h = (f[0] == 'E') ? hexu : hex; - fv = va_arg(va, double); - if (pr == -1) - pr = 6; // default is 6 - // read the double into a string - if (stbsp__real_to_str(&sn, &l, num, &dp, fv, pr | 0x80000000)) - fl |= STBSP__NEGATIVE; - doexpfromg: - tail[0] = 0; - stbsp__lead_sign(fl, lead); - if (dp == STBSP__SPECIAL) { - s = (char *)sn; - cs = 0; - pr = 0; - goto scopy; - } - s = num + 64; - // handle leading chars - *s++ = sn[0]; - - if (pr) - *s++ = stbsp__period; - - // handle after decimal - if ((l - 1) > (stbsp__uint32)pr) - l = pr + 1; - for (n = 1; n < l; n++) - *s++ = sn[n]; - // trailing zeros - tz = pr - (l - 1); - pr = 0; - // dump expo - tail[1] = h[0xe]; - dp -= 1; - if (dp < 0) { - tail[2] = '-'; - dp = -dp; - } else - tail[2] = '+'; -#ifdef STB_SPRINTF_MSVC_MODE - n = 5; -#else - n = (dp >= 100) ? 5 : 4; -#endif - tail[0] = (char)n; - for (;;) { - tail[n] = '0' + dp % 10; - if (n <= 3) - break; - --n; - dp /= 10; - } - cs = 1 + (3 << 24); // how many tens - goto flt_lead; - - case 'f': // float - fv = va_arg(va, double); - doafloat: - // do kilos - if (fl & STBSP__METRIC_SUFFIX) { - double divisor; - divisor = 1000.0f; - if (fl & STBSP__METRIC_1024) - divisor = 1024.0; - while (fl < 0x4000000) { - if ((fv < divisor) && (fv > -divisor)) - break; - fv /= divisor; - fl += 0x1000000; - } - } - if (pr == -1) - pr = 6; // default is 6 - // read the double into a string - if (stbsp__real_to_str(&sn, &l, num, &dp, fv, pr)) - fl |= STBSP__NEGATIVE; - dofloatfromg: - tail[0] = 0; - stbsp__lead_sign(fl, lead); - if (dp == STBSP__SPECIAL) { - s = (char *)sn; - cs = 0; - pr = 0; - goto scopy; - } - s = num + 64; - - // handle the three decimal varieties - if (dp <= 0) { - stbsp__int32 i; - // handle 0.000*000xxxx - *s++ = '0'; - if (pr) - *s++ = stbsp__period; - n = -dp; - if ((stbsp__int32)n > pr) - n = pr; - i = n; - while (i) { - if ((((stbsp__uintptr)s) & 3) == 0) - break; - *s++ = '0'; - --i; - } - while (i >= 4) { - *(stbsp__uint32 *)s = 0x30303030; - s += 4; - i -= 4; - } - while (i) { - *s++ = '0'; - --i; - } - if ((stbsp__int32)(l + n) > pr) - l = pr - n; - i = l; - while (i) { - *s++ = *sn++; - --i; - } - tz = pr - (n + l); - cs = 1 + (3 << 24); // how many tens did we write (for commas below) - } else { - cs = (fl & STBSP__TRIPLET_COMMA) ? ((600 - (stbsp__uint32)dp) % 3) : 0; - if ((stbsp__uint32)dp >= l) { - // handle xxxx000*000.0 - n = 0; - for (;;) { - if ((fl & STBSP__TRIPLET_COMMA) && (++cs == 4)) { - cs = 0; - *s++ = stbsp__comma; - } else { - *s++ = sn[n]; - ++n; - if (n >= l) - break; - } - } - if (n < (stbsp__uint32)dp) { - n = dp - n; - if ((fl & STBSP__TRIPLET_COMMA) == 0) { - while (n) { - if ((((stbsp__uintptr)s) & 3) == 0) - break; - *s++ = '0'; - --n; - } - while (n >= 4) { - *(stbsp__uint32 *)s = 0x30303030; - s += 4; - n -= 4; - } - } - while (n) { - if ((fl & STBSP__TRIPLET_COMMA) && (++cs == 4)) { - cs = 0; - *s++ = stbsp__comma; - } else { - *s++ = '0'; - --n; - } - } - } - cs = (int)(s - (num + 64)) + (3 << 24); // cs is how many tens - if (pr) { - *s++ = stbsp__period; - tz = pr; - } - } else { - // handle xxxxx.xxxx000*000 - n = 0; - for (;;) { - if ((fl & STBSP__TRIPLET_COMMA) && (++cs == 4)) { - cs = 0; - *s++ = stbsp__comma; - } else { - *s++ = sn[n]; - ++n; - if (n >= (stbsp__uint32)dp) - break; - } - } - cs = (int)(s - (num + 64)) + (3 << 24); // cs is how many tens - if (pr) - *s++ = stbsp__period; - if ((l - dp) > (stbsp__uint32)pr) - l = pr + dp; - while (n < l) { - *s++ = sn[n]; - ++n; - } - tz = pr - (l - dp); - } - } - pr = 0; - - // handle k,m,g,t - if (fl & STBSP__METRIC_SUFFIX) { - char idx; - idx = 1; - if (fl & STBSP__METRIC_NOSPACE) - idx = 0; - tail[0] = idx; - tail[1] = ' '; - { - if (fl >> 24) { // SI kilo is 'k', JEDEC and SI kibits are 'K'. - if (fl & STBSP__METRIC_1024) - tail[idx + 1] = "_KMGT"[fl >> 24]; - else - tail[idx + 1] = "_kMGT"[fl >> 24]; - idx++; - // If printing kibits and not in jedec, add the 'i'. - if (fl & STBSP__METRIC_1024 && !(fl & STBSP__METRIC_JEDEC)) { - tail[idx + 1] = 'i'; - idx++; - } - tail[0] = idx; - } - } - }; - - flt_lead: - // get the length that we copied - l = (stbsp__uint32)(s - (num + 64)); - s = num + 64; - goto scopy; +#if defined(__cplusplus) +struct DN_TCScratchCpp +{ + DN_TCScratchCpp(DN_Arena **conflicts, DN_USize count); + ~DN_TCScratchCpp(); + DN_TCScratch data; +}; #endif - case 'B': // upper binary - case 'b': // lower binary - h = (f[0] == 'B') ? hexu : hex; - lead[0] = 0; - if (fl & STBSP__LEADING_0X) { - lead[0] = 2; - lead[1] = '0'; - lead[2] = h[0xb]; - } - l = (8 << 4) | (1 << 8); - goto radixnum; - - case 'o': // octal - h = hexu; - lead[0] = 0; - if (fl & STBSP__LEADING_0X) { - lead[0] = 1; - lead[1] = '0'; - } - l = (3 << 4) | (3 << 8); - goto radixnum; - - case 'p': // pointer - fl |= (sizeof(void *) == 8) ? STBSP__INTMAX : 0; - pr = sizeof(void *) * 2; - fl &= ~STBSP__LEADINGZERO; // 'p' only prints the pointer with zeros - // fall through - to X - - case 'X': // upper hex - case 'x': // lower hex - h = (f[0] == 'X') ? hexu : hex; - l = (4 << 4) | (4 << 8); - lead[0] = 0; - if (fl & STBSP__LEADING_0X) { - lead[0] = 2; - lead[1] = '0'; - lead[2] = h[16]; - } - radixnum: - // get the number - if (fl & STBSP__INTMAX) - n64 = va_arg(va, stbsp__uint64); - else - n64 = va_arg(va, stbsp__uint32); - - s = num + STBSP__NUMSZ; - dp = 0; - // clear tail, and clear leading if value is zero - tail[0] = 0; - if (n64 == 0) { - lead[0] = 0; - if (pr == 0) { - l = 0; - cs = 0; - goto scopy; - } - } - // convert to string - for (;;) { - *--s = h[n64 & ((1 << (l >> 8)) - 1)]; - n64 >>= (l >> 8); - if (!((n64) || ((stbsp__int32)((num + STBSP__NUMSZ) - s) < pr))) - break; - if (fl & STBSP__TRIPLET_COMMA) { - ++l; - if ((l & 15) == ((l >> 4) & 15)) { - l &= ~15; - *--s = stbsp__comma; - } - } - }; - // get the tens and the comma pos - cs = (stbsp__uint32)((num + STBSP__NUMSZ) - s) + ((((l >> 4) & 15)) << 24); - // get the length that we copied - l = (stbsp__uint32)((num + STBSP__NUMSZ) - s); - // copy it - goto scopy; - - case 'u': // unsigned - case 'i': - case 'd': // integer - // get the integer and abs it - if (fl & STBSP__INTMAX) { - stbsp__int64 i64 = va_arg(va, stbsp__int64); - n64 = (stbsp__uint64)i64; - if ((f[0] != 'u') && (i64 < 0)) { - n64 = (stbsp__uint64)-i64; - fl |= STBSP__NEGATIVE; - } - } else { - stbsp__int32 i = va_arg(va, stbsp__int32); - n64 = (stbsp__uint32)i; - if ((f[0] != 'u') && (i < 0)) { - n64 = (stbsp__uint32)-i; - fl |= STBSP__NEGATIVE; - } - } - -#ifndef STB_SPRINTF_NOFLOAT - if (fl & STBSP__METRIC_SUFFIX) { - if (n64 < 1024) - pr = 0; - else if (pr == -1) - pr = 1; - fv = (double)(stbsp__int64)n64; - goto doafloat; - } -#endif - - // convert to string - s = num + STBSP__NUMSZ; - l = 0; - - for (;;) { - // do in 32-bit chunks (avoid lots of 64-bit divides even with constant denominators) - char *o = s - 8; - if (n64 >= 100000000) { - n = (stbsp__uint32)(n64 % 100000000); - n64 /= 100000000; - } else { - n = (stbsp__uint32)n64; - n64 = 0; - } - if ((fl & STBSP__TRIPLET_COMMA) == 0) { - do { - s -= 2; - *(stbsp__uint16 *)s = *(stbsp__uint16 *)&stbsp__digitpair.pair[(n % 100) * 2]; - n /= 100; - } while (n); - } - while (n) { - if ((fl & STBSP__TRIPLET_COMMA) && (l++ == 3)) { - l = 0; - *--s = stbsp__comma; - --o; - } else { - *--s = (char)(n % 10) + '0'; - n /= 10; - } - } - if (n64 == 0) { - if ((s[0] == '0') && (s != (num + STBSP__NUMSZ))) - ++s; - break; - } - while (s != o) - if ((fl & STBSP__TRIPLET_COMMA) && (l++ == 3)) { - l = 0; - *--s = stbsp__comma; - --o; - } else { - *--s = '0'; - } - } - - tail[0] = 0; - stbsp__lead_sign(fl, lead); - - // get the length that we copied - l = (stbsp__uint32)((num + STBSP__NUMSZ) - s); - if (l == 0) { - *--s = '0'; - l = 1; - } - cs = l + (3 << 24); - if (pr < 0) - pr = 0; - - scopy: - // get fw=leading/trailing space, pr=leading zeros - if (pr < (stbsp__int32)l) - pr = l; - n = pr + lead[0] + tail[0] + tz; - if (fw < (stbsp__int32)n) - fw = n; - fw -= n; - pr -= l; - - // handle right justify and leading zeros - if ((fl & STBSP__LEFTJUST) == 0) { - if (fl & STBSP__LEADINGZERO) // if leading zeros, everything is in pr - { - pr = (fw > pr) ? fw : pr; - fw = 0; - } else { - fl &= ~STBSP__TRIPLET_COMMA; // if no leading zeros, then no commas - } - } - - // copy the spaces and/or zeros - if (fw + pr) { - stbsp__int32 i; - stbsp__uint32 c; - - // copy leading spaces (or when doing %8.4d stuff) - if ((fl & STBSP__LEFTJUST) == 0) - while (fw > 0) { - stbsp__cb_buf_clamp(i, fw); - fw -= i; - while (i) { - if ((((stbsp__uintptr)bf) & 3) == 0) - break; - *bf++ = ' '; - --i; - } - while (i >= 4) { - *(stbsp__uint32 *)bf = 0x20202020; - bf += 4; - i -= 4; - } - while (i) { - *bf++ = ' '; - --i; - } - stbsp__chk_cb_buf(1); - } - - // copy leader - sn = lead + 1; - while (lead[0]) { - stbsp__cb_buf_clamp(i, lead[0]); - lead[0] -= (char)i; - while (i) { - *bf++ = *sn++; - --i; - } - stbsp__chk_cb_buf(1); - } - - // copy leading zeros - c = cs >> 24; - cs &= 0xffffff; - cs = (fl & STBSP__TRIPLET_COMMA) ? ((stbsp__uint32)(c - ((pr + cs) % (c + 1)))) : 0; - while (pr > 0) { - stbsp__cb_buf_clamp(i, pr); - pr -= i; - if ((fl & STBSP__TRIPLET_COMMA) == 0) { - while (i) { - if ((((stbsp__uintptr)bf) & 3) == 0) - break; - *bf++ = '0'; - --i; - } - while (i >= 4) { - *(stbsp__uint32 *)bf = 0x30303030; - bf += 4; - i -= 4; - } - } - while (i) { - if ((fl & STBSP__TRIPLET_COMMA) && (cs++ == c)) { - cs = 0; - *bf++ = stbsp__comma; - } else - *bf++ = '0'; - --i; - } - stbsp__chk_cb_buf(1); - } - } - - // copy leader if there is still one - sn = lead + 1; - while (lead[0]) { - stbsp__int32 i; - stbsp__cb_buf_clamp(i, lead[0]); - lead[0] -= (char)i; - while (i) { - *bf++ = *sn++; - --i; - } - stbsp__chk_cb_buf(1); - } - - // copy the string - n = l; - while (n) { - stbsp__int32 i; - stbsp__cb_buf_clamp(i, n); - n -= i; - STBSP__UNALIGNED(while (i >= 4) { - *(stbsp__uint32 volatile *)bf = *(stbsp__uint32 volatile *)s; - bf += 4; - s += 4; - i -= 4; - }) - while (i) { - *bf++ = *s++; - --i; - } - stbsp__chk_cb_buf(1); - } - - // copy trailing zeros - while (tz) { - stbsp__int32 i; - stbsp__cb_buf_clamp(i, tz); - tz -= i; - while (i) { - if ((((stbsp__uintptr)bf) & 3) == 0) - break; - *bf++ = '0'; - --i; - } - while (i >= 4) { - *(stbsp__uint32 *)bf = 0x30303030; - bf += 4; - i -= 4; - } - while (i) { - *bf++ = '0'; - --i; - } - stbsp__chk_cb_buf(1); - } - - // copy tail if there is one - sn = tail + 1; - while (tail[0]) { - stbsp__int32 i; - stbsp__cb_buf_clamp(i, tail[0]); - tail[0] -= (char)i; - while (i) { - *bf++ = *sn++; - --i; - } - stbsp__chk_cb_buf(1); - } - - // handle the left justify - if (fl & STBSP__LEFTJUST) - if (fw > 0) { - while (fw) { - stbsp__int32 i; - stbsp__cb_buf_clamp(i, fw); - fw -= i; - while (i) { - if ((((stbsp__uintptr)bf) & 3) == 0) - break; - *bf++ = ' '; - --i; - } - while (i >= 4) { - *(stbsp__uint32 *)bf = 0x20202020; - bf += 4; - i -= 4; - } - while (i--) - *bf++ = ' '; - stbsp__chk_cb_buf(1); - } - } - break; - - default: // unknown, just copy code - s = num + STBSP__NUMSZ - 1; - *s = f[0]; - l = 1; - fw = fl = 0; - lead[0] = 0; - tail[0] = 0; - pr = 0; - dp = 0; - cs = 0; - goto scopy; - } - ++f; - } -endfmt: - - if (!callback) - *bf = 0; - else - stbsp__flush_cb(); - -done: - return tlen + (int)(bf - buf); -} - -// cleanup -#undef STBSP__LEFTJUST -#undef STBSP__LEADINGPLUS -#undef STBSP__LEADINGSPACE -#undef STBSP__LEADING_0X -#undef STBSP__LEADINGZERO -#undef STBSP__INTMAX -#undef STBSP__TRIPLET_COMMA -#undef STBSP__NEGATIVE -#undef STBSP__METRIC_SUFFIX -#undef STBSP__NUMSZ -#undef stbsp__chk_cb_bufL -#undef stbsp__chk_cb_buf -#undef stbsp__flush_cb -#undef stbsp__cb_buf_clamp - -// ============================================================================ -// wrapper functions - -STBSP__PUBLICDEF int STB_SPRINTF_DECORATE(sprintf)(char *buf, char const *fmt, ...) +struct DN_TCInitArgs { - int result; - va_list va; - va_start(va, fmt); - result = STB_SPRINTF_DECORATE(vsprintfcb)(0, 0, buf, fmt, va); - va_end(va); - return result; -} - -typedef struct stbsp__context { - char *buf; - int count; - int length; - char tmp[STB_SPRINTF_MIN]; -} stbsp__context; - -static char *stbsp__clamp_callback(const char *buf, void *user, int len) -{ - stbsp__context *c = (stbsp__context *)user; - c->length += len; - - if (len > c->count) - len = c->count; - - if (len) { - if (buf != c->buf) { - const char *s, *se; - char *d; - d = c->buf; - s = buf; - se = buf + len; - do { - *d++ = *s++; - } while (s < se); - } - c->buf += len; - c->count -= len; - } - - if (c->count <= 0) - return c->tmp; - return (c->count >= STB_SPRINTF_MIN) ? c->buf : c->tmp; // go direct into buffer if you can -} - -static char * stbsp__count_clamp_callback( const char * buf, void * user, int len ) -{ - stbsp__context * c = (stbsp__context*)user; - (void) sizeof(buf); - - c->length += len; - return c->tmp; // go direct into buffer if you can -} - -STBSP__PUBLICDEF int STB_SPRINTF_DECORATE( vsnprintf )( char * buf, int count, char const * fmt, va_list va ) -{ - stbsp__context c; - - if ( (count == 0) && !buf ) - { - c.length = 0; - - STB_SPRINTF_DECORATE( vsprintfcb )( stbsp__count_clamp_callback, &c, c.tmp, fmt, va ); - } - else - { - int l; - - c.buf = buf; - c.count = count; - c.length = 0; - - STB_SPRINTF_DECORATE( vsprintfcb )( stbsp__clamp_callback, &c, stbsp__clamp_callback(0,&c,0), fmt, va ); - - // zero-terminate - l = (int)( c.buf - buf ); - if ( l >= count ) // should never be greater, only equal (or less) than count - l = count - 1; - buf[l] = 0; - } - - return c.length; -} - -STBSP__PUBLICDEF int STB_SPRINTF_DECORATE(snprintf)(char *buf, int count, char const *fmt, ...) -{ - int result; - va_list va; - va_start(va, fmt); - - result = STB_SPRINTF_DECORATE(vsnprintf)(buf, count, fmt, va); - va_end(va); - - return result; -} - -STBSP__PUBLICDEF int STB_SPRINTF_DECORATE(vsprintf)(char *buf, char const *fmt, va_list va) -{ - return STB_SPRINTF_DECORATE(vsprintfcb)(0, 0, buf, fmt, va); -} - -// ======================================================================= -// low level float utility functions - -#ifndef STB_SPRINTF_NOFLOAT - -// copies d to bits w/ strict aliasing (this compiles to nothing on /Ox) -#define STBSP__COPYFP(dest, src) \ - { \ - int cn; \ - for (cn = 0; cn < 8; cn++) \ - ((char *)&dest)[cn] = ((char *)&src)[cn]; \ - } - -// get float info -static stbsp__int32 stbsp__real_to_parts(stbsp__int64 *bits, stbsp__int32 *expo, double value) -{ - double d; - stbsp__int64 b = 0; - - // load value and round at the frac_digits - d = value; - - STBSP__COPYFP(b, d); - - *bits = b & ((((stbsp__uint64)1) << 52) - 1); - *expo = (stbsp__int32)(((b >> 52) & 2047) - 1023); - - return (stbsp__int32)((stbsp__uint64) b >> 63); -} - -static double const stbsp__bot[23] = { - 1e+000, 1e+001, 1e+002, 1e+003, 1e+004, 1e+005, 1e+006, 1e+007, 1e+008, 1e+009, 1e+010, 1e+011, - 1e+012, 1e+013, 1e+014, 1e+015, 1e+016, 1e+017, 1e+018, 1e+019, 1e+020, 1e+021, 1e+022 -}; -static double const stbsp__negbot[22] = { - 1e-001, 1e-002, 1e-003, 1e-004, 1e-005, 1e-006, 1e-007, 1e-008, 1e-009, 1e-010, 1e-011, - 1e-012, 1e-013, 1e-014, 1e-015, 1e-016, 1e-017, 1e-018, 1e-019, 1e-020, 1e-021, 1e-022 -}; -static double const stbsp__negboterr[22] = { - -5.551115123125783e-018, -2.0816681711721684e-019, -2.0816681711721686e-020, -4.7921736023859299e-021, -8.1803053914031305e-022, 4.5251888174113741e-023, - 4.5251888174113739e-024, -2.0922560830128471e-025, -6.2281591457779853e-026, -3.6432197315497743e-027, 6.0503030718060191e-028, 2.0113352370744385e-029, - -3.0373745563400371e-030, 1.1806906454401013e-032, -7.7705399876661076e-032, 2.0902213275965398e-033, -7.1542424054621921e-034, -7.1542424054621926e-035, - 2.4754073164739869e-036, 5.4846728545790429e-037, 9.2462547772103625e-038, -4.8596774326570872e-039 -}; -static double const stbsp__top[13] = { - 1e+023, 1e+046, 1e+069, 1e+092, 1e+115, 1e+138, 1e+161, 1e+184, 1e+207, 1e+230, 1e+253, 1e+276, 1e+299 -}; -static double const stbsp__negtop[13] = { - 1e-023, 1e-046, 1e-069, 1e-092, 1e-115, 1e-138, 1e-161, 1e-184, 1e-207, 1e-230, 1e-253, 1e-276, 1e-299 -}; -static double const stbsp__toperr[13] = { - 8388608, - 6.8601809640529717e+028, - -7.253143638152921e+052, - -4.3377296974619174e+075, - -1.5559416129466825e+098, - -3.2841562489204913e+121, - -3.7745893248228135e+144, - -1.7356668416969134e+167, - -3.8893577551088374e+190, - -9.9566444326005119e+213, - 6.3641293062232429e+236, - -5.2069140800249813e+259, - -5.2504760255204387e+282 -}; -static double const stbsp__negtoperr[13] = { - 3.9565301985100693e-040, -2.299904345391321e-063, 3.6506201437945798e-086, 1.1875228833981544e-109, - -5.0644902316928607e-132, -6.7156837247865426e-155, -2.812077463003139e-178, -5.7778912386589953e-201, - 7.4997100559334532e-224, -4.6439668915134491e-247, -6.3691100762962136e-270, -9.436808465446358e-293, - 8.0970921678014997e-317 + DN_U64 main_reserve; + DN_U64 main_commit; + DN_U64 temp_reserve; + DN_U64 temp_commit; + DN_U64 err_sink_reserve; + DN_U64 err_sink_commit; }; -#if defined(_MSC_VER) && (_MSC_VER <= 1200) -static stbsp__uint64 const stbsp__powten[20] = { - 1, - 10, - 100, - 1000, - 10000, - 100000, - 1000000, - 10000000, - 100000000, - 1000000000, - 10000000000, - 100000000000, - 1000000000000, - 10000000000000, - 100000000000000, - 1000000000000000, - 10000000000000000, - 100000000000000000, - 1000000000000000000, - 10000000000000000000U -}; -#define stbsp__tento19th ((stbsp__uint64)1000000000000000000) -#else -static stbsp__uint64 const stbsp__powten[20] = { - 1, - 10, - 100, - 1000, - 10000, - 100000, - 1000000, - 10000000, - 100000000, - 1000000000, - 10000000000ULL, - 100000000000ULL, - 1000000000000ULL, - 10000000000000ULL, - 100000000000000ULL, - 1000000000000000ULL, - 10000000000000000ULL, - 100000000000000000ULL, - 1000000000000000000ULL, - 10000000000000000000ULL -}; -#define stbsp__tento19th (1000000000000000000ULL) -#endif - -#define stbsp__ddmulthi(oh, ol, xh, yh) \ - { \ - double ahi = 0, alo, bhi = 0, blo; \ - stbsp__int64 bt; \ - oh = xh * yh; \ - STBSP__COPYFP(bt, xh); \ - bt &= ((~(stbsp__uint64)0) << 27); \ - STBSP__COPYFP(ahi, bt); \ - alo = xh - ahi; \ - STBSP__COPYFP(bt, yh); \ - bt &= ((~(stbsp__uint64)0) << 27); \ - STBSP__COPYFP(bhi, bt); \ - blo = yh - bhi; \ - ol = ((ahi * bhi - oh) + ahi * blo + alo * bhi) + alo * blo; \ - } - -#define stbsp__ddtoS64(ob, xh, xl) \ - { \ - double ahi = 0, alo, vh, t; \ - ob = (stbsp__int64)xh; \ - vh = (double)ob; \ - ahi = (xh - vh); \ - t = (ahi - xh); \ - alo = (xh - (ahi - t)) - (vh + t); \ - ob += (stbsp__int64)(ahi + alo + xl); \ - } - -#define stbsp__ddrenorm(oh, ol) \ - { \ - double s; \ - s = oh + ol; \ - ol = ol - (s - oh); \ - oh = s; \ - } - -#define stbsp__ddmultlo(oh, ol, xh, xl, yh, yl) ol = ol + (xh * yl + xl * yh); - -#define stbsp__ddmultlos(oh, ol, xh, yl) ol = ol + (xh * yl); - -static void stbsp__raise_to_power10(double *ohi, double *olo, double d, stbsp__int32 power) // power can be -323 to +350 +struct DN_TCCore // (T)hread (C)ontext sitting in thread-local storage { - double ph, pl; - if ((power >= 0) && (power <= 22)) { - stbsp__ddmulthi(ph, pl, d, stbsp__bot[power]); - } else { - stbsp__int32 e, et, eb; - double p2h, p2l; + DN_Str8x64 name; + DN_U64 thread_id; + DN_CallSite call_site; + char lane_opaque[sizeof(DN_U64) * 4]; - e = power; - if (power < 0) - e = -e; - et = (e * 0x2c9) >> 14; /* %23 */ - if (et > 13) - et = 13; - eb = e - (et * 23); + DN_MemList main_arena_mem_; + DN_MemList temp_a_arena_mem_; + DN_MemList temp_b_arena_mem_; + DN_MemList err_sink_arena_mem_; - ph = d; - pl = 0.0; - if (power < 0) { - if (eb) { - --eb; - stbsp__ddmulthi(ph, pl, d, stbsp__negbot[eb]); - stbsp__ddmultlos(ph, pl, d, stbsp__negboterr[eb]); - } - if (et) { - stbsp__ddrenorm(ph, pl); - --et; - stbsp__ddmulthi(p2h, p2l, ph, stbsp__negtop[et]); - stbsp__ddmultlo(p2h, p2l, ph, pl, stbsp__negtop[et], stbsp__negtoperr[et]); - ph = p2h; - pl = p2l; - } - } else { - if (eb) { - e = eb; - if (eb > 22) - eb = 22; - e -= eb; - stbsp__ddmulthi(ph, pl, d, stbsp__bot[eb]); - if (e) { - stbsp__ddrenorm(ph, pl); - stbsp__ddmulthi(p2h, p2l, ph, stbsp__bot[e]); - stbsp__ddmultlos(p2h, p2l, stbsp__bot[e], pl); - ph = p2h; - pl = p2l; - } - } - if (et) { - stbsp__ddrenorm(ph, pl); - --et; - stbsp__ddmulthi(p2h, p2l, ph, stbsp__top[et]); - stbsp__ddmultlo(p2h, p2l, ph, pl, stbsp__top[et], stbsp__toperr[et]); - ph = p2h; - pl = p2l; - } - } - } - stbsp__ddrenorm(ph, pl); - *ohi = ph; - *olo = pl; -} + DN_Arena main_arena_; + DN_Arena temp_a_arena_; + DN_Arena temp_b_arena_; + DN_Arena err_sink_arena_; -// given a float value, returns the significant bits in bits, and the position of the -// decimal point in decimal_pos. +/-INF and NAN are specified by special values -// returned in the decimal_pos parameter. -// frac_digits is absolute normally, but if you want from first significant digits (got %g and %e), or in 0x80000000 -static stbsp__int32 stbsp__real_to_str(char const **start, stbsp__uint32 *len, char *out, stbsp__int32 *decimal_pos, double value, stbsp__uint32 frac_digits) -{ - double d; - stbsp__int64 bits = 0; - stbsp__int32 expo, e, ng, tens; + DN_Arena* main_arena; + DN_Pool main_pool; + DN_Arena* temp_a_arena; + DN_Arena* temp_b_arena; - d = value; - STBSP__COPYFP(bits, d); - expo = (stbsp__int32)((bits >> 52) & 2047); - ng = (stbsp__int32)((stbsp__uint64) bits >> 63); - if (ng) - d = -d; + DN_ErrSink err_sink; - if (expo == 2047) // is nan or inf? - { - *start = (bits & ((((stbsp__uint64)1) << 52) - 1)) ? "NaN" : "Inf"; - *decimal_pos = STBSP__SPECIAL; - *len = 3; - return ng; - } - - if (expo == 0) // is zero or denormal - { - if (((stbsp__uint64) bits << 1) == 0) // do zero - { - *decimal_pos = 1; - *start = out; - out[0] = '0'; - *len = 1; - return ng; - } - // find the right expo for denormals - { - stbsp__int64 v = ((stbsp__uint64)1) << 51; - while ((bits & v) == 0) { - --expo; - v >>= 1; - } - } - } - - // find the decimal exponent as well as the decimal bits of the value - { - double ph, pl; - - // log10 estimate - very specifically tweaked to hit or undershoot by no more than 1 of log10 of all expos 1..2046 - tens = expo - 1023; - tens = (tens < 0) ? ((tens * 617) / 2048) : (((tens * 1233) / 4096) + 1); - - // move the significant bits into position and stick them into an int - stbsp__raise_to_power10(&ph, &pl, d, 18 - tens); - - // get full as much precision from double-double as possible - stbsp__ddtoS64(bits, ph, pl); - - // check if we undershot - if (((stbsp__uint64)bits) >= stbsp__tento19th) - ++tens; - } - - // now do the rounding in integer land - frac_digits = (frac_digits & 0x80000000) ? ((frac_digits & 0x7ffffff) + 1) : (tens + frac_digits); - if ((frac_digits < 24)) { - stbsp__uint32 dg = 1; - if ((stbsp__uint64)bits >= stbsp__powten[9]) - dg = 10; - while ((stbsp__uint64)bits >= stbsp__powten[dg]) { - ++dg; - if (dg == 20) - goto noround; - } - if (frac_digits < dg) { - stbsp__uint64 r; - // add 0.5 at the right position and round - e = dg - frac_digits; - if ((stbsp__uint32)e >= 24) - goto noround; - r = stbsp__powten[e]; - bits = bits + (r / 2); - if ((stbsp__uint64)bits >= stbsp__powten[dg]) - ++tens; - bits /= r; - } - noround:; - } - - // kill long trailing runs of zeros - if (bits) { - stbsp__uint32 n; - for (;;) { - if (bits <= 0xffffffff) - break; - if (bits % 1000) - goto donez; - bits /= 1000; - } - n = (stbsp__uint32)bits; - while ((n % 1000) == 0) - n /= 1000; - bits = n; - donez:; - } - - // convert to string - out += 64; - e = 0; - for (;;) { - stbsp__uint32 n; - char *o = out - 8; - // do the conversion in chunks of U32s (avoid most 64-bit divides, worth it, constant denomiators be damned) - if (bits >= 100000000) { - n = (stbsp__uint32)(bits % 100000000); - bits /= 100000000; - } else { - n = (stbsp__uint32)bits; - bits = 0; - } - while (n) { - out -= 2; - *(stbsp__uint16 *)out = *(stbsp__uint16 *)&stbsp__digitpair.pair[(n % 100) * 2]; - n /= 100; - e += 2; - } - if (bits == 0) { - if ((e) && (out[0] == '0')) { - ++out; - --e; - } - break; - } - while (out != o) { - *--out = '0'; - ++e; - } - } - - *decimal_pos = tens; - *start = out; - *len = e; - return ng; -} - -#undef stbsp__ddmulthi -#undef stbsp__ddrenorm -#undef stbsp__ddmultlo -#undef stbsp__ddmultlos -#undef STBSP__SPECIAL -#undef STBSP__COPYFP - -#endif // STB_SPRINTF_NOFLOAT - -// clean up -#undef stbsp__uint16 -#undef stbsp__uint32 -#undef stbsp__int32 -#undef stbsp__uint64 -#undef stbsp__int64 -#undef STBSP__UNALIGNED - -#endif // STB_SPRINTF_IMPLEMENTATION - -/* ------------------------------------------------------------------------------- -This software is available under 2 licenses -- choose whichever you prefer. ------------------------------------------------------------------------------- -ALTERNATIVE A - MIT License -Copyright (c) 2017 Sean Barrett -Permission is hereby granted, free of charge, to any person obtaining a copy of -this software and associated documentation files (the "Software"), to deal in -the Software without restriction, including without limitation the rights to -use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies -of the Software, and to permit persons to whom the Software is furnished to do -so, subject to the following conditions: -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. ------------------------------------------------------------------------------- -ALTERNATIVE B - Public Domain (www.unlicense.org) -This is free and unencumbered software released into the public domain. -Anyone is free to copy, modify, publish, use, compile, sell, or distribute this -software, either in source code form or as a compiled binary, for any purpose, -commercial or non-commercial, and by any means. -In jurisdictions that recognize copyright laws, the author or authors of this -software dedicate any and all copyright interest in the software to the public -domain. We make this dedication for the benefit of the public at large and to -the detriment of our heirs and successors. We intend this dedication to be an -overt act of relinquishment in perpetuity of all present and future rights to -this software under copyright law. -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN -ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ------------------------------------------------------------------------------- -*/ -DN_GCC_WARNING_POP -DN_MSVC_WARNING_POP - -DN_API void DN_BeginFrame (); - -#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_MemEq (void const *lhs, DN_USize lhs_size, void const *rhs, DN_USize rhs_size); - -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_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 void DN_TicketMutex_Begin (DN_TicketMutex *mutex); -DN_API void DN_TicketMutex_End (DN_TicketMutex *mutex); -DN_API DN_UInt DN_TicketMutex_MakeTicket (DN_TicketMutex *mutex); -DN_API void DN_TicketMutex_BeginTicket (DN_TicketMutex const *mutex, DN_UInt ticket); -DN_API bool DN_TicketMutex_CanLock (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); -#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_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 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 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 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_UInt DN_SaturateCastI64ToUInt (DN_I64 val); -DN_API DN_ISize 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 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_Arena DN_ArenaFromBuffer (void *buffer, DN_USize size, DN_ArenaFlags flags); -DN_API DN_Arena DN_ArenaFromMemFuncs (DN_U64 reserve, DN_U64 commit, DN_ArenaFlags flags, DN_ArenaMemFuncs mem_funcs); -DN_API void DN_ArenaDeinit (DN_Arena *arena); -DN_API bool DN_ArenaCommit (DN_Arena *arena, DN_U64 size); -DN_API bool DN_ArenaCommitTo (DN_Arena *arena, DN_U64 pos); -DN_API bool DN_ArenaGrow (DN_Arena *arena, DN_U64 reserve, DN_U64 commit); -DN_API void * DN_ArenaAlloc (DN_Arena *arena, DN_U64 size, uint8_t align, DN_ZMem zmem); -DN_API void * DN_ArenaAllocContiguous (DN_Arena *arena, DN_U64 size, uint8_t align, DN_ZMem zmem); -DN_API void * DN_ArenaCopy (DN_Arena *arena, void const *data, DN_U64 size, uint8_t align); -DN_API void DN_ArenaPopTo (DN_Arena *arena, DN_U64 init_used); -DN_API void DN_ArenaPop (DN_Arena *arena, DN_U64 amount); -DN_API DN_U64 DN_ArenaPos (DN_Arena const *arena); -DN_API void DN_ArenaClear (DN_Arena *arena); -DN_API bool DN_ArenaOwnsPtr (DN_Arena const *arena, void *ptr); -DN_API DN_Str8x64 DN_ArenaInfoStr8x64 (DN_ArenaInfo info); -DN_API DN_ArenaStats DN_ArenaSumStatsArray (DN_ArenaStats const *array, DN_USize size); -DN_API DN_ArenaStats DN_ArenaSumStats (DN_ArenaStats lhs, DN_ArenaStats rhs); -DN_API DN_ArenaStats DN_ArenaSumArenaArrayToStats(DN_Arena const *array, DN_USize size); -DN_API DN_ArenaTempMem DN_ArenaTempMemBegin (DN_Arena *arena); -DN_API void DN_ArenaTempMemEnd (DN_ArenaTempMem mem); -#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_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)) - -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 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_U64FromStr8 (DN_Str8 string, char separator); -DN_API DN_U64FromResult DN_U64FromPtr (void const *data, DN_USize size, char separator); -DN_API DN_U64 DN_U64FromPtrUnsafe (void const *data, DN_USize size, char separator); -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_I64FromResult DN_I64FromStr8 (DN_Str8 string, char separator); -DN_API DN_I64FromResult DN_I64FromPtr (void const *data, DN_USize size, char separator); -DN_API DN_I64 DN_I64FromPtrUnsafe (void const *data, DN_USize size, char separator); - -DN_API DN_USize DN_FmtVSize (DN_FMT_ATTRIB char const *fmt, va_list args); -DN_API DN_USize DN_FmtSize (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_CStr8Size (char const *src); -DN_API DN_USize DN_CStr16Size (wchar_t const *src); - -#define DN_Str16Lit(string) DN_Str16{(wchar_t *)(string), sizeof(string)/sizeof(string[0]) - 1} -#define DN_Str8Lit(c_str) DN_Literal(DN_Str8){(char *)(c_str), sizeof(c_str) - 1} -#define DN_Str8PrintFmt(string) (int)((string).size), (string).data -#define DN_Str8FromPtr(data, size) DN_Literal(DN_Str8){(char *)(data), (DN_USize)(size)} -#define DN_Str8FromStruct(ptr) DN_Str8FromPtr((ptr)->data, (ptr)->size) -DN_API DN_Str8 DN_Str8FromCStr8 (char const *src); -DN_API DN_Str8 DN_Str8FromArena (DN_Arena *arena, DN_USize size, DN_ZMem z_mem); -DN_API DN_Str8 DN_Str8FromPool (DN_Pool *pool, DN_USize size); -DN_API DN_Str8 DN_Str8FromPtrArena (DN_Arena *arena, void const *data, DN_USize size); -DN_API DN_Str8 DN_Str8FromPtrPool (DN_Pool *pool, void const *data, DN_USize size); -DN_API DN_Str8 DN_Str8FromStr8Arena (DN_Arena *arena, DN_Str8 string); -DN_API DN_Str8 DN_Str8FromStr8Pool (DN_Pool *pool, DN_Str8 string); -DN_API DN_Str8 DN_Str8FromFmtArena (DN_Arena *arena, DN_FMT_ATTRIB char const *fmt, ...); -DN_API DN_Str8 DN_Str8FromFmtVArena (DN_Arena *arena, DN_FMT_ATTRIB char const *fmt, va_list args); -DN_API DN_Str8 DN_Str8FromFmtPool (DN_Pool *pool, DN_FMT_ATTRIB char const *fmt, ...); -DN_API DN_Str8 DN_Str8FromByteCountType (DN_ByteCountType type); -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_Str8x32 DN_Str8x32FromU64 (DN_U64 val, char separator); -DN_API bool DN_Str8IsAll (DN_Str8 string, DN_Str8IsAllType is_all); -DN_API char * DN_Str8End (DN_Str8 string); -DN_API DN_Str8 DN_Str8Slice (DN_Str8 string, DN_USize offset, DN_USize size); -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_Str8SplitIncludeEmptyStrings mode); -DN_API DN_Str8SplitResult DN_Str8SplitArena (DN_Arena *arena, DN_Str8 string, DN_Str8 delimiter, DN_Str8SplitIncludeEmptyStrings mode); -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, uint32_t 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_Str8EqCase_Sensitive); -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_Str8EqCase_Sensitive); -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_Str8EqCase_Sensitive); -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_Str8EqCase_Sensitive); -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_Str8EqCase_Sensitive); -DN_API DN_Str8 DN_Str8TrimAround (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 size); -DN_API DN_Str8TruncateResult DN_Str8TruncateMiddle (DN_Arena *arena, DN_Str8 str8, DN_U32 side_size, DN_Str8 truncator); -DN_API DN_Str8 DN_Str8Lower (DN_Arena *arena, DN_Str8 string); -DN_API DN_Str8 DN_Str8Upper (DN_Arena *arena, DN_Str8 string); - -DN_API DN_Str8Builder DN_Str8BuilderFromArena (DN_Arena *arena); -DN_API DN_Str8Builder DN_Str8BuilderFromStr8PtrRef (DN_Arena *arena, DN_Str8 const *strings, DN_USize size); -DN_API DN_Str8Builder DN_Str8BuilderFromStr8PtrCopy (DN_Arena *arena, DN_Str8 const *strings, DN_USize size); -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 size, DN_Str8BuilderAdd add); -DN_API bool DN_Str8BuilderAddArrayCopy (DN_Str8Builder *builder, DN_Str8 const *strings, DN_USize size, DN_Str8BuilderAdd add); -DN_API bool DN_Str8BuilderAddFV (DN_Str8Builder *builder, DN_Str8BuilderAdd add, DN_FMT_ATTRIB char const *fmt, va_list args); -#define DN_Str8BuilderAppendArrayRef(builder, strings, size) DN_Str8BuilderAddArrayRef(builder, strings, size, DN_Str8BuilderAdd_Append) -#define DN_Str8BuilderAppendArrayCopy(builder, strings, size) DN_Str8BuilderAddArrayCopy(builder, strings, size, DN_Str8BuilderAdd_Append) -#define DN_Str8BuilderAppendSliceRef(builder, slice) DN_Str8BuilderAddArrayRef(builder, slice.data, slice.size, DN_Str8BuilderAdd_Append) -#define DN_Str8BuilderAppendSliceCopy(builder, slice) DN_Str8BuilderAddArrayCopy(builder, slice.data, slice.size, DN_Str8BuilderAdd_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_Str8BuilderAdd_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 size); -DN_API bool DN_Str8BuilderAppendBytesCopy (DN_Str8Builder *builder, void const *ptr, DN_USize size); -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_Str8BuilderAdd_Prepend) -#define DN_Str8BuilderPrependArrayCopy(builder, strings, size) DN_Str8BuilderAddArrayCopy(builder, strings, size, DN_Str8BuilderAdd_Prepend) -#define DN_Str8BuilderPrependSliceRef(builder, slice) DN_Str8BuilderAddArrayRef(builder, slice.data, slice.size, DN_Str8BuilderAdd_Prepend) -#define DN_Str8BuilderPrependSliceCopy(builder, slice) DN_Str8BuilderAddArrayCopy(builder, slice.data, slice.size, DN_Str8BuilderAdd_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_Str8BuilderAdd_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_Str8BuilderBuild (DN_Str8Builder const *builder, DN_Arena *arena); -DN_API DN_Str8 DN_Str8BuilderBuildDelimited (DN_Str8Builder const *builder, DN_Str8 delimiter, DN_Arena *arena); -DN_API DN_Slice DN_Str8BuilderBuildSlice (DN_Str8Builder const *builder, DN_Arena *arena); - -DN_API int DN_EncodeUTF8Codepoint (uint8_t utf8[4], uint32_t codepoint); -DN_API int DN_EncodeUTF16Codepoint (uint16_t utf16[2], uint32_t codepoint); - -DN_API DN_U8 DN_U8FromHexNibble (char hex); -DN_API DN_NibbleFromU8Result DN_NibbleFromU8 (DN_U8 u8); - -DN_API DN_USize DN_BytesFromHexPtr (void const *hex, DN_USize hex_count, void *dest, DN_USize dest_count); -DN_API DN_Str8 DN_BytesFromHexPtrArena (void const *hex, DN_USize hex_count, DN_Arena *arena); -DN_API DN_USize DN_BytesFromHexStr8 (DN_Str8 hex, void *dest, DN_USize dest_count); -DN_API DN_Str8 DN_BytesFromHexStr8Arena (DN_Str8 hex, DN_Arena *arena); -DN_API DN_U8x16 DN_BytesFromHex32Ptr (void const *hex, DN_USize hex_count); -DN_API DN_U8x32 DN_BytesFromHex64Ptr (void const *hex, DN_USize hex_count); - -DN_API DN_HexU64Str8 DN_HexFromU64 (DN_U64 value, DN_HexFromU64Type type); -DN_API DN_USize DN_HexFromBytesPtr (void const *bytes, DN_USize bytes_count, void *hex, DN_USize hex_count); -DN_API DN_Str8 DN_HexFromBytesPtrArena (void const *bytes, DN_USize bytes_count, DN_Arena *arena); -DN_API DN_Hex32 DN_HexFromBytes16Ptr (void const *bytes, DN_USize bytes_count); -DN_API DN_Hex64 DN_HexFromBytes32Ptr (void const *bytes, DN_USize bytes_count); -DN_API DN_Hex128 DN_HexFromBytes64Ptr (void const *bytes, DN_USize bytes_count); - -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 DN_ByteCountResult DN_ByteCountFromType (DN_U64 bytes, DN_ByteCountType type); -#define DN_ByteCount(bytes) DN_ByteCountFromType(bytes, DN_ByteCountType_Auto) -DN_API DN_Str8x32 DN_ByteCountStr8x32FromType (DN_U64 bytes, DN_ByteCountType type); -#define DN_ByteCountStr8x32(bytes) DN_ByteCountStr8x32FromType(bytes, DN_ByteCountType_Auto) - -#define DN_ProfilerZoneLoop(prof, name, index) \ - DN_ProfilerZone DN_UniqueName(zone_) = DN_ProfilerBeginZone(prof, DN_Str8Lit(name), index), DN_UniqueName(dummy_) = {}; \ - DN_UniqueName(dummy_).begin_tsc == 0; \ - DN_ProfilerEndZone(prof, DN_UniqueName(zone_)), DN_UniqueName(dummy_).begin_tsc = 1 - -#define DN_ProfilerZoneLoopAuto(prof, name) DN_ProfilerZoneLoop(prof, name, __COUNTER__ + 1) -DN_API DN_Profiler DN_ProfilerInit (DN_ProfilerAnchor *anchors, DN_USize count, DN_USize anchors_per_frame, DN_ProfilerTSCNowFunc *tsc_now, DN_U64 tsc_frequency); -DN_API DN_ProfilerZone DN_ProfilerBeginZone (DN_Profiler *profiler, DN_Str8 name, DN_U16 anchor_index); -#define DN_ProfilerBeginZoneAuto(prof, name) DN_ProfilerBeginZone(prof, DN_Str8Lit(name), __COUNTER__ + 1) -DN_API void DN_ProfilerEndZone (DN_Profiler *profiler, DN_ProfilerZone zone); -DN_API DN_USize DN_ProfilerFrameCount (DN_Profiler const *profiler); -DN_API DN_ProfilerAnchorArray DN_ProfilerFrameAnchorsFromIndex (DN_Profiler *profiler, DN_USize frame_index); -DN_API DN_ProfilerAnchorArray DN_ProfilerFrameAnchors (DN_Profiler *profiler); -DN_API void DN_ProfilerNewFrame (DN_Profiler *profiler); -DN_API void DN_ProfilerDump (DN_Profiler *profiler); -DN_API DN_F64 DN_ProfilerSecFromTSC (DN_Profiler *profiler, DN_U64 duration_tsc); -DN_API DN_F64 DN_ProfilerMsFromTSC (DN_Profiler *profiler, DN_U64 duration_tsc); - -#endif // !defined(DN_BASE_H) -// DN: Single header generator commented out this header => #include "Base/dn_base_os.h" -#if !defined(DN_BASE_OS_H) -#define DN_BASE_OS_H - -// DN: Single header generator commented out this header => #include "../dn_base_inc.h" - -// NOTE: OS primitives that the OS layer can provide for the base layer but is optional. - -struct DN_StackTraceFrame -{ - DN_U64 address; - DN_U64 line_number; - DN_Str8 file_name; - DN_Str8 function_name; + DN_Arena* frame_arena; }; -struct DN_StackTraceRawFrame +enum DN_TCDeinitArenas { - void *process; - DN_U64 base_addr; + DN_TCDeinitArenas_No, + DN_TCDeinitArenas_Yes, }; -struct DN_StackTraceWalkResult +struct DN_PCG32 { DN_U64 state; }; +struct DN_MurmurHash3 { DN_U64 e[2]; }; + +enum DN_LogType { - void *process; // [Internal] Windows handle to the process - DN_U64 *base_addr; // The addresses of the functions in the stack trace - DN_U16 size; // The number of `base_addr`'s stored from the walk + DN_LogType_Debug, + DN_LogType_Info, + DN_LogType_Warning, + DN_LogType_Error, + DN_LogType_Count, }; -struct DN_StackTraceWalkResultIterator +enum DN_LogBold { - DN_StackTraceRawFrame raw_frame; - DN_U16 index; + DN_LogBold_No, + DN_LogBold_Yes, }; - -#if defined(DN_FREESTANDING) -#define DN_StackTraceWalkStr8FromHeap(...) DN_Str8Lit("N/A") -#define DN_StackTraceWalk(...) -#define DN_StackTraceWalkResultIterate(...) -#define DN_StackTraceWalkResultToStr8(...) DN_Str8Lit("N/A") -#define DN_StackTraceWalkStr8(...) DN_Str8Lit("N/A") -#define DN_StackTraceWalkStr8FromHeap(...) DN_Str8Lit("N/A") -#define DN_StackTraceGetFrames(...) -#define DN_StackTraceRawFrameToFrame(...) -#define DN_StackTracePrint(...) -#define DN_StackTraceReloadSymbols(...) -#else -DN_API DN_StackTraceWalkResult DN_StackTraceWalk (struct DN_Arena *arena, DN_U16 limit); -DN_API bool DN_StackTraceWalkResultIterate(DN_StackTraceWalkResultIterator *it, DN_StackTraceWalkResult const *walk); -DN_API DN_Str8 DN_StackTraceWalkResultToStr8 (struct DN_Arena *arena, DN_StackTraceWalkResult const *walk, DN_U16 skip); -DN_API DN_Str8 DN_StackTraceWalkStr8 (struct DN_Arena *arena, DN_U16 limit, DN_U16 skip); -DN_API DN_Str8 DN_StackTraceWalkStr8FromHeap (DN_U16 limit, DN_U16 skip); -DN_API DN_Slice DN_StackTraceGetFrames (struct DN_Arena *arena, DN_U16 limit); -DN_API DN_StackTraceFrame DN_StackTraceRawFrameToFrame (struct DN_Arena *arena, DN_StackTraceRawFrame raw_frame); -DN_API void DN_StackTracePrint (DN_U16 limit); -DN_API void DN_StackTraceReloadSymbols (); -#endif -#endif // !defined(DN_BASE_OS_H) -// DN: Single header generator commented out this header => #include "Base/dn_base_assert.h" -#if !defined(DN_BASE_ASSERT_H) -#define DN_BASE_ASSERT_H - -#define DN_HardAssertF(expr, fmt, ...) \ - do { \ - if (!(expr)) { \ - DN_Str8 stack_trace_ = DN_StackTraceWalkStr8FromHeap(128 /*limit*/, 2 /*skip*/); \ - DN_LOG_ErrorF("Hard assertion [" #expr "], stack trace was:\n\n%.*s\n\n" fmt, \ - DN_Str8PrintFmt(stack_trace_), \ - ##__VA_ARGS__); \ - DN_DebugBreak; \ - } \ - } while (0) -#define DN_HardAssert(expr) DN_HardAssertF(expr, "") - -// NOTE: Our default assert requires stack traces which has a bit of a chicken-and-egg problem if -// we're trying to detect some code related to the DN startup sequence. If we try to assert before -// the OS layer is initialised stack-traces will try to use temporary memory which requires TLS to -// be setup which belongs to the OS. -// -// This causes recursion errors as they call into each other. We use RawAsserts for these kind of -// checks. -#if defined(DN_NO_ASSERT) - #define DN_RawAssert(...) - #define DN_Assert(...) - #define DN_AssertOnce(...) - #define DN_AssertF(...) - #define DN_AssertFOnce(...) -#else - #define DN_RawAssert(expr) do { if (!(expr)) DN_DebugBreak; } while (0) - - #define DN_AssertF(expr, fmt, ...) \ - do { \ - if (!(expr)) { \ - DN_Str8 stack_trace_ = DN_StackTraceWalkStr8FromHeap(128 /*limit*/, 2 /*skip*/); \ - DN_LOG_ErrorF("Assertion [" #expr "], stack trace was:\n\n%.*s\n\n" fmt, \ - DN_Str8PrintFmt(stack_trace_), \ - ##__VA_ARGS__); \ - DN_DebugBreak; \ - } \ - } while (0) - - #define DN_AssertFOnce(expr, fmt, ...) \ - do { \ - static bool once = true; \ - if (!(expr) && once) { \ - once = false; \ - DN_Str8 stack_trace_ = DN_StackTraceWalkStr8FromHeap(128 /*limit*/, 2 /*skip*/); \ - DN_LOG_ErrorF("Assertion [" #expr "], stack trace was:\n\n%.*s\n\n" fmt, \ - DN_Str8PrintFmt(stack_trace_), \ - ##__VA_ARGS__); \ - DN_DebugBreak; \ - } \ - } while (0) - - #define DN_Assert(expr) DN_AssertF((expr), "") - #define DN_AssertOnce(expr) DN_AssertFOnce((expr), "") -#endif - -#define DN_InvalidCodePathF(fmt, ...) DN_HardAssertF(0, fmt, ##__VA_ARGS__) -#define DN_InvalidCodePath DN_InvalidCodePathF("Invalid code path triggered") -#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_Check(expr) DN_CheckF(expr, "") -#if defined(DN_NO_CHECK_BREAK) - #define DN_CheckF(expr, fmt, ...) \ - ((expr) ? true : (DN_LOG_WarningF(fmt, ##__VA_ARGS__), false)) -#else - #define DN_CheckF(expr, fmt, ...) \ - ((expr) ? true : (DN_LOG_ErrorF(fmt, ##__VA_ARGS__), DN_StackTracePrint(128 /*limit*/), DN_DebugBreak, false)) -#endif - -#endif -// DN: Single header generator commented out this header => #include "Base/dn_base_log.h" -#if !defined(DN_BASE_LOG_H) -#define DN_BASE_LOG_H - -// DN: Single header generator commented out this header => #include "../dn_base_inc.h" - -enum DN_LOGType +struct DN_LogStyle { - DN_LOGType_Debug, - DN_LOGType_Info, - DN_LOGType_Warning, - DN_LOGType_Error, - DN_LOGType_Count, -}; - -enum DN_LOGBold -{ - DN_LOGBold_No, - DN_LOGBold_Yes, -}; - -struct DN_LOGStyle -{ - DN_LOGBold bold; + DN_LogBold bold; bool colour; DN_U8 r, g, b; }; -struct DN_LOGTypeParam +struct DN_LogTypeParam { bool is_u32_enum; DN_U32 u32; DN_Str8 str8; }; -enum DN_LOGColourType +enum DN_ANSIColourMode { - DN_LOGColourType_Fg, - DN_LOGColourType_Bg, + DN_ANSIColourMode_Fg, + DN_ANSIColourMode_Bg, }; -struct DN_LOGDate +struct DN_LogDate { DN_U16 year; DN_U8 month; @@ -11190,4247 +1453,21 @@ struct DN_LOGDate DN_U8 second; }; -struct DN_LOGPrefixSize +struct DN_LogPrefixSize { DN_USize size; DN_USize padding; }; -typedef void DN_LOGEmitFromTypeFVFunc(DN_LOGTypeParam type, void *user_data, DN_CallSite call_site, DN_FMT_ATTRIB char const *fmt, va_list args); - -#define DN_LOG_ResetEscapeCode "\x1b[0m" -#define DN_LOG_BoldEscapeCode "\x1b[1m" -DN_API DN_Str8 DN_LOG_ColourEscapeCodeStr8FromRGB(DN_LOGColourType colour, DN_U8 r, DN_U8 g, DN_U8 b); -DN_API DN_Str8 DN_LOG_ColourEscapeCodeStr8FromU32(DN_LOGColourType colour, DN_U32 value); -DN_API DN_LOGPrefixSize DN_LOG_MakePrefix (DN_LOGStyle style, DN_LOGTypeParam type, DN_CallSite call_site, DN_LOGDate date, char *dest, DN_USize dest_size); -DN_API void DN_LOG_SetEmitFromTypeFVFunc (DN_LOGEmitFromTypeFVFunc *print_func, void *user_data); -DN_API void DN_LOG_EmitFromType (DN_LOGTypeParam type, DN_CallSite call_site, DN_FMT_ATTRIB char const *fmt, ...); -DN_API DN_LOGTypeParam DN_LOG_MakeU32LogTypeParam (DN_LOGType type); -#define DN_LOG_DebugF(fmt, ...) DN_LOG_EmitFromType(DN_LOG_MakeU32LogTypeParam(DN_LOGType_Debug), DN_CALL_SITE, fmt, ##__VA_ARGS__) -#define DN_LOG_InfoF(fmt, ...) DN_LOG_EmitFromType(DN_LOG_MakeU32LogTypeParam(DN_LOGType_Info), DN_CALL_SITE, fmt, ##__VA_ARGS__) -#define DN_LOG_WarningF(fmt, ...) DN_LOG_EmitFromType(DN_LOG_MakeU32LogTypeParam(DN_LOGType_Warning), DN_CALL_SITE, fmt, ##__VA_ARGS__) -#define DN_LOG_ErrorF(fmt, ...) DN_LOG_EmitFromType(DN_LOG_MakeU32LogTypeParam(DN_LOGType_Error), DN_CALL_SITE, fmt, ##__VA_ARGS__) -#endif // !defined(DN_BASE_LOG_H) -// DN: Single header generator commented out this header => #include "Base/dn_base_containers.h" -#if !defined(DN_CONTAINERS_H) -#define DN_CONTAINERS_H - -// DN: Single header generator commented out this header => #include "../dn_base_inc.h" - -struct DN_Ring -{ - DN_U64 size; - char *base; - DN_U64 write_pos; - DN_U64 read_pos; -}; - -// NOTE: DN_CArray ///////////////////////////////////////////////////////////////////////////////// -enum DN_ArrayErase -{ - DN_ArrayErase_Unstable, - DN_ArrayErase_Stable, -}; - -enum DN_ArrayAdd -{ - DN_ArrayAdd_Append, - DN_ArrayAdd_Prepend, -}; - -struct DN_ArrayEraseResult -{ - // The next index your for-index should be set to such that you can continue - // to iterate the remainder of the array, e.g: - // - // for (DN_USize index = 0; index < array.size; index++) { - // if (erase) - // index = DN_FArray_EraseRange(&array, index, -3, DN_ArrayErase_Unstable); - // } - DN_USize it_index; - DN_USize items_erased; // The number of items erased -}; - -template struct DN_ArrayFindResult -{ - T *data; // Pointer to the value if a match is found, null pointer otherwise - DN_USize index; // Index to the value if a match is found, 0 otherwise -}; - -#if !defined(DN_NO_SARRAY) -// NOTE: DN_SArray ///////////////////////////////////////////////////////////////////////////////// -template struct DN_SArray -{ - T *data; // Pointer to the start of the array items in the block of memory - DN_USize size; // Number of items currently in the array - DN_USize max; // Maximum number of items this array can store - - T *begin() { return data; } - T *end () { return data + size; } - T const *begin() const { return data; } - T const *end () const { return data + size; } -}; -#endif // !defined(DN_NO_SARRAY) - -#if !defined(DN_NO_FARRAY) -// NOTE: DN_FArray ///////////////////////////////////////////////////////////////////////////////// -template struct DN_FArray -{ - T data[N]; // Pointer to the start of the array items in the block of memory - DN_USize size; // Number of items currently in the array - - T *begin() { return data; } - T *end () { return data + size; } - T const *begin() const { return data; } - T const *end () const { return data + size; } -}; - -template using DN_FArray8 = DN_FArray; -template using DN_FArray16 = DN_FArray; -template using DN_FArray32 = DN_FArray; -template using DN_FArray64 = DN_FArray; -#endif // !defined(DN_NO_FARRAY) - -#if !defined(DN_NO_DSMAP) -// NOTE: DN_DSMap ////////////////////////////////////////////////////////////////////////////////// -enum DN_DSMapKeyType -{ - // Key | Key Hash | Map Index - DN_DSMapKeyType_Invalid, - DN_DSMapKeyType_U64, // U64 | Hash(U64) | Hash(U64) % map_size - DN_DSMapKeyType_U64NoHash, // U64 | U64 | U64 % map_size - DN_DSMapKeyType_Buffer, // Buffer | Hash(buffer) | Hash(buffer) % map_size - DN_DSMapKeyType_BufferAsU64NoHash, // Buffer | U64(buffer[0:4]) | U64(buffer[0:4]) % map_size -}; - -struct DN_DSMapKey -{ - DN_DSMapKeyType type; - DN_U32 hash; // Hash to lookup in the map. If it equals, we check that the original key payload matches - void const *buffer_data; - DN_U32 buffer_size; - DN_U64 u64; - bool no_copy_buffer; -}; - -template -struct DN_DSMapSlot -{ - DN_DSMapKey key; // Hash table lookup key - T value; // Hash table value -}; - -typedef DN_U32 DN_DSMapFlags; -enum DN_DSMapFlags_ -{ - DN_DSMapFlags_Nil = 0, - DN_DSMapFlags_DontFreeArenaOnResize = 1 << 0, -}; - -using DN_DSMapHashFunction = DN_U32(DN_DSMapKey key, DN_U32 seed); -template struct DN_DSMap -{ - DN_U32 *hash_to_slot; // Mapping from hash to a index in the slots array - DN_DSMapSlot *slots; // Values of the array stored contiguously, non-sorted order - DN_U32 size; // Total capacity of the map and is a power of two - DN_U32 occupied; // Number of slots used in the hash table - DN_Arena *arena; // Backing arena for the hash table - DN_Pool pool; // Allocator for keys that are variable-sized buffers - DN_U32 initial_size; // Initial map size, map cannot shrink on erase below this size - DN_DSMapHashFunction *hash_function; // Custom hashing function to use if field is set - DN_U32 hash_seed; // Seed for the hashing function, when 0, DN_DS_MAP_DEFAULT_HASH_SEED is used - DN_DSMapFlags flags; -}; - -template struct DN_DSMapResult -{ - bool found; - DN_DSMapSlot *slot; - T *value; -}; -#endif // !defined(DN_NO_DSMAP) - -#if !defined(DN_NO_LIST) -// NOTE: DN_List /////////////////////////////////////////////////////////////////////////////////// -template struct DN_ListChunk -{ - T *data; - DN_USize size; - DN_USize count; - DN_ListChunk *next; - DN_ListChunk *prev; -}; - -template struct DN_ListIterator -{ - DN_B32 init; // True if DN_List_Iterate has been called at-least once on this iterator - DN_ListChunk *chunk; // The chunk that the iterator is reading from - DN_USize chunk_data_index; // The index in the chunk the iterator is referencing - DN_USize index; // The index of the item in the list as if it was flat array - T *data; // Pointer to the data the iterator is referencing. Nullptr if invalid. -}; - -template struct DN_List -{ - DN_USize count; // Cumulative count of all items made across all list chunks - DN_USize chunk_size; // When new ListChunk's are required, the minimum 'data' entries to allocate for that node. - DN_ListChunk *head; - DN_ListChunk *tail; -}; -#endif // !defined(DN_NO_LIST) - -// NOTE: Macros for operating on data structures that are embedded into a C style struct or from a -// set of defined variables from the available scope. Keep it stupid simple, structs and functions. -// Minimal amount of container types with flexible construction leads to less duplicated container -// code and less template meta-programming. -// -// LArray => Literal Array -// Define a C array and size: -// -// ``` -// MyStruct buffer[TB_ASType_Count] = {}; -// DN_USize size = 0; -// MyStruct *item = DN_LArray_Make(buffer, size, DN_ArrayCountU(buffer), DN_ZMem_No); -// ``` -// -// IArray => Intrusive Array -// Define a struct with the members 'data', 'size' and 'max': -// -// ``` -// struct MyArray { -// MyStruct *data; -// DN_USize size; -// DN_USize max; -// } my_array = {}; -// -// MyStruct *item = DN_IArray_Make(&my_array, MyArray, DN_ZMem_No); -// ``` -// ISLList => Intrusive Singly Linked List -// Define a struct with the members 'next': -// -// ``` -// struct MyLinkItem { -// int data; -// MyLinkItem *next; -// } my_link = {}; -// -// MyLinkItem *first_item = DN_ISLList_Detach(&my_link, MyLinkItem); -// ``` - -#define DN_DLList_Init(list) \ - (list)->next = (list)->prev = (list) - -#define DN_DLList_IsSentinel(list, item) ((list) == (item)) - -#define DN_DLList_InitArena(list, T, arena) \ - do { \ - (list) = DN_ArenaNew(arena, T, DN_ZMem_Yes); \ - DN_DLList_Init(list); \ - } while (0) - -#define DN_DLList_InitPool(list, T, pool) \ - do { \ - (list) = DN_PoolNew(pool, T); \ - DN_DLList_Init(list); \ - } while (0) - -#define DN_DLList_Detach(item) \ - do { \ - if (item) { \ - (item)->prev->next = (item)->next; \ - (item)->next->prev = (item)->prev; \ - (item)->next = nullptr; \ - (item)->prev = nullptr; \ - } \ - } while (0) - -#define DN_DLList_Dequeue(list, dest_ptr) \ - if (DN_DLList_HasItems(list)) { \ - dest_ptr = (list)->next; \ - DN_DLList_Detach(dest_ptr); \ - } - -#define DN_DLList_Append(list, item) \ - do { \ - if (item) { \ - if ((item)->next) \ - DN_DLList_Detach(item); \ - (item)->next = (list)->next; \ - (item)->prev = (list); \ - (item)->next->prev = (item); \ - (item)->prev->next = (item); \ - } \ - } while (0) - -#define DN_DLList_Prepend(list, item) \ - do { \ - if (item) { \ - if ((item)->next) \ - DN_DLList_Detach(item); \ - (item)->next = (list); \ - (item)->prev = (list)->prev; \ - (item)->next->prev = (item); \ - (item)->prev->next = (item); \ - } \ - } while (0) - -#define DN_DLList_IsEmpty(list) \ - (!(list) || ((list) == (list)->next)) - -#define DN_DLList_IsInit(list) \ - ((list)->next && (list)->prev) - -#define DN_DLList_HasItems(list) \ - ((list) && ((list) != (list)->next)) - -#define DN_DLList_ForEach(it, list) \ - auto *it = (list)->next; (it) != (list); (it) = (it)->next - -#define DN_DoublyLLDetach(head, ptr) \ - do { \ - if ((head) && (head) == (ptr)) \ - (head) = (head)->next; \ - if ((ptr)) { \ - if ((ptr)->next) \ - (ptr)->next->prev = (ptr)->prev; \ - if ((ptr)->prev) \ - (ptr)->prev->next = (ptr)->next; \ - (ptr)->prev = (ptr)->next = 0; \ - } \ - } while (0) - -#define DN_DoublyLLAppend(head, ptr) \ - do { \ - if ((ptr)) { \ - DN_AssertF((ptr)->prev == 0 && (ptr)->next == 0, "Detach the pointer first"); \ - (ptr)->prev = (head); \ - (ptr)->next = 0; \ - if ((head)) { \ - (ptr)->next = (head)->next; \ - (head)->next = (ptr); \ - } else { \ - (head) = (ptr); \ - } \ - } \ - } while (0) - -#define DN_DoublyLLPrepend(head, ptr) \ - do { \ - if ((ptr)) { \ - DN_AssertF((ptr)->prev == 0 && (ptr)->next == 0, "Detach the pointer first"); \ - (ptr)->prev = nullptr; \ - (ptr)->next = (head); \ - if ((head)) { \ - (ptr)->prev = (head)->prev; \ - (head)->prev = (ptr); \ - } else { \ - (head) = (ptr); \ - } \ - } \ - } while (0) - -#define DN_ISLList_Detach(list) (decltype(list))DN_CSLList_Detach((void **)&(list), (void **)&(list)->next) - -#define DN_LArray_ResizeFromPool(c_array, size, max, pool, new_max) DN_CArray2_ResizeFromPool((void **)&(c_array), size, max, sizeof((c_array)[0]), pool, new_max) -#define DN_LArray_GrowFromPool(c_array, size, max, pool, new_max) DN_CArray2_GrowFromPool((void **)&(c_array), size, max, sizeof((c_array)[0]), pool, new_max) -#define DN_LArray_GrowIfNeededFromPool(c_array, size, max, pool, add_count) DN_CArray2_GrowIfNeededFromPool((void **)(c_array), size, max, sizeof((c_array)[0]), pool, add_count) -#define DN_LArray_MakeArray(c_array, size, max, count, z_mem) (decltype(&(c_array)[0]))DN_CArray2_MakeArray(c_array, size, max, sizeof((c_array)[0]), count, z_mem) -#define DN_LArray_MakeArrayZ(c_array, size, max, count) (decltype(&(c_array)[0]))DN_CArray2_MakeArray(c_array, size, max, sizeof((c_array)[0]), count, DN_ZMem_Yes) -#define DN_LArray_Make(c_array, size, max, z_mem) (decltype(&(c_array)[0]))DN_CArray2_MakeArray(c_array, size, max, sizeof((c_array)[0]), 1, z_mem) -#define DN_LArray_MakeZ(c_array, size, max) (decltype(&(c_array)[0]))DN_CArray2_MakeArray(c_array, size, max, sizeof((c_array)[0]), 1, DN_ZMem_Yes) -#define DN_LArray_AddArray(c_array, size, max, items, count, add) (decltype(&(c_array)[0]))DN_CArray2_AddArray(c_array, size, max, sizeof((c_array)[0]), items, count, add) -#define DN_LArray_Add(c_array, size, max, item, add) (decltype(&(c_array)[0]))DN_CArray2_AddArray(c_array, size, max, sizeof((c_array)[0]), &item, 1, add) -#define DN_LArray_AppendArray(c_array, size, max, items, count) (decltype(&(c_array)[0]))DN_CArray2_AddArray(c_array, size, max, sizeof((c_array)[0]), items, count, DN_ArrayAdd_Append) -#define DN_LArray_Append(c_array, size, max, item) (decltype(&(c_array)[0]))DN_CArray2_AddArray(c_array, size, max, sizeof((c_array)[0]), &item, 1, DN_ArrayAdd_Append) -#define DN_LArray_PrependArray(c_array, size, max, items, count) (decltype(&(c_array)[0]))DN_CArray2_AddArray(c_array, size, max, sizeof((c_array)[0]), items, count, DN_ArrayAdd_Prepend) -#define DN_LArray_Prepend(c_array, size, max, item) (decltype(&(c_array)[0]))DN_CArray2_AddArray(c_array, size, max, sizeof((c_array)[0]), &item, 1, DN_ArrayAdd_Prepend) -#define DN_LArray_EraseRange(c_array, size, begin_index, count, erase) DN_CArray2_EraseRange(c_array, size, sizeof((c_array)[0]), begin_index, count, erase) -#define DN_LArray_Erase(c_array, size, index, erase) DN_CArray2_EraseRange(c_array, size, sizeof((c_array)[0]), index, 1, erase) -#define DN_LArray_InsertArray(c_array, size, max, index, items, count) (decltype(&(c_array)[0]))DN_CArray2_InsertArray(c_array, size, max, sizeof((c_array)[0]), index, items, count) -#define DN_LArray_Insert(c_array, size, max, index, item) (decltype(&(c_array)[0]))DN_CArray2_InsertArray(c_array, size, max, sizeof((c_array)[0]), index, &item, 1) - -#define DN_IArray_ResizeFromPool(array, pool, new_max) DN_CArray2_ResizeFromPool((void **)(&(array)->data), &(array)->size, &(array)->max, sizeof((array)->data[0]), pool, new_max) -#define DN_IArray_GrowFromPool(array, pool, new_max) DN_CArray2_GrowFromPool((void **)(&(array)->data), &(array)->size, &(array)->max, sizeof((array)->data[0]), pool, new_max) -#define DN_IArray_GrowIfNeededFromPool(array, pool, add_count) DN_CArray2_GrowIfNeededFromPool((void **)(&(array)->data), (array)->size, &(array)->max, sizeof((array)->data[0]), pool, add_count) -#define DN_IArray_MakeArray(array, count, z_mem) (decltype(&((array)->data)[0]))DN_CArray2_MakeArray((array)->data, &(array)->size, (array)->max, sizeof(((array)->data)[0]), count, z_mem) -#define DN_IArray_MakeArrayZ(array, count) (decltype(&((array)->data)[0]))DN_CArray2_MakeArray((array)->data, &(array)->size, (array)->max, sizeof(((array)->data)[0]), count, DN_ZMem_Yes) -#define DN_IArray_Make(array, z_mem) (decltype(&((array)->data)[0]))DN_CArray2_MakeArray((array)->data, &(array)->size, (array)->max, sizeof(((array)->data)[0]), 1, z_mem) -#define DN_IArray_MakeZ(array) (decltype(&((array)->data)[0]))DN_CArray2_MakeArray((array)->data, &(array)->size, (array)->max, sizeof(((array)->data)[0]), 1, DN_ZMem_Yes) -#define DN_IArray_AddArray(array, items, count, add) (decltype(&((array)->data)[0]))DN_CArray2_AddArray((array)->data, &(array)->size, (array)->max, sizeof(((array)->data)[0]), items, count, add) -#define DN_IArray_Add(array, item, add) (decltype(&((array)->data)[0]))DN_CArray2_AddArray((array)->data, &(array)->size, (array)->max, sizeof(((array)->data)[0]), &item, 1, add) -#define DN_IArray_AppendArray(array, items, count) (decltype(&((array)->data)[0]))DN_CArray2_AddArray((array)->data, &(array)->size, (array)->max, sizeof(((array)->data)[0]), items, count, DN_ArrayAdd_Append) -#define DN_IArray_Append(array, item) (decltype(&((array)->data)[0]))DN_CArray2_AddArray((array)->data, &(array)->size, (array)->max, sizeof(((array)->data)[0]), &item, 1, DN_ArrayAdd_Append) -#define DN_IArray_PrependArray(array, items, count) (decltype(&((array)->data)[0]))DN_CArray2_AddArray((array)->data, &(array)->size, (array)->max, sizeof(((array)->data)[0]), items, count, DN_ArrayAdd_Prepend) -#define DN_IArray_Prepend(array, item) (decltype(&((array)->data)[0]))DN_CArray2_AddArray((array)->data, &(array)->size, (array)->max, sizeof(((array)->data)[0]), &item, 1, DN_ArrayAdd_Prepend) -#define DN_IArray_EraseRange(array, begin_index, count, erase) DN_CArray2_EraseRange((array)->data, &(array)->size, sizeof(((array)->data)[0]), begin_index, count, erase) -#define DN_IArray_Erase(array, index, erase) DN_CArray2_EraseRange((array)->data, &(array)->size, sizeof(((array)->data)[0]), index, 1, erase) -#define DN_IArray_InsertArray(array, index, items, count) (decltype(&((array)->data)[0]))DN_CArray2_InsertArray((array)->data, &(array)->size, (array)->max, sizeof(((array)->data)[0]), index, items, count) -#define DN_IArray_Insert(array, index, item, count) (decltype(&((array)->data)[0]))DN_CArray2_InsertArray((array)->data, &(array)->size, (array)->max, sizeof(((array)->data)[0]), index, &item, 1) - -DN_API DN_ArrayEraseResult DN_CArray2_EraseRange (void *data, DN_USize *size, DN_USize elem_size, DN_USize begin_index, DN_ISize count, DN_ArrayErase erase); -DN_API void *DN_CArray2_MakeArray (void *data, DN_USize *size, DN_USize max, DN_USize data_size, DN_USize make_size, DN_ZMem z_mem); -DN_API void *DN_CArray2_AddArray (void *data, DN_USize *size, DN_USize max, DN_USize data_size, void const *elems, DN_USize elems_count, DN_ArrayAdd add); -DN_API bool DN_CArray2_Resize (void **data, DN_USize *size, DN_USize *max, DN_USize data_size, DN_Pool *pool, DN_USize new_max); -DN_API bool DN_CArray2_Grow (void **data, DN_USize *size, DN_USize *max, DN_USize data_size, DN_Pool *pool, DN_USize new_max); -DN_API bool DN_CArray2_GrowIfNeededFromPool (void **data, DN_USize size, DN_USize *max, DN_USize data_size, DN_Pool *pool); -DN_API void *DN_CSLList_Detach (void **link, void **next); - -DN_API bool DN_Ring_HasSpace (DN_Ring const *ring, DN_U64 size); -DN_API bool DN_Ring_HasData (DN_Ring const *ring, DN_U64 size); -DN_API void DN_Ring_Write (DN_Ring *ring, void const *src, DN_U64 src_size); -#define DN_Ring_WriteStruct(ring, item) DN_Ring_Write((ring), (item), sizeof(*(item))) -DN_API void DN_Ring_Read (DN_Ring *ring, void *dest, DN_U64 dest_size); -#define DN_Ring_ReadStruct(ring, dest) DN_Ring_Read((ring), (dest), sizeof(*(dest))) - -template DN_ArrayEraseResult DN_CArray_EraseRange (T *data, DN_USize *size, DN_USize begin_index, DN_ISize count, DN_ArrayErase erase); -template T * DN_CArray_MakeArray (T *data, DN_USize *size, DN_USize max, DN_USize count, DN_ZMem z_mem); -template T * DN_CArray_InsertArray (T *data, DN_USize *size, DN_USize max, DN_USize index, T const *items, DN_USize count); -template T DN_CArray_PopFront (T *data, DN_USize *size, DN_USize count); -template T DN_CArray_PopBack (T *data, DN_USize *size, DN_USize count); -template DN_ArrayFindResult DN_CArray_Find (T *data, DN_USize size, T const &value); - -// NOTE: DN_SArray ///////////////////////////////////////////////////////////////////////////////// -#if !defined(DN_NO_SARRAY) -template DN_SArray DN_SArray_Init (DN_Arena *arena, DN_USize size, DN_ZMem z_mem); -template DN_SArray DN_SArray_InitSlice (DN_Arena *arena, DN_Slice slice, DN_USize size, DN_ZMem z_mem); -template DN_SArray DN_SArray_InitCArray (DN_Arena *arena, T const (&array)[N], DN_USize size, DN_ZMem); -template DN_SArray DN_SArray_InitBuffer (T* buffer, DN_USize size); -template bool DN_SArray_IsValid (DN_SArray const *array); -template DN_Slice DN_SArray_Slice (DN_SArray const *array); -template T * DN_SArray_AddArray (DN_SArray *array, T const *items, DN_USize count); -template T * DN_SArray_AddCArray (DN_SArray *array, T const (&items)[N]); -template T * DN_SArray_Add (DN_SArray *array, T const &item); -#define DN_SArray_AddArrayAssert(...) DN_HardAssert(DN_SArray_AddArray(__VA_ARGS__)) -#define DN_SArray_AddCArrayAssert(...) DN_HardAssert(DN_SArray_AddCArray(__VA_ARGS__)) -#define DN_SArray_AddAssert(...) DN_HardAssert(DN_SArray_Add(__VA_ARGS__)) -template T * DN_SArray_MakeArray (DN_SArray *array, DN_USize count, DN_ZMem z_mem); -template T * DN_SArray_Make (DN_SArray *array, DN_ZMem z_mem); -#define DN_SArray_MakeArrayAssert(...) DN_HardAssert(DN_SArray_MakeArray(__VA_ARGS__)) -#define DN_SArray_MakeAssert(...) DN_HardAssert(DN_SArray_Make(__VA_ARGS__)) -template T * DN_SArray_InsertArray (DN_SArray *array, DN_USize index, T const *items, DN_USize count); -template T * DN_SArray_InsertCArray (DN_SArray *array, DN_USize index, T const (&items)[N]); -template T * DN_SArray_Insert (DN_SArray *array, DN_USize index, T const &item); -#define DN_SArray_InsertArrayAssert(...) DN_HardAssert(DN_SArray_InsertArray(__VA_ARGS__)) -#define DN_SArray_InsertCArrayAssert(...) DN_HardAssert(DN_SArray_InsertCArray(__VA_ARGS__)) -#define DN_SArray_InsertAssert(...) DN_HardAssert(DN_SArray_Insert(__VA_ARGS__)) -template T DN_SArray_PopFront (DN_SArray *array, DN_USize count); -template T DN_SArray_PopBack (DN_SArray *array, DN_USize count); -template DN_ArrayEraseResult DN_SArray_EraseRange (DN_SArray *array, DN_USize begin_index, DN_ISize count, DN_ArrayErase erase); -template void DN_SArray_Clear (DN_SArray *array); -#endif // !defined(DN_NO_SARRAY) - -#if !defined(DN_NO_FARRAY) -#define DN_FArray_ToSArray(array) DN_SArray_InitBuffer((array)->data, DN_ArrayCountU((array)->data)) -template DN_FArray DN_FArray_Init (T const *array, DN_USize count); -#define DN_FArray_HasData(array) ((array).data && (array).size) -template DN_FArray DN_FArray_InitSlice (DN_Slice slice); -template DN_FArray DN_FArray_InitCArray (T const (&items)[K]); -template bool DN_FArray_IsValid (DN_FArray const *array); -template DN_USize DN_FArray_Max (DN_FArray const *) { return N; } -template DN_Slice DN_FArray_Slice (DN_FArray const *array); -template T * DN_FArray_AddArray (DN_FArray *array, T const *items, DN_USize count); -template T * DN_FArray_AddCArray (DN_FArray *array, T const (&items)[K]); -template T * DN_FArray_Add (DN_FArray *array, T const &item); -#define DN_FArray_AddArrayAssert(...) DN_HardAssert(DN_FArray_AddArray(__VA_ARGS__)) -#define DN_FArray_AddCArrayAssert(...) DN_HardAssert(DN_FArray_AddCArray(__VA_ARGS__)) -#define DN_FArray_AddAssert(...) DN_HardAssert(DN_FArray_Add(__VA_ARGS__)) -template T * DN_FArray_MakeArray (DN_FArray *array, DN_USize count, DN_ZMem z_mem); -template T * DN_FArray_Make (DN_FArray *array, DN_ZMem z_mem); -#define DN_FArray_MakeArrayAssert(...) DN_HardAssert(DN_FArray_MakeArray(__VA_ARGS__)) -#define DN_FArray_MakeAssert(...) DN_HardAssert(DN_FArray_Make(__VA_ARGS__)) -template T * DN_FArray_InsertArray (DN_FArray *array, T const &item, DN_USize index); -template T * DN_FArray_InsertCArray (DN_FArray *array, DN_USize index, T const (&items)[K]); -template T * DN_FArray_Insert (DN_FArray *array, DN_USize index, T const &item); -#define DN_FArray_InsertArrayAssert(...) DN_HardAssert(DN_FArray_InsertArray(__VA_ARGS__)) -#define DN_FArray_InsertAssert(...) DN_HardAssert(DN_FArray_Insert(__VA_ARGS__)) -template T DN_FArray_PopFront (DN_FArray *array, DN_USize count); -template T DN_FArray_PopBack (DN_FArray *array, DN_USize count); -template DN_ArrayFindResult DN_FArray_Find (DN_FArray *array, T const &find); -template DN_ArrayEraseResult DN_FArray_EraseRange (DN_FArray *array, DN_USize begin_index, DN_ISize count, DN_ArrayErase erase); -template void DN_FArray_Clear (DN_FArray *array); -#endif // !defined(DN_NO_FARRAY) - -#if !defined(DN_NO_SLICE) -#define DN_TO_SLICE(val) DN_Slice_Init((val)->data, (val)->size) -#define DN_Slice_InitCArray(array) DN_Slice_Init(array, DN_ArrayCountU(array)) -template DN_Slice DN_Slice_Init (T* const data, DN_USize size); -template DN_Slice DN_Slice_InitCArrayCopy (DN_Arena *arena, T const (&array)[N]); -template DN_Slice DN_Slice_Copy (DN_Arena *arena, DN_Slice slice); -template DN_Slice DN_Slice_CopyPtr (DN_Arena *arena, T* const data, DN_USize size); -template DN_Slice DN_Slice_Alloc (DN_Arena *arena, DN_USize size, DN_ZMem z_mem); - DN_Str8 DN_Slice_Str8Render (DN_Arena *arena, DN_Slice array, DN_Str8 separator); - DN_Str8 DN_Slice_Str8RenderSpaceSeparated (DN_Arena *arena, DN_Slice array); - DN_Str16 DN_Slice_Str16Render (DN_Arena *arena, DN_Slice array, DN_Str16 separator); - DN_Str16 DN_Slice_Str16RenderSpaceSeparated(DN_Arena *arena, DN_Slice array); -#endif // !defined(DN_NO_SLICE) - -#if !defined(DN_NO_DSMAP) -template DN_DSMap DN_DSMap_Init (DN_Arena *arena, DN_U32 size, DN_DSMapFlags flags); -template void DN_DSMap_Deinit (DN_DSMap *map, DN_ZMem z_mem); -template bool DN_DSMap_IsValid (DN_DSMap const *map); -template DN_U32 DN_DSMap_Hash (DN_DSMap const *map, DN_DSMapKey key); -template DN_U32 DN_DSMap_HashToSlotIndex (DN_DSMap const *map, DN_DSMapKey key); -template DN_DSMapResult DN_DSMap_Find (DN_DSMap const *map, DN_DSMapKey key); -template DN_DSMapResult DN_DSMap_Make (DN_DSMap *map, DN_DSMapKey key); -template DN_DSMapResult DN_DSMap_Set (DN_DSMap *map, DN_DSMapKey key, T const &value); -template DN_DSMapResult DN_DSMap_FindKeyU64 (DN_DSMap const *map, DN_U64 key); -template DN_DSMapResult DN_DSMap_MakeKeyU64 (DN_DSMap *map, DN_U64 key); -template DN_DSMapResult DN_DSMap_SetKeyU64 (DN_DSMap *map, DN_U64 key, T const &value); -template DN_DSMapResult DN_DSMap_FindKeyStr8 (DN_DSMap const *map, DN_Str8 key); -template DN_DSMapResult DN_DSMap_MakeKeyStr8 (DN_DSMap *map, DN_Str8 key); -template DN_DSMapResult DN_DSMap_SetKeyStr8 (DN_DSMap *map, DN_Str8 key, T const &value); -template bool DN_DSMap_Resize (DN_DSMap *map, DN_U32 size); -template bool DN_DSMap_Erase (DN_DSMap *map, DN_DSMapKey key); -template bool DN_DSMap_EraseKeyU64 (DN_DSMap *map, DN_U64 key); -template bool DN_DSMap_EraseKeyStr8 (DN_DSMap *map, DN_Str8 key); -template DN_DSMapKey DN_DSMap_KeyBuffer (DN_DSMap const *map, void const *data, DN_U32 size); -template DN_DSMapKey DN_DSMap_KeyBufferAsU64NoHash (DN_DSMap const *map, void const *data, DN_U32 size); -template DN_DSMapKey DN_DSMap_KeyU64 (DN_DSMap const *map, DN_U64 u64); -template DN_DSMapKey DN_DSMap_KeyStr8 (DN_DSMap const *map, DN_Str8 string); -#define DN_DSMap_KeyCStr8(map, string) DN_DSMap_KeyBuffer(map, string, sizeof((string))/sizeof((string)[0]) - 1) -DN_API DN_DSMapKey DN_DSMap_KeyU64NoHash (DN_U64 u64); -DN_API bool DN_DSMap_KeyEquals (DN_DSMapKey lhs, DN_DSMapKey rhs); -DN_API bool operator== (DN_DSMapKey lhs, DN_DSMapKey rhs); -#endif // !defined(DN_NO_DSMAP) - -#if !defined(DN_NO_LIST) -template DN_List DN_List_Init (DN_USize chunk_size); -template DN_List DN_List_InitCArray (DN_Arena *arena, DN_USize chunk_size, T const (&array)[N]); -template T * DN_List_At (DN_List *list, DN_USize index, DN_ListChunk **at_chunk); -template void DN_List_Clear (DN_List *list); -template bool DN_List_Iterate (DN_List *list, DN_ListIterator *it, DN_USize start_index); -template T * DN_List_MakeArena (DN_List *list, DN_Arena *arena, DN_USize count); -template T * DN_List_MakePool (DN_List *list, DN_Pool *pool, DN_USize count); -template T * DN_List_AddArena (DN_List *list, DN_Arena *arena, T const &value); -template T * DN_List_AddPool (DN_List *list, DN_Pool *pool, T const &value); -template void DN_List_AddListArena (DN_List *list, DN_Arena *arena, DN_List other); -template void DN_List_AddListArena (DN_List *list, DN_Pool *pool, DN_List other); -template DN_Slice DN_List_ToSliceCopy (DN_List const *list, DN_Arena* arena); -#endif // !defined(DN_NO_LIST) -#endif // !defined(DN_CONTAINER_H) -// DN: Single header generator commented out this header => #include "Base/dn_base_leak.h" -// DN: Single header generator commented out this header => #include "../dn_base_inc.h" - -enum DN_LeakAllocFlag -{ - DN_LeakAllocFlag_Freed = 1 << 0, - DN_LeakAllocFlag_LeakPermitted = 1 << 1, -}; - -struct DN_LeakAlloc -{ - void *ptr; // 8 Pointer to the allocation being tracked - DN_USize size; // 16 Size of the allocation - DN_USize freed_size; // 24 Store the size of the allocation when it is freed - DN_Str8 stack_trace; // 40 Stack trace at the point of allocation - DN_Str8 freed_stack_trace; // 56 Stack trace of where the allocation was freed - DN_U16 flags; // 72 Bit flags from `DN_LeakAllocFlag` -}; - -// NOTE: We aim to keep the allocation record as light as possible as memory tracking can get -// expensive. Enforce that there is no unexpected padding. -DN_StaticAssert(sizeof(DN_LeakAlloc) == 64 || sizeof(DN_LeakAlloc) == 32); // NOTE: 64 bit vs 32 bit pointers respectively - -struct DN_LeakTracker -{ - DN_DSMap alloc_table; - DN_TicketMutex alloc_table_mutex; - DN_Arena alloc_table_arena; - DN_U64 alloc_table_bytes_allocated_for_stack_traces; -}; - -DN_API void DN_LeakTrackAlloc_ (DN_LeakTracker *leak, void *ptr, DN_USize size, bool alloc_can_leak); -DN_API void DN_LeakTrackDealloc_(DN_LeakTracker *leak, void *ptr); -DN_API void DN_LeakDump_ (DN_LeakTracker *leak); - -#if defined(DN_LEAK_TRACKING) -#define DN_LeakTrackAlloc(leak, ptr, size, alloc_can_leak) DN_LeakTrackAlloc_(leak, ptr, size, alloc_can_leak) -#define DN_LeakTrackDealloc(leak, ptr) DN_LeakTrackDealloc_(leak, ptr) -#define DN_LeakDump(leak) DN_LeakDump_(leak) -#else -#define DN_LeakTrackAlloc(leak, ptr, size, alloc_can_leak) do { (void)ptr; (void)size; (void)alloc_can_leak; } while (0) -#define DN_LeakTrackDealloc(leak, ptr) do { (void)ptr; } while (0) -#define DN_LeakDump(leak) do { } while (0) -#endif - - -#endif // !defined(DN_BASE_INC_H) - // DN: Single header generator inlined this file => #include "dn_os_inc.h" -#if !defined(DN_OS_INC_H) -#define DN_OS_INC_H - -#if defined(DN_PLATFORM_WIN32) - // DN: Single header generator commented out this header => #include "OS/dn_os_windows.h" -#if !defined(DN_OS_WINDOWS_H) -#define DN_OS_WINDOWS_H - -#if defined(_CLANGD) - // DN: Single header generator commented out this header => #include "../dn_base_inc.h" -#endif - -#if defined(DN_COMPILER_MSVC) || defined(DN_COMPILER_CLANG_CL) - #pragma comment(lib, "bcrypt") - #pragma comment(lib, "winhttp") - #pragma comment(lib, "dbghelp") - #pragma comment(lib, "comdlg32") - #pragma comment(lib, "pathcch") - #pragma comment(lib, "Shell32") // ShellExecuteW - #pragma comment(lib, "shlwapi") -#endif - -#if defined(DN_NO_WINDOWS_H_REPLACEMENT_HEADER) || defined(_INC_WINDOWS) - #define WIN32_LEAN_AND_MEAN - #include // LONG - #include // DN_OS_SecureRNGBytes -> BCryptOpenAlgorithmProvider ... etc - #include // DN_Win_MakeProcessDPIAware -> SetProcessDpiAwareProc - #include // PathRelativePathTO - #include // PathCchCanonicalizeEx - #include // WinHttp* - #include // PROCESS_MEMORY_COUNTERS_EX2 - #include // OPENFILENAMEW - #include -#else - DN_MSVC_WARNING_PUSH - DN_MSVC_WARNING_DISABLE(4201) // warning C4201: nonstandard extension used: nameless struct/union - - // NOTE: basetsd.h ///////////////////////////////////////////////////////////////////////////// - typedef unsigned __int64 ULONG_PTR, *PULONG_PTR; - typedef unsigned __int64 UINT_PTR, *PUINT_PTR; - typedef ULONG_PTR SIZE_T, *PSIZE_T; - typedef __int64 LONG_PTR, *PLONG_PTR; - typedef ULONG_PTR DWORD_PTR, *PDWORD_PTR; - typedef unsigned __int64 ULONG64, *PULONG64; - typedef unsigned __int64 DWORD64, *PDWORD64; - - // NOTE: shared/minwindef.h //////////////////////////////////////////////////////////////////// - struct HINSTANCE__ { - int unused; - }; - typedef struct HINSTANCE__ *HINSTANCE; - - typedef unsigned long DWORD; - typedef int BOOL; - typedef int INT; - typedef unsigned long ULONG; - typedef unsigned int UINT; - typedef unsigned short WORD; - typedef unsigned char BYTE; - typedef unsigned char UCHAR; - typedef HINSTANCE HMODULE; /* HMODULEs can be used in place of HINSTANCEs */ - typedef void * HANDLE; - typedef HANDLE HLOCAL; - - typedef unsigned __int64 WPARAM; - typedef LONG_PTR LPARAM; - typedef LONG_PTR LRESULT; - - #define MAX_PATH 260 - - typedef struct _FILETIME { - DWORD dwLowDateTime; - DWORD dwHighDateTime; - } FILETIME, *PFILETIME, *LPFILETIME; - - // NOTE: shared/winerror.h ///////////////////////////////////////////////////////////////////// - // NOTE: GetModuleFileNameW - #define ERROR_INSUFFICIENT_BUFFER 122L // dderror - - // NOTE: um/winnls.h /////////////////////////////////////////////////////////////////////////// - // NOTE: MultiByteToWideChar - #define CP_UTF8 65001 // UTF-8 translation - - // NOTE: um/winnt.h //////////////////////////////////////////////////////////////////////////// - typedef void VOID; - typedef __int64 LONGLONG; - typedef unsigned __int64 ULONGLONG; - typedef void * HANDLE; - typedef char CHAR; - typedef short SHORT; - typedef long LONG; - typedef wchar_t WCHAR; // wc, 16-bit UNICODE character - typedef CHAR * NPSTR, *LPSTR, *PSTR; - typedef WCHAR * NWPSTR, *LPWSTR, *PWSTR; - typedef long HRESULT; - - // NOTE: VirtualAlloc: Allocation Type - #define MEM_RESERVE 0x00002000 - #define MEM_COMMIT 0x00001000 - #define MEM_DECOMMIT 0x00004000 - #define MEM_RELEASE 0x00008000 - - // NOTE: VirtualAlloc: Page Permissions - #define PAGE_NOACCESS 0x01 - #define PAGE_READONLY 0x02 - #define PAGE_READWRITE 0x04 - #define PAGE_GUARD 0x100 - - // NOTE: HeapAlloc - #define HEAP_ZERO_MEMORY 0x00000008 - #define HEAP_NO_SERIALIZE 0x00000001 - #define HEAP_GROWABLE 0x00000002 - #define HEAP_GENERATE_EXCEPTIONS 0x00000004 - #define HEAP_ZERO_MEMORY 0x00000008 - #define HEAP_REALLOC_IN_PLACE_ONLY 0x00000010 - #define HEAP_TAIL_CHECKING_ENABLED 0x00000020 - #define HEAP_FREE_CHECKING_ENABLED 0x00000040 - #define HEAP_DISABLE_COALESCE_ON_FREE 0x00000080 - #define HEAP_CREATE_ALIGN_16 0x00010000 - #define HEAP_CREATE_ENABLE_TRACING 0x00020000 - #define HEAP_CREATE_ENABLE_EXECUTE 0x00040000 - #define HEAP_MAXIMUM_TAG 0x0FFF - #define HEAP_PSEUDO_TAG_FLAG 0x8000 - #define HEAP_TAG_SHIFT 18 - #define HEAP_CREATE_SEGMENT_HEAP 0x00000100 - #define HEAP_CREATE_HARDENED 0x00000200 - - // NOTE: FormatMessageA - #define MAKELANGID(p, s) ((((WORD )(s)) << 10) | (WORD )(p)) - #define LANG_NEUTRAL 0x00 - #define SUBLANG_DEFAULT 0x01 // user default - - // NOTE: CreateFile - #define GENERIC_READ (0x80000000L) - #define GENERIC_WRITE (0x40000000L) - #define GENERIC_EXECUTE (0x20000000L) - #define GENERIC_ALL (0x10000000L) - - #define FILE_APPEND_DATA (0x0004) // file - - // NOTE: CreateFile/FindFirstFile - #define FILE_SHARE_READ 0x00000001 - #define FILE_SHARE_WRITE 0x00000002 - #define FILE_SHARE_DELETE 0x00000004 - - #define FILE_ATTRIBUTE_READONLY 0x00000001 - #define FILE_ATTRIBUTE_HIDDEN 0x00000002 - #define FILE_ATTRIBUTE_SYSTEM 0x00000004 - #define FILE_ATTRIBUTE_DIRECTORY 0x00000010 - #define FILE_ATTRIBUTE_NORMAL 0x00000080 - - // NOTE: STACKFRAME64 - #define IMAGE_FILE_MACHINE_AMD64 0x8664 // AMD64 (K8) - - // NOTE: WaitForSingleObject - #define WAIT_TIMEOUT 258L // dderror - #define STATUS_WAIT_0 ((DWORD )0x00000000L) - #define STATUS_ABANDONED_WAIT_0 ((DWORD )0x00000080L) - - #define S_OK ((HRESULT)0L) - #define S_FALSE ((HRESULT)1L) - - typedef union _ULARGE_INTEGER { - struct { - DWORD LowPart; - DWORD HighPart; - } DUMMYSTRUCTNAME; - struct { - DWORD LowPart; - DWORD HighPart; - } u; - ULONGLONG QuadPart; - } ULARGE_INTEGER; - - typedef union _LARGE_INTEGER { - struct { - DWORD LowPart; - LONG HighPart; - } DUMMYSTRUCTNAME; - struct { - DWORD LowPart; - LONG HighPart; - } u; - LONGLONG QuadPart; - } LARGE_INTEGER; - - typedef struct __declspec(align(16)) _M128A { - ULONGLONG Low; - LONGLONG High; - } M128A, *PM128A; - - typedef struct __declspec(align(16)) _XSAVE_FORMAT { - WORD ControlWord; - WORD StatusWord; - BYTE TagWord; - BYTE Reserved1; - WORD ErrorOpcode; - DWORD ErrorOffset; - WORD ErrorSelector; - WORD Reserved2; - DWORD DataOffset; - WORD DataSelector; - WORD Reserved3; - DWORD MxCsr; - DWORD MxCsr_Mask; - M128A FloatRegisters[8]; - #if defined(_WIN64) - M128A XmmRegisters[16]; - BYTE Reserved4[96]; - #else - M128A XmmRegisters[8]; - BYTE Reserved4[224]; - #endif - } XSAVE_FORMAT, *PXSAVE_FORMAT; - typedef XSAVE_FORMAT XMM_SAVE_AREA32, *PXMM_SAVE_AREA32; - - typedef struct __declspec(align(16)) _CONTEXT { - DWORD64 P1Home; - DWORD64 P2Home; - DWORD64 P3Home; - DWORD64 P4Home; - DWORD64 P5Home; - DWORD64 P6Home; - DWORD ContextFlags; - DWORD MxCsr; - WORD SegCs; - WORD SegDs; - WORD SegEs; - WORD SegFs; - WORD SegGs; - WORD SegSs; - DWORD EFlags; - DWORD64 Dr0; - DWORD64 Dr1; - DWORD64 Dr2; - DWORD64 Dr3; - DWORD64 Dr6; - DWORD64 Dr7; - DWORD64 Rax; - DWORD64 Rcx; - DWORD64 Rdx; - DWORD64 Rbx; - DWORD64 Rsp; - DWORD64 Rbp; - DWORD64 Rsi; - DWORD64 Rdi; - DWORD64 R8; - DWORD64 R9; - DWORD64 R10; - DWORD64 R11; - DWORD64 R12; - DWORD64 R13; - DWORD64 R14; - DWORD64 R15; - DWORD64 Rip; - - union { - XMM_SAVE_AREA32 FltSave; - - struct { - M128A Header[2]; - M128A Legacy[8]; - M128A Xmm0; - M128A Xmm1; - M128A Xmm2; - M128A Xmm3; - M128A Xmm4; - M128A Xmm5; - M128A Xmm6; - M128A Xmm7; - M128A Xmm8; - M128A Xmm9; - M128A Xmm10; - M128A Xmm11; - M128A Xmm12; - M128A Xmm13; - M128A Xmm14; - M128A Xmm15; - } DUMMYSTRUCTNAME; - } DUMMYUNIONNAME; - - M128A VectorRegister[26]; - DWORD64 VectorControl; - DWORD64 DebugControl; - DWORD64 LastBranchToRip; - DWORD64 LastBranchFromRip; - DWORD64 LastExceptionToRip; - DWORD64 LastExceptionFromRip; - } CONTEXT; - - typedef struct _LIST_ENTRY { - struct _LIST_ENTRY *Flink; - struct _LIST_ENTRY *Blink; - } LIST_ENTRY, *PLIST_ENTRY, PRLIST_ENTRY; - - typedef struct _RTL_CRITICAL_SECTION_DEBUG { - WORD Type; - WORD CreatorBackTraceIndex; - struct _RTL_CRITICAL_SECTION *CriticalSection; - LIST_ENTRY ProcessLocksList; - DWORD EntryCount; - DWORD ContentionCount; - DWORD Flags; - WORD CreatorBackTraceIndexHigh; - WORD Identifier; - } RTL_CRITICAL_SECTION_DEBUG, *PRTL_CRITICAL_SECTION_DEBUG, RTL_RESOURCE_DEBUG, *PRTL_RESOURCE_DEBUG; - - typedef struct _RTL_CONDITION_VARIABLE { - VOID *Ptr; - } RTL_CONDITION_VARIABLE, *PRTL_CONDITION_VARIABLE; - - #pragma pack(push, 8) - typedef struct _RTL_CRITICAL_SECTION { - PRTL_CRITICAL_SECTION_DEBUG DebugInfo; - - // - // The following three fields control entering and exiting the critical - // section for the resource - // - - LONG LockCount; - LONG RecursionCount; - HANDLE OwningThread; // from the thread's ClientId->UniqueThread - HANDLE LockSemaphore; - ULONG_PTR SpinCount; // force size on 64-bit systems when packed - } RTL_CRITICAL_SECTION, *PRTL_CRITICAL_SECTION; - #pragma pack(pop) - - typedef struct _MODLOAD_DATA { - DWORD ssize; // size of this struct - DWORD ssig; // signature identifying the passed data - VOID *data; // pointer to passed data - DWORD size; // size of passed data - DWORD flags; // options - } MODLOAD_DATA, *PMODLOAD_DATA; - - #define SLMFLAG_VIRTUAL 0x1 - #define SLMFLAG_ALT_INDEX 0x2 - #define SLMFLAG_NO_SYMBOLS 0x4 - - extern "C" - { - __declspec(dllimport) VOID __stdcall RtlCaptureContext(CONTEXT *ContextRecord); - __declspec(dllimport) HANDLE __stdcall GetCurrentProcess(void); - __declspec(dllimport) HANDLE __stdcall GetCurrentThread(void); - __declspec(dllimport) DWORD __stdcall SymSetOptions(DWORD SymOptions); - __declspec(dllimport) BOOL __stdcall SymInitialize(HANDLE hProcess, const CHAR* UserSearchPath, BOOL fInvadeProcess); - __declspec(dllimport) DWORD64 __stdcall SymLoadModuleEx(HANDLE hProcess, HANDLE hFile, CHAR const *ImageName, CHAR const *ModuleName, DWORD64 BaseOfDll, DWORD DllSize, MODLOAD_DATA *Data, DWORD Flags); - __declspec(dllimport) BOOL __stdcall SymUnloadModule64(HANDLE hProcess, DWORD64 BaseOfDll); - } - - // NOTE: um/heapapi.h //////////////////////////////////////////////////////////////////// - extern "C" - { - __declspec(dllimport) HANDLE __stdcall HeapCreate(DWORD flOptions, SIZE_T dwInitialSize, SIZE_T dwMaximumSize); - __declspec(dllimport) BOOL __stdcall HeapDestroy(HANDLE hHeap); - __declspec(dllimport) VOID * __stdcall HeapAlloc(HANDLE hHeap, DWORD dwFlags,SIZE_T dwBytes); - __declspec(dllimport) VOID * __stdcall HeapReAlloc(HANDLE hHeap, DWORD dwFlags, VOID *lpMem, SIZE_T dwBytes); - __declspec(dllimport) BOOL __stdcall HeapFree(HANDLE hHeap, DWORD dwFlags, VOID *lpMem); - __declspec(dllimport) SIZE_T __stdcall HeapSize(HANDLE hHeap, DWORD dwFlags, VOID const *lpMem); - __declspec(dllimport) HANDLE __stdcall GetProcessHeap(VOID); - __declspec(dllimport) SIZE_T __stdcall HeapCompact(HANDLE hHeap, DWORD dwFlags); - } - - // NOTE: shared/windef.h //////////////////////////////////////////////////////////////////// - typedef struct tagPOINT - { - LONG x; - LONG y; - } POINT, *PPOINT, *NPPOINT, *LPPOINT; - - // NOTE: handleapi.h /////////////////////////////////////////////////////////////////////////// - #define INVALID_HANDLE_VALUE ((HANDLE)(LONG_PTR)-1) - - extern "C" - { - __declspec(dllimport) BOOL __stdcall CloseHandle(HANDLE hObject); - } - - // NOTE: consoleapi.h /////////////////////////////////////////////////////////////////////////// - extern "C" - { - __declspec(dllimport) BOOL __stdcall WriteConsoleA(HANDLE hConsoleOutput, const VOID* lpBuffer, DWORD nNumberOfCharsToWrite, DWORD *lpNumberOfCharsWritten, VOID *lpReserved); - __declspec(dllimport) BOOL __stdcall AllocConsole(VOID); - __declspec(dllimport) BOOL __stdcall FreeConsole(VOID); - __declspec(dllimport) BOOL __stdcall AttachConsole(DWORD dwProcessId); - __declspec(dllimport) BOOL __stdcall GetConsoleMode(HANDLE hConsoleHandle, DWORD *lpMode); - } - - // NOTE: um/minwinbase.h /////////////////////////////////////////////////////////////////////// - // NOTE: FindFirstFile - #define FIND_FIRST_EX_CASE_SENSITIVE 0x00000001 - #define FIND_FIRST_EX_LARGE_FETCH 0x00000002 - - // NOTE: WaitFor.. - #define WAIT_FAILED ((DWORD)0xFFFFFFFF) - #define WAIT_OBJECT_0 ((STATUS_WAIT_0 ) + 0 ) - #define WAIT_ABANDONED ((STATUS_ABANDONED_WAIT_0 ) + 0 ) - #define WAIT_ABANDONED_0 ((STATUS_ABANDONED_WAIT_0 ) + 0 ) - - // NOTE: CreateProcessW - #define CREATE_UNICODE_ENVIRONMENT 0x00000400 - #define CREATE_NO_WINDOW 0x08000000 - - typedef enum _GET_FILEEX_INFO_LEVELS { - GetFileExInfoStandard, - GetFileExMaxInfoLevel - } GET_FILEEX_INFO_LEVELS; - - typedef struct _SECURITY_ATTRIBUTES { - DWORD nLength; - VOID *lpSecurityDescriptor; - BOOL bInheritHandle; - } SECURITY_ATTRIBUTES, *PSECURITY_ATTRIBUTES, *LPSECURITY_ATTRIBUTES; - - typedef enum _FINDEX_INFO_LEVELS { - FindExInfoStandard, - FindExInfoBasic, - FindExInfoMaxInfoLevel - } FINDEX_INFO_LEVELS; - - typedef enum _FINDEX_SEARCH_OPS { - FindExSearchNameMatch, - FindExSearchLimitToDirectories, - FindExSearchLimitToDevices, - FindExSearchMaxSearchOp - } FINDEX_SEARCH_OPS; - - typedef struct _WIN32_FIND_DATAW { - DWORD dwFileAttributes; - FILETIME ftCreationTime; - FILETIME ftLastAccessTime; - FILETIME ftLastWriteTime; - DWORD nFileSizeHigh; - DWORD nFileSizeLow; - DWORD dwReserved0; - DWORD dwReserved1; - WCHAR cFileName[ MAX_PATH ]; - WCHAR cAlternateFileName[ 14 ]; - #ifdef _MAC - DWORD dwFileType; - DWORD dwCreatorType; - WORD wFinderFlags; - #endif - } WIN32_FIND_DATAW, *PWIN32_FIND_DATAW, *LPWIN32_FIND_DATAW; - - typedef struct _SYSTEMTIME { - WORD wYear; - WORD wMonth; - WORD wDayOfWeek; - WORD wDay; - WORD wHour; - WORD wMinute; - WORD wSecond; - WORD wMilliseconds; - } SYSTEMTIME, *PSYSTEMTIME, *LPSYSTEMTIME; - - typedef struct _OVERLAPPED { - ULONG_PTR Internal; - ULONG_PTR InternalHigh; - union { - struct { - DWORD Offset; - DWORD OffsetHigh; - } DUMMYSTRUCTNAME; - VOID *Pointer; - } DUMMYUNIONNAME; - - HANDLE hEvent; - } OVERLAPPED, *LPOVERLAPPED; - - typedef RTL_CRITICAL_SECTION CRITICAL_SECTION; - - #define WAIT_FAILED ((DWORD)0xFFFFFFFF) - #define WAIT_OBJECT_0 ((STATUS_WAIT_0 ) + 0 ) - - #define INFINITE 0xFFFFFFFF // Wait/Synchronisation: Infinite timeout - - #define STD_INPUT_HANDLE ((DWORD)-10) - #define STD_OUTPUT_HANDLE ((DWORD)-11) - #define STD_ERROR_HANDLE ((DWORD)-12) - - #define HANDLE_FLAG_INHERIT 0x00000001 - #define HANDLE_FLAG_PROTECT_FROM_CLOSE 0x00000002 - - // NOTE: MoveFile - #define MOVEFILE_REPLACE_EXISTING 0x00000001 - #define MOVEFILE_COPY_ALLOWED 0x00000002 - - // NOTE: FormatMessageA - #define FORMAT_MESSAGE_ALLOCATE_BUFFER 0x00000100 - #define FORMAT_MESSAGE_IGNORE_INSERTS 0x00000200 - #define FORMAT_MESSAGE_FROM_HMODULE 0x00000800 - #define FORMAT_MESSAGE_FROM_SYSTEM 0x00001000 - - // NOTE: CreateProcessW - #define STARTF_USESTDHANDLES 0x00000100 - - extern "C" - { - __declspec(dllimport) BOOL __stdcall MoveFileExW (const WCHAR *lpExistingFileName, const WCHAR *lpNewFileName, DWORD dwFlags); - __declspec(dllimport) BOOL __stdcall CopyFileW (const WCHAR *lpExistingFileName, const WCHAR *lpNewFileName, BOOL bFailIfExists); - __declspec(dllimport) HANDLE __stdcall CreateSemaphoreA(SECURITY_ATTRIBUTES *lpSemaphoreAttributes, LONG lInitialCount, LONG lMaximumCount, const CHAR *lpName); - __declspec(dllimport) DWORD __stdcall FormatMessageW (DWORD dwFlags, VOID const *lpSource, DWORD dwMessageId, DWORD dwLanguageId, LPWSTR lpBuffer, DWORD nSize, va_list *Arguments); - __declspec(dllimport) HLOCAL __stdcall LocalFree (HLOCAL hMem); - } - - // NOTE: um/stringapiset.h ///////////////////////////////////////////////////////////////////// - extern "C" - { - __declspec(dllimport) int __stdcall MultiByteToWideChar(UINT CodePage, DWORD dwFlags, const CHAR *lpMultiByteStr, int cbMultiByte, WCHAR *lpWideCharStr, int cchWideChar); - __declspec(dllimport) int __stdcall WideCharToMultiByte(UINT CodePage, DWORD dwFlags, const WCHAR *lpWideCharStr, int cchWideChar, LPSTR lpMultiByteStr, int cbMultiByte, const CHAR *lpDefaultChar, BOOL *lpUsedDefaultChar); - } - - // NOTE: um/fileapi.h ////////////////////////////////////////////////////////////////////////// - #define INVALID_FILE_SIZE ((DWORD)0xFFFFFFFF) - #define INVALID_FILE_ATTRIBUTES ((DWORD)-1) - - // NOTE: CreateFile - #define CREATE_NEW 1 - #define CREATE_ALWAYS 2 - #define OPEN_EXISTING 3 - #define OPEN_ALWAYS 4 - #define TRUNCATE_EXISTING 5 - - typedef struct _WIN32_FILE_ATTRIBUTE_DATA { - DWORD dwFileAttributes; - FILETIME ftCreationTime; - FILETIME ftLastAccessTime; - FILETIME ftLastWriteTime; - DWORD nFileSizeHigh; - DWORD nFileSizeLow; - } WIN32_FILE_ATTRIBUTE_DATA, *LPWIN32_FILE_ATTRIBUTE_DATA; - - extern "C" - { - __declspec(dllimport) BOOL __stdcall FlushFileBuffers (HANDLE hFile); - __declspec(dllimport) BOOL __stdcall CreateDirectoryW (const WCHAR *lpPathName, SECURITY_ATTRIBUTES *lpSecurityAttributes); - __declspec(dllimport) BOOL __stdcall RemoveDirectoryW (const WCHAR *lpPathName); - __declspec(dllimport) BOOL __stdcall FindNextFileW (HANDLE hFindFile, WIN32_FIND_DATAW *lpFindFileData); - __declspec(dllimport) BOOL __stdcall FindClose (HANDLE hFindFile); - __declspec(dllimport) BOOL __stdcall FileTimeToLocalFileTime(const FILETIME *lpFileTime, FILETIME *lpLocalFileTime); - - __declspec(dllimport) HANDLE __stdcall FindFirstFileExW (const WCHAR *lpFileName, FINDEX_INFO_LEVELS fInfoLevelId, VOID *lpFindFileData, FINDEX_SEARCH_OPS fSearchOp, VOID *lpSearchFilter, DWORD dwAdditionalFlags); - __declspec(dllimport) BOOL __stdcall GetFileAttributesExW (const WCHAR *lpFileName, GET_FILEEX_INFO_LEVELS fInfoLevelId, VOID *lpFileInformation); - __declspec(dllimport) BOOL __stdcall GetFileSizeEx (HANDLE hFile, LARGE_INTEGER *lpFileSize); - __declspec(dllimport) BOOL __stdcall DeleteFileW (const WCHAR *lpFileName); - __declspec(dllimport) HANDLE __stdcall CreateFileW (const WCHAR *lpFileName, DWORD dwDesiredAccess, DWORD dwShareMode, SECURITY_ATTRIBUTES *lpSecurityAttributes, DWORD dwCreationDisposition, DWORD dwFlagsAndAttributes, HANDLE hTemplateFile); - __declspec(dllimport) BOOL __stdcall ReadFile (HANDLE hFile, VOID *lpBuffer, DWORD nNumberOfBytesToRead, DWORD *lpNumberOfBytesRead, OVERLAPPED *lpOverlapped); - __declspec(dllimport) BOOL __stdcall WriteFile (HANDLE hFile, const VOID *lpBuffer, DWORD nNumberOfBytesToWrite, DWORD *lpNumberOfBytesWritten, OVERLAPPED *lpOverlapped); - __declspec(dllimport) BOOL __stdcall GetDiskFreeSpaceExW (WCHAR const *lpDirectoryName, ULARGE_INTEGER *lpFreeBytesAvailableToCaller, ULARGE_INTEGER *lpTotalNumberOfBytes, ULARGE_INTEGER *lpTotalNumberOfFreeBytes); - } - - // NOTE: um/processenv.h /////////////////////////////////////////////////////////////////////// - extern "C" - { - __declspec(dllimport) DWORD __stdcall GetCurrentDirectoryW (DWORD nBufferLength, WCHAR *lpBuffer); - __declspec(dllimport) HANDLE __stdcall GetStdHandle (DWORD nStdHandle); - __declspec(dllimport) WCHAR* __stdcall GetEnvironmentStringsW (); - __declspec(dllimport) BOOL __stdcall FreeEnvironmentStringsW(WCHAR *penv); - __declspec(dllimport) DWORD __stdcall GetEnvironmentVariableW(WCHAR const *lpName, WCHAR *lpBuffer, DWORD nSize); - __declspec(dllimport) BOOL __stdcall SetEnvironmentVariableW(WCHAR const *lpName, WCHAR const *lpValue); - } - - // NOTE: um/psapi.h //////////////////////////////////////////////////////////////////////////// - typedef struct _PROCESS_MEMORY_COUNTERS { - 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; - } PROCESS_MEMORY_COUNTERS; - typedef PROCESS_MEMORY_COUNTERS *PPROCESS_MEMORY_COUNTERS; - - extern "C" - { - __declspec(dllimport) BOOL __stdcall GetProcessMemoryInfo(HANDLE Process, PPROCESS_MEMORY_COUNTERS ppsmemCounters, DWORD cb); - } - - // NOTE: um/sysinfoapi.h /////////////////////////////////////////////////////////////////////// - typedef struct _SYSTEM_INFO { - union { - DWORD dwOemId; // Obsolete field...do not use - struct { - WORD wProcessorArchitecture; - WORD wReserved; - } DUMMYSTRUCTNAME; - } DUMMYUNIONNAME; - DWORD dwPageSize; - VOID *lpMinimumApplicationAddress; - VOID *lpMaximumApplicationAddress; - DWORD_PTR dwActiveProcessorMask; - DWORD dwNumberOfProcessors; - DWORD dwProcessorType; - DWORD dwAllocationGranularity; - WORD wProcessorLevel; - WORD wProcessorRevision; - } SYSTEM_INFO, *LPSYSTEM_INFO; - - extern "C" - { - __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); - } - - // NOTE: um/timezoneapi.h ////////////////////////////////////////////////////////////////////// - typedef struct _TIME_ZONE_INFORMATION { - LONG Bias; - WCHAR StandardName[32]; - SYSTEMTIME StandardDate; - LONG StandardBias; - WCHAR DaylightName[32]; - SYSTEMTIME DaylightDate; - LONG DaylightBias; - } TIME_ZONE_INFORMATION, *PTIME_ZONE_INFORMATION, *LPTIME_ZONE_INFORMATION; - - extern "C" - { - __declspec(dllimport) BOOL __stdcall FileTimeToSystemTime (const FILETIME* lpFileTime, SYSTEMTIME *lpSystemTime); - __declspec(dllimport) BOOL __stdcall SystemTimeToFileTime (const SYSTEMTIME* lpSystemTime, FILETIME *lpFileTime); - __declspec(dllimport) BOOL __stdcall TzSpecificLocalTimeToSystemTime(const TIME_ZONE_INFORMATION* lpTimeZoneInformation, const SYSTEMTIME* lpLocalTime, const LPSYSTEMTIME lpUniversalTime); - } - - // NOTE: shared/windef.h /////////////////////////////////////////////////////////////////////// - typedef struct tagRECT { - LONG left; - LONG top; - LONG right; - LONG bottom; - } RECT; - - struct HWND__ { - int unused; - }; - typedef struct HWND__ *HWND; - - struct DPI_AWARENESS_CONTEXT__ { - int unused; - }; - typedef struct DPI_AWARENESS_CONTEXT__ *DPI_AWARENESS_CONTEXT; - - typedef enum DPI_AWARENESS { - DPI_AWARENESS_INVALID = -1, - DPI_AWARENESS_UNAWARE = 0, - DPI_AWARENESS_SYSTEM_AWARE = 1, - DPI_AWARENESS_PER_MONITOR_AWARE = 2 - } DPI_AWARENESS; - - #define DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2 ((DPI_AWARENESS_CONTEXT)-4) - - // NOTE: um/winuser.h ////////////////////////////////////////////////////////////////////////// - typedef struct tagWINDOWPLACEMENT { - UINT length; - UINT flags; - UINT showCmd; - POINT ptMinPosition; - POINT ptMaxPosition; - RECT rcNormalPosition; - #ifdef _MAC - RECT rcDevice; - #endif - } WINDOWPLACEMENT; - typedef WINDOWPLACEMENT *PWINDOWPLACEMENT, *LPWINDOWPLACEMENT; - - #define SW_HIDE 0 - #define SW_NORMAL 1 - #define SW_MAXIMIZE 3 - #define SW_SHOWNOACTIVATE 4 - #define SW_SHOW 5 - #define SW_FORCEMINIMIZE 11 - - extern "C" - { - __declspec(dllimport) BOOL __stdcall GetWindowRect (HWND hWnd, RECT *lpRect); - __declspec(dllimport) BOOL __stdcall SetWindowPos (HWND hWnd, HWND hWndInsertAfter, int X, int Y, int cx, int cy, UINT uFlags); - __declspec(dllimport) UINT __stdcall GetWindowModuleFileNameA(HWND hwnd, LPSTR pszFileName, UINT cchFileNameMax); - __declspec(dllimport) BOOL __stdcall ShowWindow (HWND hWnd, int nCmdShow); - __declspec(dllimport) BOOL __stdcall GetWindowPlacement (HWND hWnd, WINDOWPLACEMENT *lpwndpl); - - } - - // NOTE: um/wininet.h ////////////////////////////////////////////////////////////////////////// - typedef WORD INTERNET_PORT; - typedef VOID *HINTERNET; - - // NOTE: um/winhttp.h ////////////////////////////////////////////////////////////////////////// - #define WINHTTP_ACCESS_TYPE_DEFAULT_PROXY 0 - #define WINHTTP_ACCESS_TYPE_NO_PROXY 1 - #define WINHTTP_ACCESS_TYPE_NAMED_PROXY 3 - #define WINHTTP_ACCESS_TYPE_AUTOMATIC_PROXY 4 - - #define INTERNET_DEFAULT_PORT 0 // use the protocol-specific default - #define INTERNET_DEFAULT_HTTP_PORT 80 // " " HTTP " - #define INTERNET_DEFAULT_HTTPS_PORT 443 // " " HTTPS " - - // NOTE: WinHttpOpen - #define WINHTTP_FLAG_ASYNC 0x10000000 // this session is asynchronous (where supported) - #define WINHTTP_FLAG_SECURE_DEFAULTS 0x30000000 // note that this flag also forces async - - // NOTE: WinHttpOpenRequest - #define WINHTTP_FLAG_SECURE 0x00800000 // use SSL if applicable (HTTPS) - #define WINHTTP_FLAG_ESCAPE_PERCENT 0x00000004 // if escaping enabled, escape percent as well - #define WINHTTP_FLAG_NULL_CODEPAGE 0x00000008 // assume all symbols are ASCII, use fast convertion - #define WINHTTP_FLAG_ESCAPE_DISABLE 0x00000040 // disable escaping - #define WINHTTP_FLAG_ESCAPE_DISABLE_QUERY 0x00000080 // if escaping enabled escape path part, but do not escape query - #define WINHTTP_FLAG_BYPASS_PROXY_CACHE 0x00000100 // add "pragma: no-cache" request header - #define WINHTTP_FLAG_REFRESH WINHTTP_FLAG_BYPASS_PROXY_CACHE - #define WINHTTP_FLAG_AUTOMATIC_CHUNKING 0x00000200 // Send request without content-length header or chunked TE - - #define WINHTTP_NO_PROXY_NAME NULL - #define WINHTTP_NO_PROXY_BYPASS NULL - - // - // WINHTTP_QUERY_FLAG_NUMBER - if this bit is set in the dwInfoLevel parameter of - // HttpQueryHeader(), then the value of the header will be converted to a number - // before being returned to the caller, if applicable - // - #define WINHTTP_QUERY_FLAG_NUMBER 0x20000000 - - #define WINHTTP_QUERY_MIME_VERSION 0 - #define WINHTTP_QUERY_CONTENT_TYPE 1 - #define WINHTTP_QUERY_CONTENT_TRANSFER_ENCODING 2 - #define WINHTTP_QUERY_CONTENT_ID 3 - #define WINHTTP_QUERY_CONTENT_DESCRIPTION 4 - #define WINHTTP_QUERY_CONTENT_LENGTH 5 - #define WINHTTP_QUERY_CONTENT_LANGUAGE 6 - #define WINHTTP_QUERY_ALLOW 7 - #define WINHTTP_QUERY_PUBLIC 8 - #define WINHTTP_QUERY_DATE 9 - #define WINHTTP_QUERY_EXPIRES 10 - #define WINHTTP_QUERY_LAST_MODIFIED 11 - #define WINHTTP_QUERY_MESSAGE_ID 12 - #define WINHTTP_QUERY_URI 13 - #define WINHTTP_QUERY_DERIVED_FROM 14 - #define WINHTTP_QUERY_COST 15 - #define WINHTTP_QUERY_LINK 16 - #define WINHTTP_QUERY_PRAGMA 17 - #define WINHTTP_QUERY_VERSION 18 // special: part of status line - #define WINHTTP_QUERY_STATUS_CODE 19 // special: part of status line - #define WINHTTP_QUERY_STATUS_TEXT 20 // special: part of status line - #define WINHTTP_QUERY_RAW_HEADERS 21 // special: all headers as ASCIIZ - #define WINHTTP_QUERY_RAW_HEADERS_CRLF 22 // special: all headers - #define WINHTTP_QUERY_CONNECTION 23 - #define WINHTTP_QUERY_ACCEPT 24 - #define WINHTTP_QUERY_ACCEPT_CHARSET 25 - #define WINHTTP_QUERY_ACCEPT_ENCODING 26 - #define WINHTTP_QUERY_ACCEPT_LANGUAGE 27 - #define WINHTTP_QUERY_AUTHORIZATION 28 - #define WINHTTP_QUERY_CONTENT_ENCODING 29 - #define WINHTTP_QUERY_FORWARDED 30 - #define WINHTTP_QUERY_FROM 31 - #define WINHTTP_QUERY_IF_MODIFIED_SINCE 32 - #define WINHTTP_QUERY_LOCATION 33 - #define WINHTTP_QUERY_ORIG_URI 34 - #define WINHTTP_QUERY_REFERER 35 - #define WINHTTP_QUERY_RETRY_AFTER 36 - #define WINHTTP_QUERY_SERVER 37 - #define WINHTTP_QUERY_TITLE 38 - #define WINHTTP_QUERY_USER_AGENT 39 - #define WINHTTP_QUERY_WWW_AUTHENTICATE 40 - #define WINHTTP_QUERY_PROXY_AUTHENTICATE 41 - #define WINHTTP_QUERY_ACCEPT_RANGES 42 - #define WINHTTP_QUERY_SET_COOKIE 43 - #define WINHTTP_QUERY_COOKIE 44 - #define WINHTTP_QUERY_REQUEST_METHOD 45 // special: GET/POST etc. - #define WINHTTP_QUERY_REFRESH 46 - #define WINHTTP_QUERY_CONTENT_DISPOSITION 47 - - // NOTE: WinHttpQueryHeaders prettifiers for optional parameters. - #define WINHTTP_HEADER_NAME_BY_INDEX NULL - #define WINHTTP_NO_OUTPUT_BUFFER NULL - #define WINHTTP_NO_HEADER_INDEX NULL - - // NOTE: Http Response Status Codes - #define HTTP_STATUS_CONTINUE 100 // OK to continue with request - #define HTTP_STATUS_SWITCH_PROTOCOLS 101 // server has switched protocols in upgrade header - - #define HTTP_STATUS_OK 200 // request completed - #define HTTP_STATUS_CREATED 201 // object created, reason = new URI - #define HTTP_STATUS_ACCEPTED 202 // async completion (TBS) - #define HTTP_STATUS_PARTIAL 203 // partial completion - #define HTTP_STATUS_NO_CONTENT 204 // no info to return - #define HTTP_STATUS_RESET_CONTENT 205 // request completed, but clear form - #define HTTP_STATUS_PARTIAL_CONTENT 206 // partial GET fulfilled - #define HTTP_STATUS_WEBDAV_MULTI_STATUS 207 // WebDAV Multi-Status - - #define HTTP_STATUS_AMBIGUOUS 300 // server couldn't decide what to return - #define HTTP_STATUS_MOVED 301 // object permanently moved - #define HTTP_STATUS_REDIRECT 302 // object temporarily moved - #define HTTP_STATUS_REDIRECT_METHOD 303 // redirection w/ new access method - #define HTTP_STATUS_NOT_MODIFIED 304 // if-modified-since was not modified - #define HTTP_STATUS_USE_PROXY 305 // redirection to proxy, location header specifies proxy to use - #define HTTP_STATUS_REDIRECT_KEEP_VERB 307 // HTTP/1.1: keep same verb - #define HTTP_STATUS_PERMANENT_REDIRECT 308 // Object permanently moved keep verb - - #define HTTP_STATUS_BAD_REQUEST 400 // invalid syntax - #define HTTP_STATUS_DENIED 401 // access denied - #define HTTP_STATUS_PAYMENT_REQ 402 // payment required - #define HTTP_STATUS_FORBIDDEN 403 // request forbidden - #define HTTP_STATUS_NOT_FOUND 404 // object not found - #define HTTP_STATUS_BAD_METHOD 405 // method is not allowed - #define HTTP_STATUS_NONE_ACCEPTABLE 406 // no response acceptable to client found - #define HTTP_STATUS_PROXY_AUTH_REQ 407 // proxy authentication required - #define HTTP_STATUS_REQUEST_TIMEOUT 408 // server timed out waiting for request - #define HTTP_STATUS_CONFLICT 409 // user should resubmit with more info - #define HTTP_STATUS_GONE 410 // the resource is no longer available - #define HTTP_STATUS_LENGTH_REQUIRED 411 // the server refused to accept request w/o a length - #define HTTP_STATUS_PRECOND_FAILED 412 // precondition given in request failed - #define HTTP_STATUS_REQUEST_TOO_LARGE 413 // request entity was too large - #define HTTP_STATUS_URI_TOO_LONG 414 // request URI too long - #define HTTP_STATUS_UNSUPPORTED_MEDIA 415 // unsupported media type - #define HTTP_STATUS_RETRY_WITH 449 // retry after doing the appropriate action. - - #define HTTP_STATUS_SERVER_ERROR 500 // internal server error - #define HTTP_STATUS_NOT_SUPPORTED 501 // required not supported - #define HTTP_STATUS_BAD_GATEWAY 502 // error response received from gateway - #define HTTP_STATUS_SERVICE_UNAVAIL 503 // temporarily overloaded - #define HTTP_STATUS_GATEWAY_TIMEOUT 504 // timed out waiting for gateway - #define HTTP_STATUS_VERSION_NOT_SUP 505 // HTTP version not supported - - #define HTTP_STATUS_FIRST HTTP_STATUS_CONTINUE - #define HTTP_STATUS_LAST HTTP_STATUS_VERSION_NOT_SUP - - #define WINHTTP_CALLBACK_STATUS_RESOLVING_NAME 0x00000001 - #define WINHTTP_CALLBACK_STATUS_NAME_RESOLVED 0x00000002 - #define WINHTTP_CALLBACK_STATUS_CONNECTING_TO_SERVER 0x00000004 - #define WINHTTP_CALLBACK_STATUS_CONNECTED_TO_SERVER 0x00000008 - #define WINHTTP_CALLBACK_STATUS_SENDING_REQUEST 0x00000010 - #define WINHTTP_CALLBACK_STATUS_REQUEST_SENT 0x00000020 - #define WINHTTP_CALLBACK_STATUS_RECEIVING_RESPONSE 0x00000040 - #define WINHTTP_CALLBACK_STATUS_RESPONSE_RECEIVED 0x00000080 - #define WINHTTP_CALLBACK_STATUS_CLOSING_CONNECTION 0x00000100 - #define WINHTTP_CALLBACK_STATUS_CONNECTION_CLOSED 0x00000200 - #define WINHTTP_CALLBACK_STATUS_HANDLE_CREATED 0x00000400 - #define WINHTTP_CALLBACK_STATUS_HANDLE_CLOSING 0x00000800 - #define WINHTTP_CALLBACK_STATUS_DETECTING_PROXY 0x00001000 - #define WINHTTP_CALLBACK_STATUS_REDIRECT 0x00004000 - #define WINHTTP_CALLBACK_STATUS_INTERMEDIATE_RESPONSE 0x00008000 - #define WINHTTP_CALLBACK_STATUS_SECURE_FAILURE 0x00010000 - #define WINHTTP_CALLBACK_STATUS_HEADERS_AVAILABLE 0x00020000 - #define WINHTTP_CALLBACK_STATUS_DATA_AVAILABLE 0x00040000 - #define WINHTTP_CALLBACK_STATUS_READ_COMPLETE 0x00080000 - #define WINHTTP_CALLBACK_STATUS_WRITE_COMPLETE 0x00100000 - #define WINHTTP_CALLBACK_STATUS_REQUEST_ERROR 0x00200000 - #define WINHTTP_CALLBACK_STATUS_SENDREQUEST_COMPLETE 0x00400000 - - #define WINHTTP_CALLBACK_STATUS_GETPROXYFORURL_COMPLETE 0x01000000 - #define WINHTTP_CALLBACK_STATUS_CLOSE_COMPLETE 0x02000000 - #define WINHTTP_CALLBACK_STATUS_SHUTDOWN_COMPLETE 0x04000000 - #define WINHTTP_CALLBACK_STATUS_SETTINGS_WRITE_COMPLETE 0x10000000 - #define WINHTTP_CALLBACK_STATUS_SETTINGS_READ_COMPLETE 0x20000000 - - #define WINHTTP_CALLBACK_FLAG_RESOLVE_NAME (WINHTTP_CALLBACK_STATUS_RESOLVING_NAME | WINHTTP_CALLBACK_STATUS_NAME_RESOLVED) - #define WINHTTP_CALLBACK_FLAG_CONNECT_TO_SERVER (WINHTTP_CALLBACK_STATUS_CONNECTING_TO_SERVER | WINHTTP_CALLBACK_STATUS_CONNECTED_TO_SERVER) - #define WINHTTP_CALLBACK_FLAG_SEND_REQUEST (WINHTTP_CALLBACK_STATUS_SENDING_REQUEST | WINHTTP_CALLBACK_STATUS_REQUEST_SENT) - #define WINHTTP_CALLBACK_FLAG_RECEIVE_RESPONSE (WINHTTP_CALLBACK_STATUS_RECEIVING_RESPONSE | WINHTTP_CALLBACK_STATUS_RESPONSE_RECEIVED) - #define WINHTTP_CALLBACK_FLAG_CLOSE_CONNECTION (WINHTTP_CALLBACK_STATUS_CLOSING_CONNECTION | WINHTTP_CALLBACK_STATUS_CONNECTION_CLOSED) - #define WINHTTP_CALLBACK_FLAG_HANDLES (WINHTTP_CALLBACK_STATUS_HANDLE_CREATED | WINHTTP_CALLBACK_STATUS_HANDLE_CLOSING) - #define WINHTTP_CALLBACK_FLAG_DETECTING_PROXY WINHTTP_CALLBACK_STATUS_DETECTING_PROXY - #define WINHTTP_CALLBACK_FLAG_REDIRECT WINHTTP_CALLBACK_STATUS_REDIRECT - #define WINHTTP_CALLBACK_FLAG_INTERMEDIATE_RESPONSE WINHTTP_CALLBACK_STATUS_INTERMEDIATE_RESPONSE - #define WINHTTP_CALLBACK_FLAG_SECURE_FAILURE WINHTTP_CALLBACK_STATUS_SECURE_FAILURE - #define WINHTTP_CALLBACK_FLAG_SENDREQUEST_COMPLETE WINHTTP_CALLBACK_STATUS_SENDREQUEST_COMPLETE - #define WINHTTP_CALLBACK_FLAG_HEADERS_AVAILABLE WINHTTP_CALLBACK_STATUS_HEADERS_AVAILABLE - #define WINHTTP_CALLBACK_FLAG_DATA_AVAILABLE WINHTTP_CALLBACK_STATUS_DATA_AVAILABLE - #define WINHTTP_CALLBACK_FLAG_READ_COMPLETE WINHTTP_CALLBACK_STATUS_READ_COMPLETE - #define WINHTTP_CALLBACK_FLAG_WRITE_COMPLETE WINHTTP_CALLBACK_STATUS_WRITE_COMPLETE - #define WINHTTP_CALLBACK_FLAG_REQUEST_ERROR WINHTTP_CALLBACK_STATUS_REQUEST_ERROR - - #define WINHTTP_CALLBACK_FLAG_GETPROXYFORURL_COMPLETE WINHTTP_CALLBACK_STATUS_GETPROXYFORURL_COMPLETE - - #define WINHTTP_CALLBACK_FLAG_ALL_COMPLETIONS (WINHTTP_CALLBACK_STATUS_SENDREQUEST_COMPLETE \ - | WINHTTP_CALLBACK_STATUS_HEADERS_AVAILABLE \ - | WINHTTP_CALLBACK_STATUS_DATA_AVAILABLE \ - | WINHTTP_CALLBACK_STATUS_READ_COMPLETE \ - | WINHTTP_CALLBACK_STATUS_WRITE_COMPLETE \ - | WINHTTP_CALLBACK_STATUS_REQUEST_ERROR \ - | WINHTTP_CALLBACK_STATUS_GETPROXYFORURL_COMPLETE) - - #define WINHTTP_CALLBACK_FLAG_ALL_NOTIFICATIONS 0xffffffff - #define WINHTTP_INVALID_STATUS_CALLBACK ((WINHTTP_STATUS_CALLBACK)(-1L)) - - typedef struct _WINHTTP_EXTENDED_HEADER - { - union - { - CHAR const *pwszName; - WCHAR const *pszName; - }; - union - { - WCHAR const *pwszValue; - CHAR const *pszValue; - }; - } WINHTTP_EXTENDED_HEADER, *PWINHTTP_EXTENDED_HEADER; - - typedef struct _WINHTTP_ASYNC_RESULT - { - DWORD *dwResult; // indicates which async API has encountered an error - DWORD dwError; // the error code if the API failed - } WINHTTP_ASYNC_RESULT, *LPWINHTTP_ASYNC_RESULT, *PWINHTTP_ASYNC_RESULT; - - typedef - VOID - (*WINHTTP_STATUS_CALLBACK)( - HINTERNET hInternet, - DWORD *dwContext, - DWORD dwInternetStatus, - VOID *lpvStatusInformation, - DWORD dwStatusInformationLength - ); - - extern "C" - { - __declspec(dllimport) HINTERNET __stdcall WinHttpOpen(WCHAR const *pszAgentW, DWORD dwAccessType, WCHAR const *pszProxyW, WCHAR const *pszProxyBypassW, DWORD dwFlags); - __declspec(dllimport) BOOL __stdcall WinHttpCloseHandle(HINTERNET hInternet); - __declspec(dllimport) HINTERNET __stdcall WinHttpConnect(HINTERNET hSession, WCHAR const *pswzServerName, INTERNET_PORT nServerPort, DWORD dwReserved); - __declspec(dllimport) BOOL __stdcall WinHttpReadData(HINTERNET hRequest, VOID *lpBuffer, DWORD dwNumberOfBytesToRead, DWORD *lpdwNumberOfBytesRead); - __declspec(dllimport) HINTERNET __stdcall WinHttpOpenRequest(HINTERNET hConnect, WCHAR const *pwszVerb, WCHAR const *pwszObjectName, WCHAR const *pwszVersion, WCHAR const *pwszReferrer, WCHAR const *ppwszAcceptTypes, DWORD dwFlags); - __declspec(dllimport) BOOL __stdcall WinHttpSendRequest(HINTERNET hRequest, WCHAR const *lpszHeaders, DWORD dwHeadersLength, VOID *lpOptional, DWORD dwOptionalLength, DWORD dwTotalLength, DWORD_PTR dwContext); - __declspec(dllimport) DWORD __stdcall WinHttpAddRequestHeadersEx(HINTERNET hRequest, DWORD dwModifiers, ULONGLONG ullFlags, ULONGLONG ullExtra, DWORD cHeaders, WINHTTP_EXTENDED_HEADER *pHeaders); - __declspec(dllimport) BOOL __stdcall WinHttpSetCredentials(HINTERNET hRequest, // HINTERNET handle returned by WinHttpOpenRequest. - DWORD AuthTargets, // Only WINHTTP_AUTH_TARGET_SERVER and WINHTTP_AUTH_TARGET_PROXY are supported in this version and they are mutually exclusive - DWORD AuthScheme, // must be one of the supported Auth Schemes returned from WinHttpQueryAuthSchemes() - WCHAR * pwszUserName, // 1) NULL if default creds is to be used, in which case pszPassword will be ignored - WCHAR * pwszPassword, // 1) "" == Blank Password; 2)Parameter ignored if pszUserName is NULL; 3) Invalid to pass in NULL if pszUserName is not NULL - VOID * pAuthParams); - __declspec(dllimport) BOOL __stdcall WinHttpQueryHeaders(HINTERNET hRequest, DWORD dwInfoLevel, WCHAR const *pwszName, VOID *lpBuffer, DWORD *lpdwBufferLength, DWORD *lpdwIndex); - __declspec(dllimport) BOOL __stdcall WinHttpReceiveResponse(HINTERNET hRequest, VOID *lpReserved); - __declspec(dllimport) WINHTTP_STATUS_CALLBACK __stdcall WinHttpSetStatusCallback(HINTERNET hInternet, WINHTTP_STATUS_CALLBACK lpfnInternetCallback, DWORD dwNotificationFlags, DWORD_PTR dwReserved); - } - - // NOTE: um/DbgHelp.h ////////////////////////////////////////////////////////////////////////// - #define SYMOPT_CASE_INSENSITIVE 0x00000001 - #define SYMOPT_UNDNAME 0x00000002 - #define SYMOPT_DEFERRED_LOADS 0x00000004 - #define SYMOPT_NO_CPP 0x00000008 - #define SYMOPT_LOAD_LINES 0x00000010 - #define SYMOPT_OMAP_FIND_NEAREST 0x00000020 - #define SYMOPT_LOAD_ANYTHING 0x00000040 - #define SYMOPT_IGNORE_CVREC 0x00000080 - #define SYMOPT_NO_UNQUALIFIED_LOADS 0x00000100 - #define SYMOPT_FAIL_CRITICAL_ERRORS 0x00000200 - #define SYMOPT_EXACT_SYMBOLS 0x00000400 - #define SYMOPT_ALLOW_ABSOLUTE_SYMBOLS 0x00000800 - #define SYMOPT_IGNORE_NT_SYMPATH 0x00001000 - #define SYMOPT_INCLUDE_32BIT_MODULES 0x00002000 - #define SYMOPT_PUBLICS_ONLY 0x00004000 - #define SYMOPT_NO_PUBLICS 0x00008000 - #define SYMOPT_AUTO_PUBLICS 0x00010000 - #define SYMOPT_NO_IMAGE_SEARCH 0x00020000 - #define SYMOPT_SECURE 0x00040000 - #define SYMOPT_NO_PROMPTS 0x00080000 - #define SYMOPT_OVERWRITE 0x00100000 - #define SYMOPT_IGNORE_IMAGEDIR 0x00200000 - #define SYMOPT_FLAT_DIRECTORY 0x00400000 - #define SYMOPT_FAVOR_COMPRESSED 0x00800000 - #define SYMOPT_ALLOW_ZERO_ADDRESS 0x01000000 - #define SYMOPT_DISABLE_SYMSRV_AUTODETECT 0x02000000 - #define SYMOPT_READONLY_CACHE 0x04000000 - #define SYMOPT_SYMPATH_LAST 0x08000000 - #define SYMOPT_DISABLE_FAST_SYMBOLS 0x10000000 - #define SYMOPT_DISABLE_SYMSRV_TIMEOUT 0x20000000 - #define SYMOPT_DISABLE_SRVSTAR_ON_STARTUP 0x40000000 - #define SYMOPT_DEBUG 0x80000000 - - #define MAX_SYM_NAME 2000 - - typedef enum { - AddrMode1616, - AddrMode1632, - AddrModeReal, - AddrModeFlat - } ADDRESS_MODE; - - typedef struct _tagADDRESS64 { - DWORD64 Offset; - WORD Segment; - ADDRESS_MODE Mode; - } ADDRESS64, *LPADDRESS64; - - - typedef struct _KDHELP64 { - DWORD64 Thread; - DWORD ThCallbackStack; - DWORD ThCallbackBStore; - DWORD NextCallback; - DWORD FramePointer; - DWORD64 KiCallUserMode; - DWORD64 KeUserCallbackDispatcher; - DWORD64 SystemRangeStart; - DWORD64 KiUserExceptionDispatcher; - DWORD64 StackBase; - DWORD64 StackLimit; - DWORD BuildVersion; - DWORD RetpolineStubFunctionTableSize; - DWORD64 RetpolineStubFunctionTable; - DWORD RetpolineStubOffset; - DWORD RetpolineStubSize; - DWORD64 Reserved0[2]; - } KDHELP64, *PKDHELP64; - - typedef struct _tagSTACKFRAME64 { - ADDRESS64 AddrPC; // program counter - ADDRESS64 AddrReturn; // return address - ADDRESS64 AddrFrame; // frame pointer - ADDRESS64 AddrStack; // stack pointer - ADDRESS64 AddrBStore; // backing store pointer - VOID *FuncTableEntry; // pointer to pdata/fpo or NULL - DWORD64 Params[4]; // possible arguments to the function - BOOL Far; // WOW far call - BOOL Virtual; // is this a virtual frame? - DWORD64 Reserved[3]; - KDHELP64 KdHelp; - } STACKFRAME64; - - typedef struct _IMAGEHLP_LINEW64 { - DWORD SizeOfStruct; // set to sizeof(IMAGEHLP_LINE64) - VOID *Key; // internal - DWORD LineNumber; // line number in file - WCHAR *FileName; // full filename - DWORD64 Address; // first instruction of line - } IMAGEHLP_LINEW64; - - typedef struct _SYMBOL_INFOW { - ULONG SizeOfStruct; - ULONG TypeIndex; // Type Index of symbol - ULONG64 Reserved[2]; - ULONG Index; - ULONG Size; - ULONG64 ModBase; // Base Address of module comtaining this symbol - ULONG Flags; - ULONG64 Value; // Value of symbol, ValuePresent should be 1 - ULONG64 Address; // Address of symbol including base address of module - ULONG Register; // register holding value or pointer to value - ULONG Scope; // scope of the symbol - ULONG Tag; // pdb classification - ULONG NameLen; // Actual length of name - ULONG MaxNameLen; - WCHAR Name[1]; // Name of symbol - } SYMBOL_INFOW; - - typedef BOOL (__stdcall READ_PROCESS_MEMORY_ROUTINE64)(HANDLE hProcess, DWORD64 qwBaseAddress, VOID *lpBuffer, DWORD nSize, DWORD *lpNumberOfBytesRead); - typedef VOID * (__stdcall FUNCTION_TABLE_ACCESS_ROUTINE64)(HANDLE ahProcess, DWORD64 AddrBase); - typedef DWORD64(__stdcall GET_MODULE_BASE_ROUTINE64)(HANDLE hProcess, DWORD64 Address); - typedef DWORD64(__stdcall TRANSLATE_ADDRESS_ROUTINE64)(HANDLE hProcess, HANDLE hThread, ADDRESS64 *lpaddr); - - extern "C" - { - __declspec(dllimport) BOOL __stdcall StackWalk64 (DWORD MachineType, HANDLE hProcess, HANDLE hThread, STACKFRAME64 *StackFrame, VOID *ContextRecord, READ_PROCESS_MEMORY_ROUTINE64 *ReadMemoryRoutine, FUNCTION_TABLE_ACCESS_ROUTINE64 *FunctionTableAccessRoutine, GET_MODULE_BASE_ROUTINE64 *GetModuleBaseRoutine, TRANSLATE_ADDRESS_ROUTINE64 *TranslateAddress); - __declspec(dllimport) BOOL __stdcall SymFromAddrW (HANDLE hProcess, DWORD64 Address, DWORD64 *Displacement, SYMBOL_INFOW *Symbol); - __declspec(dllimport) VOID * __stdcall SymFunctionTableAccess64(HANDLE hProcess, DWORD64 AddrBase); - __declspec(dllimport) BOOL __stdcall SymGetLineFromAddrW64 (HANDLE hProcess, DWORD64 dwAddr, DWORD *pdwDisplacement, IMAGEHLP_LINEW64 *Line); - __declspec(dllimport) DWORD64 __stdcall SymGetModuleBase64 (HANDLE hProcess, DWORD64 qwAddr); - __declspec(dllimport) BOOL __stdcall SymRefreshModuleList (HANDLE hProcess); - }; - - // NOTE: um/errhandlingapi.h /////////////////////////////////////////////////////////////////// - extern "C" - { - __declspec(dllimport) DWORD __stdcall GetLastError(VOID); - } - - // NOTE: um/libloaderapi.h ///////////////////////////////////////////////////////////////////// - extern "C" - { - __declspec(dllimport) HMODULE __stdcall LoadLibraryA (const CHAR *lpLibFileName); - __declspec(dllimport) BOOL __stdcall FreeLibrary (HMODULE hLibModule); - __declspec(dllimport) void * __stdcall GetProcAddress (HMODULE hModule, const CHAR *lpProcName); - __declspec(dllimport) HMODULE __stdcall GetModuleHandleA (const CHAR *lpModuleName); - __declspec(dllimport) DWORD __stdcall GetModuleFileNameW(HMODULE hModule, WCHAR *lpFilename, DWORD nSize); - } - - // NOTE: um/synchapi.h ///////////////////////////////////////////////////////////////////////// - typedef RTL_CONDITION_VARIABLE CONDITION_VARIABLE, *PCONDITION_VARIABLE; - - extern "C" - { - __declspec(dllimport) VOID __stdcall InitializeConditionVariable (CONDITION_VARIABLE *ConditionVariable); - __declspec(dllimport) VOID __stdcall WakeConditionVariable (CONDITION_VARIABLE *ConditionVariable); - __declspec(dllimport) VOID __stdcall WakeAllConditionVariable (CONDITION_VARIABLE *ConditionVariable); - __declspec(dllimport) BOOL __stdcall SleepConditionVariableCS (CONDITION_VARIABLE *ConditionVariable, CRITICAL_SECTION *CriticalSection, DWORD dwMilliseconds); - - __declspec(dllimport) VOID __stdcall InitializeCriticalSection (CRITICAL_SECTION *lpCriticalSection); - __declspec(dllimport) VOID __stdcall EnterCriticalSection (CRITICAL_SECTION *lpCriticalSection); - __declspec(dllimport) VOID __stdcall LeaveCriticalSection (CRITICAL_SECTION *lpCriticalSection); - __declspec(dllimport) BOOL __stdcall InitializeCriticalSectionAndSpinCount(CRITICAL_SECTION *lpCriticalSection, DWORD dwSpinCount); - __declspec(dllimport) BOOL __stdcall InitializeCriticalSectionEx (CRITICAL_SECTION *lpCriticalSection, DWORD dwSpinCount, DWORD Flags); - __declspec(dllimport) DWORD __stdcall SetCriticalSectionSpinCount (CRITICAL_SECTION *lpCriticalSection, DWORD dwSpinCount); - __declspec(dllimport) BOOL __stdcall TryEnterCriticalSection (CRITICAL_SECTION *lpCriticalSection); - __declspec(dllimport) VOID __stdcall DeleteCriticalSection (CRITICAL_SECTION *lpCriticalSection); - - __declspec(dllimport) DWORD __stdcall WaitForSingleObject (HANDLE hHandle, DWORD dwMilliseconds); - __declspec(dllimport) BOOL __stdcall ReleaseSemaphore (HANDLE hSemaphore, LONG lReleaseCount, LONG *lpPreviousCount); - __declspec(dllimport) VOID __stdcall Sleep (DWORD dwMilliseconds); - } - - // NOTE: um/profileapi.h /////////////////////////////////////////////////////////////////////// - extern "C" - { - __declspec(dllimport) BOOL __stdcall QueryPerformanceCounter (LARGE_INTEGER* lpPerformanceCount); - __declspec(dllimport) BOOL __stdcall QueryPerformanceFrequency(LARGE_INTEGER* lpFrequency); - } - - // NOTE: um/processthreadsapi.h //////////////////////////////////////////////////////////////// - typedef struct _PROCESS_INFORMATION { - HANDLE hProcess; - HANDLE hThread; - DWORD dwProcessId; - DWORD dwThreadId; - } PROCESS_INFORMATION, *PPROCESS_INFORMATION, *LPPROCESS_INFORMATION; - - typedef struct _STARTUPINFOW { - DWORD cb; - WCHAR *lpReserved; - WCHAR *lpDesktop; - WCHAR *lpTitle; - DWORD dwX; - DWORD dwY; - DWORD dwXSize; - DWORD dwYSize; - DWORD dwXCountChars; - DWORD dwYCountChars; - DWORD dwFillAttribute; - DWORD dwFlags; - WORD wShowWindow; - WORD cbReserved2; - BYTE *lpReserved2; - HANDLE hStdInput; - HANDLE hStdOutput; - HANDLE hStdError; - } STARTUPINFOW, *LPSTARTUPINFOW; - - typedef DWORD (__stdcall *PTHREAD_START_ROUTINE)( - VOID *lpThreadParameter - ); - typedef PTHREAD_START_ROUTINE LPTHREAD_START_ROUTINE; - - extern "C" - { - __declspec(dllimport) BOOL __stdcall CreateProcessW (WCHAR const *lpApplicationName, WCHAR *lpCommandLine, SECURITY_ATTRIBUTES *lpProcessAttributes, SECURITY_ATTRIBUTES *lpThreadAttributes, BOOL bInheritHandles, DWORD dwCreationFlags, VOID *lpEnvironment, WCHAR const *lpCurrentDirectory, STARTUPINFOW *lpStartupInfo, PROCESS_INFORMATION *lpProcessInformation); - __declspec(dllimport) HANDLE __stdcall CreateThread (SECURITY_ATTRIBUTES *lpThreadAttributes, SIZE_T dwStackSize, PTHREAD_START_ROUTINE lpStartAddress, VOID *lpParameter, DWORD dwCreationFlags, DWORD *lpThreadId); - __declspec(dllimport) DWORD __stdcall GetCurrentThreadId(VOID); - __declspec(dllimport) BOOL __stdcall GetExitCodeProcess(HANDLE hProcess, DWORD *lpExitCode); - __declspec(dllimport) void __stdcall ExitProcess (UINT uExitCode); - } - - // NOTE: um/memoryapi.h //////////////////////////////////////////////////////////////////////// - extern "C" - { - __declspec(dllimport) VOID * __stdcall VirtualAlloc (VOID *lpAddress, SIZE_T dwSize, DWORD flAllocationType, DWORD flProtect); - __declspec(dllimport) BOOL __stdcall VirtualProtect(VOID *lpAddress, SIZE_T dwSize, DWORD flNewProtect, DWORD *lpflOldProtect); - __declspec(dllimport) BOOL __stdcall VirtualFree (VOID *lpAddress, SIZE_T dwSize, DWORD dwFreeType); - } - - // NOTE: shared/bcrypt.h /////////////////////////////////////////////////////////////////////// - typedef VOID *BCRYPT_ALG_HANDLE; - typedef LONG NTSTATUS; - - extern "C" - { - __declspec(dllimport) NTSTATUS __stdcall BCryptOpenAlgorithmProvider(BCRYPT_ALG_HANDLE *phAlgorithm, const WCHAR *pszAlgId, const WCHAR *pszImplementation, ULONG dwFlags); - __declspec(dllimport) NTSTATUS __stdcall BCryptGenRandom (BCRYPT_ALG_HANDLE hAlgorithm, UCHAR *pbBuffer, ULONG cbBuffer, ULONG dwFlags); - } - - // NOTE: um/shellapi.h ///////////////////////////////////////////////////////////////////////// - extern "C" - { - __declspec(dllimport) HINSTANCE __stdcall ShellExecuteA(HWND hwnd, CHAR const *lpOperation, CHAR const *lpFile, CHAR const *lpParameters, CHAR const *lpDirectory, INT nShowCmd); - __declspec(dllimport) HINSTANCE __stdcall ShellExecuteW(HWND hwnd, WCHAR const *lpOperation, WCHAR const *lpFile, WCHAR const *lpParameters, WCHAR const *lpDirectory, INT nShowCmd); - } - - // NOTE: um/debugapi.h ///////////////////////////////////////////////////////////////////////// - extern "C" - { - __declspec(dllimport) BOOL __stdcall IsDebuggerPresent(); - } - - // NOTE: um/namedpipeapi.h ///////////////////////////////////////////////////////////////////// - extern "C" - { - __declspec(dllimport) BOOL __stdcall CreatePipe (HANDLE *hReadPipe, HANDLE *hWritePipe, LPSECURITY_ATTRIBUTES lpPipeAttributes, DWORD nSize); - __declspec(dllimport) BOOL __stdcall PeekNamedPipe(HANDLE hNamedPipe, VOID *lpBuffer, DWORD nBufferSize, DWORD *lpBytesRead, DWORD *lpTotalBytesAvail, DWORD *lpBytesLeftThisMessage); - } - - // NOTE: um/handleapi.h //////////////////////////////////////////////////////////////////////// - extern "C" - { - __declspec(dllimport) BOOL __stdcall SetHandleInformation(HANDLE hObject, DWORD dwMask, DWORD dwFlags); - } - - // NOTE: um/commdlg.h ////////////////////////////////////////////////////////////////////////// - typedef UINT_PTR (__stdcall *LPOFNHOOKPROC)(HWND, UINT, WPARAM, LPARAM); - typedef struct tagOFNW { - DWORD lStructSize; - HWND hwndOwner; - HINSTANCE hInstance; - WCHAR const * lpstrFilter; - LPWSTR lpstrCustomFilter; - DWORD nMaxCustFilter; - DWORD nFilterIndex; - LPWSTR lpstrFile; - DWORD nMaxFile; - LPWSTR lpstrFileTitle; - DWORD nMaxFileTitle; - WCHAR const * lpstrInitialDir; - WCHAR const * lpstrTitle; - DWORD Flags; - WORD nFileOffset; - WORD nFileExtension; - WCHAR const * lpstrDefExt; - LPARAM lCustData; - LPOFNHOOKPROC lpfnHook; - WCHAR const * lpTemplateName; - #ifdef _MAC - LPEDITMENU lpEditInfo; - LPCSTR lpstrPrompt; - #endif - #if (_WIN32_WINNT >= 0x0500) - void * pvReserved; - DWORD dwReserved; - DWORD FlagsEx; - #endif // (_WIN32_WINNT >= 0x0500) - } OPENFILENAMEW, *LPOPENFILENAMEW; - - - #define OFN_READONLY 0x00000001 - #define OFN_OVERWRITEPROMPT 0x00000002 - #define OFN_HIDEREADONLY 0x00000004 - #define OFN_NOCHANGEDIR 0x00000008 - #define OFN_SHOWHELP 0x00000010 - #define OFN_ENABLEHOOK 0x00000020 - #define OFN_ENABLETEMPLATE 0x00000040 - #define OFN_ENABLETEMPLATEHANDLE 0x00000080 - #define OFN_NOVALIDATE 0x00000100 - #define OFN_ALLOWMULTISELECT 0x00000200 - #define OFN_EXTENSIONDIFFERENT 0x00000400 - #define OFN_PATHMUSTEXIST 0x00000800 - #define OFN_FILEMUSTEXIST 0x00001000 - #define OFN_CREATEPROMPT 0x00002000 - #define OFN_SHAREAWARE 0x00004000 - #define OFN_NOREADONLYRETURN 0x00008000 - #define OFN_NOTESTFILECREATE 0x00010000 - #define OFN_NONETWORKBUTTON 0x00020000 - #define OFN_NOLONGNAMES 0x00040000 // force no long names for 4.x modules - #if(WINVER >= 0x0400) - #define OFN_EXPLORER 0x00080000 // new look commdlg - #define OFN_NODEREFERENCELINKS 0x00100000 - #define OFN_LONGNAMES 0x00200000 // force long names for 3.x modules - // OFN_ENABLEINCLUDENOTIFY and OFN_ENABLESIZING require - // Windows 2000 or higher to have any effect. - #define OFN_ENABLEINCLUDENOTIFY 0x00400000 // send include message to callback - #define OFN_ENABLESIZING 0x00800000 - #endif /* WINVER >= 0x0400 */ - #if (_WIN32_WINNT >= 0x0500) - #define OFN_DONTADDTORECENT 0x02000000 - #define OFN_FORCESHOWHIDDEN 0x10000000 // Show All files including System and hidden files - #endif // (_WIN32_WINNT >= 0x0500) - - //FlagsEx Values - #if (_WIN32_WINNT >= 0x0500) - #define OFN_EX_NOPLACESBAR 0x00000001 - #endif // (_WIN32_WINNT >= 0x0500) - - extern "C" - { - __declspec(dllimport) BOOL __stdcall GetSaveFileNameW(LPOPENFILENAMEW); - __declspec(dllimport) BOOL __stdcall GetOpenFileNameW(LPOPENFILENAMEW); - } - - // NOTE: um/shlwapi.h ////////////////////////////////////////////////////////////////////////// - extern "C" - { - __declspec(dllimport) BOOL __stdcall PathRelativePathToW(WCHAR *pszPath, WCHAR const *pszFrom, DWORD dwAttrFrom, WCHAR const *pszTo, DWORD dwAttrTo); - __declspec(dllimport) BOOL __stdcall PathIsRelativeW(WCHAR *pszPath); - } - - // NOTE: um/pathcch.h ////////////////////////////////////////////////////////////////////////// - typedef enum PATHCCH_OPTIONS - { - PATHCCH_NONE = 0x0, - - // This option allows applications to gain access to long paths. It has two - // different behaviors. For process configured to enable long paths it will allow - // the returned path to be longer than the max path limit that is normally imposed. - // For process that are not this option will convert long paths into the extended - // length DOS device form (with \\?\ prefix) when the path is longer than the limit. - // This form is not length limited by the Win32 file system API on all versions of Windows. - // This second behavior is the same behavior for OSes that don't have the long path feature. - // This can not be specified with PATHCCH_ENSURE_IS_EXTENDED_LENGTH_PATH. - PATHCCH_ALLOW_LONG_PATHS = 0x01, - - // Can only be used when PATHCCH_ALLOW_LONG_PATHS is specified. This - // Forces the API to treat the caller as long path enabled, independent of the - // process's long name enabled state. Cannot be used with PATHCCH_FORCE_DISABLE_LONG_NAME_PROCESS. - PATHCCH_FORCE_ENABLE_LONG_NAME_PROCESS = 0x02, - - // Can only be used when PATHCCH_ALLOW_LONG_PATHS is specified. This - // Forces the API to treat the caller as long path disabled, independent of the - // process's long name enabled state. Cannot be used with PATHCCH_FORCE_ENABLE_LONG_NAME_PROCESS. - PATHCCH_FORCE_DISABLE_LONG_NAME_PROCESS = 0x04, - - // Disable the normalization of path segments that includes removing trailing dots and spaces. - // This enables access to paths that win32 path normalization will block. - PATHCCH_DO_NOT_NORMALIZE_SEGMENTS = 0x08, - - // Convert the input path into the extended length DOS device path form (with the \\?\ prefix) - // if not already in that form. This enables access to paths that are otherwise not addressable - // due to Win32 normalization rules (that can strip trailing dots and spaces) and path - // length limitations. This option implies the same behavior of PATHCCH_DO_NOT_NORMALIZE_SEGMENTS. - // This can not be specified with PATHCCH_ALLOW_LONG_PATHS. - PATHCCH_ENSURE_IS_EXTENDED_LENGTH_PATH = 0x10, - - // When combining or normalizing a path ensure there is a trailing backslash. - PATHCCH_ENSURE_TRAILING_SLASH = 0x020, - - // Convert forward slashes to back slashes and collapse multiple slashes. - // This is needed to to support sub-path or identity comparisons. - PATHCCH_CANONICALIZE_SLASHES = 0x040, - } PATHCCH_OPTIONS; - - extern "C" - { - __declspec(dllimport) HRESULT __stdcall PathCchCanonicalizeEx(PWSTR pszPathOut, size_t cchPathOut, WCHAR const *pszPathIn, ULONG dwFlags); - }; - - // NOTE: um/errhandlingapi.h /////////////////////////////////////////////////////////////////// - extern "C" - { - __declspec(dllimport) VOID __stdcall RaiseException(DWORD dwExceptionCode, DWORD dwExceptionFlags, DWORD nNumberOfArguments, const ULONG_PTR* lpArguments); - }; - - // NOTE: include/excpt.h /////////////////////////////////////////////////////////////////// - #define EXCEPTION_EXECUTE_HANDLER 1 - #define EXCEPTION_CONTINUE_SEARCH 0 - #define EXCEPTION_CONTINUE_EXECUTION (-1) - - DN_MSVC_WARNING_POP -#endif // !defined(_INC_WINDOWS) -#endif // !defined(DN_OS_WINDOWS_H) - // DN: Single header generator commented out this header => #include "OS/dn_os_w32.h" -#if !defined(DN_OS_WIN32_H) -#define DN_OS_WIN32_H - -#if defined(_CLANGD) - // DN: Single header generator commented out this header => #include "../dn_base_inc.h" - // DN: Single header generator commented out this header => #include "dn_os_windows.h" -#if !defined(DN_OS_WINDOWS_H) -#define DN_OS_WINDOWS_H - -#if defined(_CLANGD) - // DN: Single header generator commented out this header => #include "../dn_base_inc.h" -#endif - -#if defined(DN_COMPILER_MSVC) || defined(DN_COMPILER_CLANG_CL) - #pragma comment(lib, "bcrypt") - #pragma comment(lib, "winhttp") - #pragma comment(lib, "dbghelp") - #pragma comment(lib, "comdlg32") - #pragma comment(lib, "pathcch") - #pragma comment(lib, "Shell32") // ShellExecuteW - #pragma comment(lib, "shlwapi") -#endif - -#if defined(DN_NO_WINDOWS_H_REPLACEMENT_HEADER) || defined(_INC_WINDOWS) - #define WIN32_LEAN_AND_MEAN - #include // LONG - #include // DN_OS_SecureRNGBytes -> BCryptOpenAlgorithmProvider ... etc - #include // DN_Win_MakeProcessDPIAware -> SetProcessDpiAwareProc - #include // PathRelativePathTO - #include // PathCchCanonicalizeEx - #include // WinHttp* - #include // PROCESS_MEMORY_COUNTERS_EX2 - #include // OPENFILENAMEW - #include -#else - DN_MSVC_WARNING_PUSH - DN_MSVC_WARNING_DISABLE(4201) // warning C4201: nonstandard extension used: nameless struct/union - - // NOTE: basetsd.h ///////////////////////////////////////////////////////////////////////////// - typedef unsigned __int64 ULONG_PTR, *PULONG_PTR; - typedef unsigned __int64 UINT_PTR, *PUINT_PTR; - typedef ULONG_PTR SIZE_T, *PSIZE_T; - typedef __int64 LONG_PTR, *PLONG_PTR; - typedef ULONG_PTR DWORD_PTR, *PDWORD_PTR; - typedef unsigned __int64 ULONG64, *PULONG64; - typedef unsigned __int64 DWORD64, *PDWORD64; - - // NOTE: shared/minwindef.h //////////////////////////////////////////////////////////////////// - struct HINSTANCE__ { - int unused; - }; - typedef struct HINSTANCE__ *HINSTANCE; - - typedef unsigned long DWORD; - typedef int BOOL; - typedef int INT; - typedef unsigned long ULONG; - typedef unsigned int UINT; - typedef unsigned short WORD; - typedef unsigned char BYTE; - typedef unsigned char UCHAR; - typedef HINSTANCE HMODULE; /* HMODULEs can be used in place of HINSTANCEs */ - typedef void * HANDLE; - typedef HANDLE HLOCAL; - - typedef unsigned __int64 WPARAM; - typedef LONG_PTR LPARAM; - typedef LONG_PTR LRESULT; - - #define MAX_PATH 260 - - typedef struct _FILETIME { - DWORD dwLowDateTime; - DWORD dwHighDateTime; - } FILETIME, *PFILETIME, *LPFILETIME; - - // NOTE: shared/winerror.h ///////////////////////////////////////////////////////////////////// - // NOTE: GetModuleFileNameW - #define ERROR_INSUFFICIENT_BUFFER 122L // dderror - - // NOTE: um/winnls.h /////////////////////////////////////////////////////////////////////////// - // NOTE: MultiByteToWideChar - #define CP_UTF8 65001 // UTF-8 translation - - // NOTE: um/winnt.h //////////////////////////////////////////////////////////////////////////// - typedef void VOID; - typedef __int64 LONGLONG; - typedef unsigned __int64 ULONGLONG; - typedef void * HANDLE; - typedef char CHAR; - typedef short SHORT; - typedef long LONG; - typedef wchar_t WCHAR; // wc, 16-bit UNICODE character - typedef CHAR * NPSTR, *LPSTR, *PSTR; - typedef WCHAR * NWPSTR, *LPWSTR, *PWSTR; - typedef long HRESULT; - - // NOTE: VirtualAlloc: Allocation Type - #define MEM_RESERVE 0x00002000 - #define MEM_COMMIT 0x00001000 - #define MEM_DECOMMIT 0x00004000 - #define MEM_RELEASE 0x00008000 - - // NOTE: VirtualAlloc: Page Permissions - #define PAGE_NOACCESS 0x01 - #define PAGE_READONLY 0x02 - #define PAGE_READWRITE 0x04 - #define PAGE_GUARD 0x100 - - // NOTE: HeapAlloc - #define HEAP_ZERO_MEMORY 0x00000008 - #define HEAP_NO_SERIALIZE 0x00000001 - #define HEAP_GROWABLE 0x00000002 - #define HEAP_GENERATE_EXCEPTIONS 0x00000004 - #define HEAP_ZERO_MEMORY 0x00000008 - #define HEAP_REALLOC_IN_PLACE_ONLY 0x00000010 - #define HEAP_TAIL_CHECKING_ENABLED 0x00000020 - #define HEAP_FREE_CHECKING_ENABLED 0x00000040 - #define HEAP_DISABLE_COALESCE_ON_FREE 0x00000080 - #define HEAP_CREATE_ALIGN_16 0x00010000 - #define HEAP_CREATE_ENABLE_TRACING 0x00020000 - #define HEAP_CREATE_ENABLE_EXECUTE 0x00040000 - #define HEAP_MAXIMUM_TAG 0x0FFF - #define HEAP_PSEUDO_TAG_FLAG 0x8000 - #define HEAP_TAG_SHIFT 18 - #define HEAP_CREATE_SEGMENT_HEAP 0x00000100 - #define HEAP_CREATE_HARDENED 0x00000200 - - // NOTE: FormatMessageA - #define MAKELANGID(p, s) ((((WORD )(s)) << 10) | (WORD )(p)) - #define LANG_NEUTRAL 0x00 - #define SUBLANG_DEFAULT 0x01 // user default - - // NOTE: CreateFile - #define GENERIC_READ (0x80000000L) - #define GENERIC_WRITE (0x40000000L) - #define GENERIC_EXECUTE (0x20000000L) - #define GENERIC_ALL (0x10000000L) - - #define FILE_APPEND_DATA (0x0004) // file - - // NOTE: CreateFile/FindFirstFile - #define FILE_SHARE_READ 0x00000001 - #define FILE_SHARE_WRITE 0x00000002 - #define FILE_SHARE_DELETE 0x00000004 - - #define FILE_ATTRIBUTE_READONLY 0x00000001 - #define FILE_ATTRIBUTE_HIDDEN 0x00000002 - #define FILE_ATTRIBUTE_SYSTEM 0x00000004 - #define FILE_ATTRIBUTE_DIRECTORY 0x00000010 - #define FILE_ATTRIBUTE_NORMAL 0x00000080 - - // NOTE: STACKFRAME64 - #define IMAGE_FILE_MACHINE_AMD64 0x8664 // AMD64 (K8) - - // NOTE: WaitForSingleObject - #define WAIT_TIMEOUT 258L // dderror - #define STATUS_WAIT_0 ((DWORD )0x00000000L) - #define STATUS_ABANDONED_WAIT_0 ((DWORD )0x00000080L) - - #define S_OK ((HRESULT)0L) - #define S_FALSE ((HRESULT)1L) - - typedef union _ULARGE_INTEGER { - struct { - DWORD LowPart; - DWORD HighPart; - } DUMMYSTRUCTNAME; - struct { - DWORD LowPart; - DWORD HighPart; - } u; - ULONGLONG QuadPart; - } ULARGE_INTEGER; - - typedef union _LARGE_INTEGER { - struct { - DWORD LowPart; - LONG HighPart; - } DUMMYSTRUCTNAME; - struct { - DWORD LowPart; - LONG HighPart; - } u; - LONGLONG QuadPart; - } LARGE_INTEGER; - - typedef struct __declspec(align(16)) _M128A { - ULONGLONG Low; - LONGLONG High; - } M128A, *PM128A; - - typedef struct __declspec(align(16)) _XSAVE_FORMAT { - WORD ControlWord; - WORD StatusWord; - BYTE TagWord; - BYTE Reserved1; - WORD ErrorOpcode; - DWORD ErrorOffset; - WORD ErrorSelector; - WORD Reserved2; - DWORD DataOffset; - WORD DataSelector; - WORD Reserved3; - DWORD MxCsr; - DWORD MxCsr_Mask; - M128A FloatRegisters[8]; - #if defined(_WIN64) - M128A XmmRegisters[16]; - BYTE Reserved4[96]; - #else - M128A XmmRegisters[8]; - BYTE Reserved4[224]; - #endif - } XSAVE_FORMAT, *PXSAVE_FORMAT; - typedef XSAVE_FORMAT XMM_SAVE_AREA32, *PXMM_SAVE_AREA32; - - typedef struct __declspec(align(16)) _CONTEXT { - DWORD64 P1Home; - DWORD64 P2Home; - DWORD64 P3Home; - DWORD64 P4Home; - DWORD64 P5Home; - DWORD64 P6Home; - DWORD ContextFlags; - DWORD MxCsr; - WORD SegCs; - WORD SegDs; - WORD SegEs; - WORD SegFs; - WORD SegGs; - WORD SegSs; - DWORD EFlags; - DWORD64 Dr0; - DWORD64 Dr1; - DWORD64 Dr2; - DWORD64 Dr3; - DWORD64 Dr6; - DWORD64 Dr7; - DWORD64 Rax; - DWORD64 Rcx; - DWORD64 Rdx; - DWORD64 Rbx; - DWORD64 Rsp; - DWORD64 Rbp; - DWORD64 Rsi; - DWORD64 Rdi; - DWORD64 R8; - DWORD64 R9; - DWORD64 R10; - DWORD64 R11; - DWORD64 R12; - DWORD64 R13; - DWORD64 R14; - DWORD64 R15; - DWORD64 Rip; - - union { - XMM_SAVE_AREA32 FltSave; - - struct { - M128A Header[2]; - M128A Legacy[8]; - M128A Xmm0; - M128A Xmm1; - M128A Xmm2; - M128A Xmm3; - M128A Xmm4; - M128A Xmm5; - M128A Xmm6; - M128A Xmm7; - M128A Xmm8; - M128A Xmm9; - M128A Xmm10; - M128A Xmm11; - M128A Xmm12; - M128A Xmm13; - M128A Xmm14; - M128A Xmm15; - } DUMMYSTRUCTNAME; - } DUMMYUNIONNAME; - - M128A VectorRegister[26]; - DWORD64 VectorControl; - DWORD64 DebugControl; - DWORD64 LastBranchToRip; - DWORD64 LastBranchFromRip; - DWORD64 LastExceptionToRip; - DWORD64 LastExceptionFromRip; - } CONTEXT; - - typedef struct _LIST_ENTRY { - struct _LIST_ENTRY *Flink; - struct _LIST_ENTRY *Blink; - } LIST_ENTRY, *PLIST_ENTRY, PRLIST_ENTRY; - - typedef struct _RTL_CRITICAL_SECTION_DEBUG { - WORD Type; - WORD CreatorBackTraceIndex; - struct _RTL_CRITICAL_SECTION *CriticalSection; - LIST_ENTRY ProcessLocksList; - DWORD EntryCount; - DWORD ContentionCount; - DWORD Flags; - WORD CreatorBackTraceIndexHigh; - WORD Identifier; - } RTL_CRITICAL_SECTION_DEBUG, *PRTL_CRITICAL_SECTION_DEBUG, RTL_RESOURCE_DEBUG, *PRTL_RESOURCE_DEBUG; - - typedef struct _RTL_CONDITION_VARIABLE { - VOID *Ptr; - } RTL_CONDITION_VARIABLE, *PRTL_CONDITION_VARIABLE; - - #pragma pack(push, 8) - typedef struct _RTL_CRITICAL_SECTION { - PRTL_CRITICAL_SECTION_DEBUG DebugInfo; - - // - // The following three fields control entering and exiting the critical - // section for the resource - // - - LONG LockCount; - LONG RecursionCount; - HANDLE OwningThread; // from the thread's ClientId->UniqueThread - HANDLE LockSemaphore; - ULONG_PTR SpinCount; // force size on 64-bit systems when packed - } RTL_CRITICAL_SECTION, *PRTL_CRITICAL_SECTION; - #pragma pack(pop) - - typedef struct _MODLOAD_DATA { - DWORD ssize; // size of this struct - DWORD ssig; // signature identifying the passed data - VOID *data; // pointer to passed data - DWORD size; // size of passed data - DWORD flags; // options - } MODLOAD_DATA, *PMODLOAD_DATA; - - #define SLMFLAG_VIRTUAL 0x1 - #define SLMFLAG_ALT_INDEX 0x2 - #define SLMFLAG_NO_SYMBOLS 0x4 - - extern "C" - { - __declspec(dllimport) VOID __stdcall RtlCaptureContext(CONTEXT *ContextRecord); - __declspec(dllimport) HANDLE __stdcall GetCurrentProcess(void); - __declspec(dllimport) HANDLE __stdcall GetCurrentThread(void); - __declspec(dllimport) DWORD __stdcall SymSetOptions(DWORD SymOptions); - __declspec(dllimport) BOOL __stdcall SymInitialize(HANDLE hProcess, const CHAR* UserSearchPath, BOOL fInvadeProcess); - __declspec(dllimport) DWORD64 __stdcall SymLoadModuleEx(HANDLE hProcess, HANDLE hFile, CHAR const *ImageName, CHAR const *ModuleName, DWORD64 BaseOfDll, DWORD DllSize, MODLOAD_DATA *Data, DWORD Flags); - __declspec(dllimport) BOOL __stdcall SymUnloadModule64(HANDLE hProcess, DWORD64 BaseOfDll); - } - - // NOTE: um/heapapi.h //////////////////////////////////////////////////////////////////// - extern "C" - { - __declspec(dllimport) HANDLE __stdcall HeapCreate(DWORD flOptions, SIZE_T dwInitialSize, SIZE_T dwMaximumSize); - __declspec(dllimport) BOOL __stdcall HeapDestroy(HANDLE hHeap); - __declspec(dllimport) VOID * __stdcall HeapAlloc(HANDLE hHeap, DWORD dwFlags,SIZE_T dwBytes); - __declspec(dllimport) VOID * __stdcall HeapReAlloc(HANDLE hHeap, DWORD dwFlags, VOID *lpMem, SIZE_T dwBytes); - __declspec(dllimport) BOOL __stdcall HeapFree(HANDLE hHeap, DWORD dwFlags, VOID *lpMem); - __declspec(dllimport) SIZE_T __stdcall HeapSize(HANDLE hHeap, DWORD dwFlags, VOID const *lpMem); - __declspec(dllimport) HANDLE __stdcall GetProcessHeap(VOID); - __declspec(dllimport) SIZE_T __stdcall HeapCompact(HANDLE hHeap, DWORD dwFlags); - } - - // NOTE: shared/windef.h //////////////////////////////////////////////////////////////////// - typedef struct tagPOINT - { - LONG x; - LONG y; - } POINT, *PPOINT, *NPPOINT, *LPPOINT; - - // NOTE: handleapi.h /////////////////////////////////////////////////////////////////////////// - #define INVALID_HANDLE_VALUE ((HANDLE)(LONG_PTR)-1) - - extern "C" - { - __declspec(dllimport) BOOL __stdcall CloseHandle(HANDLE hObject); - } - - // NOTE: consoleapi.h /////////////////////////////////////////////////////////////////////////// - extern "C" - { - __declspec(dllimport) BOOL __stdcall WriteConsoleA(HANDLE hConsoleOutput, const VOID* lpBuffer, DWORD nNumberOfCharsToWrite, DWORD *lpNumberOfCharsWritten, VOID *lpReserved); - __declspec(dllimport) BOOL __stdcall AllocConsole(VOID); - __declspec(dllimport) BOOL __stdcall FreeConsole(VOID); - __declspec(dllimport) BOOL __stdcall AttachConsole(DWORD dwProcessId); - __declspec(dllimport) BOOL __stdcall GetConsoleMode(HANDLE hConsoleHandle, DWORD *lpMode); - } - - // NOTE: um/minwinbase.h /////////////////////////////////////////////////////////////////////// - // NOTE: FindFirstFile - #define FIND_FIRST_EX_CASE_SENSITIVE 0x00000001 - #define FIND_FIRST_EX_LARGE_FETCH 0x00000002 - - // NOTE: WaitFor.. - #define WAIT_FAILED ((DWORD)0xFFFFFFFF) - #define WAIT_OBJECT_0 ((STATUS_WAIT_0 ) + 0 ) - #define WAIT_ABANDONED ((STATUS_ABANDONED_WAIT_0 ) + 0 ) - #define WAIT_ABANDONED_0 ((STATUS_ABANDONED_WAIT_0 ) + 0 ) - - // NOTE: CreateProcessW - #define CREATE_UNICODE_ENVIRONMENT 0x00000400 - #define CREATE_NO_WINDOW 0x08000000 - - typedef enum _GET_FILEEX_INFO_LEVELS { - GetFileExInfoStandard, - GetFileExMaxInfoLevel - } GET_FILEEX_INFO_LEVELS; - - typedef struct _SECURITY_ATTRIBUTES { - DWORD nLength; - VOID *lpSecurityDescriptor; - BOOL bInheritHandle; - } SECURITY_ATTRIBUTES, *PSECURITY_ATTRIBUTES, *LPSECURITY_ATTRIBUTES; - - typedef enum _FINDEX_INFO_LEVELS { - FindExInfoStandard, - FindExInfoBasic, - FindExInfoMaxInfoLevel - } FINDEX_INFO_LEVELS; - - typedef enum _FINDEX_SEARCH_OPS { - FindExSearchNameMatch, - FindExSearchLimitToDirectories, - FindExSearchLimitToDevices, - FindExSearchMaxSearchOp - } FINDEX_SEARCH_OPS; - - typedef struct _WIN32_FIND_DATAW { - DWORD dwFileAttributes; - FILETIME ftCreationTime; - FILETIME ftLastAccessTime; - FILETIME ftLastWriteTime; - DWORD nFileSizeHigh; - DWORD nFileSizeLow; - DWORD dwReserved0; - DWORD dwReserved1; - WCHAR cFileName[ MAX_PATH ]; - WCHAR cAlternateFileName[ 14 ]; - #ifdef _MAC - DWORD dwFileType; - DWORD dwCreatorType; - WORD wFinderFlags; - #endif - } WIN32_FIND_DATAW, *PWIN32_FIND_DATAW, *LPWIN32_FIND_DATAW; - - typedef struct _SYSTEMTIME { - WORD wYear; - WORD wMonth; - WORD wDayOfWeek; - WORD wDay; - WORD wHour; - WORD wMinute; - WORD wSecond; - WORD wMilliseconds; - } SYSTEMTIME, *PSYSTEMTIME, *LPSYSTEMTIME; - - typedef struct _OVERLAPPED { - ULONG_PTR Internal; - ULONG_PTR InternalHigh; - union { - struct { - DWORD Offset; - DWORD OffsetHigh; - } DUMMYSTRUCTNAME; - VOID *Pointer; - } DUMMYUNIONNAME; - - HANDLE hEvent; - } OVERLAPPED, *LPOVERLAPPED; - - typedef RTL_CRITICAL_SECTION CRITICAL_SECTION; - - #define WAIT_FAILED ((DWORD)0xFFFFFFFF) - #define WAIT_OBJECT_0 ((STATUS_WAIT_0 ) + 0 ) - - #define INFINITE 0xFFFFFFFF // Wait/Synchronisation: Infinite timeout - - #define STD_INPUT_HANDLE ((DWORD)-10) - #define STD_OUTPUT_HANDLE ((DWORD)-11) - #define STD_ERROR_HANDLE ((DWORD)-12) - - #define HANDLE_FLAG_INHERIT 0x00000001 - #define HANDLE_FLAG_PROTECT_FROM_CLOSE 0x00000002 - - // NOTE: MoveFile - #define MOVEFILE_REPLACE_EXISTING 0x00000001 - #define MOVEFILE_COPY_ALLOWED 0x00000002 - - // NOTE: FormatMessageA - #define FORMAT_MESSAGE_ALLOCATE_BUFFER 0x00000100 - #define FORMAT_MESSAGE_IGNORE_INSERTS 0x00000200 - #define FORMAT_MESSAGE_FROM_HMODULE 0x00000800 - #define FORMAT_MESSAGE_FROM_SYSTEM 0x00001000 - - // NOTE: CreateProcessW - #define STARTF_USESTDHANDLES 0x00000100 - - extern "C" - { - __declspec(dllimport) BOOL __stdcall MoveFileExW (const WCHAR *lpExistingFileName, const WCHAR *lpNewFileName, DWORD dwFlags); - __declspec(dllimport) BOOL __stdcall CopyFileW (const WCHAR *lpExistingFileName, const WCHAR *lpNewFileName, BOOL bFailIfExists); - __declspec(dllimport) HANDLE __stdcall CreateSemaphoreA(SECURITY_ATTRIBUTES *lpSemaphoreAttributes, LONG lInitialCount, LONG lMaximumCount, const CHAR *lpName); - __declspec(dllimport) DWORD __stdcall FormatMessageW (DWORD dwFlags, VOID const *lpSource, DWORD dwMessageId, DWORD dwLanguageId, LPWSTR lpBuffer, DWORD nSize, va_list *Arguments); - __declspec(dllimport) HLOCAL __stdcall LocalFree (HLOCAL hMem); - } - - // NOTE: um/stringapiset.h ///////////////////////////////////////////////////////////////////// - extern "C" - { - __declspec(dllimport) int __stdcall MultiByteToWideChar(UINT CodePage, DWORD dwFlags, const CHAR *lpMultiByteStr, int cbMultiByte, WCHAR *lpWideCharStr, int cchWideChar); - __declspec(dllimport) int __stdcall WideCharToMultiByte(UINT CodePage, DWORD dwFlags, const WCHAR *lpWideCharStr, int cchWideChar, LPSTR lpMultiByteStr, int cbMultiByte, const CHAR *lpDefaultChar, BOOL *lpUsedDefaultChar); - } - - // NOTE: um/fileapi.h ////////////////////////////////////////////////////////////////////////// - #define INVALID_FILE_SIZE ((DWORD)0xFFFFFFFF) - #define INVALID_FILE_ATTRIBUTES ((DWORD)-1) - - // NOTE: CreateFile - #define CREATE_NEW 1 - #define CREATE_ALWAYS 2 - #define OPEN_EXISTING 3 - #define OPEN_ALWAYS 4 - #define TRUNCATE_EXISTING 5 - - typedef struct _WIN32_FILE_ATTRIBUTE_DATA { - DWORD dwFileAttributes; - FILETIME ftCreationTime; - FILETIME ftLastAccessTime; - FILETIME ftLastWriteTime; - DWORD nFileSizeHigh; - DWORD nFileSizeLow; - } WIN32_FILE_ATTRIBUTE_DATA, *LPWIN32_FILE_ATTRIBUTE_DATA; - - extern "C" - { - __declspec(dllimport) BOOL __stdcall FlushFileBuffers (HANDLE hFile); - __declspec(dllimport) BOOL __stdcall CreateDirectoryW (const WCHAR *lpPathName, SECURITY_ATTRIBUTES *lpSecurityAttributes); - __declspec(dllimport) BOOL __stdcall RemoveDirectoryW (const WCHAR *lpPathName); - __declspec(dllimport) BOOL __stdcall FindNextFileW (HANDLE hFindFile, WIN32_FIND_DATAW *lpFindFileData); - __declspec(dllimport) BOOL __stdcall FindClose (HANDLE hFindFile); - __declspec(dllimport) BOOL __stdcall FileTimeToLocalFileTime(const FILETIME *lpFileTime, FILETIME *lpLocalFileTime); - - __declspec(dllimport) HANDLE __stdcall FindFirstFileExW (const WCHAR *lpFileName, FINDEX_INFO_LEVELS fInfoLevelId, VOID *lpFindFileData, FINDEX_SEARCH_OPS fSearchOp, VOID *lpSearchFilter, DWORD dwAdditionalFlags); - __declspec(dllimport) BOOL __stdcall GetFileAttributesExW (const WCHAR *lpFileName, GET_FILEEX_INFO_LEVELS fInfoLevelId, VOID *lpFileInformation); - __declspec(dllimport) BOOL __stdcall GetFileSizeEx (HANDLE hFile, LARGE_INTEGER *lpFileSize); - __declspec(dllimport) BOOL __stdcall DeleteFileW (const WCHAR *lpFileName); - __declspec(dllimport) HANDLE __stdcall CreateFileW (const WCHAR *lpFileName, DWORD dwDesiredAccess, DWORD dwShareMode, SECURITY_ATTRIBUTES *lpSecurityAttributes, DWORD dwCreationDisposition, DWORD dwFlagsAndAttributes, HANDLE hTemplateFile); - __declspec(dllimport) BOOL __stdcall ReadFile (HANDLE hFile, VOID *lpBuffer, DWORD nNumberOfBytesToRead, DWORD *lpNumberOfBytesRead, OVERLAPPED *lpOverlapped); - __declspec(dllimport) BOOL __stdcall WriteFile (HANDLE hFile, const VOID *lpBuffer, DWORD nNumberOfBytesToWrite, DWORD *lpNumberOfBytesWritten, OVERLAPPED *lpOverlapped); - __declspec(dllimport) BOOL __stdcall GetDiskFreeSpaceExW (WCHAR const *lpDirectoryName, ULARGE_INTEGER *lpFreeBytesAvailableToCaller, ULARGE_INTEGER *lpTotalNumberOfBytes, ULARGE_INTEGER *lpTotalNumberOfFreeBytes); - } - - // NOTE: um/processenv.h /////////////////////////////////////////////////////////////////////// - extern "C" - { - __declspec(dllimport) DWORD __stdcall GetCurrentDirectoryW (DWORD nBufferLength, WCHAR *lpBuffer); - __declspec(dllimport) HANDLE __stdcall GetStdHandle (DWORD nStdHandle); - __declspec(dllimport) WCHAR* __stdcall GetEnvironmentStringsW (); - __declspec(dllimport) BOOL __stdcall FreeEnvironmentStringsW(WCHAR *penv); - __declspec(dllimport) DWORD __stdcall GetEnvironmentVariableW(WCHAR const *lpName, WCHAR *lpBuffer, DWORD nSize); - __declspec(dllimport) BOOL __stdcall SetEnvironmentVariableW(WCHAR const *lpName, WCHAR const *lpValue); - } - - // NOTE: um/psapi.h //////////////////////////////////////////////////////////////////////////// - typedef struct _PROCESS_MEMORY_COUNTERS { - 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; - } PROCESS_MEMORY_COUNTERS; - typedef PROCESS_MEMORY_COUNTERS *PPROCESS_MEMORY_COUNTERS; - - extern "C" - { - __declspec(dllimport) BOOL __stdcall GetProcessMemoryInfo(HANDLE Process, PPROCESS_MEMORY_COUNTERS ppsmemCounters, DWORD cb); - } - - // NOTE: um/sysinfoapi.h /////////////////////////////////////////////////////////////////////// - typedef struct _SYSTEM_INFO { - union { - DWORD dwOemId; // Obsolete field...do not use - struct { - WORD wProcessorArchitecture; - WORD wReserved; - } DUMMYSTRUCTNAME; - } DUMMYUNIONNAME; - DWORD dwPageSize; - VOID *lpMinimumApplicationAddress; - VOID *lpMaximumApplicationAddress; - DWORD_PTR dwActiveProcessorMask; - DWORD dwNumberOfProcessors; - DWORD dwProcessorType; - DWORD dwAllocationGranularity; - WORD wProcessorLevel; - WORD wProcessorRevision; - } SYSTEM_INFO, *LPSYSTEM_INFO; - - extern "C" - { - __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); - } - - // NOTE: um/timezoneapi.h ////////////////////////////////////////////////////////////////////// - typedef struct _TIME_ZONE_INFORMATION { - LONG Bias; - WCHAR StandardName[32]; - SYSTEMTIME StandardDate; - LONG StandardBias; - WCHAR DaylightName[32]; - SYSTEMTIME DaylightDate; - LONG DaylightBias; - } TIME_ZONE_INFORMATION, *PTIME_ZONE_INFORMATION, *LPTIME_ZONE_INFORMATION; - - extern "C" - { - __declspec(dllimport) BOOL __stdcall FileTimeToSystemTime (const FILETIME* lpFileTime, SYSTEMTIME *lpSystemTime); - __declspec(dllimport) BOOL __stdcall SystemTimeToFileTime (const SYSTEMTIME* lpSystemTime, FILETIME *lpFileTime); - __declspec(dllimport) BOOL __stdcall TzSpecificLocalTimeToSystemTime(const TIME_ZONE_INFORMATION* lpTimeZoneInformation, const SYSTEMTIME* lpLocalTime, const LPSYSTEMTIME lpUniversalTime); - } - - // NOTE: shared/windef.h /////////////////////////////////////////////////////////////////////// - typedef struct tagRECT { - LONG left; - LONG top; - LONG right; - LONG bottom; - } RECT; - - struct HWND__ { - int unused; - }; - typedef struct HWND__ *HWND; - - struct DPI_AWARENESS_CONTEXT__ { - int unused; - }; - typedef struct DPI_AWARENESS_CONTEXT__ *DPI_AWARENESS_CONTEXT; - - typedef enum DPI_AWARENESS { - DPI_AWARENESS_INVALID = -1, - DPI_AWARENESS_UNAWARE = 0, - DPI_AWARENESS_SYSTEM_AWARE = 1, - DPI_AWARENESS_PER_MONITOR_AWARE = 2 - } DPI_AWARENESS; - - #define DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2 ((DPI_AWARENESS_CONTEXT)-4) - - // NOTE: um/winuser.h ////////////////////////////////////////////////////////////////////////// - typedef struct tagWINDOWPLACEMENT { - UINT length; - UINT flags; - UINT showCmd; - POINT ptMinPosition; - POINT ptMaxPosition; - RECT rcNormalPosition; - #ifdef _MAC - RECT rcDevice; - #endif - } WINDOWPLACEMENT; - typedef WINDOWPLACEMENT *PWINDOWPLACEMENT, *LPWINDOWPLACEMENT; - - #define SW_HIDE 0 - #define SW_NORMAL 1 - #define SW_MAXIMIZE 3 - #define SW_SHOWNOACTIVATE 4 - #define SW_SHOW 5 - #define SW_FORCEMINIMIZE 11 - - extern "C" - { - __declspec(dllimport) BOOL __stdcall GetWindowRect (HWND hWnd, RECT *lpRect); - __declspec(dllimport) BOOL __stdcall SetWindowPos (HWND hWnd, HWND hWndInsertAfter, int X, int Y, int cx, int cy, UINT uFlags); - __declspec(dllimport) UINT __stdcall GetWindowModuleFileNameA(HWND hwnd, LPSTR pszFileName, UINT cchFileNameMax); - __declspec(dllimport) BOOL __stdcall ShowWindow (HWND hWnd, int nCmdShow); - __declspec(dllimport) BOOL __stdcall GetWindowPlacement (HWND hWnd, WINDOWPLACEMENT *lpwndpl); - - } - - // NOTE: um/wininet.h ////////////////////////////////////////////////////////////////////////// - typedef WORD INTERNET_PORT; - typedef VOID *HINTERNET; - - // NOTE: um/winhttp.h ////////////////////////////////////////////////////////////////////////// - #define WINHTTP_ACCESS_TYPE_DEFAULT_PROXY 0 - #define WINHTTP_ACCESS_TYPE_NO_PROXY 1 - #define WINHTTP_ACCESS_TYPE_NAMED_PROXY 3 - #define WINHTTP_ACCESS_TYPE_AUTOMATIC_PROXY 4 - - #define INTERNET_DEFAULT_PORT 0 // use the protocol-specific default - #define INTERNET_DEFAULT_HTTP_PORT 80 // " " HTTP " - #define INTERNET_DEFAULT_HTTPS_PORT 443 // " " HTTPS " - - // NOTE: WinHttpOpen - #define WINHTTP_FLAG_ASYNC 0x10000000 // this session is asynchronous (where supported) - #define WINHTTP_FLAG_SECURE_DEFAULTS 0x30000000 // note that this flag also forces async - - // NOTE: WinHttpOpenRequest - #define WINHTTP_FLAG_SECURE 0x00800000 // use SSL if applicable (HTTPS) - #define WINHTTP_FLAG_ESCAPE_PERCENT 0x00000004 // if escaping enabled, escape percent as well - #define WINHTTP_FLAG_NULL_CODEPAGE 0x00000008 // assume all symbols are ASCII, use fast convertion - #define WINHTTP_FLAG_ESCAPE_DISABLE 0x00000040 // disable escaping - #define WINHTTP_FLAG_ESCAPE_DISABLE_QUERY 0x00000080 // if escaping enabled escape path part, but do not escape query - #define WINHTTP_FLAG_BYPASS_PROXY_CACHE 0x00000100 // add "pragma: no-cache" request header - #define WINHTTP_FLAG_REFRESH WINHTTP_FLAG_BYPASS_PROXY_CACHE - #define WINHTTP_FLAG_AUTOMATIC_CHUNKING 0x00000200 // Send request without content-length header or chunked TE - - #define WINHTTP_NO_PROXY_NAME NULL - #define WINHTTP_NO_PROXY_BYPASS NULL - - // - // WINHTTP_QUERY_FLAG_NUMBER - if this bit is set in the dwInfoLevel parameter of - // HttpQueryHeader(), then the value of the header will be converted to a number - // before being returned to the caller, if applicable - // - #define WINHTTP_QUERY_FLAG_NUMBER 0x20000000 - - #define WINHTTP_QUERY_MIME_VERSION 0 - #define WINHTTP_QUERY_CONTENT_TYPE 1 - #define WINHTTP_QUERY_CONTENT_TRANSFER_ENCODING 2 - #define WINHTTP_QUERY_CONTENT_ID 3 - #define WINHTTP_QUERY_CONTENT_DESCRIPTION 4 - #define WINHTTP_QUERY_CONTENT_LENGTH 5 - #define WINHTTP_QUERY_CONTENT_LANGUAGE 6 - #define WINHTTP_QUERY_ALLOW 7 - #define WINHTTP_QUERY_PUBLIC 8 - #define WINHTTP_QUERY_DATE 9 - #define WINHTTP_QUERY_EXPIRES 10 - #define WINHTTP_QUERY_LAST_MODIFIED 11 - #define WINHTTP_QUERY_MESSAGE_ID 12 - #define WINHTTP_QUERY_URI 13 - #define WINHTTP_QUERY_DERIVED_FROM 14 - #define WINHTTP_QUERY_COST 15 - #define WINHTTP_QUERY_LINK 16 - #define WINHTTP_QUERY_PRAGMA 17 - #define WINHTTP_QUERY_VERSION 18 // special: part of status line - #define WINHTTP_QUERY_STATUS_CODE 19 // special: part of status line - #define WINHTTP_QUERY_STATUS_TEXT 20 // special: part of status line - #define WINHTTP_QUERY_RAW_HEADERS 21 // special: all headers as ASCIIZ - #define WINHTTP_QUERY_RAW_HEADERS_CRLF 22 // special: all headers - #define WINHTTP_QUERY_CONNECTION 23 - #define WINHTTP_QUERY_ACCEPT 24 - #define WINHTTP_QUERY_ACCEPT_CHARSET 25 - #define WINHTTP_QUERY_ACCEPT_ENCODING 26 - #define WINHTTP_QUERY_ACCEPT_LANGUAGE 27 - #define WINHTTP_QUERY_AUTHORIZATION 28 - #define WINHTTP_QUERY_CONTENT_ENCODING 29 - #define WINHTTP_QUERY_FORWARDED 30 - #define WINHTTP_QUERY_FROM 31 - #define WINHTTP_QUERY_IF_MODIFIED_SINCE 32 - #define WINHTTP_QUERY_LOCATION 33 - #define WINHTTP_QUERY_ORIG_URI 34 - #define WINHTTP_QUERY_REFERER 35 - #define WINHTTP_QUERY_RETRY_AFTER 36 - #define WINHTTP_QUERY_SERVER 37 - #define WINHTTP_QUERY_TITLE 38 - #define WINHTTP_QUERY_USER_AGENT 39 - #define WINHTTP_QUERY_WWW_AUTHENTICATE 40 - #define WINHTTP_QUERY_PROXY_AUTHENTICATE 41 - #define WINHTTP_QUERY_ACCEPT_RANGES 42 - #define WINHTTP_QUERY_SET_COOKIE 43 - #define WINHTTP_QUERY_COOKIE 44 - #define WINHTTP_QUERY_REQUEST_METHOD 45 // special: GET/POST etc. - #define WINHTTP_QUERY_REFRESH 46 - #define WINHTTP_QUERY_CONTENT_DISPOSITION 47 - - // NOTE: WinHttpQueryHeaders prettifiers for optional parameters. - #define WINHTTP_HEADER_NAME_BY_INDEX NULL - #define WINHTTP_NO_OUTPUT_BUFFER NULL - #define WINHTTP_NO_HEADER_INDEX NULL - - // NOTE: Http Response Status Codes - #define HTTP_STATUS_CONTINUE 100 // OK to continue with request - #define HTTP_STATUS_SWITCH_PROTOCOLS 101 // server has switched protocols in upgrade header - - #define HTTP_STATUS_OK 200 // request completed - #define HTTP_STATUS_CREATED 201 // object created, reason = new URI - #define HTTP_STATUS_ACCEPTED 202 // async completion (TBS) - #define HTTP_STATUS_PARTIAL 203 // partial completion - #define HTTP_STATUS_NO_CONTENT 204 // no info to return - #define HTTP_STATUS_RESET_CONTENT 205 // request completed, but clear form - #define HTTP_STATUS_PARTIAL_CONTENT 206 // partial GET fulfilled - #define HTTP_STATUS_WEBDAV_MULTI_STATUS 207 // WebDAV Multi-Status - - #define HTTP_STATUS_AMBIGUOUS 300 // server couldn't decide what to return - #define HTTP_STATUS_MOVED 301 // object permanently moved - #define HTTP_STATUS_REDIRECT 302 // object temporarily moved - #define HTTP_STATUS_REDIRECT_METHOD 303 // redirection w/ new access method - #define HTTP_STATUS_NOT_MODIFIED 304 // if-modified-since was not modified - #define HTTP_STATUS_USE_PROXY 305 // redirection to proxy, location header specifies proxy to use - #define HTTP_STATUS_REDIRECT_KEEP_VERB 307 // HTTP/1.1: keep same verb - #define HTTP_STATUS_PERMANENT_REDIRECT 308 // Object permanently moved keep verb - - #define HTTP_STATUS_BAD_REQUEST 400 // invalid syntax - #define HTTP_STATUS_DENIED 401 // access denied - #define HTTP_STATUS_PAYMENT_REQ 402 // payment required - #define HTTP_STATUS_FORBIDDEN 403 // request forbidden - #define HTTP_STATUS_NOT_FOUND 404 // object not found - #define HTTP_STATUS_BAD_METHOD 405 // method is not allowed - #define HTTP_STATUS_NONE_ACCEPTABLE 406 // no response acceptable to client found - #define HTTP_STATUS_PROXY_AUTH_REQ 407 // proxy authentication required - #define HTTP_STATUS_REQUEST_TIMEOUT 408 // server timed out waiting for request - #define HTTP_STATUS_CONFLICT 409 // user should resubmit with more info - #define HTTP_STATUS_GONE 410 // the resource is no longer available - #define HTTP_STATUS_LENGTH_REQUIRED 411 // the server refused to accept request w/o a length - #define HTTP_STATUS_PRECOND_FAILED 412 // precondition given in request failed - #define HTTP_STATUS_REQUEST_TOO_LARGE 413 // request entity was too large - #define HTTP_STATUS_URI_TOO_LONG 414 // request URI too long - #define HTTP_STATUS_UNSUPPORTED_MEDIA 415 // unsupported media type - #define HTTP_STATUS_RETRY_WITH 449 // retry after doing the appropriate action. - - #define HTTP_STATUS_SERVER_ERROR 500 // internal server error - #define HTTP_STATUS_NOT_SUPPORTED 501 // required not supported - #define HTTP_STATUS_BAD_GATEWAY 502 // error response received from gateway - #define HTTP_STATUS_SERVICE_UNAVAIL 503 // temporarily overloaded - #define HTTP_STATUS_GATEWAY_TIMEOUT 504 // timed out waiting for gateway - #define HTTP_STATUS_VERSION_NOT_SUP 505 // HTTP version not supported - - #define HTTP_STATUS_FIRST HTTP_STATUS_CONTINUE - #define HTTP_STATUS_LAST HTTP_STATUS_VERSION_NOT_SUP - - #define WINHTTP_CALLBACK_STATUS_RESOLVING_NAME 0x00000001 - #define WINHTTP_CALLBACK_STATUS_NAME_RESOLVED 0x00000002 - #define WINHTTP_CALLBACK_STATUS_CONNECTING_TO_SERVER 0x00000004 - #define WINHTTP_CALLBACK_STATUS_CONNECTED_TO_SERVER 0x00000008 - #define WINHTTP_CALLBACK_STATUS_SENDING_REQUEST 0x00000010 - #define WINHTTP_CALLBACK_STATUS_REQUEST_SENT 0x00000020 - #define WINHTTP_CALLBACK_STATUS_RECEIVING_RESPONSE 0x00000040 - #define WINHTTP_CALLBACK_STATUS_RESPONSE_RECEIVED 0x00000080 - #define WINHTTP_CALLBACK_STATUS_CLOSING_CONNECTION 0x00000100 - #define WINHTTP_CALLBACK_STATUS_CONNECTION_CLOSED 0x00000200 - #define WINHTTP_CALLBACK_STATUS_HANDLE_CREATED 0x00000400 - #define WINHTTP_CALLBACK_STATUS_HANDLE_CLOSING 0x00000800 - #define WINHTTP_CALLBACK_STATUS_DETECTING_PROXY 0x00001000 - #define WINHTTP_CALLBACK_STATUS_REDIRECT 0x00004000 - #define WINHTTP_CALLBACK_STATUS_INTERMEDIATE_RESPONSE 0x00008000 - #define WINHTTP_CALLBACK_STATUS_SECURE_FAILURE 0x00010000 - #define WINHTTP_CALLBACK_STATUS_HEADERS_AVAILABLE 0x00020000 - #define WINHTTP_CALLBACK_STATUS_DATA_AVAILABLE 0x00040000 - #define WINHTTP_CALLBACK_STATUS_READ_COMPLETE 0x00080000 - #define WINHTTP_CALLBACK_STATUS_WRITE_COMPLETE 0x00100000 - #define WINHTTP_CALLBACK_STATUS_REQUEST_ERROR 0x00200000 - #define WINHTTP_CALLBACK_STATUS_SENDREQUEST_COMPLETE 0x00400000 - - #define WINHTTP_CALLBACK_STATUS_GETPROXYFORURL_COMPLETE 0x01000000 - #define WINHTTP_CALLBACK_STATUS_CLOSE_COMPLETE 0x02000000 - #define WINHTTP_CALLBACK_STATUS_SHUTDOWN_COMPLETE 0x04000000 - #define WINHTTP_CALLBACK_STATUS_SETTINGS_WRITE_COMPLETE 0x10000000 - #define WINHTTP_CALLBACK_STATUS_SETTINGS_READ_COMPLETE 0x20000000 - - #define WINHTTP_CALLBACK_FLAG_RESOLVE_NAME (WINHTTP_CALLBACK_STATUS_RESOLVING_NAME | WINHTTP_CALLBACK_STATUS_NAME_RESOLVED) - #define WINHTTP_CALLBACK_FLAG_CONNECT_TO_SERVER (WINHTTP_CALLBACK_STATUS_CONNECTING_TO_SERVER | WINHTTP_CALLBACK_STATUS_CONNECTED_TO_SERVER) - #define WINHTTP_CALLBACK_FLAG_SEND_REQUEST (WINHTTP_CALLBACK_STATUS_SENDING_REQUEST | WINHTTP_CALLBACK_STATUS_REQUEST_SENT) - #define WINHTTP_CALLBACK_FLAG_RECEIVE_RESPONSE (WINHTTP_CALLBACK_STATUS_RECEIVING_RESPONSE | WINHTTP_CALLBACK_STATUS_RESPONSE_RECEIVED) - #define WINHTTP_CALLBACK_FLAG_CLOSE_CONNECTION (WINHTTP_CALLBACK_STATUS_CLOSING_CONNECTION | WINHTTP_CALLBACK_STATUS_CONNECTION_CLOSED) - #define WINHTTP_CALLBACK_FLAG_HANDLES (WINHTTP_CALLBACK_STATUS_HANDLE_CREATED | WINHTTP_CALLBACK_STATUS_HANDLE_CLOSING) - #define WINHTTP_CALLBACK_FLAG_DETECTING_PROXY WINHTTP_CALLBACK_STATUS_DETECTING_PROXY - #define WINHTTP_CALLBACK_FLAG_REDIRECT WINHTTP_CALLBACK_STATUS_REDIRECT - #define WINHTTP_CALLBACK_FLAG_INTERMEDIATE_RESPONSE WINHTTP_CALLBACK_STATUS_INTERMEDIATE_RESPONSE - #define WINHTTP_CALLBACK_FLAG_SECURE_FAILURE WINHTTP_CALLBACK_STATUS_SECURE_FAILURE - #define WINHTTP_CALLBACK_FLAG_SENDREQUEST_COMPLETE WINHTTP_CALLBACK_STATUS_SENDREQUEST_COMPLETE - #define WINHTTP_CALLBACK_FLAG_HEADERS_AVAILABLE WINHTTP_CALLBACK_STATUS_HEADERS_AVAILABLE - #define WINHTTP_CALLBACK_FLAG_DATA_AVAILABLE WINHTTP_CALLBACK_STATUS_DATA_AVAILABLE - #define WINHTTP_CALLBACK_FLAG_READ_COMPLETE WINHTTP_CALLBACK_STATUS_READ_COMPLETE - #define WINHTTP_CALLBACK_FLAG_WRITE_COMPLETE WINHTTP_CALLBACK_STATUS_WRITE_COMPLETE - #define WINHTTP_CALLBACK_FLAG_REQUEST_ERROR WINHTTP_CALLBACK_STATUS_REQUEST_ERROR - - #define WINHTTP_CALLBACK_FLAG_GETPROXYFORURL_COMPLETE WINHTTP_CALLBACK_STATUS_GETPROXYFORURL_COMPLETE - - #define WINHTTP_CALLBACK_FLAG_ALL_COMPLETIONS (WINHTTP_CALLBACK_STATUS_SENDREQUEST_COMPLETE \ - | WINHTTP_CALLBACK_STATUS_HEADERS_AVAILABLE \ - | WINHTTP_CALLBACK_STATUS_DATA_AVAILABLE \ - | WINHTTP_CALLBACK_STATUS_READ_COMPLETE \ - | WINHTTP_CALLBACK_STATUS_WRITE_COMPLETE \ - | WINHTTP_CALLBACK_STATUS_REQUEST_ERROR \ - | WINHTTP_CALLBACK_STATUS_GETPROXYFORURL_COMPLETE) - - #define WINHTTP_CALLBACK_FLAG_ALL_NOTIFICATIONS 0xffffffff - #define WINHTTP_INVALID_STATUS_CALLBACK ((WINHTTP_STATUS_CALLBACK)(-1L)) - - typedef struct _WINHTTP_EXTENDED_HEADER - { - union - { - CHAR const *pwszName; - WCHAR const *pszName; - }; - union - { - WCHAR const *pwszValue; - CHAR const *pszValue; - }; - } WINHTTP_EXTENDED_HEADER, *PWINHTTP_EXTENDED_HEADER; - - typedef struct _WINHTTP_ASYNC_RESULT - { - DWORD *dwResult; // indicates which async API has encountered an error - DWORD dwError; // the error code if the API failed - } WINHTTP_ASYNC_RESULT, *LPWINHTTP_ASYNC_RESULT, *PWINHTTP_ASYNC_RESULT; - - typedef - VOID - (*WINHTTP_STATUS_CALLBACK)( - HINTERNET hInternet, - DWORD *dwContext, - DWORD dwInternetStatus, - VOID *lpvStatusInformation, - DWORD dwStatusInformationLength - ); - - extern "C" - { - __declspec(dllimport) HINTERNET __stdcall WinHttpOpen(WCHAR const *pszAgentW, DWORD dwAccessType, WCHAR const *pszProxyW, WCHAR const *pszProxyBypassW, DWORD dwFlags); - __declspec(dllimport) BOOL __stdcall WinHttpCloseHandle(HINTERNET hInternet); - __declspec(dllimport) HINTERNET __stdcall WinHttpConnect(HINTERNET hSession, WCHAR const *pswzServerName, INTERNET_PORT nServerPort, DWORD dwReserved); - __declspec(dllimport) BOOL __stdcall WinHttpReadData(HINTERNET hRequest, VOID *lpBuffer, DWORD dwNumberOfBytesToRead, DWORD *lpdwNumberOfBytesRead); - __declspec(dllimport) HINTERNET __stdcall WinHttpOpenRequest(HINTERNET hConnect, WCHAR const *pwszVerb, WCHAR const *pwszObjectName, WCHAR const *pwszVersion, WCHAR const *pwszReferrer, WCHAR const *ppwszAcceptTypes, DWORD dwFlags); - __declspec(dllimport) BOOL __stdcall WinHttpSendRequest(HINTERNET hRequest, WCHAR const *lpszHeaders, DWORD dwHeadersLength, VOID *lpOptional, DWORD dwOptionalLength, DWORD dwTotalLength, DWORD_PTR dwContext); - __declspec(dllimport) DWORD __stdcall WinHttpAddRequestHeadersEx(HINTERNET hRequest, DWORD dwModifiers, ULONGLONG ullFlags, ULONGLONG ullExtra, DWORD cHeaders, WINHTTP_EXTENDED_HEADER *pHeaders); - __declspec(dllimport) BOOL __stdcall WinHttpSetCredentials(HINTERNET hRequest, // HINTERNET handle returned by WinHttpOpenRequest. - DWORD AuthTargets, // Only WINHTTP_AUTH_TARGET_SERVER and WINHTTP_AUTH_TARGET_PROXY are supported in this version and they are mutually exclusive - DWORD AuthScheme, // must be one of the supported Auth Schemes returned from WinHttpQueryAuthSchemes() - WCHAR * pwszUserName, // 1) NULL if default creds is to be used, in which case pszPassword will be ignored - WCHAR * pwszPassword, // 1) "" == Blank Password; 2)Parameter ignored if pszUserName is NULL; 3) Invalid to pass in NULL if pszUserName is not NULL - VOID * pAuthParams); - __declspec(dllimport) BOOL __stdcall WinHttpQueryHeaders(HINTERNET hRequest, DWORD dwInfoLevel, WCHAR const *pwszName, VOID *lpBuffer, DWORD *lpdwBufferLength, DWORD *lpdwIndex); - __declspec(dllimport) BOOL __stdcall WinHttpReceiveResponse(HINTERNET hRequest, VOID *lpReserved); - __declspec(dllimport) WINHTTP_STATUS_CALLBACK __stdcall WinHttpSetStatusCallback(HINTERNET hInternet, WINHTTP_STATUS_CALLBACK lpfnInternetCallback, DWORD dwNotificationFlags, DWORD_PTR dwReserved); - } - - // NOTE: um/DbgHelp.h ////////////////////////////////////////////////////////////////////////// - #define SYMOPT_CASE_INSENSITIVE 0x00000001 - #define SYMOPT_UNDNAME 0x00000002 - #define SYMOPT_DEFERRED_LOADS 0x00000004 - #define SYMOPT_NO_CPP 0x00000008 - #define SYMOPT_LOAD_LINES 0x00000010 - #define SYMOPT_OMAP_FIND_NEAREST 0x00000020 - #define SYMOPT_LOAD_ANYTHING 0x00000040 - #define SYMOPT_IGNORE_CVREC 0x00000080 - #define SYMOPT_NO_UNQUALIFIED_LOADS 0x00000100 - #define SYMOPT_FAIL_CRITICAL_ERRORS 0x00000200 - #define SYMOPT_EXACT_SYMBOLS 0x00000400 - #define SYMOPT_ALLOW_ABSOLUTE_SYMBOLS 0x00000800 - #define SYMOPT_IGNORE_NT_SYMPATH 0x00001000 - #define SYMOPT_INCLUDE_32BIT_MODULES 0x00002000 - #define SYMOPT_PUBLICS_ONLY 0x00004000 - #define SYMOPT_NO_PUBLICS 0x00008000 - #define SYMOPT_AUTO_PUBLICS 0x00010000 - #define SYMOPT_NO_IMAGE_SEARCH 0x00020000 - #define SYMOPT_SECURE 0x00040000 - #define SYMOPT_NO_PROMPTS 0x00080000 - #define SYMOPT_OVERWRITE 0x00100000 - #define SYMOPT_IGNORE_IMAGEDIR 0x00200000 - #define SYMOPT_FLAT_DIRECTORY 0x00400000 - #define SYMOPT_FAVOR_COMPRESSED 0x00800000 - #define SYMOPT_ALLOW_ZERO_ADDRESS 0x01000000 - #define SYMOPT_DISABLE_SYMSRV_AUTODETECT 0x02000000 - #define SYMOPT_READONLY_CACHE 0x04000000 - #define SYMOPT_SYMPATH_LAST 0x08000000 - #define SYMOPT_DISABLE_FAST_SYMBOLS 0x10000000 - #define SYMOPT_DISABLE_SYMSRV_TIMEOUT 0x20000000 - #define SYMOPT_DISABLE_SRVSTAR_ON_STARTUP 0x40000000 - #define SYMOPT_DEBUG 0x80000000 - - #define MAX_SYM_NAME 2000 - - typedef enum { - AddrMode1616, - AddrMode1632, - AddrModeReal, - AddrModeFlat - } ADDRESS_MODE; - - typedef struct _tagADDRESS64 { - DWORD64 Offset; - WORD Segment; - ADDRESS_MODE Mode; - } ADDRESS64, *LPADDRESS64; - - - typedef struct _KDHELP64 { - DWORD64 Thread; - DWORD ThCallbackStack; - DWORD ThCallbackBStore; - DWORD NextCallback; - DWORD FramePointer; - DWORD64 KiCallUserMode; - DWORD64 KeUserCallbackDispatcher; - DWORD64 SystemRangeStart; - DWORD64 KiUserExceptionDispatcher; - DWORD64 StackBase; - DWORD64 StackLimit; - DWORD BuildVersion; - DWORD RetpolineStubFunctionTableSize; - DWORD64 RetpolineStubFunctionTable; - DWORD RetpolineStubOffset; - DWORD RetpolineStubSize; - DWORD64 Reserved0[2]; - } KDHELP64, *PKDHELP64; - - typedef struct _tagSTACKFRAME64 { - ADDRESS64 AddrPC; // program counter - ADDRESS64 AddrReturn; // return address - ADDRESS64 AddrFrame; // frame pointer - ADDRESS64 AddrStack; // stack pointer - ADDRESS64 AddrBStore; // backing store pointer - VOID *FuncTableEntry; // pointer to pdata/fpo or NULL - DWORD64 Params[4]; // possible arguments to the function - BOOL Far; // WOW far call - BOOL Virtual; // is this a virtual frame? - DWORD64 Reserved[3]; - KDHELP64 KdHelp; - } STACKFRAME64; - - typedef struct _IMAGEHLP_LINEW64 { - DWORD SizeOfStruct; // set to sizeof(IMAGEHLP_LINE64) - VOID *Key; // internal - DWORD LineNumber; // line number in file - WCHAR *FileName; // full filename - DWORD64 Address; // first instruction of line - } IMAGEHLP_LINEW64; - - typedef struct _SYMBOL_INFOW { - ULONG SizeOfStruct; - ULONG TypeIndex; // Type Index of symbol - ULONG64 Reserved[2]; - ULONG Index; - ULONG Size; - ULONG64 ModBase; // Base Address of module comtaining this symbol - ULONG Flags; - ULONG64 Value; // Value of symbol, ValuePresent should be 1 - ULONG64 Address; // Address of symbol including base address of module - ULONG Register; // register holding value or pointer to value - ULONG Scope; // scope of the symbol - ULONG Tag; // pdb classification - ULONG NameLen; // Actual length of name - ULONG MaxNameLen; - WCHAR Name[1]; // Name of symbol - } SYMBOL_INFOW; - - typedef BOOL (__stdcall READ_PROCESS_MEMORY_ROUTINE64)(HANDLE hProcess, DWORD64 qwBaseAddress, VOID *lpBuffer, DWORD nSize, DWORD *lpNumberOfBytesRead); - typedef VOID * (__stdcall FUNCTION_TABLE_ACCESS_ROUTINE64)(HANDLE ahProcess, DWORD64 AddrBase); - typedef DWORD64(__stdcall GET_MODULE_BASE_ROUTINE64)(HANDLE hProcess, DWORD64 Address); - typedef DWORD64(__stdcall TRANSLATE_ADDRESS_ROUTINE64)(HANDLE hProcess, HANDLE hThread, ADDRESS64 *lpaddr); - - extern "C" - { - __declspec(dllimport) BOOL __stdcall StackWalk64 (DWORD MachineType, HANDLE hProcess, HANDLE hThread, STACKFRAME64 *StackFrame, VOID *ContextRecord, READ_PROCESS_MEMORY_ROUTINE64 *ReadMemoryRoutine, FUNCTION_TABLE_ACCESS_ROUTINE64 *FunctionTableAccessRoutine, GET_MODULE_BASE_ROUTINE64 *GetModuleBaseRoutine, TRANSLATE_ADDRESS_ROUTINE64 *TranslateAddress); - __declspec(dllimport) BOOL __stdcall SymFromAddrW (HANDLE hProcess, DWORD64 Address, DWORD64 *Displacement, SYMBOL_INFOW *Symbol); - __declspec(dllimport) VOID * __stdcall SymFunctionTableAccess64(HANDLE hProcess, DWORD64 AddrBase); - __declspec(dllimport) BOOL __stdcall SymGetLineFromAddrW64 (HANDLE hProcess, DWORD64 dwAddr, DWORD *pdwDisplacement, IMAGEHLP_LINEW64 *Line); - __declspec(dllimport) DWORD64 __stdcall SymGetModuleBase64 (HANDLE hProcess, DWORD64 qwAddr); - __declspec(dllimport) BOOL __stdcall SymRefreshModuleList (HANDLE hProcess); - }; - - // NOTE: um/errhandlingapi.h /////////////////////////////////////////////////////////////////// - extern "C" - { - __declspec(dllimport) DWORD __stdcall GetLastError(VOID); - } - - // NOTE: um/libloaderapi.h ///////////////////////////////////////////////////////////////////// - extern "C" - { - __declspec(dllimport) HMODULE __stdcall LoadLibraryA (const CHAR *lpLibFileName); - __declspec(dllimport) BOOL __stdcall FreeLibrary (HMODULE hLibModule); - __declspec(dllimport) void * __stdcall GetProcAddress (HMODULE hModule, const CHAR *lpProcName); - __declspec(dllimport) HMODULE __stdcall GetModuleHandleA (const CHAR *lpModuleName); - __declspec(dllimport) DWORD __stdcall GetModuleFileNameW(HMODULE hModule, WCHAR *lpFilename, DWORD nSize); - } - - // NOTE: um/synchapi.h ///////////////////////////////////////////////////////////////////////// - typedef RTL_CONDITION_VARIABLE CONDITION_VARIABLE, *PCONDITION_VARIABLE; - - extern "C" - { - __declspec(dllimport) VOID __stdcall InitializeConditionVariable (CONDITION_VARIABLE *ConditionVariable); - __declspec(dllimport) VOID __stdcall WakeConditionVariable (CONDITION_VARIABLE *ConditionVariable); - __declspec(dllimport) VOID __stdcall WakeAllConditionVariable (CONDITION_VARIABLE *ConditionVariable); - __declspec(dllimport) BOOL __stdcall SleepConditionVariableCS (CONDITION_VARIABLE *ConditionVariable, CRITICAL_SECTION *CriticalSection, DWORD dwMilliseconds); - - __declspec(dllimport) VOID __stdcall InitializeCriticalSection (CRITICAL_SECTION *lpCriticalSection); - __declspec(dllimport) VOID __stdcall EnterCriticalSection (CRITICAL_SECTION *lpCriticalSection); - __declspec(dllimport) VOID __stdcall LeaveCriticalSection (CRITICAL_SECTION *lpCriticalSection); - __declspec(dllimport) BOOL __stdcall InitializeCriticalSectionAndSpinCount(CRITICAL_SECTION *lpCriticalSection, DWORD dwSpinCount); - __declspec(dllimport) BOOL __stdcall InitializeCriticalSectionEx (CRITICAL_SECTION *lpCriticalSection, DWORD dwSpinCount, DWORD Flags); - __declspec(dllimport) DWORD __stdcall SetCriticalSectionSpinCount (CRITICAL_SECTION *lpCriticalSection, DWORD dwSpinCount); - __declspec(dllimport) BOOL __stdcall TryEnterCriticalSection (CRITICAL_SECTION *lpCriticalSection); - __declspec(dllimport) VOID __stdcall DeleteCriticalSection (CRITICAL_SECTION *lpCriticalSection); - - __declspec(dllimport) DWORD __stdcall WaitForSingleObject (HANDLE hHandle, DWORD dwMilliseconds); - __declspec(dllimport) BOOL __stdcall ReleaseSemaphore (HANDLE hSemaphore, LONG lReleaseCount, LONG *lpPreviousCount); - __declspec(dllimport) VOID __stdcall Sleep (DWORD dwMilliseconds); - } - - // NOTE: um/profileapi.h /////////////////////////////////////////////////////////////////////// - extern "C" - { - __declspec(dllimport) BOOL __stdcall QueryPerformanceCounter (LARGE_INTEGER* lpPerformanceCount); - __declspec(dllimport) BOOL __stdcall QueryPerformanceFrequency(LARGE_INTEGER* lpFrequency); - } - - // NOTE: um/processthreadsapi.h //////////////////////////////////////////////////////////////// - typedef struct _PROCESS_INFORMATION { - HANDLE hProcess; - HANDLE hThread; - DWORD dwProcessId; - DWORD dwThreadId; - } PROCESS_INFORMATION, *PPROCESS_INFORMATION, *LPPROCESS_INFORMATION; - - typedef struct _STARTUPINFOW { - DWORD cb; - WCHAR *lpReserved; - WCHAR *lpDesktop; - WCHAR *lpTitle; - DWORD dwX; - DWORD dwY; - DWORD dwXSize; - DWORD dwYSize; - DWORD dwXCountChars; - DWORD dwYCountChars; - DWORD dwFillAttribute; - DWORD dwFlags; - WORD wShowWindow; - WORD cbReserved2; - BYTE *lpReserved2; - HANDLE hStdInput; - HANDLE hStdOutput; - HANDLE hStdError; - } STARTUPINFOW, *LPSTARTUPINFOW; - - typedef DWORD (__stdcall *PTHREAD_START_ROUTINE)( - VOID *lpThreadParameter - ); - typedef PTHREAD_START_ROUTINE LPTHREAD_START_ROUTINE; - - extern "C" - { - __declspec(dllimport) BOOL __stdcall CreateProcessW (WCHAR const *lpApplicationName, WCHAR *lpCommandLine, SECURITY_ATTRIBUTES *lpProcessAttributes, SECURITY_ATTRIBUTES *lpThreadAttributes, BOOL bInheritHandles, DWORD dwCreationFlags, VOID *lpEnvironment, WCHAR const *lpCurrentDirectory, STARTUPINFOW *lpStartupInfo, PROCESS_INFORMATION *lpProcessInformation); - __declspec(dllimport) HANDLE __stdcall CreateThread (SECURITY_ATTRIBUTES *lpThreadAttributes, SIZE_T dwStackSize, PTHREAD_START_ROUTINE lpStartAddress, VOID *lpParameter, DWORD dwCreationFlags, DWORD *lpThreadId); - __declspec(dllimport) DWORD __stdcall GetCurrentThreadId(VOID); - __declspec(dllimport) BOOL __stdcall GetExitCodeProcess(HANDLE hProcess, DWORD *lpExitCode); - __declspec(dllimport) void __stdcall ExitProcess (UINT uExitCode); - } - - // NOTE: um/memoryapi.h //////////////////////////////////////////////////////////////////////// - extern "C" - { - __declspec(dllimport) VOID * __stdcall VirtualAlloc (VOID *lpAddress, SIZE_T dwSize, DWORD flAllocationType, DWORD flProtect); - __declspec(dllimport) BOOL __stdcall VirtualProtect(VOID *lpAddress, SIZE_T dwSize, DWORD flNewProtect, DWORD *lpflOldProtect); - __declspec(dllimport) BOOL __stdcall VirtualFree (VOID *lpAddress, SIZE_T dwSize, DWORD dwFreeType); - } - - // NOTE: shared/bcrypt.h /////////////////////////////////////////////////////////////////////// - typedef VOID *BCRYPT_ALG_HANDLE; - typedef LONG NTSTATUS; - - extern "C" - { - __declspec(dllimport) NTSTATUS __stdcall BCryptOpenAlgorithmProvider(BCRYPT_ALG_HANDLE *phAlgorithm, const WCHAR *pszAlgId, const WCHAR *pszImplementation, ULONG dwFlags); - __declspec(dllimport) NTSTATUS __stdcall BCryptGenRandom (BCRYPT_ALG_HANDLE hAlgorithm, UCHAR *pbBuffer, ULONG cbBuffer, ULONG dwFlags); - } - - // NOTE: um/shellapi.h ///////////////////////////////////////////////////////////////////////// - extern "C" - { - __declspec(dllimport) HINSTANCE __stdcall ShellExecuteA(HWND hwnd, CHAR const *lpOperation, CHAR const *lpFile, CHAR const *lpParameters, CHAR const *lpDirectory, INT nShowCmd); - __declspec(dllimport) HINSTANCE __stdcall ShellExecuteW(HWND hwnd, WCHAR const *lpOperation, WCHAR const *lpFile, WCHAR const *lpParameters, WCHAR const *lpDirectory, INT nShowCmd); - } - - // NOTE: um/debugapi.h ///////////////////////////////////////////////////////////////////////// - extern "C" - { - __declspec(dllimport) BOOL __stdcall IsDebuggerPresent(); - } - - // NOTE: um/namedpipeapi.h ///////////////////////////////////////////////////////////////////// - extern "C" - { - __declspec(dllimport) BOOL __stdcall CreatePipe (HANDLE *hReadPipe, HANDLE *hWritePipe, LPSECURITY_ATTRIBUTES lpPipeAttributes, DWORD nSize); - __declspec(dllimport) BOOL __stdcall PeekNamedPipe(HANDLE hNamedPipe, VOID *lpBuffer, DWORD nBufferSize, DWORD *lpBytesRead, DWORD *lpTotalBytesAvail, DWORD *lpBytesLeftThisMessage); - } - - // NOTE: um/handleapi.h //////////////////////////////////////////////////////////////////////// - extern "C" - { - __declspec(dllimport) BOOL __stdcall SetHandleInformation(HANDLE hObject, DWORD dwMask, DWORD dwFlags); - } - - // NOTE: um/commdlg.h ////////////////////////////////////////////////////////////////////////// - typedef UINT_PTR (__stdcall *LPOFNHOOKPROC)(HWND, UINT, WPARAM, LPARAM); - typedef struct tagOFNW { - DWORD lStructSize; - HWND hwndOwner; - HINSTANCE hInstance; - WCHAR const * lpstrFilter; - LPWSTR lpstrCustomFilter; - DWORD nMaxCustFilter; - DWORD nFilterIndex; - LPWSTR lpstrFile; - DWORD nMaxFile; - LPWSTR lpstrFileTitle; - DWORD nMaxFileTitle; - WCHAR const * lpstrInitialDir; - WCHAR const * lpstrTitle; - DWORD Flags; - WORD nFileOffset; - WORD nFileExtension; - WCHAR const * lpstrDefExt; - LPARAM lCustData; - LPOFNHOOKPROC lpfnHook; - WCHAR const * lpTemplateName; - #ifdef _MAC - LPEDITMENU lpEditInfo; - LPCSTR lpstrPrompt; - #endif - #if (_WIN32_WINNT >= 0x0500) - void * pvReserved; - DWORD dwReserved; - DWORD FlagsEx; - #endif // (_WIN32_WINNT >= 0x0500) - } OPENFILENAMEW, *LPOPENFILENAMEW; - - - #define OFN_READONLY 0x00000001 - #define OFN_OVERWRITEPROMPT 0x00000002 - #define OFN_HIDEREADONLY 0x00000004 - #define OFN_NOCHANGEDIR 0x00000008 - #define OFN_SHOWHELP 0x00000010 - #define OFN_ENABLEHOOK 0x00000020 - #define OFN_ENABLETEMPLATE 0x00000040 - #define OFN_ENABLETEMPLATEHANDLE 0x00000080 - #define OFN_NOVALIDATE 0x00000100 - #define OFN_ALLOWMULTISELECT 0x00000200 - #define OFN_EXTENSIONDIFFERENT 0x00000400 - #define OFN_PATHMUSTEXIST 0x00000800 - #define OFN_FILEMUSTEXIST 0x00001000 - #define OFN_CREATEPROMPT 0x00002000 - #define OFN_SHAREAWARE 0x00004000 - #define OFN_NOREADONLYRETURN 0x00008000 - #define OFN_NOTESTFILECREATE 0x00010000 - #define OFN_NONETWORKBUTTON 0x00020000 - #define OFN_NOLONGNAMES 0x00040000 // force no long names for 4.x modules - #if(WINVER >= 0x0400) - #define OFN_EXPLORER 0x00080000 // new look commdlg - #define OFN_NODEREFERENCELINKS 0x00100000 - #define OFN_LONGNAMES 0x00200000 // force long names for 3.x modules - // OFN_ENABLEINCLUDENOTIFY and OFN_ENABLESIZING require - // Windows 2000 or higher to have any effect. - #define OFN_ENABLEINCLUDENOTIFY 0x00400000 // send include message to callback - #define OFN_ENABLESIZING 0x00800000 - #endif /* WINVER >= 0x0400 */ - #if (_WIN32_WINNT >= 0x0500) - #define OFN_DONTADDTORECENT 0x02000000 - #define OFN_FORCESHOWHIDDEN 0x10000000 // Show All files including System and hidden files - #endif // (_WIN32_WINNT >= 0x0500) - - //FlagsEx Values - #if (_WIN32_WINNT >= 0x0500) - #define OFN_EX_NOPLACESBAR 0x00000001 - #endif // (_WIN32_WINNT >= 0x0500) - - extern "C" - { - __declspec(dllimport) BOOL __stdcall GetSaveFileNameW(LPOPENFILENAMEW); - __declspec(dllimport) BOOL __stdcall GetOpenFileNameW(LPOPENFILENAMEW); - } - - // NOTE: um/shlwapi.h ////////////////////////////////////////////////////////////////////////// - extern "C" - { - __declspec(dllimport) BOOL __stdcall PathRelativePathToW(WCHAR *pszPath, WCHAR const *pszFrom, DWORD dwAttrFrom, WCHAR const *pszTo, DWORD dwAttrTo); - __declspec(dllimport) BOOL __stdcall PathIsRelativeW(WCHAR *pszPath); - } - - // NOTE: um/pathcch.h ////////////////////////////////////////////////////////////////////////// - typedef enum PATHCCH_OPTIONS - { - PATHCCH_NONE = 0x0, - - // This option allows applications to gain access to long paths. It has two - // different behaviors. For process configured to enable long paths it will allow - // the returned path to be longer than the max path limit that is normally imposed. - // For process that are not this option will convert long paths into the extended - // length DOS device form (with \\?\ prefix) when the path is longer than the limit. - // This form is not length limited by the Win32 file system API on all versions of Windows. - // This second behavior is the same behavior for OSes that don't have the long path feature. - // This can not be specified with PATHCCH_ENSURE_IS_EXTENDED_LENGTH_PATH. - PATHCCH_ALLOW_LONG_PATHS = 0x01, - - // Can only be used when PATHCCH_ALLOW_LONG_PATHS is specified. This - // Forces the API to treat the caller as long path enabled, independent of the - // process's long name enabled state. Cannot be used with PATHCCH_FORCE_DISABLE_LONG_NAME_PROCESS. - PATHCCH_FORCE_ENABLE_LONG_NAME_PROCESS = 0x02, - - // Can only be used when PATHCCH_ALLOW_LONG_PATHS is specified. This - // Forces the API to treat the caller as long path disabled, independent of the - // process's long name enabled state. Cannot be used with PATHCCH_FORCE_ENABLE_LONG_NAME_PROCESS. - PATHCCH_FORCE_DISABLE_LONG_NAME_PROCESS = 0x04, - - // Disable the normalization of path segments that includes removing trailing dots and spaces. - // This enables access to paths that win32 path normalization will block. - PATHCCH_DO_NOT_NORMALIZE_SEGMENTS = 0x08, - - // Convert the input path into the extended length DOS device path form (with the \\?\ prefix) - // if not already in that form. This enables access to paths that are otherwise not addressable - // due to Win32 normalization rules (that can strip trailing dots and spaces) and path - // length limitations. This option implies the same behavior of PATHCCH_DO_NOT_NORMALIZE_SEGMENTS. - // This can not be specified with PATHCCH_ALLOW_LONG_PATHS. - PATHCCH_ENSURE_IS_EXTENDED_LENGTH_PATH = 0x10, - - // When combining or normalizing a path ensure there is a trailing backslash. - PATHCCH_ENSURE_TRAILING_SLASH = 0x020, - - // Convert forward slashes to back slashes and collapse multiple slashes. - // This is needed to to support sub-path or identity comparisons. - PATHCCH_CANONICALIZE_SLASHES = 0x040, - } PATHCCH_OPTIONS; - - extern "C" - { - __declspec(dllimport) HRESULT __stdcall PathCchCanonicalizeEx(PWSTR pszPathOut, size_t cchPathOut, WCHAR const *pszPathIn, ULONG dwFlags); - }; - - // NOTE: um/errhandlingapi.h /////////////////////////////////////////////////////////////////// - extern "C" - { - __declspec(dllimport) VOID __stdcall RaiseException(DWORD dwExceptionCode, DWORD dwExceptionFlags, DWORD nNumberOfArguments, const ULONG_PTR* lpArguments); - }; - - // NOTE: include/excpt.h /////////////////////////////////////////////////////////////////// - #define EXCEPTION_EXECUTE_HANDLER 1 - #define EXCEPTION_CONTINUE_SEARCH 0 - #define EXCEPTION_CONTINUE_EXECUTION (-1) - - DN_MSVC_WARNING_POP -#endif // !defined(_INC_WINDOWS) -#endif // !defined(DN_OS_WINDOWS_H) -#endif - -struct DN_W32Error -{ - unsigned long code; - DN_Str8 msg; -}; - -struct DN_W32FolderIteratorW -{ - void *handle; - DN_Str16 file_name; - wchar_t file_name_buf[512]; -}; - -enum DN_W32SyncPrimitiveType -{ - DN_OSW32SyncPrimitiveType_Semaphore, - DN_OSW32SyncPrimitiveType_Mutex, - DN_OSW32SyncPrimitiveType_ConditionVariable, -}; - -struct DN_W32SyncPrimitive -{ - union - { - void *sem; - CRITICAL_SECTION mutex; - CONDITION_VARIABLE cv; - }; - - DN_W32SyncPrimitive *next; -}; - -typedef HRESULT DN_W32SetThreadDescriptionFunc(HANDLE hThread, PWSTR const lpThreadDescription); -struct DN_W32Core -{ - DN_W32SetThreadDescriptionFunc *set_thread_description; - LARGE_INTEGER qpc_frequency; - void *bcrypt_rng_handle; - bool bcrypt_init_success; - bool sym_initialised; - - CRITICAL_SECTION sync_primitive_free_list_mutex; - DN_W32SyncPrimitive *sync_primitive_free_list; -}; - -DN_API void DN_W32_ThreadSetName (DN_Str8 name); - -DN_API DN_Str16 DN_W32_ErrorCodeToMsg16Alloc(DN_U32 error_code); -DN_API DN_W32Error DN_W32_ErrorCodeToMsg (DN_Arena *arena, DN_U32 error_code); -DN_API DN_W32Error DN_W32_ErrorCodeToMsgAlloc (DN_U32 error_code); -DN_API DN_W32Error DN_W32_LastError (DN_Arena *arena); -DN_API DN_W32Error DN_W32_LastErrorAlloc (); -DN_API void DN_W32_MakeProcessDPIAware (); - -// NOTE: Windows Str8 <-> Str16 //////////////////////////////////////////////////////////////////// -DN_API DN_Str16 DN_W32_Str8ToStr16 (DN_Arena *arena, DN_Str8 src); -DN_API int DN_W32_Str8ToStr16Buffer (DN_Str16 src, char *dest, int dest_size); -DN_API DN_Str8 DN_W32_Str16ToStr8 (DN_Arena *arena, DN_Str16 src); -DN_API int DN_W32_Str16ToStr8Buffer (DN_Str16 src, char *dest, int dest_size); -DN_API DN_Str8 DN_W32_Str16ToStr8FromHeap(DN_Str16 src); - -// NOTE: Path navigation /////////////////////////////////////////////////////////////////////////// -DN_API DN_Str16 DN_W32_EXEPathW (DN_Arena *arena); -DN_API DN_Str16 DN_W32_EXEDirW (DN_Arena *arena); -DN_API DN_Str8 DN_W32_WorkingDir (DN_Arena *arena, DN_Str8 suffix); -DN_API DN_Str16 DN_W32_WorkingDirW (DN_Arena *arena, DN_Str16 suffix); -DN_API bool DN_W32_DirWIterate (DN_Str16 path, DN_W32FolderIteratorW *it); -#endif // !defined(DN_OS_WIN32) -#elif defined(DN_PLATFORM_POSIX) || defined(DN_PLATFORM_EMSCRIPTEN) - // DN: Single header generator commented out this header => #include "OS/dn_os_posix.h" -#if !defined(DN_OS_POSIX_H) -#define DN_OS_POSIX_H - -#if defined(_CLANGD) - // DN: Single header generator commented out this header => #include "../dn_base_inc.h" -#endif - -#include -#include - -/* -//////////////////////////////////////////////////////////////////////////////////////////////////// -// -// $$$$$$\ $$$$$$\ $$$$$$$\ $$$$$$\ $$$$$$\ $$$$$$\ $$\ $$\ -// $$ __$$\ $$ __$$\ $$ __$$\ $$ __$$\ $$ __$$\ \_$$ _|$$ | $$ | -// $$ / $$ |$$ / \__| $$ | $$ |$$ / $$ |$$ / \__| $$ | \$$\ $$ | -// $$ | $$ |\$$$$$$\ $$$$$$$ |$$ | $$ |\$$$$$$\ $$ | \$$$$ / -// $$ | $$ | \____$$\ $$ ____/ $$ | $$ | \____$$\ $$ | $$ $$< -// $$ | $$ |$$\ $$ | $$ | $$ | $$ |$$\ $$ | $$ | $$ /\$$\ -// $$$$$$ |\$$$$$$ | $$ | $$$$$$ |\$$$$$$ |$$$$$$\ $$ / $$ | -// \______/ \______/ \__| \______/ \______/ \______|\__| \__| -// -// dn_os_posix.h -// -//////////////////////////////////////////////////////////////////////////////////////////////////// -*/ - -struct DN_POSIXProcSelfStatus -{ - char name[64]; - DN_U8 name_size; - DN_U32 pid; - DN_U64 vm_peak; - DN_U32 vm_size; -}; - -// NOTE: The POSIX implementation disallows copies of synchronisation objects in -// general hence we have to dynamically allocate these primitives to maintain a -// consistent address. -// -// -// Source: The Open Group Base Specifications Issue 7, 2018 edition -// https://pubs.opengroup.org/onlinepubs/9699919799/functions/V2_chap02.html#tag_15_09_09 -// -// 2.9.9 Synchronization Object Copies and Alternative Mappings -// -// For barriers, condition variables, mutexes, and read-write locks, [TSH] -// [Option Start] if the process-shared attribute is set to -// PTHREAD_PROCESS_PRIVATE, [Option End] only the synchronization object at the -// address used to initialize it can be used for performing synchronization. The -// effect of referring to another mapping of the same object when locking, -// unlocking, or destroying the object is undefined. [...] The effect of -// referring to a copy of the object when locking, unlocking, or destroying it -// is undefined. - -enum DN_POSIXSyncPrimitiveType -{ - DN_OSPOSIXSyncPrimitiveType_Semaphore, - DN_OSPOSIXSyncPrimitiveType_Mutex, - DN_OSPOSIXSyncPrimitiveType_ConditionVariable, -}; - -struct DN_POSIXSyncPrimitive -{ - union - { - sem_t sem; - pthread_mutex_t mutex; - pthread_cond_t cv; - }; - DN_POSIXSyncPrimitive *next; -}; - -struct DN_POSIXCore -{ - DN_POSIXSyncPrimitive *sync_primitive_free_list; - pthread_mutex_t sync_primitive_free_list_mutex; - bool clock_monotonic_raw; -}; - -DN_API void DN_Posix_Init(DN_POSIXCore *posix); -DN_API void DN_Posix_ThreadSetName(DN_Str8 name); -DN_API DN_POSIXProcSelfStatus DN_Posix_ProcSelfStatus(); -#endif // !defined(DN_OS_POSIX_H) -#else - #error Please define a platform e.g. 'DN_PLATFORM_WIN32' to enable the correct implementation for platform APIs -#endif - -// DN: Single header generator commented out this header => #include "OS/dn_os_tls.h" -#if !defined(DN_OS_TLS_H) -#define DN_OS_TLS_H - -#if defined(_CLANGD) - // DN: Single header generator commented out this header => #include "../dn_base_inc.h" - // DN: Single header generator commented out this header => #include "../dn_os_inc.h" -#endif - -// NOTE: DN_OSErrSink -enum DN_OSErrSinkMode -{ - DN_OSErrSinkMode_Nil, // Default behaviour to accumulate errors into the sink - DN_OSErrSinkMode_DebugBreakOnEndAndLog, // Debug break (int3) when error is encountered and the sink is ended by the 'end and log' functions. - DN_OSErrSinkMode_ExitOnError, // When an error is encountered, exit the program with the error code of the error that was caught. -}; - -struct DN_OSErrSinkMsg -{ - DN_I32 error_code; - DN_Str8 msg; - DN_CallSite call_site; - DN_OSErrSinkMsg *next; - DN_OSErrSinkMsg *prev; -}; - -struct DN_OSErrSinkNode -{ - DN_CallSite call_site; // Call site that the node was created - DN_OSErrSinkMode mode; // Controls how the sink behaves when an error is registered onto the sink. - DN_OSErrSinkMsg *msg_sentinel; // List of error messages accumulated for the current scope - DN_U64 arena_pos; // Position to reset the arena when the scope is ended -}; - -struct DN_OSErrSink -{ - DN_Arena * arena; // Dedicated allocator from the thread's local storage - DN_OSErrSinkNode stack[128]; // Each entry contains errors accumulated between a [begin, end] region of the active sink. - DN_USize stack_size; -}; - -enum DN_OSTLSArena -{ - DN_OSTLSArena_Main, // NOTE: Arena for permanent allocations - DN_OSTLSArena_ErrorSink, // NOTE: Arena for logging error information for this thread - - // NOTE: Per-thread scratch arenas (2 to prevent aliasing) - DN_OSTLSArena_TMem0, - DN_OSTLSArena_TMem1, - - DN_OSTLSArena_Count, -}; - -struct DN_OSTLS -{ - DN_B32 init; // Flag to track if TLS has been initialised - DN_U64 thread_id; - DN_CallSite call_site; // Stores call-site information when requested by thread - DN_OSErrSink err_sink; // Error handling state - DN_Arena arenas[DN_OSTLSArena_Count]; // Default arenas that the thread has access to implicitly - DN_Arena * arena_stack[8]; // Active stack of arenas push/popped arenas on into the TLS - DN_USize arena_stack_index; - - DN_Arena * frame_arena; - char name[64]; - DN_U8 name_size; -}; - -// Push the temporary memory arena when retrieved, popped when the arena goes -// out of scope. Pushed arenas are used automatically as the allocator in TLS -// suffixed function. -enum DN_OSTLSPushTMem -{ - DN_OSTLSPushTMem_No, - DN_OSTLSPushTMem_Yes, -}; - -struct DN_OSTLSTMem -{ - DN_OSTLSTMem(DN_OSTLS *context, uint8_t context_index, DN_OSTLSPushTMem push_scratch); - ~DN_OSTLSTMem(); - DN_Arena *arena; - DN_B32 destructed; - DN_OSTLSPushTMem push_arena; - DN_ArenaTempMem temp_mem; -}; - -struct DN_OSTLSInitArgs -{ - DN_U64 reserve; - DN_U64 commit; - DN_U64 err_sink_reserve; - DN_U64 err_sink_commit; -}; - -DN_API void DN_OS_TLSInit (DN_OSTLS *tls, DN_OSTLSInitArgs args); -DN_API void DN_OS_TLSDeinit (DN_OSTLS *tls); -DN_API DN_OSTLS * DN_OS_TLSGet (); -DN_API void DN_OS_TLSSetCurrentThreadTLS (DN_OSTLS *tls); -DN_API DN_Arena * DN_OS_TLSArena (); -DN_API DN_OSTLSTMem DN_OS_TLSGetTMem (void const *conflict_arena, DN_OSTLSPushTMem push_tmp_mem); -DN_API void DN_OS_TLSPushArena (DN_Arena *arena); -DN_API void DN_OS_TLSPopArena (); -DN_API DN_Arena * DN_OS_TLSTopArena (); -DN_API void DN_OS_TLSBeginFrame (DN_Arena *frame_arena); -DN_API DN_Arena * DN_OS_TLSFrameArena (); -#define DN_OS_TLSSaveCallSite do { DN_OS_TLSGet()->call_site = DN_CALL_SITE; } while (0) -#define DN_OS_TLSTMem(...) DN_OS_TLSGetTMem(__VA_ARGS__, DN_OSTLSPushTMem_No) -#define DN_OS_TLSPushTMem(...) DN_OS_TLSGetTMem(__VA_ARGS__, DN_OSTLSPushTMem_Yes) - -DN_API DN_OSErrSink * DN_OS_ErrSinkBegin_ (DN_OSErrSinkMode mode, DN_CallSite call_site); -#define DN_OS_ErrSinkBegin(mode) DN_OS_ErrSinkBegin_(mode, DN_CALL_SITE) -#define DN_OS_ErrSinkBeginDefault() DN_OS_ErrSinkBegin(DN_OSErrSinkMode_Nil) -DN_API bool DN_OS_ErrSinkHasError (DN_OSErrSink *err); -DN_API DN_OSErrSinkMsg * DN_OS_ErrSinkEnd (DN_Arena *arena, DN_OSErrSink *err); -DN_API DN_Str8 DN_OS_ErrSinkEndStr8 (DN_Arena *arena, DN_OSErrSink *err); -DN_API void DN_OS_ErrSinkEndAndIgnore (DN_OSErrSink *err); -DN_API bool DN_OS_ErrSinkEndAndLogError_ (DN_OSErrSink *err, DN_CallSite call_site, DN_Str8 msg); -DN_API bool DN_OS_ErrSinkEndAndLogErrorFV_ (DN_OSErrSink *err, DN_CallSite call_site, DN_FMT_ATTRIB char const *fmt, va_list args); -DN_API bool DN_OS_ErrSinkEndAndLogErrorF_ (DN_OSErrSink *err, DN_CallSite call_site, DN_FMT_ATTRIB char const *fmt, ...); -DN_API void DN_OS_ErrSinkEndAndExitIfErrorF_ (DN_OSErrSink *err, DN_CallSite call_site, DN_U32 exit_val, DN_FMT_ATTRIB char const *fmt, ...); -DN_API void DN_OS_ErrSinkEndAndExitIfErrorFV_ (DN_OSErrSink *err, DN_CallSite call_site, DN_U32 exit_val, DN_FMT_ATTRIB char const *fmt, va_list args); -DN_API void DN_OS_ErrSinkAppendFV_ (DN_OSErrSink *err, DN_U32 error_code, DN_FMT_ATTRIB char const *fmt, va_list args); -DN_API void DN_OS_ErrSinkAppendF_ (DN_OSErrSink *err, DN_U32 error_code, DN_FMT_ATTRIB char const *fmt, ...); -#define DN_OS_ErrSinkEndAndLogError(err, err_msg) DN_OS_ErrSinkEndAndLogError_(err, DN_CALL_SITE, err_msg) -#define DN_OS_ErrSinkEndAndLogErrorFV(err, fmt, args) DN_OS_ErrSinkEndAndLogErrorFV_(err, DN_CALL_SITE, fmt, args) -#define DN_OS_ErrSinkEndAndLogErrorF(err, fmt, ...) DN_OS_ErrSinkEndAndLogErrorF_(err, DN_CALL_SITE, fmt, ##__VA_ARGS__) -#define DN_OS_ErrSinkEndAndExitIfErrorFV(err, exit_val, fmt, args) DN_OS_ErrSinkEndAndExitIfErrorFV_(err, DN_CALL_SITE, exit_val, fmt, args) -#define DN_OS_ErrSinkEndAndExitIfErrorF(err, exit_val, fmt, ...) DN_OS_ErrSinkEndAndExitIfErrorF_(err, DN_CALL_SITE, exit_val, fmt, ##__VA_ARGS__) - -#define DN_OS_ErrSinkAppendFV(error, error_code, fmt, args) \ - do { \ - DN_OS_TLSSaveCallSite; \ - DN_OS_ErrSinkAppendFV_(error, error_code, fmt, args); \ - } while (0) - -#define DN_OS_ErrSinkAppendF(error, error_code, fmt, ...) \ - do { \ - DN_OS_TLSSaveCallSite; \ - DN_OS_ErrSinkAppendF_(error, error_code, fmt, ##__VA_ARGS__); \ - } while (0) - -#endif // defined(DN_OS_TLS_H) -// DN: Single header generator commented out this header => #include "OS/dn_os.h" -#if !defined(DN_OS_H) -#define DN_OS_H - -#if defined(_CLANGD) - // DN: Single header generator commented out this header => #include "../dn_base_inc.h" - // DN: Single header generator commented out this header => #include "../dn_os_inc.h" -#endif - -#include // operator new - -#if !defined(DN_OS_WIN32) || defined(DN_OS_WIN32_USE_PTHREADS) - #include - #include -#endif - -#if defined(DN_PLATFORM_POSIX) || defined(DN_PLATFORM_EMSCRIPTEN) - #include // errno - #include // O_RDONLY ... etc - #include // ioctl - #include // mmap - #include // getrandom - #include // stat - #include // pid_t - #include // waitpid - #include // clock_gettime, nanosleep - #include // access, gettid, write - - #if !defined(DN_PLATFORM_EMSCRIPTEN) - #include // FICLONE - #include // sendfile - #endif -#endif - -#if defined(DN_PLATFORM_EMSCRIPTEN) - #include // emscripten_fetch (for DN_OSHttpResponse) -#endif - -extern DN_CPUFeatureDecl g_dn_cpu_feature_decl[DN_CPUFeature_Count]; - -struct DN_OSTimer /// Record time between two time-points using the OS's performance counter. -{ - DN_U64 start; - DN_U64 end; -}; - -// NOTE: DN_OSFile -enum DN_OSPathInfoType -{ - DN_OSPathInfoType_Unknown, - DN_OSPathInfoType_Directory, - DN_OSPathInfoType_File, -}; - -struct DN_OSPathInfo -{ - bool exists; - DN_OSPathInfoType type; - DN_U64 create_time_in_s; - DN_U64 last_write_time_in_s; - DN_U64 last_access_time_in_s; - DN_U64 size; -}; - -struct DN_OSDirIterator -{ - void *handle; - DN_Str8 file_name; - char buffer[512]; -}; - -// NOTE: R/W Stream API -struct DN_OSFileRead -{ - bool success; - DN_USize bytes_read; -}; - -struct DN_OSFile -{ - bool error; - void *handle; -}; - -enum DN_OSFileOpen -{ - DN_OSFileOpen_CreateAlways, // Create file if it does not exist, otherwise, zero out the file and open - DN_OSFileOpen_OpenIfExist, // Open file at path only if it exists - DN_OSFileOpen_OpenAlways, // Open file at path, create file if it does not exist -}; - -typedef DN_U32 DN_OSFileAccess; - -enum DN_OSFileAccess_ -{ - DN_OSFileAccess_Read = 1 << 0, - DN_OSFileAccess_Write = 1 << 1, - DN_OSFileAccess_Execute = 1 << 2, - DN_OSFileAccess_AppendOnly = 1 << 3, // This flag cannot be combined with any other access mode - DN_OSFileAccess_ReadWrite = DN_OSFileAccess_Read | DN_OSFileAccess_Write, - DN_OSFileAccess_All = DN_OSFileAccess_ReadWrite | DN_OSFileAccess_Execute | DN_OSFileAccess_AppendOnly, -}; - -// NOTE: DN_OSPath -#if !defined(DN_OSPathSeperator) - #if defined(DN_OS_WIN32) - #define DN_OSPathSeperator "\\" - #else - #define DN_OSPathSeperator "/" - #endif - #define DN_OSPathSeperatorString DN_Str8Lit(DN_OSPathSeperator) -#endif - -struct DN_OSPathLink -{ - DN_Str8 string; - DN_OSPathLink *next; - DN_OSPathLink *prev; -}; - -struct DN_OSPath -{ - bool has_prefix_path_separator; - DN_OSPathLink *head; - DN_OSPathLink *tail; - DN_USize string_size; - DN_U16 links_size; -}; - -// NOTE: DN_OSExec -typedef DN_U32 DN_OSExecFlags; - -enum DN_OSExecFlags_ -{ - DN_OSExecFlags_Nil = 0, - DN_OSExecFlags_SaveStdout = 1 << 0, - DN_OSExecFlags_SaveStderr = 1 << 1, - DN_OSExecFlags_SaveOutput = DN_OSExecFlags_SaveStdout | DN_OSExecFlags_SaveStderr, - DN_OSExecFlags_MergeStderrToStdout = 1 << 2 | DN_OSExecFlags_SaveOutput, -}; - -struct DN_OSExecAsyncHandle -{ - DN_OSExecFlags exec_flags; - DN_U32 os_error_code; - DN_U32 exit_code; - void *process; - void *stdout_read; - void *stdout_write; - void *stderr_read; - void *stderr_write; -}; - -struct DN_OSExecResult -{ - bool finished; - DN_Str8 stdout_text; - DN_Str8 stderr_text; - DN_U32 os_error_code; - DN_U32 exit_code; -}; - -struct DN_OSExecArgs -{ - DN_OSExecFlags flags; - DN_Str8 working_dir; - DN_Slice environment; -}; - -// NOTE: DN_OSSemaphore -DN_U32 const DN_OS_SEMAPHORE_INFINITE_TIMEOUT = UINT32_MAX; - -struct DN_OSSemaphore -{ - DN_U64 handle; -}; - -enum DN_OSSemaphoreWaitResult -{ - DN_OSSemaphoreWaitResult_Failed, - DN_OSSemaphoreWaitResult_Success, - DN_OSSemaphoreWaitResult_Timeout, -}; - -struct DN_OSMutex -{ - DN_U64 handle; -}; - -struct DN_OSConditionVariable -{ - DN_U64 handle; -}; - -// NOTE: DN_OSThread -typedef DN_I32(DN_OSThreadFunc)(struct DN_OSThread *); - -struct DN_OSThread -{ - DN_Str8x64 name; - DN_OSTLS tls; - DN_OSTLSInitArgs tls_init_args; - void *handle; - DN_U64 thread_id; - void *user_context; - DN_OSThreadFunc *func; - DN_OSSemaphore init_semaphore; -}; - -// NOTE: DN_OSHttp -enum DN_OSHttpRequestSecure -{ - DN_OSHttpRequestSecure_No, - DN_OSHttpRequestSecure_Yes, -}; - -struct DN_OSHttpResponse -{ - // NOTE: Response data - DN_U32 error_code; - DN_Str8 error_msg; - DN_U16 http_status; - DN_Str8 body; - DN_B32 done; - - // NOTE: Book-keeping - DN_Arena *arena; // Allocates memory for the response - - // NOTE: Async book-keeping - // Synchronous HTTP response uses the TLS scratch arena whereas async - // calls use their own dedicated arena. - DN_Arena tmp_arena; - DN_Arena *tmem_arena; - DN_Str8Builder builder; - DN_OSSemaphore on_complete_semaphore; - - #if defined(DN_PLATFORM_EMSCRIPTEN) - emscripten_fetch_t *em_handle; - #elif defined(DN_PLATFORM_WIN32) - HINTERNET w32_request_session; - HINTERNET w32_request_connection; - HINTERNET w32_request_handle; - #endif -}; - -struct DN_OSCore -{ - DN_CPUReport cpu_report; - DN_OSTLS tls; // Thread local storage state for the main thread. - - // NOTE: Logging - DN_LOGEmitFromTypeFVFunc * log_callback; // Set this pointer to override the logging routine - void * log_user_data; // User pointer passed into 'log_callback' - bool log_to_file; // Output logs to file as well as standard out - DN_OSFile log_file; // TODO(dn): Hmmm, how should we do this... ? - DN_TicketMutex log_file_mutex; // Is locked when instantiating the log_file for the first time - bool log_no_colour; // Disable colours in the logging output - - // NOTE: OS - DN_U32 logical_processor_count; - DN_U32 page_size; - DN_U32 alloc_granularity; - - // NOTE: Memory - // Total OS mem allocs in lifetime of program (e.g. malloc, VirtualAlloc, HeapAlloc ...). This - // only includes allocations routed through the library such as the growing nature of arenas or - // using the memory allocation routines in the library like DN_OS_MemCommit and so forth. - DN_U64 vmem_allocs_total; - DN_U64 vmem_allocs_frame; // Total OS virtual memory allocs since the last 'DN_Core_FrameBegin' was invoked - DN_U64 mem_allocs_total; - DN_U64 mem_allocs_frame; // Total OS heap allocs since the last 'DN_Core_FrameBegin' was invoked - - DN_Arena arena; - void *platform_context; -}; - -struct DN_OSDiskSpace -{ - bool success; - DN_U64 avail; - DN_U64 size; -}; - -DN_API void DN_OS_EmitLogsWithOSPrintFunctions (DN_OSCore *os); -DN_API void DN_OS_DumpThreadContextArenaStat (DN_Str8 file_path); - -DN_API DN_Str8 DN_OS_BytesFromHexPtrArenaFrame (void const *hex, DN_USize hex_count); -DN_API DN_Str8 DN_OS_BytesFromHexStr8ArenaFrame (DN_Str8 hex); -DN_API DN_Str8 DN_OS_HexFromBytesPtrArenaFrame (void const *bytes, DN_USize bytes_count); -DN_API DN_Str8 DN_OS_HexFromBytesPtrArenaTLS (void const *bytes, DN_USize bytes_count); - -DN_API void * DN_OS_MemReserve (DN_USize size, DN_MemCommit commit, DN_MemPage page_flags); -DN_API bool DN_OS_MemCommit (void *ptr, DN_USize size, DN_U32 page_flags); -DN_API void DN_OS_MemDecommit (void *ptr, DN_USize size); -DN_API void DN_OS_MemRelease (void *ptr, DN_USize size); -DN_API int DN_OS_MemProtect (void *ptr, DN_USize size, DN_U32 page_flags); - -DN_API void * DN_OS_MemAlloc (DN_USize size, DN_ZMem z_mem); -DN_API void DN_OS_MemDealloc (void *ptr); - -DN_API DN_Date DN_OS_DateLocalTimeNow (); -DN_API DN_Str8x32 DN_OS_DateLocalTimeStr8Now (char date_separator = '-', char hms_separator = ':'); -DN_API DN_Str8x32 DN_OS_DateLocalTimeStr8 (DN_Date time, char date_separator = '-', char hms_separator = ':'); -DN_API DN_U64 DN_OS_DateUnixTimeNs (); -#define DN_OS_DateUnixTimeUs() (DN_OS_DateUnixTimeNs() / 1000) -#define DN_OS_DateUnixTimeMs() (DN_OS_DateUnixTimeNs() / (1000 * 1000)) -#define DN_OS_DateUnixTimeS() (DN_OS_DateUnixTimeNs() / (1000 * 1000 * 1000)) -DN_API DN_U64 DN_OS_DateUnixTimeSFromLocalDate (DN_Date date); -DN_API DN_U64 DN_OS_DateLocalUnixTimeSFromUnixTimeS (DN_U64 unix_ts_s); - -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_Str8 DN_OS_EXEPath (DN_Arena *arena); -DN_API DN_Str8 DN_OS_EXEDir (DN_Arena *arena); -#define DN_OS_EXEDirFromTLS() DN_OS_EXEDir(DN_OS_TLSTopArena()) -DN_API void DN_OS_SleepMs (DN_UInt milliseconds); - -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_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 bool DN_OS_FileCopy (DN_Str8 src, DN_Str8 dest, bool overwrite, DN_OSErrSink *err); -DN_API bool DN_OS_FileMove (DN_Str8 src, DN_Str8 dest, bool overwrite, DN_OSErrSink *err); - -DN_API DN_OSFile DN_OS_FileOpen (DN_Str8 path, DN_OSFileOpen open_mode, DN_OSFileAccess access, DN_OSErrSink *err); -DN_API DN_OSFileRead DN_OS_FileRead (DN_OSFile *file, void *buffer, DN_USize size, DN_OSErrSink *err); -DN_API bool DN_OS_FileWritePtr (DN_OSFile *file, void const *data, DN_USize size, DN_OSErrSink *err); -DN_API bool DN_OS_FileWrite (DN_OSFile *file, DN_Str8 buffer, DN_OSErrSink *err); -DN_API bool DN_OS_FileWriteFV (DN_OSFile *file, DN_OSErrSink *err, DN_FMT_ATTRIB char const *fmt, va_list args); -DN_API bool DN_OS_FileWriteF (DN_OSFile *file, DN_OSErrSink *err, DN_FMT_ATTRIB char const *fmt, ...); -DN_API bool DN_OS_FileFlush (DN_OSFile *file, DN_OSErrSink *err); -DN_API void DN_OS_FileClose (DN_OSFile *file); - -DN_API DN_Str8 DN_OS_FileReadAll (DN_Allocator alloc_type, void *allocator, DN_Str8 path, DN_OSErrSink *err); -DN_API DN_Str8 DN_OS_FileReadAllArena (DN_Arena *arena, DN_Str8 path, DN_OSErrSink *err); -DN_API DN_Str8 DN_OS_FileReadAllPool (DN_Pool *pool, DN_Str8 path, DN_OSErrSink *err); -DN_API DN_Str8 DN_OS_FileReadAllTLS (DN_Str8 path, DN_OSErrSink *err); -DN_API bool DN_OS_FileWriteAll (DN_Str8 path, DN_Str8 buffer, DN_OSErrSink *err); -DN_API bool DN_OS_FileWriteAllFV (DN_Str8 path, DN_OSErrSink *err, DN_FMT_ATTRIB char const *fmt, va_list args); -DN_API bool DN_OS_FileWriteAllF (DN_Str8 path, DN_OSErrSink *err, DN_FMT_ATTRIB char const *fmt, ...); -DN_API bool DN_OS_FileWriteAllSafe (DN_Str8 path, DN_Str8 buffer, DN_OSErrSink *err); -DN_API bool DN_OS_FileWriteAllSafeFV (DN_Str8 path, DN_OSErrSink *err, DN_FMT_ATTRIB char const *fmt, va_list args); -DN_API bool DN_OS_FileWriteAllSafeF (DN_Str8 path, DN_OSErrSink *err, DN_FMT_ATTRIB char const *fmt, ...); - -DN_API DN_OSPathInfo DN_OS_PathInfo (DN_Str8 path); -DN_API bool DN_OS_PathIsOlderThan (DN_Str8 file, DN_Str8 check_against); -DN_API bool DN_OS_PathDelete (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_PathMakeDir (DN_Str8 path); -DN_API bool DN_OS_PathIterateDir (DN_Str8 path, DN_OSDirIterator *it); - -DN_API bool DN_OS_PathAddRef (DN_Arena *arena, DN_OSPath *fs_path, DN_Str8 path); -DN_API bool DN_OS_PathAddRefTLS (DN_OSPath *fs_path, DN_Str8 path); -DN_API bool DN_OS_PathAddRefFrame (DN_OSPath *fs_path, DN_Str8 path); -DN_API bool DN_OS_PathAdd (DN_Arena *arena, DN_OSPath *fs_path, DN_Str8 path); -#define DN_OS_PathAddFromTLS(...) DN_OS_PathAdd(DN_OS_TLSTopArena(), ##__VA_ARGS__) -#define DN_OS_PathAddFromFrame(...) DN_OS_PathAdd(DN_OS_TLSFrameArena(), ##__VA_ARGS__) -DN_API bool DN_OS_PathAddF (DN_Arena *arena, DN_OSPath *fs_path, DN_FMT_ATTRIB char const *fmt, ...); -#define DN_OS_PathAddFFromTLS(...) DN_OS_PathAddF(DN_OS_TLSTopArena(), ##__VA_ARGS__) -#define DN_OS_PathAddFFromFrame(...) DN_OS_PathAddF(DN_OS_TLSFrameArena(), ##__VA_ARGS__) -DN_API bool DN_OS_PathPop (DN_OSPath *fs_path); -DN_API DN_Str8 DN_OS_PathBuildWithSeparator (DN_Arena *arena, DN_OSPath const *fs_path, DN_Str8 path_separator); -#define DN_OS_PathBuildWithSeperatorFromTLS(...) DN_OS_PathBuildWithSeperator(DN_OS_TLSTopArena(), ##__VA_ARGS__) -#define DN_OS_PathBuildWithSeperatorFromFrame(...) DN_OS_PathBuildWithSeperator(DN_OS_TLSFrameArena(), ##__VA_ARGS__) -DN_API DN_Str8 DN_OS_PathTo (DN_Arena *arena, DN_Str8 path, DN_Str8 path_separtor); -#define DN_OS_PathToFromTLS(...) DN_OS_PathTo(DN_OS_TLSTopArena(), ##__VA_ARGS__) -#define DN_OS_PathToFromFrame(...) DN_OS_PathTo(DN_OS_TLSFrameArena(), ##__VA_ARGS__) -DN_API DN_Str8 DN_OS_PathToF (DN_Arena *arena, DN_Str8 path_separator, DN_FMT_ATTRIB char const *fmt, ...); -#define DN_OS_PathToFFromTLS(...) DN_OS_PathToF(DN_OS_TLSTopArena(), ##__VA_ARGS__) -#define DN_OS_PathToFFromFrame(...) DN_OS_PathToF(DN_OS_TLSFrameArena(), ##__VA_ARGS__) -DN_API DN_Str8 DN_OS_Path (DN_Arena *arena, DN_Str8 path); -#define DN_OS_PathFromTLS(...) DN_OS_Path(DN_OS_TLSTopArena(), ##__VA_ARGS__) -#define DN_OS_PathFromFrame(...) DN_OS_Path(DN_OS_TLSFrameArena(), ##__VA_ARGS__) -DN_API DN_Str8 DN_OS_PathF (DN_Arena *arena, DN_FMT_ATTRIB char const *fmt, ...); -#define DN_OS_PathFFromTLS(...) DN_OS_PathF(DN_OS_TLSTopArena(), ##__VA_ARGS__) -#define DN_OS_PathFFromFrame(...) DN_OS_PathF(DN_OS_TLSFrameArena(), ##__VA_ARGS__) - -#define DN_OS_PathBuildFwdSlash(allocator, fs_path) DN_OS_PathBuildWithSeparator(allocator, fs_path, DN_Str8Lit("/")) -#define DN_OS_PathBuildBackSlash(allocator, fs_path) DN_OS_PathBuildWithSeparator(allocator, fs_path, DN_Str8Lit("\\")) -#define DN_OS_PathBuild(allocator, fs_path) DN_OS_PathBuildWithSeparator(allocator, fs_path, DN_OSPathSeparatorString) - -DN_API void DN_OS_Exit (int32_t exit_code); -DN_API DN_OSExecResult DN_OS_ExecPump (DN_OSExecAsyncHandle handle, char *stdout_buffer, size_t *stdout_size, char *stderr_buffer, size_t *stderr_size, DN_U32 timeout_ms, DN_OSErrSink *err); -DN_API DN_OSExecResult DN_OS_ExecWait (DN_OSExecAsyncHandle handle, DN_Arena *arena, DN_OSErrSink *err); -DN_API DN_OSExecAsyncHandle DN_OS_ExecAsync (DN_Slice cmd_line, DN_OSExecArgs *args, DN_OSErrSink *err); -DN_API DN_OSExecResult DN_OS_Exec (DN_Slice cmd_line, DN_OSExecArgs *args, DN_Arena *arena, DN_OSErrSink *err); -DN_API DN_OSExecResult DN_OS_ExecOrAbort (DN_Slice cmd_line, DN_OSExecArgs *args, DN_Arena *arena); -#define DN_OS_ExecOrAbortFromTLS (...) DN_OS_ExecOrAbort(__VA_ARGS__, DN_OS_TLSTopArena()) - -DN_API DN_OSSemaphore DN_OS_SemaphoreInit (DN_U32 initial_count); -DN_API bool DN_OS_SemaphoreIsValid (DN_OSSemaphore *semaphore); -DN_API void DN_OS_SemaphoreDeinit (DN_OSSemaphore *semaphore); -DN_API void DN_OS_SemaphoreIncrement (DN_OSSemaphore *semaphore, DN_U32 amount); -DN_API DN_OSSemaphoreWaitResult DN_OS_SemaphoreWait (DN_OSSemaphore *semaphore, DN_U32 timeout_ms); - -DN_API DN_OSMutex DN_OS_MutexInit (); -DN_API void DN_OS_MutexDeinit (DN_OSMutex *mutex); -DN_API void DN_OS_MutexLock (DN_OSMutex *mutex); -DN_API void DN_OS_MutexUnlock (DN_OSMutex *mutex); -#define DN_OS_MutexScope(mutex) DN_DeferLoop(DN_OS_MutexLock(mutex), DN_OS_MutexUnlock(mutex)) - -DN_API DN_OSConditionVariable DN_OS_ConditionVariableInit (); -DN_API void DN_OS_ConditionVariableDeinit (DN_OSConditionVariable *cv); -DN_API bool DN_OS_ConditionVariableWait (DN_OSConditionVariable *cv, DN_OSMutex *mutex, DN_U64 sleep_ms); -DN_API bool DN_OS_ConditionVariableWaitUntil (DN_OSConditionVariable *cv, DN_OSMutex *mutex, DN_U64 end_ts_ms); -DN_API void DN_OS_ConditionVariableSignal (DN_OSConditionVariable *cv); -DN_API void DN_OS_ConditionVariableBroadcast (DN_OSConditionVariable *cv); - -DN_API bool DN_OS_ThreadInit (DN_OSThread *thread, DN_OSThreadFunc *func, void *user_context); -DN_API void DN_OS_ThreadDeinit (DN_OSThread *thread); -DN_API DN_U32 DN_OS_ThreadID (); -DN_API void DN_OS_ThreadSetName (DN_Str8 name); - -DN_API void DN_OS_HttpRequestAsync (DN_OSHttpResponse *response, DN_Arena *arena, DN_Str8 host, DN_Str8 path, DN_OSHttpRequestSecure secure, DN_Str8 method, DN_Str8 body, DN_Str8 headers); -DN_API void DN_OS_HttpRequestWait (DN_OSHttpResponse *response); -DN_API void DN_OS_HttpRequestFree (DN_OSHttpResponse *response); -DN_API DN_OSHttpResponse DN_OS_HttpRequest (DN_Arena *arena, DN_Str8 host, DN_Str8 path, DN_OSHttpRequestSecure secure, DN_Str8 method, DN_Str8 body, DN_Str8 headers); -#endif // !defined(DN_OS_H) -// DN: Single header generator commented out this header => #include "OS/dn_os_allocator.h" -#if !defined(DN_OS_ALLOCATOR_H) -#define DN_OS_ALLOCATOR_H - -#if defined(_CLANGD) - // DN: Single header generator commented out this header => #include "../dn_base_inc.h" -#endif - -DN_API DN_Arena DN_ArenaFromHeap(DN_U64 size, DN_ArenaFlags flags); -DN_API DN_Arena DN_ArenaFromVMem(DN_U64 reserve, DN_U64 commit, DN_ArenaFlags flags); - -#endif // !defined(DN_OS_ALLOCATOR_H) -// DN: Single header generator commented out this header => #include "OS/dn_os_containers.h" -#if !defined(DN_OS_CONTAINERS_H) -#define DN_OS_CONTAINERS_H - -#if defined(_CLANGD) - // DN: Single header generator commented out this header => #include "../dn_base_inc.h" -#endif - -// NOTE: DN_VArray -// TODO(doyle): Add an API for shrinking the array by decomitting pages back to the OS. -template struct DN_VArray -{ - T *data; // Pointer to the start of the array items in the block of memory - DN_USize size; // Number of items currently in the array - DN_USize max; // Maximum number of items this array can store - DN_USize commit; // Bytes committed - - T *begin() { return data; } - T *end () { return data + size; } - T const *begin() const { return data; } - T const *end () const { return data + size; } -}; - -template DN_VArray DN_VArray_InitByteSize (DN_USize byte_size); -template DN_VArray DN_VArray_Init (DN_USize max); -template DN_VArray DN_VArray_InitSlice (DN_Slice slice, DN_USize max); -template DN_VArray DN_VArray_InitCArray (T const (&items)[N], DN_USize max); -template void DN_VArray_Deinit (DN_VArray *array); -template bool DN_VArray_IsValid (DN_VArray const *array); -template DN_Slice DN_VArray_Slice (DN_VArray const *array); -template bool DN_VArray_Reserve (DN_VArray *array, DN_USize count); -template T * DN_VArray_AddArray (DN_VArray *array, T const *items, DN_USize count); -template T * DN_VArray_AddCArray (DN_VArray *array, T const (&items)[N]); -template T * DN_VArray_Add (DN_VArray *array, T const &item); -#define DN_VArray_AddArrayAssert(...) DN_HardAssert(DN_VArray_AddArray(__VA_ARGS__)) -#define DN_VArray_AddCArrayAssert(...) DN_HardAssert(DN_VArray_AddCArray(__VA_ARGS__)) -#define DN_VArray_AddAssert(...) DN_HardAssert(DN_VArray_Add(__VA_ARGS__)) -template T * DN_VArray_MakeArray (DN_VArray *array, DN_USize count, DN_ZMem z_mem); -template T * DN_VArray_Make (DN_VArray *array, DN_ZMem z_mem); -#define DN_VArray_MakeArrayAssert(...) DN_HardAssert(DN_VArray_MakeArray(__VA_ARGS__)) -#define DN_VArray_MakeAssert(...) DN_HardAssert(DN_VArray_Make(__VA_ARGS__)) -template T * DN_VArray_InsertArray (DN_VArray *array, DN_USize index, T const *items, DN_USize count); -template T * DN_VArray_InsertCArray (DN_VArray *array, DN_USize index, T const (&items)[N]); -template T * DN_VArray_Insert (DN_VArray *array, DN_USize index, T const &item); -#define DN_VArray_InsertArrayAssert(...) DN_HardAssert(DN_VArray_InsertArray(__VA_ARGS__)) -#define DN_VArray_InsertCArrayAssert(...) DN_HardAssert(DN_VArray_InsertCArray(__VA_ARGS__)) -#define DN_VArray_InsertAssert(...) DN_HardAssert(DN_VArray_Insert(__VA_ARGS__)) -template T DN_VArray_PopFront (DN_VArray *array, DN_USize count); -template T DN_VArray_PopBack (DN_VArray *array, DN_USize count); -template DN_ArrayEraseResult DN_VArray_EraseRange (DN_VArray *array, DN_USize begin_index, DN_ISize count, DN_ArrayErase erase); -template void DN_VArray_Clear (DN_VArray *array, DN_ZMem z_mem); -#endif // !defined(DN_OS_CONTAINERS_H) -// DN: Single header generator commented out this header => #include "OS/dn_os_print.h" -#if !defined(DN_OS_PRINT_H) -#define DN_OS_PRINT_H - -enum DN_OSPrintDest -{ - DN_OSPrintDest_Out, - DN_OSPrintDest_Err, -}; - -// NOTE: Print Macros -#define DN_OS_PrintOut(string) DN_OS_Print(DN_OSPrintDest_Out, string) -#define DN_OS_PrintOutF(fmt, ...) DN_OS_PrintF(DN_OSPrintDest_Out, fmt, ##__VA_ARGS__) -#define DN_OS_PrintOutFV(fmt, args) DN_OS_PrintFV(DN_OSPrintDest_Out, fmt, args) - -#define DN_OS_PrintOutStyle(style, string) DN_OS_PrintStyle(DN_OSPrintDest_Out, style, string) -#define DN_OS_PrintOutFStyle(style, fmt, ...) DN_OS_PrintFStyle(DN_OSPrintDest_Out, style, fmt, ##__VA_ARGS__) -#define DN_OS_PrintOutFVStyle(style, fmt, args, ...) DN_OS_PrintFVStyle(DN_OSPrintDest_Out, style, fmt, args) - -#define DN_OS_PrintOutLn(string) DN_OS_PrintLn(DN_OSPrintDest_Out, string) -#define DN_OS_PrintOutLnF(fmt, ...) DN_OS_PrintLnF(DN_OSPrintDest_Out, fmt, ##__VA_ARGS__) -#define DN_OS_PrintOutLnFV(fmt, args) DN_OS_PrintLnFV(DN_OSPrintDest_Out, fmt, args) - -#define DN_OS_PrintOutLnStyle(style, string) DN_OS_PrintLnStyle(DN_OSPrintDest_Out, style, string); -#define DN_OS_PrintOutLnFStyle(style, fmt, ...) DN_OS_PrintLnFStyle(DN_OSPrintDest_Out, style, fmt, ##__VA_ARGS__) -#define DN_OS_PrintOutLnFVStyle(style, fmt, args) DN_OS_PrintLnFVStyle(DN_OSPrintDest_Out, style, fmt, args); - -#define DN_OS_PrintErr(string) DN_OS_Print(DN_OSPrintDest_Err, string) -#define DN_OS_PrintErrF(fmt, ...) DN_OS_PrintF(DN_OSPrintDest_Err, fmt, ##__VA_ARGS__) -#define DN_OS_PrintErrFV(fmt, args) DN_OS_PrintFV(DN_OSPrintDest_Err, fmt, args) - -#define DN_OS_PrintErrStyle(style, string) DN_OS_PrintStyle(DN_OSPrintDest_Err, style, string) -#define DN_OS_PrintErrFStyle(style, fmt, ...) DN_OS_PrintFStyle(DN_OSPrintDest_Err, style, fmt, ##__VA_ARGS__) -#define DN_OS_PrintErrFVStyle(style, fmt, args, ...) DN_OS_PrintFVStyle(DN_OSPrintDest_Err, style, fmt, args) - -#define DN_OS_PrintErrLn(string) DN_OS_PrintLn(DN_OSPrintDest_Err, string) -#define DN_OS_PrintErrLnF(fmt, ...) DN_OS_PrintLnF(DN_OSPrintDest_Err, fmt, ##__VA_ARGS__) -#define DN_OS_PrintErrLnFV(fmt, args) DN_OS_PrintLnFV(DN_OSPrintDest_Err, fmt, args) - -#define DN_OS_PrintErrLnStyle(style, string) DN_OS_PrintLnStyle(DN_OSPrintDest_Err, style, string); -#define DN_OS_PrintErrLnFStyle(style, fmt, ...) DN_OS_PrintLnFStyle(DN_OSPrintDest_Err, style, fmt, ##__VA_ARGS__) -#define DN_OS_PrintErrLnFVStyle(style, fmt, args) DN_OS_PrintLnFVStyle(DN_OSPrintDest_Err, style, fmt, args); - -// NOTE: Print -DN_API void DN_OS_Print (DN_OSPrintDest dest, DN_Str8 string); -DN_API void DN_OS_PrintF (DN_OSPrintDest dest, DN_FMT_ATTRIB char const *fmt, ...); -DN_API void DN_OS_PrintFV (DN_OSPrintDest dest, DN_FMT_ATTRIB char const *fmt, va_list args); - -DN_API void DN_OS_PrintStyle (DN_OSPrintDest dest, DN_LOGStyle style, DN_Str8 string); -DN_API void DN_OS_PrintFStyle (DN_OSPrintDest dest, DN_LOGStyle style, DN_FMT_ATTRIB char const *fmt, ...); -DN_API void DN_OS_PrintFVStyle (DN_OSPrintDest dest, DN_LOGStyle style, DN_FMT_ATTRIB char const *fmt, va_list args); - -DN_API void DN_OS_PrintLn (DN_OSPrintDest dest, DN_Str8 string); -DN_API void DN_OS_PrintLnF (DN_OSPrintDest dest, DN_FMT_ATTRIB char const *fmt, ...); -DN_API void DN_OS_PrintLnFV (DN_OSPrintDest dest, DN_FMT_ATTRIB char const *fmt, va_list args); - -DN_API void DN_OS_PrintLnStyle (DN_OSPrintDest dest, DN_LOGStyle style, DN_Str8 string); -DN_API void DN_OS_PrintLnFStyle (DN_OSPrintDest dest, DN_LOGStyle style, DN_FMT_ATTRIB char const *fmt, ...); -DN_API void DN_OS_PrintLnFVStyle (DN_OSPrintDest dest, DN_LOGStyle style, DN_FMT_ATTRIB char const *fmt, va_list args); -#endif // !defined(DN_OS_PRINT_H) -// DN: Single header generator commented out this header => #include "OS/dn_os_string.h" -#if !defined(DN_OS_STRING_H) -#define DN_OS_STRING_H - -#if defined(_CLANGD) - // DN: Single header generator commented out this header => #include "../dn_base_inc.h" - // DN: Single header generator commented out this header => #include "../dn_os_inc.h" -#endif - -// NOTE: DN_Str8 - -DN_API DN_Str8 DN_Str8FromFmtVArenaFrame (DN_FMT_ATTRIB char const *fmt, va_list args); -DN_API DN_Str8 DN_Str8FromFmtArenaFrame (DN_FMT_ATTRIB char const *fmt, ...); -DN_API DN_Str8 DN_Str8FromArenaFrame (DN_USize size, DN_ZMem z_mem); -DN_API DN_Str8 DN_Str8FromHeapF (DN_FMT_ATTRIB char const *fmt, ...); -DN_API DN_Str8 DN_Str8FromHeap (DN_USize size, DN_ZMem z_mem); -DN_API DN_Str8 DN_Str8FromTLSFV (DN_FMT_ATTRIB char const *fmt, va_list args); -DN_API DN_Str8 DN_Str8FromTLSF (DN_FMT_ATTRIB char const *fmt, ...); -DN_API DN_Str8 DN_Str8FromTLS (DN_USize size, DN_ZMem z_mem); -DN_API DN_Str8 DN_Str8FromStr8Frame (DN_Str8 string); -DN_API DN_Str8 DN_Str8FromStr8TLS (DN_Str8 string); - -DN_API DN_Str8SplitResult DN_Str8SplitFromFrame (DN_Str8 string, DN_Str8 delimiter, DN_Str8SplitIncludeEmptyStrings mode); -DN_API DN_Str8SplitResult DN_Str8SplitFromTLS (DN_Str8 string, DN_Str8 delimiter, DN_Str8SplitIncludeEmptyStrings mode); - -DN_API DN_Str8 DN_Str8SegmentFromFrame (DN_Str8 src, DN_USize segment_size, char segment_char); -DN_API DN_Str8 DN_Str8SegmentFromTLS (DN_Str8 src, DN_USize segment_size, char segment_char); - -DN_API DN_Str8 DN_Str8ReverseSegmentFromFrame (DN_Str8 src, DN_USize segment_size, char segment_char); -DN_API DN_Str8 DN_Str8ReverseSegmentFromTLS (DN_Str8 src, DN_USize segment_size, char segment_char); - -DN_API DN_Str8 DN_Str8AppendFFromFrame (DN_Str8 string, char const *fmt, ...); -DN_API DN_Str8 DN_Str8AppendFFromTLS (DN_Str8 string, char const *fmt, ...); - -DN_API DN_Str8 DN_Str8FillFFromFrame (DN_Str8 string, char const *fmt, ...); -DN_API DN_Str8 DN_Str8FillFFromTLS (DN_Str8 string, char const *fmt, ...); - -DN_API DN_Str8TruncateResult DN_Str8TruncateMiddleArenaFrame (DN_Str8 str8, uint32_t side_size, DN_Str8 truncator); -DN_API DN_Str8TruncateResult DN_Str8TruncateMiddleArenaTLS (DN_Str8 str8, uint32_t side_size, DN_Str8 truncator); - -DN_API DN_Str8 DN_Str8PadNewLines (DN_Arena *arena, DN_Str8 src, DN_Str8 pad); -DN_API DN_Str8 DN_Str8PadNewLinesFromFrame (DN_Str8 src, DN_Str8 pad); -DN_API DN_Str8 DN_Str8PadNewLinesFromTLS (DN_Str8 src, DN_Str8 pad); - -DN_API DN_Str8 DN_Str8UpperFromFrame (DN_Str8 string); -DN_API DN_Str8 DN_Str8UpperFromTLS (DN_Str8 string); - -DN_API DN_Str8 DN_Str8LowerFromFrame (DN_Str8 string); -DN_API DN_Str8 DN_Str8LowerFromTLS (DN_Str8 string); - -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_Str8EqCase_Sensitive); -DN_API DN_Str8 DN_Str8ReplaceInsensitive (DN_Str8 string, DN_Str8 find, DN_Str8 replace, DN_USize start_index, DN_Arena *arena); - -// NOTE: DN_Str8Builder //////////////////////////////////////////////////////////////////////////// - -DN_API DN_Str8Builder DN_Str8BuilderFromArena () { return DN_Str8BuilderFromArena(DN_OS_TLSGet()->frame_arena); } -DN_API DN_Str8Builder DN_Str8BuilderFromTLS () { return DN_Str8BuilderFromArena(DN_OS_TLSTopArena()); } - -DN_API DN_Str8Builder DN_Str8BuilderFromStr8PtrRefFrame (DN_Str8 const *strings, DN_USize size) { return DN_Str8BuilderFromStr8PtrRef(DN_OS_TLSGet()->frame_arena, strings, size); } -DN_API DN_Str8Builder DN_Str8BuilderFromStr8PtrRefTLS (DN_Str8 const *strings, DN_USize size) { return DN_Str8BuilderFromStr8PtrRef(DN_OS_TLSTopArena(), strings, size); } -DN_API DN_Str8Builder DN_Str8BuilderFromStr8PtrCopyFrame (DN_Str8 const *strings, DN_USize size) { return DN_Str8BuilderFromStr8PtrCopy(DN_OS_TLSGet()->frame_arena, strings, size); } -DN_API DN_Str8Builder DN_Str8BuilderFromStr8PtrCopyTLS (DN_Str8 const *strings, DN_USize size) { return DN_Str8BuilderFromStr8PtrCopy(DN_OS_TLSTopArena(), strings, size); } - -DN_API DN_Str8Builder DN_Str8BuilderFromBuilderFrame (DN_Str8Builder const *builder) { return DN_Str8BuilderFromBuilder(DN_OS_TLSGet()->frame_arena, builder); } -DN_API DN_Str8Builder DN_Str8BuilderFromBuilderTLS (DN_Str8Builder const *builder) { return DN_Str8BuilderFromBuilder(DN_OS_TLSTopArena(), builder); } - -DN_API DN_Str8 DN_Str8BuilderBuildFromFrame (DN_Str8Builder const *builder) { return DN_Str8BuilderBuild(builder, DN_OS_TLSGet()->frame_arena); } -DN_API DN_Str8 DN_Str8BuilderBuildFromHeap (DN_Str8Builder const *builder, DN_Arena *arena); -DN_API DN_Str8 DN_Str8BuilderBuildFromTLS (DN_Str8Builder const *builder) { return DN_Str8BuilderBuild(builder, DN_OS_TLSTopArena()); } - -DN_API DN_Str8 DN_Str8BuilderBuildDelimitedFromFrame(DN_Str8Builder const *builder, DN_Str8 delimiter) { return DN_Str8BuilderBuildDelimited(builder, delimiter, DN_OS_TLSGet()->frame_arena); } -DN_API DN_Str8 DN_Str8BuilderBuildDelimitedFromTLS (DN_Str8Builder const *builder, DN_Str8 delimiter) { return DN_Str8BuilderBuildDelimited(builder, delimiter, DN_OS_TLSTopArena()); } - -DN_API DN_Slice DN_Str8BuilderBuildSliceFromFrame (DN_Str8Builder const *builder) { return DN_Str8BuilderBuildSlice(builder, DN_OS_TLSGet()->frame_arena); } -DN_API DN_Slice DN_Str8BuilderBuildSliceFromTLS (DN_Str8Builder const *builder) { return DN_Str8BuilderBuildSlice(builder, DN_OS_TLSTopArena()); } - -#endif // !defined(DN_OS_STRING_H) - -#endif // DN_OS_INC_H -#endif - -struct DN_InitArgs -{ - DN_U64 os_tls_reserve; - DN_U64 os_tls_commit; - DN_U64 os_tls_err_sink_reserve; - DN_U64 os_tls_err_sink_commit; -}; - -typedef DN_USize DN_InitFlags; -enum DN_InitFlags_ -{ - DN_InitFlags_Nil = 0, - DN_InitFlags_OS = 1 << 0, - DN_InitFlags_OSLeakTracker = 1 << 1, - DN_InitFlags_LogLibFeatures = 1 << 2, - DN_InitFlags_LogCPUFeatures = 1 << 3, - DN_InitFlags_LogAllFeatures = DN_InitFlags_LogLibFeatures | DN_InitFlags_LogCPUFeatures, -}; - -struct DN_Core +typedef DN_U32 DN_LogFlags; +enum DN_LogFlags_ { - DN_InitFlags init_flags; - DN_USize mem_allocs_frame; - DN_LeakTracker leak; - #if defined(DN_OS_H) - DN_OSCore os; - #endif + DN_LogFlags_Nil = 0, + DN_LogFlags_NoNewLine = 1 << 0, + DN_LogFlags_NoPrefix = 1 << 1, }; -extern DN_Core *g_dn_; - -DN_API void DN_Init(DN_Core *dn, DN_InitFlags flags, DN_InitArgs *args); -DN_API void DN_BeginFrame(); - -#endif // !defined(DN_INC_H) -#if !defined(DN_MATH_H) -#define DN_MATH_H - -#if defined(_CLANGD) - // DN: Single header generator commented out this header => #include "../dn_base_inc.h" -#endif +typedef void DN_LogPrintFunc(DN_LogTypeParam type, void *user_data, DN_CallSite call_site, DN_LogFlags flags, DN_FMT_ATTRIB char const *fmt, va_list args); DN_MSVC_WARNING_PUSH DN_MSVC_WARNING_DISABLE(4201) // warning C4201: nonstandard extension used: nameless struct/union @@ -15450,8 +1487,9 @@ union DN_V2U16 union DN_V2U32 { - struct { DN_U32 x, y; }; - struct { DN_U32 w, h; }; + struct { DN_U32 x, y; }; + struct { DN_U32 w, h; }; + struct { DN_U32 min, max; }; DN_U32 data[2]; }; @@ -15462,23 +1500,41 @@ union DN_V2F32 DN_F32 data[2]; }; +struct DN_2V2F32 +{ + DN_V2F32 min; + DN_V2F32 max; +}; + +struct DN_V2F32Array +{ + DN_V2F32 *data; + DN_USize count; + DN_USize max; +}; + union DN_V3F32 { struct { DN_F32 x, y, z; }; struct { DN_F32 r, g, b; }; - DN_F32 data[3]; + DN_V2F32 xy; + DN_F32 data[3]; }; - union DN_V4F32 { struct { DN_F32 x, y, z, w; }; struct { DN_F32 r, g, b, a; }; - #if !defined(DN_NO_V3) DN_V3F32 rgb; DN_V3F32 xyz; - #endif - DN_F32 data[4]; + DN_F32 data[4]; +}; + +struct DN_V4F32Array +{ + DN_V4F32* data; + DN_USize count; + DN_USize max; }; DN_MSVC_WARNING_POP @@ -15493,16 +1549,23 @@ union DN_M2x3 DN_F32 row[2][3]; }; +struct DN_M2x3XForm +{ + DN_M2x3 forward; + DN_M2x3 inverse; +}; + +enum DN_M2x3ProjOrigin +{ + DN_M2x3ProjOrigin_TopLeft, + DN_M2x3ProjOrigin_Center, +}; + struct DN_Rect { DN_V2F32 pos, size; }; -struct DN_RectMinMax -{ - DN_V2F32 min, max; -}; - enum DN_RectCutClip { DN_RectCutClip_No, @@ -15523,285 +1586,5957 @@ struct DN_RectCut DN_RectCutSide side; }; -struct DN_RaycastLineIntersectV2Result +struct DN_RaycastV2 { - bool hit; // True if there was an intersection, false if the lines are parallel - DN_F32 t_a; // Distance along `dir_a` that the intersection occurred, e.g. `origin_a + (dir_a * t_a)` - DN_F32 t_b; // Distance along `dir_b` that the intersection occurred, e.g. `origin_b + (dir_b * t_b)` + bool hit; // True if there was an intersection, false if the lines are parallel + DN_F32 t_a; // Distance along `dir_a` that the intersection occurred, e.g. `origin_a + (dir_a * t_a)` + DN_F32 t_b; // Distance along `dir_b` that the intersection occurred, e.g. `origin_b + (dir_b * t_b)` }; -#define DN_V2I32_Zero DN_Literal(DN_V2I32){{(int32_t)(0), (int32_t)(0)}} -#define DN_V2I32_One DN_Literal(DN_V2I32){{(int32_t)(1), (int32_t)(1)}} -#define DN_V2I32_From1N(x) DN_Literal(DN_V2I32){{(int32_t)(x), (int32_t)(x)}} -#define DN_V2I32_From2N(x, y) DN_Literal(DN_V2I32){{(int32_t)(x), (int32_t)(y)}} -#define DN_V2I32_InitV2(xy) DN_Literal(DN_V2I32){{(int32_t)(xy).x, (int32_t)(xy).y}} +#if !defined(DN_STB_SPRINTF_HEADER_ONLY) + #define STB_SPRINTF_IMPLEMENTATION + #define STB_SPRINTF_STATIC +#endif -DN_API bool operator!= (DN_V2I32 lhs, DN_V2I32 rhs); -DN_API bool operator== (DN_V2I32 lhs, DN_V2I32 rhs); -DN_API bool operator>= (DN_V2I32 lhs, DN_V2I32 rhs); -DN_API bool operator<= (DN_V2I32 lhs, DN_V2I32 rhs); -DN_API bool operator< (DN_V2I32 lhs, DN_V2I32 rhs); -DN_API bool operator> (DN_V2I32 lhs, DN_V2I32 rhs); -DN_API DN_V2I32 operator- (DN_V2I32 lhs, DN_V2I32 rhs); -DN_API DN_V2I32 operator- (DN_V2I32 lhs); -DN_API DN_V2I32 operator+ (DN_V2I32 lhs, DN_V2I32 rhs); -DN_API DN_V2I32 operator* (DN_V2I32 lhs, DN_V2I32 rhs); -DN_API DN_V2I32 operator* (DN_V2I32 lhs, DN_F32 rhs); -DN_API DN_V2I32 operator* (DN_V2I32 lhs, int32_t rhs); -DN_API DN_V2I32 operator/ (DN_V2I32 lhs, DN_V2I32 rhs); -DN_API DN_V2I32 operator/ (DN_V2I32 lhs, DN_F32 rhs); -DN_API DN_V2I32 operator/ (DN_V2I32 lhs, int32_t rhs); -DN_API DN_V2I32 & operator*= (DN_V2I32& lhs, DN_V2I32 rhs); -DN_API DN_V2I32 & operator*= (DN_V2I32& lhs, DN_F32 rhs); -DN_API DN_V2I32 & operator*= (DN_V2I32& lhs, int32_t rhs); -DN_API DN_V2I32 & operator/= (DN_V2I32& lhs, DN_V2I32 rhs); -DN_API DN_V2I32 & operator/= (DN_V2I32& lhs, DN_F32 rhs); -DN_API DN_V2I32 & operator/= (DN_V2I32& lhs, int32_t rhs); -DN_API DN_V2I32 & operator-= (DN_V2I32& lhs, DN_V2I32 rhs); -DN_API DN_V2I32 & operator+= (DN_V2I32& lhs, DN_V2I32 rhs); +DN_MSVC_WARNING_PUSH +DN_MSVC_WARNING_DISABLE(4505) // Unused function warning +DN_GCC_WARNING_PUSH +DN_GCC_WARNING_DISABLE(-Wunused-function) +// DN: Single header generator commented out => #include "../External/stb_sprintf.h" +// NOTE: Additional *unofficial* changes +// - Adding STBSP__ASAN to STBSP__PUBLICDEC so that MSVC's ASAN does not trigger (https://github.com/nothings/stb/pull/1350) +// - Adding __attribute__((no_sanitize("undefined"))) to STBSP__ASAN for CLANG so that UBSAN does not trigger (https://github.com/nothings/stb/pull/1477) +// - Adding '%S' for DN_Str8 +// - Using defined(__wasm64__) to correctly assign stbsp__uintptr to stbsp__uint64 for a 64bit WASM target. -DN_API DN_V2I32 DN_V2I32_Min (DN_V2I32 a, DN_V2I32 b); -DN_API DN_V2I32 DN_V2I32_Max (DN_V2I32 a, DN_V2I32 b); -DN_API DN_V2I32 DN_V2I32_Abs (DN_V2I32 a); +// stb_sprintf - v1.10 - public domain snprintf() implementation +// originally by Jeff Roberts / RAD Game Tools, 2015/10/20 +// http://github.com/nothings/stb +// +// allowed types: sc uidBboXx p AaGgEef n +// lengths : hh h ll j z t I64 I32 I +// +// Contributors: +// Fabian "ryg" Giesen (reformatting) +// github:aganm (attribute format) +// +// Contributors (bugfixes): +// github:d26435 +// github:trex78 +// github:account-login +// Jari Komppa (SI suffixes) +// Rohit Nirmal +// Marcin Wojdyr +// Leonard Ritter +// Stefano Zanotti +// Adam Allison +// Arvid Gerstmann +// Markus Kolb +// +// LICENSE: +// +// See end of file for license information. -#define DN_V2U16_Zero DN_Literal(DN_V2U16){{(uint16_t)(0), (uint16_t)(0)}} -#define DN_V2U16_One DN_Literal(DN_V2U16){{(uint16_t)(1), (uint16_t)(1)}} -#define DN_V2U16_From1N(x) DN_Literal(DN_V2U16){{(uint16_t)(x), (uint16_t)(x)}} -#define DN_V2U16_From2N(x, y) DN_Literal(DN_V2U16){{(uint16_t)(x), (uint16_t)(y)}} +#ifndef STB_SPRINTF_H_INCLUDE +#define STB_SPRINTF_H_INCLUDE -DN_API bool operator!= (DN_V2U16 lhs, DN_V2U16 rhs); -DN_API bool operator== (DN_V2U16 lhs, DN_V2U16 rhs); -DN_API bool operator>= (DN_V2U16 lhs, DN_V2U16 rhs); -DN_API bool operator<= (DN_V2U16 lhs, DN_V2U16 rhs); -DN_API bool operator< (DN_V2U16 lhs, DN_V2U16 rhs); -DN_API bool operator> (DN_V2U16 lhs, DN_V2U16 rhs); -DN_API DN_V2U16 operator- (DN_V2U16 lhs, DN_V2U16 rhs); -DN_API DN_V2U16 operator+ (DN_V2U16 lhs, DN_V2U16 rhs); -DN_API DN_V2U16 operator* (DN_V2U16 lhs, DN_V2U16 rhs); -DN_API DN_V2U16 operator* (DN_V2U16 lhs, DN_F32 rhs); -DN_API DN_V2U16 operator* (DN_V2U16 lhs, int32_t rhs); -DN_API DN_V2U16 operator/ (DN_V2U16 lhs, DN_V2U16 rhs); -DN_API DN_V2U16 operator/ (DN_V2U16 lhs, DN_F32 rhs); -DN_API DN_V2U16 operator/ (DN_V2U16 lhs, int32_t rhs); -DN_API DN_V2U16 & operator*= (DN_V2U16& lhs, DN_V2U16 rhs); -DN_API DN_V2U16 & operator*= (DN_V2U16& lhs, DN_F32 rhs); -DN_API DN_V2U16 & operator*= (DN_V2U16& lhs, int32_t rhs); -DN_API DN_V2U16 & operator/= (DN_V2U16& lhs, DN_V2U16 rhs); -DN_API DN_V2U16 & operator/= (DN_V2U16& lhs, DN_F32 rhs); -DN_API DN_V2U16 & operator/= (DN_V2U16& lhs, int32_t rhs); -DN_API DN_V2U16 & operator-= (DN_V2U16& lhs, DN_V2U16 rhs); -DN_API DN_V2U16 & operator+= (DN_V2U16& lhs, DN_V2U16 rhs); +/* +Single file sprintf replacement. -#define DN_V2F32_Zero DN_Literal(DN_V2F32){{(DN_F32)(0), (DN_F32)(0)}} -#define DN_V2F32_One DN_Literal(DN_V2F32){{(DN_F32)(1), (DN_F32)(1)}} -#define DN_V2F32_From1N(x) DN_Literal(DN_V2F32){{(DN_F32)(x), (DN_F32)(x)}} -#define DN_V2F32_From2N(x, y) DN_Literal(DN_V2F32){{(DN_F32)(x), (DN_F32)(y)}} -#define DN_V2F32_FromV2I32(xy) DN_Literal(DN_V2F32){{(DN_F32)(xy).x, (DN_F32)(xy).y}} -#define DN_V2F32_FromV2U32(xy) DN_Literal(DN_V2F32){{(DN_F32)(xy).x, (DN_F32)(xy).y}} +Originally written by Jeff Roberts at RAD Game Tools - 2015/10/20. +Hereby placed in public domain. -DN_API bool operator!= (DN_V2F32 lhs, DN_V2F32 rhs); -DN_API bool operator== (DN_V2F32 lhs, DN_V2F32 rhs); -DN_API bool operator>= (DN_V2F32 lhs, DN_V2F32 rhs); -DN_API bool operator<= (DN_V2F32 lhs, DN_V2F32 rhs); -DN_API bool operator< (DN_V2F32 lhs, DN_V2F32 rhs); -DN_API bool operator> (DN_V2F32 lhs, DN_V2F32 rhs); +This is a full sprintf replacement that supports everything that +the C runtime sprintfs support, including float/double, 64-bit integers, +hex floats, field parameters (%*.*d stuff), length reads backs, etc. -DN_API DN_V2F32 operator- (DN_V2F32 lhs); -DN_API DN_V2F32 operator- (DN_V2F32 lhs, DN_V2F32 rhs); -DN_API DN_V2F32 operator- (DN_V2F32 lhs, DN_V2I32 rhs); -DN_API DN_V2F32 operator- (DN_V2F32 lhs, DN_F32 rhs); -DN_API DN_V2F32 operator- (DN_V2F32 lhs, int32_t rhs); +Why would you need this if sprintf already exists? Well, first off, +it's *much* faster (see below). It's also much smaller than the CRT +versions code-space-wise. We've also added some simple improvements +that are super handy (commas in thousands, callbacks at buffer full, +for example). Finally, the format strings for MSVC and GCC differ +for 64-bit integers (among other small things), so this lets you use +the same format strings in cross platform code. -DN_API DN_V2F32 operator+ (DN_V2F32 lhs, DN_V2F32 rhs); -DN_API DN_V2F32 operator+ (DN_V2F32 lhs, DN_V2I32 rhs); -DN_API DN_V2F32 operator+ (DN_V2F32 lhs, DN_F32 rhs); -DN_API DN_V2F32 operator+ (DN_V2F32 lhs, int32_t rhs); +It uses the standard single file trick of being both the header file +and the source itself. If you just include it normally, you just get +the header file function definitions. To get the code, you include +it from a C or C++ file and define STB_SPRINTF_IMPLEMENTATION first. -DN_API DN_V2F32 operator* (DN_V2F32 lhs, DN_V2F32 rhs); -DN_API DN_V2F32 operator* (DN_V2F32 lhs, DN_V2I32 rhs); -DN_API DN_V2F32 operator* (DN_V2F32 lhs, DN_F32 rhs); -DN_API DN_V2F32 operator* (DN_V2F32 lhs, int32_t rhs); +It only uses va_args macros from the C runtime to do it's work. It +does cast doubles to S64s and shifts and divides U64s, which does +drag in CRT code on most platforms. -DN_API DN_V2F32 operator/ (DN_V2F32 lhs, DN_V2F32 rhs); -DN_API DN_V2F32 operator/ (DN_V2F32 lhs, DN_V2I32 rhs); -DN_API DN_V2F32 operator/ (DN_V2F32 lhs, DN_F32 rhs); -DN_API DN_V2F32 operator/ (DN_V2F32 lhs, int32_t rhs); +It compiles to roughly 8K with float support, and 4K without. +As a comparison, when using MSVC static libs, calling sprintf drags +in 16K. -DN_API DN_V2F32 & operator*= (DN_V2F32& lhs, DN_V2F32 rhs); -DN_API DN_V2F32 & operator*= (DN_V2F32& lhs, DN_V2I32 rhs); -DN_API DN_V2F32 & operator*= (DN_V2F32& lhs, DN_F32 rhs); -DN_API DN_V2F32 & operator*= (DN_V2F32& lhs, int32_t rhs); +API: +==== +int stbsp_sprintf( char * buf, char const * fmt, ... ) +int stbsp_snprintf( char * buf, int count, char const * fmt, ... ) + Convert an arg list into a buffer. stbsp_snprintf always returns + a zero-terminated string (unlike regular snprintf). -DN_API DN_V2F32 & operator/= (DN_V2F32& lhs, DN_V2F32 rhs); -DN_API DN_V2F32 & operator/= (DN_V2F32& lhs, DN_V2I32 rhs); -DN_API DN_V2F32 & operator/= (DN_V2F32& lhs, DN_F32 rhs); -DN_API DN_V2F32 & operator/= (DN_V2F32& lhs, int32_t rhs); +int stbsp_vsprintf( char * buf, char const * fmt, va_list va ) +int stbsp_vsnprintf( char * buf, int count, char const * fmt, va_list va ) + Convert a va_list arg list into a buffer. stbsp_vsnprintf always returns + a zero-terminated string (unlike regular snprintf). -DN_API DN_V2F32 & operator-= (DN_V2F32& lhs, DN_V2F32 rhs); -DN_API DN_V2F32 & operator-= (DN_V2F32& lhs, DN_V2I32 rhs); -DN_API DN_V2F32 & operator-= (DN_V2F32& lhs, DN_F32 rhs); -DN_API DN_V2F32 & operator-= (DN_V2F32& lhs, int32_t rhs); +int stbsp_vsprintfcb( STBSP_SPRINTFCB * callback, void * user, char * buf, char const * fmt, va_list va ) + typedef char * STBSP_SPRINTFCB( char const * buf, void * user, int len ); + Convert into a buffer, calling back every STB_SPRINTF_MIN chars. + Your callback can then copy the chars out, print them or whatever. + This function is actually the workhorse for everything else. + The buffer you pass in must hold at least STB_SPRINTF_MIN characters. + // you return the next buffer to use or 0 to stop converting -DN_API DN_V2F32 & operator+= (DN_V2F32& lhs, DN_V2F32 rhs); -DN_API DN_V2F32 & operator+= (DN_V2F32& lhs, DN_V2I32 rhs); -DN_API DN_V2F32 & operator+= (DN_V2F32& lhs, DN_F32 rhs); -DN_API DN_V2F32 & operator+= (DN_V2F32& lhs, int32_t rhs); +void stbsp_set_separators( char comma, char period ) + Set the comma and period characters to use. -DN_API DN_V2F32 DN_V2F32_Min (DN_V2F32 a, DN_V2F32 b); -DN_API DN_V2F32 DN_V2F32_Max (DN_V2F32 a, DN_V2F32 b); -DN_API DN_V2F32 DN_V2F32_Abs (DN_V2F32 a); -DN_API DN_F32 DN_V2F32_Dot (DN_V2F32 a, DN_V2F32 b); -DN_API DN_F32 DN_V2F32_LengthSq2V2 (DN_V2F32 lhs, DN_V2F32 rhs); -DN_API bool DN_V2F32_LengthSqIsWithin2V2 (DN_V2F32 lhs, DN_V2F32 rhs, DN_F32 within_amount_sq); -DN_API DN_F32 DN_V2F32_Length2V2 (DN_V2F32 lhs, DN_V2F32 rhs); -DN_API DN_F32 DN_V2F32_LengthSq (DN_V2F32 lhs); -DN_API DN_F32 DN_V2F32_Length (DN_V2F32 lhs); -DN_API DN_V2F32 DN_V2F32_Normalise (DN_V2F32 a); -DN_API DN_V2F32 DN_V2F32_Perpendicular (DN_V2F32 a); -DN_API DN_V2F32 DN_V2F32_Reflect (DN_V2F32 in, DN_V2F32 surface); -DN_API DN_F32 DN_V2F32_Area (DN_V2F32 a); +FLOATS/DOUBLES: +=============== +This code uses a internal float->ascii conversion method that uses +doubles with error correction (double-doubles, for ~105 bits of +precision). This conversion is round-trip perfect - that is, an atof +of the values output here will give you the bit-exact double back. -#define DN_V3F32_From1N(x) DN_Literal(DN_V3F32){{(DN_F32)(x), (DN_F32)(x), (DN_F32)(x)}} -#define DN_V3F32_From3N(x, y, z) DN_Literal(DN_V3F32){{(DN_F32)(x), (DN_F32)(y), (DN_F32)(z)}} -#define DN_V3F32_FromV2F32And1N(xy, z) DN_Literal(DN_V3F32){{(DN_F32)(xy.x), (DN_F32)(xy.y), (DN_F32)(z)}} +One difference is that our insignificant digits will be different than +with MSVC or GCC (but they don't match each other either). We also +don't attempt to find the minimum length matching float (pre-MSVC15 +doesn't either). -DN_API bool operator== (DN_V3F32 lhs, DN_V3F32 rhs); -DN_API bool operator!= (DN_V3F32 lhs, DN_V3F32 rhs); -DN_API bool operator>= (DN_V3F32 lhs, DN_V3F32 rhs); -DN_API bool operator<= (DN_V3F32 lhs, DN_V3F32 rhs); -DN_API bool operator< (DN_V3F32 lhs, DN_V3F32 rhs); -DN_API bool operator> (DN_V3F32 lhs, DN_V3F32 rhs); -DN_API DN_V3F32 operator- (DN_V3F32 lhs, DN_V3F32 rhs); -DN_API DN_V3F32 operator- (DN_V3F32 lhs); -DN_API DN_V3F32 operator+ (DN_V3F32 lhs, DN_V3F32 rhs); -DN_API DN_V3F32 operator* (DN_V3F32 lhs, DN_V3F32 rhs); -DN_API DN_V3F32 operator* (DN_V3F32 lhs, DN_F32 rhs); -DN_API DN_V3F32 operator* (DN_V3F32 lhs, int32_t rhs); -DN_API DN_V3F32 operator/ (DN_V3F32 lhs, DN_V3F32 rhs); -DN_API DN_V3F32 operator/ (DN_V3F32 lhs, DN_F32 rhs); -DN_API DN_V3F32 operator/ (DN_V3F32 lhs, int32_t rhs); -DN_API DN_V3F32 & operator*= (DN_V3F32 &lhs, DN_V3F32 rhs); -DN_API DN_V3F32 & operator*= (DN_V3F32 &lhs, DN_F32 rhs); -DN_API DN_V3F32 & operator*= (DN_V3F32 &lhs, int32_t rhs); -DN_API DN_V3F32 & operator/= (DN_V3F32 &lhs, DN_V3F32 rhs); -DN_API DN_V3F32 & operator/= (DN_V3F32 &lhs, DN_F32 rhs); -DN_API DN_V3F32 & operator/= (DN_V3F32 &lhs, int32_t rhs); -DN_API DN_V3F32 & operator-= (DN_V3F32 &lhs, DN_V3F32 rhs); -DN_API DN_V3F32 & operator+= (DN_V3F32 &lhs, DN_V3F32 rhs); -DN_API DN_F32 DN_V3F32_LengthSq (DN_V3F32 a); -DN_API DN_F32 DN_V3F32_Length (DN_V3F32 a); -DN_API DN_V3F32 DN_V3F32_Normalise (DN_V3F32 a); +If you don't need float or doubles at all, define STB_SPRINTF_NOFLOAT +and you'll save 4K of code space. -#define DN_V4F32_From1N(x) DN_Literal(DN_V4F32){{(DN_F32)(x), (DN_F32)(x), (DN_F32)(x), (DN_F32)(x)}} -#define DN_V4F32_From4N(x, y, z, w) DN_Literal(DN_V4F32){{(DN_F32)(x), (DN_F32)(y), (DN_F32)(z), (DN_F32)(w)}} -#define DN_V4F32_FromV3And1N(xyz, w) DN_Literal(DN_V4F32){{xyz.x, xyz.y, xyz.z, w}} -#define DN_V4F32_FromRGBAU8(r, g, b, a) DN_Literal(DN_V4F32){{r / 255.f, g / 255.f, b / 255.f, a / 255.f}} -#define DN_V4F32_FromRGBU8(r, g, b) DN_Literal(DN_V4F32){{r / 255.f, g / 255.f, b / 255.f, 1.f}} -DN_API DN_V4F32 DN_V4F32_FromRGBU32(DN_U32 u32); -DN_API DN_V4F32 DN_V4F32_FromRGBAU32(DN_U32 u32); -#define DN_V4F32_FromV4Alpha(v4, alpha) DN_V4F32_FromV3And1N(v4.xyz, alpha) -DN_API bool operator== (DN_V4F32 lhs, DN_V4F32 rhs); -DN_API bool operator!= (DN_V4F32 lhs, DN_V4F32 rhs); -DN_API bool operator<= (DN_V4F32 lhs, DN_V4F32 rhs); -DN_API bool operator< (DN_V4F32 lhs, DN_V4F32 rhs); -DN_API bool operator> (DN_V4F32 lhs, DN_V4F32 rhs); -DN_API DN_V4F32 operator- (DN_V4F32 lhs, DN_V4F32 rhs); -DN_API DN_V4F32 operator- (DN_V4F32 lhs); -DN_API DN_V4F32 operator+ (DN_V4F32 lhs, DN_V4F32 rhs); -DN_API DN_V4F32 operator* (DN_V4F32 lhs, DN_V4F32 rhs); -DN_API DN_V4F32 operator* (DN_V4F32 lhs, DN_F32 rhs); -DN_API DN_V4F32 operator* (DN_V4F32 lhs, int32_t rhs); -DN_API DN_V4F32 operator/ (DN_V4F32 lhs, DN_F32 rhs); -DN_API DN_V4F32 & operator*= (DN_V4F32 &lhs, DN_V4F32 rhs); -DN_API DN_V4F32 & operator*= (DN_V4F32 &lhs, DN_F32 rhs); -DN_API DN_V4F32 & operator*= (DN_V4F32 &lhs, int32_t rhs); -DN_API DN_V4F32 & operator-= (DN_V4F32 &lhs, DN_V4F32 rhs); -DN_API DN_V4F32 & operator+= (DN_V4F32 &lhs, DN_V4F32 rhs); -DN_API DN_F32 DN_V4F32_Dot (DN_V4F32 a, DN_V4F32 b); +64-BIT INTS: +============ +This library also supports 64-bit integers and you can use MSVC style or +GCC style indicators (%I64d or %lld). It supports the C99 specifiers +for size_t and ptr_diff_t (%jd %zd) as well. -DN_API DN_M4 DN_M4_Identity (); -DN_API DN_M4 DN_M4_ScaleF (DN_F32 x, DN_F32 y, DN_F32 z); -DN_API DN_M4 DN_M4_Scale (DN_V3F32 xyz); -DN_API DN_M4 DN_M4_TranslateF (DN_F32 x, DN_F32 y, DN_F32 z); -DN_API DN_M4 DN_M4_Translate (DN_V3F32 xyz); -DN_API DN_M4 DN_M4_Transpose (DN_M4 mat); -DN_API DN_M4 DN_M4_Rotate (DN_V3F32 axis, DN_F32 radians); -DN_API DN_M4 DN_M4_Orthographic (DN_F32 left, DN_F32 right, DN_F32 bottom, DN_F32 top, DN_F32 z_near, DN_F32 z_far); -DN_API DN_M4 DN_M4_Perspective (DN_F32 fov /*radians*/, DN_F32 aspect, DN_F32 z_near, DN_F32 z_far); -DN_API DN_M4 DN_M4_Add (DN_M4 lhs, DN_M4 rhs); -DN_API DN_M4 DN_M4_Sub (DN_M4 lhs, DN_M4 rhs); -DN_API DN_M4 DN_M4_Mul (DN_M4 lhs, DN_M4 rhs); -DN_API DN_M4 DN_M4_Div (DN_M4 lhs, DN_M4 rhs); -DN_API DN_M4 DN_M4_AddF (DN_M4 lhs, DN_F32 rhs); -DN_API DN_M4 DN_M4_SubF (DN_M4 lhs, DN_F32 rhs); -DN_API DN_M4 DN_M4_MulF (DN_M4 lhs, DN_F32 rhs); -DN_API DN_M4 DN_M4_DivF (DN_M4 lhs, DN_F32 rhs); -DN_API DN_Str8x256 DN_M4_ColumnMajorString (DN_M4 mat); +EXTRAS: +======= +Like some GCCs, for integers and floats, you can use a ' (single quote) +specifier and commas will be inserted on the thousands: "%'d" on 12345 +would print 12,345. -DN_API bool operator== (DN_M2x3 const &lhs, DN_M2x3 const &rhs); -DN_API bool operator!= (DN_M2x3 const &lhs, DN_M2x3 const &rhs); -DN_API DN_M2x3 DN_M2x3_Identity (); -DN_API DN_M2x3 DN_M2x3_Translate (DN_V2F32 offset); -DN_API DN_M2x3 DN_M2x3_Scale (DN_V2F32 scale); -DN_API DN_M2x3 DN_M2x3_Rotate (DN_F32 radians); -DN_API DN_M2x3 DN_M2x3_Mul (DN_M2x3 m1, DN_M2x3 m2); -DN_API DN_V2F32 DN_M2x3_Mul2F32 (DN_M2x3 m1, DN_F32 x, DN_F32 y); -DN_API DN_V2F32 DN_M2x3_MulV2 (DN_M2x3 m1, DN_V2F32 v2); +For integers and floats, you can use a "$" specifier and the number +will be converted to float and then divided to get kilo, mega, giga or +tera and then printed, so "%$d" 1000 is "1.0 k", "%$.2d" 2536000 is +"2.53 M", etc. For byte values, use two $:s, like "%$$d" to turn +2536000 to "2.42 Mi". If you prefer JEDEC suffixes to SI ones, use three +$:s: "%$$$d" -> "2.42 M". To remove the space between the number and the +suffix, add "_" specifier: "%_$d" -> "2.53M". -#define DN_Rect_From2V2(pos, size) DN_Literal(DN_Rect){(pos), (size)} -#define DN_Rect_From4N(x, y, w, h) DN_Literal(DN_Rect){DN_Literal(DN_V2F32){{x, y}}, DN_Literal(DN_V2F32){{w, h}}} +In addition to octal and hexadecimal conversions, you can print +integers in binary: "%b" for 256 would print 100. -DN_API bool operator== (const DN_Rect& lhs, const DN_Rect& rhs); -DN_API DN_V2F32 DN_Rect_Center (DN_Rect rect); -DN_API bool DN_Rect_ContainsPoint (DN_Rect rect, DN_V2F32 p); -DN_API bool DN_Rect_ContainsRect (DN_Rect a, DN_Rect b); -DN_API DN_Rect DN_Rect_Expand (DN_Rect a, DN_F32 amount); -DN_API DN_Rect DN_Rect_ExpandV2 (DN_Rect a, DN_V2F32 amount); -DN_API bool DN_Rect_Intersects (DN_Rect a, DN_Rect b); -DN_API DN_Rect DN_Rect_Intersection (DN_Rect a, DN_Rect b); -DN_API DN_Rect DN_Rect_Union (DN_Rect a, DN_Rect b); -DN_API DN_RectMinMax DN_Rect_MinMax (DN_Rect a); -DN_API DN_F32 DN_Rect_Area (DN_Rect a); -DN_API DN_V2F32 DN_Rect_InterpolatedPoint (DN_Rect rect, DN_V2F32 t01); -DN_API DN_V2F32 DN_Rect_TopLeft (DN_Rect rect); -DN_API DN_V2F32 DN_Rect_TopRight (DN_Rect rect); -DN_API DN_V2F32 DN_Rect_BottomLeft (DN_Rect rect); -DN_API DN_V2F32 DN_Rect_BottomRight (DN_Rect rect); +PERFORMANCE vs MSVC 2008 32-/64-bit (GCC is even slower than MSVC): +=================================================================== +"%d" across all 32-bit ints (4.8x/4.0x faster than 32-/64-bit MSVC) +"%24d" across all 32-bit ints (4.5x/4.2x faster) +"%x" across all 32-bit ints (4.5x/3.8x faster) +"%08x" across all 32-bit ints (4.3x/3.8x faster) +"%f" across e-10 to e+10 floats (7.3x/6.0x faster) +"%e" across e-10 to e+10 floats (8.1x/6.0x faster) +"%g" across e-10 to e+10 floats (10.0x/7.1x faster) +"%f" for values near e-300 (7.9x/6.5x faster) +"%f" for values near e+300 (10.0x/9.1x faster) +"%e" for values near e-300 (10.1x/7.0x faster) +"%e" for values near e+300 (9.2x/6.0x faster) +"%.320f" for values near e-300 (12.6x/11.2x faster) +"%a" for random values (8.6x/4.3x faster) +"%I64d" for 64-bits with 32-bit values (4.8x/3.4x faster) +"%I64d" for 64-bits > 32-bit values (4.9x/5.5x faster) +"%s%s%s" for 64 char strings (7.1x/7.3x faster) +"...512 char string..." ( 35.0x/32.5x faster!) +*/ -DN_API DN_Rect DN_Rect_CutLeftClip (DN_Rect *rect, DN_F32 amount, DN_RectCutClip clip); -DN_API DN_Rect DN_Rect_CutRightClip (DN_Rect *rect, DN_F32 amount, DN_RectCutClip clip); -DN_API DN_Rect DN_Rect_CutTopClip (DN_Rect *rect, DN_F32 amount, DN_RectCutClip clip); -DN_API DN_Rect DN_Rect_CutBottomClip (DN_Rect *rect, DN_F32 amount, DN_RectCutClip clip); +#if defined(__clang__) + #if defined(__has_feature) && defined(__has_attribute) + #if __has_feature(address_sanitizer) + #if __has_attribute(__no_sanitize__) + #define STBSP__ASAN __attribute__((__no_sanitize__("address"))) + #elif __has_attribute(__no_sanitize_address__) + #define STBSP__ASAN __attribute__((__no_sanitize_address__)) + #elif __has_attribute(__no_address_safety_analysis__) + #define STBSP__ASAN __attribute__((__no_address_safety_analysis__)) + #endif + #endif + #endif +#elif defined(__GNUC__) && (__GNUC__ >= 5 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8)) + #if defined(__SANITIZE_ADDRESS__) && __SANITIZE_ADDRESS__ + #define STBSP__ASAN __attribute__((__no_sanitize_address__)) + #endif +#elif defined(_MSC_VER) + #if defined(__SANITIZE_ADDRESS__) + #define STBSP__ASAN __declspec(no_sanitize_address) + #endif +#endif -#define DN_Rect_CutLeft(rect, amount) DN_Rect_CutLeftClip(rect, amount, DN_RectCutClip_Yes) -#define DN_Rect_CutRight(rect, amount) DN_Rect_CutRightClip(rect, amount, DN_RectCutClip_Yes) -#define DN_Rect_CutTop(rect, amount) DN_Rect_CutTopClip(rect, amount, DN_RectCutClip_Yes) -#define DN_Rect_CutBottom(rect, amount) DN_Rect_CutBottomClip(rect, amount, DN_RectCutClip_Yes) +#ifndef STBSP__ASAN +#define STBSP__ASAN +#endif -#define DN_Rect_CutLeftNoClip(rect, amount) DN_Rect_CutLeftClip(rect, amount, DN_RectCutClip_No) -#define DN_Rect_CutRightNoClip(rect, amount) DN_Rect_CutRightClip(rect, amount, DN_RectCutClip_No) -#define DN_Rect_CutTopNoClip(rect, amount) DN_Rect_CutTopClip(rect, amount, DN_RectCutClip_No) -#define DN_Rect_CutBottomNoClip(rect, amount) DN_Rect_CutBottomClip(rect, amount, DN_RectCutClip_No) +#ifdef STB_SPRINTF_STATIC +#define STBSP__PUBLICDEC static STBSP__ASAN +#define STBSP__PUBLICDEF static STBSP__ASAN +#else +#ifdef __cplusplus +#define STBSP__PUBLICDEC extern "C" STBSP__ASAN +#define STBSP__PUBLICDEF extern "C" STBSP__ASAN +#else +#define STBSP__PUBLICDEC extern STBSP__ASAN +#define STBSP__PUBLICDEF STBSP__ASAN +#endif +#endif -DN_API DN_Rect DN_RectCut_Cut (DN_RectCut rect_cut, DN_V2F32 size, DN_RectCutClip clip); -#define DN_RectCut_Init(rect, side) DN_Literal(DN_RectCut){rect, side} -#define DN_RectCut_Left(rect) DN_Literal(DN_RectCut){rect, DN_RectCutSide_Left} -#define DN_RectCut_Right(rect) DN_Literal(DN_RectCut){rect, DN_RectCutSide_Right} -#define DN_RectCut_Top(rect) DN_Literal(DN_RectCut){rect, DN_RectCutSide_Top} -#define DN_RectCut_Bottom(rect) DN_Literal(DN_RectCut){rect, DN_RectCutSide_Bottom} +#if defined(__has_attribute) + #if __has_attribute(format) + #define STBSP__ATTRIBUTE_FORMAT(fmt,va) __attribute__((format(printf,fmt,va))) + #endif +#endif -DN_API DN_RaycastLineIntersectV2Result DN_Raycast_LineIntersectV2(DN_V2F32 origin_a, DN_V2F32 dir_a, DN_V2F32 origin_b, DN_V2F32 dir_b); -DN_API DN_V2F32 DN_Lerp_V2F32 (DN_V2F32 a, DN_F32 t, DN_V2F32 b); -DN_API DN_F32 DN_Lerp_F32 (DN_F32 a, DN_F32 t, DN_F32 b); -#endif // !defined(DN_MATH_H) +#ifndef STBSP__ATTRIBUTE_FORMAT +#define STBSP__ATTRIBUTE_FORMAT(fmt,va) +#endif + +#ifdef _MSC_VER +#define STBSP__NOTUSED(v) (void)(v) +#else +#define STBSP__NOTUSED(v) (void)sizeof(v) +#endif + +#include // for va_arg(), va_list() +#include // size_t, ptrdiff_t + +#ifndef STB_SPRINTF_MIN +#define STB_SPRINTF_MIN 512 // how many characters per callback +#endif +typedef char *STBSP_SPRINTFCB(const char *buf, void *user, int len); + +#ifndef STB_SPRINTF_DECORATE +#define STB_SPRINTF_DECORATE(name) stbsp_##name // define this before including if you want to change the names +#endif + +STBSP__PUBLICDEC int STB_SPRINTF_DECORATE(vsprintf)(char *buf, char const *fmt, va_list va); +STBSP__PUBLICDEC int STB_SPRINTF_DECORATE(vsnprintf)(char *buf, int count, char const *fmt, va_list va); +STBSP__PUBLICDEC int STB_SPRINTF_DECORATE(sprintf)(char *buf, char const *fmt, ...) STBSP__ATTRIBUTE_FORMAT(2,3); +STBSP__PUBLICDEC int STB_SPRINTF_DECORATE(snprintf)(char *buf, int count, char const *fmt, ...) STBSP__ATTRIBUTE_FORMAT(3,4); + +STBSP__PUBLICDEC int STB_SPRINTF_DECORATE(vsprintfcb)(STBSP_SPRINTFCB *callback, void *user, char *buf, char const *fmt, va_list va); +STBSP__PUBLICDEC void STB_SPRINTF_DECORATE(set_separators)(char comma, char period); + +#endif // STB_SPRINTF_H_INCLUDE + +#ifdef STB_SPRINTF_IMPLEMENTATION + +#define stbsp__uint32 unsigned int +#define stbsp__int32 signed int + +#ifdef _MSC_VER +#define stbsp__uint64 unsigned __int64 +#define stbsp__int64 signed __int64 +#else +#define stbsp__uint64 unsigned long long +#define stbsp__int64 signed long long +#endif +#define stbsp__uint16 unsigned short + +#ifndef stbsp__uintptr +#if defined(__ppc64__) || defined(__powerpc64__) || defined(__aarch64__) || defined(_M_X64) || defined(__x86_64__) || defined(__x86_64) || defined(__s390x__) || defined(__wasm64__) +#define stbsp__uintptr stbsp__uint64 +#else +#define stbsp__uintptr stbsp__uint32 +#endif +#endif + +#ifndef STB_SPRINTF_MSVC_MODE // used for MSVC2013 and earlier (MSVC2015 matches GCC) +#if defined(_MSC_VER) && (_MSC_VER < 1900) +#define STB_SPRINTF_MSVC_MODE +#endif +#endif + +#ifdef STB_SPRINTF_NOUNALIGNED // define this before inclusion to force stbsp_sprintf to always use aligned accesses +#define STBSP__UNALIGNED(code) +#else +#define STBSP__UNALIGNED(code) code +#endif + +#ifndef STB_SPRINTF_NOFLOAT +// internal float utility functions +static stbsp__int32 stbsp__real_to_str(char const **start, stbsp__uint32 *len, char *out, stbsp__int32 *decimal_pos, double value, stbsp__uint32 frac_digits); +static stbsp__int32 stbsp__real_to_parts(stbsp__int64 *bits, stbsp__int32 *expo, double value); +#define STBSP__SPECIAL 0x7000 +#endif + +static char stbsp__period = '.'; +static char stbsp__comma = ','; +static struct +{ + short temp; // force next field to be 2-byte aligned + char pair[201]; +} stbsp__digitpair = +{ + 0, + "00010203040506070809101112131415161718192021222324" + "25262728293031323334353637383940414243444546474849" + "50515253545556575859606162636465666768697071727374" + "75767778798081828384858687888990919293949596979899" +}; + +STBSP__PUBLICDEF void STB_SPRINTF_DECORATE(set_separators)(char pcomma, char pperiod) +{ + stbsp__period = pperiod; + stbsp__comma = pcomma; +} + +#define STBSP__LEFTJUST 1 +#define STBSP__LEADINGPLUS 2 +#define STBSP__LEADINGSPACE 4 +#define STBSP__LEADING_0X 8 +#define STBSP__LEADINGZERO 16 +#define STBSP__INTMAX 32 +#define STBSP__TRIPLET_COMMA 64 +#define STBSP__NEGATIVE 128 +#define STBSP__METRIC_SUFFIX 256 +#define STBSP__HALFWIDTH 512 +#define STBSP__METRIC_NOSPACE 1024 +#define STBSP__METRIC_1024 2048 +#define STBSP__METRIC_JEDEC 4096 + +static void stbsp__lead_sign(stbsp__uint32 fl, char *sign) +{ + sign[0] = 0; + if (fl & STBSP__NEGATIVE) { + sign[0] = 1; + sign[1] = '-'; + } else if (fl & STBSP__LEADINGSPACE) { + sign[0] = 1; + sign[1] = ' '; + } else if (fl & STBSP__LEADINGPLUS) { + sign[0] = 1; + sign[1] = '+'; + } +} + +static STBSP__ASAN stbsp__uint32 stbsp__strlen_limited(char const *s, stbsp__uint32 limit) +{ + char const * sn = s; + + // get up to 4-byte alignment + for (;;) { + if (((stbsp__uintptr)sn & 3) == 0) + break; + + if (!limit || *sn == 0) + return (stbsp__uint32)(sn - s); + + ++sn; + --limit; + } + + // scan over 4 bytes at a time to find terminating 0 + // this will intentionally scan up to 3 bytes past the end of buffers, + // but becase it works 4B aligned, it will never cross page boundaries + // (hence the STBSP__ASAN markup; the over-read here is intentional + // and harmless) + while (limit >= 4) { + stbsp__uint32 v = *(stbsp__uint32 *)sn; + // bit hack to find if there's a 0 byte in there + if ((v - 0x01010101) & (~v) & 0x80808080UL) + break; + + sn += 4; + limit -= 4; + } + + // handle the last few characters to find actual size + while (limit && *sn) { + ++sn; + --limit; + } + + return (stbsp__uint32)(sn - s); +} + +STBSP__PUBLICDEF int STB_SPRINTF_DECORATE(vsprintfcb)(STBSP_SPRINTFCB *callback, void *user, char *buf, char const *fmt, va_list va) +{ + static char hex[] = "0123456789abcdefxp"; + static char hexu[] = "0123456789ABCDEFXP"; + char *bf; + char const *f; + int tlen = 0; + + bf = buf; + f = fmt; + for (;;) { + stbsp__int32 fw, pr, tz; + stbsp__uint32 fl; + + // macros for the callback buffer stuff + #define stbsp__chk_cb_bufL(bytes) \ + { \ + int len = (int)(bf - buf); \ + if ((len + (bytes)) >= STB_SPRINTF_MIN) { \ + tlen += len; \ + if (0 == (bf = buf = callback(buf, user, len))) \ + goto done; \ + } \ + } + #define stbsp__chk_cb_buf(bytes) \ + { \ + if (callback) { \ + stbsp__chk_cb_bufL(bytes); \ + } \ + } + #define stbsp__flush_cb() \ + { \ + stbsp__chk_cb_bufL(STB_SPRINTF_MIN - 1); \ + } // flush if there is even one byte in the buffer + #define stbsp__cb_buf_clamp(cl, v) \ + cl = v; \ + if (callback) { \ + int lg = STB_SPRINTF_MIN - (int)(bf - buf); \ + if (cl > lg) \ + cl = lg; \ + } + + // fast copy everything up to the next % (or end of string) + for (;;) { + while (((stbsp__uintptr)f) & 3) { + schk1: + if (f[0] == '%') + goto scandd; + schk2: + if (f[0] == 0) + goto endfmt; + stbsp__chk_cb_buf(1); + *bf++ = f[0]; + ++f; + } + for (;;) { + // Check if the next 4 bytes contain %(0x25) or end of string. + // Using the 'hasless' trick: + // https://graphics.stanford.edu/~seander/bithacks.html#HasLessInWord + stbsp__uint32 v, c; + v = *(stbsp__uint32 *)f; + c = (~v) & 0x80808080; + if (((v ^ 0x25252525) - 0x01010101) & c) + goto schk1; + if ((v - 0x01010101) & c) + goto schk2; + if (callback) + if ((STB_SPRINTF_MIN - (int)(bf - buf)) < 4) + goto schk1; + #ifdef STB_SPRINTF_NOUNALIGNED + if(((stbsp__uintptr)bf) & 3) { + bf[0] = f[0]; + bf[1] = f[1]; + bf[2] = f[2]; + bf[3] = f[3]; + } else + #endif + { + *(stbsp__uint32 *)bf = v; + } + bf += 4; + f += 4; + } + } + scandd: + + ++f; + + // ok, we have a percent, read the modifiers first + fw = 0; + pr = -1; + fl = 0; + tz = 0; + + // flags + for (;;) { + switch (f[0]) { + // if we have left justify + case '-': + fl |= STBSP__LEFTJUST; + ++f; + continue; + // if we have leading plus + case '+': + fl |= STBSP__LEADINGPLUS; + ++f; + continue; + // if we have leading space + case ' ': + fl |= STBSP__LEADINGSPACE; + ++f; + continue; + // if we have leading 0x + case '#': + fl |= STBSP__LEADING_0X; + ++f; + continue; + // if we have thousand commas + case '\'': + fl |= STBSP__TRIPLET_COMMA; + ++f; + continue; + // if we have kilo marker (none->kilo->kibi->jedec) + case '$': + if (fl & STBSP__METRIC_SUFFIX) { + if (fl & STBSP__METRIC_1024) { + fl |= STBSP__METRIC_JEDEC; + } else { + fl |= STBSP__METRIC_1024; + } + } else { + fl |= STBSP__METRIC_SUFFIX; + } + ++f; + continue; + // if we don't want space between metric suffix and number + case '_': + fl |= STBSP__METRIC_NOSPACE; + ++f; + continue; + // if we have leading zero + case '0': + fl |= STBSP__LEADINGZERO; + ++f; + goto flags_done; + default: goto flags_done; + } + } + flags_done: + + // get the field width + if (f[0] == '*') { + fw = va_arg(va, stbsp__uint32); + ++f; + } else { + while ((f[0] >= '0') && (f[0] <= '9')) { + fw = fw * 10 + f[0] - '0'; + f++; + } + } + // get the precision + if (f[0] == '.') { + ++f; + if (f[0] == '*') { + pr = va_arg(va, stbsp__uint32); + ++f; + } else { + pr = 0; + while ((f[0] >= '0') && (f[0] <= '9')) { + pr = pr * 10 + f[0] - '0'; + f++; + } + } + } + + // handle integer size overrides + switch (f[0]) { + // are we halfwidth? + case 'h': + fl |= STBSP__HALFWIDTH; + ++f; + if (f[0] == 'h') + ++f; // QUARTERWIDTH + break; + // are we 64-bit (unix style) + case 'l': + fl |= ((sizeof(long) == 8) ? STBSP__INTMAX : 0); + ++f; + if (f[0] == 'l') { + fl |= STBSP__INTMAX; + ++f; + } + break; + // are we 64-bit on intmax? (c99) + case 'j': + fl |= (sizeof(size_t) == 8) ? STBSP__INTMAX : 0; + ++f; + break; + // are we 64-bit on size_t or ptrdiff_t? (c99) + case 'z': + fl |= (sizeof(ptrdiff_t) == 8) ? STBSP__INTMAX : 0; + ++f; + break; + case 't': + fl |= (sizeof(ptrdiff_t) == 8) ? STBSP__INTMAX : 0; + ++f; + break; + // are we 64-bit (msft style) + case 'I': + if ((f[1] == '6') && (f[2] == '4')) { + fl |= STBSP__INTMAX; + f += 3; + } else if ((f[1] == '3') && (f[2] == '2')) { + f += 3; + } else { + fl |= ((sizeof(void *) == 8) ? STBSP__INTMAX : 0); + ++f; + } + break; + default: break; + } + + // handle each replacement + switch (f[0]) { + #define STBSP__NUMSZ 512 // big enough for e308 (with commas) or e-307 + char num[STBSP__NUMSZ]; + char lead[8]; + char tail[8]; + char *s; + char const *h; + stbsp__uint32 l, n, cs; + stbsp__uint64 n64; +#ifndef STB_SPRINTF_NOFLOAT + double fv; +#endif + stbsp__int32 dp; + char const *sn; + + case 's': + // get the string + s = va_arg(va, char *); + if (s == 0) + s = (char *)"null"; + // get the length, limited to desired precision + // always limit to ~0u chars since our counts are 32b + l = stbsp__strlen_limited(s, (pr >= 0) ? pr : ~0u); + lead[0] = 0; + tail[0] = 0; + pr = 0; + dp = 0; + cs = 0; + // copy the string in + goto scopy; + + case 'S': + { + DN_Str8 str8 = va_arg(va, DN_Str8); + s = (char *)str8.data; + l = (uint32_t)str8.size; + lead[0] = 0; + tail[0] = 0; + pr = 0; + dp = 0; + cs = 0; + }goto scopy; + + case 'c': // char + // get the character + s = num + STBSP__NUMSZ - 1; + *s = (char)va_arg(va, int); + l = 1; + lead[0] = 0; + tail[0] = 0; + pr = 0; + dp = 0; + cs = 0; + goto scopy; + + case 'n': // weird write-bytes specifier + { + int *d = va_arg(va, int *); + *d = tlen + (int)(bf - buf); + } break; + +#ifdef STB_SPRINTF_NOFLOAT + case 'A': // float + case 'a': // hex float + case 'G': // float + case 'g': // float + case 'E': // float + case 'e': // float + case 'f': // float + va_arg(va, double); // eat it + s = (char *)"No float"; + l = 8; + lead[0] = 0; + tail[0] = 0; + pr = 0; + cs = 0; + STBSP__NOTUSED(dp); + goto scopy; +#else + case 'A': // hex float + case 'a': // hex float + h = (f[0] == 'A') ? hexu : hex; + fv = va_arg(va, double); + if (pr == -1) + pr = 6; // default is 6 + // read the double into a string + if (stbsp__real_to_parts((stbsp__int64 *)&n64, &dp, fv)) + fl |= STBSP__NEGATIVE; + + s = num + 64; + + stbsp__lead_sign(fl, lead); + + if (dp == -1023) + dp = (n64) ? -1022 : 0; + else + n64 |= (((stbsp__uint64)1) << 52); + n64 <<= (64 - 56); + if (pr < 15) + n64 += ((((stbsp__uint64)8) << 56) >> (pr * 4)); +// add leading chars + +#ifdef STB_SPRINTF_MSVC_MODE + *s++ = '0'; + *s++ = 'x'; +#else + lead[1 + lead[0]] = '0'; + lead[2 + lead[0]] = 'x'; + lead[0] += 2; +#endif + *s++ = h[(n64 >> 60) & 15]; + n64 <<= 4; + if (pr) + *s++ = stbsp__period; + sn = s; + + // print the bits + n = pr; + if (n > 13) + n = 13; + if (pr > (stbsp__int32)n) + tz = pr - n; + pr = 0; + while (n--) { + *s++ = h[(n64 >> 60) & 15]; + n64 <<= 4; + } + + // print the expo + tail[1] = h[17]; + if (dp < 0) { + tail[2] = '-'; + dp = -dp; + } else + tail[2] = '+'; + n = (dp >= 1000) ? 6 : ((dp >= 100) ? 5 : ((dp >= 10) ? 4 : 3)); + tail[0] = (char)n; + for (;;) { + tail[n] = '0' + dp % 10; + if (n <= 3) + break; + --n; + dp /= 10; + } + + dp = (int)(s - sn); + l = (int)(s - (num + 64)); + s = num + 64; + cs = 1 + (3 << 24); + goto scopy; + + case 'G': // float + case 'g': // float + h = (f[0] == 'G') ? hexu : hex; + fv = va_arg(va, double); + if (pr == -1) + pr = 6; + else if (pr == 0) + pr = 1; // default is 6 + // read the double into a string + if (stbsp__real_to_str(&sn, &l, num, &dp, fv, (pr - 1) | 0x80000000)) + fl |= STBSP__NEGATIVE; + + // clamp the precision and delete extra zeros after clamp + n = pr; + if (l > (stbsp__uint32)pr) + l = pr; + while ((l > 1) && (pr) && (sn[l - 1] == '0')) { + --pr; + --l; + } + + // should we use %e + if ((dp <= -4) || (dp > (stbsp__int32)n)) { + if (pr > (stbsp__int32)l) + pr = l - 1; + else if (pr) + --pr; // when using %e, there is one digit before the decimal + goto doexpfromg; + } + // this is the insane action to get the pr to match %g semantics for %f + if (dp > 0) { + pr = (dp < (stbsp__int32)l) ? l - dp : 0; + } else { + pr = -dp + ((pr > (stbsp__int32)l) ? (stbsp__int32) l : pr); + } + goto dofloatfromg; + + case 'E': // float + case 'e': // float + h = (f[0] == 'E') ? hexu : hex; + fv = va_arg(va, double); + if (pr == -1) + pr = 6; // default is 6 + // read the double into a string + if (stbsp__real_to_str(&sn, &l, num, &dp, fv, pr | 0x80000000)) + fl |= STBSP__NEGATIVE; + doexpfromg: + tail[0] = 0; + stbsp__lead_sign(fl, lead); + if (dp == STBSP__SPECIAL) { + s = (char *)sn; + cs = 0; + pr = 0; + goto scopy; + } + s = num + 64; + // handle leading chars + *s++ = sn[0]; + + if (pr) + *s++ = stbsp__period; + + // handle after decimal + if ((l - 1) > (stbsp__uint32)pr) + l = pr + 1; + for (n = 1; n < l; n++) + *s++ = sn[n]; + // trailing zeros + tz = pr - (l - 1); + pr = 0; + // dump expo + tail[1] = h[0xe]; + dp -= 1; + if (dp < 0) { + tail[2] = '-'; + dp = -dp; + } else + tail[2] = '+'; +#ifdef STB_SPRINTF_MSVC_MODE + n = 5; +#else + n = (dp >= 100) ? 5 : 4; +#endif + tail[0] = (char)n; + for (;;) { + tail[n] = '0' + dp % 10; + if (n <= 3) + break; + --n; + dp /= 10; + } + cs = 1 + (3 << 24); // how many tens + goto flt_lead; + + case 'f': // float + fv = va_arg(va, double); + doafloat: + // do kilos + if (fl & STBSP__METRIC_SUFFIX) { + double divisor; + divisor = 1000.0f; + if (fl & STBSP__METRIC_1024) + divisor = 1024.0; + while (fl < 0x4000000) { + if ((fv < divisor) && (fv > -divisor)) + break; + fv /= divisor; + fl += 0x1000000; + } + } + if (pr == -1) + pr = 6; // default is 6 + // read the double into a string + if (stbsp__real_to_str(&sn, &l, num, &dp, fv, pr)) + fl |= STBSP__NEGATIVE; + dofloatfromg: + tail[0] = 0; + stbsp__lead_sign(fl, lead); + if (dp == STBSP__SPECIAL) { + s = (char *)sn; + cs = 0; + pr = 0; + goto scopy; + } + s = num + 64; + + // handle the three decimal varieties + if (dp <= 0) { + stbsp__int32 i; + // handle 0.000*000xxxx + *s++ = '0'; + if (pr) + *s++ = stbsp__period; + n = -dp; + if ((stbsp__int32)n > pr) + n = pr; + i = n; + while (i) { + if ((((stbsp__uintptr)s) & 3) == 0) + break; + *s++ = '0'; + --i; + } + while (i >= 4) { + *(stbsp__uint32 *)s = 0x30303030; + s += 4; + i -= 4; + } + while (i) { + *s++ = '0'; + --i; + } + if ((stbsp__int32)(l + n) > pr) + l = pr - n; + i = l; + while (i) { + *s++ = *sn++; + --i; + } + tz = pr - (n + l); + cs = 1 + (3 << 24); // how many tens did we write (for commas below) + } else { + cs = (fl & STBSP__TRIPLET_COMMA) ? ((600 - (stbsp__uint32)dp) % 3) : 0; + if ((stbsp__uint32)dp >= l) { + // handle xxxx000*000.0 + n = 0; + for (;;) { + if ((fl & STBSP__TRIPLET_COMMA) && (++cs == 4)) { + cs = 0; + *s++ = stbsp__comma; + } else { + *s++ = sn[n]; + ++n; + if (n >= l) + break; + } + } + if (n < (stbsp__uint32)dp) { + n = dp - n; + if ((fl & STBSP__TRIPLET_COMMA) == 0) { + while (n) { + if ((((stbsp__uintptr)s) & 3) == 0) + break; + *s++ = '0'; + --n; + } + while (n >= 4) { + *(stbsp__uint32 *)s = 0x30303030; + s += 4; + n -= 4; + } + } + while (n) { + if ((fl & STBSP__TRIPLET_COMMA) && (++cs == 4)) { + cs = 0; + *s++ = stbsp__comma; + } else { + *s++ = '0'; + --n; + } + } + } + cs = (int)(s - (num + 64)) + (3 << 24); // cs is how many tens + if (pr) { + *s++ = stbsp__period; + tz = pr; + } + } else { + // handle xxxxx.xxxx000*000 + n = 0; + for (;;) { + if ((fl & STBSP__TRIPLET_COMMA) && (++cs == 4)) { + cs = 0; + *s++ = stbsp__comma; + } else { + *s++ = sn[n]; + ++n; + if (n >= (stbsp__uint32)dp) + break; + } + } + cs = (int)(s - (num + 64)) + (3 << 24); // cs is how many tens + if (pr) + *s++ = stbsp__period; + if ((l - dp) > (stbsp__uint32)pr) + l = pr + dp; + while (n < l) { + *s++ = sn[n]; + ++n; + } + tz = pr - (l - dp); + } + } + pr = 0; + + // handle k,m,g,t + if (fl & STBSP__METRIC_SUFFIX) { + char idx; + idx = 1; + if (fl & STBSP__METRIC_NOSPACE) + idx = 0; + tail[0] = idx; + tail[1] = ' '; + { + if (fl >> 24) { // SI kilo is 'k', JEDEC and SI kibits are 'K'. + if (fl & STBSP__METRIC_1024) + tail[idx + 1] = "_KMGT"[fl >> 24]; + else + tail[idx + 1] = "_kMGT"[fl >> 24]; + idx++; + // If printing kibits and not in jedec, add the 'i'. + if (fl & STBSP__METRIC_1024 && !(fl & STBSP__METRIC_JEDEC)) { + tail[idx + 1] = 'i'; + idx++; + } + tail[0] = idx; + } + } + }; + + flt_lead: + // get the length that we copied + l = (stbsp__uint32)(s - (num + 64)); + s = num + 64; + goto scopy; +#endif + + case 'B': // upper binary + case 'b': // lower binary + h = (f[0] == 'B') ? hexu : hex; + lead[0] = 0; + if (fl & STBSP__LEADING_0X) { + lead[0] = 2; + lead[1] = '0'; + lead[2] = h[0xb]; + } + l = (8 << 4) | (1 << 8); + goto radixnum; + + case 'o': // octal + h = hexu; + lead[0] = 0; + if (fl & STBSP__LEADING_0X) { + lead[0] = 1; + lead[1] = '0'; + } + l = (3 << 4) | (3 << 8); + goto radixnum; + + case 'p': // pointer + fl |= (sizeof(void *) == 8) ? STBSP__INTMAX : 0; + pr = sizeof(void *) * 2; + fl &= ~STBSP__LEADINGZERO; // 'p' only prints the pointer with zeros + // fall through - to X + + case 'X': // upper hex + case 'x': // lower hex + h = (f[0] == 'X') ? hexu : hex; + l = (4 << 4) | (4 << 8); + lead[0] = 0; + if (fl & STBSP__LEADING_0X) { + lead[0] = 2; + lead[1] = '0'; + lead[2] = h[16]; + } + radixnum: + // get the number + if (fl & STBSP__INTMAX) + n64 = va_arg(va, stbsp__uint64); + else + n64 = va_arg(va, stbsp__uint32); + + s = num + STBSP__NUMSZ; + dp = 0; + // clear tail, and clear leading if value is zero + tail[0] = 0; + if (n64 == 0) { + lead[0] = 0; + if (pr == 0) { + l = 0; + cs = 0; + goto scopy; + } + } + // convert to string + for (;;) { + *--s = h[n64 & ((1 << (l >> 8)) - 1)]; + n64 >>= (l >> 8); + if (!((n64) || ((stbsp__int32)((num + STBSP__NUMSZ) - s) < pr))) + break; + if (fl & STBSP__TRIPLET_COMMA) { + ++l; + if ((l & 15) == ((l >> 4) & 15)) { + l &= ~15; + *--s = stbsp__comma; + } + } + }; + // get the tens and the comma pos + cs = (stbsp__uint32)((num + STBSP__NUMSZ) - s) + ((((l >> 4) & 15)) << 24); + // get the length that we copied + l = (stbsp__uint32)((num + STBSP__NUMSZ) - s); + // copy it + goto scopy; + + case 'u': // unsigned + case 'i': + case 'd': // integer + // get the integer and abs it + if (fl & STBSP__INTMAX) { + stbsp__int64 i64 = va_arg(va, stbsp__int64); + n64 = (stbsp__uint64)i64; + if ((f[0] != 'u') && (i64 < 0)) { + n64 = (stbsp__uint64)-i64; + fl |= STBSP__NEGATIVE; + } + } else { + stbsp__int32 i = va_arg(va, stbsp__int32); + n64 = (stbsp__uint32)i; + if ((f[0] != 'u') && (i < 0)) { + n64 = (stbsp__uint32)-i; + fl |= STBSP__NEGATIVE; + } + } + +#ifndef STB_SPRINTF_NOFLOAT + if (fl & STBSP__METRIC_SUFFIX) { + if (n64 < 1024) + pr = 0; + else if (pr == -1) + pr = 1; + fv = (double)(stbsp__int64)n64; + goto doafloat; + } +#endif + + // convert to string + s = num + STBSP__NUMSZ; + l = 0; + + for (;;) { + // do in 32-bit chunks (avoid lots of 64-bit divides even with constant denominators) + char *o = s - 8; + if (n64 >= 100000000) { + n = (stbsp__uint32)(n64 % 100000000); + n64 /= 100000000; + } else { + n = (stbsp__uint32)n64; + n64 = 0; + } + if ((fl & STBSP__TRIPLET_COMMA) == 0) { + do { + s -= 2; + *(stbsp__uint16 *)s = *(stbsp__uint16 *)&stbsp__digitpair.pair[(n % 100) * 2]; + n /= 100; + } while (n); + } + while (n) { + if ((fl & STBSP__TRIPLET_COMMA) && (l++ == 3)) { + l = 0; + *--s = stbsp__comma; + --o; + } else { + *--s = (char)(n % 10) + '0'; + n /= 10; + } + } + if (n64 == 0) { + if ((s[0] == '0') && (s != (num + STBSP__NUMSZ))) + ++s; + break; + } + while (s != o) + if ((fl & STBSP__TRIPLET_COMMA) && (l++ == 3)) { + l = 0; + *--s = stbsp__comma; + --o; + } else { + *--s = '0'; + } + } + + tail[0] = 0; + stbsp__lead_sign(fl, lead); + + // get the length that we copied + l = (stbsp__uint32)((num + STBSP__NUMSZ) - s); + if (l == 0) { + *--s = '0'; + l = 1; + } + cs = l + (3 << 24); + if (pr < 0) + pr = 0; + + scopy: + // get fw=leading/trailing space, pr=leading zeros + if (pr < (stbsp__int32)l) + pr = l; + n = pr + lead[0] + tail[0] + tz; + if (fw < (stbsp__int32)n) + fw = n; + fw -= n; + pr -= l; + + // handle right justify and leading zeros + if ((fl & STBSP__LEFTJUST) == 0) { + if (fl & STBSP__LEADINGZERO) // if leading zeros, everything is in pr + { + pr = (fw > pr) ? fw : pr; + fw = 0; + } else { + fl &= ~STBSP__TRIPLET_COMMA; // if no leading zeros, then no commas + } + } + + // copy the spaces and/or zeros + if (fw + pr) { + stbsp__int32 i; + stbsp__uint32 c; + + // copy leading spaces (or when doing %8.4d stuff) + if ((fl & STBSP__LEFTJUST) == 0) + while (fw > 0) { + stbsp__cb_buf_clamp(i, fw); + fw -= i; + while (i) { + if ((((stbsp__uintptr)bf) & 3) == 0) + break; + *bf++ = ' '; + --i; + } + while (i >= 4) { + *(stbsp__uint32 *)bf = 0x20202020; + bf += 4; + i -= 4; + } + while (i) { + *bf++ = ' '; + --i; + } + stbsp__chk_cb_buf(1); + } + + // copy leader + sn = lead + 1; + while (lead[0]) { + stbsp__cb_buf_clamp(i, lead[0]); + lead[0] -= (char)i; + while (i) { + *bf++ = *sn++; + --i; + } + stbsp__chk_cb_buf(1); + } + + // copy leading zeros + c = cs >> 24; + cs &= 0xffffff; + cs = (fl & STBSP__TRIPLET_COMMA) ? ((stbsp__uint32)(c - ((pr + cs) % (c + 1)))) : 0; + while (pr > 0) { + stbsp__cb_buf_clamp(i, pr); + pr -= i; + if ((fl & STBSP__TRIPLET_COMMA) == 0) { + while (i) { + if ((((stbsp__uintptr)bf) & 3) == 0) + break; + *bf++ = '0'; + --i; + } + while (i >= 4) { + *(stbsp__uint32 *)bf = 0x30303030; + bf += 4; + i -= 4; + } + } + while (i) { + if ((fl & STBSP__TRIPLET_COMMA) && (cs++ == c)) { + cs = 0; + *bf++ = stbsp__comma; + } else + *bf++ = '0'; + --i; + } + stbsp__chk_cb_buf(1); + } + } + + // copy leader if there is still one + sn = lead + 1; + while (lead[0]) { + stbsp__int32 i; + stbsp__cb_buf_clamp(i, lead[0]); + lead[0] -= (char)i; + while (i) { + *bf++ = *sn++; + --i; + } + stbsp__chk_cb_buf(1); + } + + // copy the string + n = l; + while (n) { + stbsp__int32 i; + stbsp__cb_buf_clamp(i, n); + n -= i; + STBSP__UNALIGNED(while (i >= 4) { + *(stbsp__uint32 volatile *)bf = *(stbsp__uint32 volatile *)s; + bf += 4; + s += 4; + i -= 4; + }) + while (i) { + *bf++ = *s++; + --i; + } + stbsp__chk_cb_buf(1); + } + + // copy trailing zeros + while (tz) { + stbsp__int32 i; + stbsp__cb_buf_clamp(i, tz); + tz -= i; + while (i) { + if ((((stbsp__uintptr)bf) & 3) == 0) + break; + *bf++ = '0'; + --i; + } + while (i >= 4) { + *(stbsp__uint32 *)bf = 0x30303030; + bf += 4; + i -= 4; + } + while (i) { + *bf++ = '0'; + --i; + } + stbsp__chk_cb_buf(1); + } + + // copy tail if there is one + sn = tail + 1; + while (tail[0]) { + stbsp__int32 i; + stbsp__cb_buf_clamp(i, tail[0]); + tail[0] -= (char)i; + while (i) { + *bf++ = *sn++; + --i; + } + stbsp__chk_cb_buf(1); + } + + // handle the left justify + if (fl & STBSP__LEFTJUST) + if (fw > 0) { + while (fw) { + stbsp__int32 i; + stbsp__cb_buf_clamp(i, fw); + fw -= i; + while (i) { + if ((((stbsp__uintptr)bf) & 3) == 0) + break; + *bf++ = ' '; + --i; + } + while (i >= 4) { + *(stbsp__uint32 *)bf = 0x20202020; + bf += 4; + i -= 4; + } + while (i--) + *bf++ = ' '; + stbsp__chk_cb_buf(1); + } + } + break; + + default: // unknown, just copy code + s = num + STBSP__NUMSZ - 1; + *s = f[0]; + l = 1; + fw = fl = 0; + lead[0] = 0; + tail[0] = 0; + pr = 0; + dp = 0; + cs = 0; + goto scopy; + } + ++f; + } +endfmt: + + if (!callback) + *bf = 0; + else + stbsp__flush_cb(); + +done: + return tlen + (int)(bf - buf); +} + +// cleanup +#undef STBSP__LEFTJUST +#undef STBSP__LEADINGPLUS +#undef STBSP__LEADINGSPACE +#undef STBSP__LEADING_0X +#undef STBSP__LEADINGZERO +#undef STBSP__INTMAX +#undef STBSP__TRIPLET_COMMA +#undef STBSP__NEGATIVE +#undef STBSP__METRIC_SUFFIX +#undef STBSP__NUMSZ +#undef stbsp__chk_cb_bufL +#undef stbsp__chk_cb_buf +#undef stbsp__flush_cb +#undef stbsp__cb_buf_clamp + +// ============================================================================ +// wrapper functions + +STBSP__PUBLICDEF int STB_SPRINTF_DECORATE(sprintf)(char *buf, char const *fmt, ...) +{ + int result; + va_list va; + va_start(va, fmt); + result = STB_SPRINTF_DECORATE(vsprintfcb)(0, 0, buf, fmt, va); + va_end(va); + return result; +} + +typedef struct stbsp__context { + char *buf; + int count; + int length; + char tmp[STB_SPRINTF_MIN]; +} stbsp__context; + +static char *stbsp__clamp_callback(const char *buf, void *user, int len) +{ + stbsp__context *c = (stbsp__context *)user; + c->length += len; + + if (len > c->count) + len = c->count; + + if (len) { + if (buf != c->buf) { + const char *s, *se; + char *d; + d = c->buf; + s = buf; + se = buf + len; + do { + *d++ = *s++; + } while (s < se); + } + c->buf += len; + c->count -= len; + } + + if (c->count <= 0) + return c->tmp; + return (c->count >= STB_SPRINTF_MIN) ? c->buf : c->tmp; // go direct into buffer if you can +} + +static char * stbsp__count_clamp_callback( const char * buf, void * user, int len ) +{ + stbsp__context * c = (stbsp__context*)user; + (void) sizeof(buf); + + c->length += len; + return c->tmp; // go direct into buffer if you can +} + +STBSP__PUBLICDEF int STB_SPRINTF_DECORATE( vsnprintf )( char * buf, int count, char const * fmt, va_list va ) +{ + stbsp__context c; + + if ( (count == 0) && !buf ) + { + c.length = 0; + + STB_SPRINTF_DECORATE( vsprintfcb )( stbsp__count_clamp_callback, &c, c.tmp, fmt, va ); + } + else + { + int l; + + c.buf = buf; + c.count = count; + c.length = 0; + + STB_SPRINTF_DECORATE( vsprintfcb )( stbsp__clamp_callback, &c, stbsp__clamp_callback(0,&c,0), fmt, va ); + + // zero-terminate + l = (int)( c.buf - buf ); + if ( l >= count ) // should never be greater, only equal (or less) than count + l = count - 1; + buf[l] = 0; + } + + return c.length; +} + +STBSP__PUBLICDEF int STB_SPRINTF_DECORATE(snprintf)(char *buf, int count, char const *fmt, ...) +{ + int result; + va_list va; + va_start(va, fmt); + + result = STB_SPRINTF_DECORATE(vsnprintf)(buf, count, fmt, va); + va_end(va); + + return result; +} + +STBSP__PUBLICDEF int STB_SPRINTF_DECORATE(vsprintf)(char *buf, char const *fmt, va_list va) +{ + return STB_SPRINTF_DECORATE(vsprintfcb)(0, 0, buf, fmt, va); +} + +// ======================================================================= +// low level float utility functions + +#ifndef STB_SPRINTF_NOFLOAT + +// copies d to bits w/ strict aliasing (this compiles to nothing on /Ox) +#define STBSP__COPYFP(dest, src) \ + { \ + int cn; \ + for (cn = 0; cn < 8; cn++) \ + ((char *)&dest)[cn] = ((char *)&src)[cn]; \ + } + +// get float info +static stbsp__int32 stbsp__real_to_parts(stbsp__int64 *bits, stbsp__int32 *expo, double value) +{ + double d; + stbsp__int64 b = 0; + + // load value and round at the frac_digits + d = value; + + STBSP__COPYFP(b, d); + + *bits = b & ((((stbsp__uint64)1) << 52) - 1); + *expo = (stbsp__int32)(((b >> 52) & 2047) - 1023); + + return (stbsp__int32)((stbsp__uint64) b >> 63); +} + +static double const stbsp__bot[23] = { + 1e+000, 1e+001, 1e+002, 1e+003, 1e+004, 1e+005, 1e+006, 1e+007, 1e+008, 1e+009, 1e+010, 1e+011, + 1e+012, 1e+013, 1e+014, 1e+015, 1e+016, 1e+017, 1e+018, 1e+019, 1e+020, 1e+021, 1e+022 +}; +static double const stbsp__negbot[22] = { + 1e-001, 1e-002, 1e-003, 1e-004, 1e-005, 1e-006, 1e-007, 1e-008, 1e-009, 1e-010, 1e-011, + 1e-012, 1e-013, 1e-014, 1e-015, 1e-016, 1e-017, 1e-018, 1e-019, 1e-020, 1e-021, 1e-022 +}; +static double const stbsp__negboterr[22] = { + -5.551115123125783e-018, -2.0816681711721684e-019, -2.0816681711721686e-020, -4.7921736023859299e-021, -8.1803053914031305e-022, 4.5251888174113741e-023, + 4.5251888174113739e-024, -2.0922560830128471e-025, -6.2281591457779853e-026, -3.6432197315497743e-027, 6.0503030718060191e-028, 2.0113352370744385e-029, + -3.0373745563400371e-030, 1.1806906454401013e-032, -7.7705399876661076e-032, 2.0902213275965398e-033, -7.1542424054621921e-034, -7.1542424054621926e-035, + 2.4754073164739869e-036, 5.4846728545790429e-037, 9.2462547772103625e-038, -4.8596774326570872e-039 +}; +static double const stbsp__top[13] = { + 1e+023, 1e+046, 1e+069, 1e+092, 1e+115, 1e+138, 1e+161, 1e+184, 1e+207, 1e+230, 1e+253, 1e+276, 1e+299 +}; +static double const stbsp__negtop[13] = { + 1e-023, 1e-046, 1e-069, 1e-092, 1e-115, 1e-138, 1e-161, 1e-184, 1e-207, 1e-230, 1e-253, 1e-276, 1e-299 +}; +static double const stbsp__toperr[13] = { + 8388608, + 6.8601809640529717e+028, + -7.253143638152921e+052, + -4.3377296974619174e+075, + -1.5559416129466825e+098, + -3.2841562489204913e+121, + -3.7745893248228135e+144, + -1.7356668416969134e+167, + -3.8893577551088374e+190, + -9.9566444326005119e+213, + 6.3641293062232429e+236, + -5.2069140800249813e+259, + -5.2504760255204387e+282 +}; +static double const stbsp__negtoperr[13] = { + 3.9565301985100693e-040, -2.299904345391321e-063, 3.6506201437945798e-086, 1.1875228833981544e-109, + -5.0644902316928607e-132, -6.7156837247865426e-155, -2.812077463003139e-178, -5.7778912386589953e-201, + 7.4997100559334532e-224, -4.6439668915134491e-247, -6.3691100762962136e-270, -9.436808465446358e-293, + 8.0970921678014997e-317 +}; + +#if defined(_MSC_VER) && (_MSC_VER <= 1200) +static stbsp__uint64 const stbsp__powten[20] = { + 1, + 10, + 100, + 1000, + 10000, + 100000, + 1000000, + 10000000, + 100000000, + 1000000000, + 10000000000, + 100000000000, + 1000000000000, + 10000000000000, + 100000000000000, + 1000000000000000, + 10000000000000000, + 100000000000000000, + 1000000000000000000, + 10000000000000000000U +}; +#define stbsp__tento19th ((stbsp__uint64)1000000000000000000) +#else +static stbsp__uint64 const stbsp__powten[20] = { + 1, + 10, + 100, + 1000, + 10000, + 100000, + 1000000, + 10000000, + 100000000, + 1000000000, + 10000000000ULL, + 100000000000ULL, + 1000000000000ULL, + 10000000000000ULL, + 100000000000000ULL, + 1000000000000000ULL, + 10000000000000000ULL, + 100000000000000000ULL, + 1000000000000000000ULL, + 10000000000000000000ULL +}; +#define stbsp__tento19th (1000000000000000000ULL) +#endif + +#define stbsp__ddmulthi(oh, ol, xh, yh) \ + { \ + double ahi = 0, alo, bhi = 0, blo; \ + stbsp__int64 bt; \ + oh = xh * yh; \ + STBSP__COPYFP(bt, xh); \ + bt &= ((~(stbsp__uint64)0) << 27); \ + STBSP__COPYFP(ahi, bt); \ + alo = xh - ahi; \ + STBSP__COPYFP(bt, yh); \ + bt &= ((~(stbsp__uint64)0) << 27); \ + STBSP__COPYFP(bhi, bt); \ + blo = yh - bhi; \ + ol = ((ahi * bhi - oh) + ahi * blo + alo * bhi) + alo * blo; \ + } + +#define stbsp__ddtoS64(ob, xh, xl) \ + { \ + double ahi = 0, alo, vh, t; \ + ob = (stbsp__int64)xh; \ + vh = (double)ob; \ + ahi = (xh - vh); \ + t = (ahi - xh); \ + alo = (xh - (ahi - t)) - (vh + t); \ + ob += (stbsp__int64)(ahi + alo + xl); \ + } + +#define stbsp__ddrenorm(oh, ol) \ + { \ + double s; \ + s = oh + ol; \ + ol = ol - (s - oh); \ + oh = s; \ + } + +#define stbsp__ddmultlo(oh, ol, xh, xl, yh, yl) ol = ol + (xh * yl + xl * yh); + +#define stbsp__ddmultlos(oh, ol, xh, yl) ol = ol + (xh * yl); + +static void stbsp__raise_to_power10(double *ohi, double *olo, double d, stbsp__int32 power) // power can be -323 to +350 +{ + double ph, pl; + if ((power >= 0) && (power <= 22)) { + stbsp__ddmulthi(ph, pl, d, stbsp__bot[power]); + } else { + stbsp__int32 e, et, eb; + double p2h, p2l; + + e = power; + if (power < 0) + e = -e; + et = (e * 0x2c9) >> 14; /* %23 */ + if (et > 13) + et = 13; + eb = e - (et * 23); + + ph = d; + pl = 0.0; + if (power < 0) { + if (eb) { + --eb; + stbsp__ddmulthi(ph, pl, d, stbsp__negbot[eb]); + stbsp__ddmultlos(ph, pl, d, stbsp__negboterr[eb]); + } + if (et) { + stbsp__ddrenorm(ph, pl); + --et; + stbsp__ddmulthi(p2h, p2l, ph, stbsp__negtop[et]); + stbsp__ddmultlo(p2h, p2l, ph, pl, stbsp__negtop[et], stbsp__negtoperr[et]); + ph = p2h; + pl = p2l; + } + } else { + if (eb) { + e = eb; + if (eb > 22) + eb = 22; + e -= eb; + stbsp__ddmulthi(ph, pl, d, stbsp__bot[eb]); + if (e) { + stbsp__ddrenorm(ph, pl); + stbsp__ddmulthi(p2h, p2l, ph, stbsp__bot[e]); + stbsp__ddmultlos(p2h, p2l, stbsp__bot[e], pl); + ph = p2h; + pl = p2l; + } + } + if (et) { + stbsp__ddrenorm(ph, pl); + --et; + stbsp__ddmulthi(p2h, p2l, ph, stbsp__top[et]); + stbsp__ddmultlo(p2h, p2l, ph, pl, stbsp__top[et], stbsp__toperr[et]); + ph = p2h; + pl = p2l; + } + } + } + stbsp__ddrenorm(ph, pl); + *ohi = ph; + *olo = pl; +} + +// given a float value, returns the significant bits in bits, and the position of the +// decimal point in decimal_pos. +/-INF and NAN are specified by special values +// returned in the decimal_pos parameter. +// frac_digits is absolute normally, but if you want from first significant digits (got %g and %e), or in 0x80000000 +static stbsp__int32 stbsp__real_to_str(char const **start, stbsp__uint32 *len, char *out, stbsp__int32 *decimal_pos, double value, stbsp__uint32 frac_digits) +{ + double d; + stbsp__int64 bits = 0; + stbsp__int32 expo, e, ng, tens; + + d = value; + STBSP__COPYFP(bits, d); + expo = (stbsp__int32)((bits >> 52) & 2047); + ng = (stbsp__int32)((stbsp__uint64) bits >> 63); + if (ng) + d = -d; + + if (expo == 2047) // is nan or inf? + { + *start = (bits & ((((stbsp__uint64)1) << 52) - 1)) ? "NaN" : "Inf"; + *decimal_pos = STBSP__SPECIAL; + *len = 3; + return ng; + } + + if (expo == 0) // is zero or denormal + { + if (((stbsp__uint64) bits << 1) == 0) // do zero + { + *decimal_pos = 1; + *start = out; + out[0] = '0'; + *len = 1; + return ng; + } + // find the right expo for denormals + { + stbsp__int64 v = ((stbsp__uint64)1) << 51; + while ((bits & v) == 0) { + --expo; + v >>= 1; + } + } + } + + // find the decimal exponent as well as the decimal bits of the value + { + double ph, pl; + + // log10 estimate - very specifically tweaked to hit or undershoot by no more than 1 of log10 of all expos 1..2046 + tens = expo - 1023; + tens = (tens < 0) ? ((tens * 617) / 2048) : (((tens * 1233) / 4096) + 1); + + // move the significant bits into position and stick them into an int + stbsp__raise_to_power10(&ph, &pl, d, 18 - tens); + + // get full as much precision from double-double as possible + stbsp__ddtoS64(bits, ph, pl); + + // check if we undershot + if (((stbsp__uint64)bits) >= stbsp__tento19th) + ++tens; + } + + // now do the rounding in integer land + frac_digits = (frac_digits & 0x80000000) ? ((frac_digits & 0x7ffffff) + 1) : (tens + frac_digits); + if ((frac_digits < 24)) { + stbsp__uint32 dg = 1; + if ((stbsp__uint64)bits >= stbsp__powten[9]) + dg = 10; + while ((stbsp__uint64)bits >= stbsp__powten[dg]) { + ++dg; + if (dg == 20) + goto noround; + } + if (frac_digits < dg) { + stbsp__uint64 r; + // add 0.5 at the right position and round + e = dg - frac_digits; + if ((stbsp__uint32)e >= 24) + goto noround; + r = stbsp__powten[e]; + bits = bits + (r / 2); + if ((stbsp__uint64)bits >= stbsp__powten[dg]) + ++tens; + bits /= r; + } + noround:; + } + + // kill long trailing runs of zeros + if (bits) { + stbsp__uint32 n; + for (;;) { + if (bits <= 0xffffffff) + break; + if (bits % 1000) + goto donez; + bits /= 1000; + } + n = (stbsp__uint32)bits; + while ((n % 1000) == 0) + n /= 1000; + bits = n; + donez:; + } + + // convert to string + out += 64; + e = 0; + for (;;) { + stbsp__uint32 n; + char *o = out - 8; + // do the conversion in chunks of U32s (avoid most 64-bit divides, worth it, constant denomiators be damned) + if (bits >= 100000000) { + n = (stbsp__uint32)(bits % 100000000); + bits /= 100000000; + } else { + n = (stbsp__uint32)bits; + bits = 0; + } + while (n) { + out -= 2; + *(stbsp__uint16 *)out = *(stbsp__uint16 *)&stbsp__digitpair.pair[(n % 100) * 2]; + n /= 100; + e += 2; + } + if (bits == 0) { + if ((e) && (out[0] == '0')) { + ++out; + --e; + } + break; + } + while (out != o) { + *--out = '0'; + ++e; + } + } + + *decimal_pos = tens; + *start = out; + *len = e; + return ng; +} + +#undef stbsp__ddmulthi +#undef stbsp__ddrenorm +#undef stbsp__ddmultlo +#undef stbsp__ddmultlos +#undef STBSP__SPECIAL +#undef STBSP__COPYFP + +#endif // STB_SPRINTF_NOFLOAT + +// clean up +#undef stbsp__uint16 +#undef stbsp__uint32 +#undef stbsp__int32 +#undef stbsp__uint64 +#undef stbsp__int64 +#undef STBSP__UNALIGNED + +#endif // STB_SPRINTF_IMPLEMENTATION + +/* +------------------------------------------------------------------------------ +This software is available under 2 licenses -- choose whichever you prefer. +------------------------------------------------------------------------------ +ALTERNATIVE A - MIT License +Copyright (c) 2017 Sean Barrett +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +------------------------------------------------------------------------------ +ALTERNATIVE B - Public Domain (www.unlicense.org) +This is free and unencumbered software released into the public domain. +Anyone is free to copy, modify, publish, use, compile, sell, or distribute this +software, either in source code form or as a compiled binary, for any purpose, +commercial or non-commercial, and by any means. +In jurisdictions that recognize copyright laws, the author or authors of this +software dedicate any and all copyright interest in the software to the public +domain. We make this dedication for the benefit of the public at large and to +the detriment of our heirs and successors. We intend this dedication to be an +overt act of relinquishment in perpetuity of all present and future rights to +this software under copyright law. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +------------------------------------------------------------------------------ +*/ +DN_GCC_WARNING_POP +DN_MSVC_WARNING_POP + +#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_size, void const *rhs, DN_USize rhs_size); +DN_API bool DN_MemEq (void const *lhs, DN_USize lhs_size, void const *rhs, DN_USize rhs_size); +DN_API bool DN_MemEqUnsafe (void const *lhs, void const *rhs, DN_USize size); + +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) \ + ) +#if defined(DN_64_BIT) + #define DN_ByteSwapUSize(val) DN_ByteSwap64(val) +#else + #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 void DN_TicketMutex_Begin (DN_TicketMutex *mutex); +DN_API void DN_TicketMutex_End (DN_TicketMutex *mutex); +DN_API DN_UInt DN_TicketMutex_MakeTicket (DN_TicketMutex *mutex); +DN_API void DN_TicketMutex_BeginTicket (DN_TicketMutex const *mutex, DN_UInt ticket); +DN_API bool DN_TicketMutex_CanLock (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); +#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_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 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 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 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_UInt DN_SaturateCastI64ToUInt (DN_I64 val); +DN_API DN_ISize 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 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_MemStats DN_MemStatsSum (DN_MemStats lhs, DN_MemStats rhs); +DN_API DN_MemStats DN_MemStatsSumArray (DN_MemStats const *array, DN_USize size); + +DN_API DN_MemList DN_MemListFromBuffer (void *buffer, DN_USize size, DN_MemFlags flags); +DN_API DN_MemList DN_MemListFromMemFuncs (DN_U64 reserve, DN_U64 commit, DN_MemFlags flags, DN_MemFuncs mem_funcs); +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, uint8_t align, DN_ZMem zmem); +DN_API void * DN_MemListAllocContiguous (DN_MemList *mem, DN_U64 size, uint8_t 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 *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 void DN_ArenaUAFCheck (DN_Arena *arena); +#define DN_ArenaDeref(arena_view) (DN_ArenaUAFCheck(arena_view), (arena_view)->arena) +DN_API DN_Arena DN_ArenaFromMemList (DN_MemList *mem); +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, uint8_t align, DN_ZMem z_mem); +DN_API void* DN_ArenaAllocContiguous (DN_Arena *arena, DN_U64 size, uint8_t align, DN_ZMem z_arena); +DN_API void* DN_ArenaCopy (DN_Arena *arena, void const *data, DN_U64 size, uint8_t align); + +#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)) + +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_ErrSink* DN_ErrSinkBegin_ (DN_ErrSink *err, DN_ErrSinkMode mode, DN_CallSite call_site); +#define DN_ErrSinkBegin(err, mode) DN_ErrSinkBegin_(err, mode, DN_CALL_SITE) +#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_CALL_SITE, 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_CALL_SITE, 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_CALL_SITE, 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_CALL_SITE, 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_CALL_SITE, 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_CALL_SITE, 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_CALL_SITE, fmt, ##__VA_ARGS__) + +DN_API void DN_TCInit (DN_TCCore *tc, DN_U64 thread_id, DN_Arena *main_arena, DN_Arena *temp_a_arena, DN_Arena *temp_b_arena, DN_Arena *err_sink_arena); +DN_API void DN_TCInitFromMemFuncs (DN_TCCore *tc, DN_U64 thread_id, DN_TCInitArgs *args, DN_MemFuncs mem_funcs); +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_TCTempArena (DN_Arena **conflicts, DN_USize count); +DN_API DN_TCScratch DN_TCScratchBegin (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 DN_U64FromResult DN_U64FromStr8 (DN_Str8 string, char separator); +DN_API DN_U64FromResult DN_U64FromPtr (void const *data, DN_USize size, char separator); +DN_API DN_U64 DN_U64FromPtrUnsafe (void const *data, DN_USize size, char separator); +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_I64FromResult DN_I64FromStr8 (DN_Str8 string, char separator); +DN_API DN_I64FromResult DN_I64FromPtr (void const *data, DN_USize size, char separator); +DN_API DN_I64 DN_I64FromPtrUnsafe (void const *data, DN_USize size, char separator); + +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 count); +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_USize DN_FmtVSize (DN_FMT_ATTRIB char const *fmt, va_list args); +DN_API DN_USize DN_FmtSize (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_CStr8Size (char const *src); +DN_API DN_USize DN_CStr16Size (wchar_t const *src); + +#define DN_Str16Lit(string) DN_Str16{(wchar_t *)(string), sizeof(string)/sizeof(string[0]) - 1} +#define DN_Str16FromPtr(data, size) DN_Literal(DN_Str16){(wchar_t *)(data), (DN_USize)(size)} + +#define DN_Str8Lit(c_str) DN_Literal(DN_Str8){(char *)(c_str), sizeof(c_str) - 1} +#define DN_Str8PrintFmt(string) (int)((string).size), (string).data +#define DN_Str8FromPtr(data, size) DN_Literal(DN_Str8){(char *)(data), (DN_USize)(size)} +#define DN_Str8FromStruct(ptr) DN_Str8FromPtr((ptr)->data, (ptr)->size) +#define DN_Str8FromLitArray(c_array) DN_Str8FromPtr(c_array, DN_ArrayCountU(c_array)) +DN_API DN_Str8 DN_Str8AllocArena (DN_USize size, DN_ZMem z_mem, DN_Arena *arena); +DN_API DN_Str8 DN_Str8AllocPool (DN_USize size, DN_Pool *pool); +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 size, DN_Arena *arena); +DN_API DN_Str8 DN_Str8FromPtrPool (void const *data, DN_USize size, DN_Pool *pool); +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_Str8FromFmtVArena (DN_Arena *arena, DN_FMT_ATTRIB char const *fmt, va_list args); +DN_API DN_Str8 DN_Str8FromFmtArena (DN_Arena *arena, DN_FMT_ATTRIB char const *fmt, ...); +DN_API DN_Str8 DN_Str8FromFmtVPool (DN_Pool *pool, DN_FMT_ATTRIB char const *fmt, va_list args); +DN_API DN_Str8 DN_Str8FromFmtPool (DN_Pool *pool, DN_FMT_ATTRIB char const *fmt, ...); +DN_API DN_Str8 DN_Str8FromByteCountType (DN_ByteCountType type); +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 separator); +DN_API bool DN_Str8IsAll (DN_Str8 string, DN_Str8IsAllType is_all); +DN_API char * DN_Str8End (DN_Str8 string); +DN_API DN_Str8 DN_Str8Subset (DN_Str8 string, DN_USize offset, DN_USize size); +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_Str8EqCase_Sensitive); +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_Str8EqCase_Sensitive); +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_Str8EqCase_Sensitive); +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_Str8EqCase_Sensitive); +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_Str8EqCase_Sensitive); +DN_API DN_Str8 DN_Str8TrimAround (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 size); +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_Str8PadNewLines (DN_Str8 string, DN_Str8 pad_string, DN_Arena *arena); +DN_API DN_Str8 DN_Str8LineBreakStr8 (DN_Str8 src, DN_USize desired_width, 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_Str8SliceRender (DN_Str8Slice array, DN_Str8 separator, DN_Arena *arena); +DN_API DN_Str8 DN_Str8RenderSpaceSep (DN_Str8Slice 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 separator, 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 size); +DN_API DN_Str8Builder DN_Str8BuilderFromStr8PtrCopy (DN_Arena *arena, DN_Str8 const *strings, DN_USize size); +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 size, DN_Str8BuilderAdd add); +DN_API bool DN_Str8BuilderAddArrayCopy (DN_Str8Builder *builder, DN_Str8 const *strings, DN_USize size, DN_Str8BuilderAdd add); +DN_API bool DN_Str8BuilderAddFV (DN_Str8Builder *builder, DN_Str8BuilderAdd add, DN_FMT_ATTRIB char const *fmt, va_list args); +#define DN_Str8BuilderAppendArrayRef(builder, strings, size) DN_Str8BuilderAddArrayRef(builder, strings, size, DN_Str8BuilderAdd_Append) +#define DN_Str8BuilderAppendArrayCopy(builder, strings, size) DN_Str8BuilderAddArrayCopy(builder, strings, size, DN_Str8BuilderAdd_Append) +#define DN_Str8BuilderAppendSliceRef(builder, slice) DN_Str8BuilderAddArrayRef(builder, slice.data, slice.size, DN_Str8BuilderAdd_Append) +#define DN_Str8BuilderAppendSliceCopy(builder, slice) DN_Str8BuilderAddArrayCopy(builder, slice.data, slice.size, DN_Str8BuilderAdd_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_Str8BuilderAdd_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 size); +DN_API bool DN_Str8BuilderAppendBytesCopy (DN_Str8Builder *builder, void const *ptr, DN_USize size); +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_Str8BuilderAdd_Prepend) +#define DN_Str8BuilderPrependArrayCopy(builder, strings, size) DN_Str8BuilderAddArrayCopy(builder, strings, size, DN_Str8BuilderAdd_Prepend) +#define DN_Str8BuilderPrependSliceRef(builder, slice) DN_Str8BuilderAddArrayRef(builder, slice.data, slice.size, DN_Str8BuilderAdd_Prepend) +#define DN_Str8BuilderPrependSliceCopy(builder, slice) DN_Str8BuilderAddArrayCopy(builder, slice.data, slice.size, DN_Str8BuilderAdd_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_Str8BuilderAdd_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_Str8BuilderBuild (DN_Str8Builder const *builder, DN_Arena *arena); +DN_API DN_Str8 DN_Str8BuilderBuildDelimited (DN_Str8Builder const *builder, DN_Str8 delimiter, DN_Arena *arena); +DN_API DN_Str8Slice DN_Str8BuilderBuildSlice (DN_Str8Builder const *builder, DN_Arena *arena); + +DN_API int DN_UTF8Encode (DN_U8 utf8[4], DN_U32 codepoint); +DN_API int DN_UTF16Encode (DN_U16 utf16[2], DN_U32 codepoint); +DN_API DN_UTF8DecodeResult DN_UTF8Decode (DN_Str8 stream); +DN_API bool DN_UTF8DecodeIterate (DN_UTF8DecodeIterator *it, DN_Str8 utf8); +DN_API DN_USize DN_USizeCodepointCountFromUTF8 (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_USize DN_BytesFromHex (DN_Str8 hex, void *dest, DN_USize dest_count); +DN_API DN_Str8 DN_BytesFromHexArena (DN_Str8 hex, DN_Arena *arena); +DN_API DN_USize DN_BytesFromHexPtr (char const *hex, DN_USize hex_count, void *dest, DN_USize dest_count); +DN_API DN_Str8 DN_BytesFromHexPtrArena (char const *hex, DN_USize hex_count, DN_Arena *arena); +DN_API DN_Str8 DN_BytesFromHexPtrPool (char const *hex, DN_USize hex_count, DN_Pool *pool); +DN_API DN_U8x16 DN_BytesFromHex32Ptr (char const *hex, DN_USize hex_count); +DN_API DN_U8x32 DN_BytesFromHex64Ptr (char const *hex, DN_USize hex_count); + +DN_API DN_HexU64Str8 DN_HexFromU64 (DN_U64 value, DN_HexFromU64Type type); +DN_API DN_USize DN_HexFromPtrBytes (void const *bytes, DN_USize bytes_count, void *hex, DN_USize hex_count, DN_TrimLeadingZero trim_leading_z); +DN_API DN_Str8 DN_HexFromPtrBytesArena (void const *bytes, DN_USize bytes_count, DN_Arena *arena, DN_TrimLeadingZero trim_leading_z); +DN_API DN_USize DN_HexFromStr8Bytes (void const *bytes, DN_USize bytes_count, void *hex, DN_USize hex_count, DN_TrimLeadingZero trim_leading_z); +DN_API DN_Hex32 DN_Hex32FromPtr16b (void const *bytes, DN_USize bytes_count, DN_TrimLeadingZero trim_leading_z); +DN_API DN_Hex64 DN_Hex64FromPtr32b (void const *bytes, DN_USize bytes_count, DN_TrimLeadingZero trim_leading_z); +DN_API DN_Hex128 DN_Hex128FromPtr64b (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 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_ByteCountResult DN_ByteCountFromType (DN_U64 bytes, DN_ByteCountType type); +#define DN_ByteCount(bytes) DN_ByteCountFromType(bytes, DN_ByteCountType_Auto) +DN_API DN_Str8x32 DN_ByteCountStr8x32FromType (DN_U64 bytes, DN_ByteCountType type); +#define DN_ByteCountStr8x32(bytes) DN_ByteCountStr8x32FromType(bytes, DN_ByteCountType_Auto) + +#define DN_ProfilerZoneLoop(prof, name, index) \ + DN_ProfilerZone DN_UniqueName(zone_) = DN_ProfilerBeginZone(prof, DN_Str8Lit(name), index), DN_UniqueName(dummy_) = {}; \ + DN_UniqueName(dummy_).begin_tsc == 0; \ + DN_ProfilerEndZone(prof, DN_UniqueName(zone_)), DN_UniqueName(dummy_).begin_tsc = 1 + +#define DN_ProfilerZoneLoopAuto(prof, name) DN_ProfilerZoneLoop(prof, name, __COUNTER__ + 1) +DN_API DN_Profiler DN_ProfilerInit (DN_ProfilerAnchor *anchors, DN_USize count, DN_USize anchors_per_frame, DN_ProfilerTSCNowFunc *tsc_now, DN_U64 tsc_frequency); +DN_API DN_ProfilerZone DN_ProfilerBeginZone (DN_Profiler *profiler, DN_Str8 name, DN_U16 anchor_index); +#define DN_ProfilerBeginZoneAuto(prof, name) DN_ProfilerBeginZone(prof, DN_Str8Lit(name), __COUNTER__ + 1) +DN_API void DN_ProfilerEndZone (DN_Profiler *profiler, DN_ProfilerZone zone); +DN_API DN_USize DN_ProfilerFrameCount (DN_Profiler const *profiler); +DN_API DN_ProfilerAnchorArray DN_ProfilerFrameAnchorsFromIndex (DN_Profiler *profiler, DN_USize frame_index); +DN_API DN_ProfilerAnchorArray DN_ProfilerFrameAnchors (DN_Profiler *profiler); +DN_API void DN_ProfilerNewFrame (DN_Profiler *profiler); +DN_API void DN_ProfilerDump (DN_Profiler *profiler); +DN_API DN_F64 DN_ProfilerSecFromTSC (DN_Profiler *profiler, DN_U64 duration_tsc); +DN_API DN_F64 DN_ProfilerMsFromTSC (DN_Profiler *profiler, DN_U64 duration_tsc); + +DN_API DN_PCG32 DN_PCG32Init (DN_U64 seed); +DN_API DN_U32 DN_PCG32Next (DN_PCG32 *rng); +DN_API DN_U64 DN_PCG32Next64 (DN_PCG32 *rng); +DN_API DN_U32 DN_PCG32Range (DN_PCG32 *rng, DN_U32 low, DN_U32 high); +DN_API DN_F32 DN_PCG32NextF32 (DN_PCG32 *rng); +DN_API DN_F64 DN_PCG32NextF64 (DN_PCG32 *rng); +DN_API void DN_PCG32Advance (DN_PCG32 *rng, DN_U64 delta); + +#if !defined(DN_FNV1A32_SEED) + #define DN_FNV1A32_SEED 2166136261U +#endif + +#if !defined(DN_FNV1A64_SEED) + #define DN_FNV1A64_SEED 14695981039346656037ULL +#endif + +DN_API DN_U32 DN_FNV1AHashU32FromBytes (void const *bytes, DN_USize size, DN_U32 seed); +DN_API DN_U64 DN_FNV1AHashU64FromBytes (void const *bytes, DN_USize size, DN_U64 seed); + +DN_API DN_U32 DN_MurmurHash3HashU32FromBytesX86 (void const *bytes, int len, DN_U32 seed); +DN_API DN_MurmurHash3 DN_MurmurHash3HashU128FromBytesX64 (void const *bytes, int len, DN_U32 seed); +DN_API DN_U64 DN_MurmurHash3HashU64FromBytesX64 (void const *bytes, int len, DN_U32 seed); +DN_API DN_U32 DN_MurmurHash3HashU32FromBytesX64 (void const *bytes, int len, DN_U32 seed); + +#if defined(DN_64_BIT) + #define DN_MurmurHash3HashU32FromBytes(bytes, len, seed) DN_MurmurHash3HashU32FromBytesX64(bytes, len, seed) +#else + #define DN_MurmurHash3HashU32FromBytes(bytes, len, seed) DN_MurmurHash3HashU32FromBytesX86(bytes, len, seed) +#endif + +#define DN_ANSICodeBoldLit "\x1b[1m" +#define DN_ANSICodeResetLit "\x1b[0m" +DN_API DN_Str8x32 DN_Str8x32FromANSIColourCodeU8RGB (DN_ANSIColourMode mode, DN_U8 r, DN_U8 g, DN_U8 b); +DN_API DN_Str8x32 DN_Str8x32FromANSIColourCodeV3F32RGB255 (DN_ANSIColourMode mode, DN_V3F32 rgb_255); +DN_API DN_Str8x32 DN_Str8x32FromANSIColourCodeU32RGB (DN_ANSIColourMode mode, DN_U32 value); +DN_API DN_Str8 DN_Str8FromStr8ANSIColourU8RGBArena (DN_ANSIColourMode mode, DN_Str8 str8, DN_U8 r, DN_U8 g, DN_U8 b, DN_Arena *arena); +DN_API DN_Str8 DN_Str8FromStr8ANSIColourV3F32RGB255Arena (DN_ANSIColourMode mode, DN_Str8 str8, DN_V3F32 rgb_255, DN_Arena *arena); +DN_API DN_Str8 DN_Str8FromFmtANSIColourU8RGBArena (DN_ANSIColourMode mode, DN_U8 r, DN_U8 g, DN_U8 b, DN_Arena *arena, char const *fmt, ...); +DN_API DN_Str8 DN_Str8FromFmtANSIColourV3F32RGB255Arena (DN_ANSIColourMode mode, DN_V3F32 rgb_255, DN_Arena *arena, char const *fmt, ...); + +DN_API DN_LogPrefixSize DN_LogMakePrefix (DN_LogStyle style, DN_LogTypeParam type, DN_CallSite call_site, DN_LogDate date, char *dest, DN_USize dest_size); +DN_API void DN_LogSetPrintFunc (DN_LogPrintFunc *print_func, void *user_data); +DN_API void DN_LogPrint (DN_LogTypeParam type, DN_CallSite call_site, DN_LogFlags flags, DN_FMT_ATTRIB char const *fmt, ...); +DN_API DN_LogTypeParam DN_LogTypeParamFromType (DN_LogType type); +#define DN_LogF(type, fmt, ...) DN_LogPrint(DN_LogTypeParamFromType(type), DN_CALL_SITE, DN_LogFlags_Nil, fmt, ##__VA_ARGS__) + +#define DN_LogDebugF(fmt, ...) DN_LogPrint(DN_LogTypeParamFromType(DN_LogType_Debug), DN_CALL_SITE, DN_LogFlags_Nil, fmt, ##__VA_ARGS__) +#define DN_LogInfoF(fmt, ...) DN_LogPrint(DN_LogTypeParamFromType(DN_LogType_Info), DN_CALL_SITE, DN_LogFlags_Nil, fmt, ##__VA_ARGS__) +#define DN_LogWarningF(fmt, ...) DN_LogPrint(DN_LogTypeParamFromType(DN_LogType_Warning), DN_CALL_SITE, DN_LogFlags_Nil, fmt, ##__VA_ARGS__) +#define DN_LogErrorF(fmt, ...) DN_LogPrint(DN_LogTypeParamFromType(DN_LogType_Error), DN_CALL_SITE, DN_LogFlags_Nil, fmt, ##__VA_ARGS__) + +#define DN_LogFlagF(type, flags, fmt, ...) DN_LogPrint(DN_LogTypeParamFromType(type), DN_CALL_SITE, flags, fmt, ##__VA_ARGS__) +#define DN_LogFlagDebugF(flags, fmt, ...) DN_LogPrint(DN_LogTypeParamFromType(DN_LogType_Debug), DN_CALL_SITE, flags, fmt, ##__VA_ARGS__) +#define DN_LogFlagInfoF(flags, fmt, ...) DN_LogPrint(DN_LogTypeParamFromType(DN_LogType_Info), DN_CALL_SITE, flags, fmt, ##__VA_ARGS__) +#define DN_LogFlagWarningF(flags, fmt, ...) DN_LogPrint(DN_LogTypeParamFromType(DN_LogType_Warning), DN_CALL_SITE, flags, fmt, ##__VA_ARGS__) +#define DN_LogFlagErrorF(flags, fmt, ...) DN_LogPrint(DN_LogTypeParamFromType(DN_LogType_Error), DN_CALL_SITE, flags, fmt, ##__VA_ARGS__) + + +// NOTE: OS primitives that the OS layer can provide for the base layer but is optional. +#if defined(DN_FREESTANDING) +#define DN_StackTraceWalk(...) +#define DN_StackTraceWalkResultIterate(...) +#define DN_StackTraceWalkResultToStr8(...) DN_Str8Lit("N/A") +#define DN_StackTraceWalkStr8(...) DN_Str8Lit("N/A") +#define DN_StackTraceWalkStr8FromHeap(...) DN_Str8Lit("N/A") +#define DN_StackTraceGetFrames(...) +#define DN_StackTraceRawFrameToFrame(...) +#define DN_StackTracePrint(...) +#define DN_StackTraceReloadSymbols(...) +#else +DN_API DN_StackTraceWalkResult DN_StackTraceWalk (DN_Arena *arena, DN_U16 limit); +DN_API bool DN_StackTraceWalkResultIterate (DN_StackTraceWalkResultIterator *it, DN_StackTraceWalkResult const *walk); +DN_API DN_Str8 DN_StackTraceWalkResultToStr8 (DN_Arena *arena, DN_StackTraceWalkResult const *walk, DN_U16 skip); +DN_API DN_Str8 DN_StackTraceWalkStr8 (DN_Arena *arena, DN_U16 limit, DN_U16 skip); +DN_API DN_Str8 DN_StackTraceWalkStr8FromHeap (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 (); +#endif + +DN_API DN_F32 DN_F32Lerp (DN_F32 a, DN_F32 t, DN_F32 b); +DN_API DN_F32 DN_F32Floor (DN_F32 val); +DN_API DN_F32 DN_F32Ceil (DN_F32 val); +DN_API DN_F32 DN_F32RoundHalfUp (DN_F32 val); + +#define DN_V2I32Zero DN_Literal(DN_V2I32){{(DN_I32)(0), (DN_I32)(0)}} +#define DN_V2I32One DN_Literal(DN_V2I32){{(DN_I32)(1), (DN_I32)(1)}} +#define DN_V2I32From1N(x) DN_Literal(DN_V2I32){{(DN_I32)(x), (DN_I32)(x)}} +#define DN_V2I32From2N(x, y) DN_Literal(DN_V2I32){{(DN_I32)(x), (DN_I32)(y)}} +#define DN_V2I32InitV2(xy) DN_Literal(DN_V2I32){{(DN_I32)(xy).x, (DN_I32)(xy).y}} + +DN_API bool operator!= (DN_V2I32 lhs, DN_V2I32 rhs); +DN_API bool operator== (DN_V2I32 lhs, DN_V2I32 rhs); +DN_API bool operator>= (DN_V2I32 lhs, DN_V2I32 rhs); +DN_API bool operator<= (DN_V2I32 lhs, DN_V2I32 rhs); +DN_API bool operator< (DN_V2I32 lhs, DN_V2I32 rhs); +DN_API bool operator> (DN_V2I32 lhs, DN_V2I32 rhs); +DN_API DN_V2I32 operator- (DN_V2I32 lhs, DN_V2I32 rhs); +DN_API DN_V2I32 operator- (DN_V2I32 lhs); +DN_API DN_V2I32 operator+ (DN_V2I32 lhs, DN_V2I32 rhs); +DN_API DN_V2I32 operator* (DN_V2I32 lhs, DN_V2I32 rhs); +DN_API DN_V2I32 operator* (DN_V2I32 lhs, DN_F32 rhs); +DN_API DN_V2I32 operator* (DN_V2I32 lhs, DN_I32 rhs); +DN_API DN_V2I32 operator/ (DN_V2I32 lhs, DN_V2I32 rhs); +DN_API DN_V2I32 operator/ (DN_V2I32 lhs, DN_F32 rhs); +DN_API DN_V2I32 operator/ (DN_V2I32 lhs, DN_I32 rhs); +DN_API DN_V2I32& operator*= (DN_V2I32& lhs, DN_V2I32 rhs); +DN_API DN_V2I32& operator*= (DN_V2I32& lhs, DN_F32 rhs); +DN_API DN_V2I32& operator*= (DN_V2I32& lhs, DN_I32 rhs); +DN_API DN_V2I32& operator/= (DN_V2I32& lhs, DN_V2I32 rhs); +DN_API DN_V2I32& operator/= (DN_V2I32& lhs, DN_F32 rhs); +DN_API DN_V2I32& operator/= (DN_V2I32& lhs, DN_I32 rhs); +DN_API DN_V2I32& operator-= (DN_V2I32& lhs, DN_V2I32 rhs); +DN_API DN_V2I32& operator+= (DN_V2I32& lhs, DN_V2I32 rhs); + +DN_API DN_V2I32 DN_V2I32Min (DN_V2I32 a, DN_V2I32 b); +DN_API DN_V2I32 DN_V2I32Max (DN_V2I32 a, DN_V2I32 b); +DN_API DN_V2I32 DN_V2I32Abs (DN_V2I32 a); + +#define DN_V2U16Zero DN_Literal(DN_V2U16){{(DN_U16)(0), (DN_U16)(0)}} +#define DN_V2U16One DN_Literal(DN_V2U16){{(DN_U16)(1), (DN_U16)(1)}} +#define DN_V2U16From1N(x) DN_Literal(DN_V2U16){{(DN_U16)(x), (DN_U16)(x)}} +#define DN_V2U16From2N(x, y) DN_Literal(DN_V2U16){{(DN_U16)(x), (DN_U16)(y)}} + +DN_API bool operator!= (DN_V2U16 lhs, DN_V2U16 rhs); +DN_API bool operator== (DN_V2U16 lhs, DN_V2U16 rhs); +DN_API bool operator>= (DN_V2U16 lhs, DN_V2U16 rhs); +DN_API bool operator<= (DN_V2U16 lhs, DN_V2U16 rhs); +DN_API bool operator< (DN_V2U16 lhs, DN_V2U16 rhs); +DN_API bool operator> (DN_V2U16 lhs, DN_V2U16 rhs); +DN_API DN_V2U16 operator- (DN_V2U16 lhs, DN_V2U16 rhs); +DN_API DN_V2U16 operator+ (DN_V2U16 lhs, DN_V2U16 rhs); +DN_API DN_V2U16 operator* (DN_V2U16 lhs, DN_V2U16 rhs); +DN_API DN_V2U16 operator* (DN_V2U16 lhs, DN_F32 rhs); +DN_API DN_V2U16 operator* (DN_V2U16 lhs, DN_I32 rhs); +DN_API DN_V2U16 operator/ (DN_V2U16 lhs, DN_V2U16 rhs); +DN_API DN_V2U16 operator/ (DN_V2U16 lhs, DN_F32 rhs); +DN_API DN_V2U16 operator/ (DN_V2U16 lhs, DN_I32 rhs); +DN_API DN_V2U16& operator*= (DN_V2U16& lhs, DN_V2U16 rhs); +DN_API DN_V2U16& operator*= (DN_V2U16& lhs, DN_F32 rhs); +DN_API DN_V2U16& operator*= (DN_V2U16& lhs, DN_I32 rhs); +DN_API DN_V2U16& operator/= (DN_V2U16& lhs, DN_V2U16 rhs); +DN_API DN_V2U16& operator/= (DN_V2U16& lhs, DN_F32 rhs); +DN_API DN_V2U16& operator/= (DN_V2U16& lhs, DN_I32 rhs); +DN_API DN_V2U16& operator-= (DN_V2U16& lhs, DN_V2U16 rhs); +DN_API DN_V2U16& operator+= (DN_V2U16& lhs, DN_V2U16 rhs); + +#define DN_V2U32Zero DN_Literal(DN_V2U32){{(DN_U32)(0), (DN_U32)(0)}} +#define DN_V2U32One DN_Literal(DN_V2U32){{(DN_U32)(1), (DN_U32)(1)}} +#define DN_V2U32From1N(x) DN_Literal(DN_V2U32){{(DN_U32)(x), (DN_U32)(x)}} +#define DN_V2U32From2N(x, y) DN_Literal(DN_V2U32){{(DN_U32)(x), (DN_U32)(y)}} + +#define DN_V2F32Zero DN_Literal(DN_V2F32){{(DN_F32)(0), (DN_F32)(0)}} +#define DN_V2F32One DN_Literal(DN_V2F32){{(DN_F32)(1), (DN_F32)(1)}} +#define DN_V2F32From1N(x) DN_Literal(DN_V2F32){{(DN_F32)(x), (DN_F32)(x)}} +#define DN_V2F32From2N(x, y) DN_Literal(DN_V2F32){{(DN_F32)(x), (DN_F32)(y)}} +#define DN_V2F32FromV2(xy) DN_Literal(DN_V2F32){{(DN_F32)(xy).x, (DN_F32)(xy).y}} + +DN_API DN_V2F32 DN_V2F32Lerp (DN_V2F32 a, DN_F32 t, DN_V2F32 b); + +DN_API bool operator!= (DN_V2F32 lhs, DN_V2F32 rhs); +DN_API bool operator== (DN_V2F32 lhs, DN_V2F32 rhs); +DN_API bool operator>= (DN_V2F32 lhs, DN_V2F32 rhs); +DN_API bool operator<= (DN_V2F32 lhs, DN_V2F32 rhs); +DN_API bool operator< (DN_V2F32 lhs, DN_V2F32 rhs); +DN_API bool operator> (DN_V2F32 lhs, DN_V2F32 rhs); + +DN_API DN_V2F32 operator- (DN_V2F32 lhs); +DN_API DN_V2F32 operator- (DN_V2F32 lhs, DN_V2F32 rhs); +DN_API DN_V2F32 operator- (DN_V2F32 lhs, DN_V2I32 rhs); +DN_API DN_V2F32 operator- (DN_V2F32 lhs, DN_F32 rhs); +DN_API DN_V2F32 operator- (DN_V2F32 lhs, DN_I32 rhs); + +DN_API DN_V2F32 operator+ (DN_V2F32 lhs, DN_V2F32 rhs); +DN_API DN_V2F32 operator+ (DN_V2F32 lhs, DN_V2I32 rhs); +DN_API DN_V2F32 operator+ (DN_V2F32 lhs, DN_F32 rhs); +DN_API DN_V2F32 operator+ (DN_V2F32 lhs, DN_I32 rhs); + +DN_API DN_V2F32 operator* (DN_V2F32 lhs, DN_V2F32 rhs); +DN_API DN_V2F32 operator* (DN_V2F32 lhs, DN_V2I32 rhs); +DN_API DN_V2F32 operator* (DN_V2F32 lhs, DN_F32 rhs); +DN_API DN_V2F32 operator* (DN_V2F32 lhs, DN_I32 rhs); + +DN_API DN_V2F32 operator/ (DN_V2F32 lhs, DN_V2F32 rhs); +DN_API DN_V2F32 operator/ (DN_V2F32 lhs, DN_V2I32 rhs); +DN_API DN_V2F32 operator/ (DN_V2F32 lhs, DN_F32 rhs); +DN_API DN_V2F32 operator/ (DN_V2F32 lhs, DN_I32 rhs); + +DN_API DN_V2F32& operator*= (DN_V2F32& lhs, DN_V2F32 rhs); +DN_API DN_V2F32& operator*= (DN_V2F32& lhs, DN_V2I32 rhs); +DN_API DN_V2F32& operator*= (DN_V2F32& lhs, DN_F32 rhs); +DN_API DN_V2F32& operator*= (DN_V2F32& lhs, DN_I32 rhs); + +DN_API DN_V2F32& operator/= (DN_V2F32& lhs, DN_V2F32 rhs); +DN_API DN_V2F32& operator/= (DN_V2F32& lhs, DN_V2I32 rhs); +DN_API DN_V2F32& operator/= (DN_V2F32& lhs, DN_F32 rhs); +DN_API DN_V2F32& operator/= (DN_V2F32& lhs, DN_I32 rhs); + +DN_API DN_V2F32& operator-= (DN_V2F32& lhs, DN_V2F32 rhs); +DN_API DN_V2F32& operator-= (DN_V2F32& lhs, DN_V2I32 rhs); +DN_API DN_V2F32& operator-= (DN_V2F32& lhs, DN_F32 rhs); +DN_API DN_V2F32& operator-= (DN_V2F32& lhs, DN_I32 rhs); + +DN_API DN_V2F32& operator+= (DN_V2F32& lhs, DN_V2F32 rhs); +DN_API DN_V2F32& operator+= (DN_V2F32& lhs, DN_V2I32 rhs); +DN_API DN_V2F32& operator+= (DN_V2F32& lhs, DN_F32 rhs); +DN_API DN_V2F32& operator+= (DN_V2F32& lhs, DN_I32 rhs); + +DN_API DN_V2F32 DN_V2F32Min (DN_V2F32 a, DN_V2F32 b); +DN_API DN_V2F32 DN_V2F32Max (DN_V2F32 a, DN_V2F32 b); +DN_API DN_V2F32 DN_V2F32Abs (DN_V2F32 a); +DN_API DN_F32 DN_V2F32Dot (DN_V2F32 a, DN_V2F32 b); +DN_API DN_F32 DN_V2F32LengthSq2V2 (DN_V2F32 lhs, DN_V2F32 rhs); +DN_API bool DN_V2F32LengthSqIsWithin2V2 (DN_V2F32 lhs, DN_V2F32 rhs, DN_F32 within_amount_sq); +DN_API DN_F32 DN_V2F32Length2V2 (DN_V2F32 lhs, DN_V2F32 rhs); +DN_API DN_F32 DN_V2F32LengthSq (DN_V2F32 lhs); +DN_API DN_F32 DN_V2F32Length (DN_V2F32 lhs); +DN_API DN_V2F32 DN_V2F32Normalise (DN_V2F32 a); +DN_API DN_V2F32 DN_V2F32Perpendicular (DN_V2F32 a); +DN_API DN_V2F32 DN_V2F32Reflect (DN_V2F32 in, DN_V2F32 surface); +DN_API DN_F32 DN_V2F32Area (DN_V2F32 a); + +#define DN_V3F32From1N(x) DN_Literal(DN_V3F32){{(DN_F32)(x), (DN_F32)(x), (DN_F32)(x)}} +#define DN_V3F32From3N(x, y, z) DN_Literal(DN_V3F32){{(DN_F32)(x), (DN_F32)(y), (DN_F32)(z)}} +#define DN_V3F32FromV2F32And1N(xy, z) DN_Literal(DN_V3F32){{(DN_F32)(xy.x), (DN_F32)(xy.y), (DN_F32)(z)}} + +// NOTE: Grayscale co-efficients from: +// https://github.com/EpicGames/UnrealEngine/blob/260bb2e1c5610b31c63a36206eedd289409c5f11/Engine/Source/Runtime/Core/Private/Math/Color.cpp#L304 +DN_V3F32 static const DN_V3F32_RGB_LUMINANCE = DN_V3F32From3N(0.3f, 0.59f, 0.11f); + +DN_API bool operator== (DN_V3F32 lhs, DN_V3F32 rhs); +DN_API bool operator!= (DN_V3F32 lhs, DN_V3F32 rhs); +DN_API bool operator>= (DN_V3F32 lhs, DN_V3F32 rhs); +DN_API bool operator<= (DN_V3F32 lhs, DN_V3F32 rhs); +DN_API bool operator< (DN_V3F32 lhs, DN_V3F32 rhs); +DN_API bool operator> (DN_V3F32 lhs, DN_V3F32 rhs); +DN_API DN_V3F32 operator- (DN_V3F32 lhs, DN_V3F32 rhs); +DN_API DN_V3F32 operator- (DN_V3F32 lhs); +DN_API DN_V3F32 operator+ (DN_V3F32 lhs, DN_V3F32 rhs); +DN_API DN_V3F32 operator* (DN_V3F32 lhs, DN_V3F32 rhs); +DN_API DN_V3F32 operator* (DN_V3F32 lhs, DN_F32 rhs); +DN_API DN_V3F32 operator* (DN_V3F32 lhs, DN_I32 rhs); +DN_API DN_V3F32 operator/ (DN_V3F32 lhs, DN_V3F32 rhs); +DN_API DN_V3F32 operator/ (DN_V3F32 lhs, DN_F32 rhs); +DN_API DN_V3F32 operator/ (DN_V3F32 lhs, DN_I32 rhs); +DN_API DN_V3F32& operator*= (DN_V3F32 &lhs, DN_V3F32 rhs); +DN_API DN_V3F32& operator*= (DN_V3F32 &lhs, DN_F32 rhs); +DN_API DN_V3F32& operator*= (DN_V3F32 &lhs, DN_I32 rhs); +DN_API DN_V3F32& operator/= (DN_V3F32 &lhs, DN_V3F32 rhs); +DN_API DN_V3F32& operator/= (DN_V3F32 &lhs, DN_F32 rhs); +DN_API DN_V3F32& operator/= (DN_V3F32 &lhs, DN_I32 rhs); +DN_API DN_V3F32& operator-= (DN_V3F32 &lhs, DN_V3F32 rhs); +DN_API DN_V3F32& operator+= (DN_V3F32 &lhs, DN_V3F32 rhs); +DN_API DN_V3F32 DN_V3F32Lerp (DN_V3F32 lhs, DN_F32 t01, DN_V3F32 rhs); +DN_API DN_F32 DN_V3F32LengthSq (DN_V3F32 a); +DN_API DN_F32 DN_V3F32Length (DN_V3F32 a); +DN_API DN_V3F32 DN_V3F32Normalise (DN_V3F32 a); + +#define DN_V4F32From1N(x) DN_Literal(DN_V4F32){{(DN_F32)(x), (DN_F32)(x), (DN_F32)(x), (DN_F32)(x)}} +#define DN_V4F32From4N(x, y, z, w) DN_Literal(DN_V4F32){{(DN_F32)(x), (DN_F32)(y), (DN_F32)(z), (DN_F32)(w)}} +#define DN_V4F32FromV3And1N(xyz, w) DN_Literal(DN_V4F32){{xyz.x, xyz.y, xyz.z, w}} +#define DN_V4F32RGBA01FromRGBAU8(r, g, b, a) DN_Literal(DN_V4F32){{r / 255.f, g / 255.f, b / 255.f, a / 255.f}} +#define DN_V4F32RGBA01FromRGBU8(r, g, b) DN_Literal(DN_V4F32){{r / 255.f, g / 255.f, b / 255.f, 1.f}} + +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_V4F32RGBA01FromRGBU32 (DN_U32 u32); +DN_API DN_V4F32 DN_V4F32RGBA01FromRGBAU32 (DN_U32 u32); +DN_API DN_V4F32 DN_V4F32Linear01FromSRGB01 (DN_V4F32 rgb01); +DN_API DN_V4F32 DN_V4F32Linear01Desaturate (DN_V4F32 linear01, DN_F32 t01); +DN_API DN_V4F32 DN_V4F32SRGB01FromLinear01 (DN_V4F32 linear01); + +#define DN_V4F32FromV4Alpha(v4, alpha) DN_V4F32FromV3And1N(v4.xyz, alpha) + +DN_API bool operator== (DN_V4F32 lhs, DN_V4F32 rhs); +DN_API bool operator!= (DN_V4F32 lhs, DN_V4F32 rhs); +DN_API bool operator<= (DN_V4F32 lhs, DN_V4F32 rhs); +DN_API bool operator< (DN_V4F32 lhs, DN_V4F32 rhs); +DN_API bool operator> (DN_V4F32 lhs, DN_V4F32 rhs); +DN_API DN_V4F32 operator- (DN_V4F32 lhs, DN_V4F32 rhs); +DN_API DN_V4F32 operator- (DN_V4F32 lhs); +DN_API DN_V4F32 operator+ (DN_V4F32 lhs, DN_V4F32 rhs); +DN_API DN_V4F32 operator* (DN_V4F32 lhs, DN_V4F32 rhs); +DN_API DN_V4F32 operator* (DN_V4F32 lhs, DN_F32 rhs); +DN_API DN_V4F32 operator* (DN_V4F32 lhs, DN_I32 rhs); +DN_API DN_V4F32 operator/ (DN_V4F32 lhs, DN_F32 rhs); +DN_API DN_V4F32& operator*= (DN_V4F32 &lhs, DN_V4F32 rhs); +DN_API DN_V4F32& operator*= (DN_V4F32 &lhs, DN_F32 rhs); +DN_API DN_V4F32& operator*= (DN_V4F32 &lhs, DN_I32 rhs); +DN_API DN_V4F32& operator-= (DN_V4F32 &lhs, DN_V4F32 rhs); +DN_API DN_V4F32& operator+= (DN_V4F32 &lhs, DN_V4F32 rhs); +DN_API DN_F32 DN_V4F32Dot (DN_V4F32 a, DN_V4F32 b); + +DN_API DN_M4 DN_M4Identity (); +DN_API DN_M4 DN_M4ScaleF (DN_F32 x, DN_F32 y, DN_F32 z); +DN_API DN_M4 DN_M4Scale (DN_V3F32 xyz); +DN_API DN_M4 DN_M4TranslateF (DN_F32 x, DN_F32 y, DN_F32 z); +DN_API DN_M4 DN_M4Translate (DN_V3F32 xyz); +DN_API DN_M4 DN_M4Transpose (DN_M4 mat); +DN_API DN_M4 DN_M4Rotate (DN_V3F32 axis, DN_F32 radians); +DN_API DN_M4 DN_M4Orthographic (DN_F32 left, DN_F32 right, DN_F32 bottom, DN_F32 top, DN_F32 z_near, DN_F32 z_far); +DN_API DN_M4 DN_M4Perspective (DN_F32 fov /*radians*/, DN_F32 aspect, DN_F32 z_near, DN_F32 z_far); +DN_API DN_M4 DN_M4Add (DN_M4 lhs, DN_M4 rhs); +DN_API DN_M4 DN_M4Sub (DN_M4 lhs, DN_M4 rhs); +DN_API DN_M4 DN_M4Mul (DN_M4 lhs, DN_M4 rhs); +DN_API DN_M4 DN_M4Div (DN_M4 lhs, DN_M4 rhs); +DN_API DN_M4 DN_M4AddF (DN_M4 lhs, DN_F32 rhs); +DN_API DN_M4 DN_M4SubF (DN_M4 lhs, DN_F32 rhs); +DN_API DN_M4 DN_M4MulF (DN_M4 lhs, DN_F32 rhs); +DN_API DN_M4 DN_M4DivF (DN_M4 lhs, DN_F32 rhs); +DN_API DN_Str8x256 DN_M4ColumnMajorString (DN_M4 mat); + +DN_API bool operator== (DN_M2x3 const &lhs, DN_M2x3 const &rhs); +DN_API bool operator!= (DN_M2x3 const &lhs, DN_M2x3 const &rhs); +DN_API DN_M2x3 DN_M2x3Identity (); +DN_API DN_M2x3 DN_M2x3Translate (DN_V2F32 offset); +DN_API DN_V2F32 DN_M2x3ScaleGet (DN_M2x3 m2x3); +DN_API DN_M2x3 DN_M2x3Scale (DN_V2F32 scale); +DN_API DN_M2x3 DN_M2x3Rotate (DN_F32 radians); +DN_API DN_M2x3 DN_M2x3ProjFromV2F32 (DN_V2F32 size, DN_M2x3ProjOrigin origin); +DN_API DN_M2x3XForm DN_M2x3XFormFrom2M2x3 (DN_M2x3 forward, DN_M2x3 inverse); +DN_API DN_M2x3XForm DN_M2x3XFormFromTRS (DN_V2F32 pos, DN_V2F32 scale, DN_F32 rotate_rads, DN_V2F32 pivot_pos); +DN_API DN_M2x3XForm DN_M2x3XFormIdentity (); +DN_API DN_M2x3XForm DN_M2x3XFormMul (DN_M2x3XForm m1, DN_M2x3XForm m2); +DN_API DN_M2x3 DN_M2x3Mul (DN_M2x3 m1, DN_M2x3 m2); +DN_API DN_V2F32 DN_M2x3Mul2F32 (DN_M2x3 m1, DN_F32 x, DN_F32 y); +DN_API DN_V2F32 DN_M2x3MulV2F32 (DN_M2x3 m1, DN_V2F32 v2); +DN_API DN_Rect DN_M2x3MulRect (DN_M2x3 m1, DN_Rect rect); + +#define DN_RectFrom2V2(pos, size) DN_Literal(DN_Rect){(pos), (size)} +#define DN_RectFrom4N(x, y, w, h) DN_Literal(DN_Rect){DN_Literal(DN_V2F32){{x, y}}, DN_Literal(DN_V2F32){{w, h}}} +#define DN_RectZero DN_RectFrom4N(0, 0, 0, 0) + +DN_API bool operator== (const DN_Rect& lhs, const DN_Rect& rhs); +DN_API DN_V2F32 DN_RectCenter (DN_Rect rect); +DN_API bool DN_RectContainsPoint (DN_Rect rect, DN_V2F32 p); +DN_API bool DN_RectContainsRect (DN_Rect a, DN_Rect b); +DN_API DN_Rect DN_RectExpand (DN_Rect a, DN_F32 amount); +DN_API DN_Rect DN_RectExpandV2 (DN_Rect a, DN_V2F32 amount); +DN_API bool DN_RectIntersects (DN_Rect a, DN_Rect b); +DN_API DN_Rect DN_RectIntersection (DN_Rect a, DN_Rect b); +DN_API DN_Rect DN_RectUnion (DN_Rect a, DN_Rect b); +DN_API DN_2V2F32 DN_RectRange (DN_Rect a); +DN_API bool DN_RectEq (DN_Rect lhs, DN_Rect rhs); +DN_API DN_F32 DN_RectArea (DN_Rect a); +DN_API DN_V2F32 DN_RectInterpV2F32 (DN_Rect rect, DN_V2F32 t01); +DN_API DN_V2F32 DN_RectTopLeft (DN_Rect rect); +DN_API DN_V2F32 DN_RectTopRight (DN_Rect rect); +DN_API DN_V2F32 DN_RectBottomLeft (DN_Rect rect); +DN_API DN_V2F32 DN_RectBottomRight (DN_Rect rect); + +DN_API DN_Rect DN_RectCutLeftClip (DN_Rect *rect, DN_F32 amount, DN_RectCutClip clip); +DN_API DN_Rect DN_RectCutRightClip (DN_Rect *rect, DN_F32 amount, DN_RectCutClip clip); +DN_API DN_Rect DN_RectCutTopClip (DN_Rect *rect, DN_F32 amount, DN_RectCutClip clip); +DN_API DN_Rect DN_RectCutBottomClip (DN_Rect *rect, DN_F32 amount, DN_RectCutClip clip); + +#define DN_RectCutLeft(rect, amount) DN_RectCutLeftClip(rect, amount, DN_RectCutClip_Yes) +#define DN_RectCutRight(rect, amount) DN_RectCutRightClip(rect, amount, DN_RectCutClip_Yes) +#define DN_RectCutTop(rect, amount) DN_RectCutTopClip(rect, amount, DN_RectCutClip_Yes) +#define DN_RectCutBottom(rect, amount) DN_RectCutBottomClip(rect, amount, DN_RectCutClip_Yes) + +#define DN_RectCutLeftNoClip(rect, amount) DN_RectCutLeftClip(rect, amount, DN_RectCutClip_No) +#define DN_RectCutRightNoClip(rect, amount) DN_RectCutRightClip(rect, amount, DN_RectCutClip_No) +#define DN_RectCutTopNoClip(rect, amount) DN_RectCutTopClip(rect, amount, DN_RectCutClip_No) +#define DN_RectCutBottomNoClip(rect, amount) DN_RectCutBottomClip(rect, amount, DN_RectCutClip_No) + +DN_API DN_Rect DN_RectCutCut (DN_RectCut rect_cut, DN_V2F32 size, DN_RectCutClip clip); +#define DN_RectCutInit(rect, side) DN_Literal(DN_RectCut){rect, side} + +DN_API DN_RaycastV2 DN_RaycastLineIntersectV2 (DN_V2F32 origin_a, DN_V2F32 dir_a, DN_V2F32 origin_b, DN_V2F32 dir_b); +#endif // !defined(DN_BASE_H) +// DN: Single header generator commented out => #include "Base/dn_base_assert.h" +#if !defined(DN_BASE_ASSERT_H) +#define DN_BASE_ASSERT_H + +#define DN_HardAssertF(expr, fmt, ...) \ + do { \ + if (!(expr)) { \ + DN_Str8 stack_trace_ = DN_StackTraceWalkStr8FromHeap(128 /*limit*/, 2 /*skip*/); \ + DN_LogErrorF("Hard assertion [" #expr "], stack trace was:\n\n%.*s\n\n" fmt, \ + DN_Str8PrintFmt(stack_trace_), \ + ##__VA_ARGS__); \ + DN_DebugBreak; \ + } \ + } while (0) +#define DN_HardAssert(expr) DN_HardAssertF(expr, "") + +// NOTE: Our default assert requires stack traces which has a bit of a chicken-and-egg problem if +// we're trying to detect some code related to the DN startup sequence. If we try to assert before +// the OS layer is initialised stack-traces will try to use temporary memory which requires TLS to +// be setup which belongs to the OS. +// +// This causes recursion errors as they call into each other. We use RawAsserts for these kind of +// checks. +#if defined(DN_NO_ASSERT) + #define DN_RawAssert(...) + #define DN_Assert(...) + #define DN_AssertOnce(...) + #define DN_AssertF(...) + #define DN_AssertFOnce(...) +#else + #define DN_RawAssert(expr) do { if (!(expr)) DN_DebugBreak; } while (0) + + #define DN_AssertF(expr, fmt, ...) \ + do { \ + if (!(expr)) { \ + DN_Str8 stack_trace_ = DN_StackTraceWalkStr8FromHeap(128 /*limit*/, 2 /*skip*/); \ + DN_LogErrorF("Assertion [" #expr "], stack trace was:\n\n%.*s\n\n" fmt, \ + DN_Str8PrintFmt(stack_trace_), \ + ##__VA_ARGS__); \ + DN_DebugBreak; \ + } \ + } while (0) + + #define DN_AssertFOnce(expr, fmt, ...) \ + do { \ + static bool once = true; \ + if (!(expr) && once) { \ + once = false; \ + DN_Str8 stack_trace_ = DN_StackTraceWalkStr8FromHeap(128 /*limit*/, 2 /*skip*/); \ + DN_LogErrorF("Assertion [" #expr "], stack trace was:\n\n%.*s\n\n" fmt, \ + DN_Str8PrintFmt(stack_trace_), \ + ##__VA_ARGS__); \ + DN_DebugBreak; \ + } \ + } while (0) + + #define DN_Assert(expr) DN_AssertF((expr), "") + #define DN_AssertOnce(expr) DN_AssertFOnce((expr), "") +#endif + +#define DN_InvalidCodePathF(fmt, ...) DN_HardAssertF(0, fmt, ##__VA_ARGS__) +#define DN_InvalidCodePath DN_InvalidCodePathF("Invalid code path triggered") +#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_Check(expr) DN_CheckF(expr, "") +#if defined(DN_NO_CHECK_BREAK) + #define DN_CheckF(expr, fmt, ...) \ + ((expr) ? true : (DN_LogWarningF(fmt, ##__VA_ARGS__), false)) +#else + #define DN_CheckF(expr, fmt, ...) \ + ((expr) ? true : (DN_LogErrorF(fmt, ##__VA_ARGS__), DN_StackTracePrint(128 /*limit*/), DN_DebugBreak, false)) +#endif + +#endif +// DN: Single header generator commented out => #include "Base/dn_base_containers.h" +#if !defined(DN_CONTAINERS_H) +#define DN_CONTAINERS_H +// Containers that are imlpemented using primarily macros for operating on data structures that are +// embedded into a C style struct or from a set of defined variables from the available scope. Keep +// it stupid simple, structs and functions. Minimal amount of container types with flexible +// construction leads to less duplicated container code and less template meta-programming. +// +// Arrays +// +// Data structures that have a `T *data`, `DN_USize count` and `DN_USize max` capacity that can be +// dynamically shrunk or expanded. +// +// API +// ResizeFrom: Resizes the array to `new_max` erase elements if resizing to a smaller size +// GrowFrom: Expands the capacity of the array if `new_max > array.max` otherwise no-op +// GrowIfNeeded: Expands the capacity of the array if `array.size + add_count > array.max` otherwise no-op +// +// Variants +// PArray => Pointer (to) Array +// LArray => Literal Array +// Define a C array and size. (P) array macros take a pointer to the aray, its size and its max +// capacity. The (L) array macros take the literal array and derives the max capacity +// automatically using DN_ArrayCountU(l_array). +// +// MyStruct buffer[TB_ASType_Count] = {}; +// DN_USize size = 0; +// MyStruct *item_0 = DN_PArrayMake(buffer, &size, DN_ArrayCountU(buffer), DN_ZMem_No); +// MyStruct *item_1 = DN_LArrayMake(buffer, &size, DN_ZMem_No); +// +// IArray => Intrusive Array +// Define a struct with the members `data`, `size` and `max`: +// +// struct MyArray { +// MyStruct *data; +// DN_USize size; +// DN_USize max; +// } my_array = {}; +// DN_Arena arena = {}; +// DN_IArrayResizeFromArena(&my_array, &arena, 256); +// MyStruct *item = DN_IArrayMake(&my_array, DN_ZMem_No); +// +// 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 +// +// ISinglyLL => Intrusive Singly Linked List +// Define a struct with the members `next`: +// +// struct MyLinkItem { +// int data; +// MyLinkItem *next; +// } my_link = {}; +// +// MyLinkItem *first_item = DN_ISinglyLLDetach(&my_link, MyLinkItem); +// +// DoublyLL => Doubly Linked List +// Define a struct with the members `next` and `prev`. This list has null pointers for head->prev +// and tail->next. +// +// struct MyLinkItem { +// int data; +// MyLinkItem *next; +// MyLinkItem *prev; +// } my_link = {}; +// +// MyLinkItem first_item = {}, second_item = {}; +// DN_DoublyLLAppend(&first_item, &second_item); // first_item -> second_item +// +// SentinelDoublyLL => Sentinel Doubly Linked List +// Uses a sentinel/dummy node as the list head. The sentinel points to itself when empty. +// Define a struct with the members `next` and `prev`: +// +// struct MyLinkItem { +// int data; +// MyLinkItem *next; +// MyLinkItem *prev; +// } my_list = {}; +// +// DN_SentinelDoublyLLInit(&my_list); +// DN_SentinelDoublyLLAppend(&my_list, &new_item); +// DN_SentinelDoublyLLForEach(it, &my_list) { /* ... */ } +// +// SinglyHeadTailLL => Singly Linked List with Head and Tail pointer (or First and Last pointer) +/* + struct MyLinkItem { + int data; + MyLinkItem *next; + } my_list = {}; + + struct MyContainer { + MyLinkItem *head; + MyLinkItem *tail; + }; + + MyLinkItem item = {}; + MyContainer container = {}; + DN_ISinglyHeadTailLLAppend(container, item); + // ... or alternatively, DN_SinglyHeadTailLLAppend(container.head, container.tail, item); + + for (MyLinkItem *it = container.head; it; it = it->next) { } +*/ + +// DN: Single header generator commented out => #if defined(_CLANGD) +// #include "../dn.h" +// #endif + +struct DN_Ring +{ + DN_U64 size; + char *base; + DN_U64 write_pos; + DN_U64 read_pos; +}; + +enum DN_ArrayErase +{ + DN_ArrayErase_Unstable, + DN_ArrayErase_Stable, +}; + +enum DN_ArrayAdd +{ + DN_ArrayAdd_Append, + DN_ArrayAdd_Prepend, +}; + +struct DN_ArrayEraseResult +{ + // The next index your for-index should be set to such that you can continue + // to iterate the remainder of the array, e.g: + // + // for (DN_USize index = 0; index < array.size; index++) { + // if (erase) + // index = DN_FArray_EraseRange(&array, index, -3, DN_ArrayErase_Unstable); + // } + DN_USize it_index; + DN_USize items_erased; // The number of items erased +}; + +template struct DN_ArrayFindResult +{ + T *data; // Pointer to the value if a match is found, null pointer otherwise + DN_USize index; // Index to the value if a match is found, 0 otherwise +}; + +enum DN_DSMapKeyType +{ + // Key | Key Hash | Map Index + DN_DSMapKeyType_Invalid, + DN_DSMapKeyType_U64, // U64 | Hash(U64) | Hash(U64) % map_size + DN_DSMapKeyType_U64NoHash, // U64 | U64 | U64 % map_size + DN_DSMapKeyType_Buffer, // Buffer | Hash(buffer) | Hash(buffer) % map_size + DN_DSMapKeyType_BufferAsU64NoHash, // Buffer | U64(buffer[0:4]) | U64(buffer[0:4]) % map_size +}; + +struct DN_DSMapKey +{ + DN_DSMapKeyType type; + DN_U32 hash; // Hash to lookup in the map. If it equals, we check that the original key payload matches + void const *buffer_data; + DN_U32 buffer_size; + DN_U64 u64; + bool no_copy_buffer; +}; + +template +struct DN_DSMapSlot +{ + DN_DSMapKey key; // Hash table lookup key + T value; // Hash table value +}; + +typedef DN_U32 DN_DSMapFlags; +enum DN_DSMapFlags_ +{ + DN_DSMapFlags_Nil = 0, + DN_DSMapFlags_DontFreeArenaOnResize = 1 << 0, +}; + +using DN_DSMapHashFunction = DN_U32(DN_DSMapKey key, DN_U32 seed); +template struct DN_DSMap +{ + DN_U32 *hash_to_slot; // Mapping from hash to a index in the slots array + DN_DSMapSlot *slots; // Values of the array stored contiguously, non-sorted order + DN_U32 size; // Total capacity of the map and is a power of two + DN_U32 occupied; // Number of slots used in the hash table + DN_Arena *arena; // Backing arena for the hash table + DN_Pool pool; // Allocator for keys that are variable-sized buffers + DN_U32 initial_size; // Initial map size, map cannot shrink on erase below this size + DN_DSMapHashFunction *hash_function; // Custom hashing function to use if field is set + DN_U32 hash_seed; // Seed for the hashing function, when 0, DN_DS_MAP_DEFAULT_HASH_SEED is used + DN_DSMapFlags flags; +}; + +template struct DN_DSMapResult +{ + bool found; + DN_DSMapSlot *slot; + T *value; +}; + +#define DN_ISinglyLLDetach(list) (decltype(list))DN_SinglyLLDetach((void **)&(list), (void **)&(list)->next) + +#define DN_SinglyHeadTailLLAppend(head, tail, to_append) \ + do { \ + if (!head) \ + head = to_append; \ + if (tail) \ + tail->next = to_append; \ + tail = to_append; \ + } while (0) +#define DN_ISinglyHeadTailLLAppend(container_ptr, to_append) DN_SinglyHeadTailLLAppend((container_ptr)->head, (container_ptr)->tail, to_append) + +#define DN_SentinelDoublyLLInit(list) (list)->next = (list)->prev = (list) +#define DN_SentinelDoublyLLIsSentinel(list, item) ((list) == (item)) +#define DN_SentinelDoublyLLIsEmpty(list) (!(list) || ((list) == (list)->next)) +#define DN_SentinelDoublyLLIsInit(list) ((list)->next && (list)->prev) +#define DN_SentinelDoublyLLHasItems(list) ((list) && ((list) != (list)->next)) +#define DN_SentinelDoublyLLForEach(it, list) auto *it = (list)->next; (it) != (list); (it) = (it)->next + +#define DN_SentinelDoublyLLInitArena(list, T, ptr_arena) \ + do { \ + (list) = DN_ArenaNew(ptr_arena, T, DN_ZMem_Yes); \ + DN_SentinelDoublyLLInit(list); \ + } while (0) + +#define DN_SentinelDoublyLLInitPool(list, T, pool) \ + do { \ + (list) = DN_PoolNew(pool, T); \ + DN_SentinelDoublyLLInit(list); \ + } while (0) + +#define DN_SentinelDoublyLLDetach(item) \ + do { \ + if (item) { \ + (item)->prev->next = (item)->next; \ + (item)->next->prev = (item)->prev; \ + (item)->next = nullptr; \ + (item)->prev = nullptr; \ + } \ + } while (0) + +#define DN_SentinelDoublyLLDequeue(list, dest_ptr) \ + if (DN_SentinelDoublyLLHasItems(list)) { \ + dest_ptr = (list)->next; \ + DN_SentinelDoublyLLDetach(dest_ptr); \ + } + +#define DN_SentinelDoublyLLAppend(list, item) \ + do { \ + if (item) { \ + if ((item)->next) \ + DN_SentinelDoublyLLDetach(item); \ + (item)->next = (list)->next; \ + (item)->prev = (list); \ + (item)->next->prev = (item); \ + (item)->prev->next = (item); \ + } \ + } while (0) + +#define DN_SentinelDoublyLLPrepend(list, item) \ + do { \ + if (item) { \ + if ((item)->next) \ + DN_SentinelDoublyLLDetach(item); \ + (item)->next = (list); \ + (item)->prev = (list)->prev; \ + (item)->next->prev = (item); \ + (item)->prev->next = (item); \ + } \ + } while (0) + +// DoublyLL => Non-intrusive Doubly Linked List +// A simple doubly linked list where each node has `next` and `prev` pointers. +// The head is passed as a pointer-to-pointer to allow head updates. +// +// struct MyLinkItem { +// int data; +// MyLinkItem *next; +// MyLinkItem *prev; +// } *head = nullptr; +// DN_DoublyLLAppend(&head, new_item); +// for (MyLinkItem *it = head; it; it = it->next) { /* ... */ } + +#define DN_DoublyLLDetach(head, ptr) \ + do { \ + if ((head) && (head) == (ptr)) \ + (head) = (head)->next; \ + if ((ptr)) { \ + if ((ptr)->next) \ + (ptr)->next->prev = (ptr)->prev; \ + if ((ptr)->prev) \ + (ptr)->prev->next = (ptr)->next; \ + (ptr)->prev = (ptr)->next = 0; \ + } \ + } while (0) + +#define DN_DoublyLLAppend(head, ptr) \ + do { \ + if ((ptr)) { \ + DN_AssertF((ptr)->prev == 0 && (ptr)->next == 0, "Detach the pointer first"); \ + (ptr)->prev = (head); \ + (ptr)->next = 0; \ + if ((head)) { \ + (ptr)->next = (head)->next; \ + (head)->next = (ptr); \ + } else { \ + (head) = (ptr); \ + } \ + } \ + } while (0) + +#define DN_DoublyLLPrepend(head, ptr) \ + do { \ + if ((ptr)) { \ + DN_AssertF((ptr)->prev == 0 && (ptr)->next == 0, "Detach the pointer first"); \ + (ptr)->prev = nullptr; \ + (ptr)->next = (head); \ + if ((head)) { \ + (ptr)->prev = (head)->prev; \ + (head)->prev = (ptr); \ + } else { \ + (head) = (ptr); \ + } \ + } \ + } while (0) + +// NOTE: For C++ we need to cast the void* returned in these functions to the concrete type. In C, +// no cast is needed. +#if defined(__cplusplus) + #define DN_CppDeclType(x) decltype(x) +#else + #define DN_CppDeclType +#endif + +#define DN_PArrayResizeFromPool(ptr, ptr_size, ptr_max, pool, new_max) DN_CArrayResizeFromPool((void **)&(ptr), ptr_size, ptr_max, sizeof((ptr)[0]), pool, new_max) +#define DN_PArrayResizeFromArena(ptr, ptr_size, ptr_max, arena, new_max) DN_CArrayResizeFromArena((void **)&(ptr), ptr_size, ptr_max, sizeof((ptr)[0]), arena, new_max) +#define DN_PArrayGrowFromPool(ptr, size, ptr_max, pool, new_max) DN_CArrayGrowFromPool((void **)&(ptr), size, ptr_max, sizeof((ptr)[0]), pool, new_max) +#define DN_PArrayGrowFromArena(ptr, size, ptr_max, arena, new_max) DN_CArrayGrowFromArena((void **)&(ptr), size, ptr_max, sizeof((ptr)[0]), arena, new_max) +#define DN_PArrayGrowIfNeededFromPool(ptr, size, ptr_max, pool, add_count) DN_CArrayGrowIfNeededFromPool((void **)(ptr), size, ptr_max, sizeof((*ptr)[0]), pool, add_count) +#define DN_PArrayGrowIfNeededFromArena(ptr, size, ptr_max, arena, add_count) DN_CArrayGrowIfNeededFromArena((void **)(ptr), size, ptr_max, sizeof((*ptr)[0]), arena, add_count) +#define DN_PArrayMakeArray(ptr, ptr_size, max, count, z_mem) (DN_CppDeclType(&(ptr)[0]))DN_CArrayMakeArray(ptr, ptr_size, max, sizeof((ptr)[0]), count, z_mem) +#define DN_PArrayMakeArrayZ(ptr, ptr_size, max, count) (DN_CppDeclType(&(ptr)[0]))DN_CArrayMakeArray(ptr, ptr_size, max, sizeof((ptr)[0]), count, DN_ZMem_Yes) +#define DN_PArrayMake(ptr, ptr_size, max, z_mem) (DN_CppDeclType(&(ptr)[0]))DN_CArrayMakeArray(ptr, ptr_size, max, sizeof((ptr)[0]), 1, z_mem) +#define DN_PArrayMakeZ(ptr, ptr_size, max) (DN_CppDeclType(&(ptr)[0]))DN_CArrayMakeArray(ptr, ptr_size, max, sizeof((ptr)[0]), 1, DN_ZMem_Yes) +#define DN_PArrayAddArray(ptr, ptr_size, max, items, count, add) (DN_CppDeclType(&(ptr)[0]))DN_CArrayAddArray(ptr, ptr_size, max, sizeof((ptr)[0]), items, count, add) +#define DN_PArrayAdd(ptr, ptr_size, max, item, add) (DN_CppDeclType(&(ptr)[0]))DN_CArrayAddArray(ptr, ptr_size, max, sizeof((ptr)[0]), &item, 1, add) +#define DN_PArrayAppendArray(ptr, ptr_size, max, items, count) (DN_CppDeclType(&(ptr)[0]))DN_CArrayAddArray(ptr, ptr_size, max, sizeof((ptr)[0]), items, count, DN_ArrayAdd_Append) +#define DN_PArrayAppend(ptr, ptr_size, max, item) (DN_CppDeclType(&(ptr)[0]))DN_CArrayAddArray(ptr, ptr_size, max, sizeof((ptr)[0]), &item, 1, DN_ArrayAdd_Append) +#define DN_PArrayPrependArray(ptr, ptr_size, max, items, count) (DN_CppDeclType(&(ptr)[0]))DN_CArrayAddArray(ptr, ptr_size, max, sizeof((ptr)[0]), items, count, DN_ArrayAdd_Prepend) +#define DN_PArrayPrepend(ptr, ptr_size, max, item) (DN_CppDeclType(&(ptr)[0]))DN_CArrayAddArray(ptr, ptr_size, max, sizeof((ptr)[0]), &item, 1, DN_ArrayAdd_Prepend) +#define DN_PArrayEraseRange(ptr, ptr_size, begin_index, count, erase) DN_CArrayEraseRange(ptr, ptr_size, sizeof((ptr)[0]), begin_index, count, erase) +#define DN_PArrayErase(ptr, ptr_size, index, erase) DN_CArrayEraseRange(ptr, ptr_size, sizeof((ptr)[0]), index, 1, erase) +#define DN_PArrayInsertArray(ptr, ptr_size, max, index, items, count) (DN_CppDeclType(&(ptr)[0]))DN_CArrayInsertArray(ptr, ptr_size, max, sizeof((ptr)[0]), index, items, count) +#define DN_PArrayInsert(ptr, ptr_size, max, index, item) (DN_CppDeclType(&(ptr)[0]))DN_CArrayInsertArray(ptr, ptr_size, max, sizeof((ptr)[0]), index, &item, 1) +#define DN_PArrayPopFront(ptr, ptr_size, max, count) (DN_CppDeclType(&(ptr)[0]))DN_CArrayPopFront(ptr, ptr_size, sizeof((ptr)[0]), count) +#define DN_PArrayPopBack(ptr, ptr_size, max, count) (DN_CppDeclType(&(ptr)[0]))DN_CArrayPopBack(ptr, ptr_size, sizeof((ptr)[0]), count) + +#define DN_LArrayResizeFromPool(c_array, size, pool, new_max) DN_PArrayResizeFromPool(c_array, size, DN_ArrayCountU(c_array), pool, new_max) +#define DN_LArrayResizeFromArena(c_array, size, arena, new_max) DN_PArrayResizeFromArena(c_array, size, DN_ArrayCountU(c_array), arena, new_max) +#define DN_LArrayGrowFromPool(c_array, size, pool, new_max) DN_PArrayGrowFromPool(c_array, size, DN_ArrayCountU(c_array), pool, new_max) +#define DN_LArrayGrowFromArena(c_array, size, arena, new_max) DN_PArrayGrowFromArena(c_array, size, DN_ArrayCountU(c_array), arena, new_max) +#define DN_LArrayGrowIfNeededFromPool(c_array, size, pool, add_count) DN_PArrayGrowIfNeededFromPool(c_array, size, DN_ArrayCountU(c_array), pool, add_count) +#define DN_LArrayGrowIfNeededFromArena(c_array, size, arena, add_count) DN_PArrayGrowIfNeededFromArena(c_array, size, DN_ArrayCountU(c_array), arena, add_count) +#define DN_LArrayMakeArray(c_array, ptr_size, count, z_mem) DN_PArrayMakeArray(c_array, ptr_size, DN_ArrayCountU(c_array), count, z_mem) +#define DN_LArrayMakeArrayZ(c_array, ptr_size, count) DN_PArrayMakeArrayZ(c_array, ptr_size, DN_ArrayCountU(c_array), count) +#define DN_LArrayMake(c_array, ptr_size, z_mem) DN_PArrayMake(c_array, ptr_size, DN_ArrayCountU(c_array), z_mem) +#define DN_LArrayMakeZ(c_array, ptr_size) DN_PArrayMakeZ(c_array, ptr_size, DN_ArrayCountU(c_array)) +#define DN_LArrayAddArray(c_array, ptr_size, items, count, add) DN_PArrayAddArray(c_array, ptr_size, DN_ArrayCountU(c_array), items, count, add) +#define DN_LArrayAdd(c_array, ptr_size, item, add) DN_PArrayAdd(c_array, ptr_size, DN_ArrayCountU(c_array), item, add) +#define DN_LArrayAppendArray(c_array, ptr_size, items, count) DN_PArrayAppendArray(c_array, ptr_size, DN_ArrayCountU(c_array), items, count) +#define DN_LArrayAppend(c_array, ptr_size, item) DN_PArrayAppend(c_array, ptr_size, DN_ArrayCountU(c_array), item) +#define DN_LArrayPrependArray(c_array, ptr_size, items, count) DN_PArrayPrependArray(c_array, ptr_size, DN_ArrayCountU(c_array), items, count) +#define DN_LArrayPrepend(c_array, ptr_size, item) DN_PArrayPrepend(c_array, ptr_size, DN_ArrayCountU(c_array), item) +#define DN_LArrayEraseRange(c_array, ptr_size, begin_index, count, erase) DN_PArrayEraseRange(c_array, ptr_size, begin_index, count, erase) +#define DN_LArrayErase(c_array, ptr_size, index, erase) DN_PArrayErase(c_array, ptr_size, index, erase) +#define DN_LArrayInsertArray(c_array, ptr_size, index, items, count) DN_PArrayInsertArray(c_array, ptr_size, DN_ArrayCountU(c_array), index, items, count) +#define DN_LArrayInsert(c_array, ptr_size, index, item) DN_PArrayInsert(c_array, ptr_size, DN_ArrayCountU(c_array), index, item) +#define DN_LArrayPopFront(c_array, ptr_size, count) DN_PArrayPopFront(c_array, ptr_size, DN_ArrayCountU(c_array), count) +#define DN_LArrayPopBack(c_array, ptr_size, count) DN_PArrayPopBack(c_array, ptr_size, DN_ArrayCountU(c_array), count) + +#define DN_IArrayResizeFromPool(ptr_array, pool, new_max) DN_CArrayResizeFromPool((void **)(&(ptr_array)->data), &(ptr_array)->size, &(ptr_array)->max, sizeof((ptr_array)->data[0]), pool, new_max) +#define DN_IArrayResizeFromArena(ptr_array, arena, new_max) DN_CArrayResizeFromArena((void **)(&(ptr_array)->data), &(ptr_array)->size, &(ptr_array)->max, sizeof((ptr_array)->data[0]), arena, new_max) +#define DN_IArrayGrowFromPool(ptr_array, pool, new_max) DN_CArrayGrowFromPool((void **)(&(ptr_array)->data), (ptr_array)->size, &(ptr_array)->max, sizeof((ptr_array)->data[0]), pool, new_max) +#define DN_IArrayGrowFromArena(ptr_array, arena, new_max) DN_CArrayGrowFromArena((void **)(&(ptr_array)->data), (ptr_array)->size, &(ptr_array)->max, sizeof((ptr_array)->data[0]), arena, new_max) +#define DN_IArrayGrowIfNeededFromPool(ptr_array, pool, add_count) DN_CArrayGrowIfNeededFromPool((void **)(&(ptr_array)->data), (ptr_array)->size, &(ptr_array)->max, sizeof((ptr_array)->data[0]), pool, add_count) +#define DN_IArrayGrowIfNeededFromArena(ptr_array, arena, add_count) DN_CArrayGrowIfNeededFromArena((void **)(&(ptr_array)->data), (ptr_array)->size, &(ptr_array)->max, sizeof((ptr_array)->data[0]), arena, add_count) +#define DN_IArrayMakeArray(ptr_array, count, z_mem) (DN_CppDeclType(&((ptr_array)->data)[0]))DN_CArrayMakeArray((ptr_array)->data, &(ptr_array)->size, (ptr_array)->max, sizeof(((ptr_array)->data)[0]), count, z_mem) +#define DN_IArrayMakeArrayZ(ptr_array, count) (DN_CppDeclType(&((ptr_array)->data)[0]))DN_CArrayMakeArray((ptr_array)->data, &(ptr_array)->size, (ptr_array)->max, sizeof(((ptr_array)->data)[0]), count, DN_ZMem_Yes) +#define DN_IArrayMake(ptr_array, z_mem) (DN_CppDeclType(&((ptr_array)->data)[0]))DN_CArrayMakeArray((ptr_array)->data, &(ptr_array)->size, (ptr_array)->max, sizeof(((ptr_array)->data)[0]), 1, z_mem) +#define DN_IArrayMakeZ(ptr_array) (DN_CppDeclType(&((ptr_array)->data)[0]))DN_CArrayMakeArray((ptr_array)->data, &(ptr_array)->size, (ptr_array)->max, sizeof(((ptr_array)->data)[0]), 1, DN_ZMem_Yes) +#define DN_IArrayAddArray(ptr_array, items, count, add) (DN_CppDeclType(&((ptr_array)->data)[0]))DN_CArrayAddArray((ptr_array)->data, &(ptr_array)->size, (ptr_array)->max, sizeof(((ptr_array)->data)[0]), items, count, add) +#define DN_IArrayAdd(ptr_array, item, add) (DN_CppDeclType(&((ptr_array)->data)[0]))DN_CArrayAddArray((ptr_array)->data, &(ptr_array)->size, (ptr_array)->max, sizeof(((ptr_array)->data)[0]), &item, 1, add) +#define DN_IArrayAppendArray(ptr_array, items, count) (DN_CppDeclType(&((ptr_array)->data)[0]))DN_CArrayAddArray((ptr_array)->data, &(ptr_array)->size, (ptr_array)->max, sizeof(((ptr_array)->data)[0]), items, count, DN_ArrayAdd_Append) +#define DN_IArrayAppend(ptr_array, item) (DN_CppDeclType(&((ptr_array)->data)[0]))DN_CArrayAddArray((ptr_array)->data, &(ptr_array)->size, (ptr_array)->max, sizeof(((ptr_array)->data)[0]), &item, 1, DN_ArrayAdd_Append) +#define DN_IArrayPrependArray(ptr_array, items, count) (DN_CppDeclType(&((ptr_array)->data)[0]))DN_CArrayAddArray((ptr_array)->data, &(ptr_array)->size, (ptr_array)->max, sizeof(((ptr_array)->data)[0]), items, count, DN_ArrayAdd_Prepend) +#define DN_IArrayPrepend(ptr_array, item) (DN_CppDeclType(&((ptr_array)->data)[0]))DN_CArrayAddArray((ptr_array)->data, &(ptr_array)->size, (ptr_array)->max, sizeof(((ptr_array)->data)[0]), &item, 1, DN_ArrayAdd_Prepend) +#define DN_IArrayEraseRange(ptr_array, begin_index, count, erase) DN_CArrayEraseRange((ptr_array)->data, &(ptr_array)->size, sizeof(((ptr_array)->data)[0]), begin_index, count, erase) +#define DN_IArrayErase(ptr_array, index, erase) DN_CArrayEraseRange((ptr_array)->data, &(ptr_array)->size, sizeof(((ptr_array)->data)[0]), index, 1, erase) +#define DN_IArrayInsertArray(ptr_array, index, items, count) (DN_CppDeclType(&((ptr_array)->data)[0]))DN_CArrayInsertArray((ptr_array)->data, &(ptr_array)->size, (ptr_array)->max, sizeof(((ptr_array)->data)[0]), index, items, count) +#define DN_IArrayInsert(ptr_array, index, item, count) (DN_CppDeclType(&((ptr_array)->data)[0]))DN_CArrayInsertArray((ptr_array)->data, &(ptr_array)->size, (ptr_array)->max, sizeof(((ptr_array)->data)[0]), index, &item, 1) +#define DN_IArrayPopFront(ptr_array, count) (DN_CppDeclType(&((ptr_array)->data)[0]))DN_CArrayPopFront((ptr_array)->data, &(ptr_array)->size, sizeof(((ptr_array)->data)[0]), count) +#define DN_IArrayPopBack(ptr_array, count) (DN_CppDeclType(&((ptr_array)->data)[0]))DN_CArrayPopBack((ptr_array)->data, &(ptr_array)->size, sizeof(((ptr_array)->data)[0]), count) + +#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 size, DN_USize elem_size, DN_U8 align, DN_ZMem zmem, DN_Arena *arena); + +DN_API void* DN_CArrayInsertArray (void *data, DN_USize *size, DN_USize max, DN_USize elem_size, DN_USize index, void const *items, DN_USize count); +DN_API void* DN_CArrayPopFront (void *data, DN_USize *size, DN_USize elem_size, DN_USize count); +DN_API void* DN_CArrayPopBack (void *data, DN_USize *size, DN_USize elem_size, DN_USize count); +DN_API DN_ArrayEraseResult DN_CArrayEraseRange (void *data, DN_USize *size, DN_USize elem_size, DN_USize begin_index, DN_ISize count, DN_ArrayErase erase); +DN_API void* DN_CArrayMakeArray (void *data, DN_USize *size, DN_USize max, DN_USize data_size, DN_USize make_size, DN_ZMem z_mem); +DN_API void* DN_CArrayAddArray (void *data, DN_USize *size, DN_USize max, DN_USize data_size, void const *elems, DN_USize elems_count, DN_ArrayAdd add); +DN_API bool DN_CArrayResizeFromPool (void **data, DN_USize *size, DN_USize *max, DN_USize data_size, DN_Pool *pool, DN_USize new_max); +DN_API bool DN_CArrayResizeFromArena (void **data, DN_USize *size, DN_USize *max, DN_USize data_size, DN_Arena *arena, DN_USize new_max); +DN_API bool DN_CArrayGrowFromPool (void **data, DN_USize size, DN_USize *max, DN_USize data_size, DN_Pool *pool, DN_USize new_max); +DN_API bool DN_CArrayGrowFromArena (void **data, DN_USize size, DN_USize *max, DN_USize data_size, DN_Pool *pool, DN_USize new_max); +DN_API bool DN_CArrayGrowIfNeededFromPool (void **data, DN_USize size, DN_USize *max, DN_USize data_size, DN_Pool *pool, DN_USize add_count); +DN_API bool DN_CArrayGrowIfNeededFromArena (void **data, DN_USize size, DN_USize *max, DN_USize data_size, DN_Arena *pool, DN_USize add_count); + +DN_API void* DN_SinglyLLDetach (void **link, void **next); + +DN_API bool DN_RingHasSpace (DN_Ring const *ring, DN_U64 size); +DN_API bool DN_RingHasData (DN_Ring const *ring, DN_U64 size); +DN_API void DN_RingWrite (DN_Ring *ring, void const *src, DN_U64 src_size); +#define DN_RingWriteStruct(ring, item) DN_RingWrite((ring), (item), sizeof(*(item))) +DN_API void DN_RingRead (DN_Ring *ring, void *dest, DN_U64 dest_size); +#define DN_RingReadStruct(ring, dest) DN_RingRead((ring), (dest), sizeof(*(dest))) + +DN_U32 const DN_DS_MAP_DEFAULT_HASH_SEED = 0x8a1ced49; +DN_U32 const DN_DS_MAP_SENTINEL_SLOT = 0; + +template DN_DSMap DN_DSMapInit (DN_Arena *arena, DN_U32 size, DN_DSMapFlags flags); +template void DN_DSMapDeinit (DN_DSMap *map, DN_ZMem z_mem); +template bool DN_DSMapIsValid (DN_DSMap const *map); +template DN_U32 DN_DSMapHash (DN_DSMap const *map, DN_DSMapKey key); +template DN_U32 DN_DSMapHashToSlotIndex (DN_DSMap const *map, DN_DSMapKey key); +template DN_DSMapResult DN_DSMapFind (DN_DSMap const *map, DN_DSMapKey key); +template DN_DSMapResult DN_DSMapMake (DN_DSMap *map, DN_DSMapKey key); +template DN_DSMapResult DN_DSMapSet (DN_DSMap *map, DN_DSMapKey key, T const &value); +template DN_DSMapResult DN_DSMapFindKeyU64 (DN_DSMap const *map, DN_U64 key); +template DN_DSMapResult DN_DSMapMakeKeyU64 (DN_DSMap *map, DN_U64 key); +template DN_DSMapResult DN_DSMapSetKeyU64 (DN_DSMap *map, DN_U64 key, T const &value); +template DN_DSMapResult DN_DSMapFindKeyStr8 (DN_DSMap const *map, DN_Str8 key); +template DN_DSMapResult DN_DSMapMakeKeyStr8 (DN_DSMap *map, DN_Str8 key); +template DN_DSMapResult DN_DSMapSetKeyStr8 (DN_DSMap *map, DN_Str8 key, T const &value); +template bool DN_DSMapResize (DN_DSMap *map, DN_U32 size); +template bool DN_DSMapErase (DN_DSMap *map, DN_DSMapKey key); +template bool DN_DSMapEraseKeyU64 (DN_DSMap *map, DN_U64 key); +template bool DN_DSMapEraseKeyStr8 (DN_DSMap *map, DN_Str8 key); +template DN_DSMapKey DN_DSMapKeyBuffer (DN_DSMap const *map, void const *data, DN_USize size); +template DN_DSMapKey DN_DSMapKeyBufferAsU64NoHash (DN_DSMap const *map, void const *data, DN_USize size); +template DN_DSMapKey DN_DSMapKeyU64 (DN_DSMap const *map, DN_U64 u64); +template DN_DSMapKey DN_DSMapKeyStr8 (DN_DSMap const *map, DN_Str8 string); +#define DN_DSMapKeyCStr8(map, string) DN_DSMapKeyBuffer(map, string, sizeof((string))/sizeof((string)[0]) - 1) +DN_API DN_DSMapKey DN_DSMapKeyU64NoHash (DN_U64 u64); +DN_API bool DN_DSMapKeyEquals (DN_DSMapKey lhs, DN_DSMapKey rhs); +DN_API bool operator== (DN_DSMapKey lhs, DN_DSMapKey rhs); +#endif // !defined(DN_CONTAINER_H) +// DN: Single header generator commented out => #include "Base/dn_base_leak.h" +#if !defined(DN_BASE_LEAK_H) +#define DN_BASE_LEAK_H + +// DN: Single header generator commented out => #if defined(_CLANGD) +// #include "../dn.h" +// #endif + +enum DN_LeakAllocFlag +{ + DN_LeakAllocFlag_Freed = 1 << 0, + DN_LeakAllocFlag_LeakPermitted = 1 << 1, +}; + +struct DN_LeakAlloc +{ + void *ptr; // 8 Pointer to the allocation being tracked + DN_USize size; // 16 Size of the allocation + DN_USize freed_size; // 24 Store the size of the allocation when it is freed + DN_Str8 stack_trace; // 40 Stack trace at the point of allocation + DN_Str8 freed_stack_trace; // 56 Stack trace of where the allocation was freed + DN_U16 flags; // 72 Bit flags from `DN_LeakAllocFlag` +}; + +// NOTE: We aim to keep the allocation record as light as possible as memory tracking can get +// expensive. Enforce that there is no unexpected padding. +DN_StaticAssert(sizeof(DN_LeakAlloc) == 64 || sizeof(DN_LeakAlloc) == 32); // NOTE: 64 bit vs 32 bit pointers respectively + +struct DN_LeakTracker +{ + DN_DSMap alloc_table; + DN_TicketMutex alloc_table_mutex; + DN_MemList alloc_table_mem; + DN_Arena alloc_table_arena; + DN_U64 alloc_table_bytes_allocated_for_stack_traces; +}; + +DN_API void DN_LeakTrackAlloc_ (DN_LeakTracker *leak, void *ptr, DN_USize size, bool alloc_can_leak); +DN_API void DN_LeakTrackDealloc_(DN_LeakTracker *leak, void *ptr); +DN_API void DN_LeakDump_ (DN_LeakTracker *leak); + +#if defined(DN_LEAK_TRACKING) +#define DN_LeakTrackAlloc(leak, ptr, size, alloc_can_leak) DN_LeakTrackAlloc_(leak, ptr, size, alloc_can_leak) +#define DN_LeakTrackDealloc(leak, ptr) DN_LeakTrackDealloc_(leak, ptr) +#define DN_LeakDump(leak) DN_LeakDump_(leak) +#else +#define DN_LeakTrackAlloc(leak, ptr, size, alloc_can_leak) do { (void)ptr; (void)size; (void)alloc_can_leak; } while (0) +#define DN_LeakTrackDealloc(leak, ptr) do { (void)ptr; } while (0) +#define DN_LeakDump(leak) do { } while (0) +#endif +#endif // DN_BASE_LEAK_H + +#if DN_H_WITH_OS +#if defined(DN_PLATFORM_WIN32) + // DN: Single header generator commented out => #include "OS/dn_os_windows.h" +#if !defined(DN_OS_WINDOWS_H) +#define DN_OS_WINDOWS_H + +// DN: Single header generator commented out => #if defined(_CLANGD) +// #include "../dn.h" +// #endif + +#if defined(DN_COMPILER_MSVC) || defined(DN_COMPILER_CLANG_CL) + #pragma comment(lib, "bcrypt") + #pragma comment(lib, "winhttp") + #pragma comment(lib, "dbghelp") + #pragma comment(lib, "comdlg32") + #pragma comment(lib, "pathcch") + #pragma comment(lib, "Shell32") // ShellExecuteW + #pragma comment(lib, "shlwapi") +#endif + +#if defined(DN_NO_WINDOWS_H_REPLACEMENT_HEADER) || defined(_INC_WINDOWS) + #define WIN32_LEAN_AND_MEAN + #include // LONG + #include // DN_OS_SecureRNGBytes -> BCryptOpenAlgorithmProvider ... etc + #include // DN_Win_MakeProcessDPIAware -> SetProcessDpiAwareProc + #include // PathRelativePathTO + #include // PathCchCanonicalizeEx + #include // WinHttp* + #include // PROCESS_MEMORY_COUNTERS_EX2 + #include // OPENFILENAMEW + #include +#else + DN_MSVC_WARNING_PUSH + DN_MSVC_WARNING_DISABLE(4201) // warning C4201: nonstandard extension used: nameless struct/union + + // NOTE: basetsd.h ///////////////////////////////////////////////////////////////////////////// + typedef unsigned __int64 ULONG_PTR, *PULONG_PTR; + typedef unsigned __int64 UINT_PTR, *PUINT_PTR; + typedef ULONG_PTR SIZE_T, *PSIZE_T; + typedef __int64 LONG_PTR, *PLONG_PTR; + typedef ULONG_PTR DWORD_PTR, *PDWORD_PTR; + typedef unsigned __int64 ULONG64, *PULONG64; + typedef unsigned __int64 DWORD64, *PDWORD64; + + // NOTE: shared/minwindef.h //////////////////////////////////////////////////////////////////// + struct HINSTANCE__ { + int unused; + }; + typedef struct HINSTANCE__ *HINSTANCE; + + typedef unsigned long DWORD; + typedef int BOOL; + typedef int INT; + typedef unsigned long ULONG; + typedef unsigned int UINT; + typedef unsigned short WORD; + typedef unsigned char BYTE; + typedef unsigned char UCHAR; + typedef HINSTANCE HMODULE; /* HMODULEs can be used in place of HINSTANCEs */ + typedef void * HANDLE; + typedef HANDLE HLOCAL; + + typedef unsigned __int64 WPARAM; + typedef LONG_PTR LPARAM; + typedef LONG_PTR LRESULT; + + #define MAX_PATH 260 + + typedef struct _FILETIME { + DWORD dwLowDateTime; + DWORD dwHighDateTime; + } FILETIME, *PFILETIME, *LPFILETIME; + + // NOTE: shared/winerror.h ///////////////////////////////////////////////////////////////////// + // NOTE: GetModuleFileNameW + #define ERROR_INSUFFICIENT_BUFFER 122L // dderror + + // NOTE: um/winnls.h /////////////////////////////////////////////////////////////////////////// + // NOTE: MultiByteToWideChar + #define CP_UTF8 65001 // UTF-8 translation + + // NOTE: um/winnt.h //////////////////////////////////////////////////////////////////////////// + typedef void VOID; + typedef __int64 LONGLONG; + typedef unsigned __int64 ULONGLONG; + typedef void * HANDLE; + typedef char CHAR; + typedef short SHORT; + typedef long LONG; + typedef wchar_t WCHAR; // wc, 16-bit UNICODE character + typedef CHAR * NPSTR, *LPSTR, *PSTR; + typedef WCHAR * NWPSTR, *LPWSTR, *PWSTR; + typedef long HRESULT; + + // NOTE: VirtualAlloc: Allocation Type + #define MEM_RESERVE 0x00002000 + #define MEM_COMMIT 0x00001000 + #define MEM_DECOMMIT 0x00004000 + #define MEM_RELEASE 0x00008000 + + // NOTE: VirtualAlloc: Page Permissions + #define PAGE_NOACCESS 0x01 + #define PAGE_READONLY 0x02 + #define PAGE_READWRITE 0x04 + #define PAGE_GUARD 0x100 + + // NOTE: HeapAlloc + #define HEAP_ZERO_MEMORY 0x00000008 + #define HEAP_NO_SERIALIZE 0x00000001 + #define HEAP_GROWABLE 0x00000002 + #define HEAP_GENERATE_EXCEPTIONS 0x00000004 + #define HEAP_ZERO_MEMORY 0x00000008 + #define HEAP_REALLOC_IN_PLACE_ONLY 0x00000010 + #define HEAP_TAIL_CHECKING_ENABLED 0x00000020 + #define HEAP_FREE_CHECKING_ENABLED 0x00000040 + #define HEAP_DISABLE_COALESCE_ON_FREE 0x00000080 + #define HEAP_CREATE_ALIGN_16 0x00010000 + #define HEAP_CREATE_ENABLE_TRACING 0x00020000 + #define HEAP_CREATE_ENABLE_EXECUTE 0x00040000 + #define HEAP_MAXIMUM_TAG 0x0FFF + #define HEAP_PSEUDO_TAG_FLAG 0x8000 + #define HEAP_TAG_SHIFT 18 + #define HEAP_CREATE_SEGMENT_HEAP 0x00000100 + #define HEAP_CREATE_HARDENED 0x00000200 + + // NOTE: FormatMessageA + #define MAKELANGID(p, s) ((((WORD )(s)) << 10) | (WORD )(p)) + #define LANG_NEUTRAL 0x00 + #define SUBLANG_DEFAULT 0x01 // user default + + // NOTE: CreateFile + #define GENERIC_READ (0x80000000L) + #define GENERIC_WRITE (0x40000000L) + #define GENERIC_EXECUTE (0x20000000L) + #define GENERIC_ALL (0x10000000L) + + #define FILE_APPEND_DATA (0x0004) // file + + // NOTE: CreateFile/FindFirstFile + #define FILE_SHARE_READ 0x00000001 + #define FILE_SHARE_WRITE 0x00000002 + #define FILE_SHARE_DELETE 0x00000004 + + #define FILE_ATTRIBUTE_READONLY 0x00000001 + #define FILE_ATTRIBUTE_HIDDEN 0x00000002 + #define FILE_ATTRIBUTE_SYSTEM 0x00000004 + #define FILE_ATTRIBUTE_DIRECTORY 0x00000010 + #define FILE_ATTRIBUTE_NORMAL 0x00000080 + + // NOTE: STACKFRAME64 + #define IMAGE_FILE_MACHINE_AMD64 0x8664 // AMD64 (K8) + + // NOTE: WaitForSingleObject + #define WAIT_TIMEOUT 258L // dderror + #define STATUS_WAIT_0 ((DWORD )0x00000000L) + #define STATUS_ABANDONED_WAIT_0 ((DWORD )0x00000080L) + + #define S_OK ((HRESULT)0L) + #define S_FALSE ((HRESULT)1L) + + typedef union _ULARGE_INTEGER { + struct { + DWORD LowPart; + DWORD HighPart; + } DUMMYSTRUCTNAME; + struct { + DWORD LowPart; + DWORD HighPart; + } u; + ULONGLONG QuadPart; + } ULARGE_INTEGER; + + typedef union _LARGE_INTEGER { + struct { + DWORD LowPart; + LONG HighPart; + } DUMMYSTRUCTNAME; + struct { + DWORD LowPart; + LONG HighPart; + } u; + LONGLONG QuadPart; + } LARGE_INTEGER; + + typedef struct __declspec(align(16)) _M128A { + ULONGLONG Low; + LONGLONG High; + } M128A, *PM128A; + + typedef struct __declspec(align(16)) _XSAVE_FORMAT { + WORD ControlWord; + WORD StatusWord; + BYTE TagWord; + BYTE Reserved1; + WORD ErrorOpcode; + DWORD ErrorOffset; + WORD ErrorSelector; + WORD Reserved2; + DWORD DataOffset; + WORD DataSelector; + WORD Reserved3; + DWORD MxCsr; + DWORD MxCsr_Mask; + M128A FloatRegisters[8]; + #if defined(_WIN64) + M128A XmmRegisters[16]; + BYTE Reserved4[96]; + #else + M128A XmmRegisters[8]; + BYTE Reserved4[224]; + #endif + } XSAVE_FORMAT, *PXSAVE_FORMAT; + typedef XSAVE_FORMAT XMM_SAVE_AREA32, *PXMM_SAVE_AREA32; + + typedef struct __declspec(align(16)) _CONTEXT { + DWORD64 P1Home; + DWORD64 P2Home; + DWORD64 P3Home; + DWORD64 P4Home; + DWORD64 P5Home; + DWORD64 P6Home; + DWORD ContextFlags; + DWORD MxCsr; + WORD SegCs; + WORD SegDs; + WORD SegEs; + WORD SegFs; + WORD SegGs; + WORD SegSs; + DWORD EFlags; + DWORD64 Dr0; + DWORD64 Dr1; + DWORD64 Dr2; + DWORD64 Dr3; + DWORD64 Dr6; + DWORD64 Dr7; + DWORD64 Rax; + DWORD64 Rcx; + DWORD64 Rdx; + DWORD64 Rbx; + DWORD64 Rsp; + DWORD64 Rbp; + DWORD64 Rsi; + DWORD64 Rdi; + DWORD64 R8; + DWORD64 R9; + DWORD64 R10; + DWORD64 R11; + DWORD64 R12; + DWORD64 R13; + DWORD64 R14; + DWORD64 R15; + DWORD64 Rip; + + union { + XMM_SAVE_AREA32 FltSave; + + struct { + M128A Header[2]; + M128A Legacy[8]; + M128A Xmm0; + M128A Xmm1; + M128A Xmm2; + M128A Xmm3; + M128A Xmm4; + M128A Xmm5; + M128A Xmm6; + M128A Xmm7; + M128A Xmm8; + M128A Xmm9; + M128A Xmm10; + M128A Xmm11; + M128A Xmm12; + M128A Xmm13; + M128A Xmm14; + M128A Xmm15; + } DUMMYSTRUCTNAME; + } DUMMYUNIONNAME; + + M128A VectorRegister[26]; + DWORD64 VectorControl; + DWORD64 DebugControl; + DWORD64 LastBranchToRip; + DWORD64 LastBranchFromRip; + DWORD64 LastExceptionToRip; + DWORD64 LastExceptionFromRip; + } CONTEXT; + + typedef struct _LIST_ENTRY { + struct _LIST_ENTRY *Flink; + struct _LIST_ENTRY *Blink; + } LIST_ENTRY, *PLIST_ENTRY, PRLIST_ENTRY; + + typedef struct _RTL_CRITICAL_SECTION_DEBUG { + WORD Type; + WORD CreatorBackTraceIndex; + struct _RTL_CRITICAL_SECTION *CriticalSection; + LIST_ENTRY ProcessLocksList; + DWORD EntryCount; + DWORD ContentionCount; + DWORD Flags; + WORD CreatorBackTraceIndexHigh; + WORD Identifier; + } RTL_CRITICAL_SECTION_DEBUG, *PRTL_CRITICAL_SECTION_DEBUG, RTL_RESOURCE_DEBUG, *PRTL_RESOURCE_DEBUG; + + typedef struct _RTL_CONDITION_VARIABLE { + VOID *Ptr; + } RTL_CONDITION_VARIABLE, *PRTL_CONDITION_VARIABLE; + + #pragma pack(push, 8) + typedef struct _RTL_CRITICAL_SECTION { + PRTL_CRITICAL_SECTION_DEBUG DebugInfo; + + // + // The following three fields control entering and exiting the critical + // section for the resource + // + + LONG LockCount; + LONG RecursionCount; + HANDLE OwningThread; // from the thread's ClientId->UniqueThread + HANDLE LockSemaphore; + ULONG_PTR SpinCount; // force size on 64-bit systems when packed + } RTL_CRITICAL_SECTION, *PRTL_CRITICAL_SECTION; + #pragma pack(pop) + + typedef struct _MODLOAD_DATA { + DWORD ssize; // size of this struct + DWORD ssig; // signature identifying the passed data + VOID *data; // pointer to passed data + DWORD size; // size of passed data + DWORD flags; // options + } MODLOAD_DATA, *PMODLOAD_DATA; + + typedef struct _RTL_BARRIER { + DWORD Reserved1; + DWORD Reserved2; + ULONG_PTR Reserved3[2]; + DWORD Reserved4; + DWORD Reserved5; + } RTL_BARRIER, *PRTL_BARRIER; + + #define SLMFLAG_VIRTUAL 0x1 + #define SLMFLAG_ALT_INDEX 0x2 + #define SLMFLAG_NO_SYMBOLS 0x4 + + extern "C" + { + __declspec(dllimport) VOID __stdcall RtlCaptureContext(CONTEXT *ContextRecord); + __declspec(dllimport) HANDLE __stdcall GetCurrentProcess(void); + __declspec(dllimport) HANDLE __stdcall GetCurrentThread(void); + __declspec(dllimport) DWORD __stdcall SymSetOptions(DWORD SymOptions); + __declspec(dllimport) BOOL __stdcall SymInitialize(HANDLE hProcess, const CHAR* UserSearchPath, BOOL fInvadeProcess); + __declspec(dllimport) DWORD64 __stdcall SymLoadModuleEx(HANDLE hProcess, HANDLE hFile, CHAR const *ImageName, CHAR const *ModuleName, DWORD64 BaseOfDll, DWORD DllSize, MODLOAD_DATA *Data, DWORD Flags); + __declspec(dllimport) BOOL __stdcall SymUnloadModule64(HANDLE hProcess, DWORD64 BaseOfDll); + } + + // NOTE: um/heapapi.h //////////////////////////////////////////////////////////////////// + extern "C" + { + __declspec(dllimport) HANDLE __stdcall HeapCreate(DWORD flOptions, SIZE_T dwInitialSize, SIZE_T dwMaximumSize); + __declspec(dllimport) BOOL __stdcall HeapDestroy(HANDLE hHeap); + __declspec(dllimport) VOID * __stdcall HeapAlloc(HANDLE hHeap, DWORD dwFlags,SIZE_T dwBytes); + __declspec(dllimport) VOID * __stdcall HeapReAlloc(HANDLE hHeap, DWORD dwFlags, VOID *lpMem, SIZE_T dwBytes); + __declspec(dllimport) BOOL __stdcall HeapFree(HANDLE hHeap, DWORD dwFlags, VOID *lpMem); + __declspec(dllimport) SIZE_T __stdcall HeapSize(HANDLE hHeap, DWORD dwFlags, VOID const *lpMem); + __declspec(dllimport) HANDLE __stdcall GetProcessHeap(VOID); + __declspec(dllimport) SIZE_T __stdcall HeapCompact(HANDLE hHeap, DWORD dwFlags); + } + + // NOTE: shared/windef.h //////////////////////////////////////////////////////////////////// + typedef struct tagPOINT + { + LONG x; + LONG y; + } POINT, *PPOINT, *NPPOINT, *LPPOINT; + + // NOTE: handleapi.h /////////////////////////////////////////////////////////////////////////// + #define INVALID_HANDLE_VALUE ((HANDLE)(LONG_PTR)-1) + + extern "C" + { + __declspec(dllimport) BOOL __stdcall CloseHandle(HANDLE hObject); + } + + // NOTE: consoleapi.h /////////////////////////////////////////////////////////////////////////// + extern "C" + { + __declspec(dllimport) BOOL __stdcall WriteConsoleA(HANDLE hConsoleOutput, const VOID* lpBuffer, DWORD nNumberOfCharsToWrite, DWORD *lpNumberOfCharsWritten, VOID *lpReserved); + __declspec(dllimport) BOOL __stdcall AllocConsole(VOID); + __declspec(dllimport) BOOL __stdcall FreeConsole(VOID); + __declspec(dllimport) BOOL __stdcall AttachConsole(DWORD dwProcessId); + __declspec(dllimport) BOOL __stdcall GetConsoleMode(HANDLE hConsoleHandle, DWORD *lpMode); + } + + // NOTE: um/minwinbase.h /////////////////////////////////////////////////////////////////////// + // NOTE: FindFirstFile + #define FIND_FIRST_EX_CASE_SENSITIVE 0x00000001 + #define FIND_FIRST_EX_LARGE_FETCH 0x00000002 + + // NOTE: WaitFor.. + #define WAIT_FAILED ((DWORD)0xFFFFFFFF) + #define WAIT_OBJECT_0 ((STATUS_WAIT_0 ) + 0 ) + #define WAIT_ABANDONED ((STATUS_ABANDONED_WAIT_0 ) + 0 ) + #define WAIT_ABANDONED_0 ((STATUS_ABANDONED_WAIT_0 ) + 0 ) + + // NOTE: CreateProcessW + #define CREATE_UNICODE_ENVIRONMENT 0x00000400 + #define CREATE_NO_WINDOW 0x08000000 + + typedef enum _GET_FILEEX_INFO_LEVELS { + GetFileExInfoStandard, + GetFileExMaxInfoLevel + } GET_FILEEX_INFO_LEVELS; + + typedef struct _SECURITY_ATTRIBUTES { + DWORD nLength; + VOID *lpSecurityDescriptor; + BOOL bInheritHandle; + } SECURITY_ATTRIBUTES, *PSECURITY_ATTRIBUTES, *LPSECURITY_ATTRIBUTES; + + typedef enum _FINDEX_INFO_LEVELS { + FindExInfoStandard, + FindExInfoBasic, + FindExInfoMaxInfoLevel + } FINDEX_INFO_LEVELS; + + typedef enum _FINDEX_SEARCH_OPS { + FindExSearchNameMatch, + FindExSearchLimitToDirectories, + FindExSearchLimitToDevices, + FindExSearchMaxSearchOp + } FINDEX_SEARCH_OPS; + + typedef struct _WIN32_FIND_DATAW { + DWORD dwFileAttributes; + FILETIME ftCreationTime; + FILETIME ftLastAccessTime; + FILETIME ftLastWriteTime; + DWORD nFileSizeHigh; + DWORD nFileSizeLow; + DWORD dwReserved0; + DWORD dwReserved1; + WCHAR cFileName[ MAX_PATH ]; + WCHAR cAlternateFileName[ 14 ]; + #ifdef _MAC + DWORD dwFileType; + DWORD dwCreatorType; + WORD wFinderFlags; + #endif + } WIN32_FIND_DATAW, *PWIN32_FIND_DATAW, *LPWIN32_FIND_DATAW; + + typedef struct _SYSTEMTIME { + WORD wYear; + WORD wMonth; + WORD wDayOfWeek; + WORD wDay; + WORD wHour; + WORD wMinute; + WORD wSecond; + WORD wMilliseconds; + } SYSTEMTIME, *PSYSTEMTIME, *LPSYSTEMTIME; + + typedef struct _OVERLAPPED { + ULONG_PTR Internal; + ULONG_PTR InternalHigh; + union { + struct { + DWORD Offset; + DWORD OffsetHigh; + } DUMMYSTRUCTNAME; + VOID *Pointer; + } DUMMYUNIONNAME; + + HANDLE hEvent; + } OVERLAPPED, *LPOVERLAPPED; + + typedef RTL_CRITICAL_SECTION CRITICAL_SECTION; + + #define WAIT_FAILED ((DWORD)0xFFFFFFFF) + #define WAIT_OBJECT_0 ((STATUS_WAIT_0 ) + 0 ) + + #define INFINITE 0xFFFFFFFF // Wait/Synchronisation: Infinite timeout + + #define STD_INPUT_HANDLE ((DWORD)-10) + #define STD_OUTPUT_HANDLE ((DWORD)-11) + #define STD_ERROR_HANDLE ((DWORD)-12) + + #define HANDLE_FLAG_INHERIT 0x00000001 + #define HANDLE_FLAG_PROTECT_FROM_CLOSE 0x00000002 + + // NOTE: MoveFile + #define MOVEFILE_REPLACE_EXISTING 0x00000001 + #define MOVEFILE_COPY_ALLOWED 0x00000002 + + // NOTE: FormatMessageA + #define FORMAT_MESSAGE_ALLOCATE_BUFFER 0x00000100 + #define FORMAT_MESSAGE_IGNORE_INSERTS 0x00000200 + #define FORMAT_MESSAGE_FROM_HMODULE 0x00000800 + #define FORMAT_MESSAGE_FROM_SYSTEM 0x00001000 + + // NOTE: CreateProcessW + #define STARTF_USESTDHANDLES 0x00000100 + + extern "C" + { + __declspec(dllimport) BOOL __stdcall MoveFileExW (const WCHAR *lpExistingFileName, const WCHAR *lpNewFileName, DWORD dwFlags); + __declspec(dllimport) BOOL __stdcall CopyFileW (const WCHAR *lpExistingFileName, const WCHAR *lpNewFileName, BOOL bFailIfExists); + __declspec(dllimport) HANDLE __stdcall CreateSemaphoreA(SECURITY_ATTRIBUTES *lpSemaphoreAttributes, LONG lInitialCount, LONG lMaximumCount, const CHAR *lpName); + __declspec(dllimport) DWORD __stdcall FormatMessageW (DWORD dwFlags, VOID const *lpSource, DWORD dwMessageId, DWORD dwLanguageId, LPWSTR lpBuffer, DWORD nSize, va_list *Arguments); + __declspec(dllimport) HLOCAL __stdcall LocalFree (HLOCAL hMem); + } + + // NOTE: um/stringapiset.h ///////////////////////////////////////////////////////////////////// + extern "C" + { + __declspec(dllimport) int __stdcall MultiByteToWideChar(UINT CodePage, DWORD dwFlags, const CHAR *lpMultiByteStr, int cbMultiByte, WCHAR *lpWideCharStr, int cchWideChar); + __declspec(dllimport) int __stdcall WideCharToMultiByte(UINT CodePage, DWORD dwFlags, const WCHAR *lpWideCharStr, int cchWideChar, LPSTR lpMultiByteStr, int cbMultiByte, const CHAR *lpDefaultChar, BOOL *lpUsedDefaultChar); + } + + // NOTE: um/fileapi.h ////////////////////////////////////////////////////////////////////////// + #define INVALID_FILE_SIZE ((DWORD)0xFFFFFFFF) + #define INVALID_FILE_ATTRIBUTES ((DWORD)-1) + + // NOTE: CreateFile + #define CREATE_NEW 1 + #define CREATE_ALWAYS 2 + #define OPEN_EXISTING 3 + #define OPEN_ALWAYS 4 + #define TRUNCATE_EXISTING 5 + + typedef struct _WIN32_FILE_ATTRIBUTE_DATA { + DWORD dwFileAttributes; + FILETIME ftCreationTime; + FILETIME ftLastAccessTime; + FILETIME ftLastWriteTime; + DWORD nFileSizeHigh; + DWORD nFileSizeLow; + } WIN32_FILE_ATTRIBUTE_DATA, *LPWIN32_FILE_ATTRIBUTE_DATA; + + extern "C" + { + __declspec(dllimport) BOOL __stdcall FlushFileBuffers (HANDLE hFile); + __declspec(dllimport) BOOL __stdcall CreateDirectoryW (const WCHAR *lpPathName, SECURITY_ATTRIBUTES *lpSecurityAttributes); + __declspec(dllimport) BOOL __stdcall RemoveDirectoryW (const WCHAR *lpPathName); + __declspec(dllimport) BOOL __stdcall FindNextFileW (HANDLE hFindFile, WIN32_FIND_DATAW *lpFindFileData); + __declspec(dllimport) BOOL __stdcall FindClose (HANDLE hFindFile); + __declspec(dllimport) BOOL __stdcall FileTimeToLocalFileTime(const FILETIME *lpFileTime, FILETIME *lpLocalFileTime); + + __declspec(dllimport) HANDLE __stdcall FindFirstFileExW (const WCHAR *lpFileName, FINDEX_INFO_LEVELS fInfoLevelId, VOID *lpFindFileData, FINDEX_SEARCH_OPS fSearchOp, VOID *lpSearchFilter, DWORD dwAdditionalFlags); + __declspec(dllimport) BOOL __stdcall GetFileAttributesExW (const WCHAR *lpFileName, GET_FILEEX_INFO_LEVELS fInfoLevelId, VOID *lpFileInformation); + __declspec(dllimport) BOOL __stdcall GetFileSizeEx (HANDLE hFile, LARGE_INTEGER *lpFileSize); + __declspec(dllimport) BOOL __stdcall DeleteFileW (const WCHAR *lpFileName); + __declspec(dllimport) HANDLE __stdcall CreateFileW (const WCHAR *lpFileName, DWORD dwDesiredAccess, DWORD dwShareMode, SECURITY_ATTRIBUTES *lpSecurityAttributes, DWORD dwCreationDisposition, DWORD dwFlagsAndAttributes, HANDLE hTemplateFile); + __declspec(dllimport) BOOL __stdcall ReadFile (HANDLE hFile, VOID *lpBuffer, DWORD nNumberOfBytesToRead, DWORD *lpNumberOfBytesRead, OVERLAPPED *lpOverlapped); + __declspec(dllimport) BOOL __stdcall WriteFile (HANDLE hFile, const VOID *lpBuffer, DWORD nNumberOfBytesToWrite, DWORD *lpNumberOfBytesWritten, OVERLAPPED *lpOverlapped); + __declspec(dllimport) BOOL __stdcall GetDiskFreeSpaceExW (WCHAR const *lpDirectoryName, ULARGE_INTEGER *lpFreeBytesAvailableToCaller, ULARGE_INTEGER *lpTotalNumberOfBytes, ULARGE_INTEGER *lpTotalNumberOfFreeBytes); + } + + // NOTE: um/processenv.h /////////////////////////////////////////////////////////////////////// + extern "C" + { + __declspec(dllimport) DWORD __stdcall GetCurrentDirectoryW (DWORD nBufferLength, WCHAR *lpBuffer); + __declspec(dllimport) HANDLE __stdcall GetStdHandle (DWORD nStdHandle); + __declspec(dllimport) WCHAR* __stdcall GetEnvironmentStringsW (); + __declspec(dllimport) BOOL __stdcall FreeEnvironmentStringsW(WCHAR *penv); + __declspec(dllimport) DWORD __stdcall GetEnvironmentVariableW(WCHAR const *lpName, WCHAR *lpBuffer, DWORD nSize); + __declspec(dllimport) BOOL __stdcall SetEnvironmentVariableW(WCHAR const *lpName, WCHAR const *lpValue); + } + + // NOTE: um/psapi.h //////////////////////////////////////////////////////////////////////////// + typedef struct _PROCESS_MEMORY_COUNTERS { + 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; + } PROCESS_MEMORY_COUNTERS; + typedef PROCESS_MEMORY_COUNTERS *PPROCESS_MEMORY_COUNTERS; + + extern "C" + { + __declspec(dllimport) BOOL __stdcall GetProcessMemoryInfo(HANDLE Process, PPROCESS_MEMORY_COUNTERS ppsmemCounters, DWORD cb); + } + + // NOTE: um/sysinfoapi.h /////////////////////////////////////////////////////////////////////// + typedef struct _SYSTEM_INFO { + union { + DWORD dwOemId; // Obsolete field...do not use + struct { + WORD wProcessorArchitecture; + WORD wReserved; + } DUMMYSTRUCTNAME; + } DUMMYUNIONNAME; + DWORD dwPageSize; + VOID *lpMinimumApplicationAddress; + VOID *lpMaximumApplicationAddress; + DWORD_PTR dwActiveProcessorMask; + DWORD dwNumberOfProcessors; + DWORD dwProcessorType; + DWORD dwAllocationGranularity; + WORD wProcessorLevel; + WORD wProcessorRevision; + } SYSTEM_INFO, *LPSYSTEM_INFO; + + extern "C" + { + __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); + } + + // NOTE: um/timezoneapi.h ////////////////////////////////////////////////////////////////////// + typedef struct _TIME_ZONE_INFORMATION { + LONG Bias; + WCHAR StandardName[32]; + SYSTEMTIME StandardDate; + LONG StandardBias; + WCHAR DaylightName[32]; + SYSTEMTIME DaylightDate; + LONG DaylightBias; + } TIME_ZONE_INFORMATION, *PTIME_ZONE_INFORMATION, *LPTIME_ZONE_INFORMATION; + + extern "C" + { + __declspec(dllimport) BOOL __stdcall FileTimeToSystemTime (const FILETIME* lpFileTime, SYSTEMTIME *lpSystemTime); + __declspec(dllimport) BOOL __stdcall SystemTimeToFileTime (const SYSTEMTIME* lpSystemTime, FILETIME *lpFileTime); + __declspec(dllimport) BOOL __stdcall TzSpecificLocalTimeToSystemTime(const TIME_ZONE_INFORMATION* lpTimeZoneInformation, const SYSTEMTIME* lpLocalTime, const LPSYSTEMTIME lpUniversalTime); + } + + // NOTE: shared/windef.h /////////////////////////////////////////////////////////////////////// + typedef struct tagRECT { + LONG left; + LONG top; + LONG right; + LONG bottom; + } RECT; + + struct HWND__ { + int unused; + }; + typedef struct HWND__ *HWND; + + struct DPI_AWARENESS_CONTEXT__ { + int unused; + }; + typedef struct DPI_AWARENESS_CONTEXT__ *DPI_AWARENESS_CONTEXT; + + typedef enum DPI_AWARENESS { + DPI_AWARENESS_INVALID = -1, + DPI_AWARENESS_UNAWARE = 0, + DPI_AWARENESS_SYSTEM_AWARE = 1, + DPI_AWARENESS_PER_MONITOR_AWARE = 2 + } DPI_AWARENESS; + + #define DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2 ((DPI_AWARENESS_CONTEXT)-4) + + // NOTE: um/winuser.h ////////////////////////////////////////////////////////////////////////// + typedef struct tagWINDOWPLACEMENT { + UINT length; + UINT flags; + UINT showCmd; + POINT ptMinPosition; + POINT ptMaxPosition; + RECT rcNormalPosition; + #ifdef _MAC + RECT rcDevice; + #endif + } WINDOWPLACEMENT; + typedef WINDOWPLACEMENT *PWINDOWPLACEMENT, *LPWINDOWPLACEMENT; + + #define SW_HIDE 0 + #define SW_NORMAL 1 + #define SW_MAXIMIZE 3 + #define SW_SHOWNOACTIVATE 4 + #define SW_SHOW 5 + #define SW_FORCEMINIMIZE 11 + + extern "C" + { + __declspec(dllimport) BOOL __stdcall GetWindowRect (HWND hWnd, RECT *lpRect); + __declspec(dllimport) BOOL __stdcall SetWindowPos (HWND hWnd, HWND hWndInsertAfter, int X, int Y, int cx, int cy, UINT uFlags); + __declspec(dllimport) UINT __stdcall GetWindowModuleFileNameA(HWND hwnd, LPSTR pszFileName, UINT cchFileNameMax); + __declspec(dllimport) BOOL __stdcall ShowWindow (HWND hWnd, int nCmdShow); + __declspec(dllimport) BOOL __stdcall GetWindowPlacement (HWND hWnd, WINDOWPLACEMENT *lpwndpl); + + } + + // NOTE: um/wininet.h ////////////////////////////////////////////////////////////////////////// + typedef WORD INTERNET_PORT; + typedef VOID *HINTERNET; + + // NOTE: um/winhttp.h ////////////////////////////////////////////////////////////////////////// + #define WINHTTP_ACCESS_TYPE_DEFAULT_PROXY 0 + #define WINHTTP_ACCESS_TYPE_NO_PROXY 1 + #define WINHTTP_ACCESS_TYPE_NAMED_PROXY 3 + #define WINHTTP_ACCESS_TYPE_AUTOMATIC_PROXY 4 + + #define INTERNET_DEFAULT_PORT 0 // use the protocol-specific default + #define INTERNET_DEFAULT_HTTP_PORT 80 // " " HTTP " + #define INTERNET_DEFAULT_HTTPS_PORT 443 // " " HTTPS " + + // NOTE: WinHttpOpen + #define WINHTTP_FLAG_ASYNC 0x10000000 // this session is asynchronous (where supported) + #define WINHTTP_FLAG_SECURE_DEFAULTS 0x30000000 // note that this flag also forces async + + // NOTE: WinHttpOpenRequest + #define WINHTTP_FLAG_SECURE 0x00800000 // use SSL if applicable (HTTPS) + #define WINHTTP_FLAG_ESCAPE_PERCENT 0x00000004 // if escaping enabled, escape percent as well + #define WINHTTP_FLAG_NULL_CODEPAGE 0x00000008 // assume all symbols are ASCII, use fast convertion + #define WINHTTP_FLAG_ESCAPE_DISABLE 0x00000040 // disable escaping + #define WINHTTP_FLAG_ESCAPE_DISABLE_QUERY 0x00000080 // if escaping enabled escape path part, but do not escape query + #define WINHTTP_FLAG_BYPASS_PROXY_CACHE 0x00000100 // add "pragma: no-cache" request header + #define WINHTTP_FLAG_REFRESH WINHTTP_FLAG_BYPASS_PROXY_CACHE + #define WINHTTP_FLAG_AUTOMATIC_CHUNKING 0x00000200 // Send request without content-length header or chunked TE + + #define WINHTTP_NO_PROXY_NAME NULL + #define WINHTTP_NO_PROXY_BYPASS NULL + + // + // WINHTTP_QUERY_FLAG_NUMBER - if this bit is set in the dwInfoLevel parameter of + // HttpQueryHeader(), then the value of the header will be converted to a number + // before being returned to the caller, if applicable + // + #define WINHTTP_QUERY_FLAG_NUMBER 0x20000000 + + #define WINHTTP_QUERY_MIME_VERSION 0 + #define WINHTTP_QUERY_CONTENT_TYPE 1 + #define WINHTTP_QUERY_CONTENT_TRANSFER_ENCODING 2 + #define WINHTTP_QUERY_CONTENT_ID 3 + #define WINHTTP_QUERY_CONTENT_DESCRIPTION 4 + #define WINHTTP_QUERY_CONTENT_LENGTH 5 + #define WINHTTP_QUERY_CONTENT_LANGUAGE 6 + #define WINHTTP_QUERY_ALLOW 7 + #define WINHTTP_QUERY_PUBLIC 8 + #define WINHTTP_QUERY_DATE 9 + #define WINHTTP_QUERY_EXPIRES 10 + #define WINHTTP_QUERY_LAST_MODIFIED 11 + #define WINHTTP_QUERY_MESSAGE_ID 12 + #define WINHTTP_QUERY_URI 13 + #define WINHTTP_QUERY_DERIVED_FROM 14 + #define WINHTTP_QUERY_COST 15 + #define WINHTTP_QUERY_LINK 16 + #define WINHTTP_QUERY_PRAGMA 17 + #define WINHTTP_QUERY_VERSION 18 // special: part of status line + #define WINHTTP_QUERY_STATUS_CODE 19 // special: part of status line + #define WINHTTP_QUERY_STATUS_TEXT 20 // special: part of status line + #define WINHTTP_QUERY_RAW_HEADERS 21 // special: all headers as ASCIIZ + #define WINHTTP_QUERY_RAW_HEADERS_CRLF 22 // special: all headers + #define WINHTTP_QUERY_CONNECTION 23 + #define WINHTTP_QUERY_ACCEPT 24 + #define WINHTTP_QUERY_ACCEPT_CHARSET 25 + #define WINHTTP_QUERY_ACCEPT_ENCODING 26 + #define WINHTTP_QUERY_ACCEPT_LANGUAGE 27 + #define WINHTTP_QUERY_AUTHORIZATION 28 + #define WINHTTP_QUERY_CONTENT_ENCODING 29 + #define WINHTTP_QUERY_FORWARDED 30 + #define WINHTTP_QUERY_FROM 31 + #define WINHTTP_QUERY_IF_MODIFIED_SINCE 32 + #define WINHTTP_QUERY_LOCATION 33 + #define WINHTTP_QUERY_ORIG_URI 34 + #define WINHTTP_QUERY_REFERER 35 + #define WINHTTP_QUERY_RETRY_AFTER 36 + #define WINHTTP_QUERY_SERVER 37 + #define WINHTTP_QUERY_TITLE 38 + #define WINHTTP_QUERY_USER_AGENT 39 + #define WINHTTP_QUERY_WWW_AUTHENTICATE 40 + #define WINHTTP_QUERY_PROXY_AUTHENTICATE 41 + #define WINHTTP_QUERY_ACCEPT_RANGES 42 + #define WINHTTP_QUERY_SET_COOKIE 43 + #define WINHTTP_QUERY_COOKIE 44 + #define WINHTTP_QUERY_REQUEST_METHOD 45 // special: GET/POST etc. + #define WINHTTP_QUERY_REFRESH 46 + #define WINHTTP_QUERY_CONTENT_DISPOSITION 47 + + // NOTE: WinHttpQueryHeaders prettifiers for optional parameters. + #define WINHTTP_HEADER_NAME_BY_INDEX NULL + #define WINHTTP_NO_OUTPUT_BUFFER NULL + #define WINHTTP_NO_HEADER_INDEX NULL + + // NOTE: Http Response Status Codes + #define HTTP_STATUS_CONTINUE 100 // OK to continue with request + #define HTTP_STATUS_SWITCH_PROTOCOLS 101 // server has switched protocols in upgrade header + + #define HTTP_STATUS_OK 200 // request completed + #define HTTP_STATUS_CREATED 201 // object created, reason = new URI + #define HTTP_STATUS_ACCEPTED 202 // async completion (TBS) + #define HTTP_STATUS_PARTIAL 203 // partial completion + #define HTTP_STATUS_NO_CONTENT 204 // no info to return + #define HTTP_STATUS_RESET_CONTENT 205 // request completed, but clear form + #define HTTP_STATUS_PARTIAL_CONTENT 206 // partial GET fulfilled + #define HTTP_STATUS_WEBDAV_MULTI_STATUS 207 // WebDAV Multi-Status + + #define HTTP_STATUS_AMBIGUOUS 300 // server couldn't decide what to return + #define HTTP_STATUS_MOVED 301 // object permanently moved + #define HTTP_STATUS_REDIRECT 302 // object temporarily moved + #define HTTP_STATUS_REDIRECT_METHOD 303 // redirection w/ new access method + #define HTTP_STATUS_NOT_MODIFIED 304 // if-modified-since was not modified + #define HTTP_STATUS_USE_PROXY 305 // redirection to proxy, location header specifies proxy to use + #define HTTP_STATUS_REDIRECT_KEEP_VERB 307 // HTTP/1.1: keep same verb + #define HTTP_STATUS_PERMANENT_REDIRECT 308 // Object permanently moved keep verb + + #define HTTP_STATUS_BAD_REQUEST 400 // invalid syntax + #define HTTP_STATUS_DENIED 401 // access denied + #define HTTP_STATUS_PAYMENT_REQ 402 // payment required + #define HTTP_STATUS_FORBIDDEN 403 // request forbidden + #define HTTP_STATUS_NOT_FOUND 404 // object not found + #define HTTP_STATUS_BAD_METHOD 405 // method is not allowed + #define HTTP_STATUS_NONE_ACCEPTABLE 406 // no response acceptable to client found + #define HTTP_STATUS_PROXY_AUTH_REQ 407 // proxy authentication required + #define HTTP_STATUS_REQUEST_TIMEOUT 408 // server timed out waiting for request + #define HTTP_STATUS_CONFLICT 409 // user should resubmit with more info + #define HTTP_STATUS_GONE 410 // the resource is no longer available + #define HTTP_STATUS_LENGTH_REQUIRED 411 // the server refused to accept request w/o a length + #define HTTP_STATUS_PRECOND_FAILED 412 // precondition given in request failed + #define HTTP_STATUS_REQUEST_TOO_LARGE 413 // request entity was too large + #define HTTP_STATUS_URI_TOO_LONG 414 // request URI too long + #define HTTP_STATUS_UNSUPPORTED_MEDIA 415 // unsupported media type + #define HTTP_STATUS_RETRY_WITH 449 // retry after doing the appropriate action. + + #define HTTP_STATUS_SERVER_ERROR 500 // internal server error + #define HTTP_STATUS_NOT_SUPPORTED 501 // required not supported + #define HTTP_STATUS_BAD_GATEWAY 502 // error response received from gateway + #define HTTP_STATUS_SERVICE_UNAVAIL 503 // temporarily overloaded + #define HTTP_STATUS_GATEWAY_TIMEOUT 504 // timed out waiting for gateway + #define HTTP_STATUS_VERSION_NOT_SUP 505 // HTTP version not supported + + #define HTTP_STATUS_FIRST HTTP_STATUS_CONTINUE + #define HTTP_STATUS_LAST HTTP_STATUS_VERSION_NOT_SUP + + #define WINHTTP_CALLBACK_STATUS_RESOLVING_NAME 0x00000001 + #define WINHTTP_CALLBACK_STATUS_NAME_RESOLVED 0x00000002 + #define WINHTTP_CALLBACK_STATUS_CONNECTING_TO_SERVER 0x00000004 + #define WINHTTP_CALLBACK_STATUS_CONNECTED_TO_SERVER 0x00000008 + #define WINHTTP_CALLBACK_STATUS_SENDING_REQUEST 0x00000010 + #define WINHTTP_CALLBACK_STATUS_REQUEST_SENT 0x00000020 + #define WINHTTP_CALLBACK_STATUS_RECEIVING_RESPONSE 0x00000040 + #define WINHTTP_CALLBACK_STATUS_RESPONSE_RECEIVED 0x00000080 + #define WINHTTP_CALLBACK_STATUS_CLOSING_CONNECTION 0x00000100 + #define WINHTTP_CALLBACK_STATUS_CONNECTION_CLOSED 0x00000200 + #define WINHTTP_CALLBACK_STATUS_HANDLE_CREATED 0x00000400 + #define WINHTTP_CALLBACK_STATUS_HANDLE_CLOSING 0x00000800 + #define WINHTTP_CALLBACK_STATUS_DETECTING_PROXY 0x00001000 + #define WINHTTP_CALLBACK_STATUS_REDIRECT 0x00004000 + #define WINHTTP_CALLBACK_STATUS_INTERMEDIATE_RESPONSE 0x00008000 + #define WINHTTP_CALLBACK_STATUS_SECURE_FAILURE 0x00010000 + #define WINHTTP_CALLBACK_STATUS_HEADERS_AVAILABLE 0x00020000 + #define WINHTTP_CALLBACK_STATUS_DATA_AVAILABLE 0x00040000 + #define WINHTTP_CALLBACK_STATUS_READ_COMPLETE 0x00080000 + #define WINHTTP_CALLBACK_STATUS_WRITE_COMPLETE 0x00100000 + #define WINHTTP_CALLBACK_STATUS_REQUEST_ERROR 0x00200000 + #define WINHTTP_CALLBACK_STATUS_SENDREQUEST_COMPLETE 0x00400000 + + #define WINHTTP_CALLBACK_STATUS_GETPROXYFORURL_COMPLETE 0x01000000 + #define WINHTTP_CALLBACK_STATUS_CLOSE_COMPLETE 0x02000000 + #define WINHTTP_CALLBACK_STATUS_SHUTDOWN_COMPLETE 0x04000000 + #define WINHTTP_CALLBACK_STATUS_SETTINGS_WRITE_COMPLETE 0x10000000 + #define WINHTTP_CALLBACK_STATUS_SETTINGS_READ_COMPLETE 0x20000000 + + #define WINHTTP_CALLBACK_FLAG_RESOLVE_NAME (WINHTTP_CALLBACK_STATUS_RESOLVING_NAME | WINHTTP_CALLBACK_STATUS_NAME_RESOLVED) + #define WINHTTP_CALLBACK_FLAG_CONNECT_TO_SERVER (WINHTTP_CALLBACK_STATUS_CONNECTING_TO_SERVER | WINHTTP_CALLBACK_STATUS_CONNECTED_TO_SERVER) + #define WINHTTP_CALLBACK_FLAG_SEND_REQUEST (WINHTTP_CALLBACK_STATUS_SENDING_REQUEST | WINHTTP_CALLBACK_STATUS_REQUEST_SENT) + #define WINHTTP_CALLBACK_FLAG_RECEIVE_RESPONSE (WINHTTP_CALLBACK_STATUS_RECEIVING_RESPONSE | WINHTTP_CALLBACK_STATUS_RESPONSE_RECEIVED) + #define WINHTTP_CALLBACK_FLAG_CLOSE_CONNECTION (WINHTTP_CALLBACK_STATUS_CLOSING_CONNECTION | WINHTTP_CALLBACK_STATUS_CONNECTION_CLOSED) + #define WINHTTP_CALLBACK_FLAG_HANDLES (WINHTTP_CALLBACK_STATUS_HANDLE_CREATED | WINHTTP_CALLBACK_STATUS_HANDLE_CLOSING) + #define WINHTTP_CALLBACK_FLAG_DETECTING_PROXY WINHTTP_CALLBACK_STATUS_DETECTING_PROXY + #define WINHTTP_CALLBACK_FLAG_REDIRECT WINHTTP_CALLBACK_STATUS_REDIRECT + #define WINHTTP_CALLBACK_FLAG_INTERMEDIATE_RESPONSE WINHTTP_CALLBACK_STATUS_INTERMEDIATE_RESPONSE + #define WINHTTP_CALLBACK_FLAG_SECURE_FAILURE WINHTTP_CALLBACK_STATUS_SECURE_FAILURE + #define WINHTTP_CALLBACK_FLAG_SENDREQUEST_COMPLETE WINHTTP_CALLBACK_STATUS_SENDREQUEST_COMPLETE + #define WINHTTP_CALLBACK_FLAG_HEADERS_AVAILABLE WINHTTP_CALLBACK_STATUS_HEADERS_AVAILABLE + #define WINHTTP_CALLBACK_FLAG_DATA_AVAILABLE WINHTTP_CALLBACK_STATUS_DATA_AVAILABLE + #define WINHTTP_CALLBACK_FLAG_READ_COMPLETE WINHTTP_CALLBACK_STATUS_READ_COMPLETE + #define WINHTTP_CALLBACK_FLAG_WRITE_COMPLETE WINHTTP_CALLBACK_STATUS_WRITE_COMPLETE + #define WINHTTP_CALLBACK_FLAG_REQUEST_ERROR WINHTTP_CALLBACK_STATUS_REQUEST_ERROR + + #define WINHTTP_CALLBACK_FLAG_GETPROXYFORURL_COMPLETE WINHTTP_CALLBACK_STATUS_GETPROXYFORURL_COMPLETE + + #define WINHTTP_CALLBACK_FLAG_ALL_COMPLETIONS (WINHTTP_CALLBACK_STATUS_SENDREQUEST_COMPLETE \ + | WINHTTP_CALLBACK_STATUS_HEADERS_AVAILABLE \ + | WINHTTP_CALLBACK_STATUS_DATA_AVAILABLE \ + | WINHTTP_CALLBACK_STATUS_READ_COMPLETE \ + | WINHTTP_CALLBACK_STATUS_WRITE_COMPLETE \ + | WINHTTP_CALLBACK_STATUS_REQUEST_ERROR \ + | WINHTTP_CALLBACK_STATUS_GETPROXYFORURL_COMPLETE) + + #define WINHTTP_CALLBACK_FLAG_ALL_NOTIFICATIONS 0xffffffff + #define WINHTTP_INVALID_STATUS_CALLBACK ((WINHTTP_STATUS_CALLBACK)(-1L)) + + typedef struct _WINHTTP_EXTENDED_HEADER + { + union + { + CHAR const *pwszName; + WCHAR const *pszName; + }; + union + { + WCHAR const *pwszValue; + CHAR const *pszValue; + }; + } WINHTTP_EXTENDED_HEADER, *PWINHTTP_EXTENDED_HEADER; + + typedef struct _WINHTTP_ASYNC_RESULT + { + DWORD *dwResult; // indicates which async API has encountered an error + DWORD dwError; // the error code if the API failed + } WINHTTP_ASYNC_RESULT, *LPWINHTTP_ASYNC_RESULT, *PWINHTTP_ASYNC_RESULT; + + typedef + VOID + (*WINHTTP_STATUS_CALLBACK)( + HINTERNET hInternet, + DWORD *dwContext, + DWORD dwInternetStatus, + VOID *lpvStatusInformation, + DWORD dwStatusInformationLength + ); + + extern "C" + { + __declspec(dllimport) HINTERNET __stdcall WinHttpOpen(WCHAR const *pszAgentW, DWORD dwAccessType, WCHAR const *pszProxyW, WCHAR const *pszProxyBypassW, DWORD dwFlags); + __declspec(dllimport) BOOL __stdcall WinHttpCloseHandle(HINTERNET hInternet); + __declspec(dllimport) HINTERNET __stdcall WinHttpConnect(HINTERNET hSession, WCHAR const *pswzServerName, INTERNET_PORT nServerPort, DWORD dwReserved); + __declspec(dllimport) BOOL __stdcall WinHttpReadData(HINTERNET hRequest, VOID *lpBuffer, DWORD dwNumberOfBytesToRead, DWORD *lpdwNumberOfBytesRead); + __declspec(dllimport) HINTERNET __stdcall WinHttpOpenRequest(HINTERNET hConnect, WCHAR const *pwszVerb, WCHAR const *pwszObjectName, WCHAR const *pwszVersion, WCHAR const *pwszReferrer, WCHAR const *ppwszAcceptTypes, DWORD dwFlags); + __declspec(dllimport) BOOL __stdcall WinHttpSendRequest(HINTERNET hRequest, WCHAR const *lpszHeaders, DWORD dwHeadersLength, VOID *lpOptional, DWORD dwOptionalLength, DWORD dwTotalLength, DWORD_PTR dwContext); + __declspec(dllimport) DWORD __stdcall WinHttpAddRequestHeadersEx(HINTERNET hRequest, DWORD dwModifiers, ULONGLONG ullFlags, ULONGLONG ullExtra, DWORD cHeaders, WINHTTP_EXTENDED_HEADER *pHeaders); + __declspec(dllimport) BOOL __stdcall WinHttpSetCredentials(HINTERNET hRequest, // HINTERNET handle returned by WinHttpOpenRequest. + DWORD AuthTargets, // Only WINHTTP_AUTH_TARGET_SERVER and WINHTTP_AUTH_TARGET_PROXY are supported in this version and they are mutually exclusive + DWORD AuthScheme, // must be one of the supported Auth Schemes returned from WinHttpQueryAuthSchemes() + WCHAR * pwszUserName, // 1) NULL if default creds is to be used, in which case pszPassword will be ignored + WCHAR * pwszPassword, // 1) "" == Blank Password; 2)Parameter ignored if pszUserName is NULL; 3) Invalid to pass in NULL if pszUserName is not NULL + VOID * pAuthParams); + __declspec(dllimport) BOOL __stdcall WinHttpQueryHeaders(HINTERNET hRequest, DWORD dwInfoLevel, WCHAR const *pwszName, VOID *lpBuffer, DWORD *lpdwBufferLength, DWORD *lpdwIndex); + __declspec(dllimport) BOOL __stdcall WinHttpReceiveResponse(HINTERNET hRequest, VOID *lpReserved); + __declspec(dllimport) WINHTTP_STATUS_CALLBACK __stdcall WinHttpSetStatusCallback(HINTERNET hInternet, WINHTTP_STATUS_CALLBACK lpfnInternetCallback, DWORD dwNotificationFlags, DWORD_PTR dwReserved); + } + + // NOTE: um/DbgHelp.h ////////////////////////////////////////////////////////////////////////// + #define SYMOPT_CASE_INSENSITIVE 0x00000001 + #define SYMOPT_UNDNAME 0x00000002 + #define SYMOPT_DEFERRED_LOADS 0x00000004 + #define SYMOPT_NO_CPP 0x00000008 + #define SYMOPT_LOAD_LINES 0x00000010 + #define SYMOPT_OMAP_FIND_NEAREST 0x00000020 + #define SYMOPT_LOAD_ANYTHING 0x00000040 + #define SYMOPT_IGNORE_CVREC 0x00000080 + #define SYMOPT_NO_UNQUALIFIED_LOADS 0x00000100 + #define SYMOPT_FAIL_CRITICAL_ERRORS 0x00000200 + #define SYMOPT_EXACT_SYMBOLS 0x00000400 + #define SYMOPT_ALLOW_ABSOLUTE_SYMBOLS 0x00000800 + #define SYMOPT_IGNORE_NT_SYMPATH 0x00001000 + #define SYMOPT_INCLUDE_32BIT_MODULES 0x00002000 + #define SYMOPT_PUBLICS_ONLY 0x00004000 + #define SYMOPT_NO_PUBLICS 0x00008000 + #define SYMOPT_AUTO_PUBLICS 0x00010000 + #define SYMOPT_NO_IMAGE_SEARCH 0x00020000 + #define SYMOPT_SECURE 0x00040000 + #define SYMOPT_NO_PROMPTS 0x00080000 + #define SYMOPT_OVERWRITE 0x00100000 + #define SYMOPT_IGNORE_IMAGEDIR 0x00200000 + #define SYMOPT_FLAT_DIRECTORY 0x00400000 + #define SYMOPT_FAVOR_COMPRESSED 0x00800000 + #define SYMOPT_ALLOW_ZERO_ADDRESS 0x01000000 + #define SYMOPT_DISABLE_SYMSRV_AUTODETECT 0x02000000 + #define SYMOPT_READONLY_CACHE 0x04000000 + #define SYMOPT_SYMPATH_LAST 0x08000000 + #define SYMOPT_DISABLE_FAST_SYMBOLS 0x10000000 + #define SYMOPT_DISABLE_SYMSRV_TIMEOUT 0x20000000 + #define SYMOPT_DISABLE_SRVSTAR_ON_STARTUP 0x40000000 + #define SYMOPT_DEBUG 0x80000000 + + #define MAX_SYM_NAME 2000 + + typedef enum { + AddrMode1616, + AddrMode1632, + AddrModeReal, + AddrModeFlat + } ADDRESS_MODE; + + typedef struct _tagADDRESS64 { + DWORD64 Offset; + WORD Segment; + ADDRESS_MODE Mode; + } ADDRESS64, *LPADDRESS64; + + + typedef struct _KDHELP64 { + DWORD64 Thread; + DWORD ThCallbackStack; + DWORD ThCallbackBStore; + DWORD NextCallback; + DWORD FramePointer; + DWORD64 KiCallUserMode; + DWORD64 KeUserCallbackDispatcher; + DWORD64 SystemRangeStart; + DWORD64 KiUserExceptionDispatcher; + DWORD64 StackBase; + DWORD64 StackLimit; + DWORD BuildVersion; + DWORD RetpolineStubFunctionTableSize; + DWORD64 RetpolineStubFunctionTable; + DWORD RetpolineStubOffset; + DWORD RetpolineStubSize; + DWORD64 Reserved0[2]; + } KDHELP64, *PKDHELP64; + + typedef struct _tagSTACKFRAME64 { + ADDRESS64 AddrPC; // program counter + ADDRESS64 AddrReturn; // return address + ADDRESS64 AddrFrame; // frame pointer + ADDRESS64 AddrStack; // stack pointer + ADDRESS64 AddrBStore; // backing store pointer + VOID *FuncTableEntry; // pointer to pdata/fpo or NULL + DWORD64 Params[4]; // possible arguments to the function + BOOL Far; // WOW far call + BOOL Virtual; // is this a virtual frame? + DWORD64 Reserved[3]; + KDHELP64 KdHelp; + } STACKFRAME64; + + typedef struct _IMAGEHLP_LINEW64 { + DWORD SizeOfStruct; // set to sizeof(IMAGEHLP_LINE64) + VOID *Key; // internal + DWORD LineNumber; // line number in file + WCHAR *FileName; // full filename + DWORD64 Address; // first instruction of line + } IMAGEHLP_LINEW64; + + typedef struct _SYMBOL_INFOW { + ULONG SizeOfStruct; + ULONG TypeIndex; // Type Index of symbol + ULONG64 Reserved[2]; + ULONG Index; + ULONG Size; + ULONG64 ModBase; // Base Address of module comtaining this symbol + ULONG Flags; + ULONG64 Value; // Value of symbol, ValuePresent should be 1 + ULONG64 Address; // Address of symbol including base address of module + ULONG Register; // register holding value or pointer to value + ULONG Scope; // scope of the symbol + ULONG Tag; // pdb classification + ULONG NameLen; // Actual length of name + ULONG MaxNameLen; + WCHAR Name[1]; // Name of symbol + } SYMBOL_INFOW; + + typedef BOOL (__stdcall READ_PROCESS_MEMORY_ROUTINE64)(HANDLE hProcess, DWORD64 qwBaseAddress, VOID *lpBuffer, DWORD nSize, DWORD *lpNumberOfBytesRead); + typedef VOID * (__stdcall FUNCTION_TABLE_ACCESS_ROUTINE64)(HANDLE ahProcess, DWORD64 AddrBase); + typedef DWORD64(__stdcall GET_MODULE_BASE_ROUTINE64)(HANDLE hProcess, DWORD64 Address); + typedef DWORD64(__stdcall TRANSLATE_ADDRESS_ROUTINE64)(HANDLE hProcess, HANDLE hThread, ADDRESS64 *lpaddr); + + extern "C" + { + __declspec(dllimport) BOOL __stdcall StackWalk64 (DWORD MachineType, HANDLE hProcess, HANDLE hThread, STACKFRAME64 *StackFrame, VOID *ContextRecord, READ_PROCESS_MEMORY_ROUTINE64 *ReadMemoryRoutine, FUNCTION_TABLE_ACCESS_ROUTINE64 *FunctionTableAccessRoutine, GET_MODULE_BASE_ROUTINE64 *GetModuleBaseRoutine, TRANSLATE_ADDRESS_ROUTINE64 *TranslateAddress); + __declspec(dllimport) BOOL __stdcall SymFromAddrW (HANDLE hProcess, DWORD64 Address, DWORD64 *Displacement, SYMBOL_INFOW *Symbol); + __declspec(dllimport) VOID * __stdcall SymFunctionTableAccess64(HANDLE hProcess, DWORD64 AddrBase); + __declspec(dllimport) BOOL __stdcall SymGetLineFromAddrW64 (HANDLE hProcess, DWORD64 dwAddr, DWORD *pdwDisplacement, IMAGEHLP_LINEW64 *Line); + __declspec(dllimport) DWORD64 __stdcall SymGetModuleBase64 (HANDLE hProcess, DWORD64 qwAddr); + __declspec(dllimport) BOOL __stdcall SymRefreshModuleList (HANDLE hProcess); + }; + + // NOTE: um/errhandlingapi.h /////////////////////////////////////////////////////////////////// + extern "C" + { + __declspec(dllimport) DWORD __stdcall GetLastError(VOID); + } + + // NOTE: um/libloaderapi.h ///////////////////////////////////////////////////////////////////// + extern "C" + { + __declspec(dllimport) HMODULE __stdcall LoadLibraryA (const CHAR *lpLibFileName); + __declspec(dllimport) BOOL __stdcall FreeLibrary (HMODULE hLibModule); + __declspec(dllimport) void * __stdcall GetProcAddress (HMODULE hModule, const CHAR *lpProcName); + __declspec(dllimport) HMODULE __stdcall GetModuleHandleA (const CHAR *lpModuleName); + __declspec(dllimport) DWORD __stdcall GetModuleFileNameW(HMODULE hModule, WCHAR *lpFilename, DWORD nSize); + } + + // NOTE: um/synchapi.h ///////////////////////////////////////////////////////////////////////// + typedef RTL_CONDITION_VARIABLE CONDITION_VARIABLE, *PCONDITION_VARIABLE; + + typedef RTL_BARRIER SYNCHRONIZATION_BARRIER; + typedef PRTL_BARRIER PSYNCHRONIZATION_BARRIER; + typedef PRTL_BARRIER LPSYNCHRONIZATION_BARRIER; + + #define SYNCHRONIZATION_BARRIER_FLAGS_SPIN_ONLY 0x01 + #define SYNCHRONIZATION_BARRIER_FLAGS_BLOCK_ONLY 0x02 + #define SYNCHRONIZATION_BARRIER_FLAGS_NO_DELETE 0x04 + + extern "C" + { + __declspec(dllimport) VOID __stdcall InitializeConditionVariable (CONDITION_VARIABLE *ConditionVariable); + __declspec(dllimport) VOID __stdcall WakeConditionVariable (CONDITION_VARIABLE *ConditionVariable); + __declspec(dllimport) VOID __stdcall WakeAllConditionVariable (CONDITION_VARIABLE *ConditionVariable); + __declspec(dllimport) BOOL __stdcall SleepConditionVariableCS (CONDITION_VARIABLE *ConditionVariable, CRITICAL_SECTION *CriticalSection, DWORD dwMilliseconds); + + __declspec(dllimport) VOID __stdcall InitializeCriticalSection (CRITICAL_SECTION *lpCriticalSection); + __declspec(dllimport) VOID __stdcall EnterCriticalSection (CRITICAL_SECTION *lpCriticalSection); + __declspec(dllimport) VOID __stdcall LeaveCriticalSection (CRITICAL_SECTION *lpCriticalSection); + __declspec(dllimport) BOOL __stdcall InitializeCriticalSectionAndSpinCount(CRITICAL_SECTION *lpCriticalSection, DWORD dwSpinCount); + __declspec(dllimport) BOOL __stdcall InitializeCriticalSectionEx (CRITICAL_SECTION *lpCriticalSection, DWORD dwSpinCount, DWORD Flags); + __declspec(dllimport) DWORD __stdcall SetCriticalSectionSpinCount (CRITICAL_SECTION *lpCriticalSection, DWORD dwSpinCount); + __declspec(dllimport) BOOL __stdcall TryEnterCriticalSection (CRITICAL_SECTION *lpCriticalSection); + __declspec(dllimport) VOID __stdcall DeleteCriticalSection (CRITICAL_SECTION *lpCriticalSection); + + __declspec(dllimport) DWORD __stdcall WaitForSingleObject (HANDLE hHandle, DWORD dwMilliseconds); + __declspec(dllimport) BOOL __stdcall ReleaseSemaphore (HANDLE hSemaphore, LONG lReleaseCount, LONG *lpPreviousCount); + __declspec(dllimport) VOID __stdcall Sleep (DWORD dwMilliseconds); + + __declspec(dllimport) BOOL __stdcall EnterSynchronizationBarrier (SYNCHRONIZATION_BARRIER *lpBarrier, DWORD dwFlags); + __declspec(dllimport) BOOL __stdcall InitializeSynchronizationBarrier (SYNCHRONIZATION_BARRIER *lpBarrier, LONG lTotalThreads, LONG lSpinCount); + __declspec(dllimport) BOOL __stdcall DeleteSynchronizationBarrier (SYNCHRONIZATION_BARRIER *lpBarrier); + } + + // NOTE: um/profileapi.h /////////////////////////////////////////////////////////////////////// + extern "C" + { + __declspec(dllimport) BOOL __stdcall QueryPerformanceCounter (LARGE_INTEGER* lpPerformanceCount); + __declspec(dllimport) BOOL __stdcall QueryPerformanceFrequency(LARGE_INTEGER* lpFrequency); + } + + // NOTE: um/processthreadsapi.h //////////////////////////////////////////////////////////////// + typedef struct _PROCESS_INFORMATION { + HANDLE hProcess; + HANDLE hThread; + DWORD dwProcessId; + DWORD dwThreadId; + } PROCESS_INFORMATION, *PPROCESS_INFORMATION, *LPPROCESS_INFORMATION; + + typedef struct _STARTUPINFOW { + DWORD cb; + WCHAR *lpReserved; + WCHAR *lpDesktop; + WCHAR *lpTitle; + DWORD dwX; + DWORD dwY; + DWORD dwXSize; + DWORD dwYSize; + DWORD dwXCountChars; + DWORD dwYCountChars; + DWORD dwFillAttribute; + DWORD dwFlags; + WORD wShowWindow; + WORD cbReserved2; + BYTE *lpReserved2; + HANDLE hStdInput; + HANDLE hStdOutput; + HANDLE hStdError; + } STARTUPINFOW, *LPSTARTUPINFOW; + + typedef DWORD (__stdcall *PTHREAD_START_ROUTINE)( + VOID *lpThreadParameter + ); + typedef PTHREAD_START_ROUTINE LPTHREAD_START_ROUTINE; + + extern "C" + { + __declspec(dllimport) BOOL __stdcall CreateProcessW (WCHAR const *lpApplicationName, WCHAR *lpCommandLine, SECURITY_ATTRIBUTES *lpProcessAttributes, SECURITY_ATTRIBUTES *lpThreadAttributes, BOOL bInheritHandles, DWORD dwCreationFlags, VOID *lpEnvironment, WCHAR const *lpCurrentDirectory, STARTUPINFOW *lpStartupInfo, PROCESS_INFORMATION *lpProcessInformation); + __declspec(dllimport) HANDLE __stdcall CreateThread (SECURITY_ATTRIBUTES *lpThreadAttributes, SIZE_T dwStackSize, PTHREAD_START_ROUTINE lpStartAddress, VOID *lpParameter, DWORD dwCreationFlags, DWORD *lpThreadId); + __declspec(dllimport) DWORD __stdcall GetCurrentThreadId(VOID); + __declspec(dllimport) BOOL __stdcall GetExitCodeProcess(HANDLE hProcess, DWORD *lpExitCode); + __declspec(dllimport) void __stdcall ExitProcess (UINT uExitCode); + } + + // NOTE: um/memoryapi.h //////////////////////////////////////////////////////////////////////// + extern "C" + { + __declspec(dllimport) VOID * __stdcall VirtualAlloc (VOID *lpAddress, SIZE_T dwSize, DWORD flAllocationType, DWORD flProtect); + __declspec(dllimport) BOOL __stdcall VirtualProtect(VOID *lpAddress, SIZE_T dwSize, DWORD flNewProtect, DWORD *lpflOldProtect); + __declspec(dllimport) BOOL __stdcall VirtualFree (VOID *lpAddress, SIZE_T dwSize, DWORD dwFreeType); + } + + // NOTE: shared/bcrypt.h /////////////////////////////////////////////////////////////////////// + typedef VOID *BCRYPT_ALG_HANDLE; + typedef LONG NTSTATUS; + + extern "C" + { + __declspec(dllimport) NTSTATUS __stdcall BCryptOpenAlgorithmProvider(BCRYPT_ALG_HANDLE *phAlgorithm, const WCHAR *pszAlgId, const WCHAR *pszImplementation, ULONG dwFlags); + __declspec(dllimport) NTSTATUS __stdcall BCryptGenRandom (BCRYPT_ALG_HANDLE hAlgorithm, UCHAR *pbBuffer, ULONG cbBuffer, ULONG dwFlags); + } + + // NOTE: um/shellapi.h ///////////////////////////////////////////////////////////////////////// + extern "C" + { + __declspec(dllimport) HINSTANCE __stdcall ShellExecuteA(HWND hwnd, CHAR const *lpOperation, CHAR const *lpFile, CHAR const *lpParameters, CHAR const *lpDirectory, INT nShowCmd); + __declspec(dllimport) HINSTANCE __stdcall ShellExecuteW(HWND hwnd, WCHAR const *lpOperation, WCHAR const *lpFile, WCHAR const *lpParameters, WCHAR const *lpDirectory, INT nShowCmd); + } + + // NOTE: um/debugapi.h ///////////////////////////////////////////////////////////////////////// + extern "C" + { + __declspec(dllimport) BOOL __stdcall IsDebuggerPresent(); + } + + // NOTE: um/namedpipeapi.h ///////////////////////////////////////////////////////////////////// + extern "C" + { + __declspec(dllimport) BOOL __stdcall CreatePipe (HANDLE *hReadPipe, HANDLE *hWritePipe, LPSECURITY_ATTRIBUTES lpPipeAttributes, DWORD nSize); + __declspec(dllimport) BOOL __stdcall PeekNamedPipe(HANDLE hNamedPipe, VOID *lpBuffer, DWORD nBufferSize, DWORD *lpBytesRead, DWORD *lpTotalBytesAvail, DWORD *lpBytesLeftThisMessage); + } + + // NOTE: um/handleapi.h //////////////////////////////////////////////////////////////////////// + extern "C" + { + __declspec(dllimport) BOOL __stdcall SetHandleInformation(HANDLE hObject, DWORD dwMask, DWORD dwFlags); + } + + // NOTE: um/commdlg.h ////////////////////////////////////////////////////////////////////////// + typedef UINT_PTR (__stdcall *LPOFNHOOKPROC)(HWND, UINT, WPARAM, LPARAM); + typedef struct tagOFNW { + DWORD lStructSize; + HWND hwndOwner; + HINSTANCE hInstance; + WCHAR const * lpstrFilter; + LPWSTR lpstrCustomFilter; + DWORD nMaxCustFilter; + DWORD nFilterIndex; + LPWSTR lpstrFile; + DWORD nMaxFile; + LPWSTR lpstrFileTitle; + DWORD nMaxFileTitle; + WCHAR const * lpstrInitialDir; + WCHAR const * lpstrTitle; + DWORD Flags; + WORD nFileOffset; + WORD nFileExtension; + WCHAR const * lpstrDefExt; + LPARAM lCustData; + LPOFNHOOKPROC lpfnHook; + WCHAR const * lpTemplateName; + #ifdef _MAC + LPEDITMENU lpEditInfo; + LPCSTR lpstrPrompt; + #endif + #if (_WIN32_WINNT >= 0x0500) + void * pvReserved; + DWORD dwReserved; + DWORD FlagsEx; + #endif // (_WIN32_WINNT >= 0x0500) + } OPENFILENAMEW, *LPOPENFILENAMEW; + + + #define OFN_READONLY 0x00000001 + #define OFN_OVERWRITEPROMPT 0x00000002 + #define OFN_HIDEREADONLY 0x00000004 + #define OFN_NOCHANGEDIR 0x00000008 + #define OFN_SHOWHELP 0x00000010 + #define OFN_ENABLEHOOK 0x00000020 + #define OFN_ENABLETEMPLATE 0x00000040 + #define OFN_ENABLETEMPLATEHANDLE 0x00000080 + #define OFN_NOVALIDATE 0x00000100 + #define OFN_ALLOWMULTISELECT 0x00000200 + #define OFN_EXTENSIONDIFFERENT 0x00000400 + #define OFN_PATHMUSTEXIST 0x00000800 + #define OFN_FILEMUSTEXIST 0x00001000 + #define OFN_CREATEPROMPT 0x00002000 + #define OFN_SHAREAWARE 0x00004000 + #define OFN_NOREADONLYRETURN 0x00008000 + #define OFN_NOTESTFILECREATE 0x00010000 + #define OFN_NONETWORKBUTTON 0x00020000 + #define OFN_NOLONGNAMES 0x00040000 // force no long names for 4.x modules + #if(WINVER >= 0x0400) + #define OFN_EXPLORER 0x00080000 // new look commdlg + #define OFN_NODEREFERENCELINKS 0x00100000 + #define OFN_LONGNAMES 0x00200000 // force long names for 3.x modules + // OFN_ENABLEINCLUDENOTIFY and OFN_ENABLESIZING require + // Windows 2000 or higher to have any effect. + #define OFN_ENABLEINCLUDENOTIFY 0x00400000 // send include message to callback + #define OFN_ENABLESIZING 0x00800000 + #endif /* WINVER >= 0x0400 */ + #if (_WIN32_WINNT >= 0x0500) + #define OFN_DONTADDTORECENT 0x02000000 + #define OFN_FORCESHOWHIDDEN 0x10000000 // Show All files including System and hidden files + #endif // (_WIN32_WINNT >= 0x0500) + + //FlagsEx Values + #if (_WIN32_WINNT >= 0x0500) + #define OFN_EX_NOPLACESBAR 0x00000001 + #endif // (_WIN32_WINNT >= 0x0500) + + extern "C" + { + __declspec(dllimport) BOOL __stdcall GetSaveFileNameW(LPOPENFILENAMEW); + __declspec(dllimport) BOOL __stdcall GetOpenFileNameW(LPOPENFILENAMEW); + } + + // NOTE: um/shlwapi.h ////////////////////////////////////////////////////////////////////////// + extern "C" + { + __declspec(dllimport) BOOL __stdcall PathRelativePathToW(WCHAR *pszPath, WCHAR const *pszFrom, DWORD dwAttrFrom, WCHAR const *pszTo, DWORD dwAttrTo); + __declspec(dllimport) BOOL __stdcall PathIsRelativeW(WCHAR *pszPath); + } + + // NOTE: um/pathcch.h ////////////////////////////////////////////////////////////////////////// + typedef enum PATHCCH_OPTIONS + { + PATHCCH_NONE = 0x0, + + // This option allows applications to gain access to long paths. It has two + // different behaviors. For process configured to enable long paths it will allow + // the returned path to be longer than the max path limit that is normally imposed. + // For process that are not this option will convert long paths into the extended + // length DOS device form (with \\?\ prefix) when the path is longer than the limit. + // This form is not length limited by the Win32 file system API on all versions of Windows. + // This second behavior is the same behavior for OSes that don't have the long path feature. + // This can not be specified with PATHCCH_ENSURE_IS_EXTENDED_LENGTH_PATH. + PATHCCH_ALLOW_LONG_PATHS = 0x01, + + // Can only be used when PATHCCH_ALLOW_LONG_PATHS is specified. This + // Forces the API to treat the caller as long path enabled, independent of the + // process's long name enabled state. Cannot be used with PATHCCH_FORCE_DISABLE_LONG_NAME_PROCESS. + PATHCCH_FORCE_ENABLE_LONG_NAME_PROCESS = 0x02, + + // Can only be used when PATHCCH_ALLOW_LONG_PATHS is specified. This + // Forces the API to treat the caller as long path disabled, independent of the + // process's long name enabled state. Cannot be used with PATHCCH_FORCE_ENABLE_LONG_NAME_PROCESS. + PATHCCH_FORCE_DISABLE_LONG_NAME_PROCESS = 0x04, + + // Disable the normalization of path segments that includes removing trailing dots and spaces. + // This enables access to paths that win32 path normalization will block. + PATHCCH_DO_NOT_NORMALIZE_SEGMENTS = 0x08, + + // Convert the input path into the extended length DOS device path form (with the \\?\ prefix) + // if not already in that form. This enables access to paths that are otherwise not addressable + // due to Win32 normalization rules (that can strip trailing dots and spaces) and path + // length limitations. This option implies the same behavior of PATHCCH_DO_NOT_NORMALIZE_SEGMENTS. + // This can not be specified with PATHCCH_ALLOW_LONG_PATHS. + PATHCCH_ENSURE_IS_EXTENDED_LENGTH_PATH = 0x10, + + // When combining or normalizing a path ensure there is a trailing backslash. + PATHCCH_ENSURE_TRAILING_SLASH = 0x020, + + // Convert forward slashes to back slashes and collapse multiple slashes. + // This is needed to to support sub-path or identity comparisons. + PATHCCH_CANONICALIZE_SLASHES = 0x040, + } PATHCCH_OPTIONS; + + extern "C" + { + __declspec(dllimport) HRESULT __stdcall PathCchCanonicalizeEx(PWSTR pszPathOut, size_t cchPathOut, WCHAR const *pszPathIn, ULONG dwFlags); + }; + + // NOTE: um/errhandlingapi.h /////////////////////////////////////////////////////////////////// + extern "C" + { + __declspec(dllimport) VOID __stdcall RaiseException(DWORD dwExceptionCode, DWORD dwExceptionFlags, DWORD nNumberOfArguments, const ULONG_PTR* lpArguments); + }; + + // NOTE: include/excpt.h /////////////////////////////////////////////////////////////////// + #define EXCEPTION_EXECUTE_HANDLER 1 + #define EXCEPTION_CONTINUE_SEARCH 0 + #define EXCEPTION_CONTINUE_EXECUTION (-1) + + DN_MSVC_WARNING_POP +#endif // !defined(_INC_WINDOWS) +#endif // !defined(DN_OS_WINDOWS_H) + // DN: Single header generator commented out => #include "OS/dn_os_w32.h" +#if !defined(DN_OS_W32_H) +#define DN_OS_W32_H + +// DN: Single header generator commented out => #if defined(_CLANGD) +// #define DN_H_WITH_OS 1 +// #include "../dn.h" +// #include "dn_os_windows.h" +// #endif + +struct DN_OSW32Error +{ + unsigned long code; + DN_Str8 msg; +}; + +struct DN_OSW32FolderIteratorW +{ + void *handle; + DN_Str16 file_name; + wchar_t file_name_buf[512]; +}; + +enum DN_OSW32SyncPrimitiveType +{ + DN_OSW32SyncPrimitiveType_Semaphore, + DN_OSW32SyncPrimitiveType_Mutex, + DN_OSW32SyncPrimitiveType_ConditionVariable, + DN_OSW32SyncPrimitiveType_Barrier, +}; + +struct DN_OSW32SyncPrimitive +{ + union + { + void *sem; + CRITICAL_SECTION mutex; + CONDITION_VARIABLE cv; + SYNCHRONIZATION_BARRIER barrier; + }; + + DN_OSW32SyncPrimitive *next; +}; + +typedef HRESULT DN_OSW32SetThreadDescriptionFunc(HANDLE hThread, PWSTR const lpThreadDescription); +struct DN_OSW32Core +{ + DN_OSW32SetThreadDescriptionFunc *set_thread_description; + LARGE_INTEGER qpc_frequency; + void *bcrypt_rng_handle; + bool bcrypt_init_success; + bool sym_initialised; + + CRITICAL_SECTION sync_primitive_free_list_mutex; + DN_OSW32SyncPrimitive *sync_primitive_free_list; +}; + +DN_API DN_OSW32Core* DN_OS_W32GetCore (); +DN_API void DN_OS_W32ThreadSetName (DN_Str8 name); + +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: 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); + +// 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); +#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" +#if !defined(DN_OS_POSIX_H) +#define DN_OS_POSIX_H + +// DN: Single header generator commented out => #if defined(_CLANGD) +// #include "../dn.h" +// #endif + +#include +#include + +struct DN_OSPosixProcSelfStatus +{ + char name[64]; + DN_U8 name_size; + DN_U32 pid; + DN_U64 vm_peak; + DN_U32 vm_size; +}; + +// NOTE: The POSIX implementation disallows copies of synchronisation objects in +// general hence we have to dynamically allocate these primitives to maintain a +// consistent address. +// +// +// Source: The Open Group Base Specifications Issue 7, 2018 edition +// https://pubs.opengroup.org/onlinepubs/9699919799/functions/V2_chap02.html#tag_15_09_09 +// +// 2.9.9 Synchronization Object Copies and Alternative Mappings +// +// For barriers, condition variables, mutexes, and read-write locks, [TSH] +// [Option Start] if the process-shared attribute is set to +// PTHREAD_PROCESS_PRIVATE, [Option End] only the synchronization object at the +// address used to initialize it can be used for performing synchronization. The +// effect of referring to another mapping of the same object when locking, +// unlocking, or destroying the object is undefined. [...] The effect of +// referring to a copy of the object when locking, unlocking, or destroying it +// is undefined. +enum DN_OSPosixSyncPrimitiveType +{ + DN_OSPosixSyncPrimitiveType_Semaphore, + DN_OSPosixSyncPrimitiveType_Mutex, + DN_OSPosixSyncPrimitiveType_ConditionVariable, +}; + +struct DN_OSPosixSyncPrimitive +{ + union + { + sem_t sem; + pthread_mutex_t mutex; + pthread_cond_t cv; + pthread_barrier_t barrier; + }; + DN_OSPosixSyncPrimitive *next; +}; + +struct DN_OSPosixCore +{ + DN_OSPosixSyncPrimitive *sync_primitive_free_list; + pthread_mutex_t sync_primitive_free_list_mutex; + bool clock_monotonic_raw; +}; + +DN_API void DN_OS_PosixInit (DN_OSPosixCore *posix); +DN_API void DN_OS_PosixThreadSetName (DN_Str8 name); +DN_API DN_OSPosixProcSelfStatus DN_OS_PosixProcSelfStatus(); +#endif // !defined(DN_OS_POSIX_H) +#else + #error Please define a platform e.g. 'DN_PLATFORM_WIN32' to enable the correct implementation for platform APIs +#endif +// DN: Single header generator commented out => #include "OS/dn_os.h" +#if !defined(DN_OS_H) +#define DN_OS_H + +// DN: Single header generator commented out => #if defined(_CLANGD) +// #define DN_H_WITH_OS 1 +// #include "../dn.h" +// #endif + +#include // operator new + +#if !defined(DN_OS_WIN32) || defined(DN_OS_WIN32_USE_PTHREADS) + #include + #include +#endif + +#if defined(DN_PLATFORM_POSIX) || defined(DN_PLATFORM_EMSCRIPTEN) + #include // errno + #include // O_RDONLY ... etc + #include // ioctl + #include // mmap + #include // getrandom + #include // stat + #include // pid_t + #include // waitpid + #include // clock_gettime, nanosleep + #include // access, gettid, write + + #if !defined(DN_PLATFORM_EMSCRIPTEN) + #include // FICLONE + #include // sendfile + #endif +#endif + +#if defined(DN_PLATFORM_EMSCRIPTEN) + #include // emscripten_fetch (for DN_OSHttpResponse) +#endif + +extern DN_CPUFeatureDecl g_dn_cpu_feature_decl[DN_CPUFeature_Count]; + +struct DN_OSTimer /// Record time between two time-points using the OS's performance counter. +{ + DN_U64 start; + DN_U64 end; +}; + +// NOTE: DN_OSFile +enum DN_OSPathInfoType +{ + DN_OSPathInfoType_Unknown, + DN_OSPathInfoType_Directory, + DN_OSPathInfoType_File, +}; + +struct DN_OSPathInfo +{ + bool exists; + DN_OSPathInfoType type; + DN_U64 create_time_in_s; + DN_U64 last_write_time_in_s; + DN_U64 last_access_time_in_s; + DN_U64 size; +}; + +struct DN_OSDirIterator +{ + void *handle; + DN_Str8 file_name; + char buffer[512]; +}; + +// NOTE: R/W Stream API +struct DN_OSFileRead +{ + bool success; + DN_USize bytes_read; +}; + +struct DN_OSFile +{ + bool error; + void *handle; +}; + +enum DN_OSFileOpen +{ + DN_OSFileOpen_CreateAlways, // Create file if it does not exist, otherwise, zero out the file and open + DN_OSFileOpen_OpenIfExist, // Open file at path only if it exists + DN_OSFileOpen_OpenAlways, // Open file at path, create file if it does not exist +}; + +typedef DN_U32 DN_OSFileAccess; + +enum DN_OSFileAccess_ +{ + DN_OSFileAccess_Read = 1 << 0, + DN_OSFileAccess_Write = 1 << 1, + DN_OSFileAccess_Execute = 1 << 2, + DN_OSFileAccess_AppendOnly = 1 << 3, // This flag cannot be combined with any other access mode + DN_OSFileAccess_ReadWrite = DN_OSFileAccess_Read | DN_OSFileAccess_Write, + DN_OSFileAccess_All = DN_OSFileAccess_ReadWrite | DN_OSFileAccess_Execute | DN_OSFileAccess_AppendOnly, +}; + +// NOTE: DN_OSPath +#if !defined(DN_OSPathSeperator) + #if defined(DN_OS_WIN32) + #define DN_OSPathSeperator "\\" + #else + #define DN_OSPathSeperator "/" + #endif + #define DN_OSPathSeperatorString DN_Str8Lit(DN_OSPathSeperator) +#endif + +struct DN_OSPathLink +{ + DN_Str8 string; + DN_OSPathLink *next; + DN_OSPathLink *prev; +}; + +struct DN_OSPath +{ + bool has_prefix_path_separator; + DN_OSPathLink *head; + DN_OSPathLink *tail; + DN_USize string_size; + DN_U16 links_size; +}; + +// NOTE: DN_OSExec +typedef DN_U32 DN_OSExecFlags; + +enum DN_OSExecFlags_ +{ + DN_OSExecFlags_Nil = 0, + DN_OSExecFlags_SaveStdout = 1 << 0, + DN_OSExecFlags_SaveStderr = 1 << 1, + DN_OSExecFlags_SaveOutput = DN_OSExecFlags_SaveStdout | DN_OSExecFlags_SaveStderr, + DN_OSExecFlags_MergeStderrToStdout = 1 << 2 | DN_OSExecFlags_SaveOutput, +}; + +struct DN_OSExecAsyncHandle +{ + DN_OSExecFlags exec_flags; + DN_U32 os_error_code; + DN_U32 exit_code; + void *process; + void *stdout_read; + void *stdout_write; + void *stderr_read; + void *stderr_write; +}; + +struct DN_OSExecResult +{ + bool finished; + DN_Str8 stdout_text; + DN_Str8 stderr_text; + DN_U32 os_error_code; + DN_U32 exit_code; +}; + +struct DN_OSExecArgs +{ + DN_OSExecFlags flags; + DN_Str8 working_dir; + DN_Str8Slice environment; +}; + +// NOTE: DN_OSSemaphore +DN_U32 const DN_OS_SEMAPHORE_INFINITE_TIMEOUT = UINT32_MAX; + +struct DN_OSSemaphore +{ + DN_U64 handle; +}; + +struct DN_OSBarrier +{ + DN_U64 handle; +}; + +enum DN_OSSemaphoreWaitResult +{ + DN_OSSemaphoreWaitResult_Failed, + DN_OSSemaphoreWaitResult_Success, + DN_OSSemaphoreWaitResult_Timeout, +}; + +struct DN_OSMutex +{ + DN_U64 handle; +}; + +struct DN_OSConditionVariable +{ + DN_U64 handle; +}; + +// NOTE: DN_OSThread +typedef DN_I32(DN_OSThreadFunc)(struct DN_OSThread *); + +struct DN_OSThreadLane +{ + DN_USize index; + DN_USize count; + DN_OSBarrier barrier; + void* shared_mem; +}; + +struct DN_OSThread +{ + DN_Str8x64 name; + DN_TCCore context; + DN_OSThreadLane lane; + bool is_lane_set; + void *handle; + DN_U64 thread_id; + void *user_context; + DN_OSThreadFunc *func; + DN_OSSemaphore init_semaphore; +}; + +// NOTE: DN_OSHttp +enum DN_OSHttpRequestSecure +{ + DN_OSHttpRequestSecure_No, + DN_OSHttpRequestSecure_Yes, +}; + +struct DN_OSHttpResponse +{ + // NOTE: Response data + DN_U32 error_code; + DN_Str8 error_msg; + DN_U16 http_status; + DN_Str8 body; + DN_B32 done; + + // NOTE: Book-keeping + DN_Arena *arena; // Allocates memory for the response + + // NOTE: Async book-keeping + // Synchronous HTTP response uses the TLS scratch arena whereas async + // calls use their own dedicated arena. + DN_Arena tmp_arena; + DN_Arena scratch_arena; + DN_Str8Builder builder; + DN_OSSemaphore on_complete_semaphore; + + #if defined(DN_PLATFORM_EMSCRIPTEN) + emscripten_fetch_t *em_handle; + #elif defined(DN_PLATFORM_WIN32) + HINTERNET w32_request_session; + HINTERNET w32_request_connection; + HINTERNET w32_request_handle; + #endif +}; + +struct DN_OSCore +{ + DN_CPUReport cpu_report; + + // NOTE: Logging + bool log_to_file; // Output logs to file as well as standard out + DN_OSFile log_file; // TODO(dn): Hmmm, how should we do this... ? + DN_TicketMutex log_file_mutex; // Is locked when instantiating the log_file for the first time + bool log_no_colour; // Disable colours in the logging output + DN_TicketMutex log_mutex; + + // NOTE: OS + DN_U32 logical_processor_count; + DN_U32 page_size; + DN_U32 alloc_granularity; + + // NOTE: Memory + // Total OS mem allocs in lifetime of program (e.g. malloc, VirtualAlloc, HeapAlloc ...). This + // only includes allocations routed through the library such as the growing nature of arenas or + // using the memory allocation routines in the library like DN_OS_MemCommit and so forth. + DN_U64 vmem_allocs_total; + DN_U64 vmem_allocs_frame; // Total OS virtual memory allocs since the last 'DN_Core_FrameBegin' was invoked + 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_Arena arena; + void *platform_context; +}; + +struct DN_OSDiskSpace +{ + bool success; + DN_U64 avail; + DN_U64 size; +}; + +DN_API DN_MemFuncs DN_MemFuncsFromType (DN_MemFuncsType type); +DN_API DN_MemFuncs DN_MemFuncsDefault (); +DN_API DN_MemList DN_MemListFromHeap (DN_U64 size, DN_MemFlags flags); +DN_API DN_MemList DN_MemListFromVMem (DN_U64 reserve, DN_U64 commit, DN_MemFlags flags); + + +DN_API DN_Str8 DN_Str8FromHeapF (DN_FMT_ATTRIB char const *fmt, ...); +DN_API DN_Str8 DN_Str8FromHeap (DN_USize size, DN_ZMem z_mem); +DN_API DN_Str8 DN_Str8BuilderBuildFromHeap (DN_Str8Builder const *builder); + +DN_API void DN_OS_LogPrint (DN_LogTypeParam type, void *user_data, DN_CallSite call_site, DN_FMT_ATTRIB char const *fmt, va_list args); +DN_API void DN_OS_SetLogPrintFuncToOS (); + +DN_API void * DN_OS_MemReserve (DN_USize size, DN_MemCommit commit, DN_MemPage page_flags); +DN_API bool DN_OS_MemCommit (void *ptr, DN_USize size, DN_U32 page_flags); +DN_API void DN_OS_MemDecommit (void *ptr, DN_USize size); +DN_API void DN_OS_MemRelease (void *ptr, DN_USize size); +DN_API int DN_OS_MemProtect (void *ptr, DN_USize size, DN_U32 page_flags); + +DN_API void * DN_OS_MemAlloc (DN_USize size, DN_ZMem z_mem); +DN_API void DN_OS_MemDealloc (void *ptr); + +DN_API DN_Date DN_OS_DateLocalTimeNow (); +DN_API DN_Str8x32 DN_OS_DateLocalTimeStr8Now (char date_separator = '-', char hms_separator = ':'); +DN_API DN_Str8x32 DN_OS_DateLocalTimeStr8 (DN_Date time, char date_separator = '-', char hms_separator = ':'); +DN_API DN_U64 DN_OS_DateUnixTimeNs (); +#define DN_OS_DateUnixTimeUs() (DN_OS_DateUnixTimeNs() / 1000) +#define DN_OS_DateUnixTimeMs() (DN_OS_DateUnixTimeNs() / (1000 * 1000)) +#define DN_OS_DateUnixTimeS() (DN_OS_DateUnixTimeNs() / (1000 * 1000 * 1000)) +DN_API DN_U64 DN_OS_DateUnixTimeSFromLocalDate (DN_Date date); +DN_API DN_U64 DN_OS_DateLocalUnixTimeSFromUnixTimeS (DN_U64 unix_ts_s); + +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_Str8 DN_OS_EXEPath (DN_Arena *arena); +DN_API DN_Str8 DN_OS_EXEDir (DN_Arena *arena); +DN_API void DN_OS_SleepMs (DN_UInt milliseconds); + +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_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 bool DN_OS_FileCopy (DN_Str8 src, DN_Str8 dest, bool overwrite, DN_ErrSink *err); +DN_API bool DN_OS_FileMove (DN_Str8 src, DN_Str8 dest, bool overwrite, DN_ErrSink *err); + +DN_API DN_OSFile DN_OS_FileOpen (DN_Str8 path, DN_OSFileOpen open_mode, DN_OSFileAccess access, DN_ErrSink *err); +DN_API DN_OSFileRead DN_OS_FileRead (DN_OSFile *file, void *buffer, DN_USize size, DN_ErrSink *err); +DN_API bool DN_OS_FileWritePtr (DN_OSFile *file, void const *data, DN_USize size, DN_ErrSink *err); +DN_API bool DN_OS_FileWrite (DN_OSFile *file, DN_Str8 buffer, DN_ErrSink *err); +DN_API bool DN_OS_FileWriteFV (DN_OSFile *file, DN_ErrSink *err, DN_FMT_ATTRIB char const *fmt, va_list args); +DN_API bool DN_OS_FileWriteF (DN_OSFile *file, DN_ErrSink *err, DN_FMT_ATTRIB char const *fmt, ...); +DN_API bool DN_OS_FileFlush (DN_OSFile *file, DN_ErrSink *err); +DN_API void DN_OS_FileClose (DN_OSFile *file); + +DN_API DN_Str8 DN_OS_FileReadAll (DN_Allocator alloc_type, void *allocator, DN_Str8 path, DN_ErrSink *err); +DN_API DN_Str8 DN_OS_FileReadAllArena (DN_Arena *arena, DN_Str8 path, DN_ErrSink *err); +DN_API DN_Str8 DN_OS_FileReadAllPool (DN_Pool *pool, DN_Str8 path, DN_ErrSink *err); + +DN_API bool DN_OS_FileWriteAll (DN_Str8 path, DN_Str8 buffer, DN_ErrSink *err); +DN_API bool DN_OS_FileWriteAllFV (DN_Str8 path, DN_ErrSink *err, DN_FMT_ATTRIB char const *fmt, va_list args); +DN_API bool DN_OS_FileWriteAllF (DN_Str8 path, DN_ErrSink *err, DN_FMT_ATTRIB char const *fmt, ...); +DN_API bool DN_OS_FileWriteAllSafe (DN_Str8 path, DN_Str8 buffer, DN_ErrSink *err); +DN_API bool DN_OS_FileWriteAllSafeFV (DN_Str8 path, DN_ErrSink *err, DN_FMT_ATTRIB char const *fmt, va_list args); +DN_API bool DN_OS_FileWriteAllSafeF (DN_Str8 path, DN_ErrSink *err, DN_FMT_ATTRIB char const *fmt, ...); + +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_PathIsOlderThan (DN_Str8 file, DN_Str8 check_against); +DN_API bool DN_OS_PathDelete (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_PathMakeDir (DN_Str8 path); +DN_API bool DN_OS_PathIterateDir (DN_Str8 path, DN_OSDirIterator *it); + +DN_API bool DN_OS_PathAddRef (DN_Arena *arena, DN_OSPath *fs_path, DN_Str8 path); +DN_API bool DN_OS_PathAdd (DN_Arena *arena, DN_OSPath *fs_path, DN_Str8 path); +DN_API bool DN_OS_PathAddF (DN_Arena *arena, DN_OSPath *fs_path, DN_FMT_ATTRIB char const *fmt, ...); +DN_API bool DN_OS_PathPop (DN_OSPath *fs_path); +DN_API DN_Str8 DN_OS_PathBuildWithSeparator (DN_Arena *arena, DN_OSPath const *fs_path, DN_Str8 path_separator); +DN_API DN_Str8 DN_OS_PathTo (DN_Arena *arena, DN_Str8 path, DN_Str8 path_separtor); +DN_API DN_Str8 DN_OS_PathToF (DN_Arena *arena, DN_Str8 path_separator, DN_FMT_ATTRIB char const *fmt, ...); +DN_API DN_Str8 DN_OS_Path (DN_Arena *arena, DN_Str8 path); +DN_API DN_Str8 DN_OS_PathF (DN_Arena *arena, DN_FMT_ATTRIB char const *fmt, ...); + +#define DN_OS_PathBuildFwdSlash(allocator, fs_path) DN_OS_PathBuildWithSeparator(allocator, fs_path, DN_Str8Lit("/")) +#define DN_OS_PathBuildBackSlash(allocator, fs_path) DN_OS_PathBuildWithSeparator(allocator, fs_path, DN_Str8Lit("\\")) +#define DN_OS_PathBuild(allocator, fs_path) DN_OS_PathBuildWithSeparator(allocator, fs_path, DN_OSPathSeparatorString) + +DN_API void DN_OS_Exit (int32_t exit_code); +DN_API DN_OSExecResult DN_OS_ExecPump (DN_OSExecAsyncHandle handle, char *stdout_buffer, size_t *stdout_size, char *stderr_buffer, size_t *stderr_size, DN_U32 timeout_ms, DN_ErrSink *err); +DN_API DN_OSExecResult DN_OS_ExecWait (DN_OSExecAsyncHandle handle, DN_Arena *arena, DN_ErrSink *err); +DN_API DN_OSExecAsyncHandle DN_OS_ExecAsync (DN_Str8Slice cmd_line, DN_OSExecArgs *args, DN_ErrSink *err); +DN_API DN_OSExecResult DN_OS_Exec (DN_Str8Slice cmd_line, DN_OSExecArgs *args, DN_Arena *arena, DN_ErrSink *err); +DN_API DN_OSExecResult DN_OS_ExecOrAbort (DN_Str8Slice cmd_line, DN_OSExecArgs *args, DN_Arena *arena); + +DN_API DN_OSSemaphore DN_OS_SemaphoreInit (DN_U32 initial_count); +DN_API void DN_OS_SemaphoreDeinit (DN_OSSemaphore *semaphore); +DN_API void DN_OS_SemaphoreIncrement (DN_OSSemaphore *semaphore, DN_U32 amount); +DN_API DN_OSSemaphoreWaitResult DN_OS_SemaphoreWait (DN_OSSemaphore *semaphore, DN_U32 timeout_ms); + +DN_API DN_OSBarrier DN_OS_BarrierInit (DN_U32 thread_count); +DN_API void DN_OS_BarrierDeinit (DN_OSBarrier *barrier); +DN_API void DN_OS_BarrierWait (DN_OSBarrier *barrier); + +DN_API DN_OSMutex DN_OS_MutexInit (); +DN_API void DN_OS_MutexDeinit (DN_OSMutex *mutex); +DN_API void DN_OS_MutexLock (DN_OSMutex *mutex); +DN_API void DN_OS_MutexUnlock (DN_OSMutex *mutex); +#define DN_OS_MutexScope(mutex) DN_DeferLoop(DN_OS_MutexLock(mutex), DN_OS_MutexUnlock(mutex)) + +DN_API DN_OSConditionVariable DN_OS_ConditionVariableInit (); +DN_API void DN_OS_ConditionVariableDeinit (DN_OSConditionVariable *cv); +DN_API bool DN_OS_ConditionVariableWait (DN_OSConditionVariable *cv, DN_OSMutex *mutex, DN_U64 sleep_ms); +DN_API bool DN_OS_ConditionVariableWaitUntil (DN_OSConditionVariable *cv, DN_OSMutex *mutex, DN_U64 end_ts_ms); +DN_API void DN_OS_ConditionVariableSignal (DN_OSConditionVariable *cv); +DN_API void DN_OS_ConditionVariableBroadcast (DN_OSConditionVariable *cv); + +DN_API bool DN_OS_ThreadInit (DN_OSThread *thread, DN_OSThreadFunc *func, DN_OSThreadLane *lane, void *user_context); +DN_API bool DN_OS_ThreadJoin (DN_OSThread *thread, DN_TCDeinitArenas deinit_arenas); +DN_API DN_U32 DN_OS_ThreadID (); +DN_API void DN_OS_ThreadSetNameFmt (char const *fmt, ...); + +DN_API DN_OSThreadLane DN_OS_ThreadLaneInit (DN_USize index, DN_USize thread_count, DN_OSBarrier barrier, DN_UPtr *share_mem); +DN_API void DN_OS_ThreadLaneSync (DN_OSThreadLane *lane, void **ptr_to_share); +DN_API DN_V2USize DN_OS_ThreadLaneRange (DN_OSThreadLane *lane, DN_USize values_count); + +DN_API DN_OSThreadLane* DN_OS_TCThreadLane (); +DN_API void DN_OS_TCThreadLaneSync (void **ptr_to_share); +DN_API DN_OSThreadLane DN_OS_TCThreadLaneEquip (DN_OSThreadLane lane); + +DN_API void DN_OS_HttpRequestAsync (DN_OSHttpResponse *response, DN_Arena *arena, DN_Str8 host, DN_Str8 path, DN_OSHttpRequestSecure secure, DN_Str8 method, DN_Str8 body, DN_Str8 headers); +DN_API void DN_OS_HttpRequestWait (DN_OSHttpResponse *response); +DN_API void DN_OS_HttpRequestFree (DN_OSHttpResponse *response); +DN_API DN_OSHttpResponse DN_OS_HttpRequest (DN_Arena *arena, DN_Str8 host, DN_Str8 path, DN_OSHttpRequestSecure secure, DN_Str8 method, DN_Str8 body, DN_Str8 headers); + +// NOTE: DN_OSPrint +enum DN_OSPrintDest +{ + DN_OSPrintDest_Out, + DN_OSPrintDest_Err, +}; + +// NOTE: Print Macros +#define DN_OS_PrintOut(string) DN_OS_Print(DN_OSPrintDest_Out, string) +#define DN_OS_PrintOutF(fmt, ...) DN_OS_PrintF(DN_OSPrintDest_Out, fmt, ##__VA_ARGS__) +#define DN_OS_PrintOutFV(fmt, args) DN_OS_PrintFV(DN_OSPrintDest_Out, fmt, args) + +#define DN_OS_PrintOutStyle(style, string) DN_OS_PrintStyle(DN_OSPrintDest_Out, style, string) +#define DN_OS_PrintOutFStyle(style, fmt, ...) DN_OS_PrintFStyle(DN_OSPrintDest_Out, style, fmt, ##__VA_ARGS__) +#define DN_OS_PrintOutFVStyle(style, fmt, args, ...) DN_OS_PrintFVStyle(DN_OSPrintDest_Out, style, fmt, args) + +#define DN_OS_PrintOutLn(string) DN_OS_PrintLn(DN_OSPrintDest_Out, string) +#define DN_OS_PrintOutLnF(fmt, ...) DN_OS_PrintLnF(DN_OSPrintDest_Out, fmt, ##__VA_ARGS__) +#define DN_OS_PrintOutLnFV(fmt, args) DN_OS_PrintLnFV(DN_OSPrintDest_Out, fmt, args) + +#define DN_OS_PrintOutLnStyle(style, string) DN_OS_PrintLnStyle(DN_OSPrintDest_Out, style, string); +#define DN_OS_PrintOutLnFStyle(style, fmt, ...) DN_OS_PrintLnFStyle(DN_OSPrintDest_Out, style, fmt, ##__VA_ARGS__) +#define DN_OS_PrintOutLnFVStyle(style, fmt, args) DN_OS_PrintLnFVStyle(DN_OSPrintDest_Out, style, fmt, args); + +#define DN_OS_PrintErr(string) DN_OS_Print(DN_OSPrintDest_Err, string) +#define DN_OS_PrintErrF(fmt, ...) DN_OS_PrintF(DN_OSPrintDest_Err, fmt, ##__VA_ARGS__) +#define DN_OS_PrintErrFV(fmt, args) DN_OS_PrintFV(DN_OSPrintDest_Err, fmt, args) + +#define DN_OS_PrintErrStyle(style, string) DN_OS_PrintStyle(DN_OSPrintDest_Err, style, string) +#define DN_OS_PrintErrFStyle(style, fmt, ...) DN_OS_PrintFStyle(DN_OSPrintDest_Err, style, fmt, ##__VA_ARGS__) +#define DN_OS_PrintErrFVStyle(style, fmt, args, ...) DN_OS_PrintFVStyle(DN_OSPrintDest_Err, style, fmt, args) + +#define DN_OS_PrintErrLn(string) DN_OS_PrintLn(DN_OSPrintDest_Err, string) +#define DN_OS_PrintErrLnF(fmt, ...) DN_OS_PrintLnF(DN_OSPrintDest_Err, fmt, ##__VA_ARGS__) +#define DN_OS_PrintErrLnFV(fmt, args) DN_OS_PrintLnFV(DN_OSPrintDest_Err, fmt, args) + +#define DN_OS_PrintErrLnStyle(style, string) DN_OS_PrintLnStyle(DN_OSPrintDest_Err, style, string); +#define DN_OS_PrintErrLnFStyle(style, fmt, ...) DN_OS_PrintLnFStyle(DN_OSPrintDest_Err, style, fmt, ##__VA_ARGS__) +#define DN_OS_PrintErrLnFVStyle(style, fmt, args) DN_OS_PrintLnFVStyle(DN_OSPrintDest_Err, style, fmt, args); + +// NOTE: Print +DN_API void DN_OS_Print (DN_OSPrintDest dest, DN_Str8 string); +DN_API void DN_OS_PrintF (DN_OSPrintDest dest, DN_FMT_ATTRIB char const *fmt, ...); +DN_API void DN_OS_PrintFV (DN_OSPrintDest dest, DN_FMT_ATTRIB char const *fmt, va_list args); + +DN_API void DN_OS_PrintStyle (DN_OSPrintDest dest, DN_LogStyle style, DN_Str8 string); +DN_API void DN_OS_PrintFStyle (DN_OSPrintDest dest, DN_LogStyle style, DN_FMT_ATTRIB char const *fmt, ...); +DN_API void DN_OS_PrintFVStyle (DN_OSPrintDest dest, DN_LogStyle style, DN_FMT_ATTRIB char const *fmt, va_list args); + +DN_API void DN_OS_PrintLn (DN_OSPrintDest dest, DN_Str8 string); +DN_API void DN_OS_PrintLnF (DN_OSPrintDest dest, DN_FMT_ATTRIB char const *fmt, ...); +DN_API void DN_OS_PrintLnFV (DN_OSPrintDest dest, DN_FMT_ATTRIB char const *fmt, va_list args); + +DN_API void DN_OS_PrintLnStyle (DN_OSPrintDest dest, DN_LogStyle style, DN_Str8 string); +DN_API void DN_OS_PrintLnFStyle (DN_OSPrintDest dest, DN_LogStyle style, DN_FMT_ATTRIB char const *fmt, ...); +DN_API void DN_OS_PrintLnFVStyle (DN_OSPrintDest dest, DN_LogStyle style, DN_FMT_ATTRIB char const *fmt, va_list args); + +// NOTE: DN_VArray +// TODO(doyle): Add an API for shrinking the array by decomitting pages back to the OS. +template struct DN_VArray +{ + T *data; // Pointer to the start of the array items in the block of memory + DN_USize size; // Number of items currently in the array + DN_USize max; // Maximum number of items this array can store + DN_USize commit; // Bytes committed + + T *begin() { return data; } + T *end () { return data + size; } + T const *begin() const { return data; } + T const *end () const { return data + size; } +}; + +template DN_VArray DN_OS_VArrayInitByteSize (DN_USize byte_size); +template DN_VArray DN_OS_VArrayInit (DN_USize max); +template DN_VArray DN_OS_VArrayInitCArray (T const (&items)[N], DN_USize max); +template void DN_OS_VArrayDeinit (DN_VArray *array); +template bool DN_OS_VArrayIsValid (DN_VArray const *array); +template bool DN_OS_VArrayReserve (DN_VArray *array, DN_USize count); +template T * DN_OS_VArrayAddArray (DN_VArray *array, T const *items, DN_USize count); +template T * DN_OS_VArrayAddCArray (DN_VArray *array, T const (&items)[N]); +template T * DN_OS_VArrayAdd (DN_VArray *array, T const &item); +#define DN_OS_VArrayAddArrayAssert(...) DN_HardAssert(DN_OS_VArrayAddArray(__VA_ARGS__)) +#define DN_OS_VArrayAddCArrayAssert(...) DN_HardAssert(DN_OS_VArrayAddCArray(__VA_ARGS__)) +#define DN_OS_VArrayAddAssert(...) DN_HardAssert(DN_OS_VArrayAdd(__VA_ARGS__)) +template T * DN_OS_VArrayMakeArray (DN_VArray *array, DN_USize count, DN_ZMem z_mem); +template T * DN_OS_VArrayMake (DN_VArray *array, DN_ZMem z_mem); +#define DN_OS_VArrayMakeArrayAssert(...) DN_HardAssert(DN_OS_VArrayMakeArray(__VA_ARGS__)) +#define DN_OS_VArrayMakeAssert(...) DN_HardAssert(DN_OS_VArrayMake(__VA_ARGS__)) +template T * DN_OS_VArrayInsertArray (DN_VArray *array, DN_USize index, T const *items, DN_USize count); +template T * DN_OS_VArrayInsertCArray (DN_VArray *array, DN_USize index, T const (&items)[N]); +template T * DN_OS_VArrayInsert (DN_VArray *array, DN_USize index, T const &item); +#define DN_OS_VArrayInsertArrayAssert(...) DN_HardAssert(DN_OS_VArrayInsertArray(__VA_ARGS__)) +#define DN_OS_VArrayInsertCArrayAssert(...) DN_HardAssert(DN_OS_VArrayInsertCArray(__VA_ARGS__)) +#define DN_OS_VArrayInsertAssert(...) DN_HardAssert(DN_OS_VArrayInsert(__VA_ARGS__)) +template T DN_OS_VArrayPopFront (DN_VArray *array, DN_USize count); +template T DN_OS_VArrayPopBack (DN_VArray *array, DN_USize count); +template DN_ArrayEraseResult DN_OS_VArrayEraseRange (DN_VArray *array, DN_USize begin_index, DN_ISize count, DN_ArrayErase erase); +template void DN_OS_VArrayClear (DN_VArray *array, DN_ZMem z_mem); +#endif // !defined(DN_OS_H) +#endif + +struct DN_InitArgs +{ + DN_TCInitArgs thread_context_init_args; +}; + +typedef DN_USize DN_InitFlags; +enum DN_InitFlags_ +{ + DN_InitFlags_Nil = 0, + DN_InitFlags_OS = (1 << 0), + DN_InitFlags_ThreadContext = (1 << 1) | DN_InitFlags_OS, + DN_InitFlags_LeakTracker = (1 << 2) | DN_InitFlags_OS, + DN_InitFlags_LogLibFeatures = (1 << 3), + DN_InitFlags_LogCPUFeatures = (1 << 4) | DN_InitFlags_OS, + DN_InitFlags_LogAllFeatures = DN_InitFlags_LogLibFeatures | DN_InitFlags_LogCPUFeatures, +}; + +struct DN_Core +{ + DN_InitFlags init_flags; + DN_TCCore main_tc; + DN_USize mem_allocs_frame; + DN_LeakTracker leak; + + DN_U32 log_level_to_show_from; + DN_LogPrintFunc* print_func; + void* print_func_context; + + bool os_init; + #if defined(DN_OS_H) + DN_OSCore os; + #endif +}; + +DN_API void DN_Init (DN_Core *dn, DN_InitFlags flags, DN_InitArgs *args); +DN_API void DN_Set (DN_Core *dn); +DN_API DN_Core *DN_Get (); +DN_API void DN_BeginFrame(); + +#if DN_H_WITH_HELPERS +// DN: Single header generator commented out => #include "Extra/dn_helpers.h" +#if !defined(DN_HELPERS_H) +#define DN_HELPERS_H + +// DN: Single header generator commented out => #if defined(_CLANGD) +// #include "../dn.h" +// #endif + +/* +//////////////////////////////////////////////////////////////////////////////////////////////////// +// +// $$\ $$\ $$$$$$$$\ $$\ $$$$$$$\ $$$$$$$$\ $$$$$$$\ $$$$$$\ +// $$ | $$ |$$ _____|$$ | $$ __$$\ $$ _____|$$ __$$\ $$ __$$\ +// $$ | $$ |$$ | $$ | $$ | $$ |$$ | $$ | $$ |$$ / \__| +// $$$$$$$$ |$$$$$\ $$ | $$$$$$$ |$$$$$\ $$$$$$$ |\$$$$$$\ +// $$ __$$ |$$ __| $$ | $$ ____/ $$ __| $$ __$$< \____$$\ +// $$ | $$ |$$ | $$ | $$ | $$ | $$ | $$ |$$\ $$ | +// $$ | $$ |$$$$$$$$\ $$$$$$$$\ $$ | $$$$$$$$\ $$ | $$ |\$$$$$$ | +// \__| \__|\________|\________|\__| \________|\__| \__| \______/ +// +// dn_helpers.h -- Helper functions/data structures +// +//////////////////////////////////////////////////////////////////////////////////////////////////// +*/ + +#if !defined(DN_NO_JSON_BUILDER) +enum DN_JSONBuilderItem +{ + DN_JSONBuilderItem_Empty, + DN_JSONBuilderItem_OpenContainer, + DN_JSONBuilderItem_CloseContainer, + DN_JSONBuilderItem_KeyValue, +}; + +struct DN_JSONBuilder +{ + bool use_stdout; // When set, ignore the string builder and dump immediately to stdout + DN_Str8Builder string_builder; // (Internal) + int indent_level; // (Internal) + int spaces_per_indent; // The number of spaces per indent level + DN_JSONBuilderItem last_item; +}; +#endif // !defined(DN_NO_JSON_BUIDLER) + +template +using DN_BinarySearchLessThanProc = bool(T const &lhs, T const &rhs); + +template +bool DN_BinarySearch_DefaultLessThan(T const &lhs, T const &rhs); + +enum DN_BinarySearchType +{ + // Index of the match. If no match is found, found is set to false and the + // index is set to the index where the match should be inserted/exist, if + // it were in the array + DN_BinarySearchType_Match, + + // Index of the first element in the array that is `element >= find`. If no such + // item is found or the array is empty, then, the index is set to the array + // size and found is set to `false`. + // + // For example: + // int array[] = {0, 1, 2, 3, 4, 5}; + // DN_BinarySearchResult result = DN_BinarySearch(array, DN_ArrayCountU(array), 4, DN_BinarySearchType_LowerBound); + // printf("%zu\n", result.index); // Prints index '4' + + DN_BinarySearchType_LowerBound, + + // Index of the first element in the array that is `element > find`. If no such + // item is found or the array is empty, then, the index is set to the array + // size and found is set to `false`. + // + // For example: + // int array[] = {0, 1, 2, 3, 4, 5}; + // DN_BinarySearchResult result = DN_BinarySearch(array, DN_ArrayCountU(array), 4, DN_BinarySearchType_UpperBound); + // printf("%zu\n", result.index); // Prints index '5' + + DN_BinarySearchType_UpperBound, +}; + +struct DN_BinarySearchResult +{ + bool found; + DN_USize index; +}; + +template +using DN_QSortLessThanProc = bool(T const &a, T const &b, void *user_context); + +#if !defined(DN_NO_JSON_BUILDER) +// NOTE: DN_JSONBuilder //////////////////////////////////////////////////////////////////////////// +#define DN_JSONBuilder_Object(builder) \ + DN_DeferLoop(DN_JSONBuilder_ObjectBegin(builder), \ + DN_JSONBuilder_ObjectEnd(builder)) + +#define DN_JSONBuilder_ObjectNamed(builder, name) \ + DN_DeferLoop(DN_JSONBuilder_ObjectBeginNamed(builder, name), \ + DN_JSONBuilder_ObjectEnd(builder)) + +#define DN_JSONBuilder_Array(builder) \ + DN_DeferLoop(DN_JSONBuilder_ArrayBegin(builder), \ + DN_JSONBuilder_ArrayEnd(builder)) + +#define DN_JSONBuilder_ArrayNamed(builder, name) \ + DN_DeferLoop(DN_JSONBuilder_ArrayBeginNamed(builder, name), \ + DN_JSONBuilder_ArrayEnd(builder)) + +DN_API DN_JSONBuilder DN_JSONBuilder_Init (DN_Arena *arena, int spaces_per_indent); +DN_API DN_Str8 DN_JSONBuilder_Build (DN_JSONBuilder const *builder, DN_Arena *arena); +DN_API void DN_JSONBuilder_KeyValue (DN_JSONBuilder *builder, DN_Str8 key, DN_Str8 value); +DN_API void DN_JSONBuilder_KeyValueF (DN_JSONBuilder *builder, DN_Str8 key, char const *value_fmt, ...); +DN_API void DN_JSONBuilder_ObjectBeginNamed (DN_JSONBuilder *builder, DN_Str8 name); +DN_API void DN_JSONBuilder_ObjectEnd (DN_JSONBuilder *builder); +DN_API void DN_JSONBuilder_ArrayBeginNamed (DN_JSONBuilder *builder, DN_Str8 name); +DN_API void DN_JSONBuilder_ArrayEnd (DN_JSONBuilder *builder); +DN_API void DN_JSONBuilder_Str8Named (DN_JSONBuilder *builder, DN_Str8 key, DN_Str8 value); +DN_API void DN_JSONBuilder_LiteralNamed (DN_JSONBuilder *builder, DN_Str8 key, DN_Str8 value); +DN_API void DN_JSONBuilder_U64Named (DN_JSONBuilder *builder, DN_Str8 key, uint64_t value); +DN_API void DN_JSONBuilder_I64Named (DN_JSONBuilder *builder, DN_Str8 key, int64_t value); +DN_API void DN_JSONBuilder_F64Named (DN_JSONBuilder *builder, DN_Str8 key, double value, int decimal_places); +DN_API void DN_JSONBuilder_BoolNamed (DN_JSONBuilder *builder, DN_Str8 key, bool value); + +#define DN_JSONBuilder_ObjectBegin(builder) DN_JSONBuilder_ObjectBeginNamed(builder, DN_Str8Lit("")) +#define DN_JSONBuilder_ArrayBegin(builder) DN_JSONBuilder_ArrayBeginNamed(builder, DN_Str8Lit("")) +#define DN_JSONBuilder_Str8(builder, value) DN_JSONBuilder_Str8Named(builder, DN_Str8Lit(""), value) +#define DN_JSONBuilder_Literal(builder, value) DN_JSONBuilder_LiteralNamed(builder, DN_Str8Lit(""), value) +#define DN_JSONBuilder_U64(builder, value) DN_JSONBuilder_U64Named(builder, DN_Str8Lit(""), value) +#define DN_JSONBuilder_I64(builder, value) DN_JSONBuilder_I64Named(builder, DN_Str8Lit(""), value) +#define DN_JSONBuilder_F64(builder, value) DN_JSONBuilder_F64Named(builder, DN_Str8Lit(""), value) +#define DN_JSONBuilder_Bool(builder, value) DN_JSONBuilder_BoolNamed(builder, DN_Str8Lit(""), value) +#endif // !defined(DN_NO_JSON_BUILDER) + +// NOTE: DN_BinarySearch +template bool DN_BinarySearch_DefaultLessThan(T const &lhs, T const &rhs); +template DN_BinarySearchResult DN_BinarySearch (T const *array, DN_USize array_size, T const &find, DN_BinarySearchType type = DN_BinarySearchType_Match, DN_BinarySearchLessThanProc less_than = DN_BinarySearch_DefaultLessThan); + +// NOTE: DN_QSort +template bool DN_QSort_DefaultLessThan(T const &lhs, T const &rhs, void *user_context); +template void DN_QSort (T *array, DN_USize array_size, void *user_context, DN_QSortLessThanProc less_than = DN_QSort_DefaultLessThan); + +// NOTE: DN_BinarySearch +template +bool DN_BinarySearch_DefaultLessThan(T const &lhs, T const &rhs) +{ + bool result = lhs < rhs; + return result; +} + +template +DN_BinarySearchResult DN_BinarySearch(T const *array, + DN_USize array_size, + T const &find, + DN_BinarySearchType type, + DN_BinarySearchLessThanProc less_than) +{ + DN_BinarySearchResult result = {}; + if (!array || array_size <= 0 || !less_than) + return result; + + T const *end = array + array_size; + T const *first = array; + T const *last = end; + while (first != last) { + DN_USize count = last - first; + T const *it = first + (count / 2); + + bool advance_first = false; + if (type == DN_BinarySearchType_UpperBound) + advance_first = !less_than(find, it[0]); + else + advance_first = less_than(it[0], find); + + if (advance_first) + first = it + 1; + else + last = it; + } + + switch (type) { + case DN_BinarySearchType_Match: { + result.found = first != end && !less_than(find, *first); + } break; + + case DN_BinarySearchType_LowerBound: /*FALLTHRU*/ + case DN_BinarySearchType_UpperBound: { + result.found = first != end; + } break; + } + + result.index = first - array; + return result; +} + +// NOTE: DN_QSort ////////////////////////////////////////////////////////////////////////////////// +template +bool DN_QSort_DefaultLessThan(T const &lhs, T const &rhs, void *user_context) +{ + (void)user_context; + bool result = lhs < rhs; + return result; +} + +template +void DN_QSort(T *array, DN_USize array_size, void *user_context, DN_QSortLessThanProc less_than) +{ + if (!array || array_size <= 1 || !less_than) + return; + + // NOTE: Insertion Sort, under 24->32 is an optimal amount ///////////////////////////////////// + const DN_USize QSORT_THRESHOLD = 24; + if (array_size < QSORT_THRESHOLD) { + for (DN_USize item_to_insert_index = 1; item_to_insert_index < array_size; item_to_insert_index++) { + for (DN_USize index = 0; index < item_to_insert_index; index++) { + if (!less_than(array[index], array[item_to_insert_index], user_context)) { + T item_to_insert = array[item_to_insert_index]; + for (DN_USize i = item_to_insert_index; i > index; i--) + array[i] = array[i - 1]; + + array[index] = item_to_insert; + break; + } + } + } + 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; + + // Swap pivot with last index, so pivot is always at the end of the array. + // This makes logic much simpler. + DN_Swap(array[last_index], array[pivot_index]); + pivot_index = last_index; + + // 4^, 8, 7, 5, 2, 3, 6 + if (less_than(array[start_index], array[pivot_index], 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 (less_than(array[index], array[pivot_index], user_context)) { + DN_Swap(array[partition_index], array[index]); + partition_index++; + } + } + + // Move pivot to right of partition + // 4, 5, 2, 3, |6, 8, ^7* + DN_Swap(array[partition_index], array[pivot_index]); + DN_QSort(array, partition_index, user_context, less_than); + + // 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 + one_after_partition_index, (array_size - one_after_partition_index), user_context, less_than); +} + +#endif // !defined(DN_HELPERS_H) +#endif + +#if DN_H_WITH_ASYNC +// DN: Single header generator commented out => #include "Extra/dn_async.h" #if !defined(DN_ASYNC_H) #define DN_ASYNC_H -#if defined(_CLANGD) - // DN: Single header generator commented out this header => #include "../dn_base_inc.h" - // DN: Single header generator commented out this header => #include "../dn_os_inc.h" +// DN: Single header generator commented out => #if defined(_CLANGD) +// #define DN_H_WITH_OS 1 +// #include "../dn.h" +// #endif + +enum DN_ASYNCPriority +{ + DN_ASYNCPriority_Low, + DN_ASYNCPriority_High, + DN_ASYNCPriority_Count, +}; + +struct DN_ASYNCCore +{ + DN_OSMutex ring_mutex; + DN_OSConditionVariable ring_write_cv; + DN_OSSemaphore worker_sem; + DN_Ring ring; + DN_OSThread *threads; + DN_U32 thread_count; + DN_U32 busy_threads; + DN_U32 join_threads; +}; + +struct DN_ASYNCWorkArgs +{ + DN_OSThread *thread; + void *input; +}; + +typedef void(DN_ASYNCWorkFunc)(DN_ASYNCWorkArgs work_args); + +struct DN_ASYNCWork +{ + DN_ASYNCWorkFunc *func; + void *input; + void *output; +}; + +struct DN_ASYNCTask +{ + bool queued; + DN_ASYNCWork work; + DN_OSSemaphore completion_sem; +}; + +DN_API void DN_ASYNC_Init (DN_ASYNCCore *async, char *base, DN_USize base_size, DN_OSThread *threads, DN_U32 threads_size); +DN_API void DN_ASYNC_Deinit (DN_ASYNCCore *async); +DN_API bool DN_ASYNC_QueueWork(DN_ASYNCCore *async, DN_ASYNCWorkFunc *func, void *input, DN_U64 wait_time_ms); +DN_API DN_ASYNCTask DN_ASYNC_QueueTask(DN_ASYNCCore *async, DN_ASYNCWorkFunc *func, void *input, DN_U64 wait_time_ms); +DN_API void DN_ASYNC_WaitTask (DN_OSSemaphore *sem, DN_U32 timeout_ms); + +#endif // DN_ASYNC_H #endif +#if DN_H_WITH_NET +// DN: Single header generator commented out => #include "Extra/dn_net.h" +#if !defined(DN_NET_H) +#define DN_NET_H + +// DN: Single header generator commented out => #if defined(_CLANGD) +// #define DN_H_WITH_OS 1 +// #include "../dn.h" +// #endif + +enum DN_NETRequestType +{ + DN_NETRequestType_Nil, + DN_NETRequestType_HTTP, + DN_NETRequestType_WS, +}; + +enum DN_NETResponseState +{ + DN_NETResponseState_Nil, + DN_NETResponseState_Error, + DN_NETResponseState_HTTP, + DN_NETResponseState_WSOpen, + DN_NETResponseState_WSText, + DN_NETResponseState_WSBinary, + DN_NETResponseState_WSClose, + DN_NETResponseState_WSPing, + DN_NETResponseState_WSPong, +}; + +enum DN_NETWSSend +{ + DN_NETWSSend_Text, + DN_NETWSSend_Binary, + DN_NETWSSend_Close, + DN_NETWSSend_Ping, + DN_NETWSSend_Pong, +}; + +enum DN_NETDoHTTPFlags +{ + DN_NETDoHTTPFlags_Nil = 0, + DN_NETDoHTTPFlags_BasicAuth = 1 << 0, +}; + +struct DN_NETDoHTTPArgs +{ + // NOTE: WS and HTTP args + DN_NETDoHTTPFlags flags; + DN_Str8 username; + DN_Str8 password; + DN_Str8 *headers; + DN_U16 headers_size; + + // NOTE: HTTP args only + DN_Str8 payload; +}; + +struct DN_NETRequestHandle +{ + DN_UPtr handle; + DN_U64 gen; +}; + +struct DN_NETResponse +{ + // NOTE: Common to WS and HTTP responses + DN_NETResponseState state; + DN_NETRequestHandle request; + DN_Str8 error_str8; + DN_Str8 body; + + // NOTE: HTTP responses only + DN_U32 http_status; +}; + +struct DN_NETRequest +{ + DN_MemList mem; + DN_Arena arena; + DN_Arena start_response_arena; + DN_NETRequestType type; + DN_U64 gen; + DN_Str8 url; + DN_Str8 method; + DN_OSSemaphore completion_sem; + DN_NETDoHTTPArgs args; + DN_NETResponse response; + DN_NETRequest *next; + DN_NETRequest *prev; + DN_U64 context[2]; +}; + +typedef void (DN_NETInitFunc) (struct DN_NETCore *net, char *base, DN_U64 base_size); +typedef void (DN_NETDeinitFunc) (struct DN_NETCore *net); +typedef DN_NETRequestHandle(DN_NETDoHTTPFunc) (struct DN_NETCore *net, DN_Str8 url, DN_Str8 method, DN_NETDoHTTPArgs const *args); +typedef DN_NETRequestHandle(DN_NETDoWSFunc) (struct DN_NETCore *net, DN_Str8 url); +typedef void (DN_NETDoWSSendFunc) (DN_NETRequestHandle handle, DN_Str8 data, DN_NETWSSend send); +typedef DN_NETResponse (DN_NETWaitForResponseFunc) (DN_NETRequestHandle handle, DN_Arena *arena, DN_U32 timeout_ms); +typedef DN_NETResponse (DN_NETWaitForAnyResponseFunc)(struct DN_NETCore *net, DN_Arena *arena, DN_U32 timeout_ms); + +struct DN_NETInterface +{ + DN_NETInitFunc* init; + DN_NETDeinitFunc* deinit; + DN_NETDoHTTPFunc* do_http; + DN_NETDoWSFunc* do_ws; + DN_NETDoWSSendFunc* do_ws_send; + DN_NETWaitForResponseFunc* wait_for_response; + DN_NETWaitForAnyResponseFunc* wait_for_any_response; +}; + +struct DN_NETCore +{ + char *base; + DN_U64 base_size; + DN_MemList mem; + DN_Arena arena; + DN_OSSemaphore completion_sem; + void *context; + DN_NETInterface api; +}; + +DN_Str8 DN_NET_Str8FromResponseState(DN_NETResponseState state); +DN_NETRequest * DN_NET_RequestFromHandle (DN_NETRequestHandle handle); +DN_NETRequestHandle DN_NET_HandleFromRequest (DN_NETRequest *request); + +// 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); +void DN_NET_EndFinishedRequest_ (DN_NETRequest *request); + +#endif // DN_NET_H +#endif +#endif // !defined(DN_H) +#if !defined(DN_ASYNC_H) +#define DN_ASYNC_H + +// DN: Single header generator commented out => #if defined(_CLANGD) +// #define DN_H_WITH_OS 1 +// #include "../dn.h" +// #endif + enum DN_ASYNCPriority { DN_ASYNCPriority_Low, @@ -15853,13 +7588,9 @@ DN_API void DN_ASYNC_WaitTask (DN_OSSemaphore *sem, DN_U32 timeout_ms); #if !defined(DN_BIN_PACK_H) #define DN_BIN_PACK_H -#if defined(_CLANGD) - // DN: Single header generator commented out this header => #include "../dn_base_inc.h" -#endif - -#if !defined(DN_BASE_INC_H) - #error dn_base_inc.h must be included before this -#endif +// DN: Single header generator commented out => #if defined(_CLANGD) +// #include "../dn.h" +// #endif enum DN_BinPackMode { @@ -15904,9 +7635,18 @@ DN_API DN_Str8 DN_BinPackBuild (DN_BinPack const *pack, DN_Arena *are #if !defined(DN_CSV_H) #define DN_CSV_H -#if defined(_CLANGD) - // DN: Single header generator commented out this header => #include "../dn_base_inc.h" -#endif +// NOTE: Data structures to create and parse CSV files, supports Python style escaped quotes (e.g. +// Using "" to escape quotes inside a quoted string). +// +// API +// DN_CSV_TokeniserNextN: Reads the next N consecutive fields from the parser. If `column_iterator` +// is `false` then the read of the N consecutive fields does not proceed past the end of the +// current CSV row. If `true` then it reads the next N fields even if reading would progress onto +// the next row. + + // DN: Single header generator commented out => #if defined(_CLANGD) +// #include "../dn.h" +// #endif enum DN_CSVSerialise { @@ -15930,440 +7670,36 @@ struct DN_CSVPack DN_CSVTokeniser read_tokeniser; }; +DN_CSVTokeniser DN_CSV_TokeniserInit (DN_Str8 string, char delimiter); +bool DN_CSV_TokeniserValid (DN_CSVTokeniser *tokeniser); +bool DN_CSV_TokeniserNextRow (DN_CSVTokeniser *tokeniser); +DN_Str8 DN_CSV_TokeniserNextField (DN_CSVTokeniser *tokeniser); +DN_Str8 DN_CSV_TokeniserNextColumn (DN_CSVTokeniser *tokeniser); +void DN_CSV_TokeniserSkipLine (DN_CSVTokeniser *tokeniser); +int DN_CSV_TokeniserNextN (DN_CSVTokeniser *tokeniser, DN_Str8 *fields, int fields_size, bool column_iterator); +int DN_CSV_TokeniserNextColumnN(DN_CSVTokeniser *tokeniser, DN_Str8 *fields, int fields_size); +int DN_CSV_TokeniserNextFieldN (DN_CSVTokeniser *tokeniser, DN_Str8 *fields, int fields_size); +void DN_CSV_TokeniserSkipLineN (DN_CSVTokeniser *tokeniser, int count); +void DN_CSV_PackU64 (DN_CSVPack *pack, DN_CSVSerialise serialise, DN_U64 *value); +void DN_CSV_PackI64 (DN_CSVPack *pack, DN_CSVSerialise serialise, DN_I64 *value); +void DN_CSV_PackI32 (DN_CSVPack *pack, DN_CSVSerialise serialise, DN_I32 *value); +void DN_CSV_PackI16 (DN_CSVPack *pack, DN_CSVSerialise serialise, DN_I16 *value); +void DN_CSV_PackI8 (DN_CSVPack *pack, DN_CSVSerialise serialise, DN_I8 *value); +void DN_CSV_PackU32 (DN_CSVPack *pack, DN_CSVSerialise serialise, DN_U32 *value); +void DN_CSV_PackU16 (DN_CSVPack *pack, DN_CSVSerialise serialise, DN_U16 *value); +void DN_CSV_PackBoolAsU64 (DN_CSVPack *pack, DN_CSVSerialise serialise, bool *value); +void DN_CSV_PackStr8 (DN_CSVPack *pack, DN_CSVSerialise serialise, DN_Str8 *str8, DN_Arena *arena); +void DN_CSV_PackBuffer (DN_CSVPack *pack, DN_CSVSerialise serialise, void *dest, size_t *size); +void DN_CSV_PackBufferWithMax (DN_CSVPack *pack, DN_CSVSerialise serialise, void *dest, size_t *size, size_t max); +bool DN_CSV_PackNewLine (DN_CSVPack *pack, DN_CSVSerialise serialise); + #endif // !defined(DN_CSV_H) -#if !defined(DN_HASH_H) -#define DN_HASH_H - -#if defined(_CLANGD) - // DN: Single header generator commented out this header => #include "../dn_base_inc.h" -#endif - -/* -//////////////////////////////////////////////////////////////////////////////////////////////////// -// -// $$\ $$\ $$$$$$\ $$$$$$\ $$\ $$\ -// $$ | $$ |$$ __$$\ $$ __$$\ $$ | $$ | -// $$ | $$ |$$ / $$ |$$ / \__|$$ | $$ | -// $$$$$$$$ |$$$$$$$$ |\$$$$$$\ $$$$$$$$ | -// $$ __$$ |$$ __$$ | \____$$\ $$ __$$ | -// $$ | $$ |$$ | $$ |$$\ $$ |$$ | $$ | -// $$ | $$ |$$ | $$ |\$$$$$$ |$$ | $$ | -// \__| \__|\__| \__| \______/ \__| \__| -// -// dn_hash.h -- Hashing functions -// -//////////////////////////////////////////////////////////////////////////////////////////////////// -*/ - -// NOTE: DN_FNV1A ////////////////////////////////////////////////////////////////////////////////// -#if !defined(DN_FNV1A32_SEED) - #define DN_FNV1A32_SEED 2166136261U -#endif - -#if !defined(DN_FNV1A64_SEED) - #define DN_FNV1A64_SEED 14695981039346656037ULL -#endif - -// NOTE: DN_MurmurHash3 //////////////////////////////////////////////////////////////////////////// -struct DN_MurmurHash3 { uint64_t e[2]; }; - -// NOTE: DN_FNV1A ////////////////////////////////////////////////////////////////////////////////// -DN_API uint32_t DN_FNV1A32_Hash (void const *bytes, DN_USize size); -DN_API uint64_t DN_FNV1A64_Hash (void const *bytes, DN_USize size); -DN_API uint32_t DN_FNV1A32_Iterate (void const *bytes, DN_USize size, uint32_t hash); -DN_API uint64_t DN_FNV1A64_Iterate (void const *bytes, DN_USize size, uint64_t hash); - -// NOTE: DN_MurmurHash3 //////////////////////////////////////////////////////////////////////////// -DN_API uint32_t DN_MurmurHash3_x86U32 (void const *key, int len, uint32_t seed); -DN_API DN_MurmurHash3 DN_MurmurHash3_x64U128 (void const *key, int len, uint32_t seed); -#define DN_MurmurHash3_x64U128AsU64(key, len, seed) (DN_MurmurHash3_x64U128(key, len, seed).e[0]) -#define DN_MurmurHash3_x64U128AsU32(key, len, seed) (DN_Cast(uint32_t)DN_MurmurHash3_x64U128(key, len, seed).e[0]) - -#endif // !defined(DN_HASH_H) #if !defined(DN_HELPERS_H) #define DN_HELPERS_H -#if defined(_CLANGD) - // DN: Single header generator commented out this header => #include "../dn_base_inc.h" - // DN: Single header generator commented out this header => #include "dn_math.h" -#if !defined(DN_MATH_H) -#define DN_MATH_H - -#if defined(_CLANGD) - // DN: Single header generator commented out this header => #include "../dn_base_inc.h" -#endif - -DN_MSVC_WARNING_PUSH -DN_MSVC_WARNING_DISABLE(4201) // warning C4201: nonstandard extension used: nameless struct/union -union DN_V2I32 -{ - struct { DN_I32 x, y; }; - struct { DN_I32 w, h; }; - DN_I32 data[2]; -}; - -union DN_V2U16 -{ - struct { DN_U16 x, y; }; - struct { DN_U16 w, h; }; - DN_U16 data[2]; -}; - -union DN_V2U32 -{ - struct { DN_U32 x, y; }; - struct { DN_U32 w, h; }; - DN_U32 data[2]; -}; - -union DN_V2F32 -{ - struct { DN_F32 x, y; }; - struct { DN_F32 w, h; }; - DN_F32 data[2]; -}; - -union DN_V3F32 -{ - struct { DN_F32 x, y, z; }; - struct { DN_F32 r, g, b; }; - DN_F32 data[3]; -}; - - -union DN_V4F32 -{ - struct { DN_F32 x, y, z, w; }; - struct { DN_F32 r, g, b, a; }; - #if !defined(DN_NO_V3) - DN_V3F32 rgb; - DN_V3F32 xyz; - #endif - DN_F32 data[4]; -}; -DN_MSVC_WARNING_POP - -struct DN_M4 -{ - DN_F32 columns[4][4]; // Column major matrix -}; - -union DN_M2x3 -{ - DN_F32 e[6]; - DN_F32 row[2][3]; -}; - -struct DN_Rect -{ - DN_V2F32 pos, size; -}; - -struct DN_RectMinMax -{ - DN_V2F32 min, max; -}; - -enum DN_RectCutClip -{ - DN_RectCutClip_No, - DN_RectCutClip_Yes, -}; - -enum DN_RectCutSide -{ - DN_RectCutSide_Left, - DN_RectCutSide_Right, - DN_RectCutSide_Top, - DN_RectCutSide_Bottom, -}; - -struct DN_RectCut -{ - DN_Rect* rect; - DN_RectCutSide side; -}; - -struct DN_RaycastLineIntersectV2Result -{ - bool hit; // True if there was an intersection, false if the lines are parallel - DN_F32 t_a; // Distance along `dir_a` that the intersection occurred, e.g. `origin_a + (dir_a * t_a)` - DN_F32 t_b; // Distance along `dir_b` that the intersection occurred, e.g. `origin_b + (dir_b * t_b)` -}; - -#define DN_V2I32_Zero DN_Literal(DN_V2I32){{(int32_t)(0), (int32_t)(0)}} -#define DN_V2I32_One DN_Literal(DN_V2I32){{(int32_t)(1), (int32_t)(1)}} -#define DN_V2I32_From1N(x) DN_Literal(DN_V2I32){{(int32_t)(x), (int32_t)(x)}} -#define DN_V2I32_From2N(x, y) DN_Literal(DN_V2I32){{(int32_t)(x), (int32_t)(y)}} -#define DN_V2I32_InitV2(xy) DN_Literal(DN_V2I32){{(int32_t)(xy).x, (int32_t)(xy).y}} - -DN_API bool operator!= (DN_V2I32 lhs, DN_V2I32 rhs); -DN_API bool operator== (DN_V2I32 lhs, DN_V2I32 rhs); -DN_API bool operator>= (DN_V2I32 lhs, DN_V2I32 rhs); -DN_API bool operator<= (DN_V2I32 lhs, DN_V2I32 rhs); -DN_API bool operator< (DN_V2I32 lhs, DN_V2I32 rhs); -DN_API bool operator> (DN_V2I32 lhs, DN_V2I32 rhs); -DN_API DN_V2I32 operator- (DN_V2I32 lhs, DN_V2I32 rhs); -DN_API DN_V2I32 operator- (DN_V2I32 lhs); -DN_API DN_V2I32 operator+ (DN_V2I32 lhs, DN_V2I32 rhs); -DN_API DN_V2I32 operator* (DN_V2I32 lhs, DN_V2I32 rhs); -DN_API DN_V2I32 operator* (DN_V2I32 lhs, DN_F32 rhs); -DN_API DN_V2I32 operator* (DN_V2I32 lhs, int32_t rhs); -DN_API DN_V2I32 operator/ (DN_V2I32 lhs, DN_V2I32 rhs); -DN_API DN_V2I32 operator/ (DN_V2I32 lhs, DN_F32 rhs); -DN_API DN_V2I32 operator/ (DN_V2I32 lhs, int32_t rhs); -DN_API DN_V2I32 & operator*= (DN_V2I32& lhs, DN_V2I32 rhs); -DN_API DN_V2I32 & operator*= (DN_V2I32& lhs, DN_F32 rhs); -DN_API DN_V2I32 & operator*= (DN_V2I32& lhs, int32_t rhs); -DN_API DN_V2I32 & operator/= (DN_V2I32& lhs, DN_V2I32 rhs); -DN_API DN_V2I32 & operator/= (DN_V2I32& lhs, DN_F32 rhs); -DN_API DN_V2I32 & operator/= (DN_V2I32& lhs, int32_t rhs); -DN_API DN_V2I32 & operator-= (DN_V2I32& lhs, DN_V2I32 rhs); -DN_API DN_V2I32 & operator+= (DN_V2I32& lhs, DN_V2I32 rhs); - -DN_API DN_V2I32 DN_V2I32_Min (DN_V2I32 a, DN_V2I32 b); -DN_API DN_V2I32 DN_V2I32_Max (DN_V2I32 a, DN_V2I32 b); -DN_API DN_V2I32 DN_V2I32_Abs (DN_V2I32 a); - -#define DN_V2U16_Zero DN_Literal(DN_V2U16){{(uint16_t)(0), (uint16_t)(0)}} -#define DN_V2U16_One DN_Literal(DN_V2U16){{(uint16_t)(1), (uint16_t)(1)}} -#define DN_V2U16_From1N(x) DN_Literal(DN_V2U16){{(uint16_t)(x), (uint16_t)(x)}} -#define DN_V2U16_From2N(x, y) DN_Literal(DN_V2U16){{(uint16_t)(x), (uint16_t)(y)}} - -DN_API bool operator!= (DN_V2U16 lhs, DN_V2U16 rhs); -DN_API bool operator== (DN_V2U16 lhs, DN_V2U16 rhs); -DN_API bool operator>= (DN_V2U16 lhs, DN_V2U16 rhs); -DN_API bool operator<= (DN_V2U16 lhs, DN_V2U16 rhs); -DN_API bool operator< (DN_V2U16 lhs, DN_V2U16 rhs); -DN_API bool operator> (DN_V2U16 lhs, DN_V2U16 rhs); -DN_API DN_V2U16 operator- (DN_V2U16 lhs, DN_V2U16 rhs); -DN_API DN_V2U16 operator+ (DN_V2U16 lhs, DN_V2U16 rhs); -DN_API DN_V2U16 operator* (DN_V2U16 lhs, DN_V2U16 rhs); -DN_API DN_V2U16 operator* (DN_V2U16 lhs, DN_F32 rhs); -DN_API DN_V2U16 operator* (DN_V2U16 lhs, int32_t rhs); -DN_API DN_V2U16 operator/ (DN_V2U16 lhs, DN_V2U16 rhs); -DN_API DN_V2U16 operator/ (DN_V2U16 lhs, DN_F32 rhs); -DN_API DN_V2U16 operator/ (DN_V2U16 lhs, int32_t rhs); -DN_API DN_V2U16 & operator*= (DN_V2U16& lhs, DN_V2U16 rhs); -DN_API DN_V2U16 & operator*= (DN_V2U16& lhs, DN_F32 rhs); -DN_API DN_V2U16 & operator*= (DN_V2U16& lhs, int32_t rhs); -DN_API DN_V2U16 & operator/= (DN_V2U16& lhs, DN_V2U16 rhs); -DN_API DN_V2U16 & operator/= (DN_V2U16& lhs, DN_F32 rhs); -DN_API DN_V2U16 & operator/= (DN_V2U16& lhs, int32_t rhs); -DN_API DN_V2U16 & operator-= (DN_V2U16& lhs, DN_V2U16 rhs); -DN_API DN_V2U16 & operator+= (DN_V2U16& lhs, DN_V2U16 rhs); - -#define DN_V2F32_Zero DN_Literal(DN_V2F32){{(DN_F32)(0), (DN_F32)(0)}} -#define DN_V2F32_One DN_Literal(DN_V2F32){{(DN_F32)(1), (DN_F32)(1)}} -#define DN_V2F32_From1N(x) DN_Literal(DN_V2F32){{(DN_F32)(x), (DN_F32)(x)}} -#define DN_V2F32_From2N(x, y) DN_Literal(DN_V2F32){{(DN_F32)(x), (DN_F32)(y)}} -#define DN_V2F32_FromV2I32(xy) DN_Literal(DN_V2F32){{(DN_F32)(xy).x, (DN_F32)(xy).y}} -#define DN_V2F32_FromV2U32(xy) DN_Literal(DN_V2F32){{(DN_F32)(xy).x, (DN_F32)(xy).y}} - -DN_API bool operator!= (DN_V2F32 lhs, DN_V2F32 rhs); -DN_API bool operator== (DN_V2F32 lhs, DN_V2F32 rhs); -DN_API bool operator>= (DN_V2F32 lhs, DN_V2F32 rhs); -DN_API bool operator<= (DN_V2F32 lhs, DN_V2F32 rhs); -DN_API bool operator< (DN_V2F32 lhs, DN_V2F32 rhs); -DN_API bool operator> (DN_V2F32 lhs, DN_V2F32 rhs); - -DN_API DN_V2F32 operator- (DN_V2F32 lhs); -DN_API DN_V2F32 operator- (DN_V2F32 lhs, DN_V2F32 rhs); -DN_API DN_V2F32 operator- (DN_V2F32 lhs, DN_V2I32 rhs); -DN_API DN_V2F32 operator- (DN_V2F32 lhs, DN_F32 rhs); -DN_API DN_V2F32 operator- (DN_V2F32 lhs, int32_t rhs); - -DN_API DN_V2F32 operator+ (DN_V2F32 lhs, DN_V2F32 rhs); -DN_API DN_V2F32 operator+ (DN_V2F32 lhs, DN_V2I32 rhs); -DN_API DN_V2F32 operator+ (DN_V2F32 lhs, DN_F32 rhs); -DN_API DN_V2F32 operator+ (DN_V2F32 lhs, int32_t rhs); - -DN_API DN_V2F32 operator* (DN_V2F32 lhs, DN_V2F32 rhs); -DN_API DN_V2F32 operator* (DN_V2F32 lhs, DN_V2I32 rhs); -DN_API DN_V2F32 operator* (DN_V2F32 lhs, DN_F32 rhs); -DN_API DN_V2F32 operator* (DN_V2F32 lhs, int32_t rhs); - -DN_API DN_V2F32 operator/ (DN_V2F32 lhs, DN_V2F32 rhs); -DN_API DN_V2F32 operator/ (DN_V2F32 lhs, DN_V2I32 rhs); -DN_API DN_V2F32 operator/ (DN_V2F32 lhs, DN_F32 rhs); -DN_API DN_V2F32 operator/ (DN_V2F32 lhs, int32_t rhs); - -DN_API DN_V2F32 & operator*= (DN_V2F32& lhs, DN_V2F32 rhs); -DN_API DN_V2F32 & operator*= (DN_V2F32& lhs, DN_V2I32 rhs); -DN_API DN_V2F32 & operator*= (DN_V2F32& lhs, DN_F32 rhs); -DN_API DN_V2F32 & operator*= (DN_V2F32& lhs, int32_t rhs); - -DN_API DN_V2F32 & operator/= (DN_V2F32& lhs, DN_V2F32 rhs); -DN_API DN_V2F32 & operator/= (DN_V2F32& lhs, DN_V2I32 rhs); -DN_API DN_V2F32 & operator/= (DN_V2F32& lhs, DN_F32 rhs); -DN_API DN_V2F32 & operator/= (DN_V2F32& lhs, int32_t rhs); - -DN_API DN_V2F32 & operator-= (DN_V2F32& lhs, DN_V2F32 rhs); -DN_API DN_V2F32 & operator-= (DN_V2F32& lhs, DN_V2I32 rhs); -DN_API DN_V2F32 & operator-= (DN_V2F32& lhs, DN_F32 rhs); -DN_API DN_V2F32 & operator-= (DN_V2F32& lhs, int32_t rhs); - -DN_API DN_V2F32 & operator+= (DN_V2F32& lhs, DN_V2F32 rhs); -DN_API DN_V2F32 & operator+= (DN_V2F32& lhs, DN_V2I32 rhs); -DN_API DN_V2F32 & operator+= (DN_V2F32& lhs, DN_F32 rhs); -DN_API DN_V2F32 & operator+= (DN_V2F32& lhs, int32_t rhs); - -DN_API DN_V2F32 DN_V2F32_Min (DN_V2F32 a, DN_V2F32 b); -DN_API DN_V2F32 DN_V2F32_Max (DN_V2F32 a, DN_V2F32 b); -DN_API DN_V2F32 DN_V2F32_Abs (DN_V2F32 a); -DN_API DN_F32 DN_V2F32_Dot (DN_V2F32 a, DN_V2F32 b); -DN_API DN_F32 DN_V2F32_LengthSq2V2 (DN_V2F32 lhs, DN_V2F32 rhs); -DN_API bool DN_V2F32_LengthSqIsWithin2V2 (DN_V2F32 lhs, DN_V2F32 rhs, DN_F32 within_amount_sq); -DN_API DN_F32 DN_V2F32_Length2V2 (DN_V2F32 lhs, DN_V2F32 rhs); -DN_API DN_F32 DN_V2F32_LengthSq (DN_V2F32 lhs); -DN_API DN_F32 DN_V2F32_Length (DN_V2F32 lhs); -DN_API DN_V2F32 DN_V2F32_Normalise (DN_V2F32 a); -DN_API DN_V2F32 DN_V2F32_Perpendicular (DN_V2F32 a); -DN_API DN_V2F32 DN_V2F32_Reflect (DN_V2F32 in, DN_V2F32 surface); -DN_API DN_F32 DN_V2F32_Area (DN_V2F32 a); - -#define DN_V3F32_From1N(x) DN_Literal(DN_V3F32){{(DN_F32)(x), (DN_F32)(x), (DN_F32)(x)}} -#define DN_V3F32_From3N(x, y, z) DN_Literal(DN_V3F32){{(DN_F32)(x), (DN_F32)(y), (DN_F32)(z)}} -#define DN_V3F32_FromV2F32And1N(xy, z) DN_Literal(DN_V3F32){{(DN_F32)(xy.x), (DN_F32)(xy.y), (DN_F32)(z)}} - -DN_API bool operator== (DN_V3F32 lhs, DN_V3F32 rhs); -DN_API bool operator!= (DN_V3F32 lhs, DN_V3F32 rhs); -DN_API bool operator>= (DN_V3F32 lhs, DN_V3F32 rhs); -DN_API bool operator<= (DN_V3F32 lhs, DN_V3F32 rhs); -DN_API bool operator< (DN_V3F32 lhs, DN_V3F32 rhs); -DN_API bool operator> (DN_V3F32 lhs, DN_V3F32 rhs); -DN_API DN_V3F32 operator- (DN_V3F32 lhs, DN_V3F32 rhs); -DN_API DN_V3F32 operator- (DN_V3F32 lhs); -DN_API DN_V3F32 operator+ (DN_V3F32 lhs, DN_V3F32 rhs); -DN_API DN_V3F32 operator* (DN_V3F32 lhs, DN_V3F32 rhs); -DN_API DN_V3F32 operator* (DN_V3F32 lhs, DN_F32 rhs); -DN_API DN_V3F32 operator* (DN_V3F32 lhs, int32_t rhs); -DN_API DN_V3F32 operator/ (DN_V3F32 lhs, DN_V3F32 rhs); -DN_API DN_V3F32 operator/ (DN_V3F32 lhs, DN_F32 rhs); -DN_API DN_V3F32 operator/ (DN_V3F32 lhs, int32_t rhs); -DN_API DN_V3F32 & operator*= (DN_V3F32 &lhs, DN_V3F32 rhs); -DN_API DN_V3F32 & operator*= (DN_V3F32 &lhs, DN_F32 rhs); -DN_API DN_V3F32 & operator*= (DN_V3F32 &lhs, int32_t rhs); -DN_API DN_V3F32 & operator/= (DN_V3F32 &lhs, DN_V3F32 rhs); -DN_API DN_V3F32 & operator/= (DN_V3F32 &lhs, DN_F32 rhs); -DN_API DN_V3F32 & operator/= (DN_V3F32 &lhs, int32_t rhs); -DN_API DN_V3F32 & operator-= (DN_V3F32 &lhs, DN_V3F32 rhs); -DN_API DN_V3F32 & operator+= (DN_V3F32 &lhs, DN_V3F32 rhs); -DN_API DN_F32 DN_V3F32_LengthSq (DN_V3F32 a); -DN_API DN_F32 DN_V3F32_Length (DN_V3F32 a); -DN_API DN_V3F32 DN_V3F32_Normalise (DN_V3F32 a); - -#define DN_V4F32_From1N(x) DN_Literal(DN_V4F32){{(DN_F32)(x), (DN_F32)(x), (DN_F32)(x), (DN_F32)(x)}} -#define DN_V4F32_From4N(x, y, z, w) DN_Literal(DN_V4F32){{(DN_F32)(x), (DN_F32)(y), (DN_F32)(z), (DN_F32)(w)}} -#define DN_V4F32_FromV3And1N(xyz, w) DN_Literal(DN_V4F32){{xyz.x, xyz.y, xyz.z, w}} -#define DN_V4F32_FromRGBAU8(r, g, b, a) DN_Literal(DN_V4F32){{r / 255.f, g / 255.f, b / 255.f, a / 255.f}} -#define DN_V4F32_FromRGBU8(r, g, b) DN_Literal(DN_V4F32){{r / 255.f, g / 255.f, b / 255.f, 1.f}} -DN_API DN_V4F32 DN_V4F32_FromRGBU32(DN_U32 u32); -DN_API DN_V4F32 DN_V4F32_FromRGBAU32(DN_U32 u32); -#define DN_V4F32_FromV4Alpha(v4, alpha) DN_V4F32_FromV3And1N(v4.xyz, alpha) -DN_API bool operator== (DN_V4F32 lhs, DN_V4F32 rhs); -DN_API bool operator!= (DN_V4F32 lhs, DN_V4F32 rhs); -DN_API bool operator<= (DN_V4F32 lhs, DN_V4F32 rhs); -DN_API bool operator< (DN_V4F32 lhs, DN_V4F32 rhs); -DN_API bool operator> (DN_V4F32 lhs, DN_V4F32 rhs); -DN_API DN_V4F32 operator- (DN_V4F32 lhs, DN_V4F32 rhs); -DN_API DN_V4F32 operator- (DN_V4F32 lhs); -DN_API DN_V4F32 operator+ (DN_V4F32 lhs, DN_V4F32 rhs); -DN_API DN_V4F32 operator* (DN_V4F32 lhs, DN_V4F32 rhs); -DN_API DN_V4F32 operator* (DN_V4F32 lhs, DN_F32 rhs); -DN_API DN_V4F32 operator* (DN_V4F32 lhs, int32_t rhs); -DN_API DN_V4F32 operator/ (DN_V4F32 lhs, DN_F32 rhs); -DN_API DN_V4F32 & operator*= (DN_V4F32 &lhs, DN_V4F32 rhs); -DN_API DN_V4F32 & operator*= (DN_V4F32 &lhs, DN_F32 rhs); -DN_API DN_V4F32 & operator*= (DN_V4F32 &lhs, int32_t rhs); -DN_API DN_V4F32 & operator-= (DN_V4F32 &lhs, DN_V4F32 rhs); -DN_API DN_V4F32 & operator+= (DN_V4F32 &lhs, DN_V4F32 rhs); -DN_API DN_F32 DN_V4F32_Dot (DN_V4F32 a, DN_V4F32 b); - -DN_API DN_M4 DN_M4_Identity (); -DN_API DN_M4 DN_M4_ScaleF (DN_F32 x, DN_F32 y, DN_F32 z); -DN_API DN_M4 DN_M4_Scale (DN_V3F32 xyz); -DN_API DN_M4 DN_M4_TranslateF (DN_F32 x, DN_F32 y, DN_F32 z); -DN_API DN_M4 DN_M4_Translate (DN_V3F32 xyz); -DN_API DN_M4 DN_M4_Transpose (DN_M4 mat); -DN_API DN_M4 DN_M4_Rotate (DN_V3F32 axis, DN_F32 radians); -DN_API DN_M4 DN_M4_Orthographic (DN_F32 left, DN_F32 right, DN_F32 bottom, DN_F32 top, DN_F32 z_near, DN_F32 z_far); -DN_API DN_M4 DN_M4_Perspective (DN_F32 fov /*radians*/, DN_F32 aspect, DN_F32 z_near, DN_F32 z_far); -DN_API DN_M4 DN_M4_Add (DN_M4 lhs, DN_M4 rhs); -DN_API DN_M4 DN_M4_Sub (DN_M4 lhs, DN_M4 rhs); -DN_API DN_M4 DN_M4_Mul (DN_M4 lhs, DN_M4 rhs); -DN_API DN_M4 DN_M4_Div (DN_M4 lhs, DN_M4 rhs); -DN_API DN_M4 DN_M4_AddF (DN_M4 lhs, DN_F32 rhs); -DN_API DN_M4 DN_M4_SubF (DN_M4 lhs, DN_F32 rhs); -DN_API DN_M4 DN_M4_MulF (DN_M4 lhs, DN_F32 rhs); -DN_API DN_M4 DN_M4_DivF (DN_M4 lhs, DN_F32 rhs); -DN_API DN_Str8x256 DN_M4_ColumnMajorString (DN_M4 mat); - -DN_API bool operator== (DN_M2x3 const &lhs, DN_M2x3 const &rhs); -DN_API bool operator!= (DN_M2x3 const &lhs, DN_M2x3 const &rhs); -DN_API DN_M2x3 DN_M2x3_Identity (); -DN_API DN_M2x3 DN_M2x3_Translate (DN_V2F32 offset); -DN_API DN_M2x3 DN_M2x3_Scale (DN_V2F32 scale); -DN_API DN_M2x3 DN_M2x3_Rotate (DN_F32 radians); -DN_API DN_M2x3 DN_M2x3_Mul (DN_M2x3 m1, DN_M2x3 m2); -DN_API DN_V2F32 DN_M2x3_Mul2F32 (DN_M2x3 m1, DN_F32 x, DN_F32 y); -DN_API DN_V2F32 DN_M2x3_MulV2 (DN_M2x3 m1, DN_V2F32 v2); - -#define DN_Rect_From2V2(pos, size) DN_Literal(DN_Rect){(pos), (size)} -#define DN_Rect_From4N(x, y, w, h) DN_Literal(DN_Rect){DN_Literal(DN_V2F32){{x, y}}, DN_Literal(DN_V2F32){{w, h}}} - -DN_API bool operator== (const DN_Rect& lhs, const DN_Rect& rhs); -DN_API DN_V2F32 DN_Rect_Center (DN_Rect rect); -DN_API bool DN_Rect_ContainsPoint (DN_Rect rect, DN_V2F32 p); -DN_API bool DN_Rect_ContainsRect (DN_Rect a, DN_Rect b); -DN_API DN_Rect DN_Rect_Expand (DN_Rect a, DN_F32 amount); -DN_API DN_Rect DN_Rect_ExpandV2 (DN_Rect a, DN_V2F32 amount); -DN_API bool DN_Rect_Intersects (DN_Rect a, DN_Rect b); -DN_API DN_Rect DN_Rect_Intersection (DN_Rect a, DN_Rect b); -DN_API DN_Rect DN_Rect_Union (DN_Rect a, DN_Rect b); -DN_API DN_RectMinMax DN_Rect_MinMax (DN_Rect a); -DN_API DN_F32 DN_Rect_Area (DN_Rect a); -DN_API DN_V2F32 DN_Rect_InterpolatedPoint (DN_Rect rect, DN_V2F32 t01); -DN_API DN_V2F32 DN_Rect_TopLeft (DN_Rect rect); -DN_API DN_V2F32 DN_Rect_TopRight (DN_Rect rect); -DN_API DN_V2F32 DN_Rect_BottomLeft (DN_Rect rect); -DN_API DN_V2F32 DN_Rect_BottomRight (DN_Rect rect); - -DN_API DN_Rect DN_Rect_CutLeftClip (DN_Rect *rect, DN_F32 amount, DN_RectCutClip clip); -DN_API DN_Rect DN_Rect_CutRightClip (DN_Rect *rect, DN_F32 amount, DN_RectCutClip clip); -DN_API DN_Rect DN_Rect_CutTopClip (DN_Rect *rect, DN_F32 amount, DN_RectCutClip clip); -DN_API DN_Rect DN_Rect_CutBottomClip (DN_Rect *rect, DN_F32 amount, DN_RectCutClip clip); - -#define DN_Rect_CutLeft(rect, amount) DN_Rect_CutLeftClip(rect, amount, DN_RectCutClip_Yes) -#define DN_Rect_CutRight(rect, amount) DN_Rect_CutRightClip(rect, amount, DN_RectCutClip_Yes) -#define DN_Rect_CutTop(rect, amount) DN_Rect_CutTopClip(rect, amount, DN_RectCutClip_Yes) -#define DN_Rect_CutBottom(rect, amount) DN_Rect_CutBottomClip(rect, amount, DN_RectCutClip_Yes) - -#define DN_Rect_CutLeftNoClip(rect, amount) DN_Rect_CutLeftClip(rect, amount, DN_RectCutClip_No) -#define DN_Rect_CutRightNoClip(rect, amount) DN_Rect_CutRightClip(rect, amount, DN_RectCutClip_No) -#define DN_Rect_CutTopNoClip(rect, amount) DN_Rect_CutTopClip(rect, amount, DN_RectCutClip_No) -#define DN_Rect_CutBottomNoClip(rect, amount) DN_Rect_CutBottomClip(rect, amount, DN_RectCutClip_No) - -DN_API DN_Rect DN_RectCut_Cut (DN_RectCut rect_cut, DN_V2F32 size, DN_RectCutClip clip); -#define DN_RectCut_Init(rect, side) DN_Literal(DN_RectCut){rect, side} -#define DN_RectCut_Left(rect) DN_Literal(DN_RectCut){rect, DN_RectCutSide_Left} -#define DN_RectCut_Right(rect) DN_Literal(DN_RectCut){rect, DN_RectCutSide_Right} -#define DN_RectCut_Top(rect) DN_Literal(DN_RectCut){rect, DN_RectCutSide_Top} -#define DN_RectCut_Bottom(rect) DN_Literal(DN_RectCut){rect, DN_RectCutSide_Bottom} - -DN_API DN_RaycastLineIntersectV2Result DN_Raycast_LineIntersectV2(DN_V2F32 origin_a, DN_V2F32 dir_a, DN_V2F32 origin_b, DN_V2F32 dir_b); -DN_API DN_V2F32 DN_Lerp_V2F32 (DN_V2F32 a, DN_F32 t, DN_V2F32 b); -DN_API DN_F32 DN_Lerp_F32 (DN_F32 a, DN_F32 t, DN_F32 b); -#endif // !defined(DN_MATH_H) -#endif - -#if !defined(DN_BASE_H) - #error dn_base_inc.h must be included before this -#endif - -#if !defined(DN_MATH_H) - #error dn_math.h must be included before this -#endif +// DN: Single header generator commented out => #if defined(_CLANGD) +// #include "../dn.h" +// #endif /* //////////////////////////////////////////////////////////////////////////////////////////////////// @@ -16382,11 +7718,7 @@ DN_API DN_F32 DN_Lerp_F32 (DN_F32 a, DN_F //////////////////////////////////////////////////////////////////////////////////////////////////// */ -// NOTE: DN_PCG32 ////////////////////////////////////////////////////////////////////////////////// -struct DN_PCG32 { uint64_t state; }; - #if !defined(DN_NO_JSON_BUILDER) -// NOTE: DN_JSONBuilder //////////////////////////////////////////////////////////////////////////// enum DN_JSONBuilderItem { DN_JSONBuilderItem_Empty, @@ -16405,7 +7737,6 @@ struct DN_JSONBuilder }; #endif // !defined(DN_NO_JSON_BUIDLER) -// NOTE: DN_BinarySearch /////////////////////////////////////////////////////////////////////////// template using DN_BinarySearchLessThanProc = bool(T const &lhs, T const &rhs); @@ -16451,15 +7782,6 @@ struct DN_BinarySearchResult template using DN_QSortLessThanProc = bool(T const &a, T const &b, void *user_context); -// NOTE: DN_PCG32 ////////////////////////////////////////////////////////////////////////////////// -DN_API DN_PCG32 DN_PCG32_Init (uint64_t seed); -DN_API uint32_t DN_PCG32_Next (DN_PCG32 *rng); -DN_API uint64_t DN_PCG32_Next64 (DN_PCG32 *rng); -DN_API uint32_t DN_PCG32_Range (DN_PCG32 *rng, uint32_t low, uint32_t high); -DN_API DN_F32 DN_PCG32_NextF32 (DN_PCG32 *rng); -DN_API DN_F64 DN_PCG32_NextF64 (DN_PCG32 *rng); -DN_API void DN_PCG32_Advance (DN_PCG32 *rng, uint64_t delta); - #if !defined(DN_NO_JSON_BUILDER) // NOTE: DN_JSONBuilder //////////////////////////////////////////////////////////////////////////// #define DN_JSONBuilder_Object(builder) \ diff --git a/Source/Base/dn_base.cpp b/Source/Base/dn_base.cpp index c0cf6da..cdda2f3 100644 --- a/Source/Base/dn_base.cpp +++ b/Source/Base/dn_base.cpp @@ -1,15 +1,31 @@ #define DN_BASE_CPP #if defined(_CLANGD) + #define DN_ARENA_TEMP_MEM_UAF_GUARD 1 + #define DN_H_WITH_OS 1 #include "../dn.h" #endif +DN_API bool DN_MemStartsWith(void const *lhs, DN_USize lhs_size, void const *rhs, DN_USize rhs_size) +{ + bool result = false; + if (lhs_size >= rhs_size) + result = DN_MemEqUnsafe(lhs, rhs, rhs_size); + return result; +} + DN_API bool DN_MemEq(void const *lhs, DN_USize lhs_size, void const *rhs, DN_USize rhs_size) { bool result = lhs_size == rhs_size && DN_Memcmp(lhs, rhs, rhs_size) == 0; return result; } +DN_API bool DN_MemEqUnsafe(void const *lhs, void const *rhs, DN_USize size) +{ + bool result = DN_Memcmp(lhs, rhs, size) == 0; + return result; +} + #if !defined(DN_PLATFORM_ARM64) && !defined(DN_PLATFORM_EMSCRIPTEN) #define DN_SUPPORTS_CPU_ID #endif @@ -800,16 +816,16 @@ DN_API DN_F32 DN_EpsilonClampF32(DN_F32 value, DN_F32 target, DN_F32 epsilon) return result; } -static DN_ArenaBlock *DN_ArenaBlockFromMemFuncs_(DN_U64 reserve, DN_U64 commit, bool track_alloc, bool alloc_can_leak, DN_ArenaMemFuncs mem_funcs) +static DN_MemBlock *DN_ArenaBlockFromMemFuncs_(DN_U64 reserve, DN_U64 commit, bool track_alloc, bool alloc_can_leak, DN_MemFuncs mem_funcs) { - DN_ArenaBlock *result = nullptr; + DN_MemBlock *result = nullptr; switch (mem_funcs.type) { - case DN_ArenaMemFuncType_Nil: + case DN_MemFuncsType_Nil: break; - case DN_ArenaMemFuncType_Basic: { + case DN_MemFuncsType_Heap: { DN_AssertF(reserve > DN_ARENA_HEADER_SIZE, "%I64u > %I64u", reserve, DN_ARENA_HEADER_SIZE); - result = DN_Cast(DN_ArenaBlock *) mem_funcs.basic_alloc(reserve); + result = DN_Cast(DN_MemBlock *) mem_funcs.heap_alloc(reserve); if (!result) return result; @@ -818,11 +834,11 @@ static DN_ArenaBlock *DN_ArenaBlockFromMemFuncs_(DN_U64 reserve, DN_U64 commit, result->reserve = reserve; } break; - case DN_ArenaMemFuncType_VMem: { - DN_AssertF(mem_funcs.vmem_page_size, "Page size must be set to a non-zero, power of two value"); - DN_Assert(DN_IsPowerOfTwo(mem_funcs.vmem_page_size)); + case DN_MemFuncsType_Virtual: { + DN_AssertF(mem_funcs.virtual_page_size, "Page size must be set to a non-zero, power of two value"); + DN_Assert(DN_IsPowerOfTwo(mem_funcs.virtual_page_size)); - DN_USize const page_size = mem_funcs.vmem_page_size; + DN_USize const page_size = mem_funcs.virtual_page_size; DN_U64 real_reserve = reserve ? reserve : DN_ARENA_RESERVE_SIZE; DN_U64 real_commit = commit ? commit : DN_ARENA_COMMIT_SIZE; real_reserve = DN_AlignUpPowerOfTwo(real_reserve, page_size); @@ -830,12 +846,12 @@ static DN_ArenaBlock *DN_ArenaBlockFromMemFuncs_(DN_U64 reserve, DN_U64 commit, DN_AssertF(DN_ARENA_HEADER_SIZE < real_commit && real_commit <= real_reserve, "%I64u < %I64u <= %I64u", DN_ARENA_HEADER_SIZE, real_commit, real_reserve); DN_MemCommit mem_commit = real_reserve == real_commit ? DN_MemCommit_Yes : DN_MemCommit_No; - result = DN_Cast(DN_ArenaBlock *) mem_funcs.vmem_reserve(real_reserve, mem_commit, DN_MemPage_ReadWrite); + result = DN_Cast(DN_MemBlock *) mem_funcs.virtual_reserve(real_reserve, mem_commit, DN_MemPage_ReadWrite); if (!result) return result; - if (mem_commit == DN_MemCommit_No && !mem_funcs.vmem_commit(result, real_commit, DN_MemPage_ReadWrite)) { - mem_funcs.vmem_release(result, real_reserve); + if (mem_commit == DN_MemCommit_No && !mem_funcs.virtual_commit(result, real_commit, DN_MemPage_ReadWrite)) { + mem_funcs.virtual_release(result, real_reserve); return result; } @@ -851,107 +867,131 @@ static DN_ArenaBlock *DN_ArenaBlockFromMemFuncs_(DN_U64 reserve, DN_U64 commit, return result; } -static bool DN_ArenaHasPoison_(DN_ArenaFlags flags) +static bool DN_ArenaHasPoison_(DN_MemFlags flags) { DN_MSVC_WARNING_PUSH DN_MSVC_WARNING_DISABLE(6237) // warning C6237: ( && ) is always zero. is never evaluated and might have side effects. - bool result = DN_ASAN_POISON && DN_BitIsNotSet(flags, DN_ArenaFlags_NoPoison); + bool result = DN_ASAN_POISON && DN_BitIsNotSet(flags, DN_MemFlags_NoPoison); DN_MSVC_WARNING_POP return result; } -static DN_ArenaBlock *DN_ArenaBlockFlagsFromMemFuncs_(DN_U64 reserve, DN_U64 commit, DN_ArenaFlags flags, DN_ArenaMemFuncs mem_funcs) +static DN_MemBlock *DN_MemBlockFromMemFuncsFlags_(DN_U64 reserve, DN_U64 commit, DN_MemFlags flags, DN_MemFuncs mem_funcs) { - bool track_alloc = (flags & DN_ArenaFlags_NoAllocTrack) == 0; - bool alloc_can_leak = flags & DN_ArenaFlags_AllocCanLeak; - DN_ArenaBlock *result = DN_ArenaBlockFromMemFuncs_(reserve, commit, track_alloc, alloc_can_leak, mem_funcs); + bool track_alloc = (flags & DN_MemFlags_NoAllocTrack) == 0; + bool alloc_can_leak = flags & DN_MemFlags_AllocCanLeak; + DN_MemBlock *result = DN_ArenaBlockFromMemFuncs_(reserve, commit, track_alloc, alloc_can_leak, mem_funcs); if (result && DN_ArenaHasPoison_(flags)) DN_ASanPoisonMemoryRegion(DN_Cast(char *) result + DN_ARENA_HEADER_SIZE, result->commit - DN_ARENA_HEADER_SIZE); return result; } -static void DN_ArenaUpdateStatsOnNewBlock_(DN_Arena *arena, DN_ArenaBlock const *block) +static void DN_MemListOnNewBlock_(DN_MemList *mem, DN_MemBlock const *block) { - DN_Assert(arena); + DN_Assert(mem); if (block) { - arena->stats.info.used += block->used; - arena->stats.info.commit += block->commit; - arena->stats.info.reserve += block->reserve; - arena->stats.info.blocks += 1; + mem->stats.info.used += block->used; + mem->stats.info.commit += block->commit; + mem->stats.info.reserve += block->reserve; + mem->stats.info.blocks += 1; - arena->stats.hwm.used = DN_Max(arena->stats.hwm.used, arena->stats.info.used); - arena->stats.hwm.commit = DN_Max(arena->stats.hwm.commit, arena->stats.info.commit); - arena->stats.hwm.reserve = DN_Max(arena->stats.hwm.reserve, arena->stats.info.reserve); - arena->stats.hwm.blocks = DN_Max(arena->stats.hwm.blocks, arena->stats.info.blocks); + mem->stats.hwm.used = DN_Max(mem->stats.hwm.used, mem->stats.info.used); + mem->stats.hwm.commit = DN_Max(mem->stats.hwm.commit, mem->stats.info.commit); + mem->stats.hwm.reserve = DN_Max(mem->stats.hwm.reserve, mem->stats.info.reserve); + mem->stats.hwm.blocks = DN_Max(mem->stats.hwm.blocks, mem->stats.info.blocks); } } -DN_API DN_Arena DN_ArenaFromBuffer(void *buffer, DN_USize size, DN_ArenaFlags flags) +DN_API DN_MemStats DN_MemStatsSum(DN_MemStats lhs, DN_MemStats rhs) +{ + DN_MemStats array[] = {lhs, rhs}; + DN_MemStats result = DN_MemStatsSumArray(array, DN_ArrayCountU(array)); + return result; +} + +DN_API DN_MemStats DN_MemStatsSumArray(DN_MemStats const *array, DN_USize size) +{ + DN_MemStats result = {}; + for (DN_ForItSize(it, DN_MemStats const, array, size)) { + DN_MemStats stats = *it.data; + result.info.used += stats.info.used; + result.info.commit += stats.info.commit; + result.info.reserve += stats.info.reserve; + result.info.blocks += stats.info.blocks; + + result.hwm.used = DN_Max(result.hwm.used, result.info.used); + result.hwm.commit = DN_Max(result.hwm.commit, result.info.commit); + result.hwm.reserve = DN_Max(result.hwm.reserve, result.info.reserve); + result.hwm.blocks = DN_Max(result.hwm.blocks, result.info.blocks); + } + return result; +} + +DN_API DN_MemList DN_MemListFromBuffer(void *buffer, DN_USize size, DN_MemFlags flags) { 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); DN_AssertF(DN_IsPowerOfTwo(size), "Buffer (%zu bytes) must be a power-of-two", size); // NOTE: Init block - DN_ArenaBlock *block = DN_Cast(DN_ArenaBlock *) buffer; + DN_MemBlock *block = DN_Cast(DN_MemBlock *) buffer; block->commit = size; block->reserve = size; block->used = DN_ARENA_HEADER_SIZE; if (block && DN_ArenaHasPoison_(flags)) DN_ASanPoisonMemoryRegion(DN_Cast(char *) block + DN_ARENA_HEADER_SIZE, block->commit - DN_ARENA_HEADER_SIZE); - DN_Arena result = {}; - result.flags = flags | DN_ArenaFlags_NoGrow | DN_ArenaFlags_NoAllocTrack | DN_ArenaFlags_AllocCanLeak | DN_ArenaFlags_UserBuffer; - result.curr = block; - DN_ArenaUpdateStatsOnNewBlock_(&result, result.curr); + DN_MemList result = {}; + result.flags = flags | DN_MemFlags_NoGrow | DN_MemFlags_NoAllocTrack | DN_MemFlags_AllocCanLeak | DN_MemFlags_UserBuffer; + result.curr = block; + DN_MemListOnNewBlock_(&result, result.curr); return result; } -DN_API DN_Arena DN_ArenaFromMemFuncs(DN_U64 reserve, DN_U64 commit, DN_ArenaFlags flags, DN_ArenaMemFuncs mem_funcs) +DN_API DN_MemList DN_MemListFromMemFuncs(DN_U64 reserve, DN_U64 commit, DN_MemFlags flags, DN_MemFuncs mem_funcs) { - DN_Arena result = {}; - result.flags = flags; - result.mem_funcs = mem_funcs; - result.flags |= DN_ArenaFlags_MemFuncs; - result.curr = DN_ArenaBlockFlagsFromMemFuncs_(reserve, commit, flags, mem_funcs); - DN_ArenaUpdateStatsOnNewBlock_(&result, result.curr); + DN_MemList result = {}; + result.funcs = mem_funcs; + result.flags |= flags | DN_MemFlags_MemFuncs; + result.curr = DN_MemBlockFromMemFuncsFlags_(reserve, commit, flags, mem_funcs); + DN_MemListOnNewBlock_(&result, result.curr); return result; } -static void DN_ArenaBlockDeinit_(DN_Arena const *arena, DN_ArenaBlock *block) +static void DN_MemBlockDeinit_(DN_MemList const *mem, DN_MemBlock *block) { DN_USize release_size = block->reserve; - if (DN_BitIsNotSet(arena->flags, DN_ArenaFlags_NoAllocTrack)) + if (DN_BitIsNotSet(mem->flags, DN_MemFlags_NoAllocTrack)) DN_LeakTrackDealloc(&g_dn_->leak, block); - if (DN_ArenaHasPoison_(arena->flags)) + if (DN_ArenaHasPoison_(mem->flags)) DN_ASanUnpoisonMemoryRegion(block, block->commit); - if (arena->flags & DN_ArenaFlags_MemFuncs) { - if (arena->mem_funcs.type == DN_ArenaMemFuncType_Basic) - arena->mem_funcs.basic_dealloc(block); + if (mem->flags & DN_MemFlags_MemFuncs) { + if (mem->funcs.type == DN_MemFuncsType_Heap) + mem->funcs.heap_dealloc(block); else - arena->mem_funcs.vmem_release(block, release_size); + mem->funcs.virtual_release(block, release_size); } } -DN_API void DN_ArenaDeinit(DN_Arena *arena) +DN_API void DN_MemListDeinit(DN_MemList *mem) { - for (DN_ArenaBlock *block = arena ? arena->curr : nullptr; block;) { - DN_ArenaBlock *block_to_free = block; + for (DN_MemBlock *block = mem ? mem->curr : nullptr; block;) { + DN_MemBlock *block_to_free = block; block = block->prev; - DN_ArenaBlockDeinit_(arena, block_to_free); + DN_MemBlockDeinit_(mem, block_to_free); } - if (arena) - *arena = {}; + if (mem) + *mem = {}; } -DN_API bool DN_ArenaCommitTo(DN_Arena *arena, DN_U64 pos) +DN_API bool DN_MemListCommitTo(DN_MemList *mem, DN_U64 pos) { - if (!arena || !arena->curr) + if (!mem || !mem->curr) return false; - DN_ArenaBlock *curr = arena->curr; + DN_MemBlock *curr = mem->curr; if (pos <= curr->commit) return true; @@ -959,188 +999,202 @@ DN_API bool DN_ArenaCommitTo(DN_Arena *arena, DN_U64 pos) if (!DN_Check(pos <= curr->reserve)) real_pos = curr->reserve; - DN_Assert(arena->mem_funcs.vmem_page_size); - DN_USize end_commit = DN_AlignUpPowerOfTwo(real_pos, arena->mem_funcs.vmem_page_size); + DN_Assert(mem->funcs.virtual_page_size); + DN_USize end_commit = DN_AlignUpPowerOfTwo(real_pos, mem->funcs.virtual_page_size); DN_USize commit_size = end_commit - curr->commit; char *commit_ptr = DN_Cast(char *) curr + curr->commit; - if (!arena->mem_funcs.vmem_commit(commit_ptr, commit_size, DN_MemPage_ReadWrite)) + if (!mem->funcs.virtual_commit(commit_ptr, commit_size, DN_MemPage_ReadWrite)) return false; - if (DN_ArenaHasPoison_(arena->flags)) + if (DN_ArenaHasPoison_(mem->flags)) DN_ASanPoisonMemoryRegion(commit_ptr, commit_size); curr->commit = end_commit; return true; } -DN_API bool DN_ArenaCommit(DN_Arena *arena, DN_U64 size) +DN_API bool DN_MemListCommit(DN_MemList *mem, DN_U64 size) { - if (!arena || !arena->curr) + if (!mem || !mem->curr) return false; - DN_U64 pos = DN_Min(arena->curr->reserve, arena->curr->commit + size); - bool result = DN_ArenaCommitTo(arena, pos); + DN_U64 pos = DN_Min(mem->curr->reserve, mem->curr->commit + size); + bool result = DN_MemListCommitTo(mem, pos); return result; } -DN_API bool DN_ArenaGrow(DN_Arena *arena, DN_U64 reserve, DN_U64 commit) +DN_API bool DN_MemListGrow(DN_MemList *mem, DN_U64 reserve, DN_U64 commit) { - if (arena->flags & (DN_ArenaFlags_NoGrow | DN_ArenaFlags_UserBuffer)) + if (mem->flags & (DN_MemFlags_NoGrow | DN_MemFlags_UserBuffer)) return false; bool result = false; - DN_ArenaBlock *new_block = DN_ArenaBlockFlagsFromMemFuncs_(reserve, commit, arena->flags, arena->mem_funcs); + DN_MemBlock *new_block = DN_MemBlockFromMemFuncsFlags_(reserve, commit, mem->flags, mem->funcs); if (new_block) { - result = true; - new_block->prev = arena->curr; - arena->curr = new_block; - new_block->reserve_sum = new_block->prev->reserve_sum + new_block->prev->reserve; - DN_ArenaUpdateStatsOnNewBlock_(arena, arena->curr); + result = true; + new_block->prev = mem->curr; + mem->curr = new_block; + new_block->reserve_sum = new_block->prev->reserve_sum + new_block->prev->reserve; + DN_MemListOnNewBlock_(mem, mem->curr); } return result; } -DN_API void *DN_ArenaAlloc(DN_Arena *arena, DN_U64 size, uint8_t align, DN_ZMem z_mem) +DN_API void *DN_MemListAlloc(DN_MemList *mem, DN_U64 size, uint8_t align, DN_ZMem z_mem) { - if (!arena) + if (!mem) return nullptr; - if (!arena->curr) { - arena->curr = DN_ArenaBlockFlagsFromMemFuncs_(DN_ARENA_RESERVE_SIZE, DN_ARENA_COMMIT_SIZE, arena->flags, arena->mem_funcs); - DN_ArenaUpdateStatsOnNewBlock_(arena, arena->curr); + if (!mem->curr) { + mem->curr = DN_MemBlockFromMemFuncsFlags_(DN_ARENA_RESERVE_SIZE, DN_ARENA_COMMIT_SIZE, mem->flags, mem->funcs); + DN_MemListOnNewBlock_(mem, mem->curr); } - if (!arena->curr) + if (!mem->curr) return nullptr; try_alloc_again: - DN_ArenaBlock *curr = arena->curr; - bool poison = DN_ArenaHasPoison_(arena->flags); - uint8_t real_align = poison ? DN_Max(align, DN_ASAN_POISON_ALIGNMENT) : align; - DN_U64 offset_pos = DN_AlignUpPowerOfTwo(curr->used, real_align) + (poison ? DN_ASAN_POISON_GUARD_SIZE : 0); - DN_U64 end_pos = offset_pos + size; - DN_U64 alloc_size = end_pos - curr->used; + DN_MemBlock *curr = mem->curr; + bool poison = DN_ArenaHasPoison_(mem->flags); + uint8_t real_align = poison ? DN_Max(align, DN_ASAN_POISON_ALIGNMENT) : align; + DN_U64 offset_pos = DN_AlignUpPowerOfTwo(curr->used, real_align) + (poison ? DN_ASAN_POISON_GUARD_SIZE : 0); + DN_U64 end_pos = offset_pos + size; + DN_U64 alloc_size = end_pos - curr->used; - if (end_pos > curr->reserve) { - if (arena->flags & (DN_ArenaFlags_NoGrow | DN_ArenaFlags_UserBuffer)) - 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_ArenaGrow(arena, new_reserve, new_commit)) - return nullptr; - goto try_alloc_again; + if (end_pos > curr->reserve) { + if (mem->flags & (DN_MemFlags_NoGrow | DN_MemFlags_UserBuffer)) + 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)) + return nullptr; + goto try_alloc_again; } DN_USize prev_arena_commit = curr->commit; if (end_pos > curr->commit) { - DN_Assert(arena->mem_funcs.vmem_page_size); - DN_Assert(arena->mem_funcs.type == DN_ArenaMemFuncType_VMem); - DN_Assert((arena->flags & DN_ArenaFlags_UserBuffer) == 0); - DN_USize end_commit = DN_AlignUpPowerOfTwo(end_pos, arena->mem_funcs.vmem_page_size); + DN_Assert(mem->funcs.virtual_page_size); + DN_Assert(mem->funcs.type == DN_MemFuncsType_Virtual); + DN_Assert((mem->flags & DN_MemFlags_UserBuffer) == 0); + DN_USize end_commit = DN_AlignUpPowerOfTwo(end_pos, mem->funcs.virtual_page_size); DN_USize commit_size = end_commit - curr->commit; char *commit_ptr = DN_Cast(char *) curr + curr->commit; - if (!arena->mem_funcs.vmem_commit(commit_ptr, commit_size, DN_MemPage_ReadWrite)) + if (!mem->funcs.virtual_commit(commit_ptr, commit_size, DN_MemPage_ReadWrite)) return nullptr; - if (poison && DN_BitIsNotSet(arena->flags, DN_ArenaFlags_SimAlloc)) + if (poison && DN_BitIsNotSet(mem->flags, DN_MemFlags_SimAlloc)) DN_ASanPoisonMemoryRegion(commit_ptr, commit_size); curr->commit = end_commit; - arena->stats.info.commit += commit_size; - arena->stats.hwm.commit = DN_Max(arena->stats.hwm.commit, arena->stats.info.commit); + mem->stats.info.commit += commit_size; + mem->stats.hwm.commit = DN_Max(mem->stats.hwm.commit, mem->stats.info.commit); } - void *result = DN_Cast(char *) curr + offset_pos; - curr->used += alloc_size; - arena->stats.info.used += alloc_size; - arena->stats.hwm.used = DN_Max(arena->stats.hwm.used, arena->stats.info.used); + 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); - if (poison && DN_BitIsNotSet(arena->flags, DN_ArenaFlags_SimAlloc)) + if (poison && DN_BitIsNotSet(mem->flags, DN_MemFlags_SimAlloc)) DN_ASanUnpoisonMemoryRegion(result, size); - if (z_mem == DN_ZMem_Yes && DN_BitIsNotSet(arena->flags, DN_ArenaFlags_SimAlloc)) { + if (z_mem == DN_ZMem_Yes && DN_BitIsNotSet(mem->flags, DN_MemFlags_SimAlloc)) { DN_USize reused_bytes = DN_Min(prev_arena_commit - offset_pos, size); DN_Memset(result, 0, reused_bytes); } - DN_Assert(arena->stats.hwm.used >= arena->stats.info.used); - DN_Assert(arena->stats.hwm.commit >= arena->stats.info.commit); - DN_Assert(arena->stats.hwm.reserve >= arena->stats.info.reserve); - DN_Assert(arena->stats.hwm.blocks >= arena->stats.info.blocks); + DN_Assert(mem->stats.hwm.used >= mem->stats.info.used); + DN_Assert(mem->stats.hwm.commit >= mem->stats.info.commit); + DN_Assert(mem->stats.hwm.reserve >= mem->stats.info.reserve); + DN_Assert(mem->stats.hwm.blocks >= mem->stats.info.blocks); return result; } -DN_API void *DN_ArenaAllocContiguous(DN_Arena *arena, DN_U64 size, uint8_t align, DN_ZMem z_mem) +DN_API void *DN_MemListAllocContiguous(DN_MemList *mem, DN_U64 size, uint8_t align, DN_ZMem z_mem) { - DN_ArenaFlags prev_flags = arena->flags; - arena->flags |= (DN_ArenaFlags_NoGrow | DN_ArenaFlags_NoPoison); - void *memory = DN_ArenaAlloc(arena, size, align, z_mem); - arena->flags = prev_flags; + DN_MemFlags prev_flags = mem->flags; + mem->flags |= (DN_MemFlags_NoGrow | DN_MemFlags_NoPoison); + void *memory = DN_MemListAlloc(mem, size, align, z_mem); + mem->flags = prev_flags; return memory; } -DN_API void *DN_ArenaCopy(DN_Arena *arena, void const *data, DN_U64 size, uint8_t align) +DN_API void *DN_MemListCopy(DN_MemList *mem, void const *data, DN_U64 size, uint8_t align) { - if (!arena || !data || size == 0) + if (!mem || !data || size == 0) return nullptr; - void *result = DN_ArenaAlloc(arena, size, align, DN_ZMem_No); + void *result = DN_MemListAlloc(mem, size, align, DN_ZMem_No); if (result) DN_Memcpy(result, data, size); return result; } -DN_API void DN_ArenaPopTo(DN_Arena *arena, DN_U64 init_used) +DN_API void DN_MemListPopTo(DN_MemList *mem, DN_U64 init_used) { - if (!arena || !arena->curr) + if (!mem || !mem->curr) return; + + // NOTE: Free any memory blocks allocated additionally from the initial block to revert to DN_U64 used = DN_Max(DN_ARENA_HEADER_SIZE, init_used); - DN_ArenaBlock *curr = arena->curr; + DN_MemBlock *curr = mem->curr; while (curr->reserve_sum >= used) { - DN_ArenaBlock *block_to_free = curr; - arena->stats.info.used -= block_to_free->used; - arena->stats.info.commit -= block_to_free->commit; - arena->stats.info.reserve -= block_to_free->reserve; - arena->stats.info.blocks -= 1; - if (arena->flags & DN_ArenaFlags_UserBuffer) + DN_MemBlock *block_to_free = curr; + mem->stats.info.used -= block_to_free->used; + mem->stats.info.commit -= block_to_free->commit; + mem->stats.info.reserve -= block_to_free->reserve; + mem->stats.info.blocks -= 1; + if (mem->flags & DN_MemFlags_UserBuffer) break; curr = curr->prev; - DN_ArenaBlockDeinit_(arena, block_to_free); + DN_MemBlockDeinit_(mem, block_to_free); } - arena->stats.info.used -= curr->used; - arena->curr = curr; + // NOTE: Revert the memory block we returned to + DN_U64 old_used = curr->used; + mem->stats.info.used = old_used; + mem->curr = curr; curr->used = used - curr->reserve_sum; - if (DN_ArenaHasPoison_(arena->flags)) { + + // NOTE: Scrub memory that we used previously in the block but no longer after reverting + if (DN_SCRUB_UNINIT_MEM_BYTE) { + if (old_used > curr->used) { + char *discarded = (char *)curr + curr->used; + DN_Memset(discarded, DN_SCRUB_UNINIT_MEM_BYTE, old_used - curr->used); + } + } + + // NOTE: ASAN Poison + if (DN_ArenaHasPoison_(mem->flags)) { char *poison_ptr = (char *)curr + DN_AlignUpPowerOfTwo(curr->used, DN_ASAN_POISON_ALIGNMENT); DN_USize poison_size = ((char *)curr + curr->commit) - poison_ptr; DN_ASanPoisonMemoryRegion(poison_ptr, poison_size); } - arena->stats.info.used += curr->used; + mem->stats.info.used += curr->used; } -DN_API void DN_ArenaPop(DN_Arena *arena, DN_U64 amount) +DN_API void DN_MemListPop(DN_MemList *mem, DN_U64 amount) { - DN_ArenaBlock *curr = arena->curr; + DN_MemBlock *curr = mem->curr; DN_USize used_sum = curr->reserve_sum + curr->used; if (!DN_Check(amount <= used_sum)) amount = used_sum; DN_USize pop_to = used_sum - amount; - DN_ArenaPopTo(arena, pop_to); + DN_MemListPopTo(mem, pop_to); } -DN_API DN_U64 DN_ArenaPos(DN_Arena const *arena) +DN_API DN_U64 DN_MemListPos(DN_MemList const *mem) { - DN_U64 result = (arena && arena->curr) ? arena->curr->reserve_sum + arena->curr->used : 0; + DN_U64 result = (mem && mem->curr) ? mem->curr->reserve_sum + mem->curr->used : 0; return result; } -DN_API void DN_ArenaClear(DN_Arena *arena) +DN_API void DN_MemListClear(DN_MemList *mem) { - DN_ArenaPopTo(arena, 0); + DN_MemListPopTo(mem, 0); } -DN_API bool DN_ArenaOwnsPtr(DN_Arena const *arena, void *ptr) +DN_API bool DN_MemListOwnsPtr(DN_MemList const *mem, void *ptr) { bool result = false; uintptr_t uint_ptr = DN_Cast(uintptr_t) ptr; - for (DN_ArenaBlock const *block = arena ? arena->curr : nullptr; !result && block; block = block->prev) { + for (DN_MemBlock const *block = mem ? mem->curr : nullptr; !result && block; block = block->prev) { uintptr_t begin = DN_Cast(uintptr_t) block + DN_ARENA_HEADER_SIZE; uintptr_t end = begin + block->reserve; result = uint_ptr >= begin && uint_ptr <= end; @@ -1148,7 +1202,7 @@ DN_API bool DN_ArenaOwnsPtr(DN_Arena const *arena, void *ptr) return result; } -DN_API DN_Str8x64 DN_ArenaInfoStr8x64(DN_ArenaInfo info) +DN_API DN_Str8x64 DN_MemListInfoStr8x64(DN_MemListInfo info) { DN_Str8x64 result = {}; DN_Str8x32 used = DN_ByteCountStr8x32(info.used); @@ -1159,67 +1213,219 @@ DN_API DN_Str8x64 DN_ArenaInfoStr8x64(DN_ArenaInfo info) return result; } -DN_API DN_ArenaStats DN_ArenaSumStatsArray(DN_ArenaStats const *array, DN_USize size) +DN_API DN_MemListTemp DN_MemListTempBegin(DN_MemList *mem) { - DN_ArenaStats result = {}; - for (DN_ForItSize(it, DN_ArenaStats const, array, size)) { - DN_ArenaStats stats = *it.data; - result.info.used += stats.info.used; - result.info.commit += stats.info.commit; - result.info.reserve += stats.info.reserve; - result.info.blocks += stats.info.blocks; - - result.hwm.used = DN_Max(result.hwm.used, result.info.used); - result.hwm.commit = DN_Max(result.hwm.commit, result.info.commit); - result.hwm.reserve = DN_Max(result.hwm.reserve, result.info.reserve); - result.hwm.blocks = DN_Max(result.hwm.blocks, result.info.blocks); - } - return result; -} - -DN_API DN_ArenaStats DN_ArenaSumStats(DN_ArenaStats lhs, DN_ArenaStats rhs) -{ - DN_ArenaStats array[] = {lhs, rhs}; - DN_ArenaStats result = DN_ArenaSumStatsArray(array, DN_ArrayCountU(array)); - return result; -} - -DN_API DN_ArenaStats DN_ArenaSumArenaArrayToStats(DN_Arena const *array, DN_USize size) -{ - DN_ArenaStats result = {}; - for (DN_USize index = 0; index < size; index++) { - DN_Arena const *arena = array + index; - result = DN_ArenaSumStats(result, arena->stats); - } - return result; -} - -DN_API DN_ArenaTempMem DN_ArenaTempMemBegin(DN_Arena *arena) -{ - DN_ArenaTempMem result = {}; - if (arena) { - DN_ArenaBlock *curr = arena->curr; - result = {arena, curr ? curr->reserve_sum + curr->used : 0}; + DN_MemListTemp result = {}; + if (mem) { + result.mem = mem; + result.used_sum = mem->curr ? mem->curr->reserve_sum + mem->curr->used : 0; } return result; }; -DN_API void DN_ArenaTempMemEnd(DN_ArenaTempMem mem) +DN_API void DN_MemListTempEnd(DN_MemListTemp temp) { - DN_ArenaPopTo(mem.arena, mem.used_sum); + DN_MemListPopTo(temp.mem, temp.used_sum); }; -DN_ArenaTempMemScope::DN_ArenaTempMemScope(DN_Arena *arena) +DN_Str8 const DN_MEM_LIST_UAF_TRACING_DISABLED_MORE_INFO_STR8_ = DN_Str8Lit( + "\n\nSet `DN_MemFlags_TempMemUAFTrace` on the affected arenas or " + "`#define DN_ARENA_TEMP_MEM_UAF_TRACE_ON_BY_DEFAULT 1` for more information" +); + +#if defined(DN_ARENA_TEMP_MEM_UAF_GUARD) +static bool DN_MemListUAFTracingEnabled_(DN_MemList *mem) { - mem = DN_ArenaTempMemBegin(arena); + bool result = DN_ARENA_TEMP_MEM_UAF_TRACE_ON_BY_DEFAULT; + if (!result) + result = mem->flags & DN_MemFlags_TempMemUAFTrace; + if (mem->flags & DN_MemFlags_TempMemUAFTraceDisable) + result = false; + return result; +} +#endif + +DN_API void DN_ArenaUAFCheck(DN_Arena *arena) +{ + (void)arena; + #if DN_ARENA_TEMP_MEM_UAF_GUARD + DN_MemList *mem = arena->mem; + if (!mem) + return; + + if (arena->uaf_guard_temp_mem && !arena->uaf_guard_is_being_checked) { + // NOTE: The following functions below allocate memory which might trigger an additional UAF + // check which would cause infinite recursion so we set a flag here to prevent that. + arena->uaf_guard_is_being_checked = true; + if (mem->uaf_guard_active_id != arena->uaf_guard_id) { + // NOTE: MSVC does not recognise %'u which is a STB extension which causes a lot of incorrect + // format arguments warnings that we mute here. + DN_MSVC_WARNING_PUSH + DN_MSVC_WARNING_DISABLE(6271) // Extra argument passed to 'DN_Str8FromFmtArena' + DN_MSVC_WARNING_DISABLE(6067) // _Param_(10) in call to 'DN_LogPrint' must be the address of a string. Actual type: 'int'. + DN_MSVC_WARNING_DISABLE(6273) // Non-integer passed as _Param_(11) when an integer is required in call to 'DN_LogPrint' Actual type: 'char *'. + DN_Str8 prefix = DN_Str8LineBreakStr8(DN_Str8FromFmtArena(arena, + "Arena use-after-free (UAF) detected in temporary memory usage! This allocation (trace " + "shown above) is attempting to allocate memory inside the active temporary region (id: %'u) " + "but belongs to a different region (id: %'u). This means when the active temporary region is " + "released, this allocation will be released and scrubbed causing a potential UAF.\n\nEnsure " + "that scratch memory is deconflicting correctly, scratch and or temporary memory regions have " + "matching begin and end pairs and only the arena view with the active temporary memory region " + "is being allocated from.", + mem->uaf_guard_active_id, + arena->uaf_guard_id), + 100, + arena); + + if (DN_MemListUAFTracingEnabled_(mem)) { + DN_Str8 curr_stack_trace = DN_Str8PadNewLines(DN_StackTraceWalkResultToStr8(arena, &arena->uaf_guard_temp_mem->trace, 1), DN_Str8Lit(" "), arena); + DN_Str8 active_stack_trace = DN_Str8PadNewLines(DN_StackTraceWalkResultToStr8(arena, &mem->uaf_guard_active_temp_mem->trace, 1), DN_Str8Lit(" "), arena); + DN_AssertF(mem->uaf_guard_active_id == arena->uaf_guard_id, + "%.*s\n\nThe originating temporary memory region (id: %'u) was created at:" + "\n\n %.*s\n\nThe active temporary memory region (id: %'u) was created at:\n\n %.*s", + DN_Str8PrintFmt(prefix), + arena->uaf_guard_id, + DN_Str8PrintFmt(curr_stack_trace), + mem->uaf_guard_active_id, + DN_Str8PrintFmt(active_stack_trace)); + } else { + DN_Str8 suffix = DN_Str8LineBreakStr8(DN_MEM_LIST_UAF_TRACING_DISABLED_MORE_INFO_STR8_, 100, arena); + DN_AssertF(mem->uaf_guard_active_id == arena->uaf_guard_id, "%.*s%.*s", DN_Str8PrintFmt(prefix), DN_Str8PrintFmt(suffix)); + } + DN_MSVC_WARNING_POP + } + arena->uaf_guard_is_being_checked = false; + } + #endif } -DN_ArenaTempMemScope::~DN_ArenaTempMemScope() +DN_API DN_Arena DN_ArenaFromMemList(DN_MemList *mem) { - DN_ArenaTempMemEnd(mem); + DN_Arena result = {}; + result.mem = mem; + return result; +} + +DN_API DN_Arena DN_ArenaTempBeginFromMemList(DN_MemList* mem) +{ + DN_Arena result = DN_ArenaFromMemList(mem); + DN_MemListTemp temp_mem = DN_MemListTempBegin(mem); + +#if DN_ARENA_TEMP_MEM_UAF_GUARD + if (DN_MemListUAFTracingEnabled_(mem)) + temp_mem.trace = DN_StackTraceWalk(&result, 256); + + // NOTE: Create persistent temp mem and set it on the mem list + result.uaf_guard_temp_mem = DN_ArenaNewCopy(&result, DN_MemListTemp, &temp_mem); + result.uaf_guard_prev_temp_mem = mem->uaf_guard_active_temp_mem; + mem->uaf_guard_active_temp_mem = result.uaf_guard_temp_mem; + + // NOTE: Update IDs + result.uaf_guard_id = ++mem->uaf_guard_next_id; + result.uaf_guard_prev_id = mem->uaf_guard_active_id; + mem->uaf_guard_active_id = result.uaf_guard_id; +#else + result.temp_mem = temp_mem; +#endif + return result; +} + + +DN_API DN_Arena DN_ArenaTempBeginFromArena(DN_Arena *arena) +{ + DN_Arena result = DN_ArenaTempBeginFromMemList(arena->mem); + return result; +} + +DN_API void DN_ArenaTempEnd(DN_Arena *arena, DN_ArenaReset reset) +{ +#if DN_ARENA_TEMP_MEM_UAF_GUARD + DN_AssertF(arena->uaf_guard_temp_mem, "Arena was not created with temp memory"); +#else + DN_AssertF(arena->temp_mem.mem, "Arena was not created with temp memory"); +#endif + +#if DN_ARENA_TEMP_MEM_UAF_GUARD + DN_MemList *mem = arena->mem; + if (mem->uaf_guard_active_id != arena->uaf_guard_id) { + // NOTE: MSVC does not recognise %'u which is a STB extension which causes a lot of incorrect + // format arguments warnings that we mute here. + DN_MSVC_WARNING_PUSH + DN_MSVC_WARNING_DISABLE(6271) // Extra argument passed to 'DN_Str8FromFmtArena' + DN_MSVC_WARNING_DISABLE(6067) // _Param_(10) in call to 'DN_LogPrint' must be the address of a string. Actual type: 'int'. + DN_MSVC_WARNING_DISABLE(6273) // Non-integer passed as _Param_(11) when an integer is required in call to 'DN_LogPrint' Actual type: 'char *'. + + // TODO: If this triggers, using the arena to format the error message is going to trigger the UAF check which is already failing. + DN_Str8 prefix = DN_Str8LineBreakStr8(DN_Str8Lit("The active temporary memory region recorded on the arena is " + "different from the current temporary memory region recorded on " + "the memory list allocator. This means that a temporary region " + "began but was not ended after the region was completed. Temporary " + "memory regions are enforced in a first-in-last-out manner (FILO) " + "to ensure the developer's intent of what the temporary region " + "spans is logically consistent and always strictly ends and begins " + "within a known lifetime."), + 100, + arena); + + if (DN_MemListUAFTracingEnabled_(mem)) { + DN_Str8 curr_stack_trace = DN_Str8PadNewLines(DN_StackTraceWalkResultToStr8(arena, &arena->uaf_guard_temp_mem->trace, 1), DN_Str8Lit(" "), arena); + DN_Str8 active_stack_trace = DN_Str8PadNewLines(DN_StackTraceWalkResultToStr8(arena, &mem->uaf_guard_active_temp_mem->trace, 1), DN_Str8Lit(" "), arena); + DN_AssertF(mem->uaf_guard_active_id == arena->uaf_guard_id, + "%.*s\n\nThe originating temporary memory region (id: %'u) was created at:" + "\n\n %.*s\n\nThe active temporary memory region (id: %'u) was created at:\n\n %.*s", + DN_Str8PrintFmt(prefix), + arena->uaf_guard_id, + DN_Str8PrintFmt(curr_stack_trace), + mem->uaf_guard_active_id, + DN_Str8PrintFmt(active_stack_trace)); + } else { + DN_Str8 suffix = DN_Str8LineBreakStr8(DN_MEM_LIST_UAF_TRACING_DISABLED_MORE_INFO_STR8_, 100, arena); + DN_AssertF(mem->uaf_guard_active_id == arena->uaf_guard_id, "%.*s%.*s", DN_Str8PrintFmt(prefix), DN_Str8PrintFmt(suffix)); + } + DN_MSVC_WARNING_POP + DN_Assert(arena->mem->uaf_guard_active_id == arena->uaf_guard_id); + } +#endif + + if (reset == DN_ArenaReset_Yes) { +#if DN_ARENA_TEMP_MEM_UAF_GUARD + DN_MemListTempEnd(*arena->uaf_guard_temp_mem); +#else + DN_MemListTempEnd(arena->temp_mem); +#endif + } + +#if DN_ARENA_TEMP_MEM_UAF_GUARD + mem->uaf_guard_active_id = arena->uaf_guard_prev_id; + mem->uaf_guard_active_temp_mem = arena->uaf_guard_prev_temp_mem; + + arena->uaf_guard_prev_temp_mem = nullptr; + arena->uaf_guard_prev_id = 0; + arena->uaf_guard_temp_mem = nullptr; +#endif +} + +DN_API void *DN_ArenaAlloc(DN_Arena *arena, DN_U64 size, uint8_t align, DN_ZMem z_mem) +{ + DN_ArenaUAFCheck(arena); + void *result = DN_MemListAlloc(arena->mem, size, align, z_mem); + return result; +} + +DN_API void *DN_ArenaAllocContiguous(DN_Arena *arena, DN_U64 size, uint8_t align, DN_ZMem z_mem) +{ + DN_ArenaUAFCheck(arena); + void *result = DN_MemListAllocContiguous(arena->mem, size, align, z_mem); + return result; +} + +DN_API void *DN_ArenaCopy(DN_Arena *arena, void const *data, DN_U64 size, uint8_t align) +{ + DN_ArenaUAFCheck(arena); + void *result = DN_MemListCopy(arena->mem, data, size, align); + return result; } -// NOTE: DN_Pool /////////////////////////////////////////////////////////////////////////////////// DN_API DN_Pool DN_PoolFromArena(DN_Arena *arena, uint8_t align) { DN_Pool result = {}; @@ -1303,7 +1509,7 @@ DN_API void DN_PoolDealloc(DN_Pool *pool, void *ptr) if (!DN_PoolIsValid(pool) || !ptr) return; - DN_Assert(DN_ArenaOwnsPtr(pool->arena, ptr)); + DN_Assert(DN_MemListOwnsPtr(pool->arena->mem, ptr)); char const *one_byte_behind_ptr = DN_Cast(char *) ptr - 1; DN_USize offset_to_original_ptr = 0; @@ -1315,13 +1521,20 @@ DN_API void DN_PoolDealloc(DN_Pool *pool, void *ptr) DN_PoolSlotSize slot_index = DN_Cast(DN_PoolSlotSize)(DN_Cast(uintptr_t) slot->next); DN_Assert(slot_index < DN_PoolSlotSize_Count); + // NOTE: Scrub memory before returning to the pool + if (DN_SCRUB_UNINIT_MEM_BYTE) { + DN_USize slot_size_in_bytes = 1ULL << (slot_index + 5); + DN_USize data_offset = (char *)slot->data - (char *)slot; + DN_Memset(slot->data, DN_SCRUB_UNINIT_MEM_BYTE, slot_size_in_bytes - data_offset); + } + slot->next = pool->slots[slot_index]; pool->slots[slot_index] = slot; } static void DN_ErrSinkCheck_(DN_ErrSink const *err) { - DN_Assert(err->arena); + DN_Assert(err->arena->mem); if (err->stack_size == 0) return; @@ -1342,28 +1555,29 @@ static void DN_ErrSinkCheck_(DN_ErrSink const *err) DN_API DN_ErrSink* DN_ErrSinkBegin_(DN_ErrSink *err, DN_ErrSinkMode mode, DN_CallSite call_site) { - DN_USize arena_pos = DN_ArenaPos(err->arena); + // NOTE: OOM error if (err->stack_size == DN_ArrayCountU(err->stack)) { DN_Str8Builder builder = DN_Str8BuilderFromArena(err->arena); for (DN_ForItSize(it, DN_ErrSinkNode, err->stack, err->stack_size)) DN_Str8BuilderAppendF(&builder, " [%04zu] %.*s:%u %.*s\n", it.index, DN_Str8PrintFmt(it.data->call_site.file), it.data->call_site.line, DN_Str8PrintFmt(it.data->call_site.function)); DN_Str8 msg = DN_Str8BuilderBuild(&builder, err->arena); DN_AssertF(err->stack_size < DN_ArrayCountU(err->stack), "Error sink has run out of error scopes, potential leak. Scopes were\n%.*s", DN_Str8PrintFmt(msg)); - DN_ArenaPopTo(err->arena, arena_pos); } + // NOTE: Allocate the node DN_ErrSinkNode *node = err->stack + err->stack_size++; - node->arena_pos = arena_pos; + node->arena_pos = DN_MemListPos(err->arena->mem); node->mode = mode; node->call_site = call_site; DN_SentinelDoublyLLInitArena(node->msg_sentinel, DN_ErrSinkMsg, err->arena); // NOTE: Handle allocation error if (!DN_Check(node && node->msg_sentinel)) { - DN_ArenaPopTo(err->arena, arena_pos); + DN_MemListPopTo(err->arena->mem, node->arena_pos); node->msg_sentinel = nullptr; err->stack_size--; } + DN_ErrSink *result = err; return result; } @@ -1389,7 +1603,7 @@ DN_API DN_ErrSinkMsg *DN_ErrSinkEnd(DN_Arena *arena, DN_ErrSink *err) DN_ErrSinkMsg *prev = nullptr; for (DN_ErrSinkMsg *it = node->msg_sentinel->next; it != node->msg_sentinel; it = it->next) { DN_ErrSinkMsg *entry = DN_ArenaNew(arena, DN_ErrSinkMsg, DN_ZMem_Yes); - entry->msg = DN_Str8FromStr8Arena(arena, it->msg); + entry->msg = DN_Str8FromStr8Arena(it->msg, arena); entry->call_site = it->call_site; entry->error_code = it->error_code; if (!result) @@ -1401,7 +1615,7 @@ DN_API DN_ErrSinkMsg *DN_ErrSinkEnd(DN_Arena *arena, DN_ErrSink *err) // NOTE: Deallocate all the memory for this scope err->stack_size--; - DN_ArenaPopTo(err->arena, node->arena_pos); + DN_MemListPopTo(err->arena->mem, node->arena_pos); return result; } @@ -1451,8 +1665,7 @@ DN_API DN_Str8 DN_ErrSinkEndStr8(DN_Arena *arena, DN_ErrSink *err) // NOTE: Deallocate all the memory for this scope err->stack_size--; - DN_U64 arena_pos = node->arena_pos; - DN_ArenaPopTo(err->arena, arena_pos); + DN_MemListPopTo(err->arena->mem, node->arena_pos); result = DN_Str8BuilderBuild(&builder, arena); return result; @@ -1468,6 +1681,8 @@ DN_API bool DN_ErrSinkEndLogError_(DN_ErrSink *err, DN_CallSite call_site, DN_St DN_ErrSinkNode *node = err->stack + (err->stack_size - 1); DN_AssertF(err->stack_size, "Begin must be called before calling end"); DN_AssertF(node->msg_sentinel, "Begin must be called before calling end"); + err->stack_size--; + bool result = false; if (node->msg_sentinel != node->msg_sentinel->next) { result = true; @@ -1487,14 +1702,13 @@ DN_API bool DN_ErrSinkEndLogError_(DN_ErrSink *err, DN_CallSite call_site, DN_St // NOTE: Log the error DN_Str8 log = DN_Str8BuilderBuild(&builder, err->arena); - DN_LogPrint(DN_LogTypeParamFromType(DN_LogType_Error), call_site, "%.*s", DN_Str8PrintFmt(log)); + DN_LogPrint(DN_LogTypeParamFromType(DN_LogType_Error), call_site, DN_LogFlags_Nil, "%.*s", DN_Str8PrintFmt(log)); if (node->mode == DN_ErrSinkMode_DebugBreakOnErrorLog) DN_DebugBreak; // NOTE: Deallocate the error node's memory and pop it from the stack - DN_ArenaPopTo(err->arena, node->arena_pos); - err->stack_size--; + DN_MemListPopTo(err->arena->mem, node->arena_pos); } return result; } @@ -1566,12 +1780,13 @@ DN_API void DN_TCInit(DN_TCCore *tc, DN_U64 thread_id, DN_Arena *main_arena, DN_ { tc->thread_id = thread_id; tc->main_arena = main_arena; + tc->main_pool = DN_PoolFromArena(tc->main_arena, 0); tc->temp_a_arena = temp_a_arena; tc->temp_b_arena = temp_b_arena; tc->err_sink.arena = err_sink_arena; } -DN_API void DN_TCInitFromMemFuncs(DN_TCCore *tc, DN_U64 thread_id, DN_TCInitArgs *args, DN_ArenaMemFuncs mem_funcs) +DN_API void DN_TCInitFromMemFuncs(DN_TCCore *tc, DN_U64 thread_id, DN_TCInitArgs *args, DN_MemFuncs mem_funcs) { DN_U64 main_reserve = (args && args->main_reserve) ? args->main_reserve : DN_Kilobytes(64); DN_U64 main_commit = (args && args->main_commit) ? args->main_commit : DN_Kilobytes(4); @@ -1580,20 +1795,26 @@ DN_API void DN_TCInitFromMemFuncs(DN_TCCore *tc, DN_U64 thread_id, DN_TCInitArgs DN_U64 err_sink_reserve = (args && args->err_sink_reserve) ? args->err_sink_reserve : DN_Kilobytes(64); DN_U64 err_sink_commit = (args && args->err_sink_commit) ? args->err_sink_commit : DN_Kilobytes(4); - tc->main_arena_ = DN_ArenaFromMemFuncs(main_reserve, main_commit, DN_ArenaFlags_AllocCanLeak | DN_ArenaFlags_NoAllocTrack, mem_funcs); - tc->temp_a_arena_ = DN_ArenaFromMemFuncs(temp_reserve, temp_commit, DN_ArenaFlags_AllocCanLeak | DN_ArenaFlags_NoAllocTrack, mem_funcs); - tc->temp_b_arena_ = DN_ArenaFromMemFuncs(temp_reserve, temp_commit, DN_ArenaFlags_AllocCanLeak | DN_ArenaFlags_NoAllocTrack, mem_funcs); - tc->err_sink_arena_ = DN_ArenaFromMemFuncs(err_sink_reserve, err_sink_commit, DN_ArenaFlags_AllocCanLeak | DN_ArenaFlags_NoAllocTrack, mem_funcs); + tc->main_arena_mem_ = DN_MemListFromMemFuncs(main_reserve, main_commit, DN_MemFlags_AllocCanLeak | DN_MemFlags_NoAllocTrack, mem_funcs); + tc->temp_a_arena_mem_ = DN_MemListFromMemFuncs(temp_reserve, temp_commit, DN_MemFlags_AllocCanLeak | DN_MemFlags_NoAllocTrack, mem_funcs); + tc->temp_b_arena_mem_ = DN_MemListFromMemFuncs(temp_reserve, temp_commit, DN_MemFlags_AllocCanLeak | DN_MemFlags_NoAllocTrack, mem_funcs); + tc->err_sink_arena_mem_ = DN_MemListFromMemFuncs(err_sink_reserve, err_sink_commit, DN_MemFlags_AllocCanLeak | DN_MemFlags_NoAllocTrack, mem_funcs); + tc->main_arena_ = DN_ArenaFromMemList(&tc->main_arena_mem_); + tc->temp_a_arena_ = DN_ArenaFromMemList(&tc->temp_a_arena_mem_); + tc->temp_b_arena_ = DN_ArenaFromMemList(&tc->temp_b_arena_mem_); + tc->err_sink_arena_ = DN_ArenaFromMemList(&tc->err_sink_arena_mem_); DN_TCInit(tc, thread_id, &tc->main_arena_, &tc->temp_a_arena_, &tc->temp_b_arena_, &tc->err_sink_arena_); } -DN_API void DN_TCDeinit(DN_TCCore *tc) +DN_API void DN_TCDeinit(DN_TCCore *tc, DN_TCDeinitArenas deinit_arenas) { - DN_ArenaDeinit(tc->main_arena); - DN_ArenaDeinit(tc->temp_a_arena); - DN_ArenaDeinit(tc->temp_b_arena); - DN_ArenaDeinit(tc->err_sink.arena); + if (deinit_arenas == DN_TCDeinitArenas_Yes) { + DN_MemListDeinit(tc->main_arena->mem); + DN_MemListDeinit(tc->temp_a_arena->mem); + DN_MemListDeinit(tc->temp_b_arena->mem); + DN_MemListDeinit(tc->err_sink.arena->mem); + } } DN_API void DN_TCEquip(DN_TCCore *tc) @@ -1617,25 +1838,37 @@ DN_API DN_Arena *DN_TCMainArena() return result; } -DN_API DN_Arena *DN_TCTempArena(DN_Arena **conflicts, DN_USize count) +DN_API DN_Pool *DN_TCMainPool() { - DN_TCCore *tc = DN_TCGet(); - DN_Arena *candidates[] = {tc->temp_a_arena, tc->temp_b_arena}; - DN_Arena *result = nullptr; - for (DN_ForItCArray(it, DN_Arena *, candidates)) { - bool is_usable = false; + DN_TCCore *tc = DN_TCGet(); + DN_Pool *result = &tc->main_pool; + return result; +} + +DN_API DN_Arena DN_TCTempArena(DN_Arena **conflicts, DN_USize count) +{ + DN_TCCore *tc = DN_TCGet(); + DN_MemList *candidates[] = {tc->temp_a_arena->mem, tc->temp_b_arena->mem}; + DN_Arena result = {}; + for (DN_ForItCArray(it, DN_MemList *, candidates)) { + bool is_usable = true; + DN_MemList *rhs_mem = *it.data; for (DN_ForItSize(conflict_it, DN_Arena *, conflicts, count)) { - if (*conflict_it.data == *it.data) - continue; - is_usable = true; - break; + DN_Arena *lhs_arena = *conflict_it.data; + DN_MemList *lhs_mem = lhs_arena->mem; + if (lhs_mem == rhs_mem) { + is_usable = false; + break; + } } - if (count == 0 || is_usable) { - result = *it.data; + if (is_usable) { + result = DN_ArenaTempBeginFromMemList(rhs_mem); break; } } + + DN_AssertF(result.mem, "All temp arenas are being used, there are none left to return to the caller"); return result; } @@ -1655,17 +1888,15 @@ DN_API DN_TCScratch DN_TCScratchBegin(DN_Arena **conflicts, DN_USize count) { DN_TCScratch result = {}; result.arena = DN_TCTempArena(conflicts, count); - result.temp_mem = DN_ArenaTempMemBegin(result.arena); return result; } DN_API void DN_TCScratchEnd(DN_TCScratch *scratch) { DN_Assert(scratch->destructed == false); - DN_ArenaTempMemEnd(scratch->temp_mem); + DN_ArenaTempEnd(&scratch->arena, DN_ArenaReset_Yes); + *scratch = {}; scratch->destructed = true; - scratch->arena = nullptr; - scratch->temp_mem = {}; } DN_API void DN_TCSetFrameArena(DN_Arena *arena) @@ -1859,15 +2090,15 @@ DN_API DN_U64 DN_U64FromU8x32HiBEUnsafe(DN_U8x32 const *val) return result; } -DN_API DN_U64 DN_U64FromU8x32HiBE(DN_U8x32 const *val) +DN_API DN_U64FromResult DN_U64FromU8x32HiBE(DN_U8x32 const *val) { - DN_U64 result = {}; + DN_U64FromResult result = {}; if (val) { // NOTE: Check that the high bits are not set DN_U8x32 zero_mask = {}; bool high_bits_set = DN_Memcmp(val->data, zero_mask.data, sizeof(zero_mask.data) - sizeof(result)) != 0; - DN_Assert(!high_bits_set); - result = DN_U64FromU8x32HiBEUnsafe(val); + result.success = !high_bits_set; + result.value = DN_U64FromU8x32HiBEUnsafe(val); } return result; } @@ -1880,16 +2111,16 @@ DN_API DN_USize DN_USizeFromU8x32HiBEUnsafe(DN_U8x32 const *val) return result; } -DN_API DN_USize DN_USizeFromU8x32HiBE(DN_U8x32 const *val) +DN_API DN_USizeFromResult DN_USizeFromU8x32HiBE(DN_U8x32 const *val) { - DN_USize result = {}; + DN_USizeFromResult result = {}; if (val) { // NOTE: Check that the high bits are not set DN_U8x32 mask = {}; DN_Memset(mask.data, 1, sizeof(mask.data) - sizeof(result)); bool high_bits_set = DN_Memcmp(val->data, mask.data, 24) != 0; - DN_Assert(!high_bits_set); - result = DN_USizeFromU8x32HiBEUnsafe(val); + result.success = !high_bits_set; + result.value = DN_USizeFromU8x32HiBEUnsafe(val); } return result; } @@ -1969,6 +2200,72 @@ DN_API DN_I64 DN_I64FromPtrUnsafe(void const *data, DN_USize size, char separato return result; } +DN_API bool DN_U8x32Eq(DN_U8x32 const *lhs, DN_U8x32 const *rhs) +{ + bool result = DN_MemEqUnsafe(lhs->data, rhs->data, sizeof(lhs->data)); + return result; +} + +DN_API DN_U8x32 DN_U8x32FromBytesLeftPadZ(DN_U8 const *ptr, DN_USize count) +{ + DN_U8x32 result = {}; + DN_Assert(count <= sizeof(result.data)); + DN_Memcpy(result.data + sizeof(result.data) - count, ptr, count); + return result; +} + +DN_API DN_U8x32 DN_U8x32FromHexUnsafe(DN_Str8 hex_32b) +{ + DN_U8x32 result = {}; + hex_32b = DN_Str8TrimHexPrefix(hex_32b); + DN_Assert(hex_32b.size <= sizeof(result.data) * 2); + DN_BytesFromHexPtr(hex_32b.data, hex_32b.size, result.data, sizeof(result.data)); + return result; +} + +DN_API DN_U8x32FromResult DN_U8x32FromHex(DN_Str8 hex_32b) +{ + DN_U8x32FromResult result = {}; + DN_USize bytes_written = DN_BytesFromHexPtr(hex_32b.data, hex_32b.size, result.value.data, sizeof(result.value.data)); + if (bytes_written == sizeof(result.value.data)) + result.success = true; + return result; +} + +DN_API DN_U8x32FromResult DN_U8x32FromDecimalStr8(DN_Str8 decimal) +{ + DN_U8x32FromResult result = {}; + result.success = true; + for (DN_USize i = 0; i < decimal.size; i++) { + DN_U8 digit = decimal.data[i]; + if (!DN_CharIsDigit(digit)) { + result.success = false; + break; + } + + DN_U8 digit_val = digit - '0'; + + // NOTE: Goal is to do => (result = result * 10 + digit_val) + // Multiply current result by 10 + DN_U16 carry = 0; + for (int j = 31; j >= 0; j--) { + DN_U16 prod = DN_Cast(DN_U16)result.value.data[j] * 10 + carry; + result.value.data[j] = DN_Cast(DN_U8)(prod & 0xFF); + carry = prod >> 8; + } + + // Add the digit + carry = digit_val; + for (int j = 31; j >= 0 && carry > 0; j--) { + DN_U16 sum = DN_Cast(DN_U16)result.value.data[j] + carry; + result.value.data[j] = DN_Cast(DN_U8)(sum & 0xFF); + carry = sum >> 8; + } + } + + return result; +} + 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 = {}; @@ -2037,15 +2334,7 @@ DN_API DN_USize DN_CStr16Size(wchar_t const *src) return result; } -DN_API bool DN_Str16Eq(DN_Str16 lhs, DN_Str16 rhs) -{ - if (lhs.size != rhs.size) - return false; - bool result = (DN_Memcmp(lhs.data, rhs.data, lhs.size) == 0); - return result; -} - -DN_API DN_Str8 DN_Str8AllocArena(DN_Arena *arena, DN_USize size, DN_ZMem z_mem) +DN_API DN_Str8 DN_Str8AllocArena(DN_USize size, DN_ZMem z_mem, DN_Arena *arena) { DN_Str8 result = {}; result.data = DN_ArenaNewArray(arena, char, size + 1, z_mem); @@ -2055,7 +2344,7 @@ DN_API DN_Str8 DN_Str8AllocArena(DN_Arena *arena, DN_USize size, DN_ZMem z_mem) return result; } -DN_API DN_Str8 DN_Str8AllocPool(DN_Pool *pool, DN_USize size) +DN_API DN_Str8 DN_Str8AllocPool(DN_USize size, DN_Pool *pool) { DN_Str8 result = {}; result.data = DN_PoolNewArray(pool, char, size + 1); @@ -2072,23 +2361,30 @@ DN_API DN_Str8 DN_Str8FromCStr8(char const *src) return result; } -DN_API DN_Str8 DN_Str8FromPtrArena(DN_Arena *arena, void const *data, DN_USize size) +DN_API DN_Str8 DN_Str8FromCStr8Arena(char const *src, DN_Arena *arena) { - DN_Str8 result = DN_Str8AllocArena(arena, size, DN_ZMem_No); + DN_Str8 shallow = DN_Str8FromCStr8(src); + DN_Str8 result = DN_Str8FromStr8Arena(shallow, arena); + return result; +} + +DN_API DN_Str8 DN_Str8FromPtrArena(void const *data, DN_USize size, DN_Arena *arena) +{ + DN_Str8 result = DN_Str8AllocArena(size, DN_ZMem_No, arena); if (result.size) DN_Memcpy(result.data, data, size); return result; } -DN_API DN_Str8 DN_Str8FromPtrPool(DN_Pool *pool, void const *data, DN_USize size) +DN_API DN_Str8 DN_Str8FromPtrPool(void const *data, DN_USize size, DN_Pool *pool) { - DN_Str8 result = DN_Str8AllocPool(pool, size); + DN_Str8 result = DN_Str8AllocPool(size, pool); if (result.size) DN_Memcpy(result.data, data, size); return result; } -DN_API DN_Str8 DN_Str8FromStr8Arena(DN_Arena *arena, DN_Str8 string) +DN_API DN_Str8 DN_Str8FromStr8Arena(DN_Str8 string, DN_Arena *arena) { DN_Str8 result = {}; result.data = DN_Cast(char *) DN_ArenaAlloc(arena, string.size + 1, alignof(char), DN_ZMem_No); @@ -2100,7 +2396,7 @@ DN_API DN_Str8 DN_Str8FromStr8Arena(DN_Arena *arena, DN_Str8 string) return result; } -DN_API DN_Str8 DN_Str8FromStr8Pool(DN_Pool *pool, DN_Str8 string) +DN_API DN_Str8 DN_Str8FromStr8Pool(DN_Str8 string, DN_Pool *pool) { DN_Str8 result = {}; result.data = DN_Cast(char *) DN_PoolAlloc(pool, string.size + 1); @@ -2112,6 +2408,18 @@ DN_API DN_Str8 DN_Str8FromStr8Pool(DN_Pool *pool, DN_Str8 string) return result; } +DN_API DN_Str8 DN_Str8FromFmtVArena(DN_Arena *arena, DN_FMT_ATTRIB char const *fmt, va_list args) +{ + DN_USize size = DN_FmtVSize(fmt, args); + DN_Str8 result = DN_Str8AllocArena(size, DN_ZMem_No, arena); + if (result.data) { + DN_USize written = 0; + DN_FmtVAppend(result.data, &written, result.size + 1, fmt, args); + DN_Assert(written == result.size); + } + return result; +} + DN_API DN_Str8 DN_Str8FromFmtArena(DN_Arena *arena, DN_FMT_ATTRIB char const *fmt, ...) { va_list va; @@ -2121,10 +2429,10 @@ DN_API DN_Str8 DN_Str8FromFmtArena(DN_Arena *arena, DN_FMT_ATTRIB char const *fm return result; } -DN_API DN_Str8 DN_Str8FromFmtVArena(DN_Arena *arena, DN_FMT_ATTRIB char const *fmt, va_list args) +DN_API DN_Str8 DN_Str8FromFmtVPool(DN_Pool *pool, DN_FMT_ATTRIB char const *fmt, va_list args) { DN_USize size = DN_FmtVSize(fmt, args); - DN_Str8 result = DN_Str8AllocArena(arena, size, DN_ZMem_No); + DN_Str8 result = DN_Str8AllocPool(size, pool); if (result.data) { DN_USize written = 0; DN_FmtVAppend(result.data, &written, result.size + 1, fmt, args); @@ -2137,13 +2445,7 @@ DN_API DN_Str8 DN_Str8FromFmtPool(DN_Pool *pool, DN_FMT_ATTRIB char const *fmt, { va_list args; va_start(args, fmt); - DN_USize size = DN_FmtVSize(fmt, args); - DN_Str8 result = DN_Str8AllocPool(pool, size); - if (result.data) { - DN_USize written = 0; - DN_FmtVAppend(result.data, &written, result.size + 1, fmt, args); - DN_Assert(written == result.size); - } + DN_Str8 result = DN_Str8FromFmtVPool(pool, fmt, args); va_end(args); return result; } @@ -2158,7 +2460,7 @@ DN_API DN_Str8x16 DN_Str8x16FromFmt(DN_FMT_ATTRIB char const *fmt, ...) return result; } -DN_API DN_Str8x16 DN_Str8x16FromFmtV(DN_FMT_ATTRIB char const *fmt, va_list args) +DN_API DN_Str8x16 DN_Str8x16FromFmtVArena(DN_FMT_ATTRIB char const *fmt, va_list args) { DN_Str8x16 result = {}; DN_FmtVAppend(result.data, &result.size, sizeof(result.data), fmt, args); @@ -2175,7 +2477,7 @@ DN_API DN_Str8x32 DN_Str8x32FromFmt(DN_FMT_ATTRIB char const *fmt, ...) return result; } -DN_API DN_Str8x32 DN_Str8x32FromFmtV(DN_FMT_ATTRIB char const *fmt, va_list args) +DN_API DN_Str8x32 DN_Str8x32FromFmtVArena(DN_FMT_ATTRIB char const *fmt, va_list args) { DN_Str8x32 result = {}; DN_FmtVAppend(result.data, &result.size, sizeof(result.data), fmt, args); @@ -2209,7 +2511,7 @@ DN_API DN_Str8x128 DN_Str8x128FromFmt(DN_FMT_ATTRIB char const *fmt, ...) return result; } -DN_API DN_Str8x128 DN_Str8x128FromFmtV(DN_FMT_ATTRIB char const *fmt, va_list args) +DN_API DN_Str8x128 DN_Str8x128FromFmtVArena(DN_FMT_ATTRIB char const *fmt, va_list args) { DN_Str8x128 result = {}; DN_FmtVAppend(result.data, &result.size, sizeof(result.data), fmt, args); @@ -2226,7 +2528,7 @@ DN_API DN_Str8x256 DN_Str8x256FromFmt(DN_FMT_ATTRIB char const *fmt, ...) return result; } -DN_API DN_Str8x256 DN_Str8x256FromFmtV(DN_FMT_ATTRIB char const *fmt, va_list args) +DN_API DN_Str8x256 DN_Str8x256FromFmtVArena(DN_FMT_ATTRIB char const *fmt, va_list args) { DN_Str8x256 result = {}; DN_FmtVAppend(result.data, &result.size, sizeof(result.data), fmt, args); @@ -2243,7 +2545,7 @@ DN_API DN_Str8x512 DN_Str8x512FromFmt(DN_FMT_ATTRIB char const *fmt, ...) return result; } -DN_API DN_Str8x512 DN_Str8x512FromFmtV(DN_FMT_ATTRIB char const *fmt, va_list args) +DN_API DN_Str8x512 DN_Str8x512FromFmtVArena(DN_FMT_ATTRIB char const *fmt, va_list args) { DN_Str8x512 result = {}; DN_FmtVAppend(result.data, &result.size, sizeof(result.data), fmt, args); @@ -2260,7 +2562,7 @@ DN_API DN_Str8x1024 DN_Str8x1024FromFmt(DN_FMT_ATTRIB char const *fmt, ...) return result; } -DN_API DN_Str8x1024 DN_Str8x1024FromFmtV(DN_FMT_ATTRIB char const *fmt, va_list args) +DN_API DN_Str8x1024 DN_Str8x1024FromFmtVArena(DN_FMT_ATTRIB char const *fmt, va_list args) { DN_Str8x1024 result = {}; DN_FmtVAppend(result.data, &result.size, sizeof(result.data), fmt, args); @@ -2447,9 +2749,10 @@ DN_API DN_Str8BSplitResult DN_Str8BSplitArray(DN_Str8 string, DN_Str8 const *fin DN_Str8 find_item = find[find_index]; DN_Str8 string_slice = DN_Str8Subset(string, index, find_item.size); if (DN_Str8Eq(string_slice, find_item)) { - result.lhs.size = index; - result.rhs.data = string_slice.data + find_item.size; - result.rhs.size = string.size - (index + find_item.size); + result.input_index = find_index; + result.lhs.size = index; + result.rhs.data = string_slice.data + find_item.size; + result.rhs.size = string.size - (index + find_item.size); break; } } @@ -2493,28 +2796,39 @@ DN_API DN_Str8BSplitResult DN_Str8BSplitLast(DN_Str8 string, DN_Str8 find) return result; } -DN_API DN_USize DN_Str8Split(DN_Str8 string, DN_Str8 delimiter, DN_Str8 *splits, DN_USize splits_count, DN_Str8SplitIncludeEmptyStrings mode) +DN_API DN_USize DN_Str8Split(DN_Str8 string, DN_Str8 delimiter, DN_Str8 *splits, DN_USize splits_count, DN_Str8SplitFlags flags) { DN_USize result = 0; // The number of splits in the actual string. if (string.size == 0 || delimiter.size == 0 || delimiter.size <= 0) return result; - DN_Str8BSplitResult split = {}; - DN_Str8 first = string; + DN_Str8 it = string; + bool allow_empty_strings = DN_BitIsNotSet(flags, DN_Str8SplitFlags_ExcludeEmptyStrings); + bool handle_quotes = DN_BitIsSet(flags, DN_Str8SplitFlags_HandleQuotedStrings); do { - split = DN_Str8BSplit(first, delimiter); - if (split.lhs.size || mode == DN_Str8SplitIncludeEmptyStrings_Yes) { + DN_Str8 item = {}; + if (handle_quotes && DN_Str8StartsWith(it, DN_Str8Lit("\""))) { + DN_Str8FindResult find = DN_Str8FindStr8(DN_Str8Advance(it, 1), DN_Str8Lit("\""), DN_Str8EqCase_Sensitive); + DN_Assert(find.found); + item = find.start_to_before_match; + it = DN_Str8BSplit(find.after_match_to_end_of_buffer, DN_Str8Lit(",")).rhs; + } else { + DN_Str8BSplitResult sub_split = DN_Str8BSplit(it, DN_Str8Lit(",")); + item = sub_split.lhs; + it = sub_split.rhs; + } + + if (item.size || allow_empty_strings) { if (splits && result < splits_count) - splits[result] = split.lhs; + splits[result] = item; result++; } - first = split.rhs; - } while (first.size); + } while (it.size); return result; } -DN_API DN_Str8SplitResult DN_Str8SplitArena(DN_Arena *arena, DN_Str8 string, DN_Str8 delimiter, DN_Str8SplitIncludeEmptyStrings mode) +DN_API DN_Str8SplitResult DN_Str8SplitArena(DN_Arena *arena, DN_Str8 string, DN_Str8 delimiter, DN_Str8SplitFlags mode) { DN_Str8SplitResult result = {}; DN_USize count = DN_Str8Split(string, delimiter, /*splits*/ nullptr, /*count*/ 0, mode); @@ -2575,7 +2889,7 @@ 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) { if (!segment_size || src.size == 0) { - DN_Str8 result = DN_Str8FromStr8Arena(arena, src); + DN_Str8 result = DN_Str8FromStr8Arena(src, arena); return result; } @@ -2584,7 +2898,7 @@ DN_API DN_Str8 DN_Str8Segment(DN_Arena *arena, DN_Str8 src, DN_USize segment_siz segments--; DN_USize segment_counter = 0; - DN_Str8 result = DN_Str8AllocArena(arena, src.size + segments, DN_ZMem_Yes); + DN_Str8 result = DN_Str8AllocArena(src.size + segments, DN_ZMem_Yes, arena); DN_USize write_index = 0; for (DN_ForIndexU(src_index, src.size)) { result.data[write_index++] = src.data[src_index]; @@ -2602,7 +2916,7 @@ DN_API DN_Str8 DN_Str8Segment(DN_Arena *arena, DN_Str8 src, DN_USize segment_siz DN_API DN_Str8 DN_Str8ReverseSegment(DN_Arena *arena, DN_Str8 src, DN_USize segment_size, char segment_char) { if (!segment_size || src.size == 0) { - DN_Str8 result = DN_Str8FromStr8Arena(arena, src); + DN_Str8 result = DN_Str8FromStr8Arena(src, arena); return result; } @@ -2612,7 +2926,7 @@ DN_API DN_Str8 DN_Str8ReverseSegment(DN_Arena *arena, DN_Str8 src, DN_USize segm DN_USize write_counter = 0; DN_USize segment_counter = 0; - DN_Str8 result = DN_Str8AllocArena(arena, src.size + segments, DN_ZMem_Yes); + DN_Str8 result = DN_Str8AllocArena(src.size + segments, DN_ZMem_Yes, arena); DN_USize write_index = result.size - 1; DN_MSVC_WARNING_PUSH @@ -2827,7 +3141,7 @@ DN_API DN_Str8 DN_Str8AppendFV(DN_Arena *arena, DN_Str8 string, char const *fmt, { // TODO: Calculate size and write into one buffer instead of 2 appends DN_Str8 append = DN_Str8FromFmtVArena(arena, fmt, args); - DN_Str8 result = DN_Str8AllocArena(arena, string.size + append.size, DN_ZMem_No); + DN_Str8 result = DN_Str8AllocArena(string.size + append.size, DN_ZMem_No, arena); DN_Memcpy(result.data, string.data, string.size); DN_Memcpy(result.data + string.size, append.data, append.size); return result; @@ -2845,7 +3159,7 @@ 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_Str8 fill = DN_Str8FromFmtVArena(arena, fmt, args); - DN_Str8 result = DN_Str8AllocArena(arena, count * fill.size, DN_ZMem_No); + DN_Str8 result = DN_Str8AllocArena(count * fill.size, DN_ZMem_No, arena); for (DN_USize index = 0; index < count; index++) { void *dest = result.data + (index * fill.size); DN_Memcpy(dest, fill.data, fill.size); @@ -2866,35 +3180,64 @@ DN_API void DN_Str8Remove(DN_Str8 *string, DN_USize offset, DN_USize size) string->size -= bytes_to_move; } -DN_API DN_Str8TruncateResult DN_Str8TruncateMiddle(DN_Arena *arena, DN_Str8 str8, DN_U32 side_size, DN_Str8 truncator) +DN_API DN_Str8TruncResult DN_Str8TruncMiddlePtr(DN_Str8 str8, DN_USize side_size, DN_Str8 truncator, char *dest, DN_USize dest_max) { - DN_Str8TruncateResult result = {}; + DN_Assert(side_size <= DN_USIZE_MAX / 2); + if (dest) { + // NOTE: If the user passes the dest buffer, we expect it to be sized correctly. + if ((side_size * 2) >= str8.size) { + DN_Assert(dest_max >= str8.size + 1 /*null*/); + } else { + DN_Assert(dest_max >= (2 * side_size + truncator.size) + 1 /*null*/); + } + } + + DN_Str8TruncResult result = {}; if (str8.size <= (side_size * 2)) { - result.str8 = DN_Str8FromStr8Arena(arena, str8); + result.size_req = str8.size; + if (dest) { + DN_Memcpy(dest, str8.data, str8.size); + dest[str8.size] = 0; + result.str8 = DN_Str8FromPtr(dest, result.size_req); + } return result; } - DN_Str8 head = DN_Str8Subset(str8, 0, side_size); - DN_Str8 tail = DN_Str8Subset(str8, str8.size - side_size, side_size); - DN_MSVC_WARNING_PUSH - DN_MSVC_WARNING_DISABLE(6284) // Object passed as _Param_(3) when a string is required in call to 'DN_Str8FromFmtArena' Actual type: 'struct DN_Str8' - result.str8 = DN_Str8FromFmtArena(arena, "%S%S%S", head, truncator, tail); - DN_MSVC_WARNING_POP - result.truncated = true; + DN_Str8 head = DN_Str8Subset(str8, 0, side_size); + DN_Str8 tail = DN_Str8Subset(str8, str8.size - side_size, side_size); + DN_USize dest_size = 0; + if (dest) { + DN_FmtAppendResult append_result = DN_FmtAppend(dest, &dest_size, dest_max, "%.*s%.*s%.*s", DN_Str8PrintFmt(head), DN_Str8PrintFmt(truncator), DN_Str8PrintFmt(tail)); + result.str8 = append_result.str8; + result.truncated = true; + result.size_req = result.str8.size; + } else { + result.size_req = DN_FmtSize("%.*s%.*s%.*s", DN_Str8PrintFmt(head), DN_Str8PrintFmt(truncator), DN_Str8PrintFmt(tail)); + result.truncated = true; + } + return result; } -DN_API DN_Str8 DN_Str8Lower(DN_Arena *arena, DN_Str8 string) +DN_API DN_Str8TruncResult DN_Str8TruncMiddle(DN_Str8 str8, DN_USize side_size, DN_Str8 truncator, DN_Arena *arena) { - DN_Str8 result = DN_Str8FromStr8Arena(arena, string); + DN_Str8TruncResult trunc = DN_Str8TruncMiddlePtr(str8, side_size, truncator, nullptr, 0); + DN_Str8 dest = DN_Str8AllocArena(trunc.size_req, DN_ZMem_No, arena); + DN_Str8TruncResult result = DN_Str8TruncMiddlePtr(str8, side_size, truncator, dest.data, dest.size + 1); + return result; +} + +DN_API DN_Str8 DN_Str8Lower(DN_Str8 string, DN_Arena *arena) +{ + DN_Str8 result = DN_Str8FromStr8Arena(string, arena); for (DN_ForIndexU(index, result.size)) result.data[index] = DN_CharToLower(result.data[index]); return result; } -DN_API DN_Str8 DN_Str8Upper(DN_Arena *arena, DN_Str8 string) +DN_API DN_Str8 DN_Str8Upper(DN_Str8 string, DN_Arena *arena) { - DN_Str8 result = DN_Str8FromStr8Arena(arena, string); + DN_Str8 result = DN_Str8FromStr8Arena(string, arena); for (DN_ForIndexU(index, result.size)) result.data[index] = DN_CharToUpper(result.data[index]); return result; @@ -2907,15 +3250,14 @@ DN_API DN_Str8 DN_Str8Replace(DN_Str8 string, DN_Arena *arena, DN_Str8EqCase eq_case) { - // TODO: Implement this without requiring TLS so it can go into base strings DN_Str8 result = {}; if (string.size == 0 || find.size == 0 || find.size > string.size || find.size == 0 || string.size == 0) { - result = DN_Str8FromStr8Arena(arena, string); + result = DN_Str8FromStr8Arena(string, arena); return result; } DN_TCScratch scratch = DN_TCScratchBegin(&arena, 1); - DN_Str8Builder string_builder = DN_Str8BuilderFromArena(scratch.arena); + DN_Str8Builder string_builder = DN_Str8BuilderFromArena(&scratch.arena); DN_USize max = string.size - find.size; DN_USize head = start_index; @@ -2942,7 +3284,7 @@ DN_API DN_Str8 DN_Str8Replace(DN_Str8 string, if (string_builder.string_size == 0) { // NOTE: No replacement possible, so we just do a full-copy - result = DN_Str8FromStr8Arena(arena, string); + result = DN_Str8FromStr8Arena(string, arena); } else { DN_Str8 remainder = DN_Str8FromPtr(string.data + head, string.size - head); DN_Str8BuilderAppendRef(&string_builder, remainder); @@ -2964,6 +3306,187 @@ DN_API DN_Str8 DN_Str8ReplaceInsensitive(DN_Str8 string, DN_Str8 find, DN_Str8 r return result; } +DN_API DN_Str8 DN_Str8PadNewLines(DN_Str8 string, DN_Str8 pad_string, DN_Arena *arena) +{ + DN_TCScratch scratch = DN_TCScratchBegin(&arena, 1); + DN_Str8Builder builder = DN_Str8BuilderFromArena(&scratch.arena); + DN_Str8 it = string; + while (it.size) { + DN_Str8BSplitResult split = DN_Str8BSplit(it, DN_Str8Lit("\n")); + DN_Str8BuilderAppendRef(&builder, DN_Str8FromPtr(split.lhs.data, split.lhs.size + 1)); + it = split.rhs; + } + + DN_Str8 result = DN_Str8BuilderBuildDelimited(&builder, pad_string, arena); + DN_TCScratchEnd(&scratch); + return result; +} + +DN_API DN_USize DN_USizeCodepointCountFromUTF8(DN_Str8 str, DN_CodepointCountFlags flags) +{ + DN_USize result = 0; + + if (DN_BitIsNotSet(flags, DN_CodepointCountFlags_SkipANSICode)) { + DN_UTF8DecodeIterator it = {}; + while (DN_UTF8DecodeIterate(&it, str)) + ; + result = it.codepoint_index; + } else { + // NOTE: ANSI SGR (Select Graphic Rendition) sequence handling + // Format: ESC [ parameter_bytes intermediate_bytes final_byte + // Common examples: \x1b[31m (red), \x1b[1;31m (bold red), \x1b[0m (reset) + // Parameter bytes: 0x30-0x3F (digits and :;<=>?) + // Intermediate bytes: 0x20-0x2F (space and !"#$%&'()*+,-./) + // Final byte: 0x40-0x7E (@A-Z[\]^_`a-z{|}~) + char const *p = str.data; + char const *end = DN_Str8End(str); + while (p < end) { + if (*p == '\x1b' && p + 1 < end && *(p + 1) == '[') { // Detect CSI sequence: ESC [ + p += 2; + while (p < end && *p >= 0x30 && *p <= 0x3F) // Skip parameter bytes (0x30-0x3F) + p++; + while (p < end && *p >= 0x20 && *p <= 0x2F) // Skip intermediate bytes (0x20-0x2F) + p++; + if (p < end && *p >= 0x40 && *p <= 0x7E) // Skip final byte (0x40-0x7E) + p++; + continue; + } + + DN_UTF8DecodeResult decode = DN_UTF8Decode(DN_Str8FromPtr(p, end - p)); + if (!decode.success) + break; + p = decode.remaining.data; + result++; + } + } + + return result; +} + +DN_API DN_Str8 DN_Str8LineBreakStr8(DN_Str8 src, DN_USize desired_width, DN_Arena *arena) +{ + DN_TCScratch scratch = DN_TCScratchBegin(&arena, 1); + DN_Str8Builder builder = DN_Str8BuilderFromArena(&scratch.arena); + + char* start = src.data; + char* end = src.data; + DN_Str8 it = src; + while (it.size) { + DN_Str8 splitters[] = {DN_Str8Lit(" "), DN_Str8Lit("\n")}; + DN_Str8BSplitResult split = DN_Str8BSplitArray(it, splitters, DN_ArrayCountU(splitters)); + DN_USize curr_line_length = end - start; + + // Handle explicit newlines in input + if (split.input_index == 1 /*the newline*/) { + if (curr_line_length == 0 && split.lhs.size) + start = split.lhs.data; + if (split.lhs.size) + end = DN_Str8End(split.lhs); + DN_Str8BuilderAppendRef(&builder, DN_Str8FromPtr(start, end - start)); + start = split.rhs.data; + end = split.rhs.data; + it = split.rhs; + continue; + } + + // Skip empty segments (multiple spaces, leading/trailing spaces) + if (split.lhs.size == 0) { + it = split.rhs; + continue; + } + + // First word on this line + if (curr_line_length == 0) { + start = split.lhs.data; + end = DN_Str8End(split.lhs); + it = split.rhs; + continue; + } + + // Check if adding this word (plus separator space) would overflow + DN_USize combined_length = curr_line_length + 1 + split.lhs.size; + if (combined_length > desired_width) { + // Commit current line, start new line with current word + DN_Str8BuilderAppendRef(&builder, DN_Str8FromPtr(start, end - start)); + start = split.lhs.data; + end = DN_Str8End(split.lhs); + it = split.rhs; + } else { + // Add word to current line + end = DN_Str8End(split.lhs); + it = split.rhs; + } + } + + // Append final line + if (end > start) + DN_Str8BuilderAppendRef(&builder, DN_Str8FromPtr(start, end - start)); + + DN_Str8 result = DN_Str8BuilderBuildDelimited(&builder, DN_Str8Lit("\n"), arena); + DN_TCScratchEnd(&scratch); + return result; +} + +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_TCScratch scratch = DN_TCScratchBegin(&arena, 1); + DN_U16 col_widths[128] = {}; + for (DN_USize i = 0; i < num_cols; i++) { + for (DN_USize j = 0; j < num_rows; j++) { + DN_USize index = j * num_cols + i; + col_widths[i] = DN_Max(col_widths[i], (DN_U16)DN_USizeCodepointCountFromUTF8(rows[index], DN_CodepointCountFlags_SkipANSICode)); + } + } + + DN_Str8Builder builder = DN_Str8BuilderFromArena(&scratch.arena); + DN_Str8BuilderAppendF(&builder, "+"); + for (DN_USize i = 0; i < num_cols; i++) { + for (DN_USize j = 0; j < col_widths[i] + 2; j++) + DN_Str8BuilderAppendF(&builder, "-"); + DN_Str8BuilderAppendF(&builder, "+"); + } + DN_Str8BuilderAppendF(&builder, "\n"); + + for (DN_USize i = 0; i < num_rows; i++) { + DN_Str8BuilderAppendF(&builder, "|"); + for (DN_USize j = 0; j < num_cols; j++) { + DN_USize index = (i * num_cols) + j; + DN_Str8 item = rows[index]; + DN_Str8BuilderAppendF(&builder, " %.*s", DN_Str8PrintFmt(item)); + DN_USize item_width = DN_USizeCodepointCountFromUTF8(item, DN_CodepointCountFlags_SkipANSICode); + for (DN_USize k = 0; k < col_widths[j] - item_width; k++) + DN_Str8BuilderAppendF(&builder, " "); + DN_Str8BuilderAppendF(&builder, " |"); + } + DN_Str8BuilderAppendF(&builder, "\n"); + + bool print_row_line = i == 0 && DN_BitIsSet(flags, DN_Str8TableFlags_HasHeader); + if (!print_row_line) + print_row_line = DN_BitIsSet(flags, DN_Str8TableFlags_RowLines); + + if (print_row_line) { + DN_Str8BuilderAppendF(&builder, "+"); + for (DN_USize sub_i = 0; sub_i < num_cols; sub_i++) { + for (DN_USize sub_j = 0; sub_j < col_widths[sub_i] + 2; sub_j++) + DN_Str8BuilderAppendF(&builder, "-"); + DN_Str8BuilderAppendF(&builder, "+"); + } + DN_Str8BuilderAppendF(&builder, "\n"); + } + } + + DN_Str8BuilderAppendF(&builder, "+"); + for (DN_USize i = 0; i < num_cols; i++) { + for (DN_USize j = 0; j < col_widths[i] + 2; j++) + DN_Str8BuilderAppendF(&builder, "-"); + DN_Str8BuilderAppendF(&builder, "+"); + } + + DN_Str8 result = DN_Str8BuilderBuild(&builder, arena); + DN_TCScratchEnd(&scratch); + return result; +} + DN_API DN_Str8 DN_Str8SliceRender(DN_Str8Slice slice, DN_Str8 separator, DN_Arena *arena) { DN_Str8 result = {}; @@ -2978,7 +3501,7 @@ DN_API DN_Str8 DN_Str8SliceRender(DN_Str8Slice slice, DN_Str8 separator, DN_Aren total_size += item.size; } - result = DN_Str8AllocArena(arena, total_size, DN_ZMem_No); + result = DN_Str8AllocArena(total_size, DN_ZMem_No, arena); if (result.data) { DN_USize write_index = 0; for (DN_USize index = 0; index < slice.count; index++) { @@ -3001,6 +3524,15 @@ DN_API DN_Str8 DN_Str8RenderSpaceSep(DN_Str8Slice slice, DN_Arena *arena) return result; } +DN_API bool DN_Str16Eq(DN_Str16 lhs, DN_Str16 rhs) +{ + if (lhs.size != rhs.size) + return false; + bool result = (DN_Memcmp(lhs.data, rhs.data, lhs.size) == 0); + return result; +} + + DN_API DN_Str16 DN_Str16SliceRender(DN_Str16Slice slice, DN_Str16 separator, DN_Arena *arena) { DN_Str16 result = {}; @@ -3075,7 +3607,8 @@ DN_API bool DN_Str8BuilderAddArrayRef(DN_Str8Builder *builder, DN_Str8 const *st if (!strings || size <= 0) return true; - DN_Str8Link *links = DN_ArenaNewArray(builder->arena, DN_Str8Link, size, DN_ZMem_No); + // NOTE: Allocate the links + DN_Str8Link *links = DN_ArenaNewArrayNoZ(builder->arena, DN_Str8Link, size); if (!links) return false; @@ -3083,15 +3616,12 @@ DN_API bool DN_Str8BuilderAddArrayRef(DN_Str8Builder *builder, DN_Str8 const *st for (DN_ForIndexU(index, size)) { DN_Str8 string = strings[index]; DN_Str8Link *link = links + index; - link->string = string; link->next = NULL; - if (builder->head) builder->tail->next = link; else builder->head = link; - builder->tail = link; builder->count++; builder->string_size += string.size; @@ -3124,11 +3654,11 @@ DN_API bool DN_Str8BuilderAddArrayCopy(DN_Str8Builder *builder, DN_Str8 const *s if (!strings || size <= 0) return true; - DN_ArenaTempMem tmp_mem = DN_ArenaTempMemBegin(builder->arena); - bool result = true; - DN_Str8 *strings_copy = DN_ArenaNewArray(builder->arena, DN_Str8, size, DN_ZMem_No); + bool result = true; + DN_U64 arena_p = DN_MemListPos(builder->arena->mem); + DN_Str8 *strings_copy = DN_ArenaNewArrayNoZ(builder->arena, DN_Str8, size); for (DN_ForIndexU(index, size)) { - strings_copy[index] = DN_Str8FromStr8Arena(builder->arena, strings[index]); + strings_copy[index] = DN_Str8FromStr8Arena(strings[index], builder->arena); if (strings_copy[index].size != strings[index].size) { result = false; break; @@ -3137,20 +3667,18 @@ DN_API bool DN_Str8BuilderAddArrayCopy(DN_Str8Builder *builder, DN_Str8 const *s if (result) result = DN_Str8BuilderAddArrayRef(builder, strings_copy, size, add); - - if (!result) - DN_ArenaTempMemEnd(tmp_mem); - + else + DN_MemListPopTo(builder->arena->mem, arena_p); return result; } DN_API bool DN_Str8BuilderAddFV(DN_Str8Builder *builder, DN_Str8BuilderAdd add, DN_FMT_ATTRIB char const *fmt, va_list args) { - DN_Str8 string = DN_Str8FromFmtVArena(builder->arena, fmt, args); - DN_ArenaTempMem temp_mem = DN_ArenaTempMemBegin(builder->arena); - bool result = DN_Str8BuilderAddArrayRef(builder, &string, 1, add); + DN_Str8 string = DN_Str8FromFmtVArena(builder->arena, fmt, args); + DN_U64 arena_p = DN_MemListPos(builder->arena->mem); + bool result = DN_Str8BuilderAddArrayRef(builder, &string, 1, add); if (!result) - DN_ArenaTempMemEnd(temp_mem); + DN_MemListPopTo(builder->arena->mem, arena_p); return result; } @@ -3193,48 +3721,48 @@ static bool DN_Str8BuilderAppendBuilder_(DN_Str8Builder *dest, DN_Str8Builder co { if (!dest) return false; - if (!src) + if (!src || src->string_size == 0) return true; - DN_ArenaTempMemBegin(dest->arena); - DN_Str8Link *links = DN_ArenaNewArray(dest->arena, DN_Str8Link, src->count, DN_ZMem_No); - if (!links) - return false; + DN_Arena arena = DN_ArenaTempBeginFromArena(dest->arena); + DN_Str8Link *links = DN_ArenaNewArrayNoZ(&arena, DN_Str8Link, src->count); + bool result = true; + if (links) { + DN_Str8Link *first = nullptr; + DN_Str8Link *last = nullptr; + DN_USize link_index = 0; + for (DN_Str8Link const *it = src->head; it; it = it->next) { + DN_Str8Link *link = links + link_index++; + link->next = nullptr; + link->string = it->string; - DN_Str8Link *first = nullptr; - DN_Str8Link *last = nullptr; - DN_USize link_index = 0; - bool result = true; - for (DN_Str8Link const *it = src->head; it; it = it->next) { - DN_Str8Link *link = links + link_index++; - link->next = nullptr; - link->string = it->string; - - if (copy) { - link->string = DN_Str8FromStr8Arena(dest->arena, it->string); - if (link->string.size != it->string.size) { - result = false; - break; + if (copy) { + link->string = DN_Str8FromStr8Arena(it->string, &arena); + if (link->string.size != it->string.size) { + result = false; + break; + } } + + if (last) + last->next = link; + else + first = link; + last = link; } - if (last) - last->next = link; - else - first = link; - last = link; + if (result) { + if (dest->head) + dest->tail->next = first; + else + dest->head = first; + dest->tail = last; + dest->count += src->count; + dest->string_size += src->string_size; + } } - - if (result) { - if (dest->head) - dest->tail->next = first; - else - dest->head = first; - dest->tail = last; - dest->count += src->count; - dest->string_size += src->string_size; - } - return true; + DN_ArenaTempEnd(&arena, result ? DN_ArenaReset_No : DN_ArenaReset_Yes); + return result; } DN_API bool DN_Str8BuilderAppendBuilderRef(DN_Str8Builder *dest, DN_Str8Builder const *src) @@ -3297,9 +3825,9 @@ DN_API DN_Str8 DN_Str8BuilderBuildDelimited(DN_Str8Builder const *builder, DN_St DN_USize size_for_delimiter = delimiter.size ? ((builder->count - 1) * delimiter.size) : 0; result.data = DN_ArenaNewArray(arena, - char, - builder->string_size + size_for_delimiter + 1 /*null terminator*/, - DN_ZMem_No); + char, + builder->string_size + size_for_delimiter + 1 /*null terminator*/, + DN_ZMem_No); if (!result.data) return result; @@ -3317,23 +3845,6 @@ DN_API DN_Str8 DN_Str8BuilderBuildDelimited(DN_Str8Builder const *builder, DN_St return result; } -DN_API DN_Str8Slice DN_Str8BuilderBuildSlice(DN_Str8Builder const *builder, DN_Arena *arena) -{ - DN_Str8Slice result = {}; - if (!builder || builder->string_size <= 0 || builder->count <= 0) - return result; - - if (!DN_ISliceAllocArena(DN_Str8, &result, builder->count, DN_ZMem_No, arena)) - return result; - - DN_USize slice_index = 0; - for (DN_Str8Link *link = builder->head; link; link = link->next) - result.data[slice_index++] = DN_Str8FromStr8Arena(arena, link->string); - - DN_Assert(slice_index == builder->count); - return result; -} - // NOTE: DN_UTF DN_API int DN_UTF8Encode(DN_U8 utf8[4], DN_U32 codepoint) { @@ -3559,6 +4070,18 @@ DN_API DN_Str8 DN_BytesFromHexPtrArena(char const *hex, DN_USize hex_count, DN_A return result; } +DN_API DN_Str8 DN_BytesFromHexPtrPool(char const *hex, DN_USize hex_count, DN_Pool *pool) +{ + DN_Str8 hex_trimmed = DN_Str8TrimHexPrefix(DN_Str8FromPtr(hex, hex_count)); + DN_Assert(hex_trimmed.size % 2 == 0); + DN_Str8 result = {}; + result.data = DN_PoolNewArray(pool, char, hex_trimmed.size / 2); + if (result.data) + result.size = DN_BytesFromHex(hex_trimmed, result.data, hex_trimmed.size / 2); + return result; +} + + DN_API DN_U8x16 DN_BytesFromHex32Ptr(char const *hex, DN_USize hex_count) { DN_U8x16 result = {}; @@ -3582,7 +4105,7 @@ DN_API DN_U8x32 DN_BytesFromHex64Ptr(char const *hex, DN_USize hex_count) DN_API DN_HexU64Str8 DN_HexFromU64(DN_U64 value, DN_HexFromU64Type type) { DN_HexU64Str8 result = {}; - DN_HexFromBytesPtr(&value, sizeof(value), result.data, sizeof(result.data)); + DN_HexFromPtrBytes(&value, sizeof(value), result.data, sizeof(result.data), DN_TrimLeadingZero_No); if (type == DN_HexFromU64Type_Uppercase) { for (DN_USize index = 0; index < result.size; index++) result.data[index] = DN_CharToUpper(result.data[index]); @@ -3590,55 +4113,78 @@ DN_API DN_HexU64Str8 DN_HexFromU64(DN_U64 value, DN_HexFromU64Type type) return result; } -DN_API DN_USize DN_HexFromBytesPtr(void const *bytes, DN_USize bytes_count, void *hex, DN_USize hex_count) +DN_API DN_USize DN_HexFromPtrBytes(void const *bytes, DN_USize bytes_count, void *hex, DN_USize hex_count, DN_TrimLeadingZero trim_leading_z) { DN_USize result = 0; - if ((bytes_count * 2) != hex_count) + if ((bytes_count * 2) > hex_count) return result; - DN_U8 const *src_u8 = DN_Cast(DN_U8 const *)bytes; - DN_U8 *ptr = DN_Cast(DN_U8 *)hex; + DN_U8 const *src_u8 = DN_Cast(DN_U8 const *) bytes; + DN_U8 *ptr = DN_Cast(DN_U8 *) hex; + bool leading_zeros = true; for (DN_USize index = 0; index < bytes_count; index++) { - DN_NibbleFromU8Result to_nibbles = DN_NibbleFromU8(src_u8[index]); - *ptr++ = to_nibbles.nibble0; - *ptr++ = to_nibbles.nibble1; - result += 2; + char ch = src_u8[index]; + if (leading_zeros) + leading_zeros = ch == 0; + + if (leading_zeros) { + if (trim_leading_z == DN_TrimLeadingZero_Yes && ch == 0) + continue; + } + + DN_NibbleFromU8Result to_nibbles = DN_NibbleFromU8(ch); + *ptr++ = to_nibbles.nibble0; + *ptr++ = to_nibbles.nibble1; + result += 2; + } + + if (result == 0) { + *ptr = '0'; + result++; } return result; } -DN_API DN_Str8 DN_HexFromBytesPtrArena(void const *bytes, DN_USize bytes_count, DN_Arena *arena) +DN_API DN_Str8 DN_HexFromPtrBytesArena(void const *bytes, DN_USize bytes_count, DN_Arena *arena, DN_TrimLeadingZero trim_leading_z) { DN_Str8 result = {}; - result.data = DN_ArenaNewArray(arena, char, bytes_count * 2, DN_ZMem_No); - if (result.data) - result.size = DN_HexFromBytesPtr(bytes, bytes_count, result.data, bytes_count * 2); + if (bytes_count) { + result.data = DN_ArenaNewArray(arena, char, bytes_count * 2, DN_ZMem_No); + if (result.data) + result.size = DN_HexFromPtrBytes(bytes, bytes_count, result.data, bytes_count * 2, trim_leading_z); + } return result; } -DN_API DN_Hex32 DN_HexFromBytes16Ptr(void const *bytes, DN_USize bytes_count) +DN_API DN_USize DN_HexFromStr8Bytes(DN_Str8 bytes, void *hex, DN_USize hex_count, DN_TrimLeadingZero trim_leading_z) +{ + DN_USize result = DN_HexFromPtrBytes(bytes.data, bytes.size, hex, hex_count, trim_leading_z); + return result; +} + +DN_API DN_Hex32 DN_Hex32FromPtr16b(void const *bytes, DN_USize bytes_count, DN_TrimLeadingZero trim_leading_z) { DN_Hex32 result = {}; - DN_Assert(bytes_count * 2 == sizeof result.data); - DN_USize hex_written = DN_HexFromBytesPtr(bytes, bytes_count, result.data, sizeof result.data); - DN_Assert(hex_written == sizeof result.data); + DN_Assert(bytes_count * 2 == sizeof result.data - 1); + result.size = DN_HexFromPtrBytes(bytes, bytes_count, result.data, sizeof result.data, trim_leading_z); + DN_Assert(result.size <= sizeof result.data - 1); return result; } -DN_API DN_Hex64 DN_HexFromBytes32Ptr(void const *bytes, DN_USize bytes_count) +DN_API DN_Hex64 DN_Hex64FromPtr32b(void const *bytes, DN_USize bytes_count, DN_TrimLeadingZero trim_leading_z) { DN_Hex64 result = {}; - DN_Assert(bytes_count * 2 == sizeof result.data); - DN_USize hex_written = DN_HexFromBytesPtr(bytes, bytes_count, result.data, sizeof result.data); - DN_Assert(hex_written == sizeof result.data); + DN_Assert(bytes_count * 2 == sizeof result.data - 1); + result.size = DN_HexFromPtrBytes(bytes, bytes_count, result.data, sizeof result.data, trim_leading_z); + DN_Assert(result.size <= sizeof result.data - 1); return result; } -DN_API DN_Hex128 DN_HexFromBytes64Ptr(void const *bytes, DN_USize bytes_count) +DN_API DN_Hex128 DN_Hex128FromPtr64b(void const *bytes, DN_USize bytes_count, DN_TrimLeadingZero trim_leading_z) { DN_Hex128 result = {}; - DN_Assert(bytes_count * 2 == sizeof result.data); - DN_USize hex_written = DN_HexFromBytesPtr(bytes, bytes_count, result.data, sizeof result.data); - DN_Assert(hex_written == sizeof result.data); + DN_Assert(bytes_count * 2 == sizeof result.data - 1); + result.size = DN_HexFromPtrBytes(bytes, bytes_count, result.data, sizeof result.data, trim_leading_z); + DN_Assert(result.size <= sizeof result.data - 1); return result; } @@ -4357,28 +4903,68 @@ DN_API DN_U32 DN_MurmurHash3HashU32FromBytesX64(void const *bytes, int len, DN_U return result; } -DN_API DN_Str8 DN_LogColourEscapeCodeStr8FromRGB(DN_LogColourType colour, DN_U8 r, DN_U8 g, DN_U8 b) +DN_API DN_Str8x32 DN_Str8x32FromANSIColourCodeU8RGB(DN_ANSIColourMode mode, DN_U8 r, DN_U8 g, DN_U8 b) { - DN_THREAD_LOCAL char buffer[32]; - buffer[0] = 0; - DN_Str8 result = {}; - result.size = DN_SNPrintF(buffer, - DN_ArrayCountU(buffer), - "\x1b[%d;2;%u;%u;%um", - colour == DN_LogColourType_Fg ? 38 : 48, - r, - g, - b); - result.data = buffer; + DN_Str8x32 result = DN_Str8x32FromFmt("\x1b[%d;2;%u;%u;%um", + mode == DN_ANSIColourMode_Fg ? 38 : 48, + r, + g, + b); return result; } -DN_API DN_Str8 DN_LogColourEscapeCodeStr8FromU32(DN_LogColourType colour, DN_U32 value) +DN_API DN_Str8x32 DN_Str8x32FromANSIColourCodeV3F32RGB255(DN_ANSIColourMode mode, DN_V3F32 rgb_255) { - DN_U8 r = DN_Cast(DN_U8)(value >> 24); - DN_U8 g = DN_Cast(DN_U8)(value >> 16); - DN_U8 b = DN_Cast(DN_U8)(value >> 8); - DN_Str8 result = DN_LogColourEscapeCodeStr8FromRGB(colour, r, g, b); + DN_Str8x32 result = DN_Str8x32FromANSIColourCodeU8RGB(mode, DN_Cast(DN_U8)rgb_255.r, DN_Cast(DN_U8)rgb_255.g, DN_Cast(DN_U8)rgb_255.b); + return result; +} + +DN_API DN_Str8x32 DN_Str8x32FromANSIColourCodeU32RGB(DN_ANSIColourMode mode, DN_U32 value) +{ + DN_U8 r = DN_Cast(DN_U8)(value >> 24); + DN_U8 g = DN_Cast(DN_U8)(value >> 16); + DN_U8 b = DN_Cast(DN_U8)(value >> 8); + DN_Str8x32 result = DN_Str8x32FromANSIColourCodeU8RGB(mode, r, g, b); + return result; +} + +DN_API DN_Str8 DN_Str8FromStr8ANSIColourU8RGBArena(DN_ANSIColourMode mode, DN_Str8 str8, DN_U8 r, DN_U8 g, DN_U8 b, DN_Arena *arena) +{ + DN_Str8x32 ansi = DN_Str8x32FromANSIColourCodeU8RGB(mode, r, g, b); + DN_Str8 result = DN_Str8FromFmtArena(arena, "%.*s%.*s%s", DN_Str8PrintFmt(ansi), DN_Str8PrintFmt(str8), DN_ANSICodeResetLit); + return result; +} + +DN_API DN_Str8 DN_Str8FromStr8ANSIColourV3F32RGB255Arena(DN_ANSIColourMode mode, DN_Str8 str8, DN_V3F32 rgb_255, DN_Arena *arena) +{ + DN_Str8 result = DN_Str8FromStr8ANSIColourU8RGBArena(mode, str8, DN_Cast(DN_U8)rgb_255.r, DN_Cast(DN_U8)rgb_255.g, DN_Cast(DN_U8)rgb_255.b, arena); + return result; +} + +DN_API DN_Str8 DN_Str8ANSIColourU8RGBFromFmtVArena(DN_ANSIColourMode mode, DN_U8 r, DN_U8 g, DN_U8 b, DN_Arena *arena, char const *fmt, va_list args) +{ + DN_TCScratch scratch = DN_TCScratchBegin(&arena, 1); + DN_Str8 string = DN_Str8FromFmtVArena(&scratch.arena, fmt, args); + DN_Str8 result = DN_Str8FromStr8ANSIColourU8RGBArena(mode, string, r, g, b, arena); + DN_TCScratchEnd(&scratch); + return result; +} + +DN_API DN_Str8 DN_Str8FromFmtANSIColourU8RGBArena(DN_ANSIColourMode mode, DN_U8 r, DN_U8 g, DN_U8 b, DN_Arena *arena, char const *fmt, ...) +{ + va_list args; + va_start(args, fmt); + DN_Str8 result = DN_Str8ANSIColourU8RGBFromFmtVArena(mode, r, g, b, arena, fmt, args); + va_end(args); + return result; +} + +DN_API DN_Str8 DN_Str8FromFmtANSIColourV3F32RGB255Arena(DN_ANSIColourMode mode, DN_V3F32 rgb_255, DN_Arena *arena, char const *fmt, ...) +{ + va_list args; + va_start(args, fmt); + DN_Str8 result = DN_Str8ANSIColourU8RGBFromFmtVArena(mode, DN_Cast(DN_U8)rgb_255.r, DN_Cast(DN_U8)rgb_255.g, DN_Cast(DN_U8)rgb_255.b, arena, fmt, args); + va_end(args); return result; } @@ -4399,30 +4985,25 @@ DN_API DN_LogPrefixSize DN_LogMakePrefix(DN_LogStyle style, DN_LogTypeParam type max_type_length = DN_Max(max_type_length, type_str8.size); int type_padding = DN_Cast(int)(max_type_length - type_str8.size); - DN_Str8 colour_esc = {}; - DN_Str8 bold_esc = {}; - DN_Str8 reset_esc = {}; + DN_Str8x32 colour_esc = {}; + DN_Str8 bold_esc = {}; + DN_Str8 reset_esc = {}; if (style.colour) { - bold_esc = DN_Str8Lit(DN_LogBoldEscapeCode); - reset_esc = DN_Str8Lit(DN_LogResetEscapeCode); - colour_esc = DN_LogColourEscapeCodeStr8FromRGB(DN_LogColourType_Fg, style.r, style.g, style.b); + bold_esc = DN_Str8Lit(DN_ANSICodeBoldLit); + reset_esc = DN_Str8Lit(DN_ANSICodeResetLit); + colour_esc = DN_Str8x32FromANSIColourCodeU8RGB(DN_ANSIColourMode_Fg, style.r, style.g, style.b); } DN_Str8 file_name = DN_Str8FileNameFromPath(call_site.file); - DN_GCC_WARNING_PUSH - DN_GCC_WARNING_DISABLE(-Wformat) - DN_GCC_WARNING_DISABLE(-Wformat-extra-args) - DN_MSVC_WARNING_PUSH - DN_MSVC_WARNING_DISABLE(4477) int size = DN_SNPrintF(dest, DN_Cast(int)dest_size, "%04u-%02u-%02uT%02u:%02u:%02u" // date - "%S" // colour - "%S" // bold - " %S" // type + "%.*s" // colour + "%.*s" // bold + " %.*s" // type "%.*s" // type padding - "%S" // reset - " %S" // file name + "%.*s" // reset + " %.*s" // file name ":%05I32u " // line number , date.year, @@ -4431,16 +5012,14 @@ DN_API DN_LogPrefixSize DN_LogMakePrefix(DN_LogStyle style, DN_LogTypeParam type date.hour, date.minute, date.second, - colour_esc, // colour - bold_esc, // bold - type_str8, // type + DN_Str8PrintFmt(colour_esc), // colour + DN_Str8PrintFmt(bold_esc), // bold + DN_Str8PrintFmt(type_str8), // type DN_Cast(int) type_padding, - "", // type padding - reset_esc, // reset - file_name, // file name + "", // type padding + DN_Str8PrintFmt(reset_esc), // reset + DN_Str8PrintFmt(file_name), // file name call_site.line); // line number - DN_MSVC_WARNING_POP // '%S' requires an argument of type 'wchar_t *', but variadic argument 7 has type 'DN_Str8' - DN_GCC_WARNING_POP static DN_USize max_header_length = 0; DN_USize size_no_ansi_codes = size - colour_esc.size - reset_esc.size - bold_esc.size; @@ -4460,14 +5039,19 @@ DN_API void DN_LogSetPrintFunc(DN_LogPrintFunc *print_func, void *user_data) dn->print_func_context = user_data; } -DN_API void DN_LogPrint(DN_LogTypeParam type, DN_CallSite call_site, DN_FMT_ATTRIB char const *fmt, ...) +DN_API void DN_LogPrint(DN_LogTypeParam type, DN_CallSite call_site, DN_LogFlags flags, DN_FMT_ATTRIB char const *fmt, ...) { - DN_Core *dn = DN_Get(); + DN_Core *dn = DN_Get(); + if (type.is_u32_enum) { + if (type.u32 < dn->log_level_to_show_from) + return; + } + DN_LogPrintFunc *func = dn->print_func; if (func) { va_list args; va_start(args, fmt); - func(type, dn->print_func_context, call_site, fmt, args); + func(type, dn->print_func_context, call_site, flags, fmt, args); va_end(args); } } diff --git a/Source/Base/dn_base.h b/Source/Base/dn_base.h index 80478b4..8804153 100644 --- a/Source/Base/dn_base.h +++ b/Source/Base/dn_base.h @@ -40,9 +40,11 @@ #if defined(DN_COMPILER_MSVC) #define DN_MSVC_WARNING_PUSH __pragma(warning(push)) #define DN_MSVC_WARNING_DISABLE(...) __pragma(warning(disable :##__VA_ARGS__)) + #define DN_MSVC_WARNING_ENABLE(...) __pragma(warning(default :##__VA_ARGS__)) #define DN_MSVC_WARNING_POP __pragma(warning(pop)) #else #define DN_MSVC_WARNING_PUSH + #define DN_MSVC_WARNING_ENABLE(...) #define DN_MSVC_WARNING_DISABLE(...) #define DN_MSVC_WARNING_POP #endif @@ -162,6 +164,19 @@ #include #endif +// NOTE: Memory +#if !defined(DN_ARENA_TEMP_MEM_UAF_GUARD) + #define DN_ARENA_TEMP_MEM_UAF_GUARD 0 +#endif + +#if !defined(DN_ARENA_TEMP_MEM_UAF_TRACE_ON_BY_DEFAULT) + #define DN_ARENA_TEMP_MEM_UAF_TRACE_ON_BY_DEFAULT 0 +#endif + +#if !defined(DN_SCRUB_UNINIT_MEM_BYTE) + #define DN_SCRUB_UNINIT_MEM_BYTE 0 +#endif + // NOTE: Macros #define DN_Stringify(x) #x #define DN_TokenCombine2(x, y) x ## y @@ -191,10 +206,10 @@ #define DN_ForLinkedListIt(it, T, list) struct { DN_USize index; T *data; } it = {0, list}; it.data; it.index++, it.data = ((it).data->next) #define DN_ForItCArray(it, T, array) struct { DN_USize index; T *data; } it = {0, &(array)[0]}; it.index < DN_ArrayCountU(array); it.index++, it.data = (array) + it.index -#define DN_AlignUpPowerOfTwo(value, pot) (((uintptr_t)(value) + ((uintptr_t)(pot) - 1)) & ~((uintptr_t)(pot) - 1)) -#define DN_AlignDownPowerOfTwo(value, pot) ((uintptr_t)(value) & ~((uintptr_t)(pot) - 1)) -#define DN_IsPowerOfTwo(value) ((((uintptr_t)(value)) & (((uintptr_t)(value)) - 1)) == 0) -#define DN_IsPowerOfTwoAligned(value, pot) ((((uintptr_t)value) & (((uintptr_t)pot) - 1)) == 0) +#define DN_AlignUpPowerOfTwo(value, pot) (((uintptr_t)(value) + ((uintptr_t)(pot) - 1)) & ~((uintptr_t)(pot) - 1)) +#define DN_AlignDownPowerOfTwo(value, pot) ((uintptr_t)(value) & ~((uintptr_t)(pot) - 1)) +#define DN_IsPowerOfTwo(value) ((((uintptr_t)(value)) & (((uintptr_t)(value)) - 1)) == 0) +#define DN_IsPowerOfTwoAligned(value, pot) ((((uintptr_t)value) & (((uintptr_t)pot) - 1)) == 0) // NOTE: String.h Dependencies #if !defined(DN_Memcpy) || !defined(DN_Memset) || !defined(DN_Memcmp) || !defined(DN_Memmove) @@ -546,9 +561,9 @@ struct DN_TicketMutex }; -struct DN_Hex32 { char data[32]; }; -struct DN_Hex64 { char data[64]; }; -struct DN_Hex128 { char data[128]; }; +struct DN_Hex32 { char data[32 + 1]; DN_USize size; }; +struct DN_Hex64 { char data[64 + 1]; DN_USize size; }; +struct DN_Hex128 { char data[128 + 1]; DN_USize size; }; struct DN_HexU64Str8 { @@ -562,6 +577,11 @@ enum DN_HexFromU64Type DN_HexFromU64Type_Uppercase, }; +enum DN_TrimLeadingZero +{ + DN_TrimLeadingZero_No, + DN_TrimLeadingZero_Yes, +}; struct DN_U8x16 { DN_U8 data[16]; }; struct DN_U8x32 { DN_U8 data[32]; }; @@ -627,12 +647,57 @@ struct DN_U64FromResult DN_U64 value; }; +struct DN_USizeFromResult +{ + bool success; + DN_USize value; +}; + struct DN_I64FromResult { bool success; DN_I64 value; }; +struct DN_U8x32FromResult +{ + bool success; + DN_U8x32 value; +}; + +struct DN_StackTraceFrame +{ + DN_U64 address; + DN_U64 line_number; + DN_Str8 file_name; + DN_Str8 function_name; +}; + +struct DN_StackTraceFrameSlice +{ + DN_StackTraceFrame *data; + DN_USize count; +}; + +struct DN_StackTraceRawFrame +{ + void *process; + DN_U64 base_addr; +}; + +struct DN_StackTraceWalkResult +{ + void *process; // [Internal] Windows handle to the process + DN_U64 *base_addr; // The addresses of the functions in the stack trace + DN_U16 size; // The number of `base_addr`'s stored from the walk +}; + +struct DN_StackTraceWalkResultIterator +{ + DN_StackTraceRawFrame raw_frame; + DN_U16 index; +}; + enum DN_MemCommit { DN_MemCommit_No, @@ -689,37 +754,40 @@ enum DN_MemPage_ #define DN_ARENA_COMMIT_SIZE DN_Kilobytes(64) #endif -enum DN_Allocator +enum DN_MemFuncsType { - DN_Allocator_Arena, - DN_Allocator_Pool, + DN_MemFuncsType_Nil, + DN_MemFuncsType_Heap, + DN_MemFuncsType_Virtual, }; -struct DN_ArenaBlock +typedef void *(DN_MemHeapAllocFunc)(DN_USize size); +typedef void (DN_MemHeapDeallocFunc)(void *ptr); +typedef void *(DN_MemVirtualReserveFunc)(DN_USize size, DN_MemCommit commit, DN_MemPage page_flags); +typedef bool (DN_MemVirtualCommitFunc)(void *ptr, DN_USize size, DN_U32 page_flags); +typedef void (DN_MemVirtualReleaseFunc)(void *ptr, DN_USize size); +struct DN_MemFuncs { - DN_ArenaBlock *prev; - DN_U64 used; - DN_U64 commit; - DN_U64 reserve; - DN_U64 reserve_sum; + DN_MemFuncsType type; + DN_MemHeapAllocFunc *heap_alloc; + DN_MemHeapDeallocFunc *heap_dealloc; + + DN_U32 virtual_page_size; + DN_MemVirtualReserveFunc *virtual_reserve; + DN_MemVirtualCommitFunc *virtual_commit; + DN_MemVirtualReleaseFunc *virtual_release; }; -typedef DN_U32 DN_ArenaFlags; -enum DN_ArenaFlags_ +struct DN_MemBlock { - DN_ArenaFlags_Nil = 0, - DN_ArenaFlags_NoGrow = 1 << 0, - DN_ArenaFlags_NoPoison = 1 << 1, - DN_ArenaFlags_NoAllocTrack = 1 << 2, - DN_ArenaFlags_AllocCanLeak = 1 << 3, - DN_ArenaFlags_SimAlloc = 1 << 4, - - // NOTE: Internal flags. Do not use - DN_ArenaFlags_UserBuffer = 1 << 4, - DN_ArenaFlags_MemFuncs = 1 << 5, + DN_MemBlock* prev; + DN_U64 used; + DN_U64 commit; + DN_U64 reserve; + DN_U64 reserve_sum; }; -struct DN_ArenaInfo +struct DN_MemListInfo { DN_U64 used; DN_U64 commit; @@ -727,10 +795,80 @@ struct DN_ArenaInfo DN_U64 blocks; }; -struct DN_ArenaStats +struct DN_MemStats { - DN_ArenaInfo info; - DN_ArenaInfo hwm; + DN_MemListInfo info; + DN_MemListInfo hwm; +}; + +typedef DN_U32 DN_MemFlags; +enum DN_MemFlags_ +{ + DN_MemFlags_Nil = 0, + DN_MemFlags_NoGrow = 1 << 0, + DN_MemFlags_NoPoison = 1 << 1, + DN_MemFlags_NoAllocTrack = 1 << 2, + DN_MemFlags_AllocCanLeak = 1 << 3, + DN_MemFlags_SimAlloc = 1 << 4, + + // NOTE: Records stack traces of temp memory regions on construction to provide more diagnostics + // when UAF violation occurs in the use of a region (e.g. nested regions A and B, with A + // allocating whilst B is active would result in A's memory being wiped at the end of B). Tracing + // has a heavy performance penalty as each scratch/temp memory region triggers and stores the + // stack trace. + // + // Ignored if UAF guard is disabled at the preprocessor level + // (e.g.: #define DN_ARENA_TEMP_MEM_UAF_GUARD 0) + DN_MemFlags_TempMemUAFTrace = 1 << 5, + + // NOTE: Forcibly disables TempMemUAFTrace for the arena irrespective of global settings. Globally + // UAF tracing can be enabled across all arenas via the preprocessor which turns the tracing + // feature (e.g.: #define DN_ARENA_TEMP_MEM_UAF_TRACE_ON_BY_DEFAULT 1) into an opt-out situation + // where arenas have to specify this flag, specifically to not be traced. + // + // If both TempMemUAFTrace, TempMemUAFTraceDisable and or the global preprocessor flag is set + // disabling takes precedence, always if it is set. + DN_MemFlags_TempMemUAFTraceDisable = 1 << 6, + + // NOTE: Internal flags. Do not use + DN_MemFlags_UserBuffer = 1 << 7, + DN_MemFlags_MemFuncs = 1 << 8, +}; + +struct DN_MemList +{ + DN_MemBlock* curr; + DN_MemFlags flags; + DN_MemFuncs funcs; + DN_MemStats stats; + DN_Str8 label; + + #if DN_ARENA_TEMP_MEM_UAF_GUARD + DN_U32 uaf_guard_next_id; + DN_U32 uaf_guard_active_id; + struct DN_MemListTemp* uaf_guard_active_temp_mem; + #endif +}; + +struct DN_MemListTemp +{ + DN_MemList* mem; + DN_U64 used_sum; + #if DN_ARENA_TEMP_MEM_UAF_GUARD + DN_StackTraceWalkResult trace; + #endif +}; + +enum DN_AllocatorType +{ + DN_AllocatorType_Arena, + DN_AllocatorType_Pool, +}; + +struct DN_Allocator +{ + DN_AllocatorType type; + void* context; }; struct DN_ArenaStatsStr8x64 @@ -739,51 +877,24 @@ struct DN_ArenaStatsStr8x64 DN_Str8x64 hwm; }; -enum DN_ArenaMemFuncType +enum DN_ArenaReset { - DN_ArenaMemFuncType_Nil, - DN_ArenaMemFuncType_Basic, - DN_ArenaMemFuncType_VMem, -}; - -typedef void *(DN_ArenaMemBasicAllocFunc)(DN_USize size); -typedef void (DN_ArenaMemBasicDeallocFunc)(void *ptr); -typedef void *(DN_ArenaMemVMemReserveFunc)(DN_USize size, DN_MemCommit commit, DN_MemPage page_flags); -typedef bool (DN_ArenaMemVMemCommitFunc)(void *ptr, DN_USize size, DN_U32 page_flags); -typedef void (DN_ArenaMemVMemReleaseFunc)(void *ptr, DN_USize size); -struct DN_ArenaMemFuncs -{ - DN_ArenaMemFuncType type; - DN_ArenaMemBasicAllocFunc *basic_alloc; - DN_ArenaMemBasicDeallocFunc *basic_dealloc; - - DN_U32 vmem_page_size; - DN_ArenaMemVMemReserveFunc *vmem_reserve; - DN_ArenaMemVMemCommitFunc *vmem_commit; - DN_ArenaMemVMemReleaseFunc *vmem_release; + DN_ArenaReset_No, + DN_ArenaReset_Yes, }; struct DN_Arena { - DN_ArenaMemFuncs mem_funcs; - DN_ArenaBlock *curr; - DN_ArenaStats stats; - DN_ArenaFlags flags; - DN_Str8 label; - DN_Arena *prev, *next; -}; - -struct DN_ArenaTempMem -{ - DN_Arena *arena; - DN_U64 used_sum; -}; - -struct DN_ArenaTempMemScope -{ - DN_ArenaTempMemScope(DN_Arena *arena); - ~DN_ArenaTempMemScope(); - DN_ArenaTempMem mem; + DN_MemList* mem; + #if DN_ARENA_TEMP_MEM_UAF_GUARD + DN_U32 uaf_guard_id; + DN_MemListTemp* uaf_guard_temp_mem; + DN_U32 uaf_guard_prev_id; + DN_MemListTemp* uaf_guard_prev_temp_mem; + bool uaf_guard_is_being_checked; + #else + DN_MemListTemp temp_mem; + #endif }; DN_USize const DN_ARENA_HEADER_SIZE = DN_AlignUpPowerOfTwo(sizeof(DN_Arena), 64); @@ -857,6 +968,13 @@ struct DN_UTF8DecodeIterator DN_U32 codepoint; }; +typedef DN_U32 DN_CodepointCountFlags; +enum DN_CodepointCountFlags_ +{ + DN_CodepointCountFlags_Nil = 0, + DN_CodepointCountFlags_SkipANSICode = 1 << 0, +}; + struct DN_NibbleFromU8Result { char nibble0; @@ -877,8 +995,11 @@ enum DN_Str8IsAllType struct DN_Str8BSplitResult { - DN_Str8 lhs; - DN_Str8 rhs; + // If there are multiple strings passed to split against, this is the index into that array of + // which the string was split on. If no array was passed this is always 0. + DN_USize input_index; + DN_Str8 lhs; + DN_Str8 rhs; }; struct DN_Str8FindResult @@ -902,16 +1023,18 @@ enum DN_Str8FindFlag_ DN_Str8FindFlag_AlphaNum = DN_Str8FindFlag_Alphabet | DN_Str8FindFlag_Digit, }; -enum DN_Str8SplitIncludeEmptyStrings +typedef DN_USize DN_Str8SplitFlags; +enum DN_Str8SplitFlags_ { - DN_Str8SplitIncludeEmptyStrings_No, - DN_Str8SplitIncludeEmptyStrings_Yes, + DN_Str8SplitFlags_ExcludeEmptyStrings = 1 << 0, + DN_Str8SplitFlags_HandleQuotedStrings = 1 << 1, }; -struct DN_Str8TruncateResult +struct DN_Str8TruncResult { - bool truncated; - DN_Str8 str8; + bool truncated; + DN_Str8 str8; + DN_USize size_req; // Not including null-terminator }; struct DN_Str8SplitResult @@ -920,6 +1043,14 @@ struct DN_Str8SplitResult DN_USize count; }; +typedef DN_USize DN_Str8TableFlags; +enum DN_Str8TableFlags_ +{ + DN_Str8TableFlags_None = 0, + DN_Str8TableFlags_HasHeader = 1 << 0, + DN_Str8TableFlags_RowLines = 1 << 1, +}; + struct DN_Str8Link { DN_Str8 string; // The string @@ -929,9 +1060,9 @@ struct DN_Str8Link struct DN_Str8Builder { - DN_Arena *arena; // Allocator to use to back the string list - DN_Str8Link *head; // First string in the linked list of strings - DN_Str8Link *tail; // Last string in the linked list of strings + DN_Arena* arena; // Allocator to use to back the string list + DN_Str8Link* head; // First string in the linked list of strings + DN_Str8Link* tail; // Last string in the linked list of strings DN_USize string_size; // The size in bytes necessary to construct the current string DN_USize count; // The number of links in the linked list of strings }; @@ -1070,9 +1201,8 @@ struct DN_ErrSink struct DN_TCScratch { - DN_Arena* arena; - DN_ArenaTempMem temp_mem; - DN_B32 destructed; + DN_Arena arena; + DN_B32 destructed; }; #if defined(__cplusplus) @@ -1101,19 +1231,32 @@ struct DN_TCCore // (T)hread (C)ontext sitting in thread-local storage DN_CallSite call_site; char lane_opaque[sizeof(DN_U64) * 4]; + DN_MemList main_arena_mem_; + DN_MemList temp_a_arena_mem_; + DN_MemList temp_b_arena_mem_; + DN_MemList err_sink_arena_mem_; + DN_Arena main_arena_; DN_Arena temp_a_arena_; DN_Arena temp_b_arena_; DN_Arena err_sink_arena_; DN_Arena* main_arena; + DN_Pool main_pool; DN_Arena* temp_a_arena; DN_Arena* temp_b_arena; + DN_ErrSink err_sink; DN_Arena* frame_arena; }; +enum DN_TCDeinitArenas +{ + DN_TCDeinitArenas_No, + DN_TCDeinitArenas_Yes, +}; + struct DN_PCG32 { DN_U64 state; }; struct DN_MurmurHash3 { DN_U64 e[2]; }; @@ -1146,10 +1289,10 @@ struct DN_LogTypeParam DN_Str8 str8; }; -enum DN_LogColourType +enum DN_ANSIColourMode { - DN_LogColourType_Fg, - DN_LogColourType_Bg, + DN_ANSIColourMode_Fg, + DN_ANSIColourMode_Bg, }; struct DN_LogDate @@ -1169,40 +1312,15 @@ struct DN_LogPrefixSize DN_USize padding; }; -struct DN_StackTraceFrame +typedef DN_U32 DN_LogFlags; +enum DN_LogFlags_ { - DN_U64 address; - DN_U64 line_number; - DN_Str8 file_name; - DN_Str8 function_name; + DN_LogFlags_Nil = 0, + DN_LogFlags_NoNewLine = 1 << 0, + DN_LogFlags_NoPrefix = 1 << 1, }; -struct DN_StackTraceFrameSlice -{ - DN_StackTraceFrame *data; - DN_USize count; -}; - -struct DN_StackTraceRawFrame -{ - void *process; - DN_U64 base_addr; -}; - -struct DN_StackTraceWalkResult -{ - void *process; // [Internal] Windows handle to the process - DN_U64 *base_addr; // The addresses of the functions in the stack trace - DN_U16 size; // The number of `base_addr`'s stored from the walk -}; - -struct DN_StackTraceWalkResultIterator -{ - DN_StackTraceRawFrame raw_frame; - DN_U16 index; -}; - -typedef void DN_LogPrintFunc(DN_LogTypeParam type, void *user_data, DN_CallSite call_site, DN_FMT_ATTRIB char const *fmt, va_list args); +typedef void DN_LogPrintFunc(DN_LogTypeParam type, void *user_data, DN_CallSite call_site, DN_LogFlags flags, DN_FMT_ATTRIB char const *fmt, va_list args); DN_MSVC_WARNING_PUSH DN_MSVC_WARNING_DISABLE(4201) // warning C4201: nonstandard extension used: nameless struct/union @@ -1346,7 +1464,9 @@ DN_MSVC_WARNING_POP #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_size, void const *rhs, DN_USize rhs_size); DN_API bool DN_MemEq (void const *lhs, DN_USize lhs_size, void const *rhs, DN_USize rhs_size); +DN_API bool DN_MemEqUnsafe (void const *lhs, void const *rhs, DN_USize size); 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); @@ -1371,6 +1491,15 @@ DN_API void DN_ByteSwapU64Ptr (((((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) #else @@ -1463,35 +1592,53 @@ DN_API void DN_ASanUnpoisonMemoryRegion DN_API DN_F32 DN_EpsilonClampF32 (DN_F32 value, DN_F32 target, DN_F32 epsilon); -DN_API DN_Arena DN_ArenaFromBuffer (void *buffer, DN_USize size, DN_ArenaFlags flags); -DN_API DN_Arena DN_ArenaFromMemFuncs (DN_U64 reserve, DN_U64 commit, DN_ArenaFlags flags, DN_ArenaMemFuncs mem_funcs); -DN_API void DN_ArenaDeinit (DN_Arena *arena); -DN_API bool DN_ArenaCommit (DN_Arena *arena, DN_U64 size); -DN_API bool DN_ArenaCommitTo (DN_Arena *arena, DN_U64 pos); -DN_API bool DN_ArenaGrow (DN_Arena *arena, DN_U64 reserve, DN_U64 commit); -DN_API void * DN_ArenaAlloc (DN_Arena *arena, DN_U64 size, uint8_t align, DN_ZMem zmem); -DN_API void * DN_ArenaAllocContiguous (DN_Arena *arena, DN_U64 size, uint8_t align, DN_ZMem zmem); -DN_API void * DN_ArenaCopy (DN_Arena *arena, void const *data, DN_U64 size, uint8_t align); -DN_API void DN_ArenaPopTo (DN_Arena *arena, DN_U64 init_used); -DN_API void DN_ArenaPop (DN_Arena *arena, DN_U64 amount); -DN_API DN_U64 DN_ArenaPos (DN_Arena const *arena); -DN_API void DN_ArenaClear (DN_Arena *arena); -DN_API bool DN_ArenaOwnsPtr (DN_Arena const *arena, void *ptr); -DN_API DN_Str8x64 DN_ArenaInfoStr8x64 (DN_ArenaInfo info); -DN_API DN_ArenaStats DN_ArenaSumStatsArray (DN_ArenaStats const *array, DN_USize size); -DN_API DN_ArenaStats DN_ArenaSumStats (DN_ArenaStats lhs, DN_ArenaStats rhs); -DN_API DN_ArenaStats DN_ArenaSumArenaArrayToStats (DN_Arena const *array, DN_USize size); -DN_API DN_ArenaTempMem DN_ArenaTempMemBegin (DN_Arena *arena); -DN_API void DN_ArenaTempMemEnd (DN_ArenaTempMem mem); +DN_API DN_MemStats DN_MemStatsSum (DN_MemStats lhs, DN_MemStats rhs); +DN_API DN_MemStats DN_MemStatsSumArray (DN_MemStats const *array, DN_USize size); + +DN_API DN_MemList DN_MemListFromBuffer (void *buffer, DN_USize size, DN_MemFlags flags); +DN_API DN_MemList DN_MemListFromMemFuncs (DN_U64 reserve, DN_U64 commit, DN_MemFlags flags, DN_MemFuncs mem_funcs); +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, uint8_t align, DN_ZMem zmem); +DN_API void * DN_MemListAllocContiguous (DN_MemList *mem, DN_U64 size, uint8_t 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 *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 void DN_ArenaUAFCheck (DN_Arena *arena); +#define DN_ArenaDeref(arena_view) (DN_ArenaUAFCheck(arena_view), (arena_view)->arena) +DN_API DN_Arena DN_ArenaFromMemList (DN_MemList *mem); +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, uint8_t align, DN_ZMem z_mem); +DN_API void* DN_ArenaAllocContiguous (DN_Arena *arena, DN_U64 size, uint8_t align, DN_ZMem z_arena); +DN_API void* DN_ArenaCopy (DN_Arena *arena, void const *data, DN_U64 size, uint8_t align); + #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)) @@ -1528,12 +1675,13 @@ DN_API void DN_ErrSinkAppendF_ #define DN_ErrSinkAppendF(error, error_code, fmt, ...) DN_ErrSinkAppendF_(error, error_code, DN_CALL_SITE, fmt, ##__VA_ARGS__) DN_API void DN_TCInit (DN_TCCore *tc, DN_U64 thread_id, DN_Arena *main_arena, DN_Arena *temp_a_arena, DN_Arena *temp_b_arena, DN_Arena *err_sink_arena); -DN_API void DN_TCInitFromMemFuncs (DN_TCCore *tc, DN_U64 thread_id, DN_TCInitArgs *args, DN_ArenaMemFuncs mem_funcs); -DN_API void DN_TCDeinit (DN_TCCore *tc); +DN_API void DN_TCInitFromMemFuncs (DN_TCCore *tc, DN_U64 thread_id, DN_TCInitArgs *args, DN_MemFuncs mem_funcs); +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_Arena* DN_TCTempArena (DN_Arena **conflicts, DN_USize count); +DN_API DN_Pool* DN_TCMainPool (); +DN_API DN_Arena DN_TCTempArena (DN_Arena **conflicts, DN_USize count); DN_API DN_TCScratch DN_TCScratchBegin (DN_Arena **conflicts, DN_USize count); DN_API void DN_TCScratchEnd (DN_TCScratch *scratch); DN_API void DN_TCSetFrameArena (DN_Arena *arena); @@ -1558,13 +1706,19 @@ DN_API DN_U64 DN_U64FromHexPtrUnsafe 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_U64 DN_U64FromU8x32HiBE (DN_U8x32 const *val); // Checks [0:24) bytes aren't set before getting the U64 +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_USize DN_USizeFromU8x32HiBE (DN_U8x32 const *val); // Checks [0:sizeof USize) bytes aren't set before getting the U64 +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_I64FromResult DN_I64FromStr8 (DN_Str8 string, char separator); DN_API DN_I64FromResult DN_I64FromPtr (void const *data, DN_USize size, char separator); DN_API DN_I64 DN_I64FromPtrUnsafe (void const *data, DN_USize size, char separator); +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 count); +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_USize DN_FmtVSize (DN_FMT_ATTRIB char const *fmt, va_list args); DN_API DN_USize DN_FmtSize (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); @@ -1581,15 +1735,17 @@ DN_API DN_USize DN_CStr16Size #define DN_Str8FromPtr(data, size) DN_Literal(DN_Str8){(char *)(data), (DN_USize)(size)} #define DN_Str8FromStruct(ptr) DN_Str8FromPtr((ptr)->data, (ptr)->size) #define DN_Str8FromLitArray(c_array) DN_Str8FromPtr(c_array, DN_ArrayCountU(c_array)) -DN_API DN_Str8 DN_Str8AllocArena (DN_Arena *arena, DN_USize size, DN_ZMem z_mem); -DN_API DN_Str8 DN_Str8AllocPool (DN_Pool *pool, DN_USize size); +DN_API DN_Str8 DN_Str8AllocArena (DN_USize size, DN_ZMem z_mem, DN_Arena *arena); +DN_API DN_Str8 DN_Str8AllocPool (DN_USize size, DN_Pool *pool); DN_API DN_Str8 DN_Str8FromCStr8 (char const *src); -DN_API DN_Str8 DN_Str8FromPtrArena (DN_Arena *arena, void const *data, DN_USize size); -DN_API DN_Str8 DN_Str8FromPtrPool (DN_Pool *pool, void const *data, DN_USize size); -DN_API DN_Str8 DN_Str8FromStr8Arena (DN_Arena *arena, DN_Str8 string); -DN_API DN_Str8 DN_Str8FromStr8Pool (DN_Pool *pool, DN_Str8 string); -DN_API DN_Str8 DN_Str8FromFmtArena (DN_Arena *arena, DN_FMT_ATTRIB char const *fmt, ...); +DN_API DN_Str8 DN_Str8FromCStr8Arena (char const *src, DN_Arena *arena); +DN_API DN_Str8 DN_Str8FromPtrArena (void const *data, DN_USize size, DN_Arena *arena); +DN_API DN_Str8 DN_Str8FromPtrPool (void const *data, DN_USize size, DN_Pool *pool); +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_Str8FromFmtVArena (DN_Arena *arena, DN_FMT_ATTRIB char const *fmt, va_list args); +DN_API DN_Str8 DN_Str8FromFmtArena (DN_Arena *arena, DN_FMT_ATTRIB char const *fmt, ...); +DN_API DN_Str8 DN_Str8FromFmtVPool (DN_Pool *pool, DN_FMT_ATTRIB char const *fmt, va_list args); DN_API DN_Str8 DN_Str8FromFmtPool (DN_Pool *pool, DN_FMT_ATTRIB char const *fmt, ...); DN_API DN_Str8 DN_Str8FromByteCountType (DN_ByteCountType type); DN_API DN_Str8x16 DN_Str8x16FromFmt (DN_FMT_ATTRIB char const *fmt, ...); @@ -1630,8 +1786,8 @@ DN_API DN_Str8BSplitResult DN_Str8BSplitArray 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_Str8SplitIncludeEmptyStrings mode); -DN_API DN_Str8SplitResult DN_Str8SplitArena (DN_Arena *arena, DN_Str8 string, DN_Str8 delimiter, DN_Str8SplitIncludeEmptyStrings mode); +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); @@ -1662,17 +1818,21 @@ DN_API DN_Str8 DN_Str8AppendFV 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 size); -DN_API DN_Str8TruncateResult DN_Str8TruncateMiddle (DN_Arena *arena, DN_Str8 str8, DN_U32 side_size, DN_Str8 truncator); -DN_API DN_Str8 DN_Str8Lower (DN_Arena *arena, DN_Str8 string); -DN_API DN_Str8 DN_Str8Upper (DN_Arena *arena, DN_Str8 string); -DN_API DN_Str8 DN_Str8PadNewLines (DN_Arena *arena, DN_Str8 src, DN_Str8 pad); +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_Str8PadNewLines (DN_Str8 string, DN_Str8 pad_string, DN_Arena *arena); +DN_API DN_Str8 DN_Str8LineBreakStr8 (DN_Str8 src, DN_USize desired_width, 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_Str8SliceRender (DN_Str8Slice array, DN_Str8 separator, DN_Arena *arena); DN_API DN_Str8 DN_Str8RenderSpaceSep (DN_Str8Slice 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 separator, DN_Arena *arena); DN_API DN_Str16 DN_Str16RenderSpaceSep (DN_Str16Slice array, DN_Arena *arena); @@ -1712,6 +1872,7 @@ DN_API int DN_UTF8Encode DN_API int DN_UTF16Encode (DN_U16 utf16[2], DN_U32 codepoint); DN_API DN_UTF8DecodeResult DN_UTF8Decode (DN_Str8 stream); DN_API bool DN_UTF8DecodeIterate (DN_UTF8DecodeIterator *it, DN_Str8 utf8); +DN_API DN_USize DN_USizeCodepointCountFromUTF8 (DN_Str8 str, DN_CodepointCountFlags flags); DN_API DN_U8 DN_U8FromHexNibble (char hex); DN_API DN_NibbleFromU8Result DN_NibbleFromU8 (DN_U8 u8); @@ -1720,15 +1881,17 @@ DN_API DN_USize DN_BytesFromHex DN_API DN_Str8 DN_BytesFromHexArena (DN_Str8 hex, DN_Arena *arena); DN_API DN_USize DN_BytesFromHexPtr (char const *hex, DN_USize hex_count, void *dest, DN_USize dest_count); DN_API DN_Str8 DN_BytesFromHexPtrArena (char const *hex, DN_USize hex_count, DN_Arena *arena); +DN_API DN_Str8 DN_BytesFromHexPtrPool (char const *hex, DN_USize hex_count, DN_Pool *pool); DN_API DN_U8x16 DN_BytesFromHex32Ptr (char const *hex, DN_USize hex_count); DN_API DN_U8x32 DN_BytesFromHex64Ptr (char const *hex, DN_USize hex_count); DN_API DN_HexU64Str8 DN_HexFromU64 (DN_U64 value, DN_HexFromU64Type type); -DN_API DN_USize DN_HexFromBytesPtr (void const *bytes, DN_USize bytes_count, void *hex, DN_USize hex_count); -DN_API DN_Str8 DN_HexFromBytesPtrArena (void const *bytes, DN_USize bytes_count, DN_Arena *arena); -DN_API DN_Hex32 DN_HexFromBytes16Ptr (void const *bytes, DN_USize bytes_count); -DN_API DN_Hex64 DN_HexFromBytes32Ptr (void const *bytes, DN_USize bytes_count); -DN_API DN_Hex128 DN_HexFromBytes64Ptr (void const *bytes, DN_USize bytes_count); +DN_API DN_USize DN_HexFromPtrBytes (void const *bytes, DN_USize bytes_count, void *hex, DN_USize hex_count, DN_TrimLeadingZero trim_leading_z); +DN_API DN_Str8 DN_HexFromPtrBytesArena (void const *bytes, DN_USize bytes_count, DN_Arena *arena, DN_TrimLeadingZero trim_leading_z); +DN_API DN_USize DN_HexFromStr8Bytes (void const *bytes, DN_USize bytes_count, void *hex, DN_USize hex_count, DN_TrimLeadingZero trim_leading_z); +DN_API DN_Hex32 DN_Hex32FromPtr16b (void const *bytes, DN_USize bytes_count, DN_TrimLeadingZero trim_leading_z); +DN_API DN_Hex64 DN_Hex64FromPtr32b (void const *bytes, DN_USize bytes_count, DN_TrimLeadingZero trim_leading_z); +DN_API DN_Hex128 DN_Hex128FromPtr64b (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); @@ -1792,18 +1955,33 @@ DN_API DN_U32 DN_MurmurHash3HashU32FromBytesX64 #define DN_MurmurHash3HashU32FromBytes(bytes, len, seed) DN_MurmurHash3HashU32FromBytesX86(bytes, len, seed) #endif -#define DN_LogResetEscapeCode "\x1b[0m" -#define DN_LogBoldEscapeCode "\x1b[1m" -DN_API DN_Str8 DN_LogColourEscapeCodeStr8FromRGB (DN_LogColourType colour, DN_U8 r, DN_U8 g, DN_U8 b); -DN_API DN_Str8 DN_LogColourEscapeCodeStr8FromU32 (DN_LogColourType colour, DN_U32 value); +#define DN_ANSICodeBoldLit "\x1b[1m" +#define DN_ANSICodeResetLit "\x1b[0m" +DN_API DN_Str8x32 DN_Str8x32FromANSIColourCodeU8RGB (DN_ANSIColourMode mode, DN_U8 r, DN_U8 g, DN_U8 b); +DN_API DN_Str8x32 DN_Str8x32FromANSIColourCodeV3F32RGB255 (DN_ANSIColourMode mode, DN_V3F32 rgb_255); +DN_API DN_Str8x32 DN_Str8x32FromANSIColourCodeU32RGB (DN_ANSIColourMode mode, DN_U32 value); +DN_API DN_Str8 DN_Str8FromStr8ANSIColourU8RGBArena (DN_ANSIColourMode mode, DN_Str8 str8, DN_U8 r, DN_U8 g, DN_U8 b, DN_Arena *arena); +DN_API DN_Str8 DN_Str8FromStr8ANSIColourV3F32RGB255Arena (DN_ANSIColourMode mode, DN_Str8 str8, DN_V3F32 rgb_255, DN_Arena *arena); +DN_API DN_Str8 DN_Str8FromFmtANSIColourU8RGBArena (DN_ANSIColourMode mode, DN_U8 r, DN_U8 g, DN_U8 b, DN_Arena *arena, char const *fmt, ...); +DN_API DN_Str8 DN_Str8FromFmtANSIColourV3F32RGB255Arena (DN_ANSIColourMode mode, DN_V3F32 rgb_255, DN_Arena *arena, char const *fmt, ...); + DN_API DN_LogPrefixSize DN_LogMakePrefix (DN_LogStyle style, DN_LogTypeParam type, DN_CallSite call_site, DN_LogDate date, char *dest, DN_USize dest_size); DN_API void DN_LogSetPrintFunc (DN_LogPrintFunc *print_func, void *user_data); -DN_API void DN_LogPrint (DN_LogTypeParam type, DN_CallSite call_site, DN_FMT_ATTRIB char const *fmt, ...); +DN_API void DN_LogPrint (DN_LogTypeParam type, DN_CallSite call_site, DN_LogFlags flags, DN_FMT_ATTRIB char const *fmt, ...); DN_API DN_LogTypeParam DN_LogTypeParamFromType (DN_LogType type); -#define DN_LogDebugF(fmt, ...) DN_LogPrint(DN_LogTypeParamFromType(DN_LogType_Debug), DN_CALL_SITE, fmt, ##__VA_ARGS__) -#define DN_LogInfoF(fmt, ...) DN_LogPrint(DN_LogTypeParamFromType(DN_LogType_Info), DN_CALL_SITE, fmt, ##__VA_ARGS__) -#define DN_LogWarningF(fmt, ...) DN_LogPrint(DN_LogTypeParamFromType(DN_LogType_Warning), DN_CALL_SITE, fmt, ##__VA_ARGS__) -#define DN_LogErrorF(fmt, ...) DN_LogPrint(DN_LogTypeParamFromType(DN_LogType_Error), DN_CALL_SITE, fmt, ##__VA_ARGS__) +#define DN_LogF(type, fmt, ...) DN_LogPrint(DN_LogTypeParamFromType(type), DN_CALL_SITE, DN_LogFlags_Nil, fmt, ##__VA_ARGS__) + +#define DN_LogDebugF(fmt, ...) DN_LogPrint(DN_LogTypeParamFromType(DN_LogType_Debug), DN_CALL_SITE, DN_LogFlags_Nil, fmt, ##__VA_ARGS__) +#define DN_LogInfoF(fmt, ...) DN_LogPrint(DN_LogTypeParamFromType(DN_LogType_Info), DN_CALL_SITE, DN_LogFlags_Nil, fmt, ##__VA_ARGS__) +#define DN_LogWarningF(fmt, ...) DN_LogPrint(DN_LogTypeParamFromType(DN_LogType_Warning), DN_CALL_SITE, DN_LogFlags_Nil, fmt, ##__VA_ARGS__) +#define DN_LogErrorF(fmt, ...) DN_LogPrint(DN_LogTypeParamFromType(DN_LogType_Error), DN_CALL_SITE, DN_LogFlags_Nil, fmt, ##__VA_ARGS__) + +#define DN_LogFlagF(type, flags, fmt, ...) DN_LogPrint(DN_LogTypeParamFromType(type), DN_CALL_SITE, flags, fmt, ##__VA_ARGS__) +#define DN_LogFlagDebugF(flags, fmt, ...) DN_LogPrint(DN_LogTypeParamFromType(DN_LogType_Debug), DN_CALL_SITE, flags, fmt, ##__VA_ARGS__) +#define DN_LogFlagInfoF(flags, fmt, ...) DN_LogPrint(DN_LogTypeParamFromType(DN_LogType_Info), DN_CALL_SITE, flags, fmt, ##__VA_ARGS__) +#define DN_LogFlagWarningF(flags, fmt, ...) DN_LogPrint(DN_LogTypeParamFromType(DN_LogType_Warning), DN_CALL_SITE, flags, fmt, ##__VA_ARGS__) +#define DN_LogFlagErrorF(flags, fmt, ...) DN_LogPrint(DN_LogTypeParamFromType(DN_LogType_Error), DN_CALL_SITE, flags, fmt, ##__VA_ARGS__) + // NOTE: OS primitives that the OS layer can provide for the base layer but is optional. #if defined(DN_FREESTANDING) diff --git a/Source/Base/dn_base_containers.cpp b/Source/Base/dn_base_containers.cpp index df67eb1..681affa 100644 --- a/Source/Base/dn_base_containers.cpp +++ b/Source/Base/dn_base_containers.cpp @@ -1,15 +1,13 @@ -#define DN_BASE_CONTAINERS_CPP #if defined(_CLANGD) -#include "../dn.h" + #include "../dn.h" #endif DN_API void *DN_SliceAllocArena(void **data, DN_USize *slice_size_field, DN_USize size, DN_USize elem_size, DN_U8 align, DN_ZMem zmem, DN_Arena *arena) { void *result = *data; *data = DN_ArenaAlloc(arena, size * elem_size, align, zmem); - if (*data) { + if (*data) *slice_size_field = size; - } return result; } @@ -292,9 +290,6 @@ DN_API void DN_RingRead(DN_Ring *ring, void *dest, DN_U64 dest_size) ring->read_pos += dest_size; } -DN_U32 const DN_DS_MAP_DEFAULT_HASH_SEED = 0x8a1ced49; -DN_U32 const DN_DS_MAP_SENTINEL_SLOT = 0; - template DN_DSMap DN_DSMapInit(DN_Arena *arena, DN_U32 size, DN_DSMapFlags flags) { @@ -324,7 +319,7 @@ void DN_DSMapDeinit(DN_DSMap *map, DN_ZMem z_mem) return; // TODO(doyle): Use z_mem (void)z_mem; - DN_ArenaDeinit(map->arena); + DN_MemListDeinit(map->arena->mem); *map = {}; } @@ -564,12 +559,16 @@ bool DN_DSMapResize(DN_DSMap *map, DN_U32 size) return false; DN_Arena *prev_arena = map->arena; + DN_MemList *new_mem = prev_arena->mem; + DN_MemList prev_mem = *prev_arena->mem; + prev_arena->mem = &prev_mem; + + *new_mem = {}; + new_mem->funcs = prev_mem.funcs; + new_mem->flags = prev_mem.flags; + DN_Arena new_arena = {}; - new_arena.mem_funcs = prev_arena->mem_funcs; - new_arena.flags = prev_arena->flags; - new_arena.label = prev_arena->label; - new_arena.prev = prev_arena->prev; - new_arena.next = prev_arena->next; + new_arena.mem = new_mem; DN_DSMap new_map = DN_DSMapInit(&new_arena, size, map->flags); if (!DN_DSMapIsValid(&new_map)) @@ -695,7 +694,7 @@ DN_DSMapKey DN_DSMapKeyBuffer(DN_DSMap const *map, void const *data, DN_USize } template -DN_DSMapKey DN_DSMapKeyBufferAsU64NoHash(DN_DSMap const *map, void const *data, DN_U32 size) +DN_DSMapKey DN_DSMapKeyBufferAsU64NoHash(DN_DSMap const *map, void const *data, DN_USize size) { DN_DSMapKey result = {}; result.type = DN_DSMapKeyType_BufferAsU64NoHash; diff --git a/Source/Base/dn_base_containers.h b/Source/Base/dn_base_containers.h index c6cf1c2..436c402 100644 --- a/Source/Base/dn_base_containers.h +++ b/Source/Base/dn_base_containers.h @@ -5,26 +5,46 @@ // it stupid simple, structs and functions. Minimal amount of container types with flexible // construction leads to less duplicated container code and less template meta-programming. // -// PArray => Pointer (to) Array -// LArray => Literal Array -// Define a C array and size. (P) array macros take a pointer to the aray, its size and its max -// capacity. The (L) array macros take the literal array and derives the max capacity -// automatically using DN_ArrayCountU(l_array). +// Arrays // -// MyStruct buffer[TB_ASType_Count] = {}; -// DN_USize size = 0; -// MyStruct *item_0 = DN_PArrayMake(buffer, &size, DN_ArrayCountU(buffer), DN_ZMem_No); -// MyStruct *item_1 = DN_LArrayMake(buffer, &size, DN_ZMem_No); +// Data structures that have a `T *data`, `DN_USize count` and `DN_USize max` capacity that can be +// dynamically shrunk or expanded. // -// IArray => Intrusive Array -// Define a struct with the members `data`, `size` and `max`: +// API +// ResizeFrom: Resizes the array to `new_max` erase elements if resizing to a smaller size +// GrowFrom: Expands the capacity of the array if `new_max > array.max` otherwise no-op +// GrowIfNeeded: Expands the capacity of the array if `array.size + add_count > array.max` otherwise no-op // -// struct MyArray { -// MyStruct *data; -// DN_USize size; -// DN_USize max; -// } my_array = {}; -// MyStruct *item = DN_IArrayMake(&my_array, DN_ZMem_No); +// Variants +// PArray => Pointer (to) Array +// LArray => Literal Array +// Define a C array and size. (P) array macros take a pointer to the aray, its size and its max +// capacity. The (L) array macros take the literal array and derives the max capacity +// automatically using DN_ArrayCountU(l_array). +// +// MyStruct buffer[TB_ASType_Count] = {}; +// DN_USize size = 0; +// MyStruct *item_0 = DN_PArrayMake(buffer, &size, DN_ArrayCountU(buffer), DN_ZMem_No); +// MyStruct *item_1 = DN_LArrayMake(buffer, &size, DN_ZMem_No); +// +// IArray => Intrusive Array +// Define a struct with the members `data`, `size` and `max`: +// +// struct MyArray { +// MyStruct *data; +// DN_USize size; +// DN_USize max; +// } my_array = {}; +// DN_Arena arena = {}; +// DN_IArrayResizeFromArena(&my_array, &arena, 256); +// MyStruct *item = DN_IArrayMake(&my_array, DN_ZMem_No); +// +// 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 // // ISinglyLL => Intrusive Singly Linked List // Define a struct with the members `next`: @@ -62,6 +82,26 @@ // DN_SentinelDoublyLLInit(&my_list); // DN_SentinelDoublyLLAppend(&my_list, &new_item); // DN_SentinelDoublyLLForEach(it, &my_list) { /* ... */ } +// +// SinglyHeadTailLL => Singly Linked List with Head and Tail pointer (or First and Last pointer) +/* + struct MyLinkItem { + int data; + MyLinkItem *next; + } my_list = {}; + + struct MyContainer { + MyLinkItem *head; + MyLinkItem *tail; + }; + + MyLinkItem item = {}; + MyContainer container = {}; + DN_ISinglyHeadTailLLAppend(container, item); + // ... or alternatively, DN_SinglyHeadTailLLAppend(container.head, container.tail, item); + + for (MyLinkItem *it = container.head; it; it = it->next) { } +*/ #if defined(_CLANGD) #include "../dn.h" @@ -164,6 +204,16 @@ template struct DN_DSMapResult #define DN_ISinglyLLDetach(list) (decltype(list))DN_SinglyLLDetach((void **)&(list), (void **)&(list)->next) +#define DN_SinglyHeadTailLLAppend(head, tail, to_append) \ + do { \ + if (!head) \ + head = to_append; \ + if (tail) \ + tail->next = to_append; \ + tail = to_append; \ + } while (0) +#define DN_ISinglyHeadTailLLAppend(container_ptr, to_append) DN_SinglyHeadTailLLAppend((container_ptr)->head, (container_ptr)->tail, to_append) + #define DN_SentinelDoublyLLInit(list) (list)->next = (list)->prev = (list) #define DN_SentinelDoublyLLIsSentinel(list, item) ((list) == (item)) #define DN_SentinelDoublyLLIsEmpty(list) (!(list) || ((list) == (list)->next)) @@ -171,10 +221,10 @@ template struct DN_DSMapResult #define DN_SentinelDoublyLLHasItems(list) ((list) && ((list) != (list)->next)) #define DN_SentinelDoublyLLForEach(it, list) auto *it = (list)->next; (it) != (list); (it) = (it)->next -#define DN_SentinelDoublyLLInitArena(list, T, arena) \ - do { \ - (list) = DN_ArenaNew(arena, T, DN_ZMem_Yes); \ - DN_SentinelDoublyLLInit(list); \ +#define DN_SentinelDoublyLLInitArena(list, T, ptr_arena) \ + do { \ + (list) = DN_ArenaNew(ptr_arena, T, DN_ZMem_Yes); \ + DN_SentinelDoublyLLInit(list); \ } while (0) #define DN_SentinelDoublyLLInitPool(list, T, pool) \ @@ -286,100 +336,103 @@ template struct DN_DSMapResult #define DN_CppDeclType #endif -#define DN_PArrayResizeFromPool(ptr, size, max, pool, new_max) DN_CArrayResizeFromPool((void **)&(ptr), size, max, sizeof((*ptr)[0]), pool, new_max) -#define DN_PArrayResizeFromArena(ptr, size, max, arena, new_max) DN_CArrayResizeFromArena((void **)&(ptr), size, max, sizeof((*ptr)[0]), arena, new_max) -#define DN_PArrayGrowFromPool(ptr, size, max, pool, new_max) DN_CArrayGrowFromPool((void **)&(ptr), size, max, sizeof((*ptr)[0]), pool, new_max) -#define DN_PArrayGrowFromArena(ptr, size, max, arena, new_max) DN_CArrayGrowFromArena((void **)&(ptr), size, max, sizeof((*ptr)[0]), arena, new_max) -#define DN_PArrayGrowIfNeededFromPool(ptr, size, max, pool, add_count) DN_CArrayGrowIfNeededFromPool((void **)(ptr), size, max, sizeof((*ptr)[0]), pool, add_count) -#define DN_PArrayGrowIfNeededFromArena(ptr, size, max, arena, add_count) DN_CArrayGrowIfNeededFromArena((void **)(ptr), size, max, sizeof((*ptr)[0]), arena, add_count) -#define DN_PArrayMakeArray(ptr, size, max, count, z_mem) (DN_CppDeclType(&(ptr)[0]))DN_CArrayMakeArray(ptr, size, max, sizeof((ptr)[0]), count, z_mem) -#define DN_PArrayMakeArrayZ(ptr, size, max, count) (DN_CppDeclType(&(ptr)[0]))DN_CArrayMakeArray(ptr, size, max, sizeof((ptr)[0]), count, DN_ZMem_Yes) -#define DN_PArrayMake(ptr, size, max, z_mem) (DN_CppDeclType(&(ptr)[0]))DN_CArrayMakeArray(ptr, size, max, sizeof((ptr)[0]), 1, z_mem) -#define DN_PArrayMakeZ(ptr, size, max) (DN_CppDeclType(&(ptr)[0]))DN_CArrayMakeArray(ptr, size, max, sizeof((ptr)[0]), 1, DN_ZMem_Yes) -#define DN_PArrayAddArray(ptr, size, max, items, count, add) (DN_CppDeclType(&(ptr)[0]))DN_CArrayAddArray(ptr, size, max, sizeof((ptr)[0]), items, count, add) -#define DN_PArrayAdd(ptr, size, max, item, add) (DN_CppDeclType(&(ptr)[0]))DN_CArrayAddArray(ptr, size, max, sizeof((ptr)[0]), &item, 1, add) -#define DN_PArrayAppendArray(ptr, size, max, items, count) (DN_CppDeclType(&(ptr)[0]))DN_CArrayAddArray(ptr, size, max, sizeof((ptr)[0]), items, count, DN_ArrayAdd_Append) -#define DN_PArrayAppend(ptr, size, max, item) (DN_CppDeclType(&(ptr)[0]))DN_CArrayAddArray(ptr, size, max, sizeof((ptr)[0]), &item, 1, DN_ArrayAdd_Append) -#define DN_PArrayPrependArray(ptr, size, max, items, count) (DN_CppDeclType(&(ptr)[0]))DN_CArrayAddArray(ptr, size, max, sizeof((ptr)[0]), items, count, DN_ArrayAdd_Prepend) -#define DN_PArrayPrepend(ptr, size, max, item) (DN_CppDeclType(&(ptr)[0]))DN_CArrayAddArray(ptr, size, max, sizeof((ptr)[0]), &item, 1, DN_ArrayAdd_Prepend) -#define DN_PArrayEraseRange(ptr, size, begin_index, count, erase) DN_CArrayEraseRange(ptr, size, sizeof((ptr)[0]), begin_index, count, erase) -#define DN_PArrayErase(ptr, size, index, erase) DN_CArrayEraseRange(ptr, size, sizeof((ptr)[0]), index, 1, erase) -#define DN_PArrayInsertArray(ptr, size, max, index, items, count) (DN_CppDeclType(&(ptr)[0]))DN_CArrayInsertArray(ptr, size, max, sizeof((ptr)[0]), index, items, count) -#define DN_PArrayInsert(ptr, size, max, index, item) (DN_CppDeclType(&(ptr)[0]))DN_CArrayInsertArray(ptr, size, max, sizeof((ptr)[0]), index, &item, 1) -#define DN_PArrayPopFront(ptr, size, max, count) (DN_CppDeclType(&(ptr)[0]))DN_CArrayPopFront(ptr, size, sizeof((ptr)[0]), count) -#define DN_PArrayPopBack(ptr, size, max, count) (DN_CppDeclType(&(ptr)[0]))DN_CArrayPopBack(ptr, size, sizeof((ptr)[0]), count) +#define DN_PArrayResizeFromPool(ptr, ptr_size, ptr_max, pool, new_max) DN_CArrayResizeFromPool((void **)&(ptr), ptr_size, ptr_max, sizeof((ptr)[0]), pool, new_max) +#define DN_PArrayResizeFromArena(ptr, ptr_size, ptr_max, arena, new_max) DN_CArrayResizeFromArena((void **)&(ptr), ptr_size, ptr_max, sizeof((ptr)[0]), arena, new_max) +#define DN_PArrayGrowFromPool(ptr, size, ptr_max, pool, new_max) DN_CArrayGrowFromPool((void **)&(ptr), size, ptr_max, sizeof((ptr)[0]), pool, new_max) +#define DN_PArrayGrowFromArena(ptr, size, ptr_max, arena, new_max) DN_CArrayGrowFromArena((void **)&(ptr), size, ptr_max, sizeof((ptr)[0]), arena, new_max) +#define DN_PArrayGrowIfNeededFromPool(ptr, size, ptr_max, pool, add_count) DN_CArrayGrowIfNeededFromPool((void **)(ptr), size, ptr_max, sizeof((*ptr)[0]), pool, add_count) +#define DN_PArrayGrowIfNeededFromArena(ptr, size, ptr_max, arena, add_count) DN_CArrayGrowIfNeededFromArena((void **)(ptr), size, ptr_max, sizeof((*ptr)[0]), arena, add_count) +#define DN_PArrayMakeArray(ptr, ptr_size, max, count, z_mem) (DN_CppDeclType(&(ptr)[0]))DN_CArrayMakeArray(ptr, ptr_size, max, sizeof((ptr)[0]), count, z_mem) +#define DN_PArrayMakeArrayZ(ptr, ptr_size, max, count) (DN_CppDeclType(&(ptr)[0]))DN_CArrayMakeArray(ptr, ptr_size, max, sizeof((ptr)[0]), count, DN_ZMem_Yes) +#define DN_PArrayMake(ptr, ptr_size, max, z_mem) (DN_CppDeclType(&(ptr)[0]))DN_CArrayMakeArray(ptr, ptr_size, max, sizeof((ptr)[0]), 1, z_mem) +#define DN_PArrayMakeZ(ptr, ptr_size, max) (DN_CppDeclType(&(ptr)[0]))DN_CArrayMakeArray(ptr, ptr_size, max, sizeof((ptr)[0]), 1, DN_ZMem_Yes) +#define DN_PArrayAddArray(ptr, ptr_size, max, items, count, add) (DN_CppDeclType(&(ptr)[0]))DN_CArrayAddArray(ptr, ptr_size, max, sizeof((ptr)[0]), items, count, add) +#define DN_PArrayAdd(ptr, ptr_size, max, item, add) (DN_CppDeclType(&(ptr)[0]))DN_CArrayAddArray(ptr, ptr_size, max, sizeof((ptr)[0]), &item, 1, add) +#define DN_PArrayAppendArray(ptr, ptr_size, max, items, count) (DN_CppDeclType(&(ptr)[0]))DN_CArrayAddArray(ptr, ptr_size, max, sizeof((ptr)[0]), items, count, DN_ArrayAdd_Append) +#define DN_PArrayAppend(ptr, ptr_size, max, item) (DN_CppDeclType(&(ptr)[0]))DN_CArrayAddArray(ptr, ptr_size, max, sizeof((ptr)[0]), &item, 1, DN_ArrayAdd_Append) +#define DN_PArrayPrependArray(ptr, ptr_size, max, items, count) (DN_CppDeclType(&(ptr)[0]))DN_CArrayAddArray(ptr, ptr_size, max, sizeof((ptr)[0]), items, count, DN_ArrayAdd_Prepend) +#define DN_PArrayPrepend(ptr, ptr_size, max, item) (DN_CppDeclType(&(ptr)[0]))DN_CArrayAddArray(ptr, ptr_size, max, sizeof((ptr)[0]), &item, 1, DN_ArrayAdd_Prepend) +#define DN_PArrayEraseRange(ptr, ptr_size, begin_index, count, erase) DN_CArrayEraseRange(ptr, ptr_size, sizeof((ptr)[0]), begin_index, count, erase) +#define DN_PArrayErase(ptr, ptr_size, index, erase) DN_CArrayEraseRange(ptr, ptr_size, sizeof((ptr)[0]), index, 1, erase) +#define DN_PArrayInsertArray(ptr, ptr_size, max, index, items, count) (DN_CppDeclType(&(ptr)[0]))DN_CArrayInsertArray(ptr, ptr_size, max, sizeof((ptr)[0]), index, items, count) +#define DN_PArrayInsert(ptr, ptr_size, max, index, item) (DN_CppDeclType(&(ptr)[0]))DN_CArrayInsertArray(ptr, ptr_size, max, sizeof((ptr)[0]), index, &item, 1) +#define DN_PArrayPopFront(ptr, ptr_size, max, count) (DN_CppDeclType(&(ptr)[0]))DN_CArrayPopFront(ptr, ptr_size, sizeof((ptr)[0]), count) +#define DN_PArrayPopBack(ptr, ptr_size, max, count) (DN_CppDeclType(&(ptr)[0]))DN_CArrayPopBack(ptr, ptr_size, sizeof((ptr)[0]), count) -#define DN_LArrayResizeFromPool(c_array, size, pool, new_max) DN_PArrayResizeFromPool(c_array, size, DN_ArrayCountU(c_array), pool, new_max) -#define DN_LArrayResizeFromArena(c_array, size, arena, new_max) DN_PArrayResizeFromArena(c_array, size, DN_ArrayCountU(c_array), arena, new_max) -#define DN_LArrayGrowFromPool(c_array, size, pool, new_max) DN_PArrayGrowFromPool(c_array, size, DN_ArrayCountU(c_array), pool, new_max) -#define DN_LArrayGrowFromArena(c_array, size, arena, new_max) DN_PArrayGrowFromArena(c_array, size, DN_ArrayCountU(c_array), arena, new_max) -#define DN_LArrayGrowIfNeededFromPool(c_array, size, pool, add_count) DN_PArrayGrowIfNeededFromPool(c_array, size, DN_ArrayCountU(c_array), pool, add_count) -#define DN_LArrayGrowIfNeededFromArena(c_array, size, arena, add_count) DN_PArrayGrowIfNeededFromArena(c_array, size, DN_ArrayCountU(c_array), arena, add_count) -#define DN_LArrayMakeArray(c_array, size, count, z_mem) DN_PArrayMakeArray(c_array, size, DN_ArrayCountU(c_array), count, z_mem) -#define DN_LArrayMakeArrayZ(c_array, size, count) DN_PArrayMakeArrayZ(c_array, size, DN_ArrayCountU(c_array), count) -#define DN_LArrayMake(c_array, size, z_mem) DN_PArrayMake(c_array, size, DN_ArrayCountU(c_array), z_mem) -#define DN_LArrayMakeZ(c_array, size) DN_PArrayMakeZ(c_array, size, DN_ArrayCountU(c_array)) -#define DN_LArrayAddArray(c_array, size, items, count, add) DN_PArrayAddArray(c_array, size, DN_ArrayCountU(c_array), items, count, add) -#define DN_LArrayAdd(c_array, size, item, add) DN_PArrayAdd(c_array, size, DN_ArrayCountU(c_array), item, add) -#define DN_LArrayAppendArray(c_array, size, items, count) DN_PArrayAppendArray(c_array, size, DN_ArrayCountU(c_array), items, count) -#define DN_LArrayAppend(c_array, size, item) DN_PArrayAppend(c_array, size, DN_ArrayCountU(c_array), item) -#define DN_LArrayPrependArray(c_array, size, items, count) DN_PArrayPrependArray(c_array, size, DN_ArrayCountU(c_array), items, count) -#define DN_LArrayPrepend(c_array, size, item) DN_PArrayPrepend(c_array, size, DN_ArrayCountU(c_array), item) -#define DN_LArrayEraseRange(c_array, size, begin_index, count, erase) DN_PArrayEraseRange(c_array, size, DN_ArrayCountU(c_array), begin_index, count, erase) -#define DN_LArrayErase(c_array, size, index, erase) DN_PArrayErase(c_array, size, DN_ArrayCountU(c_array), index, erase) -#define DN_LArrayInsertArray(c_array, size, index, items, count) DN_PArrayInsertArray(c_array, size, DN_ArrayCountU(c_array), index, items, count) -#define DN_LArrayInsert(c_array, size, index, item) DN_PArrayInsert(c_array, size, DN_ArrayCountU(c_array), index, item) -#define DN_LArrayPopFront(c_array, size, count) DN_PArrayPopFront(c_array, size, DN_ArrayCountU(c_array), count) -#define DN_LArrayPopBack(c_array, size, count) DN_PArrayPopBack(c_array, size, DN_ArrayCountU(c_array), count) +#define DN_LArrayResizeFromPool(c_array, size, pool, new_max) DN_PArrayResizeFromPool(c_array, size, DN_ArrayCountU(c_array), pool, new_max) +#define DN_LArrayResizeFromArena(c_array, size, arena, new_max) DN_PArrayResizeFromArena(c_array, size, DN_ArrayCountU(c_array), arena, new_max) +#define DN_LArrayGrowFromPool(c_array, size, pool, new_max) DN_PArrayGrowFromPool(c_array, size, DN_ArrayCountU(c_array), pool, new_max) +#define DN_LArrayGrowFromArena(c_array, size, arena, new_max) DN_PArrayGrowFromArena(c_array, size, DN_ArrayCountU(c_array), arena, new_max) +#define DN_LArrayGrowIfNeededFromPool(c_array, size, pool, add_count) DN_PArrayGrowIfNeededFromPool(c_array, size, DN_ArrayCountU(c_array), pool, add_count) +#define DN_LArrayGrowIfNeededFromArena(c_array, size, arena, add_count) DN_PArrayGrowIfNeededFromArena(c_array, size, DN_ArrayCountU(c_array), arena, add_count) +#define DN_LArrayMakeArray(c_array, ptr_size, count, z_mem) DN_PArrayMakeArray(c_array, ptr_size, DN_ArrayCountU(c_array), count, z_mem) +#define DN_LArrayMakeArrayZ(c_array, ptr_size, count) DN_PArrayMakeArrayZ(c_array, ptr_size, DN_ArrayCountU(c_array), count) +#define DN_LArrayMake(c_array, ptr_size, z_mem) DN_PArrayMake(c_array, ptr_size, DN_ArrayCountU(c_array), z_mem) +#define DN_LArrayMakeZ(c_array, ptr_size) DN_PArrayMakeZ(c_array, ptr_size, DN_ArrayCountU(c_array)) +#define DN_LArrayAddArray(c_array, ptr_size, items, count, add) DN_PArrayAddArray(c_array, ptr_size, DN_ArrayCountU(c_array), items, count, add) +#define DN_LArrayAdd(c_array, ptr_size, item, add) DN_PArrayAdd(c_array, ptr_size, DN_ArrayCountU(c_array), item, add) +#define DN_LArrayAppendArray(c_array, ptr_size, items, count) DN_PArrayAppendArray(c_array, ptr_size, DN_ArrayCountU(c_array), items, count) +#define DN_LArrayAppend(c_array, ptr_size, item) DN_PArrayAppend(c_array, ptr_size, DN_ArrayCountU(c_array), item) +#define DN_LArrayPrependArray(c_array, ptr_size, items, count) DN_PArrayPrependArray(c_array, ptr_size, DN_ArrayCountU(c_array), items, count) +#define DN_LArrayPrepend(c_array, ptr_size, item) DN_PArrayPrepend(c_array, ptr_size, DN_ArrayCountU(c_array), item) +#define DN_LArrayEraseRange(c_array, ptr_size, begin_index, count, erase) DN_PArrayEraseRange(c_array, ptr_size, begin_index, count, erase) +#define DN_LArrayErase(c_array, ptr_size, index, erase) DN_PArrayErase(c_array, ptr_size, index, erase) +#define DN_LArrayInsertArray(c_array, ptr_size, index, items, count) DN_PArrayInsertArray(c_array, ptr_size, DN_ArrayCountU(c_array), index, items, count) +#define DN_LArrayInsert(c_array, ptr_size, index, item) DN_PArrayInsert(c_array, ptr_size, DN_ArrayCountU(c_array), index, item) +#define DN_LArrayPopFront(c_array, ptr_size, count) DN_PArrayPopFront(c_array, ptr_size, DN_ArrayCountU(c_array), count) +#define DN_LArrayPopBack(c_array, ptr_size, count) DN_PArrayPopBack(c_array, ptr_size, DN_ArrayCountU(c_array), count) -#define DN_IArrayResizeFromPool(array, pool, new_max) DN_CArrayResizeFromPool((void **)(&(array)->data), &(array)->size, &(array)->max, sizeof((array)->data[0]), pool, new_max) -#define DN_IArrayResizeFromArena(array, arena, new_max) DN_CArrayResizeFromArena((void **)(&(array)->data), &(array)->size, &(array)->max, sizeof((array)->data[0]), arena, new_max) -#define DN_IArrayGrowFromPool(array, pool, new_max) DN_CArrayGrowFromPool((void **)(&(array)->data), (array)->size, &(array)->max, sizeof((array)->data[0]), pool, new_max) -#define DN_IArrayGrowFromArena(array, arena, new_max) DN_CArrayGrowFromArena((void **)(&(array)->data), (array)->size, &(array)->max, sizeof((array)->data[0]), arena, new_max) -#define DN_IArrayGrowIfNeededFromPool(array, pool, add_count) DN_CArrayGrowIfNeededFromPool((void **)(&(array)->data), (array)->size, &(array)->max, sizeof((array)->data[0]), pool, add_count) -#define DN_IArrayGrowIfNeededFromArena(array, arena, add_count) DN_CArrayGrowIfNeededFromArena((void **)(&(array)->data), (array)->size, &(array)->max, sizeof((array)->data[0]), arena, add_count) -#define DN_IArrayMakeArray(array, count, z_mem) (DN_CppDeclType(&((array)->data)[0]))DN_CArrayMakeArray((array)->data, &(array)->size, (array)->max, sizeof(((array)->data)[0]), count, z_mem) -#define DN_IArrayMakeArrayZ(array, count) (DN_CppDeclType(&((array)->data)[0]))DN_CArrayMakeArray((array)->data, &(array)->size, (array)->max, sizeof(((array)->data)[0]), count, DN_ZMem_Yes) -#define DN_IArrayMake(array, z_mem) (DN_CppDeclType(&((array)->data)[0]))DN_CArrayMakeArray((array)->data, &(array)->size, (array)->max, sizeof(((array)->data)[0]), 1, z_mem) -#define DN_IArrayMakeZ(array) (DN_CppDeclType(&((array)->data)[0]))DN_CArrayMakeArray((array)->data, &(array)->size, (array)->max, sizeof(((array)->data)[0]), 1, DN_ZMem_Yes) -#define DN_IArrayAddArray(array, items, count, add) (DN_CppDeclType(&((array)->data)[0]))DN_CArrayAddArray((array)->data, &(array)->size, (array)->max, sizeof(((array)->data)[0]), items, count, add) -#define DN_IArrayAdd(array, item, add) (DN_CppDeclType(&((array)->data)[0]))DN_CArrayAddArray((array)->data, &(array)->size, (array)->max, sizeof(((array)->data)[0]), &item, 1, add) -#define DN_IArrayAppendArray(array, items, count) (DN_CppDeclType(&((array)->data)[0]))DN_CArrayAddArray((array)->data, &(array)->size, (array)->max, sizeof(((array)->data)[0]), items, count, DN_ArrayAdd_Append) -#define DN_IArrayAppend(array, item) (DN_CppDeclType(&((array)->data)[0]))DN_CArrayAddArray((array)->data, &(array)->size, (array)->max, sizeof(((array)->data)[0]), &item, 1, DN_ArrayAdd_Append) -#define DN_IArrayPrependArray(array, items, count) (DN_CppDeclType(&((array)->data)[0]))DN_CArrayAddArray((array)->data, &(array)->size, (array)->max, sizeof(((array)->data)[0]), items, count, DN_ArrayAdd_Prepend) -#define DN_IArrayPrepend(array, item) (DN_CppDeclType(&((array)->data)[0]))DN_CArrayAddArray((array)->data, &(array)->size, (array)->max, sizeof(((array)->data)[0]), &item, 1, DN_ArrayAdd_Prepend) -#define DN_IArrayEraseRange(array, begin_index, count, erase) DN_CArrayEraseRange((array)->data, &(array)->size, sizeof(((array)->data)[0]), begin_index, count, erase) -#define DN_IArrayErase(array, index, erase) DN_CArrayEraseRange((array)->data, &(array)->size, sizeof(((array)->data)[0]), index, 1, erase) -#define DN_IArrayInsertArray(array, index, items, count) (DN_CppDeclType(&((array)->data)[0]))DN_CArrayInsertArray((array)->data, &(array)->size, (array)->max, sizeof(((array)->data)[0]), index, items, count) -#define DN_IArrayInsert(array, index, item, count) (DN_CppDeclType(&((array)->data)[0]))DN_CArrayInsertArray((array)->data, &(array)->size, (array)->max, sizeof(((array)->data)[0]), index, &item, 1) -#define DN_IArrayPopFront(array, count) (DN_CppDeclType(&((array)->data)[0]))DN_CArrayPopFront((array)->data, &(array)->size, sizeof(((array)->data)[0]), count) -#define DN_IArrayPopBack(array, count) (DN_CppDeclType(&((array)->data)[0]))DN_CArrayPopBack((array)->data, &(array)->size, sizeof(((array)->data)[0]), count) +#define DN_IArrayResizeFromPool(ptr_array, pool, new_max) DN_CArrayResizeFromPool((void **)(&(ptr_array)->data), &(ptr_array)->size, &(ptr_array)->max, sizeof((ptr_array)->data[0]), pool, new_max) +#define DN_IArrayResizeFromArena(ptr_array, arena, new_max) DN_CArrayResizeFromArena((void **)(&(ptr_array)->data), &(ptr_array)->size, &(ptr_array)->max, sizeof((ptr_array)->data[0]), arena, new_max) +#define DN_IArrayGrowFromPool(ptr_array, pool, new_max) DN_CArrayGrowFromPool((void **)(&(ptr_array)->data), (ptr_array)->size, &(ptr_array)->max, sizeof((ptr_array)->data[0]), pool, new_max) +#define DN_IArrayGrowFromArena(ptr_array, arena, new_max) DN_CArrayGrowFromArena((void **)(&(ptr_array)->data), (ptr_array)->size, &(ptr_array)->max, sizeof((ptr_array)->data[0]), arena, new_max) +#define DN_IArrayGrowIfNeededFromPool(ptr_array, pool, add_count) DN_CArrayGrowIfNeededFromPool((void **)(&(ptr_array)->data), (ptr_array)->size, &(ptr_array)->max, sizeof((ptr_array)->data[0]), pool, add_count) +#define DN_IArrayGrowIfNeededFromArena(ptr_array, arena, add_count) DN_CArrayGrowIfNeededFromArena((void **)(&(ptr_array)->data), (ptr_array)->size, &(ptr_array)->max, sizeof((ptr_array)->data[0]), arena, add_count) +#define DN_IArrayMakeArray(ptr_array, count, z_mem) (DN_CppDeclType(&((ptr_array)->data)[0]))DN_CArrayMakeArray((ptr_array)->data, &(ptr_array)->size, (ptr_array)->max, sizeof(((ptr_array)->data)[0]), count, z_mem) +#define DN_IArrayMakeArrayZ(ptr_array, count) (DN_CppDeclType(&((ptr_array)->data)[0]))DN_CArrayMakeArray((ptr_array)->data, &(ptr_array)->size, (ptr_array)->max, sizeof(((ptr_array)->data)[0]), count, DN_ZMem_Yes) +#define DN_IArrayMake(ptr_array, z_mem) (DN_CppDeclType(&((ptr_array)->data)[0]))DN_CArrayMakeArray((ptr_array)->data, &(ptr_array)->size, (ptr_array)->max, sizeof(((ptr_array)->data)[0]), 1, z_mem) +#define DN_IArrayMakeZ(ptr_array) (DN_CppDeclType(&((ptr_array)->data)[0]))DN_CArrayMakeArray((ptr_array)->data, &(ptr_array)->size, (ptr_array)->max, sizeof(((ptr_array)->data)[0]), 1, DN_ZMem_Yes) +#define DN_IArrayAddArray(ptr_array, items, count, add) (DN_CppDeclType(&((ptr_array)->data)[0]))DN_CArrayAddArray((ptr_array)->data, &(ptr_array)->size, (ptr_array)->max, sizeof(((ptr_array)->data)[0]), items, count, add) +#define DN_IArrayAdd(ptr_array, item, add) (DN_CppDeclType(&((ptr_array)->data)[0]))DN_CArrayAddArray((ptr_array)->data, &(ptr_array)->size, (ptr_array)->max, sizeof(((ptr_array)->data)[0]), &item, 1, add) +#define DN_IArrayAppendArray(ptr_array, items, count) (DN_CppDeclType(&((ptr_array)->data)[0]))DN_CArrayAddArray((ptr_array)->data, &(ptr_array)->size, (ptr_array)->max, sizeof(((ptr_array)->data)[0]), items, count, DN_ArrayAdd_Append) +#define DN_IArrayAppend(ptr_array, item) (DN_CppDeclType(&((ptr_array)->data)[0]))DN_CArrayAddArray((ptr_array)->data, &(ptr_array)->size, (ptr_array)->max, sizeof(((ptr_array)->data)[0]), &item, 1, DN_ArrayAdd_Append) +#define DN_IArrayPrependArray(ptr_array, items, count) (DN_CppDeclType(&((ptr_array)->data)[0]))DN_CArrayAddArray((ptr_array)->data, &(ptr_array)->size, (ptr_array)->max, sizeof(((ptr_array)->data)[0]), items, count, DN_ArrayAdd_Prepend) +#define DN_IArrayPrepend(ptr_array, item) (DN_CppDeclType(&((ptr_array)->data)[0]))DN_CArrayAddArray((ptr_array)->data, &(ptr_array)->size, (ptr_array)->max, sizeof(((ptr_array)->data)[0]), &item, 1, DN_ArrayAdd_Prepend) +#define DN_IArrayEraseRange(ptr_array, begin_index, count, erase) DN_CArrayEraseRange((ptr_array)->data, &(ptr_array)->size, sizeof(((ptr_array)->data)[0]), begin_index, count, erase) +#define DN_IArrayErase(ptr_array, index, erase) DN_CArrayEraseRange((ptr_array)->data, &(ptr_array)->size, sizeof(((ptr_array)->data)[0]), index, 1, erase) +#define DN_IArrayInsertArray(ptr_array, index, items, count) (DN_CppDeclType(&((ptr_array)->data)[0]))DN_CArrayInsertArray((ptr_array)->data, &(ptr_array)->size, (ptr_array)->max, sizeof(((ptr_array)->data)[0]), index, items, count) +#define DN_IArrayInsert(ptr_array, index, item, count) (DN_CppDeclType(&((ptr_array)->data)[0]))DN_CArrayInsertArray((ptr_array)->data, &(ptr_array)->size, (ptr_array)->max, sizeof(((ptr_array)->data)[0]), index, &item, 1) +#define DN_IArrayPopFront(ptr_array, count) (DN_CppDeclType(&((ptr_array)->data)[0]))DN_CArrayPopFront((ptr_array)->data, &(ptr_array)->size, sizeof(((ptr_array)->data)[0]), count) +#define DN_IArrayPopBack(ptr_array, count) (DN_CppDeclType(&((ptr_array)->data)[0]))DN_CArrayPopBack((ptr_array)->data, &(ptr_array)->size, sizeof(((ptr_array)->data)[0]), count) -#define DN_ISliceAllocArena(T, slice_ptr, count_, zmem, arena) (T *)DN_SliceAllocArena((void **)&((slice_ptr)->data), &((slice_ptr)->count), count_, sizeof(T), alignof(T), zmem, arena) +#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 size, DN_USize elem_size, DN_U8 align, DN_ZMem zmem, DN_Arena *arena); +DN_API void* DN_SliceAllocArena (void **data, DN_USize *slice_size_field, DN_USize size, DN_USize elem_size, DN_U8 align, DN_ZMem zmem, DN_Arena *arena); -DN_API void* DN_CArrayInsertArray (void *data, DN_USize *size, DN_USize max, DN_USize elem_size, DN_USize index, void const *items, DN_USize count); -DN_API void* DN_CArrayPopFront (void *data, DN_USize *size, DN_USize elem_size, DN_USize count); -DN_API void* DN_CArrayPopBack (void *data, DN_USize *size, DN_USize elem_size, DN_USize count); -DN_API DN_ArrayEraseResult DN_CArrayEraseRange (void *data, DN_USize *size, DN_USize elem_size, DN_USize begin_index, DN_ISize count, DN_ArrayErase erase); -DN_API void* DN_CArrayMakeArray (void *data, DN_USize *size, DN_USize max, DN_USize data_size, DN_USize make_size, DN_ZMem z_mem); -DN_API void* DN_CArrayAddArray (void *data, DN_USize *size, DN_USize max, DN_USize data_size, void const *elems, DN_USize elems_count, DN_ArrayAdd add); -DN_API bool DN_CArrayResizeFromPool (void **data, DN_USize *size, DN_USize *max, DN_USize data_size, DN_Pool *pool, DN_USize new_max); -DN_API bool DN_CArrayResizeFromArena (void **data, DN_USize *size, DN_USize *max, DN_USize data_size, DN_Arena *arena, DN_USize new_max); -DN_API bool DN_CArrayGrowFromPool (void **data, DN_USize size, DN_USize *max, DN_USize data_size, DN_Pool *pool, DN_USize new_max); -DN_API bool DN_CArrayGrowFromArena (void **data, DN_USize size, DN_USize *max, DN_USize data_size, DN_Pool *pool, DN_USize new_max); -DN_API bool DN_CArrayGrowIfNeededFromPool (void **data, DN_USize size, DN_USize *max, DN_USize data_size, DN_Pool *pool, DN_USize add_count); -DN_API bool DN_CArrayGrowIfNeededFromArena (void **data, DN_USize size, DN_USize *max, DN_USize data_size, DN_Arena *pool, DN_USize add_count); +DN_API void* DN_CArrayInsertArray (void *data, DN_USize *size, DN_USize max, DN_USize elem_size, DN_USize index, void const *items, DN_USize count); +DN_API void* DN_CArrayPopFront (void *data, DN_USize *size, DN_USize elem_size, DN_USize count); +DN_API void* DN_CArrayPopBack (void *data, DN_USize *size, DN_USize elem_size, DN_USize count); +DN_API DN_ArrayEraseResult DN_CArrayEraseRange (void *data, DN_USize *size, DN_USize elem_size, DN_USize begin_index, DN_ISize count, DN_ArrayErase erase); +DN_API void* DN_CArrayMakeArray (void *data, DN_USize *size, DN_USize max, DN_USize data_size, DN_USize make_size, DN_ZMem z_mem); +DN_API void* DN_CArrayAddArray (void *data, DN_USize *size, DN_USize max, DN_USize data_size, void const *elems, DN_USize elems_count, DN_ArrayAdd add); +DN_API bool DN_CArrayResizeFromPool (void **data, DN_USize *size, DN_USize *max, DN_USize data_size, DN_Pool *pool, DN_USize new_max); +DN_API bool DN_CArrayResizeFromArena (void **data, DN_USize *size, DN_USize *max, DN_USize data_size, DN_Arena *arena, DN_USize new_max); +DN_API bool DN_CArrayGrowFromPool (void **data, DN_USize size, DN_USize *max, DN_USize data_size, DN_Pool *pool, DN_USize new_max); +DN_API bool DN_CArrayGrowFromArena (void **data, DN_USize size, DN_USize *max, DN_USize data_size, DN_Pool *pool, DN_USize new_max); +DN_API bool DN_CArrayGrowIfNeededFromPool (void **data, DN_USize size, DN_USize *max, DN_USize data_size, DN_Pool *pool, DN_USize add_count); +DN_API bool DN_CArrayGrowIfNeededFromArena (void **data, DN_USize size, DN_USize *max, DN_USize data_size, DN_Arena *pool, DN_USize add_count); -DN_API void* DN_SinglyLLDetach (void **link, void **next); +DN_API void* DN_SinglyLLDetach (void **link, void **next); -DN_API bool DN_RingHasSpace (DN_Ring const *ring, DN_U64 size); -DN_API bool DN_RingHasData (DN_Ring const *ring, DN_U64 size); -DN_API void DN_RingWrite (DN_Ring *ring, void const *src, DN_U64 src_size); -#define DN_RingWriteStruct(ring, item) DN_RingWrite((ring), (item), sizeof(*(item))) -DN_API void DN_RingRead (DN_Ring *ring, void *dest, DN_U64 dest_size); -#define DN_RingReadStruct(ring, dest) DN_RingRead((ring), (dest), sizeof(*(dest))) +DN_API bool DN_RingHasSpace (DN_Ring const *ring, DN_U64 size); +DN_API bool DN_RingHasData (DN_Ring const *ring, DN_U64 size); +DN_API void DN_RingWrite (DN_Ring *ring, void const *src, DN_U64 src_size); +#define DN_RingWriteStruct(ring, item) DN_RingWrite((ring), (item), sizeof(*(item))) +DN_API void DN_RingRead (DN_Ring *ring, void *dest, DN_U64 dest_size); +#define DN_RingReadStruct(ring, dest) DN_RingRead((ring), (dest), sizeof(*(dest))) + +DN_U32 const DN_DS_MAP_DEFAULT_HASH_SEED = 0x8a1ced49; +DN_U32 const DN_DS_MAP_SENTINEL_SLOT = 0; template DN_DSMap DN_DSMapInit (DN_Arena *arena, DN_U32 size, DN_DSMapFlags flags); template void DN_DSMapDeinit (DN_DSMap *map, DN_ZMem z_mem); @@ -399,8 +452,8 @@ template bool DN_DSMapResize (DN_DSMap template bool DN_DSMapErase (DN_DSMap *map, DN_DSMapKey key); template bool DN_DSMapEraseKeyU64 (DN_DSMap *map, DN_U64 key); template bool DN_DSMapEraseKeyStr8 (DN_DSMap *map, DN_Str8 key); -template DN_DSMapKey DN_DSMapKeyBuffer (DN_DSMap const *map, void const *data, DN_U32 size); -template DN_DSMapKey DN_DSMapKeyBufferAsU64NoHash (DN_DSMap const *map, void const *data, DN_U32 size); +template DN_DSMapKey DN_DSMapKeyBuffer (DN_DSMap const *map, void const *data, DN_USize size); +template DN_DSMapKey DN_DSMapKeyBufferAsU64NoHash (DN_DSMap const *map, void const *data, DN_USize size); template DN_DSMapKey DN_DSMapKeyU64 (DN_DSMap const *map, DN_U64 u64); template DN_DSMapKey DN_DSMapKeyStr8 (DN_DSMap const *map, DN_Str8 string); #define DN_DSMapKeyCStr8(map, string) DN_DSMapKeyBuffer(map, string, sizeof((string))/sizeof((string)[0]) - 1) diff --git a/Source/Base/dn_base_leak.h b/Source/Base/dn_base_leak.h index 70a911f..ecc7632 100644 --- a/Source/Base/dn_base_leak.h +++ b/Source/Base/dn_base_leak.h @@ -29,6 +29,7 @@ struct DN_LeakTracker { DN_DSMap alloc_table; DN_TicketMutex alloc_table_mutex; + DN_MemList alloc_table_mem; DN_Arena alloc_table_arena; DN_U64 alloc_table_bytes_allocated_for_stack_traces; }; diff --git a/Source/Extra/dn_async.cpp b/Source/Extra/dn_async.cpp index 5fde64a..cd4936e 100644 --- a/Source/Extra/dn_async.cpp +++ b/Source/Extra/dn_async.cpp @@ -63,7 +63,7 @@ DN_API void DN_ASYNC_Deinit(DN_ASYNCCore *async) DN_AtomicSetValue32(&async->join_threads, true); DN_OS_SemaphoreIncrement(&async->worker_sem, async->thread_count); for (DN_ForItSize(it, DN_OSThread, async->threads, async->thread_count)) - DN_OS_ThreadJoin(it.data); + DN_OS_ThreadJoin(it.data, DN_TCDeinitArenas_Yes); } static bool DN_ASYNC_QueueTask_(DN_ASYNCCore *async, DN_ASYNCTask const *task, DN_U64 wait_time_ms) { diff --git a/Source/Extra/dn_bin_pack.cpp b/Source/Extra/dn_bin_pack.cpp index 6bb1bca..e2ab4d9 100644 --- a/Source/Extra/dn_bin_pack.cpp +++ b/Source/Extra/dn_bin_pack.cpp @@ -128,8 +128,8 @@ DN_API void DN_BinPackStr8FromArena(DN_BinPack *pack, DN_Arena *arena, DN_BinPac if (mode == DN_BinPackMode_Serialise) { DN_Str8BuilderAppendBytesCopy(&pack->writer, string->data, string->size); } else { - DN_Str8 src = DN_Str8Slice(pack->read, pack->read_index, string->size); - *string = DN_Str8FromStr8Arena(arena, src); + DN_Str8 src = DN_Str8Subset(pack->read, pack->read_index, string->size); + *string = DN_Str8FromStr8Arena(src, arena); pack->read_index += src.size; } } @@ -140,8 +140,8 @@ DN_API void DN_BinPackStr8FromPool(DN_BinPack *pack, DN_Pool *pool, DN_BinPackMo if (mode == DN_BinPackMode_Serialise) { DN_Str8BuilderAppendBytesCopy(&pack->writer, string->data, string->size); } else { - DN_Str8 src = DN_Str8Slice(pack->read, pack->read_index, string->size); - *string = DN_Str8FromStr8Pool(pool, src); + DN_Str8 src = DN_Str8Subset(pack->read, pack->read_index, string->size); + *string = DN_Str8FromStr8Pool(src, pool); pack->read_index += src.size; } } @@ -175,7 +175,7 @@ DN_API void DN_BinPackCArray(DN_BinPack *pack, DN_BinPackMode mode, void *ptr, D if (mode == DN_BinPackMode_Serialise) { DN_Str8BuilderAppendBytesCopy(&pack->writer, ptr, size); } else { - DN_Str8 src = DN_Str8Slice(pack->read, pack->read_index, size); + DN_Str8 src = DN_Str8Subset(pack->read, pack->read_index, size); DN_Assert(src.size == size); DN_Memcpy(ptr, src.data, DN_Min(src.size, size)); pack->read_index += src.size; diff --git a/Source/Extra/dn_csv.cpp b/Source/Extra/dn_csv.cpp index 2727d13..8d1158f 100644 --- a/Source/Extra/dn_csv.cpp +++ b/Source/Extra/dn_csv.cpp @@ -1,10 +1,8 @@ #define DN_CSV_CPP -#if defined(_CLANGD) - #include "dn_csv.h" -#endif +#include "dn_csv.h" -static DN_CSVTokeniser DN_CSV_TokeniserInit(DN_Str8 string, char delimiter) +DN_CSVTokeniser DN_CSV_TokeniserInit(DN_Str8 string, char delimiter) { DN_CSVTokeniser result = {}; result.string = string; @@ -12,13 +10,21 @@ static DN_CSVTokeniser DN_CSV_TokeniserInit(DN_Str8 string, char delimiter) return result; } -static bool DN_CSV_TokeniserValid(DN_CSVTokeniser *tokeniser) +bool DN_CSV_TokeniserValid(DN_CSVTokeniser *tokeniser) { bool result = tokeniser && !tokeniser->bad; return result; } -static bool DN_CSV_TokeniserNextRow(DN_CSVTokeniser *tokeniser) +static void DN_CSV_TokeniserEatNewLines_(DN_CSVTokeniser *tokeniser) +{ + char const *end = tokeniser->string.data + tokeniser->string.size; + while (tokeniser->it[0] == '\n' || tokeniser->it[0] == '\r') + if (++tokeniser->it == end) + break; +} + +bool DN_CSV_TokeniserNextRow(DN_CSVTokeniser *tokeniser) { bool result = false; if (DN_CSV_TokeniserValid(tokeniser) && tokeniser->string.size) { @@ -37,7 +43,7 @@ static bool DN_CSV_TokeniserNextRow(DN_CSVTokeniser *tokeniser) return result; } -static DN_Str8 DN_CSV_TokeniserNextField(DN_CSVTokeniser *tokeniser) +DN_Str8 DN_CSV_TokeniserNextField(DN_CSVTokeniser *tokeniser) { DN_Str8 result = {}; if (!DN_CSV_TokeniserValid(tokeniser)) @@ -52,10 +58,7 @@ static DN_Str8 DN_CSV_TokeniserNextField(DN_CSVTokeniser *tokeniser) char const *string_end = tokeniser->string.data + tokeniser->string.size; if (!tokeniser->it) { tokeniser->it = tokeniser->string.data; - // NOTE: Skip any leading new lines - while (tokeniser->it[0] == '\n' || tokeniser->it[0] == '\r') - if (++tokeniser->it == string_end) - break; + DN_CSV_TokeniserEatNewLines_(tokeniser); // NOTE: Skip any leading new lines } // NOTE: Tokeniser pointing at end, no more valid data to parse. @@ -68,8 +71,8 @@ static DN_Str8 DN_CSV_TokeniserNextField(DN_CSVTokeniser *tokeniser) // 3. '\n' Last field in record, extract everything leading up the the new line. char const *begin = tokeniser->it; while (tokeniser->it != string_end && (tokeniser->it[0] != '"' && - tokeniser->it[0] != tokeniser->delimiter && - tokeniser->it[0] != '\n')) + tokeniser->it[0] != tokeniser->delimiter && + tokeniser->it[0] != '\n')) tokeniser->it++; bool quoted_field = (tokeniser->it != string_end) && tokeniser->it[0] == '"'; @@ -106,8 +109,7 @@ static DN_Str8 DN_CSV_TokeniserNextField(DN_CSVTokeniser *tokeniser) // NOTE: Quoted fields may have whitespace after the closing quote, we skip // until we reach the field terminator. if (quoted_field) - while (tokeniser->it != string_end && (tokeniser->it[0] != tokeniser->delimiter && - tokeniser->it[0] != '\n')) + while (tokeniser->it != string_end && (tokeniser->it[0] != tokeniser->delimiter && tokeniser->it[0] != '\n')) tokeniser->it++; // NOTE: Advance the tokeniser past the field terminator. @@ -120,7 +122,7 @@ static DN_Str8 DN_CSV_TokeniserNextField(DN_CSVTokeniser *tokeniser) return result; } -static DN_Str8 DN_CSV_TokeniserNextColumn(DN_CSVTokeniser *tokeniser) +DN_Str8 DN_CSV_TokeniserNextColumn(DN_CSVTokeniser *tokeniser) { DN_Str8 result = {}; if (!DN_CSV_TokeniserValid(tokeniser)) @@ -135,14 +137,14 @@ static DN_Str8 DN_CSV_TokeniserNextColumn(DN_CSVTokeniser *tokeniser) return result; } -static void DN_CSV_TokeniserSkipLine(DN_CSVTokeniser *tokeniser) +void DN_CSV_TokeniserSkipLine(DN_CSVTokeniser *tokeniser) { while (DN_CSV_TokeniserValid(tokeniser) && !tokeniser->end_of_line) DN_CSV_TokeniserNextColumn(tokeniser); DN_CSV_TokeniserNextRow(tokeniser); } -static int DN_CSV_TokeniserNextN(DN_CSVTokeniser *tokeniser, DN_Str8 *fields, int fields_size, bool column_iterator) +int DN_CSV_TokeniserNextN(DN_CSVTokeniser *tokeniser, DN_Str8 *fields, int fields_size, bool column_iterator) { if (!DN_CSV_TokeniserValid(tokeniser) || !fields || fields_size <= 0) return 0; @@ -150,34 +152,32 @@ static int DN_CSV_TokeniserNextN(DN_CSVTokeniser *tokeniser, DN_Str8 *fields, in int result = 0; for (; result < fields_size; result++) { fields[result] = column_iterator ? DN_CSV_TokeniserNextColumn(tokeniser) : DN_CSV_TokeniserNextField(tokeniser); - if (!DN_CSV_TokeniserValid(tokeniser) || fields[result].size == 0) + if (!DN_CSV_TokeniserValid(tokeniser) || !fields[result].data) break; } return result; } -DN_MSVC_WARNING_PUSH -DN_MSVC_WARNING_DISABLE(4505) // 'x': unreferenced function with internal linkage has been removed -static int DN_CSV_TokeniserNextColumnN(DN_CSVTokeniser *tokeniser, DN_Str8 *fields, int fields_size) +int DN_CSV_TokeniserNextColumnN(DN_CSVTokeniser *tokeniser, DN_Str8 *fields, int fields_size) { int result = DN_CSV_TokeniserNextN(tokeniser, fields, fields_size, true /*column_iterator*/); return result; } -static int DN_CSV_TokeniserNextFieldN(DN_CSVTokeniser *tokeniser, DN_Str8 *fields, int fields_size) +int DN_CSV_TokeniserNextFieldN(DN_CSVTokeniser *tokeniser, DN_Str8 *fields, int fields_size) { int result = DN_CSV_TokeniserNextN(tokeniser, fields, fields_size, false /*column_iterator*/); return result; } -static void DN_CSV_TokeniserSkipLineN(DN_CSVTokeniser *tokeniser, int count) +void DN_CSV_TokeniserSkipLineN(DN_CSVTokeniser *tokeniser, int count) { for (int i = 0; i < count && DN_CSV_TokeniserValid(tokeniser); i++) DN_CSV_TokeniserSkipLine(tokeniser); } -static void DN_CSV_PackU64(DN_CSVPack *pack, DN_CSVSerialise serialise, DN_U64 *value) +void DN_CSV_PackU64(DN_CSVPack *pack, DN_CSVSerialise serialise, DN_U64 *value) { if (serialise == DN_CSVSerialise_Read) { DN_Str8 csv_value = DN_CSV_TokeniserNextColumn(&pack->read_tokeniser); @@ -189,7 +189,7 @@ static void DN_CSV_PackU64(DN_CSVPack *pack, DN_CSVSerialise serialise, DN_U64 * } } -static void DN_CSV_PackI64(DN_CSVPack *pack, DN_CSVSerialise serialise, DN_I64 *value) +void DN_CSV_PackI64(DN_CSVPack *pack, DN_CSVSerialise serialise, DN_I64 *value) { if (serialise == DN_CSVSerialise_Read) { DN_Str8 csv_value = DN_CSV_TokeniserNextColumn(&pack->read_tokeniser); @@ -201,7 +201,7 @@ static void DN_CSV_PackI64(DN_CSVPack *pack, DN_CSVSerialise serialise, DN_I64 * } } -static void DN_CSV_PackI32(DN_CSVPack *pack, DN_CSVSerialise serialise, DN_I32 *value) +void DN_CSV_PackI32(DN_CSVPack *pack, DN_CSVSerialise serialise, DN_I32 *value) { DN_I64 u64 = *value; DN_CSV_PackI64(pack, serialise, &u64); @@ -209,7 +209,7 @@ static void DN_CSV_PackI32(DN_CSVPack *pack, DN_CSVSerialise serialise, DN_I32 * *value = DN_SaturateCastI64ToI32(u64); } -static void DN_CSV_PackI16(DN_CSVPack *pack, DN_CSVSerialise serialise, DN_I16 *value) +void DN_CSV_PackI16(DN_CSVPack *pack, DN_CSVSerialise serialise, DN_I16 *value) { DN_I64 u64 = *value; DN_CSV_PackI64(pack, serialise, &u64); @@ -217,7 +217,7 @@ static void DN_CSV_PackI16(DN_CSVPack *pack, DN_CSVSerialise serialise, DN_I16 * *value = DN_SaturateCastI64ToI16(u64); } -static void DN_CSV_PackI8(DN_CSVPack *pack, DN_CSVSerialise serialise, DN_I8 *value) +void DN_CSV_PackI8(DN_CSVPack *pack, DN_CSVSerialise serialise, DN_I8 *value) { DN_I64 u64 = *value; DN_CSV_PackI64(pack, serialise, &u64); @@ -225,8 +225,7 @@ static void DN_CSV_PackI8(DN_CSVPack *pack, DN_CSVSerialise serialise, DN_I8 *va *value = DN_SaturateCastI64ToI8(u64); } - -static void DN_CSV_PackU32(DN_CSVPack *pack, DN_CSVSerialise serialise, DN_U32 *value) +void DN_CSV_PackU32(DN_CSVPack *pack, DN_CSVSerialise serialise, DN_U32 *value) { DN_U64 u64 = *value; DN_CSV_PackU64(pack, serialise, &u64); @@ -234,7 +233,7 @@ static void DN_CSV_PackU32(DN_CSVPack *pack, DN_CSVSerialise serialise, DN_U32 * *value = DN_SaturateCastU64ToU32(u64); } -static void DN_CSV_PackU16(DN_CSVPack *pack, DN_CSVSerialise serialise, DN_U16 *value) +void DN_CSV_PackU16(DN_CSVPack *pack, DN_CSVSerialise serialise, DN_U16 *value) { DN_U64 u64 = *value; DN_CSV_PackU64(pack, serialise, &u64); @@ -242,7 +241,7 @@ static void DN_CSV_PackU16(DN_CSVPack *pack, DN_CSVSerialise serialise, DN_U16 * *value = DN_SaturateCastU64ToU16(u64); } -static void DN_CSV_PackBoolAsU64(DN_CSVPack *pack, DN_CSVSerialise serialise, bool *value) +void DN_CSV_PackBoolAsU64(DN_CSVPack *pack, DN_CSVSerialise serialise, bool *value) { DN_U64 u64 = *value; DN_CSV_PackU64(pack, serialise, &u64); @@ -250,17 +249,17 @@ static void DN_CSV_PackBoolAsU64(DN_CSVPack *pack, DN_CSVSerialise serialise, bo *value = u64 ? 1 : 0; } -static void DN_CSV_PackStr8(DN_CSVPack *pack, DN_CSVSerialise serialise, DN_Str8 *str8, DN_Arena *arena) +void DN_CSV_PackStr8(DN_CSVPack *pack, DN_CSVSerialise serialise, DN_Str8 *str8, DN_Arena *arena) { if (serialise == DN_CSVSerialise_Read) { DN_Str8 csv_value = DN_CSV_TokeniserNextColumn(&pack->read_tokeniser); - *str8 = DN_Str8FromStr8Arena(arena, csv_value); + *str8 = DN_Str8FromStr8Arena(csv_value, arena); } else { DN_Str8BuilderAppendF(&pack->write_builder, "%s%.*s", pack->write_column++ ? "," : "", DN_Str8PrintFmt(*str8)); } } -static void DN_CSV_PackBuffer(DN_CSVPack *pack, DN_CSVSerialise serialise, void *dest, size_t *size) +void DN_CSV_PackBuffer(DN_CSVPack *pack, DN_CSVSerialise serialise, void *dest, size_t *size) { if (serialise == DN_CSVSerialise_Read) { DN_Str8 csv_value = DN_CSV_TokeniserNextColumn(&pack->read_tokeniser); @@ -271,14 +270,14 @@ static void DN_CSV_PackBuffer(DN_CSVPack *pack, DN_CSVSerialise serialise, void } } -static void DN_CSV_PackBufferWithMax(DN_CSVPack *pack, DN_CSVSerialise serialise, void *dest, size_t *size, size_t max) +void DN_CSV_PackBufferWithMax(DN_CSVPack *pack, DN_CSVSerialise serialise, void *dest, size_t *size, size_t max) { if (serialise == DN_CSVSerialise_Read) *size = max; DN_CSV_PackBuffer(pack, serialise, dest, size); } -static bool DN_CSV_PackNewLine(DN_CSVPack *pack, DN_CSVSerialise serialise) +bool DN_CSV_PackNewLine(DN_CSVPack *pack, DN_CSVSerialise serialise) { bool result = true; if (serialise == DN_CSVSerialise_Read) { @@ -289,4 +288,3 @@ static bool DN_CSV_PackNewLine(DN_CSVPack *pack, DN_CSVSerialise serialise) } return result; } -DN_MSVC_WARNING_POP diff --git a/Source/Extra/dn_csv.h b/Source/Extra/dn_csv.h index c9bbf6f..1fbd6d9 100644 --- a/Source/Extra/dn_csv.h +++ b/Source/Extra/dn_csv.h @@ -1,9 +1,18 @@ #if !defined(DN_CSV_H) #define DN_CSV_H -#if defined(_CLANGD) - #include "../dn.h" -#endif +// NOTE: Data structures to create and parse CSV files, supports Python style escaped quotes (e.g. +// Using "" to escape quotes inside a quoted string). +// +// API +// DN_CSV_TokeniserNextN: Reads the next N consecutive fields from the parser. If `column_iterator` +// is `false` then the read of the N consecutive fields does not proceed past the end of the +// current CSV row. If `true` then it reads the next N fields even if reading would progress onto +// the next row. + + #if defined(_CLANGD) + #include "../dn.h" + #endif enum DN_CSVSerialise { @@ -27,4 +36,27 @@ struct DN_CSVPack DN_CSVTokeniser read_tokeniser; }; +DN_CSVTokeniser DN_CSV_TokeniserInit (DN_Str8 string, char delimiter); +bool DN_CSV_TokeniserValid (DN_CSVTokeniser *tokeniser); +bool DN_CSV_TokeniserNextRow (DN_CSVTokeniser *tokeniser); +DN_Str8 DN_CSV_TokeniserNextField (DN_CSVTokeniser *tokeniser); +DN_Str8 DN_CSV_TokeniserNextColumn (DN_CSVTokeniser *tokeniser); +void DN_CSV_TokeniserSkipLine (DN_CSVTokeniser *tokeniser); +int DN_CSV_TokeniserNextN (DN_CSVTokeniser *tokeniser, DN_Str8 *fields, int fields_size, bool column_iterator); +int DN_CSV_TokeniserNextColumnN(DN_CSVTokeniser *tokeniser, DN_Str8 *fields, int fields_size); +int DN_CSV_TokeniserNextFieldN (DN_CSVTokeniser *tokeniser, DN_Str8 *fields, int fields_size); +void DN_CSV_TokeniserSkipLineN (DN_CSVTokeniser *tokeniser, int count); +void DN_CSV_PackU64 (DN_CSVPack *pack, DN_CSVSerialise serialise, DN_U64 *value); +void DN_CSV_PackI64 (DN_CSVPack *pack, DN_CSVSerialise serialise, DN_I64 *value); +void DN_CSV_PackI32 (DN_CSVPack *pack, DN_CSVSerialise serialise, DN_I32 *value); +void DN_CSV_PackI16 (DN_CSVPack *pack, DN_CSVSerialise serialise, DN_I16 *value); +void DN_CSV_PackI8 (DN_CSVPack *pack, DN_CSVSerialise serialise, DN_I8 *value); +void DN_CSV_PackU32 (DN_CSVPack *pack, DN_CSVSerialise serialise, DN_U32 *value); +void DN_CSV_PackU16 (DN_CSVPack *pack, DN_CSVSerialise serialise, DN_U16 *value); +void DN_CSV_PackBoolAsU64 (DN_CSVPack *pack, DN_CSVSerialise serialise, bool *value); +void DN_CSV_PackStr8 (DN_CSVPack *pack, DN_CSVSerialise serialise, DN_Str8 *str8, DN_Arena *arena); +void DN_CSV_PackBuffer (DN_CSVPack *pack, DN_CSVSerialise serialise, void *dest, size_t *size); +void DN_CSV_PackBufferWithMax (DN_CSVPack *pack, DN_CSVSerialise serialise, void *dest, size_t *size, size_t max); +bool DN_CSV_PackNewLine (DN_CSVPack *pack, DN_CSVSerialise serialise); + #endif // !defined(DN_CSV_H) diff --git a/Source/Extra/dn_helpers.cpp b/Source/Extra/dn_helpers.cpp index e3c2ba4..9b33396 100644 --- a/Source/Extra/dn_helpers.cpp +++ b/Source/Extra/dn_helpers.cpp @@ -72,7 +72,7 @@ DN_API void DN_JSONBuilder_KeyValue(DN_JSONBuilder *builder, DN_Str8 key, DN_Str DN_API void DN_JSONBuilder_KeyValueFV(DN_JSONBuilder *builder, DN_Str8 key, char const *value_fmt, va_list args) { DN_TCScratch scratch = DN_TCScratchBegin(&builder->string_builder.arena, 1); - DN_Str8 value = DN_Str8FromFmtVArena(scratch.arena, value_fmt, args); + DN_Str8 value = DN_Str8FromFmtVArena(&scratch.arena, value_fmt, args); DN_JSONBuilder_KeyValue(builder, key, value); DN_TCScratchEnd(&scratch); } diff --git a/Source/Extra/dn_helpers.h b/Source/Extra/dn_helpers.h index 688aefa..a5f276c 100644 --- a/Source/Extra/dn_helpers.h +++ b/Source/Extra/dn_helpers.h @@ -41,7 +41,6 @@ struct DN_JSONBuilder }; #endif // !defined(DN_NO_JSON_BUIDLER) -// NOTE: DN_BinarySearch /////////////////////////////////////////////////////////////////////////// template using DN_BinarySearchLessThanProc = bool(T const &lhs, T const &rhs); diff --git a/Source/Extra/dn_net.cpp b/Source/Extra/dn_net.cpp index 282435b..82ca963 100644 --- a/Source/Extra/dn_net.cpp +++ b/Source/Extra/dn_net.cpp @@ -1,6 +1,8 @@ #define DN_NET_CURL_CPP #if defined(_CLANGD) + #define DN_H_WITH_OS 1 + #include "../dn.h" #include "dn_net.h" #endif @@ -43,7 +45,7 @@ DN_NETRequestHandle DN_NET_HandleFromRequest(DN_NETRequest *request) void DN_NET_EndFinishedRequest_(DN_NETRequest *request) { // NOTE: Deallocate the memory used in the request and reset the string builder - DN_ArenaPopTo(&request->arena, request->start_response_arena_pos); + DN_ArenaTempEnd(&request->start_response_arena, DN_ArenaReset_Yes); // NOTE: Check that the request is completely detached DN_Assert(request->next == nullptr); } @@ -52,7 +54,8 @@ void DN_NET_BaseInit_(DN_NETCore *net, char *base, DN_U64 base_size) { net->base = base; net->base_size = base_size; - net->arena = DN_ArenaFromBuffer(net->base, net->base_size, DN_ArenaFlags_Nil); + net->mem = DN_MemListFromBuffer(net->base, net->base_size, DN_MemFlags_Nil); + net->arena = DN_ArenaFromMemList(&net->mem); net->completion_sem = DN_OS_SemaphoreInit(0); } @@ -61,31 +64,32 @@ DN_NETRequestHandle DN_NET_SetupRequest_(DN_NETRequest *request, DN_Str8 url, DN // NOTE: Setup request DN_Assert(request); if (request) { - if (!request->arena.curr) - request->arena = DN_ArenaFromVMem(DN_Megabytes(1), DN_Kilobytes(1), DN_ArenaFlags_Nil); + if (!request->mem.curr) + request->mem = DN_MemListFromVMem(DN_Megabytes(1), DN_Kilobytes(1), DN_MemFlags_Nil); + request->arena = DN_ArenaTempBeginFromMemList(&request->mem); request->type = type; request->gen = DN_Max(request->gen + 1, 1); - request->url = DN_Str8FromStr8Arena(&request->arena, url); - request->method = DN_Str8FromStr8Arena(&request->arena, DN_Str8TrimWhitespaceAround(method)); + request->url = DN_Str8FromStr8Arena(url, &request->arena); + request->method = DN_Str8FromStr8Arena(DN_Str8TrimWhitespaceAround(method), &request->arena); if (args) { request->args.flags = args->flags; - request->args.username = DN_Str8FromStr8Arena(&request->arena, args->username); - request->args.password = DN_Str8FromStr8Arena(&request->arena, args->password); + request->args.username = DN_Str8FromStr8Arena(args->username, &request->arena); + request->args.password = DN_Str8FromStr8Arena(args->password, &request->arena); if (type == DN_NETRequestType_HTTP) - request->args.payload = DN_Str8FromStr8Arena(&request->arena, args->payload); + request->args.payload = DN_Str8FromStr8Arena(args->payload, &request->arena); request->args.headers = DN_ArenaNewArray(&request->arena, DN_Str8, args->headers_size, DN_ZMem_No); DN_Assert(request->args.headers); if (request->args.headers) { for (DN_ForItSize(it, DN_Str8, args->headers, args->headers_size)) - request->args.headers[it.index] = DN_Str8FromStr8Arena(&request->arena, *it.data); + request->args.headers[it.index] = DN_Str8FromStr8Arena(*it.data, &request->arena); request->args.headers_size = args->headers_size; } } - request->completion_sem = DN_OS_SemaphoreInit(0); - request->start_response_arena_pos = DN_ArenaPos(&request->arena); + request->completion_sem = DN_OS_SemaphoreInit(0); + request->start_response_arena = DN_ArenaTempBeginFromArena(&request->arena); } DN_NETRequestHandle result = DN_NET_HandleFromRequest(request); diff --git a/Source/Extra/dn_net.h b/Source/Extra/dn_net.h index 9b106c6..459e734 100644 --- a/Source/Extra/dn_net.h +++ b/Source/Extra/dn_net.h @@ -2,8 +2,8 @@ #define DN_NET_H #if defined(_CLANGD) - #include "../dn_base_inc.h" - #include "../dn_os_inc.h" + #define DN_H_WITH_OS 1 + #include "../dn.h" #endif enum DN_NETRequestType @@ -74,8 +74,9 @@ struct DN_NETResponse struct DN_NETRequest { + DN_MemList mem; DN_Arena arena; - DN_USize start_response_arena_pos; + DN_Arena start_response_arena; DN_NETRequestType type; DN_U64 gen; DN_Str8 url; @@ -88,22 +89,13 @@ struct DN_NETRequest DN_U64 context[2]; }; -struct DN_NETCore -{ - char *base; - DN_U64 base_size; - DN_Arena arena; - DN_OSSemaphore completion_sem; - void *context; -}; - -typedef void (DN_NETInitFunc) (DN_NETCore *net, char *base, DN_U64 base_size); -typedef void (DN_NETDeinitFunc) (DN_NETCore *net); -typedef DN_NETRequestHandle(DN_NETDoHTTPFunc) (DN_NETCore *net, DN_Str8 url, DN_Str8 method, DN_NETDoHTTPArgs const *args); -typedef DN_NETRequestHandle(DN_NETDoWSFunc) (DN_NETCore *net, DN_Str8 url); +typedef void (DN_NETInitFunc) (struct DN_NETCore *net, char *base, DN_U64 base_size); +typedef void (DN_NETDeinitFunc) (struct DN_NETCore *net); +typedef DN_NETRequestHandle(DN_NETDoHTTPFunc) (struct DN_NETCore *net, DN_Str8 url, DN_Str8 method, DN_NETDoHTTPArgs const *args); +typedef DN_NETRequestHandle(DN_NETDoWSFunc) (struct DN_NETCore *net, DN_Str8 url); typedef void (DN_NETDoWSSendFunc) (DN_NETRequestHandle handle, DN_Str8 data, DN_NETWSSend send); typedef DN_NETResponse (DN_NETWaitForResponseFunc) (DN_NETRequestHandle handle, DN_Arena *arena, DN_U32 timeout_ms); -typedef DN_NETResponse (DN_NETWaitForAnyResponseFunc)(DN_NETCore *net, DN_Arena *arena, DN_U32 timeout_ms); +typedef DN_NETResponse (DN_NETWaitForAnyResponseFunc)(struct DN_NETCore *net, DN_Arena *arena, DN_U32 timeout_ms); struct DN_NETInterface { @@ -116,6 +108,17 @@ struct DN_NETInterface DN_NETWaitForAnyResponseFunc* wait_for_any_response; }; +struct DN_NETCore +{ + char *base; + DN_U64 base_size; + DN_MemList mem; + DN_Arena arena; + DN_OSSemaphore completion_sem; + void *context; + DN_NETInterface api; +}; + DN_Str8 DN_NET_Str8FromResponseState(DN_NETResponseState state); DN_NETRequest * DN_NET_RequestFromHandle (DN_NETRequestHandle handle); DN_NETRequestHandle DN_NET_HandleFromRequest (DN_NETRequest *request); diff --git a/Source/Extra/dn_net_curl.cpp b/Source/Extra/dn_net_curl.cpp index 476456d..2433006 100644 --- a/Source/Extra/dn_net_curl.cpp +++ b/Source/Extra/dn_net_curl.cpp @@ -129,7 +129,7 @@ static int32_t DN_NET_CurlThreadEntryPoint_(DN_OSThread *thread) DN_Str8 payload = {}; for (DN_OS_MutexScope(&curl->ring_mutex)) { DN_Assert(DN_RingHasData(&curl->ring, event.ws_send_size)); - payload = DN_Str8AllocArena(tmem.arena, event.ws_send_size, DN_ZMem_No); + payload = DN_Str8AllocArena(event.ws_send_size, DN_ZMem_No, &tmem.arena); DN_RingRead(&curl->ring, payload.data, payload.size); } @@ -168,7 +168,7 @@ static int32_t DN_NET_CurlThreadEntryPoint_(DN_OSThread *thread) DN_NETRequest *request = DN_Cast(DN_NETRequest *) event.request.handle; // NOTE: Release resources - DN_ArenaClear(&request->arena); + DN_ArenaTempEnd(&request->arena, DN_ArenaReset_Yes); DN_OS_SemaphoreDeinit(&request->completion_sem); curl_multi_remove_handle(curl->thread_curlm, curl_req->handle); @@ -224,7 +224,7 @@ static int32_t DN_NET_CurlThreadEntryPoint_(DN_OSThread *thread) } } else { req->response.error_str8 = DN_Str8FromFmtArena(&req->arena, "Failed to get HTTP response status (CURL %d): %s", msg->data.result, curl_easy_strerror(get_result)); - req->response.state = DN_NETResponseState_Error; + req->response.state = DN_NETResponseState_Error; } } else { DN_USize curl_extended_error_size = DN_CStr8Size(curl_req->error); @@ -302,7 +302,7 @@ static int32_t DN_NET_CurlThreadEntryPoint_(DN_OSThread *thread) // NOTE: Allocate and read (we use meta->bytesleft as per comment from initial recv) if (meta->bytesleft) { - DN_Str8 buffer = DN_Str8AllocArena(&req->arena, meta->bytesleft, DN_ZMem_No); + DN_Str8 buffer = DN_Str8AllocArena(meta->bytesleft, DN_ZMem_No, &req->arena); DN_Assert(buffer.size == DN_Cast(DN_USize)meta->bytesleft); receive_result = curl_ws_recv(curl_req->handle, buffer.data, buffer.size, &buffer.size, &meta); DN_Assert(buffer.size == DN_Cast(DN_USize)meta->len); @@ -353,13 +353,13 @@ static int32_t DN_NET_CurlThreadEntryPoint_(DN_OSThread *thread) DN_USize curl_extended_error_size = DN_CStr8Size(curl_req->error); req->response.state = DN_NETResponseState_Error; req->response.error_str8 = DN_Str8FromFmtArena(&req->arena, - "Websocket receive '%.*s' failed (CURL %d): %s%s%s%s", - DN_Str8PrintFmt(req->url), - receive_result, - curl_easy_strerror(receive_result), - curl_extended_error_size ? " (" : "", - curl_extended_error_size ? curl_req->error : "", - curl_extended_error_size ? ")" : ""); + "Websocket receive '%.*s' failed (CURL %d): %s%s%s%s", + DN_Str8PrintFmt(req->url), + receive_result, + curl_easy_strerror(receive_result), + curl_extended_error_size ? " (" : "", + curl_extended_error_size ? curl_req->error : "", + curl_extended_error_size ? ")" : ""); } } @@ -394,10 +394,11 @@ DN_NETInterface DN_NET_CurlInterface() void DN_NET_CurlInit(DN_NETCore *net, char *base, DN_U64 base_size) { DN_NET_BaseInit_(net, base, base_size); - DN_NETCurlCore *curl = DN_ArenaNew(&net->arena, DN_NETCurlCore, DN_ZMem_Yes); - net->context = curl; + DN_NETCurlCore *curl = DN_ArenaNew(&net->arena, DN_NETCurlCore, DN_ZMem_Yes); + net->context = curl; + net->api = DN_NET_CurlInterface(); - DN_USize arena_bytes_avail = (net->arena.curr->reserve - net->arena.curr->used); + DN_USize arena_bytes_avail = (net->arena.mem->curr->reserve - net->arena.mem->curr->used); curl->ring.size = arena_bytes_avail / 2; curl->ring.base = DN_Cast(char *) DN_ArenaAlloc(&net->arena, curl->ring.size, /*align*/ 1, DN_ZMem_Yes); DN_Assert(curl->ring.base); @@ -415,7 +416,7 @@ void DN_NET_CurlDeinit(DN_NETCore *net) DN_NETCurlCore *curl = DN_Cast(DN_NETCurlCore *) net->context; curl->kill_thread = true; curl_multi_wakeup(curl->thread_curlm); - DN_OS_ThreadJoin(&curl->thread); + DN_OS_ThreadJoin(&curl->thread, DN_TCDeinitArenas_Yes); } static DN_NETRequestHandle DN_NET_CurlDoRequest_(DN_NETCore *net, DN_Str8 url, DN_Str8 method, DN_NETDoHTTPArgs const *args, DN_NETRequestType type) @@ -434,11 +435,11 @@ static DN_NETRequestHandle DN_NET_CurlDoRequest_(DN_NETCore *net, DN_Str8 url, D // NOTE None in the free list so allocate one if (!req) { - DN_U64 arena_pos = DN_ArenaPos(&net->arena); + DN_U64 arena_pos = DN_MemListPos(net->arena.mem); req = DN_ArenaNew(&net->arena, DN_NETRequest, DN_ZMem_Yes); DN_NETCurlRequest *curl_req = DN_ArenaNew(&net->arena, DN_NETCurlRequest, DN_ZMem_Yes); if (!req || !curl_req) { - DN_ArenaPopTo(&net->arena, arena_pos); + DN_MemListPopTo(net->arena.mem, arena_pos); return result; } @@ -453,7 +454,7 @@ static DN_NETRequestHandle DN_NET_CurlDoRequest_(DN_NETCore *net, DN_Str8 url, D result = DN_NET_SetupRequest_(req, url, method, args, type); req->response.request = result; req->context[1] = DN_Cast(DN_UPtr) net; - curl_req->str8_builder = DN_Str8BuilderFromArena(&req->arena); + curl_req->str8_builder = DN_Str8BuilderFromArena(&req->start_response_arena); } // NOTE: Setup the request for curl API @@ -587,8 +588,8 @@ static DN_NETResponse DN_NET_CurlHandleFinishedRequest_(DN_NETCurlCore *curl, DN DN_NETCurlRequest *curl_req = DN_NET_CurlRequestFromRequest_(req); result.body = DN_Str8BuilderBuild(&curl_req->str8_builder, arena); if (result.error_str8.size) - result.error_str8 = DN_Str8FromStr8Arena(arena, result.error_str8); - curl_req->str8_builder = DN_Str8BuilderFromArena(&req->arena); + result.error_str8 = DN_Str8FromStr8Arena(result.error_str8, arena); + curl_req->str8_builder = {}; // Clear it out, reinitialised on subsequent do request call } DN_NET_EndFinishedRequest_(req); diff --git a/Source/Extra/dn_tests.cpp b/Source/Extra/dn_tests.cpp index 7239624..090ad58 100644 --- a/Source/Extra/dn_tests.cpp +++ b/Source/Extra/dn_tests.cpp @@ -1,6 +1,14 @@ #if defined(_CLANGD) #define DN_H_WITH_OS 1 #include "../dn.h" + #include "../Extra/dn_net.h" + #include "../Extra/dn_net_curl.h" + #include "../Standalone/dn_utest.h" + + #define DN_UNIT_TESTS_WITH_KECCAK + #define DN_UNIT_TESTS_WITH_NET + #define DN_UNIT_TESTS_WITH_CURL + #define DN_SHA3_IMPLEMENTATION #endif #if !defined(DN_UT_H) @@ -13,18 +21,18 @@ #include -struct DN_TestsResult +struct DN_TSTResult { bool passed; int total_tests; int total_good_tests; }; -enum DN_TestsPrint +enum DN_TSTPrint { - DN_TestsPrint_No, - DN_TestsPrint_OnFailure, - DN_TestsPrint_Yes, + DN_TSTPrint_No, + DN_TSTPrint_OnFailure, + DN_TSTPrint_Yes, }; // NOTE: Taken from MSDN __cpuid example implementation @@ -241,10 +249,10 @@ static void DN_RefImpl_CPUReportDump() // Print out supported instruction set fe #endif #endif // defined(DN_PLATFORM_WIN32) && defined(DN_COMPILER_MSVC) -static DN_UTCore DN_Tests_Base() +static DN_UTCore DN_TST_Base() { DN_UTCore result = DN_UT_Init(); - DN_UT_LogF(&result, "DN_Base\n"); + DN_UT_LogF(&result, "Base\n"); { #if defined(DN_PLATFORM_WIN32) && defined(DN_COMPILER_MSVC) DN_RefImplCPUReport ref_cpu_report = DN_RefImplCPUReport_Init(); @@ -310,24 +318,19 @@ static DN_UTCore DN_Tests_Base() } #endif // defined(DN_PLATFORM_WIN32) && defined(DN_COMPILER_MSVC) - - for (DN_UT_Test(&result, "DN_Age")) { - // NOTE: Seconds and milliseconds - { - DN_Str8x128 str8 = DN_AgeStr8FromMsU64(1001, DN_AgeUnit_Sec | DN_AgeUnit_Ms); - DN_Str8 expect = DN_Str8Lit("1s 1ms"); - DN_UT_AssertF(&result, DN_MemEq(str8.data, str8.size, expect.data, expect.size), "str8=%.*s, expect=%.*s", DN_Str8PrintFmt(str8), DN_Str8PrintFmt(expect)); - } - - // NOTE: Fractional seconds - { - DN_Str8x128 str8 = DN_AgeStr8FromMsU64(1001, DN_AgeUnit_FractionalSec); - DN_Str8 expect = DN_Str8Lit("1.001s"); - DN_UT_AssertF(&result, DN_MemEq(str8.data, str8.size, expect.data, expect.size), "str8=%.*s, expect=%.*s", DN_Str8PrintFmt(str8), DN_Str8PrintFmt(expect)); - } + for (DN_UT_Test(&result, "Age from U64: 1001 converts to 1s 1ms (seconds and ms)")) { + DN_Str8x128 str8 = DN_AgeStr8FromMsU64(1001, DN_AgeUnit_Sec | DN_AgeUnit_Ms); + DN_Str8 expect = DN_Str8Lit("1s 1ms"); + DN_UT_AssertF(&result, DN_MemEq(str8.data, str8.size, expect.data, expect.size), "str8=%.*s, expect=%.*s", DN_Str8PrintFmt(str8), DN_Str8PrintFmt(expect)); } - for (DN_UT_Test(&result, "Misc")) { + for (DN_UT_Test(&result, "Age from U64: 1001 converts to 1.001s (fractional)")) { + DN_Str8x128 str8 = DN_AgeStr8FromMsU64(1001, DN_AgeUnit_FractionalSec); + DN_Str8 expect = DN_Str8Lit("1.001s"); + DN_UT_AssertF(&result, DN_MemEq(str8.data, str8.size, expect.data, expect.size), "str8=%.*s, expect=%.*s", DN_Str8PrintFmt(str8), DN_Str8PrintFmt(expect)); + } + + for (DN_UT_Test(&result, "FmtAppendTruncate: String truncates with 3 dots")) { char buf[8] = {}; DN_USize buf_size = 0; DN_FmtAppendResult buf_str8 = DN_FmtAppendTruncate(buf, &buf_size, sizeof(buf), DN_Str8Lit("..."), "This string is longer than %d characters", DN_Cast(int)(sizeof(buf) - 1)); @@ -335,32 +338,122 @@ static DN_UTCore DN_Tests_Base() DN_UT_Assert(&result, buf_str8.truncated); DN_UT_AssertF(&result, DN_Str8Eq(buf_str8.str8, expect), "buf_str8=%.*s, expect=%.*s", DN_Str8PrintFmt(buf_str8.str8), DN_Str8PrintFmt(expect)); } + + for (DN_UT_Test(&result, "TicketMutex: Start and stop")) { + // TODO: We don't have a meaningful result but since atomics are + // implemented with a macro this ensures that we result that they are + // written correctly. + DN_TicketMutex mutex = {}; + DN_TicketMutex_Begin(&mutex); + DN_TicketMutex_End(&mutex); + DN_UT_Assert(&result, mutex.ticket == mutex.serving); + } + + for (DN_UT_Test(&result, "TicketMutex: Start and stop w/ advanced API")) { + DN_TicketMutex mutex = {}; + unsigned int ticket_a = DN_TicketMutex_MakeTicket(&mutex); + unsigned int ticket_b = DN_TicketMutex_MakeTicket(&mutex); + DN_UT_Assert(&result, DN_Cast(bool) DN_TicketMutex_CanLock(&mutex, ticket_b) == false); + DN_UT_Assert(&result, DN_Cast(bool) DN_TicketMutex_CanLock(&mutex, ticket_a) == true); + + DN_TicketMutex_BeginTicket(&mutex, ticket_a); + DN_TicketMutex_End(&mutex); + DN_TicketMutex_BeginTicket(&mutex, ticket_b); + DN_TicketMutex_End(&mutex); + + DN_UT_Assert(&result, mutex.ticket == mutex.serving); + DN_UT_Assert(&result, mutex.ticket == ticket_b + 1); + } + + // NOTE: MSVC SAL complains that we are using Interlocked functionality on + // variables it has detected as *not* being shared across threads. This is + // fine, we're just running some basic results, so permit it. + // + // Warning 28112 is a knock-on effect of this that it doesn't like us + // reading the value of the variable that has been used in an Interlocked + // function locally. + DN_MSVC_WARNING_PUSH + DN_MSVC_WARNING_DISABLE(28113) // Accessing a local variable val via an Interlocked function. + DN_MSVC_WARNING_DISABLE(28112) // A variable (val) which is accessed via an Interlocked function must always be accessed via an Interlocked function. See line 759. + { + // TODO(dn): We don't have meaningful results here, but since + // atomics/intrinsics are implemented using macros we ensure the macro was + // written properly with these results. + for (DN_UT_Test(&result, "AtomicAddU32")) { + DN_U32 val = 0; + DN_AtomicAddU32(&val, 1); + DN_UT_AssertF(&result, val == 1, "val: %u", val); + } + + for (DN_UT_Test(&result, "AtomicAddU64")) { + uint64_t val = 0; + DN_AtomicAddU64(&val, 1); + DN_UT_AssertF(&result, val == 1, "val: %" PRIu64, val); + } + + for (DN_UT_Test(&result, "AtomicSubU32")) { + DN_U32 val = 1; + DN_AtomicSubU32(&val, 1); + DN_UT_AssertF(&result, val == 0, "val: %u", val); + } + + for (DN_UT_Test(&result, "AtomicSubU64")) { + uint64_t val = 1; + DN_AtomicSubU64(&val, 1); + DN_UT_AssertF(&result, val == 0, "val: %" PRIu64, val); + } + + for (DN_UT_Test(&result, "AtomicSetValue32")) { + DN_U32 a = 0; + DN_U32 b = 111; + DN_AtomicSetValue32(&a, b); + DN_UT_AssertF(&result, a == b, "a: %ld, b: %ld", a, b); + } + + for (DN_UT_Test(&result, "AtomicSetValue64")) { + int64_t a = 0; + int64_t b = 111; + DN_AtomicSetValue64(DN_Cast(uint64_t *) & a, b); + DN_UT_AssertF(&result, a == b, "a: %" PRId64 ", b: %" PRId64, a, b); + } + + DN_UT_BeginF(&result, "CPUGetTSC: Compile check"); + DN_CPUGetTSC(); + DN_UT_End(&result); + + DN_UT_BeginF(&result, "CompilerReadBarrierAndCPUReadFence: Compile check"); + DN_CompilerReadBarrierAndCPUReadFence; + DN_UT_End(&result); + + DN_UT_BeginF(&result, "CompilerWriteBarrierAndCPUWriteFence: Compile check"); + DN_CompilerWriteBarrierAndCPUWriteFence; + DN_UT_End(&result); + } + DN_MSVC_WARNING_POP } return result; } -static DN_UTCore DN_Tests_Arena() +static DN_UTCore DN_TST_BaseArena() { DN_UTCore result = DN_UT_Init(); - DN_UT_LogF(&result, "DN_Arena\n"); + DN_UT_LogF(&result, "Arena\n"); { for (DN_UT_Test(&result, "Reused memory is zeroed out")) { - uint8_t alignment = 1; - DN_USize alloc_size = DN_Kilobytes(128); - DN_Arena arena = DN_ArenaFromVMem(0, 0, DN_ArenaFlags_Nil); - DN_DEFER - { - DN_ArenaDeinit(&arena); - }; + uint8_t alignment = 1; + DN_USize alloc_size = DN_Kilobytes(128); + DN_MemList mem = DN_MemListFromVMem(0, 0, DN_MemFlags_Nil); + DN_Arena arena = DN_ArenaFromMemList(&mem); + DN_DEFER { DN_MemListDeinit(&mem); }; // NOTE: Allocate 128 kilobytes, fill it with garbage, then reset the arena uintptr_t first_ptr_address = 0; { - DN_ArenaTempMem temp_mem = DN_ArenaTempMemBegin(&arena); - void *ptr = DN_ArenaAlloc(&arena, alloc_size, alignment, DN_ZMem_Yes); - first_ptr_address = DN_Cast(uintptr_t) ptr; + DN_Arena temp_mem = DN_ArenaTempBeginFromArena(&arena); + void *ptr = DN_ArenaAlloc(&arena, alloc_size, alignment, DN_ZMem_Yes); + first_ptr_address = DN_Cast(uintptr_t) ptr; DN_Memset(ptr, 'z', alloc_size); - DN_ArenaTempMemEnd(temp_mem); + DN_ArenaTempEnd(&temp_mem, DN_ArenaReset_Yes); } // NOTE: Reallocate 128 kilobytes @@ -376,21 +469,19 @@ static DN_UTCore DN_Tests_Arena() for (DN_UT_Test(&result, "Test arena grows naturally, 1mb + 4mb")) { // NOTE: Allocate 1mb, then 4mb, this should force the arena to grow - DN_Arena arena = DN_ArenaFromVMem(DN_Megabytes(2), DN_Megabytes(2), DN_ArenaFlags_Nil); - DN_DEFER - { - DN_ArenaDeinit(&arena); - }; + DN_MemList mem = DN_MemListFromVMem(DN_Megabytes(2), DN_Megabytes(2), DN_MemFlags_Nil); + 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); DN_UT_Assert(&result, ptr_1mb); DN_UT_Assert(&result, ptr_4mb); - DN_ArenaBlock const *block_4mb_begin = arena.curr; - char const *block_4mb_end = DN_Cast(char *) block_4mb_begin + block_4mb_begin->reserve; + DN_MemBlock const *block_4mb_begin = arena.mem->curr; + char const *block_4mb_end = DN_Cast(char *) block_4mb_begin + block_4mb_begin->reserve; - DN_ArenaBlock const *block_1mb_begin = block_4mb_begin->prev; + DN_MemBlock const *block_1mb_begin = block_4mb_begin->prev; DN_UT_AssertF(&result, block_1mb_begin, "New block should have been allocated"); char const *block_1mb_end = DN_Cast(char *) block_1mb_begin + block_1mb_begin->reserve; @@ -400,49 +491,47 @@ static DN_UTCore DN_Tests_Arena() } for (DN_UT_Test(&result, "Test arena grows naturally, 1mb, temp memory 4mb")) { - DN_Arena arena = DN_ArenaFromVMem(DN_Megabytes(2), DN_Megabytes(2), DN_ArenaFlags_Nil); - DN_DEFER - { - DN_ArenaDeinit(&arena); - }; + DN_MemList mem = DN_MemListFromVMem(DN_Megabytes(2), DN_Megabytes(2), DN_MemFlags_Nil); + DN_Arena arena = DN_ArenaFromMemList(&mem); + DN_DEFER { DN_MemListDeinit(&mem); }; // NOTE: Allocate 1mb, then 4mb, this should force the arena to grow char *ptr_1mb = DN_Cast(char *) DN_ArenaAlloc(&arena, DN_Megabytes(1), 1 /*align*/, DN_ZMem_Yes); DN_UT_Assert(&result, ptr_1mb); - DN_ArenaTempMem temp_memory = DN_ArenaTempMemBegin(&arena); + DN_Arena temp_memory = DN_ArenaTempBeginFromArena(&arena); { char *ptr_4mb = DN_ArenaNewArray(&arena, char, DN_Megabytes(4), DN_ZMem_Yes); DN_UT_Assert(&result, ptr_4mb); - DN_ArenaBlock const *block_4mb_begin = arena.curr; - char const *block_4mb_end = DN_Cast(char *) block_4mb_begin + block_4mb_begin->reserve; + DN_MemBlock const *block_4mb_begin = arena.mem->curr; + char const *block_4mb_end = DN_Cast(char *) block_4mb_begin + block_4mb_begin->reserve; - DN_ArenaBlock const *block_1mb_begin = block_4mb_begin->prev; - char const *block_1mb_end = DN_Cast(char *) block_1mb_begin + block_1mb_begin->reserve; + DN_MemBlock const *block_1mb_begin = block_4mb_begin->prev; + char const *block_1mb_end = DN_Cast(char *) block_1mb_begin + block_1mb_begin->reserve; DN_UT_AssertF(&result, block_1mb_begin != block_4mb_begin, "New block should have been allocated and linked"); DN_UT_AssertF(&result, ptr_1mb >= DN_Cast(char *) block_1mb_begin && ptr_1mb <= block_1mb_end, "Pointer was not allocated from correct memory block"); DN_UT_AssertF(&result, ptr_4mb >= DN_Cast(char *) block_4mb_begin && ptr_4mb <= block_4mb_end, "Pointer was not allocated from correct memory block"); } - DN_ArenaTempMemEnd(temp_memory); - DN_UT_Assert(&result, arena.curr->prev == nullptr); + DN_ArenaTempEnd(&temp_memory, DN_ArenaReset_Yes); + DN_UT_Assert(&result, arena.mem->curr->prev == nullptr); DN_UT_AssertF(&result, - arena.curr->reserve >= DN_Megabytes(1), + arena.mem->curr->reserve >= DN_Megabytes(1), "size=%" PRIu64 "MiB (%" PRIu64 "B), expect=%" PRIu64 "B", - (arena.curr->reserve / 1024 / 1024), - arena.curr->reserve, + (arena.mem->curr->reserve / 1024 / 1024), + arena.mem->curr->reserve, DN_Megabytes(1)); } } return result; } -static DN_UTCore DN_Tests_Bin() +static DN_UTCore DN_TST_BaseBytesHex() { DN_TCScratch scratch = DN_TCScratchBegin(nullptr, 0); - DN_UTCore test = DN_UT_Init(); - DN_UT_LogF(&test, "DN_Bin\n"); + DN_UTCore test = DN_UT_Init(); + DN_UT_LogF(&test, "Bytes <-> Hex\n"); { for (DN_UT_Test(&test, "Convert 0x123")) { uint64_t result = DN_U64FromHexStr8Unsafe(DN_Str8Lit("0x123")); @@ -502,30 +591,37 @@ static DN_UTCore DN_Tests_Bin() DN_U32 number = 0xd095f6; for (DN_UT_Test(&test, "Convert %x to string", number)) { - DN_Str8 number_hex = DN_HexFromBytesPtrArena(&number, sizeof(number), scratch.arena); + DN_Str8 number_hex = DN_HexFromPtrBytesArena(&number, sizeof(number), &scratch.arena, DN_TrimLeadingZero_No); DN_UT_AssertF(&test, DN_Str8Eq(number_hex, DN_Str8Lit("f695d000")), "number_hex=%.*s", DN_Str8PrintFmt(number_hex)); } number = 0xf6ed00; for (DN_UT_Test(&test, "Convert %x to string", number)) { - DN_Str8 number_hex = DN_HexFromBytesPtrArena(&number, sizeof(number), scratch.arena); + DN_Str8 number_hex = DN_HexFromPtrBytesArena(&number, sizeof(number), &scratch.arena, DN_TrimLeadingZero_No); DN_UT_AssertF(&test, DN_Str8Eq(number_hex, DN_Str8Lit("00edf600")), "number_hex=%.*s", DN_Str8PrintFmt(number_hex)); } DN_Str8 hex = DN_Str8Lit("0xf6ed00"); for (DN_UT_Test(&test, "Convert %.*s to bytes", DN_Str8PrintFmt(hex))) { - DN_Str8 bytes = DN_BytesFromHexArena(hex, scratch.arena); + DN_Str8 bytes = DN_BytesFromHexArena(hex, &scratch.arena); DN_UT_AssertF(&test, DN_Str8Eq(bytes, DN_Str8Lit("\xf6\xed\x00")), "number_hex=%.*s", - DN_Str8PrintFmt(DN_HexFromBytesPtrArena(bytes.data, bytes.size, scratch.arena))); + DN_Str8PrintFmt(DN_HexFromPtrBytesArena(bytes.data, bytes.size, &scratch.arena, DN_TrimLeadingZero_No))); + } + + for (DN_UT_Test(&test, "Convert empty bytes to string", number)) { + DN_Str8 bytes = DN_Str8Lit(""); + DN_Str8 as_hex = DN_HexFromPtrBytesArena(bytes.data, bytes.size, &scratch.arena, DN_TrimLeadingZero_No); + DN_UT_AssertF(&test, DN_Str8Eq(as_hex, DN_Str8Lit("")), "as_hex=%.*s", DN_Str8PrintFmt(as_hex)); } } DN_TCScratchEnd(&scratch); return test; } -static DN_UTCore DN_Tests_BinarySearch() +#if DN_H_WITH_HELPERS +static DN_UTCore DN_TST_BinarySearch() { DN_UTCore result = DN_UT_Init(); DN_UT_LogF(&result, "DN_BinarySearch\n"); @@ -832,17 +928,18 @@ static DN_UTCore DN_Tests_BinarySearch() } return result; } +#endif // DN_H_WITH_HELPERS -static DN_UTCore DN_Tests_BaseContainers() +static DN_UTCore DN_TST_BaseDSMap() { DN_UTCore result = DN_UT_Init(); - DN_UT_LogF(&result, "DN_DSMap\n"); { DN_TCScratch scratch = DN_TCScratchBegin(nullptr, 0); { - DN_Arena arena = DN_ArenaFromVMem(0, 0, DN_ArenaFlags_Nil); - DN_U32 const MAP_SIZE = 64; + DN_MemList mem = DN_MemListFromVMem(0, 0, DN_MemFlags_Nil); + DN_Arena arena = DN_ArenaFromMemList(&mem); + DN_U32 const MAP_SIZE = 64; DN_DSMap map = DN_DSMapInit(&arena, MAP_SIZE, DN_DSMapFlags_Nil); DN_DEFER { @@ -893,10 +990,10 @@ static DN_UTCore DN_Tests_BaseContainers() case DSMapTestType_MakeSlot: prefix = DN_Str8Lit("Make slot"); break; } - DN_ArenaTempMemScope temp_mem_scope = DN_ArenaTempMemScope(scratch.arena); - DN_Arena arena = DN_ArenaFromVMem(0, 0, DN_ArenaFlags_Nil); - DN_U32 const MAP_SIZE = 64; - DN_DSMap map = DN_DSMapInit(&arena, MAP_SIZE, DN_DSMapFlags_Nil); + DN_MemList mem = DN_MemListFromVMem(0, 0, DN_MemFlags_Nil); + DN_Arena arena = DN_ArenaFromMemList(&mem); + DN_U32 const MAP_SIZE = 64; + DN_DSMap map = DN_DSMapInit(&arena, MAP_SIZE, DN_DSMapFlags_Nil); DN_DEFER { DN_DSMapDeinit(&map, DN_ZMem_Yes); @@ -1026,7 +1123,12 @@ static DN_UTCore DN_Tests_BaseContainers() } DN_TCScratchEnd(&scratch); } + return result; +} +static DN_UTCore DN_TST_BaseIArray() +{ + DN_UTCore result = DN_UT_Init(); DN_UT_LogF(&result, "DN_IArray\n"); { struct CustomArray @@ -1046,8 +1148,13 @@ static DN_UTCore DN_Tests_BaseContainers() DN_UT_Assert(&result, item && array.size == 1); } } + return result; +} - DN_UT_LogF(&result, "DN_CArray2"); +static DN_UTCore DN_TST_BaseCArray2() +{ + DN_UTCore result = DN_UT_Init(); + DN_UT_LogF(&result, "DN_CArray2\n"); { for (DN_UT_Test(&result, "Positive count, middle of array, stable erase")) { int arr[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; @@ -1172,7 +1279,12 @@ static DN_UTCore DN_Tests_BaseContainers() DN_UT_Assert(&result, DN_Memcmp(arr, expected, size * sizeof(arr[0])) == 0); } } + return result; +} +static DN_UTCore DN_TST_BaseVArray() +{ + DN_UTCore result = DN_UT_Init(); DN_UT_LogF(&result, "DN_VArray\n"); { { @@ -1320,82 +1432,6 @@ static DN_UTCore DN_Tests_BaseContainers() return result; } -static DN_UTCore DN_Tests_Intrinsics() -{ - DN_UTCore result = DN_UT_Init(); - // TODO(dn): We don't have meaningful results here, but since - // atomics/intrinsics are implemented using macros we ensure the macro was - // written properly with these results. - - DN_MSVC_WARNING_PUSH - - // NOTE: MSVC SAL complains that we are using Interlocked functionality on - // variables it has detected as *not* being shared across threads. This is - // fine, we're just running some basic results, so permit it. - // - // Warning 28112 is a knock-on effect of this that it doesn't like us - // reading the value of the variable that has been used in an Interlocked - // function locally. - DN_MSVC_WARNING_DISABLE(28113) // Accessing a local variable val via an Interlocked function. - DN_MSVC_WARNING_DISABLE(28112) // A variable (val) which is accessed via an Interlocked function must always be accessed via an Interlocked function. See line 759. - - DN_UT_LogF(&result, "DN_Atomic\n"); - { - for (DN_UT_Test(&result, "DN_AtomicAddU32")) { - DN_U32 val = 0; - DN_AtomicAddU32(&val, 1); - DN_UT_AssertF(&result, val == 1, "val: %u", val); - } - - for (DN_UT_Test(&result, "DN_AtomicAddU64")) { - uint64_t val = 0; - DN_AtomicAddU64(&val, 1); - DN_UT_AssertF(&result, val == 1, "val: %" PRIu64, val); - } - - for (DN_UT_Test(&result, "DN_AtomicSubU32")) { - DN_U32 val = 1; - DN_AtomicSubU32(&val, 1); - DN_UT_AssertF(&result, val == 0, "val: %u", val); - } - - for (DN_UT_Test(&result, "DN_AtomicSubU64")) { - uint64_t val = 1; - DN_AtomicSubU64(&val, 1); - DN_UT_AssertF(&result, val == 0, "val: %" PRIu64, val); - } - - for (DN_UT_Test(&result, "DN_AtomicSetValue32")) { - DN_U32 a = 0; - DN_U32 b = 111; - DN_AtomicSetValue32(&a, b); - DN_UT_AssertF(&result, a == b, "a: %ld, b: %ld", a, b); - } - - for (DN_UT_Test(&result, "DN_AtomicSetValue64")) { - int64_t a = 0; - int64_t b = 111; - DN_AtomicSetValue64(DN_Cast(uint64_t *) & a, b); - DN_UT_AssertF(&result, a == b, "a: %" PRId64 ", b: %" PRId64, a, b); - } - - DN_UT_BeginF(&result, "DN_CPUGetTSC"); - DN_CPUGetTSC(); - DN_UT_End(&result); - - DN_UT_BeginF(&result, "DN_CompilerReadBarrierAndCPUReadFence"); - DN_CompilerReadBarrierAndCPUReadFence; - DN_UT_End(&result); - - DN_UT_BeginF(&result, "DN_CompilerWriteBarrierAndCPUWriteFence"); - DN_CompilerWriteBarrierAndCPUWriteFence; - DN_UT_End(&result); - } - DN_MSVC_WARNING_POP - - return result; -} - #if defined(DN_UNIT_TESTS_WITH_KECCAK) DN_GCC_WARNING_PUSH DN_GCC_WARNING_DISABLE(-Wunused-parameter) @@ -1405,13 +1441,11 @@ DN_MSVC_WARNING_PUSH DN_MSVC_WARNING_DISABLE(4244) DN_MSVC_WARNING_DISABLE(4100) DN_MSVC_WARNING_DISABLE(6385) -// NOTE: Keccak Reference Implementation /////////////////////////////////////////////////////////// +// NOTE: Keccak Reference Implementation // A very compact Keccak implementation taken from the reference implementation // repository -// // https://github.com/XKCP/XKCP/blob/master/Standalone/CompactFIPS202/C/Keccak-more-compact.c - - #define FOR(i, n) for (i = 0; i < n; ++i) +#define FOR(i, n) for (i = 0; i < n; ++i) void DN_RefImpl_Keccak_(int r, int c, const uint8_t *in, uint64_t inLen, uint8_t sfx, uint8_t *out, uint64_t outLen); void DN_RefImpl_FIPS202_SHAKE128_(const uint8_t *in, uint64_t inLen, uint8_t *out, uint64_t outLen) @@ -1581,7 +1615,7 @@ DN_GCC_WARNING_POP DN_UT_HASH_X_ENTRY(Keccak_512, "Keccak-512") \ DN_UT_HASH_X_ENTRY(Count, "Keccak-512") -enum DN_Tests__HashType +enum DN_TST__HashType { #define DN_UT_HASH_X_ENTRY(enum_val, string) Hash_##enum_val, @@ -1596,10 +1630,10 @@ DN_Str8 const DN_UT_HASH_STRING_[] = #undef DN_UT_HASH_X_ENTRY }; -void DN_Tests_KeccakDispatch_(DN_UTCore *test, int hash_type, DN_Str8 input) +void DN_TST_KeccakDispatch_(DN_UTCore *test, int hash_type, DN_Str8 input) { DN_TCScratch scratch = DN_TCScratchBegin(nullptr, 0); - DN_Str8 input_hex = DN_HexFromBytesPtrArena(input.data, input.size, scratch.arena); + DN_Str8 input_hex = DN_HexFromPtrBytesArena(input.data, input.size, &scratch.arena, DN_TrimLeadingZero_No); switch (hash_type) { case Hash_SHA3_224: { @@ -1607,8 +1641,8 @@ void DN_Tests_KeccakDispatch_(DN_UTCore *test, int hash_type, DN_Str8 input) DN_SHA3U8x28 expect; DN_RefImpl_FIPS202_SHA3_224_(DN_Cast(uint8_t *) input.data, input.size, (uint8_t *)expect.data); - DN_Str8 hash_hex = DN_HexFromBytesPtrArena(hash.data, DN_ArrayCountU(hash.data), scratch.arena); - DN_Str8 expect_hex = DN_HexFromBytesPtrArena(expect.data, DN_ArrayCountU(expect.data), scratch.arena); + DN_Str8 hash_hex = DN_HexFromPtrBytesArena(hash.data, DN_ArrayCountU(hash.data), &scratch.arena, DN_TrimLeadingZero_No); + DN_Str8 expect_hex = DN_HexFromPtrBytesArena(expect.data, DN_ArrayCountU(expect.data), &scratch.arena, DN_TrimLeadingZero_No); DN_UT_AssertF(test, DN_MemEq(hash.data, sizeof(hash.data), expect.data, sizeof(expect.data)), "\ninput: %.*s" @@ -1624,8 +1658,8 @@ void DN_Tests_KeccakDispatch_(DN_UTCore *test, int hash_type, DN_Str8 input) DN_SHA3U8x32 expect; DN_RefImpl_FIPS202_SHA3_256_(DN_Cast(uint8_t *) input.data, input.size, (uint8_t *)expect.data); - DN_Str8 hash_hex = DN_HexFromBytesPtrArena(hash.data, DN_ArrayCountU(hash.data), scratch.arena); - DN_Str8 expect_hex = DN_HexFromBytesPtrArena(expect.data, DN_ArrayCountU(expect.data), scratch.arena); + DN_Str8 hash_hex = DN_HexFromPtrBytesArena(hash.data, DN_ArrayCountU(hash.data), &scratch.arena, DN_TrimLeadingZero_No); + DN_Str8 expect_hex = DN_HexFromPtrBytesArena(expect.data, DN_ArrayCountU(expect.data), &scratch.arena, DN_TrimLeadingZero_No); DN_UT_AssertF(test, DN_MemEq(hash.data, sizeof(hash.data), expect.data, sizeof(expect.data)), "\ninput: %.*s" @@ -1641,8 +1675,8 @@ void DN_Tests_KeccakDispatch_(DN_UTCore *test, int hash_type, DN_Str8 input) DN_SHA3U8x48 expect; DN_RefImpl_FIPS202_SHA3_384_(DN_Cast(uint8_t *) input.data, input.size, (uint8_t *)expect.data); - DN_Str8 hash_hex = DN_HexFromBytesPtrArena(hash.data, DN_ArrayCountU(hash.data), scratch.arena); - DN_Str8 expect_hex = DN_HexFromBytesPtrArena(expect.data, DN_ArrayCountU(expect.data), scratch.arena); + DN_Str8 hash_hex = DN_HexFromPtrBytesArena(hash.data, DN_ArrayCountU(hash.data), &scratch.arena, DN_TrimLeadingZero_No); + DN_Str8 expect_hex = DN_HexFromPtrBytesArena(expect.data, DN_ArrayCountU(expect.data), &scratch.arena, DN_TrimLeadingZero_No); DN_UT_AssertF(test, DN_MemEq(hash.data, sizeof(hash.data), expect.data, sizeof(expect.data)), "\ninput: %.*s" @@ -1658,8 +1692,8 @@ void DN_Tests_KeccakDispatch_(DN_UTCore *test, int hash_type, DN_Str8 input) DN_SHA3U8x64 expect; DN_RefImpl_FIPS202_SHA3_512_(DN_Cast(uint8_t *) input.data, input.size, (uint8_t *)expect.data); - DN_Str8 hash_hex = DN_HexFromBytesPtrArena(hash.data, DN_ArrayCountU(hash.data), scratch.arena); - DN_Str8 expect_hex = DN_HexFromBytesPtrArena(expect.data, DN_ArrayCountU(expect.data), scratch.arena); + DN_Str8 hash_hex = DN_HexFromPtrBytesArena(hash.data, DN_ArrayCountU(hash.data), &scratch.arena, DN_TrimLeadingZero_No); + DN_Str8 expect_hex = DN_HexFromPtrBytesArena(expect.data, DN_ArrayCountU(expect.data), &scratch.arena, DN_TrimLeadingZero_No); DN_UT_AssertF(test, DN_MemEq(hash.data, sizeof(hash.data), expect.data, sizeof(expect.data)), "\ninput: %.*s" @@ -1675,8 +1709,8 @@ void DN_Tests_KeccakDispatch_(DN_UTCore *test, int hash_type, DN_Str8 input) DN_SHA3U8x28 expect; DN_RefImpl_Keccak_(1152, 448, DN_Cast(uint8_t *) input.data, input.size, 0x01, (uint8_t *)expect.data, sizeof(expect)); - DN_Str8 hash_hex = DN_HexFromBytesPtrArena(hash.data, DN_ArrayCountU(hash.data), scratch.arena); - DN_Str8 expect_hex = DN_HexFromBytesPtrArena(expect.data, DN_ArrayCountU(expect.data), scratch.arena); + DN_Str8 hash_hex = DN_HexFromPtrBytesArena(hash.data, DN_ArrayCountU(hash.data), &scratch.arena, DN_TrimLeadingZero_No); + DN_Str8 expect_hex = DN_HexFromPtrBytesArena(expect.data, DN_ArrayCountU(expect.data), &scratch.arena, DN_TrimLeadingZero_No); DN_UT_AssertF(test, DN_MemEq(hash.data, sizeof(hash.data), expect.data, sizeof(expect.data)), "\ninput: %.*s" @@ -1692,8 +1726,8 @@ void DN_Tests_KeccakDispatch_(DN_UTCore *test, int hash_type, DN_Str8 input) DN_SHA3U8x32 expect; DN_RefImpl_Keccak_(1088, 512, DN_Cast(uint8_t *) input.data, input.size, 0x01, (uint8_t *)expect.data, sizeof(expect)); - DN_Str8 hash_hex = DN_HexFromBytesPtrArena(hash.data, DN_ArrayCountU(hash.data), scratch.arena); - DN_Str8 expect_hex = DN_HexFromBytesPtrArena(expect.data, DN_ArrayCountU(expect.data), scratch.arena); + DN_Str8 hash_hex = DN_HexFromPtrBytesArena(hash.data, DN_ArrayCountU(hash.data), &scratch.arena, DN_TrimLeadingZero_No); + DN_Str8 expect_hex = DN_HexFromPtrBytesArena(expect.data, DN_ArrayCountU(expect.data), &scratch.arena, DN_TrimLeadingZero_No); DN_UT_AssertF(test, DN_MemEq(hash.data, sizeof(hash.data), expect.data, sizeof(expect.data)), "\ninput: %.*s" @@ -1709,8 +1743,8 @@ void DN_Tests_KeccakDispatch_(DN_UTCore *test, int hash_type, DN_Str8 input) DN_SHA3U8x48 expect; DN_RefImpl_Keccak_(832, 768, DN_Cast(uint8_t *) input.data, input.size, 0x01, (uint8_t *)expect.data, sizeof(expect)); - DN_Str8 hash_hex = DN_HexFromBytesPtrArena(hash.data, DN_ArrayCountU(hash.data), scratch.arena); - DN_Str8 expect_hex = DN_HexFromBytesPtrArena(expect.data, DN_ArrayCountU(expect.data), scratch.arena); + DN_Str8 hash_hex = DN_HexFromPtrBytesArena(hash.data, DN_ArrayCountU(hash.data), &scratch.arena, DN_TrimLeadingZero_No); + DN_Str8 expect_hex = DN_HexFromPtrBytesArena(expect.data, DN_ArrayCountU(expect.data), &scratch.arena, DN_TrimLeadingZero_No); DN_UT_AssertF(test, DN_MemEq(hash.data, sizeof(hash.data), expect.data, sizeof(expect.data)), "\ninput: %.*s" @@ -1726,8 +1760,8 @@ void DN_Tests_KeccakDispatch_(DN_UTCore *test, int hash_type, DN_Str8 input) DN_SHA3U8x64 expect; DN_RefImpl_Keccak_(576, 1024, DN_Cast(uint8_t *) input.data, input.size, 0x01, (uint8_t *)expect.data, sizeof(expect)); - DN_Str8 hash_hex = DN_HexFromBytesPtrArena(hash.data, DN_ArrayCountU(hash.data), scratch.arena); - DN_Str8 expect_hex = DN_HexFromBytesPtrArena(expect.data, DN_ArrayCountU(expect.data), scratch.arena); + DN_Str8 hash_hex = DN_HexFromPtrBytesArena(hash.data, DN_ArrayCountU(hash.data), &scratch.arena, DN_TrimLeadingZero_No); + DN_Str8 expect_hex = DN_HexFromPtrBytesArena(expect.data, DN_ArrayCountU(expect.data), &scratch.arena, DN_TrimLeadingZero_No); DN_UT_AssertF(test, DN_MemEq(hash.data, sizeof(hash.data), expect.data, sizeof(expect.data)), "\ninput: %.*s" @@ -1742,7 +1776,7 @@ void DN_Tests_KeccakDispatch_(DN_UTCore *test, int hash_type, DN_Str8 input) } #endif // defined(DN_UNIT_TESTS_WITH_KECCAK) -DN_UTCore DN_Tests_Keccak() +DN_UTCore DN_TST_Keccak() { DN_UTCore result = DN_UT_Init(); #if defined(DN_UNIT_TESTS_WITH_KECCAK) @@ -1760,7 +1794,7 @@ DN_UTCore DN_Tests_Keccak() DN_PCG32 rng = DN_PCG32Init(0xd48e'be21'2af8'733d); for (DN_Str8 input : INPUTS) { DN_UT_BeginF(&result, "%.*s - Input: %.*s", DN_Str8PrintFmt(DN_UT_HASH_STRING_[hash_type]), DN_Cast(int) DN_Min(input.size, 54), input.data); - DN_Tests_KeccakDispatch_(&result, hash_type, input); + DN_TST_KeccakDispatch_(&result, hash_type, input); DN_UT_End(&result); } @@ -1773,7 +1807,7 @@ DN_UTCore DN_Tests_Keccak() src[src_index] = DN_Cast(char) DN_PCG32Range(&rng, 0, 255); DN_Str8 input = DN_Str8FromPtr(src, src_size); - DN_Tests_KeccakDispatch_(&result, hash_type, input); + DN_TST_KeccakDispatch_(&result, hash_type, input); } DN_UT_End(&result); } @@ -1782,7 +1816,7 @@ DN_UTCore DN_Tests_Keccak() return result; } -static DN_UTCore DN_Tests_M4() +static DN_UTCore DN_TST_M4() { DN_UTCore result = DN_UT_Init(); DN_UT_LogF(&result, "DN_M4\n"); @@ -1811,7 +1845,7 @@ static DN_UTCore DN_Tests_M4() return result; } -static DN_UTCore DN_Tests_OS() +static DN_UTCore DN_TST_OS() { DN_UTCore result = DN_UT_Init(); @@ -1827,7 +1861,7 @@ static DN_UTCore DN_Tests_OS() for (DN_UT_Test(&result, "Query executable directory")) { DN_TCScratch scratch = DN_TCScratchBegin(nullptr, 0); - DN_Str8 os_result = DN_OS_EXEDir(scratch.arena); + DN_Str8 os_result = DN_OS_EXEDir(&scratch.arena); DN_UT_Assert(&result, os_result.size); DN_UT_AssertF(&result, DN_OS_PathIsDir(os_result), "result(%zu): %.*s", os_result.size, DN_Str8PrintFmt(os_result)); DN_TCScratchEnd(&scratch); @@ -1878,7 +1912,7 @@ static DN_UTCore DN_Tests_OS() // NOTE: Read step DN_TCScratch scratch = DN_TCScratchBegin(nullptr, 0); - DN_Str8 read_file = DN_OS_FileReadAllArena(scratch.arena, SRC_FILE, nullptr); + DN_Str8 read_file = DN_OS_FileReadAllArena(&scratch.arena, SRC_FILE, nullptr); DN_UT_AssertF(&result, read_file.size, "Failed to load file"); DN_UT_AssertF(&result, read_file.size == 4, "File read wrong amount of bytes (%zu)", read_file.size); DN_UT_AssertF(&result, DN_Str8Eq(read_file, DN_Str8Lit("1234")), "Read %zu bytes instead of the expected 4: '%.*s'", read_file.size, DN_Str8PrintFmt(read_file)); @@ -1962,7 +1996,7 @@ static DN_UTCore DN_Tests_OS() return result; } -static DN_UTCore DN_Tests_Rect() +static DN_UTCore DN_TST_Rect() { DN_UTCore result = DN_UT_Init(); DN_UT_LogF(&result, "DN_Rect\n"); @@ -2090,10 +2124,10 @@ static DN_UTCore DN_Tests_Rect() return result; } -static DN_UTCore DN_Tests_Str8() +static DN_UTCore DN_TST_BaseStrings() { DN_UTCore result = DN_UT_Init(); - DN_UT_LogF(&result, "DN_Str8\n"); + DN_UT_LogF(&result, "Strings\n"); { for (DN_UT_Test(&result, "Str8 literal")) { DN_Str8 string = DN_Str8Lit("AB"); @@ -2109,17 +2143,19 @@ static DN_UTCore DN_Tests_Str8() char arena_base[512]; for (DN_UT_Test(&result, "Str8 format from arena")) { - DN_Arena arena = DN_ArenaFromBuffer(arena_base, sizeof(arena_base), DN_ArenaFlags_Nil); + DN_MemList mem = DN_MemListFromBuffer(arena_base, sizeof(arena_base), DN_MemFlags_Nil); + DN_Arena arena = DN_ArenaFromMemList(&mem); DN_Str8 str8 = DN_Str8FromFmtArena(&arena, "Foo Bar %d", 5); DN_Str8 expect = DN_Str8Lit("Foo Bar 5"); DN_UT_AssertF(&result, DN_Str8Eq(str8, expect), "str8=%.*s", DN_Str8PrintFmt(str8), DN_Str8PrintFmt(expect)); } for (DN_UT_Test(&result, "Str8 format from pool")) { - DN_Arena arena = DN_ArenaFromBuffer(arena_base, sizeof(arena_base), DN_ArenaFlags_Nil); - DN_Pool pool = DN_PoolFromArena(&arena, 0); - DN_Str8 str8 = DN_Str8FromFmtPool(&pool, "Foo Bar %d", 5); - DN_Str8 expect = DN_Str8Lit("Foo Bar 5"); + 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_Str8FromFmtPool(&pool, "Foo Bar %d", 5); + DN_Str8 expect = DN_Str8Lit("Foo Bar 5"); DN_UT_AssertF(&result, DN_Str8Eq(str8, expect), "str8=%.*s", DN_Str8PrintFmt(str8), DN_Str8PrintFmt(expect)); } @@ -2131,7 +2167,7 @@ static DN_UTCore DN_Tests_Str8() for (DN_UT_Test(&result, "Initialise with format string")) { DN_TCScratch scratch = DN_TCScratchBegin(nullptr, 0); - DN_Str8 string = DN_Str8FromFmtArena(scratch.arena, "%s", "AB"); + DN_Str8 string = DN_Str8FromFmtArena(&scratch.arena, "%s", "AB"); DN_UT_AssertF(&result, string.size == 2, "size: %zu", string.size); DN_UT_AssertF(&result, string.data[0] == 'A', "string[0]: %c", string.data[0]); DN_UT_AssertF(&result, string.data[1] == 'B', "string[1]: %c", string.data[1]); @@ -2142,7 +2178,7 @@ static DN_UTCore DN_Tests_Str8() for (DN_UT_Test(&result, "Copy string")) { DN_TCScratch scratch = DN_TCScratchBegin(nullptr, 0); DN_Str8 string = DN_Str8Lit("AB"); - DN_Str8 copy = DN_Str8FromStr8Arena(scratch.arena, string); + DN_Str8 copy = DN_Str8FromStr8Arena(string, &scratch.arena); DN_UT_AssertF(&result, copy.size == 2, "size: %zu", copy.size); DN_UT_AssertF(&result, copy.data[0] == 'A', "copy[0]: %c", copy.data[0]); DN_UT_AssertF(&result, copy.data[1] == 'B', "copy[1]: %c", copy.data[1]); @@ -2157,7 +2193,7 @@ static DN_UTCore DN_Tests_Str8() for (DN_UT_Test(&result, "Allocate string from arena")) { DN_TCScratch scratch = DN_TCScratchBegin(nullptr, 0); - DN_Str8 string = DN_Str8AllocArena(scratch.arena, 2, DN_ZMem_No); + DN_Str8 string = DN_Str8AllocArena(2, DN_ZMem_No, &scratch.arena); DN_UT_AssertF(&result, string.size == 2, "size: %zu", string.size); DN_TCScratchEnd(&scratch); } @@ -2390,45 +2426,126 @@ static DN_UTCore DN_Tests_Str8() DN_Str8 str_result = DN_Str8TrimPrefix(buf, prefix, DN_Str8EqCase_Sensitive); DN_UT_Assert(&result, DN_Str8Eq(str_result, DN_Str8Lit("string"))); } - } - return result; -} -static DN_UTCore DN_Tests_TicketMutex() -{ - DN_UTCore result = DN_UT_Init(); - DN_UT_LogF(&result, "DN_TicketMutex\n"); - { - for (DN_UT_Test(&result, "Ticket mutex start and stop")) { - // TODO: We don't have a meaningful result but since atomics are - // implemented with a macro this ensures that we result that they are - // written correctly. - DN_TicketMutex mutex = {}; - DN_TicketMutex_Begin(&mutex); - DN_TicketMutex_End(&mutex); - DN_UT_Assert(&result, mutex.ticket == mutex.serving); - } + // NOTE: DN_Str8TruncMiddle + { + for (DN_UT_Test(&result, "TruncMiddlePtr: Short string is not truncated")) { + DN_Str8 str = DN_Str8Lit("Hello"); + DN_Str8 trunc = DN_Str8Lit("..."); + char dest[64] = {}; + DN_Str8TruncResult res = DN_Str8TruncMiddlePtr(str, 5, trunc, dest, sizeof(dest)); + DN_UT_Assert(&result, !res.truncated); + DN_UT_Assert(&result, res.size_req == 5); + DN_UT_AssertF(&result, DN_Str8Eq(res.str8, DN_Str8Lit("Hello")), "%.*s", DN_Str8PrintFmt(res.str8)); + } - for (DN_UT_Test(&result, "Ticket mutex start and stop w/ advanced API")) { - DN_TicketMutex mutex = {}; - unsigned int ticket_a = DN_TicketMutex_MakeTicket(&mutex); - unsigned int ticket_b = DN_TicketMutex_MakeTicket(&mutex); - DN_UT_Assert(&result, DN_Cast(bool) DN_TicketMutex_CanLock(&mutex, ticket_b) == false); - DN_UT_Assert(&result, DN_Cast(bool) DN_TicketMutex_CanLock(&mutex, ticket_a) == true); + for (DN_UT_Test(&result, "TruncMiddlePtr: Exact boundary (2*side_size) is not truncated")) { + DN_Str8 str = DN_Str8Lit("HelloWorld"); // 10 chars + DN_Str8 trunc = DN_Str8Lit("..."); + char dest[64] = {}; + DN_Str8TruncResult res = DN_Str8TruncMiddlePtr(str, 5, trunc, dest, sizeof(dest)); + DN_UT_Assert(&result, !res.truncated); + DN_UT_Assert(&result, res.size_req == 10); + DN_UT_AssertF(&result, DN_Str8Eq(res.str8, DN_Str8Lit("HelloWorld")), "%.*s", DN_Str8PrintFmt(res.str8)); + } - DN_TicketMutex_BeginTicket(&mutex, ticket_a); - DN_TicketMutex_End(&mutex); - DN_TicketMutex_BeginTicket(&mutex, ticket_b); - DN_TicketMutex_End(&mutex); + for (DN_UT_Test(&result, "TruncMiddlePtr: Long string is truncated in the middle")) { + DN_Str8 str = DN_Str8Lit("HelloBeautifulWorld"); + DN_Str8 trunc = DN_Str8Lit("..."); + char dest[64] = {}; + DN_Str8TruncResult res = DN_Str8TruncMiddlePtr(str, 5, trunc, dest, sizeof(dest)); + DN_UT_Assert(&result, res.truncated); + DN_UT_Assert(&result, res.size_req == 13); // 5 + 3 + 5 + DN_UT_AssertF(&result, DN_Str8Eq(res.str8, DN_Str8Lit("Hello...World")), "%.*s", DN_Str8PrintFmt(res.str8)); + } - DN_UT_Assert(&result, mutex.ticket == mutex.serving); - DN_UT_Assert(&result, mutex.ticket == ticket_b + 1); + for (DN_UT_Test(&result, "TruncMiddlePtr: Empty truncator concatenates head and tail")) { + DN_Str8 str = DN_Str8Lit("HelloBeautifulWorld"); + DN_Str8 trunc = DN_Str8Lit(""); + char dest[64] = {}; + DN_Str8TruncResult res = DN_Str8TruncMiddlePtr(str, 5, trunc, dest, sizeof(dest)); + DN_UT_Assert(&result, res.truncated); + DN_UT_Assert(&result, res.size_req == 10); // 5 + 0 + 5 + DN_UT_AssertF(&result, DN_Str8Eq(res.str8, DN_Str8Lit("HelloWorld")), "%.*s", DN_Str8PrintFmt(res.str8)); + } + + for (DN_UT_Test(&result, "TruncMiddlePtr: side_size of 0 returns just truncator")) { + DN_Str8 str = DN_Str8Lit("HelloWorld"); + DN_Str8 trunc = DN_Str8Lit("..."); + char dest[64] = {}; + DN_Str8TruncResult res = DN_Str8TruncMiddlePtr(str, 0, trunc, dest, sizeof(dest)); + DN_UT_Assert(&result, res.truncated); + DN_UT_Assert(&result, res.size_req == 3); + DN_UT_AssertF(&result, DN_Str8Eq(res.str8, DN_Str8Lit("...")), "%.*s", DN_Str8PrintFmt(res.str8)); + } + + for (DN_UT_Test(&result, "TruncMiddlePtr: Null dest calculates size without writing")) { + DN_Str8 str = DN_Str8Lit("HelloBeautifulWorld"); + DN_Str8 trunc = DN_Str8Lit("..."); + DN_Str8TruncResult res = DN_Str8TruncMiddlePtr(str, 5, trunc, nullptr, 0); + DN_UT_Assert(&result, res.truncated); + DN_UT_Assert(&result, res.size_req == 13); + DN_UT_Assert(&result, res.str8.data == nullptr); + } + + for (DN_UT_Test(&result, "TruncMiddlePtr: size_req is consistent between dry-run and actual")) { + DN_Str8 str = DN_Str8Lit("HelloBeautifulWorld"); + DN_Str8 trunc = DN_Str8Lit("..."); + DN_Str8TruncResult dry = DN_Str8TruncMiddlePtr(str, 5, trunc, nullptr, 0); + char dest[64] = {}; + DN_Str8TruncResult actual = DN_Str8TruncMiddlePtr(str, 5, trunc, dest, sizeof(dest)); + DN_UT_Assert(&result, dry.size_req == actual.size_req); + DN_UT_Assert(&result, dry.truncated == actual.truncated); + } + + for (DN_UT_Test(&result, "TruncMiddlePtr: Minimum buffer size (2*side_size + trunc.size + 1) is sufficient")) { + DN_Str8 str = DN_Str8Lit("HelloBeautifulWorld"); + DN_Str8 trunc = DN_Str8Lit("..."); + char dest[14] = {}; // Exactly 2*5 + 3 + 1 + DN_Str8TruncResult res = DN_Str8TruncMiddlePtr(str, 5, trunc, dest, sizeof(dest)); + DN_UT_Assert(&result, res.truncated); + DN_UT_Assert(&result, res.size_req == 13); + DN_UT_AssertF(&result, DN_Str8Eq(res.str8, DN_Str8Lit("Hello...World")), "%.*s", DN_Str8PrintFmt(res.str8)); + } + + for (DN_UT_Test(&result, "TruncMiddlePtr: Single character side size")) { + DN_Str8 str = DN_Str8Lit("HelloBeautifulWorld"); + DN_Str8 trunc = DN_Str8Lit("..."); + char dest[64] = {}; + DN_Str8TruncResult res = DN_Str8TruncMiddlePtr(str, 1, trunc, dest, sizeof(dest)); + DN_UT_Assert(&result, res.truncated); + DN_UT_Assert(&result, res.size_req == 5); // 1 + 3 + 1 + DN_UT_AssertF(&result, DN_Str8Eq(res.str8, DN_Str8Lit("H...d")), "%.*s", DN_Str8PrintFmt(res.str8)); + } + + for (DN_UT_Test(&result, "TruncMiddlePtr: Large side_size falls back to copy")) { + DN_Str8 str = DN_Str8Lit("Hello"); + DN_Str8 trunc = DN_Str8Lit("..."); + char dest[64] = {}; + DN_Str8TruncResult res = DN_Str8TruncMiddlePtr(str, 100, trunc, dest, sizeof(dest)); + DN_UT_Assert(&result, !res.truncated); + DN_UT_Assert(&result, res.size_req == 5); + DN_UT_AssertF(&result, DN_Str8Eq(res.str8, DN_Str8Lit("Hello")), "%.*s", DN_Str8PrintFmt(res.str8)); + } + + // NOTE: DN_Str8TruncMiddle (arena wrapper) + for (DN_UT_Test(&result, "TruncMiddle: Arena wrapper allocates and truncates correctly")) { + DN_TCScratch scratch = DN_TCScratchBegin(nullptr, 0); + DN_Str8 str = DN_Str8Lit("HelloBeautifulWorld"); + DN_Str8 trunc = DN_Str8Lit("..."); + DN_Str8TruncResult res = DN_Str8TruncMiddle(str, 5, trunc, &scratch.arena); + DN_UT_Assert(&result, res.truncated); + DN_UT_Assert(&result, res.size_req == 13); + DN_UT_AssertF(&result, DN_Str8Eq(res.str8, DN_Str8Lit("Hello...World")), "%.*s", DN_Str8PrintFmt(res.str8)); + DN_UT_Assert(&result, res.str8.data[res.str8.size] == '\0'); + DN_TCScratchEnd(&scratch); + } } } return result; } -static DN_UTCore DN_Tests_Win() +static DN_UTCore DN_TST_Win() { DN_UTCore result = DN_UT_Init(); #if defined(DN_PLATFORM_WIN32) @@ -2439,18 +2556,18 @@ static DN_UTCore DN_Tests_Win() DN_Str16 input16 = DN_Str16{(wchar_t *)(L"String"), sizeof(L"String") / sizeof(L"String"[0]) - 1}; for (DN_UT_Test(&result, "Str8 to Str16")) { - DN_Str16 str_result = DN_OS_W32Str8ToStr16(scratch.arena, input8); + DN_Str16 str_result = DN_OS_W32Str8ToStr16(&scratch.arena, input8); DN_UT_Assert(&result, DN_Str16Eq(str_result, input16)); } for (DN_UT_Test(&result, "Str16 to Str8")) { - DN_Str8 str_result = DN_OS_W32Str16ToStr8(scratch.arena, input16); + DN_Str8 str_result = DN_OS_W32Str16ToStr8(&scratch.arena, input16); DN_UT_Assert(&result, DN_Str8Eq(str_result, input8)); } for (DN_UT_Test(&result, "Str16 to Str8: Null terminates string")) { int size_required = DN_OS_W32Str16ToStr8Buffer(input16, nullptr, 0); - char *string = DN_ArenaNewArray(scratch.arena, char, size_required + 1, DN_ZMem_No); + char *string = DN_ArenaNewArray(&scratch.arena, char, size_required + 1, DN_ZMem_No); // Fill the string with error sentinels DN_Memset(string, 'Z', size_required + 1); @@ -2464,7 +2581,7 @@ static DN_UTCore DN_Tests_Win() } for (DN_UT_Test(&result, "Str16 to Str8: Arena null terminates string")) { - DN_Str8 string8 = DN_OS_W32Str16ToStr8(scratch.arena, input16); + DN_Str8 string8 = DN_OS_W32Str16ToStr8(&scratch.arena, input16); int size_returned = DN_OS_W32Str16ToStr8Buffer(input16, nullptr, 0); char const EXPECTED[] = {'S', 't', 'r', 'i', 'n', 'g', 0}; @@ -2478,7 +2595,7 @@ static DN_UTCore DN_Tests_Win() return result; } -static DN_UTCore DN_Tests_Net() +static DN_UTCore DN_TST_Net() { DN_UTCore result = DN_UT_Init(); #if defined(DN_UNIT_TESTS_WITH_NET) @@ -2495,16 +2612,17 @@ static DN_UTCore DN_Tests_Net() if (label.size) { DN_UT_LogF(&result, "DN_NET\n"); - DN_Arena arena = DN_ArenaFromHeap(DN_Megabytes(4), DN_ArenaFlags_Nil); - DN_Str8 remote_ws_server_url = DN_Str8Lit("wss://echo.websocket.org"); - DN_Str8 remote_http_server_url = DN_Str8Lit("https://google.com"); + DN_MemList mem = DN_MemListFromHeap(DN_Megabytes(4), DN_MemFlags_Nil); + DN_Arena arena = DN_ArenaFromMemList(&mem); + DN_Str8 remote_ws_server_url = DN_Str8Lit("wss://echo.websocket.org"); + DN_Str8 remote_http_server_url = DN_Str8Lit("https://google.com"); DN_USize net_base_size = DN_Megabytes(1); char *net_base = DN_ArenaNewArray(&arena, char, net_base_size, DN_ZMem_Yes); DN_NETCore net = {}; net_interface.init(&net, net_base, net_base_size); - DN_U64 arena_reset_p = DN_ArenaPos(&arena); + DN_U64 arena_reset_p = DN_MemListPos(arena.mem); for (DN_UT_Test(&result, "%.*s WaitForResponse HTTP GET request", DN_Str8PrintFmt(label))) { DN_NETRequestHandle request = net_interface.do_http(&net, remote_http_server_url, DN_Str8Lit("GET"), nullptr); DN_NETResponse response = net_interface.wait_for_response(request, &arena, UINT32_MAX); @@ -2528,7 +2646,7 @@ static DN_UTCore DN_Tests_Net() DN_USize const WS_TIMEOUT_MS = 16; // NOTE: Wait for WS connection to open - for (bool done = false; result.state != DN_UTState_TestFailed && !done; DN_ArenaPopTo(&arena, arena_reset_p)) { + for (bool done = false; result.state != DN_UTState_TestFailed && !done; DN_MemListPopTo(arena.mem, arena_reset_p)) { DN_NETResponse response = net_interface.wait_for_response(request, &arena, WS_TIMEOUT_MS); if (response.state == DN_NETResponseState_Nil) // NOTE: Timeout continue; @@ -2539,7 +2657,7 @@ static DN_UTCore DN_Tests_Net() } // NOTE: Receive the initial text from the echo server - for (bool done = false; result.state != DN_UTState_TestFailed && !done; DN_ArenaPopTo(&arena, arena_reset_p)) { + for (bool done = false; result.state != DN_UTState_TestFailed && !done; DN_MemListPopTo(arena.mem, arena_reset_p)) { DN_NETResponse response = net_interface.wait_for_response(request, &arena, WS_TIMEOUT_MS); if (response.state == DN_NETResponseState_Nil) // NOTE: Timeout continue; @@ -2552,7 +2670,7 @@ static DN_UTCore DN_Tests_Net() } // NOTE: Expect to hear the close - for (bool done = false; result.state != DN_UTState_TestFailed && !done; DN_ArenaPopTo(&arena, arena_reset_p)) { + for (bool done = false; result.state != DN_UTState_TestFailed && !done; DN_MemListPopTo(arena.mem, arena_reset_p)) { DN_NETResponse response = net_interface.wait_for_response(request, &arena, WS_TIMEOUT_MS); if (response.state == DN_NETResponseState_Nil) // NOTE: Timeout continue; @@ -2563,33 +2681,36 @@ static DN_UTCore DN_Tests_Net() } } net_interface.deinit(&net); - DN_ArenaDeinit(&arena); + DN_MemListDeinit(arena.mem); } #endif // defined(DN_UNIT_TESTS_WITH_NET) return result; } -DN_TestsResult DN_Tests_RunSuite(DN_TestsPrint print) +DN_TSTResult DN_TST_RunSuite(DN_TSTPrint print) { DN_UTCore tests[] = { - DN_Tests_Base(), - DN_Tests_Arena(), - DN_Tests_Str8(), - DN_Tests_Bin(), - DN_Tests_TicketMutex(), - DN_Tests_BinarySearch(), - DN_Tests_BaseContainers(), - DN_Tests_Intrinsics(), - DN_Tests_Keccak(), - DN_Tests_M4(), - DN_Tests_OS(), - DN_Tests_Rect(), - DN_Tests_Win(), - DN_Tests_Net(), + DN_TST_Base(), + DN_TST_BaseArena(), + DN_TST_BaseStrings(), + DN_TST_BaseBytesHex(), + #if DN_H_WITH_HELPERS + DN_TST_BinarySearch(), + #endif + DN_TST_BaseDSMap(), + DN_TST_BaseIArray(), + DN_TST_BaseCArray2(), + DN_TST_BaseVArray(), + DN_TST_Keccak(), + DN_TST_M4(), + DN_TST_OS(), + DN_TST_Rect(), + DN_TST_Win(), + DN_TST_Net(), }; - DN_TestsResult result = {}; + DN_TSTResult result = {}; for (const DN_UTCore &test : tests) { result.total_tests += test.num_tests_in_group; result.total_good_tests += test.num_tests_ok_in_group; @@ -2600,8 +2721,8 @@ DN_TestsResult DN_Tests_RunSuite(DN_TestsPrint print) for (DN_UTCore &test : tests) { if (test.num_tests_in_group <= 0) continue; - bool do_print = print == DN_TestsPrint_Yes; - if (print == DN_TestsPrint_OnFailure && test.num_tests_ok_in_group != test.num_tests_in_group) + bool do_print = print == DN_TSTPrint_Yes; + if (print == DN_TSTPrint_OnFailure && test.num_tests_ok_in_group != test.num_tests_in_group) do_print = true; if (do_print) { diff --git a/Source/Extra/dn_tests_main.cpp b/Source/Extra/dn_tests_main.cpp index b8434eb..093f63c 100644 --- a/Source/Extra/dn_tests_main.cpp +++ b/Source/Extra/dn_tests_main.cpp @@ -2,12 +2,14 @@ #define DN_NO_WINDOWS_H_REPLACEMENT_HEADER #endif -#define DN_H_WITH_OS 1 -#define DN_H_WITH_CORE 1 -#define DN_H_WITH_HASH 1 -#define DN_H_WITH_HELPERS 1 -#define DN_H_WITH_ASYNC 1 -#define DN_H_WITH_NET 1 +#define DN_ARENA_TEMP_MEM_UAF_GUARD 1 +#define DN_ARENA_TEMP_MEM_UAF_TRACE_ON_BY_DEFAULT 0 +#define DN_H_WITH_OS 1 +#define DN_H_WITH_CORE 1 +#define DN_H_WITH_HASH 1 +#define DN_H_WITH_HELPERS 1 +#define DN_H_WITH_ASYNC 1 +#define DN_H_WITH_NET 1 #include "../dn.h" #include "../dn.cpp" @@ -35,7 +37,7 @@ int main(int, char**) { DN_Core dn = {}; DN_Init(&dn, DN_InitFlags_LogAllFeatures | DN_InitFlags_OS | DN_InitFlags_ThreadContext, nullptr); - DN_Tests_RunSuite(DN_TestsPrint_Yes); + DN_TST_RunSuite(DN_TSTPrint_Yes); return 0; } DN_MSVC_WARNING_POP diff --git a/Source/OS/dn_os.cpp b/Source/OS/dn_os.cpp index d721d18..0c62c4f 100644 --- a/Source/OS/dn_os.cpp +++ b/Source/OS/dn_os.cpp @@ -11,61 +11,59 @@ #include // getpagesize #endif -static void *DN_ArenaBasicAllocFromOSHeap(DN_USize size) +static void *DN_OS_MemFuncsHeapAllocShim_(DN_USize size) { void *result = DN_OS_MemAlloc(size, DN_ZMem_Yes); return result; } -DN_API DN_ArenaMemFuncs DN_ArenaMemFuncsGet(DN_ArenaMemFuncType type) +DN_API DN_MemFuncs DN_MemFuncsFromType(DN_MemFuncsType type) { - DN_ArenaMemFuncs result = {}; - result.type = type; + DN_MemFuncs result = {}; + result.type = type; switch (type) { - case DN_ArenaMemFuncType_Nil: break; - case DN_ArenaMemFuncType_Basic: { - result.type = DN_ArenaMemFuncType_Basic; - result.basic_alloc = DN_ArenaBasicAllocFromOSHeap; - result.basic_dealloc = DN_OS_MemDealloc; + case DN_MemFuncsType_Nil: break; + case DN_MemFuncsType_Heap: { + result.heap_alloc = DN_OS_MemFuncsHeapAllocShim_; + result.heap_dealloc = DN_OS_MemDealloc; } break; - case DN_ArenaMemFuncType_VMem: { + case DN_MemFuncsType_Virtual: { DN_Core *dn = DN_Get(); DN_Assert(dn->init_flags & DN_InitFlags_OS); - result.type = DN_ArenaMemFuncType_VMem; - result.vmem_page_size = dn->os.page_size; - result.vmem_reserve = DN_OS_MemReserve; - result.vmem_commit = DN_OS_MemCommit; - result.vmem_release = DN_OS_MemRelease; + result.virtual_page_size = dn->os.page_size; + result.virtual_reserve = DN_OS_MemReserve; + result.virtual_commit = DN_OS_MemCommit; + result.virtual_release = DN_OS_MemRelease; } break; } return result; } -DN_API DN_ArenaMemFuncs DN_ArenaMemFuncsGetDefaults() +DN_API DN_MemFuncs DN_MemFuncsDefault() { - DN_Core *dn = DN_Get(); - DN_ArenaMemFuncType type = DN_ArenaMemFuncType_Basic; + DN_Core *dn = DN_Get(); + DN_MemFuncsType type = DN_MemFuncsType_Heap; if (dn->os_init) { - #if !defined(DN_PLATFORM_EMSCRIPTEN) - type = DN_ArenaMemFuncType_VMem; - #endif +#if !defined(DN_PLATFORM_EMSCRIPTEN) + type = DN_MemFuncsType_Virtual; +#endif } - DN_ArenaMemFuncs result = DN_ArenaMemFuncsGet(type); + DN_MemFuncs result = DN_MemFuncsFromType(type); return result; } -DN_API DN_Arena DN_ArenaFromHeap(DN_U64 size, DN_ArenaFlags flags) +DN_API DN_MemList DN_MemListFromHeap(DN_U64 size, DN_MemFlags flags) { - DN_ArenaMemFuncs mem_funcs = DN_ArenaMemFuncsGet(DN_ArenaMemFuncType_Basic); - DN_Arena result = DN_ArenaFromMemFuncs(size, size, flags, mem_funcs); + DN_MemFuncs mem_funcs = DN_MemFuncsFromType(DN_MemFuncsType_Heap); + DN_MemList result = DN_MemListFromMemFuncs(size, size, flags, mem_funcs); return result; } -DN_API DN_Arena DN_ArenaFromVMem(DN_U64 reserve, DN_U64 commit, DN_ArenaFlags flags) +DN_API DN_MemList DN_MemListFromVMem(DN_U64 reserve, DN_U64 commit, DN_MemFlags flags) { - DN_ArenaMemFuncs mem_funcs = DN_ArenaMemFuncsGet(DN_ArenaMemFuncType_VMem); - DN_Arena result = DN_ArenaFromMemFuncs(reserve, commit, flags, mem_funcs); + DN_MemFuncs mem_funcs = DN_MemFuncsFromType(DN_MemFuncsType_Virtual); + DN_MemList result = DN_MemListFromMemFuncs(reserve, commit, flags, mem_funcs); return result; } @@ -95,7 +93,7 @@ DN_API DN_Str8 DN_Str8PadNewLines(DN_Arena *arena, DN_Str8 src, DN_Str8 pad) { // TODO: Implement this without requiring TLS so it can go into base strings DN_TCScratch scratch = DN_TCScratchBegin(&arena, 1); - DN_Str8Builder builder = DN_Str8BuilderFromArena(scratch.arena); + DN_Str8Builder builder = DN_Str8BuilderFromArena(&scratch.arena); DN_Str8BSplitResult split = DN_Str8BSplit(src, DN_Str8Lit("\n")); while (split.lhs.size) { DN_Str8BuilderAppendRef(&builder, pad); @@ -129,7 +127,7 @@ DN_API DN_Str8 DN_Str8BuilderBuildFromHeap(DN_Str8Builder const *builder) return result; } -DN_API void DN_OS_LogPrint(DN_LogTypeParam type, void *user_data, DN_CallSite call_site, DN_FMT_ATTRIB char const *fmt, va_list args) +DN_API void DN_OS_LogPrint(DN_LogTypeParam type, void *user_data, DN_CallSite call_site, DN_LogFlags flags, DN_FMT_ATTRIB char const *fmt, va_list args) { DN_Assert(user_data); DN_OSCore *os = DN_Cast(DN_OSCore *)user_data; @@ -138,69 +136,82 @@ DN_API void DN_OS_LogPrint(DN_LogTypeParam type, void *user_data, DN_CallSite ca DN_TicketMutex_Begin(&os->log_file_mutex); if (os->log_to_file && !os->log_file.handle && !os->log_file.error) { DN_TCScratch scratch = DN_TCScratchBegin(nullptr, 0); - DN_Str8 exe_dir = DN_OS_EXEDir(scratch.arena); - DN_Str8 log_path = DN_OS_PathF(scratch.arena, "%.*s/dn.log", DN_Str8PrintFmt(exe_dir)); + DN_Str8 exe_dir = DN_OS_EXEDir(&scratch.arena); + DN_Str8 log_path = DN_OS_PathF(&scratch.arena, "%.*s/dn.log", DN_Str8PrintFmt(exe_dir)); os->log_file = DN_OS_FileOpen(log_path, DN_OSFileOpen_CreateAlways, DN_OSFileAccess_AppendOnly, nullptr); DN_TCScratchEnd(&scratch); } DN_TicketMutex_End(&os->log_file_mutex); - DN_LogStyle style = {}; - if (!os->log_no_colour) { - style.colour = true; - style.bold = DN_LogBold_Yes; - if (type.is_u32_enum) { - switch (type.u32) { - case DN_LogType_Debug: { - style.colour = false; - style.bold = DN_LogBold_No; - } break; + bool print_prefix = DN_BitIsNotSet(flags, DN_LogFlags_NoPrefix); + char prefix_buffer[128] = {}; + DN_LogPrefixSize prefix_size = {}; + if (print_prefix) { + DN_LogStyle style = {}; + if (!os->log_no_colour) { + style.colour = true; + style.bold = DN_LogBold_Yes; + if (type.is_u32_enum) { + switch (type.u32) { + case DN_LogType_Debug: { + style.colour = false; + style.bold = DN_LogBold_No; + } break; - case DN_LogType_Info: { - style.g = 0x87; - style.b = 0xff; - } break; + case DN_LogType_Info: { + style.g = 0x87; + style.b = 0xff; + } break; - case DN_LogType_Warning: { - style.r = 0xff; - style.g = 0xff; - } break; + case DN_LogType_Warning: { + style.r = 0xff; + style.g = 0xff; + } break; - case DN_LogType_Error: { - style.r = 0xff; - } break; + case DN_LogType_Error: { + style.r = 0xff; + } break; + } } } + + DN_Date os_date = DN_OS_DateLocalTimeNow(); + DN_LogDate log_date = {}; + log_date.year = os_date.year; + log_date.month = os_date.month; + log_date.day = os_date.day; + log_date.hour = os_date.hour; + log_date.minute = os_date.minutes; + log_date.second = os_date.seconds; + prefix_size = DN_LogMakePrefix(style, type, call_site, log_date, prefix_buffer, sizeof(prefix_buffer)); } - DN_Date os_date = DN_OS_DateLocalTimeNow(); - DN_LogDate log_date = {}; - log_date.year = os_date.year; - log_date.month = os_date.month; - log_date.day = os_date.day; - log_date.hour = os_date.hour; - log_date.minute = os_date.minutes; - log_date.second = os_date.seconds; - - char prefix_buffer[128] = {}; - DN_LogPrefixSize prefix_size = DN_LogMakePrefix(style, type, call_site, log_date, prefix_buffer, sizeof(prefix_buffer)); - va_list args_copy; va_copy(args_copy, args); DN_TicketMutex_Begin(&os->log_file_mutex); { - DN_OS_FileWrite(&os->log_file, DN_Str8FromPtr(prefix_buffer, prefix_size.size), nullptr); - DN_OS_FileWriteF(&os->log_file, nullptr, "%*s ", DN_Cast(int)prefix_size.padding, ""); + if (print_prefix) { + DN_OS_FileWrite(&os->log_file, DN_Str8FromPtr(prefix_buffer, prefix_size.size), nullptr); + DN_OS_FileWriteF(&os->log_file, nullptr, "%*s ", DN_Cast(int) prefix_size.padding, ""); + } DN_OS_FileWriteFV(&os->log_file, nullptr, fmt, args_copy); - DN_OS_FileWrite(&os->log_file, DN_Str8Lit("\n"), nullptr); + if (!DN_BitIsSet(flags, DN_LogFlags_NoNewLine)) + DN_OS_FileWrite(&os->log_file, DN_Str8Lit("\n"), nullptr); } DN_TicketMutex_End(&os->log_file_mutex); va_end(args_copy); - DN_OSPrintDest dest = (type.is_u32_enum && type.u32 == DN_LogType_Error) ? DN_OSPrintDest_Err : DN_OSPrintDest_Out; - DN_OS_Print(dest, DN_Str8FromPtr(prefix_buffer, prefix_size.size)); - DN_OS_PrintF(dest, "%*s ", DN_Cast(int)prefix_size.padding, ""); - DN_OS_PrintLnFV(dest, fmt, args); + DN_TicketMutex_Begin(&os->log_mutex); + { + if (print_prefix) + DN_OS_PrintF(DN_OSPrintDest_Err, "%.*s%*s ", DN_Cast(int) prefix_size.size, prefix_buffer, DN_Cast(int) prefix_size.padding, ""); + + if (DN_BitIsSet(flags, DN_LogFlags_NoNewLine)) + DN_OS_PrintFV(DN_OSPrintDest_Err, fmt, args); + else + DN_OS_PrintLnFV(DN_OSPrintDest_Err, fmt, args); + } + DN_TicketMutex_End(&os->log_mutex); } DN_API void DN_OS_SetLogPrintFuncToOS() @@ -239,11 +250,11 @@ DN_API DN_Str8 DN_OS_EXEDir(DN_Arena *arena) DN_Str8 result = {}; if (!arena) return result; - DN_TCScratch scratch = DN_TCScratchBegin(&arena, 1); - DN_Str8 exe_path = DN_OS_EXEPath(scratch.arena); - DN_Str8 separators[] = {DN_Str8Lit("/"), DN_Str8Lit("\\")}; - DN_Str8BSplitResult split = DN_Str8BSplitLastArray(exe_path, separators, DN_ArrayCountU(separators)); - result = DN_Str8FromStr8Arena(arena, split.lhs); + DN_TCScratch scratch = DN_TCScratchBegin(&arena, 1); + DN_Str8 exe_path = DN_OS_EXEPath(&scratch.arena); + DN_Str8 separators[] = {DN_Str8Lit("/"), DN_Str8Lit("\\")}; + DN_Str8BSplitResult split = DN_Str8BSplitLastArray(exe_path, separators, DN_ArrayCountU(separators)); + result = DN_Str8FromStr8Arena(split.lhs, arena); DN_TCScratchEnd(&scratch); return result; } @@ -388,7 +399,7 @@ DN_API bool DN_OS_FileWriteF(DN_OSFile *file, DN_ErrSink *error, DN_FMT_ATTRIB c return result; } -DN_API DN_Str8 DN_OS_FileReadAll(DN_Allocator alloc_type, void *allocator, DN_Str8 path, DN_ErrSink *err) +DN_API DN_Str8 DN_OS_FileReadAll(DN_Allocator allocator, DN_Str8 path, DN_ErrSink *err) { // NOTE: Query file size DN_Str8 result = {}; @@ -399,14 +410,14 @@ DN_API DN_Str8 DN_OS_FileReadAll(DN_Allocator alloc_type, void *allocator, DN_St } // NOTE: Allocate - DN_ArenaTempMem arena_tmp = {}; - if (alloc_type == DN_Allocator_Arena) { - DN_Arena *arena = DN_Cast(DN_Arena *) allocator; - arena_tmp = DN_ArenaTempMemBegin(arena); - result = DN_Str8AllocArena(arena, path_info.size, DN_ZMem_No); + 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; - result = DN_Str8AllocPool(pool, path_info.size); + DN_Pool *pool = DN_Cast(DN_Pool *) allocator.context; + result = DN_Str8AllocPool(path_info.size, pool); } if (!result.data) { @@ -416,31 +427,41 @@ DN_API DN_Str8 DN_OS_FileReadAll(DN_Allocator alloc_type, void *allocator, DN_St } // NOTE: Read all - DN_OSFile file = DN_OS_FileOpen(path, DN_OSFileOpen_OpenIfExist, DN_OSFileAccess_Read, err); - DN_OSFileRead read = DN_OS_FileRead(&file, result.data, result.size, err); - if (file.error || !read.success) { - if (alloc_type == DN_Allocator_Arena) { - DN_ArenaTempMemEnd(arena_tmp); - } else { - DN_Pool *pool = DN_Cast(DN_Pool *) allocator; + DN_OSFile file = DN_OS_FileOpen(path, DN_OSFileOpen_OpenIfExist, DN_OSFileAccess_Read, err); + DN_OSFileRead read = DN_OS_FileRead(&file, result.data, result.size, 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); } - result = {}; } + if (failed) + result = {}; + DN_OS_FileClose(&file); return result; } DN_API DN_Str8 DN_OS_FileReadAllArena(DN_Arena *arena, DN_Str8 path, DN_ErrSink *err) { - DN_Str8 result = DN_OS_FileReadAll(DN_Allocator_Arena, arena, path, err); + DN_Allocator allocator = {}; + allocator.type = DN_AllocatorType_Arena; + allocator.context = 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_Str8 result = DN_OS_FileReadAll(DN_Allocator_Pool, pool, path, err); + DN_Allocator allocator = {}; + allocator.type = DN_AllocatorType_Pool; + allocator.context = pool; + DN_Str8 result = DN_OS_FileReadAll(allocator, path, err); return result; } @@ -454,9 +475,9 @@ DN_API bool DN_OS_FileWriteAll(DN_Str8 path, DN_Str8 buffer, DN_ErrSink *error) DN_API bool DN_OS_FileWriteAllFV(DN_Str8 file_path, DN_ErrSink *error, DN_FMT_ATTRIB char const *fmt, va_list args) { - DN_TCScratch scratch = DN_TCScratchBegin(nullptr, 0); - DN_Str8 buffer = DN_Str8FromFmtVArena(scratch.arena, fmt, args); - bool result = DN_OS_FileWriteAll(file_path, buffer, error); + DN_TCScratch scratch = DN_TCScratchBegin(nullptr, 0); + DN_Str8 buffer = DN_Str8FromFmtVArena(&scratch.arena, fmt, args); + bool result = DN_OS_FileWriteAll(file_path, buffer, error); DN_TCScratchEnd(&scratch); return result; } @@ -472,8 +493,8 @@ DN_API bool DN_OS_FileWriteAllF(DN_Str8 file_path, DN_ErrSink *error, DN_FMT_ATT DN_API bool DN_OS_FileWriteAllSafe(DN_Str8 path, DN_Str8 buffer, DN_ErrSink *error) { - DN_TCScratch scratch = DN_TCScratchBegin(nullptr, 0); - DN_Str8 tmp_path = DN_Str8FromFmtArena(scratch.arena, "%.*s.tmp", DN_Str8PrintFmt(path)); + DN_TCScratch scratch = DN_TCScratchBegin(nullptr, 0); + DN_Str8 tmp_path = DN_Str8FromFmtArena(&scratch.arena, "%.*s.tmp", DN_Str8PrintFmt(path)); if (!DN_OS_FileWriteAll(tmp_path, buffer, error)) { DN_TCScratchEnd(&scratch); return false; @@ -492,9 +513,9 @@ DN_API bool DN_OS_FileWriteAllSafe(DN_Str8 path, DN_Str8 buffer, DN_ErrSink *err DN_API bool DN_OS_FileWriteAllSafeFV(DN_Str8 path, DN_ErrSink *error, DN_FMT_ATTRIB char const *fmt, va_list args) { - DN_TCScratch scratch = DN_TCScratchBegin(nullptr, 0); - DN_Str8 buffer = DN_Str8FromFmtVArena(scratch.arena, fmt, args); - bool result = DN_OS_FileWriteAllSafe(path, buffer, error); + DN_TCScratch scratch = DN_TCScratchBegin(nullptr, 0); + DN_Str8 buffer = DN_Str8FromFmtVArena(&scratch.arena, fmt, args); + bool result = DN_OS_FileWriteAllSafe(path, buffer, error); DN_TCScratchEnd(&scratch); return result; } @@ -507,6 +528,17 @@ DN_API bool DN_OS_FileWriteAllSafeF(DN_Str8 path, DN_ErrSink *error, DN_FMT_ATTR return result; } +DN_API DN_Str8 DN_OS_Str8FromPathInfoType(DN_OSPathInfoType type) +{ + DN_Str8 result = DN_Str8Lit("BAD PATH INFO TYPE"); + switch(type) { + case DN_OSPathInfoType_Unknown: result = DN_Str8Lit("Unknown"); break; + case DN_OSPathInfoType_Directory: result = DN_Str8Lit("Directory"); break; + case DN_OSPathInfoType_File: result = DN_Str8Lit("File"); break; + } + return result; +} + DN_API bool DN_OS_PathAddRef(DN_Arena *arena, DN_OSPath *fs_path, DN_Str8 path) { if (!arena || !fs_path || path.size == 0) @@ -552,7 +584,7 @@ DN_API bool DN_OS_PathAddRef(DN_Arena *arena, DN_OSPath *fs_path, DN_Str8 path) DN_API bool DN_OS_PathAdd(DN_Arena *arena, DN_OSPath *fs_path, DN_Str8 path) { - DN_Str8 copy = DN_Str8FromStr8Arena(arena, path); + DN_Str8 copy = DN_Str8FromStr8Arena(path, arena); bool result = copy.size ? true : DN_OS_PathAddRef(arena, fs_path, copy); return result; } @@ -601,7 +633,7 @@ DN_API DN_Str8 DN_OS_PathToF(DN_Arena *arena, DN_Str8 path_separator, DN_FMT_ATT DN_TCScratch scratch = DN_TCScratchBegin(&arena, 1); va_list args; va_start(args, fmt); - DN_Str8 path = DN_Str8FromFmtVArena(scratch.arena, fmt, args); + DN_Str8 path = DN_Str8FromFmtVArena(&scratch.arena, fmt, args); va_end(args); DN_Str8 result = DN_OS_PathTo(arena, path, path_separator); DN_TCScratchEnd(&scratch); @@ -619,7 +651,7 @@ DN_API DN_Str8 DN_OS_PathF(DN_Arena *arena, DN_FMT_ATTRIB char const *fmt, ...) DN_TCScratch scratch = DN_TCScratchBegin(&arena, 1); va_list args; va_start(args, fmt); - DN_Str8 path = DN_Str8FromFmtVArena(scratch.arena, fmt, args); + DN_Str8 path = DN_Str8FromFmtVArena(&scratch.arena, fmt, args); va_end(args); DN_Str8 result = DN_OS_Path(arena, path); DN_TCScratchEnd(&scratch); @@ -634,7 +666,7 @@ DN_API DN_Str8 DN_OS_PathBuildWithSeparator(DN_Arena *arena, DN_OSPath const *fs // NOTE: Each link except the last one needs the path separator appended to it, '/' or '\\' DN_USize string_size = (fs_path->has_prefix_path_separator ? path_separator.size : 0) + fs_path->string_size + ((fs_path->links_size - 1) * path_separator.size); - result = DN_Str8AllocArena(arena, string_size, DN_ZMem_No); + result = DN_Str8AllocArena(string_size, DN_ZMem_No, arena); if (result.data) { char *dest = result.data; if (fs_path->has_prefix_path_separator) { @@ -683,7 +715,7 @@ DN_API DN_OSExecResult DN_OS_ExecOrAbort(DN_Str8Slice cmd_line, DN_OSExecArgs *a static void DN_OS_ThreadExecute_(void *user_context) { DN_OSThread *thread = DN_Cast(DN_OSThread *) user_context; - DN_ArenaMemFuncs mem_funcs = DN_ArenaMemFuncsGetDefaults(); + DN_MemFuncs mem_funcs = DN_MemFuncsDefault(); DN_TCInitFromMemFuncs(&thread->context, thread->thread_id, /*args=*/nullptr, mem_funcs); DN_TCEquip(&thread->context); if (thread->is_lane_set) { @@ -800,9 +832,9 @@ DN_API void DN_OS_HttpRequestWait(DN_OSHttpResponse *response) DN_API DN_OSHttpResponse DN_OS_HttpRequest(DN_Arena *arena, DN_Str8 host, DN_Str8 path, DN_OSHttpRequestSecure secure, DN_Str8 method, DN_Str8 body, DN_Str8 headers) { // TODO(doyle): Revise the memory allocation and its lifetime - DN_OSHttpResponse result = {}; - DN_TCScratch scratch = DN_TCScratchBegin(&arena, 1); - result.scratch_arena = scratch.arena; + DN_OSHttpResponse result = {}; + DN_TCScratch scratch = DN_TCScratchBegin(&arena, 1); + result.scratch_arena = scratch.arena; DN_OS_HttpRequestAsync(&result, arena, host, path, secure, method, body, headers); DN_OS_HttpRequestWait(&result); @@ -899,13 +931,15 @@ DN_API void DN_OS_PrintFStyle(DN_OSPrintDest dest, DN_LogStyle style, DN_FMT_ATT DN_API void DN_OS_PrintStyle(DN_OSPrintDest dest, DN_LogStyle style, DN_Str8 string) { if (string.data && string.size) { - if (style.colour) - DN_OS_Print(dest, DN_LogColourEscapeCodeStr8FromRGB(DN_LogColourType_Fg, style.r, style.g, style.b)); + if (style.colour) { + DN_Str8x32 colour = DN_Str8x32FromANSIColourCodeU8RGB(DN_ANSIColourMode_Fg, style.r, style.g, style.b); + DN_OS_Print(dest, DN_Str8FromStruct(&colour)); + } if (style.bold == DN_LogBold_Yes) - DN_OS_Print(dest, DN_Str8Lit(DN_LogBoldEscapeCode)); + DN_OS_Print(dest, DN_Str8Lit(DN_ANSICodeBoldLit)); DN_OS_Print(dest, string); if (style.colour || style.bold == DN_LogBold_Yes) - DN_OS_Print(dest, DN_Str8Lit(DN_LogResetEscapeCode)); + DN_OS_Print(dest, DN_Str8Lit(DN_ANSICodeResetLit)); } } @@ -930,13 +964,15 @@ DN_API void DN_OS_PrintFV(DN_OSPrintDest dest, DN_FMT_ATTRIB char const *fmt, va DN_API void DN_OS_PrintFVStyle(DN_OSPrintDest dest, DN_LogStyle style, DN_FMT_ATTRIB char const *fmt, va_list args) { if (fmt) { - if (style.colour) - DN_OS_Print(dest, DN_LogColourEscapeCodeStr8FromRGB(DN_LogColourType_Fg, style.r, style.g, style.b)); + if (style.colour) { + DN_Str8x32 colour = DN_Str8x32FromANSIColourCodeU8RGB(DN_ANSIColourMode_Fg, style.r, style.g, style.b); + DN_OS_Print(dest, DN_Str8FromStruct(&colour)); + } if (style.bold == DN_LogBold_Yes) - DN_OS_Print(dest, DN_Str8Lit(DN_LogBoldEscapeCode)); + DN_OS_Print(dest, DN_Str8Lit(DN_ANSICodeBoldLit)); DN_OS_PrintFV(dest, fmt, args); if (style.colour || style.bold == DN_LogBold_Yes) - DN_OS_Print(dest, DN_Str8Lit(DN_LogResetEscapeCode)); + DN_OS_Print(dest, DN_Str8Lit(DN_ANSICodeResetLit)); } } @@ -1166,8 +1202,8 @@ DN_API DN_StackTraceWalkResult DN_StackTraceWalk(DN_Arena *arena, DN_U16 limit) w32->sym_initialised = true; SymSetOptions(SYMOPT_LOAD_LINES); if (!SymInitialize(result.process, nullptr /*UserSearchPath*/, true /*fInvadeProcess*/)) { - DN_TCScratch scratch = DN_TCScratchBegin(&arena, 1); - DN_OSW32Error error = DN_OS_W32LastError(scratch.arena); + DN_TCScratch scratch = DN_TCScratchBegin(&arena, 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); } @@ -1246,8 +1282,8 @@ DN_API DN_Str8 DN_StackTraceWalkResultToStr8(DN_Arena *arena, DN_StackTraceWalkR if (!walk || !arena) return result; - DN_TCScratch scratch = DN_TCScratchBegin(&arena, 1); - DN_Str8Builder builder = DN_Str8BuilderFromArena(scratch.arena); + DN_TCScratch scratch = DN_TCScratchBegin(&arena, 1); + DN_Str8Builder builder = DN_Str8BuilderFromArena(&scratch.arena); DN_StackTraceAddWalkToStr8Builder(walk, &builder, skip); result = DN_Str8BuilderBuild(&builder, arena); DN_TCScratchEnd(&scratch); @@ -1256,9 +1292,9 @@ DN_API DN_Str8 DN_StackTraceWalkResultToStr8(DN_Arena *arena, DN_StackTraceWalkR DN_API DN_Str8 DN_StackTraceWalkStr8(DN_Arena *arena, DN_U16 limit, DN_U16 skip) { - DN_TCScratch scratch = DN_TCScratchBegin(&arena, 1); - DN_StackTraceWalkResult walk = DN_StackTraceWalk(scratch.arena, limit); - DN_Str8 result = DN_StackTraceWalkResultToStr8(arena, &walk, skip); + DN_TCScratch scratch = DN_TCScratchBegin(&arena, 1); + DN_StackTraceWalkResult walk = DN_StackTraceWalk(&scratch.arena, limit); + DN_Str8 result = DN_StackTraceWalkResultToStr8(arena, &walk, skip); DN_TCScratchEnd(&scratch); return result; } @@ -1267,12 +1303,13 @@ DN_API DN_Str8 DN_StackTraceWalkStr8FromHeap(DN_U16 limit, DN_U16 skip) { // NOTE: We don't use WalkResultToStr8 because that uses the TLS arenas which // does not use the OS heap. - DN_Arena arena = DN_ArenaFromHeap(DN_Kilobytes(64), DN_ArenaFlags_NoAllocTrack); + DN_MemList mem = DN_MemListFromHeap(DN_Kilobytes(64), DN_MemFlags_NoAllocTrack); + DN_Arena arena = DN_ArenaFromMemList(&mem); DN_Str8Builder builder = DN_Str8BuilderFromArena(&arena); DN_StackTraceWalkResult walk = DN_StackTraceWalk(&arena, limit); DN_StackTraceAddWalkToStr8Builder(&walk, &builder, skip); DN_Str8 result = DN_Str8BuilderBuildFromHeap(&builder); - DN_ArenaDeinit(&arena); + DN_MemListDeinit(&mem); return result; } @@ -1283,9 +1320,9 @@ DN_API DN_StackTraceFrameSlice DN_StackTraceGetFrames(DN_Arena *arena, DN_U16 li return result; DN_TCScratch scratch = DN_TCScratchBegin(&arena, 1); - DN_StackTraceWalkResult walk = DN_StackTraceWalk(scratch.arena, limit); + DN_StackTraceWalkResult walk = DN_StackTraceWalk(&scratch.arena, limit); if (walk.size) { - if (DN_ISliceAllocArena(DN_StackTraceFrameSlice, &result, walk.size, DN_ZMem_No, arena)) { + if (DN_ISliceAllocArena(&result, walk.size, DN_ZMem_No, arena)) { DN_USize slice_index = 0; for (DN_StackTraceWalkResultIterator it = {}; DN_StackTraceWalkResultIterate(&it, &walk);) result.data[slice_index++] = DN_StackTraceRawFrameToFrame(arena, it.raw_frame); @@ -1345,7 +1382,7 @@ DN_API DN_StackTraceFrame DN_StackTraceRawFrameToFrame(DN_Arena *arena, DN_Stack DN_API void DN_StackTracePrint(DN_U16 limit) { DN_TCScratch scratch = DN_TCScratchBegin(nullptr, 0); - DN_StackTraceFrameSlice stack_trace = DN_StackTraceGetFrames(scratch.arena, limit); + 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)); diff --git a/Source/OS/dn_os.h b/Source/OS/dn_os.h index ba63f5a..a29f1f0 100644 --- a/Source/OS/dn_os.h +++ b/Source/OS/dn_os.h @@ -243,7 +243,7 @@ struct DN_OSHttpResponse // Synchronous HTTP response uses the TLS scratch arena whereas async // calls use their own dedicated arena. DN_Arena tmp_arena; - DN_Arena *scratch_arena; + DN_Arena scratch_arena; DN_Str8Builder builder; DN_OSSemaphore on_complete_semaphore; @@ -265,6 +265,7 @@ struct DN_OSCore DN_OSFile log_file; // TODO(dn): Hmmm, how should we do this... ? DN_TicketMutex log_file_mutex; // Is locked when instantiating the log_file for the first time bool log_no_colour; // Disable colours in the logging output + DN_TicketMutex log_mutex; // NOTE: OS DN_U32 logical_processor_count; @@ -280,6 +281,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_Arena arena; void *platform_context; }; @@ -291,10 +293,10 @@ struct DN_OSDiskSpace DN_U64 size; }; -DN_API DN_ArenaMemFuncs DN_ArenaMemFuncsGet (DN_ArenaMemFuncType type); -DN_API DN_ArenaMemFuncs DN_ArenaMemFuncsGetDefaults (); -DN_API DN_Arena DN_ArenaFromHeap (DN_U64 size, DN_ArenaFlags flags); -DN_API DN_Arena DN_ArenaFromVMem (DN_U64 reserve, DN_U64 commit, DN_ArenaFlags flags); +DN_API DN_MemFuncs DN_MemFuncsFromType (DN_MemFuncsType type); +DN_API DN_MemFuncs DN_MemFuncsDefault (); +DN_API DN_MemList DN_MemListFromHeap (DN_U64 size, DN_MemFlags flags); +DN_API DN_MemList DN_MemListFromVMem (DN_U64 reserve, DN_U64 commit, DN_MemFlags flags); DN_API DN_Str8 DN_Str8FromHeapF (DN_FMT_ATTRIB char const *fmt, ...); @@ -367,6 +369,7 @@ DN_API bool DN_OS_FileWriteAllSafe (D DN_API bool DN_OS_FileWriteAllSafeFV (DN_Str8 path, DN_ErrSink *err, DN_FMT_ATTRIB char const *fmt, va_list args); DN_API bool DN_OS_FileWriteAllSafeF (DN_Str8 path, DN_ErrSink *err, DN_FMT_ATTRIB char const *fmt, ...); +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_PathIsOlderThan (DN_Str8 file, DN_Str8 check_against); DN_API bool DN_OS_PathDelete (DN_Str8 path); @@ -419,7 +422,7 @@ DN_API void DN_OS_ConditionVariableSignal (D DN_API void DN_OS_ConditionVariableBroadcast (DN_OSConditionVariable *cv); DN_API bool DN_OS_ThreadInit (DN_OSThread *thread, DN_OSThreadFunc *func, DN_OSThreadLane *lane, void *user_context); -DN_API bool DN_OS_ThreadJoin (DN_OSThread *thread); +DN_API bool DN_OS_ThreadJoin (DN_OSThread *thread, DN_TCDeinitArenas deinit_arenas); DN_API DN_U32 DN_OS_ThreadID (); DN_API void DN_OS_ThreadSetNameFmt (char const *fmt, ...); diff --git a/Source/OS/dn_os_posix.cpp b/Source/OS/dn_os_posix.cpp index 61a93eb..d6b9ab7 100644 --- a/Source/OS/dn_os_posix.cpp +++ b/Source/OS/dn_os_posix.cpp @@ -1333,7 +1333,7 @@ DN_API bool DN_OS_ThreadInit(DN_OSThread *thread, DN_OSThreadFunc *func, DN_OSTh return result; } -DN_API bool DN_OS_ThreadJoin(DN_OSThread *thread) +DN_API bool DN_OS_ThreadJoin(DN_OSThread *thread, DN_TCDeinitArenas deinit_arenas) { bool result = false; if (thread && thread->handle) { @@ -1344,6 +1344,7 @@ DN_API bool DN_OS_ThreadJoin(DN_OSThread *thread) result = pthread_join(thread_id, &return_val) == 0; thread->handle = {}; thread->thread_id = {}; + DN_TCDeinit(&thread->context, deinit_arenas); } return result; } @@ -1535,8 +1536,7 @@ DN_API void DN_OS_HttpRequestAsync(DN_OSHttpResponse *response, return; response->arena = arena; - response->builder.arena = - response->scratch_arena ? response->scratch_arena : &response->tmp_arena; + response->builder.arena = response->scratch_arena ? response->scratch_arena : &response->tmp_arena; DN_Arena *scratch = response->scratch_arena; DN_TCScratch scratch_ = DN_TCScratchBegin(&arena, 1); diff --git a/Source/OS/dn_os_w32.cpp b/Source/OS/dn_os_w32.cpp index ae8e07e..1c6e1a4 100644 --- a/Source/OS/dn_os_w32.cpp +++ b/Source/OS/dn_os_w32.cpp @@ -209,9 +209,9 @@ DN_API void DN_OS_GenBytesSecure(void *buffer, DN_U32 size) DN_API DN_OSDiskSpace DN_OS_DiskSpace(DN_Str8 path) { - DN_TCScratch scratch = DN_TCScratchBegin(nullptr, 0); - DN_OSDiskSpace result = {}; - DN_Str16 path16 = DN_OS_W32Str8ToStr16(scratch.arena, path); + DN_TCScratch scratch = DN_TCScratchBegin(nullptr, 0); + DN_OSDiskSpace result = {}; + DN_Str16 path16 = DN_OS_W32Str8ToStr16(&scratch.arena, path); ULARGE_INTEGER free_bytes_avail_to_caller; ULARGE_INTEGER total_number_of_bytes; @@ -233,9 +233,9 @@ DN_API DN_OSDiskSpace DN_OS_DiskSpace(DN_Str8 path) DN_API bool DN_OS_SetEnvVar(DN_Str8 name, DN_Str8 value) { - DN_TCScratch scratch = DN_TCScratchBegin(nullptr, 0); -DN_Str16 name16 = DN_OS_W32Str8ToStr16(scratch.arena, name); - DN_Str16 value16 = DN_OS_W32Str8ToStr16(scratch.arena, value); + DN_TCScratch scratch = DN_TCScratchBegin(nullptr, 0); + DN_Str16 name16 = DN_OS_W32Str8ToStr16(&scratch.arena, name); + DN_Str16 value16 = DN_OS_W32Str8ToStr16(&scratch.arena, value); bool result = SetEnvironmentVariableW(name16.data, value16.data) != 0; DN_TCScratchEnd(&scratch); return result; @@ -246,8 +246,8 @@ DN_API DN_Str8 DN_OS_EXEPath(DN_Arena *arena) DN_Str8 result = {}; if (!arena) return result; - DN_TCScratch scratch = DN_TCScratchBegin(&arena, 1); -DN_Str16 exe_dir16 = DN_OS_W32EXEPathW(scratch.arena); + DN_TCScratch scratch = DN_TCScratchBegin(&arena, 1); + DN_Str16 exe_dir16 = DN_OS_W32EXEPathW(&scratch.arena); result = DN_OS_W32Str16ToStr8(arena, exe_dir16); DN_TCScratchEnd(&scratch); return result; @@ -286,15 +286,15 @@ static DN_U64 DN_OS_W32FileTimeToSeconds_(FILETIME const *time) DN_API bool DN_OS_FileCopy(DN_Str8 src, DN_Str8 dest, bool overwrite, DN_ErrSink *err) { bool result = false; - DN_TCScratch scratch = DN_TCScratchBegin(nullptr, 0); -DN_Str16 src16 = DN_OS_W32Str8ToStr16(scratch.arena, src); - DN_Str16 dest16 = DN_OS_W32Str8ToStr16(scratch.arena, dest); + DN_TCScratch scratch = DN_TCScratchBegin(nullptr, 0); + DN_Str16 src16 = DN_OS_W32Str8ToStr16(&scratch.arena, src); + DN_Str16 dest16 = DN_OS_W32Str8ToStr16(&scratch.arena, dest); int fail_if_exists = overwrite == false; result = CopyFileW(src16.data, dest16.data, fail_if_exists) != 0; if (!result) { - DN_OSW32Error win_error = DN_OS_W32LastError(scratch.arena); + DN_OSW32Error win_error = DN_OS_W32LastError(&scratch.arena); DN_ErrSinkAppendF(err, win_error.code, "Failed to copy file '%.*s' to '%.*s': (%u) %.*s", @@ -311,8 +311,8 @@ DN_API bool DN_OS_FileMove(DN_Str8 src, DN_Str8 dest, bool overwrite, DN_ErrSink { bool result = false; DN_TCScratch scratch = DN_TCScratchBegin(nullptr, 0); - DN_Str16 src16 = DN_OS_W32Str8ToStr16(scratch.arena, src); - DN_Str16 dest16 = DN_OS_W32Str8ToStr16(scratch.arena, dest); + DN_Str16 src16 = DN_OS_W32Str8ToStr16(&scratch.arena, src); + DN_Str16 dest16 = DN_OS_W32Str8ToStr16(&scratch.arena, dest); unsigned long flags = MOVEFILE_COPY_ALLOWED; if (overwrite) @@ -320,7 +320,7 @@ DN_API bool DN_OS_FileMove(DN_Str8 src, DN_Str8 dest, bool overwrite, DN_ErrSink result = MoveFileExW(src16.data, dest16.data, flags) != 0; if (!result) { - DN_OSW32Error win_error = DN_OS_W32LastError(scratch.arena); + DN_OSW32Error win_error = DN_OS_W32LastError(&scratch.arena); DN_ErrSinkAppendF(err, win_error.code, "Failed to move file '%.*s' to '%.*s': (%u) %.*s", @@ -333,7 +333,7 @@ DN_API bool DN_OS_FileMove(DN_Str8 src, DN_Str8 dest, bool overwrite, DN_ErrSink return result; } -DN_API DN_OSFile DN_OS_FileOpen(DN_Str8 path, DN_OSFileOpen open_mode, DN_U32 access, DN_ErrSink *err) +DN_API DN_OSFile DN_OS_FileOpen(DN_Str8 path, DN_OSFileOpen open_mode, DN_OSFileAccess access, DN_ErrSink *err) { DN_OSFile result = {}; if (path.size == 0 || path.size <= 0) @@ -366,18 +366,18 @@ DN_API DN_OSFile DN_OS_FileOpen(DN_Str8 path, DN_OSFileOpen open_mode, DN_U32 ac access_mode |= GENERIC_EXECUTE; } - DN_TCScratch scratch = DN_TCScratchBegin(nullptr, 0); - DN_Str16 path16 = DN_OS_W32Str8ToStr16(scratch.arena, path); - void *handle = CreateFileW(/*LPCWSTR lpFileName*/ path16.data, - /*DWORD dwDesiredAccess*/ access_mode, - /*DWORD dwShareMode*/ FILE_SHARE_READ | FILE_SHARE_WRITE, - /*LPSECURITY_ATTRIBUTES lpSecurityAttributes*/ nullptr, - /*DWORD dwCreationDisposition*/ create_flag, - /*DWORD dwFlagsAndAttributes*/ FILE_ATTRIBUTE_NORMAL, - /*HANDLE hTemplateFile*/ nullptr); + DN_TCScratch scratch = DN_TCScratchBegin(nullptr, 0); + DN_Str16 path16 = DN_OS_W32Str8ToStr16(&scratch.arena, path); + void *handle = CreateFileW(/*LPCWSTR lpFileName*/ path16.data, + /*DWORD dwDesiredAccess*/ access_mode, + /*DWORD dwShareMode*/ FILE_SHARE_READ | FILE_SHARE_WRITE, + /*LPSECURITY_ATTRIBUTES lpSecurityAttributes*/ nullptr, + /*DWORD dwCreationDisposition*/ create_flag, + /*DWORD dwFlagsAndAttributes*/ FILE_ATTRIBUTE_NORMAL, + /*HANDLE hTemplateFile*/ nullptr); if (handle == INVALID_HANDLE_VALUE) { - DN_OSW32Error win_error = DN_OS_W32LastError(scratch.arena); + DN_OSW32Error win_error = DN_OS_W32LastError(&scratch.arena); result.error = true; DN_ErrSinkAppendF(err, win_error.code, "Failed to open file at '%.*s': '%.*s'", DN_Str8PrintFmt(path), DN_Str8PrintFmt(win_error.msg)); DN_TCScratchEnd(&scratch); @@ -414,14 +414,14 @@ DN_API DN_OSFileRead DN_OS_FileRead(DN_OSFile *file, void *buffer, DN_USize size /*LPDWORD lpNumberOfByesRead*/ &bytes_read, /*LPOVERLAPPED lpOverlapped*/ nullptr); if (read_result == 0) { - DN_OSW32Error win_error = DN_OS_W32LastError(scratch.arena); + DN_OSW32Error win_error = DN_OS_W32LastError(&scratch.arena); DN_ErrSinkAppendF(err, win_error.code, "Failed to read data from file: (%u) %.*s", win_error.code, DN_Str8PrintFmt(win_error.msg)); DN_TCScratchEnd(&scratch); return result; } if (bytes_read != size) { - DN_OSW32Error win_error = DN_OS_W32LastError(scratch.arena); + DN_OSW32Error win_error = DN_OS_W32LastError(&scratch.arena); DN_ErrSinkAppendF( err, win_error.code, @@ -455,9 +455,9 @@ DN_API bool DN_OS_FileWritePtr(DN_OSFile *file, void const *buffer, DN_USize siz } if (!result) { - DN_TCScratch scratch = DN_TCScratchBegin(nullptr, 0); - DN_OSW32Error win_error = DN_OS_W32LastError(scratch.arena); - DN_Str8x32 buffer_size_str8 = DN_ByteCountStr8x32(size); + DN_TCScratch scratch = DN_TCScratchBegin(nullptr, 0); + DN_OSW32Error win_error = DN_OS_W32LastError(&scratch.arena); + DN_Str8x32 buffer_size_str8 = DN_ByteCountStr8x32(size); DN_ErrSinkAppendF(err, win_error.code, "Failed to write buffer (%.*s) to file handle: %.*s", DN_Str8PrintFmt(buffer_size_str8), DN_Str8PrintFmt(win_error.msg)); DN_TCScratchEnd(&scratch); } @@ -471,8 +471,8 @@ DN_API bool DN_OS_FileFlush(DN_OSFile *file, DN_ErrSink *err) BOOL result = FlushFileBuffers(DN_Cast(HANDLE) file->handle); if (!result) { - DN_TCScratch scratch = DN_TCScratchBegin(nullptr, 0); - DN_OSW32Error win_error = DN_OS_W32LastError(scratch.arena); + DN_TCScratch scratch = DN_TCScratchBegin(nullptr, 0); + DN_OSW32Error win_error = DN_OS_W32LastError(&scratch.arena); DN_ErrSinkAppendF(err, win_error.code, "Failed to flush file buffer to disk: %.*s", DN_Str8PrintFmt(win_error.msg)); DN_TCScratchEnd(&scratch); } @@ -494,8 +494,8 @@ DN_API DN_OSPathInfo DN_OS_PathInfo(DN_Str8 path) if (path.size == 0) return result; - DN_TCScratch scratch = DN_TCScratchBegin(nullptr, 0); - DN_Str16 path16 = DN_OS_W32Str8ToStr16(scratch.arena, path); + DN_TCScratch scratch = DN_TCScratchBegin(nullptr, 0); + DN_Str16 path16 = DN_OS_W32Str8ToStr16(&scratch.arena, path); WIN32_FILE_ATTRIBUTE_DATA attrib_data = {}; if (!GetFileAttributesExW(path16.data, GetFileExInfoStandard, &attrib_data)) { @@ -530,8 +530,8 @@ DN_API bool DN_OS_PathDelete(DN_Str8 path) if (path.size == 0) return result; - DN_TCScratch scratch = DN_TCScratchBegin(nullptr, 0); - DN_Str16 path16 = DN_OS_W32Str8ToStr16(scratch.arena, path); + DN_TCScratch scratch = DN_TCScratchBegin(nullptr, 0); + DN_Str16 path16 = DN_OS_W32Str8ToStr16(&scratch.arena, path); if (path16.size) { result = DeleteFileW(path16.data); if (!result) @@ -547,8 +547,8 @@ DN_API bool DN_OS_PathIsFile(DN_Str8 path) if (path.size == 0) return result; - DN_TCScratch scratch = DN_TCScratchBegin(nullptr, 0); - DN_Str16 path16 = DN_OS_W32Str8ToStr16(scratch.arena, path); + DN_TCScratch scratch = DN_TCScratchBegin(nullptr, 0); + DN_Str16 path16 = DN_OS_W32Str8ToStr16(&scratch.arena, path); if (path16.size) { WIN32_FILE_ATTRIBUTE_DATA attrib_data = {}; if (GetFileAttributesExW(path16.data, GetFileExInfoStandard, &attrib_data)) @@ -565,8 +565,8 @@ DN_API bool DN_OS_PathIsDir(DN_Str8 path) if (path.size == 0) return result; - DN_TCScratch scratch = DN_TCScratchBegin(nullptr, 0); - DN_Str16 path16 = DN_OS_W32Str8ToStr16(scratch.arena, path); + DN_TCScratch scratch = DN_TCScratchBegin(nullptr, 0); + DN_Str16 path16 = DN_OS_W32Str8ToStr16(&scratch.arena, path); if (path16.size) { WIN32_FILE_ATTRIBUTE_DATA attrib_data = {}; if (GetFileAttributesExW(path16.data, GetFileExInfoStandard, &attrib_data)) @@ -580,9 +580,9 @@ DN_API bool DN_OS_PathIsDir(DN_Str8 path) DN_API bool DN_OS_PathMakeDir(DN_Str8 path) { - bool result = true; - DN_TCScratch scratch = DN_TCScratchBegin(nullptr, 0); - DN_Str16 path16 = DN_OS_W32Str8ToStr16(scratch.arena, path); + bool result = true; + DN_TCScratch scratch = DN_TCScratchBegin(nullptr, 0); + DN_Str16 path16 = DN_OS_W32Str8ToStr16(&scratch.arena, path); // NOTE: Go back from the end of the string to all the directories in the // string, and try to create them. Since Win32 API cannot create @@ -653,12 +653,12 @@ 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_OS_PathF(scratch.arena, "%.*s*", DN_Str8PrintFmt(path)); + adjusted_path = DN_OS_PathF(&scratch.arena, "%.*s*", DN_Str8PrintFmt(path)); else - adjusted_path = DN_OS_PathF(scratch.arena, "%.*s/*", DN_Str8PrintFmt(path)); + adjusted_path = DN_OS_PathF(&scratch.arena, "%.*s/*", DN_Str8PrintFmt(path)); } - path16 = DN_OS_W32Str8ToStr16(scratch.arena, adjusted_path); + path16 = DN_OS_W32Str8ToStr16(&scratch.arena, adjusted_path); if (path16.size <= 0) { // Conversion error DN_TCScratchEnd(&scratch); return false; @@ -676,8 +676,6 @@ DN_API bool DN_OS_PathIterateDir(DN_Str8 path, DN_OSDirIterator *it) return result; } - -// NOTE: DN_OSExec ///////////////////////////////////////////////////////////////////////////////// DN_API void DN_OS_Exit(int32_t exit_code) { ExitProcess(DN_Cast(UINT) exit_code); @@ -729,7 +727,7 @@ DN_API DN_OSExecResult DN_OS_ExecPump(DN_OSExecAsyncHandle handle, exec_result = WaitForSingleObject(handle.process, timeout_ms); if (exec_result == WAIT_FAILED) { - DN_OSW32Error win_error = DN_OS_W32LastError(scratch.arena); + DN_OSW32Error win_error = DN_OS_W32LastError(&scratch.arena); result.os_error_code = win_error.code; DN_ErrSinkAppendF(err, result.os_error_code, "Executed command failed to terminate: %.*s", DN_Str8PrintFmt(win_error.msg)); DN_TCScratchEnd(&scratch); @@ -779,7 +777,7 @@ DN_API DN_OSExecResult DN_OS_ExecPump(DN_OSExecAsyncHandle handle, if (GetExitCodeProcess(handle.process, &exit_status)) { result.exit_code = exit_status; } else { - DN_OSW32Error win_error = DN_OS_W32LastError(scratch.arena); + DN_OSW32Error win_error = DN_OS_W32LastError(&scratch.arena); result.os_error_code = win_error.code; DN_ErrSinkAppendF(err, result.os_error_code, @@ -824,12 +822,12 @@ DN_API DN_OSExecResult DN_OS_ExecWait(DN_OSExecAsyncHandle handle, DN_Arena *are return result; } - DN_TCScratch scratch = DN_TCScratchBegin(&arena, 1); + DN_TCScratch scratch = DN_TCScratchBegin(&arena, 1); DN_Str8Builder stdout_builder = {}; DN_Str8Builder stderr_builder = {}; if (arena) { - stdout_builder.arena = scratch.arena; - stderr_builder.arena = scratch.arena; + stdout_builder = DN_Str8BuilderFromArena(&scratch.arena); + stderr_builder = DN_Str8BuilderFromArena(&scratch.arena); } DN_U32 const SLOW_WAIT_TIME_MS = 100; @@ -838,15 +836,15 @@ DN_API DN_OSExecResult DN_OS_ExecWait(DN_OSExecAsyncHandle handle, DN_Arena *are while (!result.finished) { size_t stdout_size = DN_Kilobytes(8); size_t stderr_size = DN_Kilobytes(8); - char *stdout_buffer = DN_ArenaNewArray(scratch.arena, char, stdout_size, DN_ZMem_No); - char *stderr_buffer = DN_ArenaNewArray(scratch.arena, char, stderr_size, DN_ZMem_No); + char *stdout_buffer = DN_ArenaNewArray(&scratch.arena, char, stdout_size, DN_ZMem_No); + char *stderr_buffer = DN_ArenaNewArray(&scratch.arena, char, stderr_size, DN_ZMem_No); result = DN_OS_ExecPump(handle, stdout_buffer, &stdout_size, stderr_buffer, &stderr_size, wait_ms, err); DN_Str8BuilderAppendCopy(&stdout_builder, result.stdout_text); DN_Str8BuilderAppendCopy(&stderr_builder, result.stderr_text); wait_ms = (result.stdout_text.size || result.stderr_text.size) ? FAST_WAIT_TIME_MS : SLOW_WAIT_TIME_MS; } - // NOTE: Get stdout/stderr. If no arena is passed this is a no-op ////////////////////////////// + // NOTE: Get stdout/stderr. If no arena is passed this is a no-op result.stdout_text = DN_Str8BuilderBuild(&stdout_builder, arena); result.stderr_text = DN_Str8BuilderBuild(&stderr_builder, arena); DN_TCScratchEnd(&scratch); @@ -861,19 +859,19 @@ DN_API DN_OSExecAsyncHandle DN_OS_ExecAsync(DN_Str8Slice cmd_line, DN_OSExecArgs return result; DN_TCScratch scratch = DN_TCScratchBegin(nullptr, 0); - DN_Str8 cmd_rendered = DN_Str8SliceRender(cmd_line, DN_Str8Lit(" "), scratch.arena); - DN_Str16 cmd16 = DN_OS_W32Str8ToStr16(scratch.arena, cmd_rendered); - DN_Str16 working_dir16 = DN_OS_W32Str8ToStr16(scratch.arena, args->working_dir); + DN_Str8 cmd_rendered = DN_Str8SliceRender(cmd_line, DN_Str8Lit(" "), &scratch.arena); + DN_Str16 cmd16 = DN_OS_W32Str8ToStr16(&scratch.arena, cmd_rendered); + DN_Str16 working_dir16 = DN_OS_W32Str8ToStr16(&scratch.arena, args->working_dir); - DN_Str8Builder env_builder = DN_Str8BuilderFromArena(scratch.arena); + DN_Str8Builder env_builder = DN_Str8BuilderFromArena(&scratch.arena); DN_Str8BuilderAppendArrayRef(&env_builder, args->environment.data, args->environment.count); if (env_builder.string_size) DN_Str8BuilderAppendRef(&env_builder, DN_Str8Lit("\0")); - DN_Str8 env_block8 = DN_Str8BuilderBuildDelimited(&env_builder, DN_Str8Lit("\0"), scratch.arena); + DN_Str8 env_block8 = DN_Str8BuilderBuildDelimited(&env_builder, DN_Str8Lit("\0"), &scratch.arena); DN_Str16 env_block16 = {}; if (env_block8.size) - env_block16 = DN_OS_W32Str8ToStr16(scratch.arena, env_block8); + env_block16 = DN_OS_W32Str8ToStr16(&scratch.arena, env_block8); // NOTE: Stdout/err security attributes SECURITY_ATTRIBUTES save_std_security_attribs = {}; @@ -893,7 +891,7 @@ DN_API DN_OSExecAsyncHandle DN_OS_ExecAsync(DN_Str8Slice cmd_line, DN_OSExecArgs if (DN_BitIsSet(args->flags, DN_OSExecFlags_SaveStdout)) { if (!CreatePipe(&stdout_read, &stdout_write, &save_std_security_attribs, /*nSize*/ 0)) { - DN_OSW32Error win_error = DN_OS_W32LastError(scratch.arena); + DN_OSW32Error win_error = DN_OS_W32LastError(&scratch.arena); result.os_error_code = win_error.code; DN_ErrSinkAppendF( err, @@ -906,7 +904,7 @@ DN_API DN_OSExecAsyncHandle DN_OS_ExecAsync(DN_Str8Slice cmd_line, DN_OSExecArgs } if (!SetHandleInformation(stdout_read, HANDLE_FLAG_INHERIT, 0)) { - DN_OSW32Error win_error = DN_OS_W32LastError(scratch.arena); + DN_OSW32Error win_error = DN_OS_W32LastError(&scratch.arena); result.os_error_code = win_error.code; DN_ErrSinkAppendF(err, result.os_error_code, @@ -936,7 +934,7 @@ DN_API DN_OSExecAsyncHandle DN_OS_ExecAsync(DN_Str8Slice cmd_line, DN_OSExecArgs stderr_write = stdout_write; } else { if (!CreatePipe(&stderr_read, &stderr_write, &save_std_security_attribs, /*nSize*/ 0)) { - DN_OSW32Error win_error = DN_OS_W32LastError(scratch.arena); + DN_OSW32Error win_error = DN_OS_W32LastError(&scratch.arena); result.os_error_code = win_error.code; DN_ErrSinkAppendF( err, @@ -949,7 +947,7 @@ DN_API DN_OSExecAsyncHandle DN_OS_ExecAsync(DN_Str8Slice cmd_line, DN_OSExecArgs } if (!SetHandleInformation(stderr_read, HANDLE_FLAG_INHERIT, 0)) { - DN_OSW32Error win_error = DN_OS_W32LastError(scratch.arena); + DN_OSW32Error win_error = DN_OS_W32LastError(&scratch.arena); result.os_error_code = win_error.code; DN_ErrSinkAppendF(err, result.os_error_code, @@ -963,7 +961,7 @@ DN_API DN_OSExecAsyncHandle DN_OS_ExecAsync(DN_Str8Slice cmd_line, DN_OSExecArgs } } - // NOTE: Execute command /////////////////////////////////////////////////////////////////////// + // NOTE: Execute command PROCESS_INFORMATION proc_info = {}; STARTUPINFOW startup_info = {}; startup_info.cb = sizeof(STARTUPINFOW); @@ -982,14 +980,14 @@ DN_API DN_OSExecAsyncHandle DN_OS_ExecAsync(DN_Str8Slice cmd_line, DN_OSExecArgs &startup_info, &proc_info); if (!create_result) { - DN_OSW32Error win_error = DN_OS_W32LastError(scratch.arena); + DN_OSW32Error win_error = DN_OS_W32LastError(&scratch.arena); result.os_error_code = win_error.code; DN_ErrSinkAppendF(err, result.os_error_code, "Failed to execute command '%.*s': %.*s", DN_Str8PrintFmt(cmd_rendered), DN_Str8PrintFmt(win_error.msg)); DN_TCScratchEnd(&scratch); return result; } - // NOTE: Post-amble //////////////////////////////////////////////////////////////////////////// + // NOTE: Post-amble CloseHandle(proc_info.hThread); result.process = proc_info.hProcess; result.stdout_read = stdout_read; @@ -1280,7 +1278,7 @@ DN_API bool DN_OS_ThreadInit(DN_OSThread *thread, DN_OSThreadFunc *func, DN_OSTh return result; } -DN_API bool DN_OS_ThreadJoin(DN_OSThread *thread) +DN_API bool DN_OS_ThreadJoin(DN_OSThread *thread, DN_TCDeinitArenas deinit_arenas) { bool result = false; if (thread && thread->handle) { @@ -1289,7 +1287,7 @@ DN_API bool DN_OS_ThreadJoin(DN_OSThread *thread) CloseHandle(thread->handle); thread->handle = INVALID_HANDLE_VALUE; thread->thread_id = {}; - DN_TCDeinit(&thread->context); + DN_TCDeinit(&thread->context, deinit_arenas); } return result; } @@ -1309,7 +1307,7 @@ DN_API void DN_OS_W32ThreadSetName(DN_Str8 name) DN_OSW32Core *w32 = DN_OS_W32GetCore(); DN_TCScratch scratch = DN_TCScratchBegin(nullptr, 0); if (w32->set_thread_description) { - DN_Str16 name16 = DN_OS_W32Str8ToStr16(scratch.arena, name); + DN_Str16 name16 = DN_OS_W32Str8ToStr16(&scratch.arena, name); w32->set_thread_description(GetCurrentThread(), (WCHAR *)name16.data); } else { // NOTE: Fallback to throw-exception method to set thread name @@ -1323,11 +1321,11 @@ DN_API void DN_OS_W32ThreadSetName(DN_Str8 name) }; #pragma pack(pop) - DN_Str8 copy = DN_Str8FromStr8Arena(scratch.arena, name); + DN_Str8 copy = DN_Str8FromStr8Arena(name, &scratch.arena); DN_OSW32ThreadNameInfo info = {}; - info.dwType = 0x1000; - info.szName = (char *)copy.data; - info.dwThreadID = DN_OS_ThreadID(); + info.dwType = 0x1000; + info.szName = (char *)copy.data; + info.dwThreadID = DN_OS_ThreadID(); // TODO: Review warning 6320 DN_MSVC_WARNING_PUSH @@ -1342,7 +1340,6 @@ DN_API void DN_OS_W32ThreadSetName(DN_Str8 name) DN_TCScratchEnd(&scratch); } -// NOTE: DN_OSHttp ///////////////////////////////////////////////////////////////////////////////// void DN_OS_HttpRequestWin32Callback(HINTERNET session, DWORD *dwContext, DWORD dwInternetStatus, VOID *lpvStatusInformation, DWORD dwStatusInformationLength) { (void)session; @@ -1449,13 +1446,12 @@ DN_API void DN_OS_HttpRequestAsync(DN_OSHttpResponse *response, if (!response || !arena) return; - response->arena = arena; - response->builder.arena = response->scratch_arena ? response->scratch_arena : &response->tmp_arena; + response->arena = arena; + response->builder = DN_Str8BuilderFromArena(response->scratch_arena.mem ? &response->scratch_arena : &response->tmp_arena); - DN_Arena *scratch_arena = response->scratch_arena; - DN_TCScratch scratch_ = DN_TCScratchBegin(&arena, 1); - if (!scratch_arena) - scratch_arena = scratch_.arena; + DN_TCScratch scratch_ = DN_TCScratchBegin(&arena, 1); + if (!response->scratch_arena.mem) + response->scratch_arena = scratch_.arena; DN_OSW32Error error = {}; DN_DEFER @@ -1489,28 +1485,28 @@ DN_API void DN_OS_HttpRequestAsync(DN_OSHttpResponse *response, return; } - DN_Str16 host16 = DN_OS_W32Str8ToStr16(scratch_arena, host); + DN_Str16 host16 = DN_OS_W32Str8ToStr16(&response->scratch_arena, host); response->w32_request_connection = WinHttpConnect(response->w32_request_session, host16.data, secure ? INTERNET_DEFAULT_HTTPS_PORT : INTERNET_DEFAULT_HTTP_PORT, 0 /*reserved*/); if (!response->w32_request_connection) { error = DN_OS_W32LastError(&response->tmp_arena); return; } - DN_Str16 method16 = DN_OS_W32Str8ToStr16(scratch_arena, method); - DN_Str16 path16 = DN_OS_W32Str8ToStr16(scratch_arena, path); + DN_Str16 method16 = DN_OS_W32Str8ToStr16(&response->scratch_arena, method); + DN_Str16 path16 = DN_OS_W32Str8ToStr16(&response->scratch_arena, path); response->w32_request_handle = WinHttpOpenRequest(response->w32_request_connection, - method16.data, - path16.data, - nullptr /*version*/, - nullptr /*referrer*/, - nullptr /*accept types*/, - secure ? WINHTTP_FLAG_SECURE : 0); + method16.data, + path16.data, + nullptr /*version*/, + nullptr /*referrer*/, + nullptr /*accept types*/, + secure ? WINHTTP_FLAG_SECURE : 0); if (!response->w32_request_handle) { error = DN_OS_W32LastError(&response->tmp_arena); return; } - DN_Str16 headers16 = DN_OS_W32Str8ToStr16(scratch_arena, headers); + DN_Str16 headers16 = DN_OS_W32Str8ToStr16(&response->scratch_arena, headers); response->on_complete_semaphore = DN_OS_SemaphoreInit(0); if (!WinHttpSendRequest(response->w32_request_handle, headers16.data, @@ -1535,7 +1531,7 @@ DN_API void DN_OS_HttpRequestFree(DN_OSHttpResponse *response) response->w32_request_session = nullptr; response->w32_request_connection = nullptr; response->w32_request_handle = nullptr; - DN_ArenaDeinit(&response->tmp_arena); + DN_MemListDeinit(response->tmp_arena.mem); DN_OS_SemaphoreDeinit(&response->on_complete_semaphore); *response = {}; @@ -1626,7 +1622,6 @@ DN_API void DN_OS_W32MakeProcessDPIAware() set_process_dpi_aware(); } -// NOTE: Windows UTF8 to Str16 ////////////////////////////////////////////// DN_API DN_Str16 DN_OS_W32Str8ToStr16(DN_Arena *arena, DN_Str8 src) { DN_Str16 result = {}; @@ -1665,7 +1660,6 @@ DN_API int DN_OS_W32Str8ToStr16Buffer(DN_Str8 src, wchar_t *dest, int dest_size) return result; } -// NOTE: Windows Str16 To UTF8 ////////////////////////////////////////////////////////////////// DN_API int DN_OS_W32Str16ToStr8Buffer(DN_Str16 src, char *dest, int dest_size) { int result = 0; @@ -1701,18 +1695,16 @@ DN_API DN_Str8 DN_OS_W32Str16ToStr8(DN_Arena *arena, DN_Str16 src) // NOTE: Str8 allocate ensures there's one extra byte for // null-termination already so no-need to +1 the required size - DN_ArenaTempMemScope temp_mem = DN_ArenaTempMemScope(arena); - DN_Str8 buffer = DN_Str8AllocArena(arena, required_size, DN_ZMem_No); - if (buffer.size == 0) - return result; - - int chars_written = WideCharToMultiByte(CP_UTF8, 0 /*dwFlags*/, src.data, src_size, buffer.data, DN_Cast(int) buffer.size, nullptr, nullptr); - if (DN_Check(chars_written == required_size)) { - result = buffer; - result.data[result.size] = 0; - temp_mem.mem = {}; + DN_Arena temp = DN_ArenaTempBeginFromArena(arena); + DN_Str8 buffer = DN_Str8AllocArena(required_size, DN_ZMem_No, &temp); + if (buffer.size) { + int chars_written = WideCharToMultiByte(CP_UTF8, 0 /*dwFlags*/, src.data, src_size, buffer.data, DN_Cast(int) buffer.size, nullptr, nullptr); + if (DN_Check(chars_written == required_size)) { + result = buffer; + result.data[result.size] = 0; + } } - + DN_ArenaTempEnd(&temp, result.size == DN_Cast(DN_USize)required_size ? DN_ArenaReset_No : DN_ArenaReset_Yes); return result; } @@ -1757,7 +1749,7 @@ DN_API DN_Str16 DN_OS_W32EXEPathW(DN_Arena *arena) wchar_t *module_path = nullptr; do { module_size += 256; - module_path = DN_ArenaNewArray(scratch.arena, wchar_t, module_size, DN_ZMem_No); + module_path = DN_ArenaNewArray(&scratch.arena, wchar_t, module_size, DN_ZMem_No); if (!module_path) { DN_TCScratchEnd(&scratch); return result; @@ -1786,7 +1778,7 @@ DN_API DN_Str16 DN_OS_W32EXEDirW(DN_Arena *arena) wchar_t *module_path = nullptr; do { module_size += 256; - module_path = DN_ArenaNewArray(scratch.arena, wchar_t, module_size, DN_ZMem_No); + module_path = DN_ArenaNewArray(&scratch.arena, wchar_t, module_size, DN_ZMem_No); if (!module_path) { DN_TCScratchEnd(&scratch); return result; @@ -1808,10 +1800,10 @@ DN_API DN_Str16 DN_OS_W32EXEDirW(DN_Arena *arena) DN_API DN_Str8 DN_OS_W32WorkingDir(DN_Arena *arena, DN_Str8 suffix) { - DN_TCScratch scratch = DN_TCScratchBegin(&arena, 1); - DN_Str16 suffix16 = DN_OS_W32Str8ToStr16(scratch.arena, suffix); - DN_Str16 dir16 = DN_OS_W32WorkingDirW(scratch.arena, suffix16); - DN_Str8 result = DN_OS_W32Str16ToStr8(arena, dir16); + DN_TCScratch scratch = DN_TCScratchBegin(&arena, 1); + DN_Str16 suffix16 = DN_OS_W32Str8ToStr16(&scratch.arena, suffix); + DN_Str16 dir16 = DN_OS_W32WorkingDirW(&scratch.arena, suffix16); + DN_Str8 result = DN_OS_W32Str16ToStr8(arena, dir16); DN_TCScratchEnd(&scratch); return result; } @@ -1822,11 +1814,11 @@ DN_API DN_Str16 DN_OS_W32WorkingDirW(DN_Arena *arena, DN_Str16 suffix) DN_Str16 result = {}; // NOTE: required_size is the size required *including* the null-terminator - DN_TCScratch scratch = DN_TCScratchBegin(&arena, 1); + DN_TCScratch scratch = DN_TCScratchBegin(&arena, 1); unsigned long required_size = GetCurrentDirectoryW(0, nullptr); unsigned long desired_size = required_size + DN_Cast(unsigned long) suffix.size; - wchar_t *scratch_w_path = DN_ArenaNewArray(scratch.arena, wchar_t, desired_size, DN_ZMem_No); + wchar_t *scratch_w_path = DN_ArenaNewArray(&scratch.arena, wchar_t, desired_size, DN_ZMem_No); if (!scratch_w_path) { DN_TCScratchEnd(&scratch); return result; diff --git a/Source/Standalone/dn_ini.c b/Source/Standalone/dn_ini.c index 328c0a8..6df1b7a 100644 --- a/Source/Standalone/dn_ini.c +++ b/Source/Standalone/dn_ini.c @@ -318,7 +318,7 @@ DN_INIToken DN_INI_NextToken(DN_INITokeniser const *tokeniser) if (DN_INI_Str8Eq(esc_str8, DN_INIStr8Lit("\n"))) { result.next_p += 2; } else if (DN_INI_Str8Eq(esc_str8, DN_INIStr8Lit("\\"))) { - // NOTE: Backespace is escaping a backspace + // NOTE: Backspace is escaping a backspace } else { result.next_p += 1; } @@ -340,7 +340,19 @@ DN_INIToken DN_INI_NextToken(DN_INITokeniser const *tokeniser) if (tokeniser->prev_token.type == DN_INITokenType_FieldSeparator || multiline_value || value) { if (tokeniser->data[pos] == ' ') // Value can have spaces in it without quotes continue; - result.type = tokeniser->prev_token.type == DN_INITokenType_FieldSeparator ? DN_INITokenType_Value : DN_INITokenType_MultilineValue; + + if (tokeniser->prev_token.type == DN_INITokenType_FieldSeparator) { + if (result.line_start_new_line) { + // NOTE: The user has terminated the value component of the key with a newline + // (e.g. no value presented). For example: `their_key=\n` which means there's no + // value and instead they started a new key-value pair. + result.type = DN_INITokenType_Key; + } else { + result.type = DN_INITokenType_Value; + } + } else { + result.type = DN_INITokenType_MultilineValue; + } } else if (tokeniser->prev_token.type == DN_INITokenType_Key) { result.type = DN_INITokenType_Error; result.error = DN_INIStr8Lit("Invalid unquoted string, multiple consecutive keys encountered"); @@ -849,7 +861,7 @@ DN_INIField *DN_INI_AppendKeyF(DN_INICore *ini, DN_INIArena *arena, DN_INISectio return result; } -#if defined(DN_INI_WITH_UNIT_TESTS) || 1 +#if defined(DN_INI_WITH_UNIT_TESTS) void DN_INI_UnitTests() { // NOTE: Section and comments @@ -1106,5 +1118,27 @@ void DN_INI_UnitTests() DN_INI_Assert(parse.error_token.type == DN_INITokenType_Nil); DN_INI_Assert(DN_INI_Str8Eq(parse.first_section.child_first->first_field->key, DN_INIStr8Lit("foo"))); } + + // NOTE: 2 empty key-values consecutively + { + char const EXAMPLE[] = + "[metadata]\n" + "foo=\n" + "bar=\n" + ; + + DN_INICore parse = DN_INI_ParseFromPtr(EXAMPLE, sizeof(EXAMPLE) - 1, 0, 0); + DN_INI_Assert(parse.error_token.type == DN_INITokenType_Nil); + DN_INI_Assert(parse.total_sections_count == 1); + DN_INI_Assert(parse.total_fields_count == 2); + + char parse_memory[400]; + DN_INI_Assert(parse.memory_required <= sizeof(parse_memory)); + + parse = DN_INI_ParseFromPtr(EXAMPLE, sizeof(EXAMPLE) - 1, parse_memory, sizeof(parse_memory)); + DN_INI_Assert(parse.error_token.type == DN_INITokenType_Nil); + DN_INI_Assert(DN_INI_Str8Eq(parse.first_section.child_first->first_field->key, DN_INIStr8Lit("foo"))); + DN_INI_Assert(DN_INI_Str8Eq(parse.first_section.child_first->first_field->next->key, DN_INIStr8Lit("bar"))); + } } #endif diff --git a/Source/Standalone/dn_ini.h b/Source/Standalone/dn_ini.h index 024f6d4..3a82ca4 100644 --- a/Source/Standalone/dn_ini.h +++ b/Source/Standalone/dn_ini.h @@ -1,34 +1,127 @@ #if !defined(DN_INI_H) #define DN_INI_H -#include // size_t +// NOTE: DN INI Configuration +// Getting Started +// This is a single header and implementation file library that implements .ini file handling. +// It supports the following .ini features: +// +// - Plain sections: [sections] +// - Arbitrarily nested sections delimited by '.': [sections.a] [sections.a.b] [sections.a.b....] +// - Repeated section names (the last section takes precedence) +// - Comments marked by #: [section] # Comment +// - Multi-line values for keys: +// [my_section] +// the_key = the_value \ +// another line for the key \ +// and another one +// the_next_key = that's cool +// +// Include both .h and .c in your translation unit or compile the .c separately and link against +// it to get started. The goals of the library are as follows: +// +// - Zero allocations to parse, accepts a NULL buffer to determine the amount of bytes required +// to parse the .ini buffer +// - Compile in C99 and compatible with C++ +// +// Example +/* + #include + #include + #include + #include "dn_ini.h" + #include "dn_ini.c" -#if !defined(DN_INI_Assert) - #include - #define DN_INI_Assert(expr) assert(expr) -#endif + void main() { + DN_INIStr8 ini_buffer = DN_INIStr8Lit( + "[my_stuff]\n" + "app=the_stuff # Comment on the stuff value\n" + "\n" + "[section]\n" + "item=abc\n" + "\n" + "[section.foo.xyz]\n" + "another=one\n" + "multi_line_key=coolios \\\n" + "from another line?!\n" + ); -#include + // 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.size, NULL, 0); + size_t parse_buffer_size = ini.memory_required; + char* parse_buffer = calloc(1, parse_buffer_size); -#if !defined(DN_INI_VSNPrintF) - #include - #define DN_INI_VSNPrintF(buffer, size, fmt, args) vsnprintf(buffer, size, fmt, args) -#endif + // NOTE: Parse the buffer into the `ini` object from the single allocation. No additional + // allocations are made + ini = DN_INI_ParseFromPtr(ini_buffer.data, ini_buffer.size, parse_buffer, parse_buffer_size); -#if !defined(DN_INI_Memset) || !defined(DN_INI_Memcmp) || !defined(DN_INI_Memcpy) - #include - #if !defined(DN_INI_Memset) - #define DN_INI_Memset(ptr, val, size) memset(ptr, val, size) + // NOTE: Process the ini file + // The .INI file parsed into a tree, resembling + // + // [Root (Sentinel)] <-- This is ini.first_section, its children contains the .ini contents + // | + // +-- [my_stuff] + // +-- [my_section] + // | + // +-- [foo] + // | + // +-- [xyz] + // + DN_INISection *my_stuff = DN_INI_ChildSectionFromStr8(&ini.first_section, DN_INIStr8Lit("my_stuff")); + DN_INISection *my_section = DN_INI_ChildSectionFromStr8(&ini.first_section, DN_INIStr8Lit("my_section")); + DN_INISection *my_section_foo = DN_INI_ChildSectionFromStr8(my_section, DN_INIStr8Lit("foo")); + DN_INISection *my_section_foo_xyz = DN_INI_ChildSectionFromStr8(my_section_foo, DN_INIStr8Lit("xyz")); + + printf("My Section Foo XYZ: %zu fields\n", my_section_foo_xyz->fields_count); + for (DN_INIField *field = my_section_foo->first_field; field; field = field->next) + printf(" %.*s: %.*s\n", (int)field->key.size, field->key.data, (int)field->value.size, field->value.data); + + // Alternatively you can access the section directly by specifying the fully qualified path from + // the section, e.g.: + DN_INISection *my_section_foo_xyz_direct = DN_INI_ChildSectionFromStr8(&ini.first_section, DN_INIStr8Lit("my_section.foo.xyz")); + if (my_section_foo_xyz_direct) { + // ... + } + + // You may also lookup the field directly by specifying the fully qualified path + DN_INIField *my_section_item = DN_INI_FieldFromSectionStr8(&ini.first_section, DN_INIStr8Lit("my_section.item")); + if (my_section_item) + printf(" %.*s: %.*s\n", (int)my_section_item->key.size, my_section_item->key.data, (int)my_section_item->value.size, my_section_item->value.data); + + // NOTE: Release memory, `ini` and its contents are invalidated and should not be used + free(parse_buffer); + } + */ + + #include // size_t + + #if !defined(DN_INI_Assert) + #include + #define DN_INI_Assert(expr) assert(expr) #endif - #if !defined(DN_INI_Memcmp) - #define DN_INI_Memcmp(dest, src, size) memcmp(dest, src, size) + #include + + #if !defined(DN_INI_VSNPrintF) + #include + #define DN_INI_VSNPrintF(buffer, size, fmt, args) vsnprintf(buffer, size, fmt, args) #endif - #if !defined(DN_INI_Memcpy) - #define DN_INI_Memcpy(dest, src, size) memcpy(dest, src, size) + #if !defined(DN_INI_Memset) || !defined(DN_INI_Memcmp) || !defined(DN_INI_Memcpy) + #include + #if !defined(DN_INI_Memset) + #define DN_INI_Memset(ptr, val, size) memset(ptr, val, size) + #endif + + #if !defined(DN_INI_Memcmp) + #define DN_INI_Memcmp(dest, src, size) memcmp(dest, src, size) + #endif + + #if !defined(DN_INI_Memcpy) + #define DN_INI_Memcpy(dest, src, size) memcpy(dest, src, size) + #endif #endif -#endif typedef enum DN_INITokenType { DN_INITokenType_Nil, @@ -175,7 +268,7 @@ DN_INIFieldStr8 DN_INI_FieldStr8FromSectionStr8 (DN_INISection *section, DN DN_INIFieldBool DN_INI_FieldBoolFromSectionStr8 (DN_INISection *section, DN_INIStr8 str8); DN_INICore DN_INI_ParseFromPtr (char const *buf, size_t count, char *base, size_t base_count); -// NOTE: Building +// NOTE: Building DN_INISection * DN_INI_AppendSectionF (DN_INICore *ini, DN_INIArena *arena, DN_INISection *section, char const *fmt, ...); DN_INIField * DN_INI_AppendKeyBool (DN_INICore *ini, DN_INIArena *arena, DN_INISection *section, DN_INIStr8 key, bool value); DN_INIField * DN_INI_AppendKeyPtrBool (DN_INICore *ini, DN_INIArena *arena, DN_INISection *section, char const *key, size_t key_size, bool value); diff --git a/Source/Standalone/dn_json_builder.c b/Source/Standalone/dn_json_builder.c new file mode 100644 index 0000000..48c0b2d --- /dev/null +++ b/Source/Standalone/dn_json_builder.c @@ -0,0 +1,299 @@ +#include "dn_json_builder.h" + +static void DN_JSB_Indent_(DN_JSBBuilder *builder, char *buf, size_t buf_size, size_t depth) +{ + for (size_t i = 0; i < depth; i++) { + DN_JSB_AppendF_(builder, buf, buf_size, " "); + } +} + +DN_JSBDepth *DN_JSB_PeekDepth_(DN_JSBBuilder *builder, size_t offset) +{ + DN_JSBDepth *result = 0; + if (builder->depth_count > offset) + result = &builder->depth[builder->depth_count - (1 + offset)]; + return result; +} + +bool DN_JSB_PushDepth_(DN_JSBBuilder *builder, DN_JSBDepthType type) +{ + bool result = false; + if (builder->depth_count < builder->depth_max) { + DN_JSBDepth *depth = &builder->depth[builder->depth_count++]; + depth->last_action = DN_JSBAction_Nil; + depth->type = type; + result = true; + } + return result; +} + +DN_JSBResult DN_JSB_PushObject(DN_JSBBuilder *builder, char *buf, size_t buf_size) +{ + DN_JSBDepth *top_depth = DN_JSB_PeekDepth_(builder, 0); + if (top_depth && top_depth->type != DN_JSBDepthType_Array) { + if ((top_depth->last_action == DN_JSBAction_Value || top_depth->last_action == DN_JSBAction_PopArray || top_depth->last_action == DN_JSBAction_PushObject)) + return DN_JSBResult_BadAPIUsage; + } + + if (!DN_JSB_PushDepth_(builder, DN_JSBDepthType_Object)) + return DN_JSBResult_DepthArrayOutOfMem; + + bool leading_comma = top_depth && (top_depth->last_action != DN_JSBAction_Nil && top_depth->last_action != DN_JSBAction_Key); + if (builder->pretty && top_depth && top_depth->type == DN_JSBDepthType_Array) { + if (leading_comma) { + DN_JSB_AppendF_(builder, buf, buf_size, ",\n"); + } else { + DN_JSB_AppendF_(builder, buf, buf_size, "\n"); + } + DN_JSB_Indent_(builder, buf, buf_size, builder->depth_count - 1); + leading_comma = false; + } + DN_JSBResult result = DN_JSB_AppendF_(builder, buf, buf_size, "%s{", leading_comma ? "," : ""); + if (top_depth) + top_depth->last_action = DN_JSBAction_PushObject; // Record the push on the now, previous depth + + if (builder->error == DN_JSBResult_Success) + builder->error = result; + return result; +} + +DN_JSBResult DN_JSB_PopObject(DN_JSBBuilder *builder, char *buf, size_t buf_size) +{ + DN_JSBDepth *top_depth = DN_JSB_PeekDepth_(builder, 0); + if (!top_depth || top_depth->type != DN_JSBDepthType_Object) + return DN_JSBResult_BadAPIUsage; + + bool had_children = top_depth->last_action != DN_JSBAction_Nil; + builder->depth_count--; // Remove the depth entry from the stack + + DN_JSBDepth *new_top = DN_JSB_PeekDepth_(builder, 0); + if (new_top) + new_top->last_action = DN_JSBAction_PopObject; + + if (builder->pretty && had_children) { + DN_JSB_AppendF_(builder, buf, buf_size, "\n"); + DN_JSB_Indent_(builder, buf, buf_size, builder->depth_count); + } + DN_JSBResult result = DN_JSB_AppendF_(builder, buf, buf_size, "}"); + if (builder->error == DN_JSBResult_Success) + builder->error = result; + return result; +} + +DN_JSBResult DN_JSB_PushArray(DN_JSBBuilder *builder, char *buf, size_t buf_size) +{ + DN_JSBDepth *top_depth = DN_JSB_PeekDepth_(builder, 0); + if (top_depth && top_depth->type != DN_JSBDepthType_Array) { + if (top_depth->last_action == DN_JSBAction_Value || top_depth->last_action == DN_JSBAction_PopArray || top_depth->last_action == DN_JSBAction_PushObject || top_depth->last_action == DN_JSBAction_PopObject) + return DN_JSBResult_BadAPIUsage; + } + + if (!DN_JSB_PushDepth_(builder, DN_JSBDepthType_Array)) + return DN_JSBResult_DepthArrayOutOfMem; + + bool leading_comma = top_depth && (top_depth->last_action != DN_JSBAction_Nil && top_depth->last_action != DN_JSBAction_Key); + if (builder->pretty && top_depth && top_depth->type == DN_JSBDepthType_Array) { + if (leading_comma) { + DN_JSB_AppendF_(builder, buf, buf_size, ",\n"); + } else { + DN_JSB_AppendF_(builder, buf, buf_size, "\n"); + } + DN_JSB_Indent_(builder, buf, buf_size, builder->depth_count - 1); + leading_comma = false; + } + DN_JSBResult result = DN_JSB_AppendF_(builder, buf, buf_size, "%s[", leading_comma ? "," : ""); + if (top_depth) + top_depth->last_action = DN_JSBAction_PushArray; // Record the push on the now, previous depth + if (builder->error == DN_JSBResult_Success) + builder->error = result; + return result; +} + +DN_JSBResult DN_JSB_PopArray(DN_JSBBuilder *builder, char *buf, size_t buf_size) +{ + DN_JSBDepth *top_depth = DN_JSB_PeekDepth_(builder, 0); + if (!top_depth || top_depth->type != DN_JSBDepthType_Array) + return DN_JSBResult_BadAPIUsage; + + bool had_children = top_depth->last_action != DN_JSBAction_Nil; + builder->depth_count--; // Remove the depth entry from the stack + DN_JSBDepth *new_top = DN_JSB_PeekDepth_(builder, 0); + if (new_top) + new_top->last_action = DN_JSBAction_PopArray; + + if (builder->pretty && had_children) { + DN_JSB_AppendF_(builder, buf, buf_size, "\n"); + DN_JSB_Indent_(builder, buf, buf_size, builder->depth_count); + } + DN_JSBResult result = DN_JSB_AppendF_(builder, buf, buf_size, "]"); + if (builder->error == DN_JSBResult_Success) + builder->error = result; + return result; +} + +DN_JSBResult DN_JSB_KeyF(DN_JSBBuilder *builder, char *buf, size_t buf_size, char const *fmt, ...) +{ + DN_JSBDepth *top_depth = DN_JSB_PeekDepth_(builder, 0); + if (!top_depth || top_depth->last_action == DN_JSBAction_Key || top_depth->last_action == DN_JSBAction_PushArray) + return DN_JSBResult_BadAPIUsage; + + va_list args; + va_start(args, fmt); + if (builder->pretty) { + if (top_depth->last_action != DN_JSBAction_Nil) { + DN_JSB_AppendF_(builder, buf, buf_size, ",\n"); + } else { + DN_JSB_AppendF_(builder, buf, buf_size, "\n"); + } + DN_JSB_Indent_(builder, buf, buf_size, builder->depth_count); + DN_JSB_AppendF_(builder, buf, buf_size, "\""); + DN_JSB_AppendFV_(builder, buf, buf_size, fmt, args); + DN_JSBResult result = DN_JSB_AppendF_(builder, buf, buf_size, "\": "); + va_end(args); + if (result == DN_JSBResult_Success) + top_depth->last_action = DN_JSBAction_Key; + if (builder->error == DN_JSBResult_Success) + builder->error = result; + return result; + } + DN_JSB_AppendF_(builder, buf, buf_size, "%s\"", top_depth->last_action != DN_JSBAction_Nil ? "," : ""); + DN_JSB_AppendFV_(builder, buf, buf_size, fmt, args); + DN_JSBResult result = DN_JSB_AppendF_(builder, buf, buf_size, "\":"); + va_end(args); + + if (result == DN_JSBResult_Success) + top_depth->last_action = DN_JSBAction_Key; + if (builder->error == DN_JSBResult_Success) + builder->error = result; + return result; +} + +DN_JSBResult DN_JSB_ValueStringF(DN_JSBBuilder *builder, char *buf, size_t buf_size, char const *fmt, ...) +{ + DN_JSBResult result = DN_JSB_BeginWriteValue_(builder, buf, buf_size); + if (result == DN_JSBResult_Success) { + DN_JSB_AppendF_(builder, buf, buf_size, "\""); + va_list args; + va_start(args, fmt); + DN_JSB_AppendFV_(builder, buf, buf_size, fmt, args); + va_end(args); + result = DN_JSB_AppendF_(builder, buf, buf_size, "\""); + DN_JSB_FinishWriteValue_(builder, result); + } + if (builder->error == DN_JSBResult_Success) + builder->error = result; + return result; +} + +DN_JSBResult DN_JSB_ValueNull(DN_JSBBuilder *builder, char *buf, size_t buf_size) +{ + DN_JSBResult result = DN_JSB_BeginWriteValue_(builder, buf, buf_size); + if (result == DN_JSBResult_Success) { + result = DN_JSB_AppendF_(builder, buf, buf_size, "null"); + DN_JSB_FinishWriteValue_(builder, result); + } + if (builder->error == DN_JSBResult_Success) + builder->error = result; + return result; +} + +DN_JSBResult DN_JSB_ValueBool(DN_JSBBuilder *builder, char *buf, size_t buf_size, bool flag) +{ + DN_JSBResult result = DN_JSB_BeginWriteValue_(builder, buf, buf_size); + if (result == DN_JSBResult_Success) { + result = DN_JSB_AppendF_(builder, buf, buf_size, flag ? "true" : "false"); + DN_JSB_FinishWriteValue_(builder, result); + } + if (builder->error == DN_JSBResult_Success) + builder->error = result; + return result; +} + +DN_JSBResult DN_JSB_ValueNumber(DN_JSBBuilder *builder, char *buf, size_t buf_size, double number) +{ + DN_JSBResult result = DN_JSB_BeginWriteValue_(builder, buf, buf_size); + if (result == DN_JSBResult_Success) { + result = DN_JSB_AppendF_(builder, buf, buf_size, "%.17G", number); + DN_JSB_FinishWriteValue_(builder, result); + } + if (builder->error == DN_JSBResult_Success) + builder->error = result; + return result; +} + +DN_JSBResult DN_JSB_BeginWriteValue_(DN_JSBBuilder *builder, char *buf, size_t buf_size) +{ + DN_JSBDepth *top = DN_JSB_PeekDepth_(builder, 0); + if (!top) + return DN_JSBResult_BadAPIUsage; + + bool is_key = top->last_action == DN_JSBAction_Key; + bool is_array = top->type == DN_JSBDepthType_Array; + if (!is_key && !is_array) + return DN_JSBResult_BadAPIUsage; + + DN_JSBResult result = DN_JSBResult_Success; + if (top->type == DN_JSBDepthType_Array) { + if (builder->pretty) { + if (top->last_action != DN_JSBAction_Nil) { + DN_JSB_AppendF_(builder, buf, buf_size, ",\n"); + } else { + DN_JSB_AppendF_(builder, buf, buf_size, "\n"); + } + DN_JSB_Indent_(builder, buf, buf_size, builder->depth_count); + } else if (top->last_action != DN_JSBAction_Nil) { + result = DN_JSB_AppendF_(builder, buf, buf_size, ","); + } + } + return result; +} + +void DN_JSB_FinishWriteValue_(DN_JSBBuilder *builder, DN_JSBResult last_value_raw_str_result) +{ + if (last_value_raw_str_result == DN_JSBResult_Success) { + DN_JSBDepth *top_depth = DN_JSB_PeekDepth_(builder, 0); + top_depth->last_action = DN_JSBAction_Value; + } +} + +DN_JSBResult DN_JSB_AppendFV_(DN_JSBBuilder *builder, char *buf, size_t buf_size, char const *fmt, va_list args) +{ + // NOTE: Calc size required + size_t size = 0; + { + va_list args_copy; + va_copy(args_copy, args); + size = DN_JSB_VSNPrintF(0, 0, fmt, args_copy); + va_end(args_copy); + } + + // NOTE: Do the write + DN_JSBResult result = DN_JSBResult_Success; + if (buf) { + if (builder->p > buf_size) + return DN_JSBResult_BadAPIUsage; + + char *dest = buf + builder->p; + size_t dest_size = (buf + buf_size) - dest; + if ((size + 1) <= dest_size) { // NOTE: +1 because vsnprintf always null-terminates the stream + DN_JSB_VSNPrintF(dest, dest_size, fmt, args); + } else { + result = DN_JSBResult_BufOutOfMem; + } + } + + if (result == DN_JSBResult_Success) + builder->p += size; + if (builder->error == DN_JSBResult_Success) + builder->error = result; + return result; +} + +DN_JSBResult DN_JSB_AppendF_(DN_JSBBuilder *builder, char *buf, size_t buf_size, char const *fmt, ...) +{ + va_list args; + va_start(args, fmt); + DN_JSBResult result = DN_JSB_AppendFV_(builder, buf, buf_size, fmt, args); + va_end(args); + return result; +} diff --git a/Source/Standalone/dn_json_builder.h b/Source/Standalone/dn_json_builder.h new file mode 100644 index 0000000..28bbb40 --- /dev/null +++ b/Source/Standalone/dn_json_builder.h @@ -0,0 +1,73 @@ +#if !defined(DN_JSON_BUILDER_H) +#define DN_JSON_BUILDER_H + +#include + +#if !defined(__cplusplus) + #include +#endif + +#if !defined(DN_JSB_VSNPrintF) + #include + #define DN_JSB_VSNPrintF(buf, size, fmt, args) vsnprintf(buf, size, fmt, args) +#endif + +typedef enum DN_JSBResult { + DN_JSBResult_Success, + DN_JSBResult_BadAPIUsage, + DN_JSBResult_DepthArrayOutOfMem, + DN_JSBResult_BufOutOfMem, +} DN_JSBResult; + +typedef enum DN_JSBPrettify { + DN_JSBPrettify_No, + DN_JSBPrettify_Yes, +} DN_JSBPrettify; + +typedef enum DN_JSBDepthType { + DN_JSBDepthType_Nil, + DN_JSBDepthType_Object, + DN_JSBDepthType_Array, +} DN_JSBDepthType; + +typedef enum DN_JSBAction { + DN_JSBAction_Nil, + DN_JSBAction_PushObject, + DN_JSBAction_PopObject, + DN_JSBAction_PushArray, + DN_JSBAction_PopArray, + DN_JSBAction_Key, + DN_JSBAction_Value, +} DN_JSBAction; + +typedef struct DN_JSBDepth { + DN_JSBDepthType type; + DN_JSBAction last_action; +} DN_JSBDepth; + +typedef struct DN_JSBBuilder { + DN_JSBDepth* depth; + size_t depth_count; + size_t depth_max; + size_t p; // Size required not incl- the null-terminator (e.g. To build, pass in `p + 1` bytes) + DN_JSBResult error; + DN_JSBPrettify pretty; +} DN_JSBBuilder; + +DN_JSBResult DN_JSB_PushObject (DN_JSBBuilder *builder, char *buf, size_t buf_size); +DN_JSBResult DN_JSB_PopObject (DN_JSBBuilder *builder, char *buf, size_t buf_size); +DN_JSBResult DN_JSB_PushArray (DN_JSBBuilder *builder, char *buf, size_t buf_size); +DN_JSBResult DN_JSB_PopArray (DN_JSBBuilder *builder, char *buf, size_t buf_size); +DN_JSBResult DN_JSB_KeyF (DN_JSBBuilder *builder, char *buf, size_t buf_size, char const *fmt, ...); +DN_JSBResult DN_JSB_ValueStringF (DN_JSBBuilder *builder, char *buf, size_t buf_size, char const *fmt, ...); +DN_JSBResult DN_JSB_ValueBool (DN_JSBBuilder *builder, char *buf, size_t buf_size, bool flag); +DN_JSBResult DN_JSB_ValueNull (DN_JSBBuilder *builder, char *buf, size_t buf_size); +DN_JSBResult DN_JSB_ValueNumber (DN_JSBBuilder *builder, char *buf, size_t buf_size, double number); + +DN_JSBDepth * DN_JSB_PeekDepth_ (DN_JSBBuilder *builder, size_t offset); +bool DN_JSB_PushDepth_ (DN_JSBBuilder *builder, DN_JSBDepthType type); +DN_JSBResult DN_JSB_AppendFV_ (DN_JSBBuilder *builder, char *buf, size_t buf_size, char const *fmt, va_list args); +DN_JSBResult DN_JSB_AppendF_ (DN_JSBBuilder *builder, char *buf, size_t buf_size, char const *fmt, ...); +DN_JSBResult DN_JSB_BeginWriteValue_ (DN_JSBBuilder *builder, char *buf, size_t buf_size); +void DN_JSB_FinishWriteValue_(DN_JSBBuilder *builder, DN_JSBResult last_value_raw_str_result); +#endif // !defined(DN_JSON_BUILDER_H) diff --git a/Source/Standalone/dn_utest.h b/Source/Standalone/dn_utest.h index 268bd4e..200eaea 100644 --- a/Source/Standalone/dn_utest.h +++ b/Source/Standalone/dn_utest.h @@ -160,6 +160,9 @@ typedef struct DN_UTCore DN_UTStr8Link *output; } DN_UTCore; +DN_UTCore DN_UT_Init(); +void DN_UT_Deinit(DN_UTCore *ut); + void DN_UT_BeginFV(DN_UTCore *test, char const *fmt, va_list args); void DN_UT_BeginF(DN_UTCore *test, char const *fmt, ...); void DN_UT_End(DN_UTCore *test); diff --git a/Source/dn.cpp b/Source/dn.cpp index 35e4463..0c278a1 100644 --- a/Source/dn.cpp +++ b/Source/dn.cpp @@ -50,9 +50,9 @@ DN_API void DN_Init(DN_Core *dn, DN_InitFlags flags, DN_InitArgs *args) #endif } - { - os->arena = DN_ArenaFromMemFuncs(DN_Megabytes(1), DN_Kilobytes(4), DN_ArenaFlags_NoAllocTrack, DN_ArenaMemFuncsGetDefaults()); + os->mem = DN_MemListFromMemFuncs(DN_Megabytes(1), DN_Kilobytes(4), DN_MemFlags_NoAllocTrack, DN_MemFuncsDefault()); + os->arena = DN_ArenaFromMemList(&os->mem); #if defined(DN_PLATFORM_WIN32) os->platform_context = DN_ArenaNew(&os->arena, DN_OSW32Core, DN_ZMem_Yes); @@ -97,7 +97,8 @@ DN_API void DN_Init(DN_Core *dn, DN_InitFlags flags, DN_InitArgs *args) #if DN_H_WITH_OS // NOTE: Setup the allocation table with allocation tracking turned off on // the arena we're using to initialise the table. - dn->leak.alloc_table_arena = DN_ArenaFromMemFuncs(DN_Megabytes(1), DN_Kilobytes(512), DN_ArenaFlags_NoAllocTrack | DN_ArenaFlags_AllocCanLeak, DN_ArenaMemFuncsGetDefaults()); + dn->leak.alloc_table_mem = DN_MemListFromMemFuncs(DN_Megabytes(1), DN_Kilobytes(512), DN_MemFlags_NoAllocTrack | DN_MemFlags_AllocCanLeak, DN_MemFuncsDefault()); + dn->leak.alloc_table_arena = DN_ArenaFromMemList(&dn->leak.alloc_table_mem); dn->leak.alloc_table = DN_DSMapInit(&dn->leak.alloc_table_arena, 4096, DN_DSMapFlags_Nil); #endif } @@ -106,7 +107,7 @@ DN_API void DN_Init(DN_Core *dn, DN_InitFlags flags, DN_InitArgs *args) DN_Assert(dn->os_init); #if DN_H_WITH_OS DN_TCInitArgs *tc_init_args = args ? &args->thread_context_init_args : nullptr; - DN_TCInitFromMemFuncs(&dn->main_tc, DN_OS_ThreadID(), tc_init_args, DN_ArenaMemFuncsGetDefaults()); + DN_TCInitFromMemFuncs(&dn->main_tc, DN_OS_ThreadID(), tc_init_args, DN_MemFuncsDefault()); DN_TCEquip(&dn->main_tc); #endif } @@ -133,17 +134,17 @@ DN_API void DN_Init(DN_Core *dn, DN_InitFlags flags, DN_InitArgs *args) if (DN_BitIsSet(flags, DN_InitFlags_ThreadContext)) { DN_Arena *arena = dn->main_tc.main_arena; DN_Str8 mem_funcs = DN_Str8Lit(""); - switch (arena->mem_funcs.type) { - case DN_ArenaMemFuncType_Nil: break; - case DN_ArenaMemFuncType_Basic: mem_funcs = DN_Str8Lit("Basic"); break; - case DN_ArenaMemFuncType_VMem: mem_funcs = DN_Str8Lit("VMem"); break; + switch (arena->mem->funcs.type) { + case DN_MemFuncsType_Nil: break; + case DN_MemFuncsType_Heap: mem_funcs = DN_Str8Lit("Heap"); break; + case DN_MemFuncsType_Virtual: mem_funcs = DN_Str8Lit("Virtual"); break; } - DN_Str8x32 main_commit = DN_ByteCountStr8x32(dn->main_tc.main_arena->curr->commit); - DN_Str8x32 main_reserve = DN_ByteCountStr8x32(dn->main_tc.main_arena->curr->reserve); - DN_Str8x32 temp_commit = DN_ByteCountStr8x32(dn->main_tc.temp_a_arena->curr->commit); - DN_Str8x32 temp_reserve = DN_ByteCountStr8x32(dn->main_tc.temp_a_arena->curr->reserve); - DN_Str8x32 err_commit = DN_ByteCountStr8x32(dn->main_tc.err_sink.arena->curr->commit); - DN_Str8x32 err_reserve = DN_ByteCountStr8x32(dn->main_tc.err_sink.arena->curr->reserve); + DN_Str8x32 main_commit = DN_ByteCountStr8x32(dn->main_tc.main_arena->mem->curr->commit); + DN_Str8x32 main_reserve = DN_ByteCountStr8x32(dn->main_tc.main_arena->mem->curr->reserve); + DN_Str8x32 temp_commit = DN_ByteCountStr8x32(dn->main_tc.temp_a_arena->mem->curr->commit); + DN_Str8x32 temp_reserve = DN_ByteCountStr8x32(dn->main_tc.temp_a_arena->mem->curr->reserve); + DN_Str8x32 err_commit = DN_ByteCountStr8x32(dn->main_tc.err_sink.arena->mem->curr->commit); + DN_Str8x32 err_reserve = DN_ByteCountStr8x32(dn->main_tc.err_sink.arena->mem->curr->reserve); DN_FmtAppendTruncate(buf, &buf_size, sizeof(buf), diff --git a/Source/dn.h b/Source/dn.h index b63986e..3bee6cc 100644 --- a/Source/dn.h +++ b/Source/dn.h @@ -82,6 +82,65 @@ // // 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 +// +// #define DN_ASAN_POISON 1 +// +// Since arenas manage their own block of memory it does not automatically benefit from ASAN's +// memory markup that ASAN does and so it is implemented manually by using the ASAN user-level +// poisoning APIs. Similarly, since the arena recycles its own memory rather than release back +// to the OS, poisoning is not as effective for arenas but every little bit helps. +// +// Scrub Uninitialised Memory +// If this macro is defined, temp memory that is returned to an arena, or allocations freed by +// a pool are scrubbed to this specified byte, in absence of this bytes returned to the +// allocators are left as-is or memset to 0. For example to scrub bytes to 0xCD (MSVC's +// pattern) define as follows: +// +// #define DN_SCRUB_UNINIT_MEM_BYTE 0xCD +// +// Due to the recycling of memory in arenas and pool, similarly to ASAN poisoning this reduces +// the window in which a use-after-free can be detected using this guard, however every little +// bit helps. +// +// Arena temp memory use-after-free (UAF) tooling +// UAF Guard +// Set the following preprocessor value to 1 to enable UAF protection when using +// scratch/temporary memory functionality. Defaults to off, or 0 if not specified +// +// #define DN_ARENA_TEMP_MEM_UAF_GUARD 1 +// +// This enables arenas to markup itself with the active memory region and subsequent +// allocations check if the allocation belongs to the same or different region. Different +// regions cause a UAF violation. +// +// More detailed diagnostics can be enabled by setting the flag DN_ArenaFlags_TempMemUAFGuard +// on the affected arenas. Note that this incurs a performance penalty as each memory region +// will store a stacktrace of its creation. It's recommended in development builds to always +// run with temp-memory guarding, if a violation occurs, then enable tracing on the arena to +// pinpoint the issue. +// +// Enabling memory guard incurs additional memory requirements from the arena's backing +// memory block and additional book-keeping fields on each arena and their temp memory +// instances. +// +// UAF Tracing +// Set the following preprocessor value to 1 to enable tracing when the UAF guard triggers. +// Defaults to off, or 0 if not specified. +// +// #define DN_ARENA_TEMP_MEM_UAF_TRACE_ON_BY_DEFAULT 1 +// +// This opts in all arenas to tracing functionality by default globally. Arenas can opt out +// by setting the flag DN_ArenaFlags_TempMemUAFTraceDisable on the arena. The disable flag +// takes precedence over all other settings including the global preprocessor macro and the +// enablement flag (DN_ArenaFlags_TempMemUAFTrace). +// +// Tracing incurs an additional much heavier performance penalty than the UAF guard due to +// the stacktrace that is stored per region to report to the user when a UAF guard violation +// occurs. #include "Base/dn_base.h" #include "Base/dn_base_assert.h" @@ -110,10 +169,10 @@ enum DN_InitFlags_ { DN_InitFlags_Nil = 0, DN_InitFlags_OS = (1 << 0), - DN_InitFlags_LeakTracker = (1 << 1) | DN_InitFlags_OS, - DN_InitFlags_LogLibFeatures = (1 << 2), - DN_InitFlags_LogCPUFeatures = (1 << 3) | DN_InitFlags_OS, - DN_InitFlags_ThreadContext = (1 << 4) | DN_InitFlags_OS, + DN_InitFlags_ThreadContext = (1 << 1) | DN_InitFlags_OS, + DN_InitFlags_LeakTracker = (1 << 2) | DN_InitFlags_OS, + DN_InitFlags_LogLibFeatures = (1 << 3), + DN_InitFlags_LogCPUFeatures = (1 << 4) | DN_InitFlags_OS, DN_InitFlags_LogAllFeatures = DN_InitFlags_LogLibFeatures | DN_InitFlags_LogCPUFeatures, }; @@ -124,6 +183,7 @@ struct DN_Core DN_USize mem_allocs_frame; DN_LeakTracker leak; + DN_U32 log_level_to_show_from; DN_LogPrintFunc* print_func; void* print_func_context; diff --git a/build.bat b/build.bat index e7704b4..4319768 100644 --- a/build.bat +++ b/build.bat @@ -39,7 +39,7 @@ pushd %build_dir% where /q emcc && ( echo [BUILD] Emscripten emcc detected, compiling ... - call emcc -g -msimd128 -msse2 %flags% -o %build_dir%\dn_unit_tests_emcc.js -s FETCH=1 -pthread -s ASYNCIFY=1 -lwebsocket -Wall + call emcc -g -msimd128 -msse2 %flags% -o %build_dir%\dn_unit_tests_emcc.js -s FETCH=1 -pthread -s ASYNCIFY=1 -lwebsocket -Wall || echo Failed&& exit /b 1 ) where /q cl && ( @@ -50,15 +50,16 @@ pushd %build_dir% ) set msvc_cmd=!msvc_cmd! -link - powershell -Command "$time = Measure-Command { !msvc_cmd! | Out-Default }; Write-Host '[BUILD] msvc:'$time.TotalSeconds's'; exit $LASTEXITCODE" || exit /b 1 - call cl %script_dir%\single_header_generator.cpp -Z7 -nologo -link - call %build_dir%\single_header_generator.exe %script_dir%\Source %script_dir%\Single-Header + powershell -Command "$time = Measure-Command { !msvc_cmd! | Out-Default }; Write-Host '[BUILD] msvc:'$time.TotalSeconds's'; exit $LASTEXITCODE" || echo MSVC build failed&& exit /b 1 + echo [BUILD] Single header generator ... + call cl %script_dir%\single_header_generator.cpp -Z7 -nologo -link || echo Single header generator build failed&& exit /b 1 + call %build_dir%\single_header_generator.exe %script_dir%\Source %script_dir%\Single-Header || echo Single header generation failed&& exit /b 1 ) where /q clang-cl && ( echo [BUILD] LLVM clang-cl detected, compiling ... set clang_cmd=clang-cl -MT %msvc_driver_flags% -fsanitize=undefined -Fe:dn_unit_tests_clang -link - powershell -Command "$time = Measure-Command { !clang_cmd! | Out-Default }; Write-Host '[BUILD] clang-cl:'$time.TotalSeconds's'; exit $LASTEXITCODE" || exit /b 1 + powershell -Command "$time = Measure-Command { !clang_cmd! | Out-Default }; Write-Host '[BUILD] clang-cl:'$time.TotalSeconds's'; exit $LASTEXITCODE" || echo CLANG build failed&& exit /b 1 ) exit /b 1 diff --git a/single_header_generator.cpp b/single_header_generator.cpp index 3f1dde5..7a441d6 100644 --- a/single_header_generator.cpp +++ b/single_header_generator.cpp @@ -29,10 +29,12 @@ struct File static void AppendCppFileLineByLine(DN_Str8Builder *dest, DN_Str8 cpp_path) { - DN_OSErrSink *err = DN_OS_ErrSinkBeginDefault(); - DN_Str8 buffer = DN_OS_FileReadAllTLS(cpp_path, err); - DN_OS_ErrSinkEndAndExitIfErrorF(err, -1, "Failed to load file from '%S' for appending", cpp_path); + DN_TCScratch scratch = DN_TCScratchBegin(&dest->arena, 1); + DN_ErrSink *err = DN_TCErrSinkBeginDefault(); + DN_Str8 buffer = DN_OS_FileReadAllArena(&scratch.arena, cpp_path, err); + DN_ErrSinkEndExitIfErrorF(err, -1, "Failed to load file from '%S' for appending", cpp_path); + bool inside_clangd_preprocessor_block = false; for (DN_Str8 inc_walker = buffer;;) { DN_Str8BSplitResult split = DN_Str8BSplit(inc_walker, DN_Str8Lit("\n")); if (split.lhs.size == 0) @@ -42,42 +44,59 @@ static void AppendCppFileLineByLine(DN_Str8Builder *dest, DN_Str8 cpp_path) // NOTE: Trim the whitespace, mainly for windows, the file we read will have \r\n whereas we just want to emit \n DN_Str8 line = DN_Str8TrimTailWhitespace(split.lhs); - // NOTE: Comment out any #include "../dn_.*" matches if we encounter one - DN_Str8FindResult find = DN_Str8FindStr8(line, DN_Str8Lit("#include \"../dn_"), DN_Str8EqCase_Sensitive); - { + // NOTE: Detect if we're inside a clangd preprocessor block + // TODO: This breaks if there's any nested #if's in the block (we naiively match on #endif) + bool commented_out = false; + if (!inside_clangd_preprocessor_block) { + DN_Str8FindResult find = DN_Str8FindStr8(line, DN_Str8Lit("#if defined(_CLANGD)"), DN_Str8EqCase_Sensitive); if (find.found) { - line = DN_Str8FromTLSF("%S// DN: Single header generator commented out this header => %S", find.start_to_before_match, DN_Str8TrimWhitespaceAround(find.match_to_end_of_buffer)); - - // The only time we use '../dn_.*' is for LSP purposes, so we - // don't care about inlining it, hence we don't set 'include_file' + line = DN_Str8FromFmtArena(&scratch.arena, "%S// DN: Single header generator commented out => %S", find.start_to_before_match, DN_Str8TrimWhitespaceAround(find.match_to_end_of_buffer)); + commented_out = true; + inside_clangd_preprocessor_block = true; } } - // NOTE: Inline any other relative includes if we encounter one - // (Right now DN only includes stb_sprintf with a relative path) + // NOTE: Inline relative includes as long as we're not inside a CLANDG block DN_Str8 extra_include_path = {}; - if (!find.found) { - find = DN_Str8FindStr8(line, DN_Str8Lit("#include \""), DN_Str8EqCase_Sensitive); - if (find.found) { - line = DN_Str8FromTLSF("%S// DN: Single header generator commented out this header => %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_OS_PathFFromTLS("%S/%S", root_dir, DN_Str8TrimSuffix(rel_include_path, DN_Str8Lit("\""))); + if (!inside_clangd_preprocessor_block) { + DN_Str8 ignore_patterns[] = { + DN_Str8Lit("#include \"dn.h\""), + DN_Str8Lit("#include \"dn.cpp\""), + }; + + DN_Str8FindResult ignore = DN_Str8FindStr8Array(line, ignore_patterns, DN_ArrayCountU(ignore_patterns), DN_Str8EqCase_Sensitive); + if (!ignore.found) { + DN_Str8FindResult find = DN_Str8FindStr8(line, DN_Str8Lit("#include \""), DN_Str8EqCase_Sensitive); + if (find.found) { + line = DN_Str8FromFmtArena(&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_OS_PathF(&scratch.arena, "%S/%S", root_dir, DN_Str8TrimSuffix(rel_include_path, DN_Str8Lit("\""))); + } } } - DN_Str8BuilderAppendRef(dest, line); + // NOTE: Detect if we're at the end of the CLAND block + if (inside_clangd_preprocessor_block) { + if (!commented_out) + line = DN_Str8FromFmtArena(&scratch.arena, "// %S", line); + if (DN_Str8FindStr8(line, DN_Str8Lit("#endif"), DN_Str8EqCase_Sensitive).found) + inside_clangd_preprocessor_block = false; + } + + DN_Str8BuilderAppendCopy(dest, line); DN_Str8BuilderAppendRef(dest, DN_Str8Lit("\n")); if (extra_include_path.size) AppendCppFileLineByLine(dest, extra_include_path); } + DN_TCScratchEnd(&scratch); } int main(int argc, char **argv) { DN_Core dn = {}; - DN_Init(&dn, DN_InitFlags_OS, nullptr); + DN_Init(&dn, DN_InitFlags_OS | DN_InitFlags_ThreadContext, nullptr); if (argc != 3) { DN_OS_PrintErrF("USAGE: %s ", argv[0]); @@ -91,81 +110,30 @@ int main(int argc, char **argv) return -1; } - File const FILES[] = { - {FileType_Header, DN_Str8Lit("dn.h")}, - {FileType_Impl, DN_Str8Lit("dn.cpp")}, + DN_Str8 const REL_FILE_PATHS[] = { + DN_Str8Lit("dn"), + DN_Str8Lit("Extra/dn_async"), + DN_Str8Lit("Extra/dn_bin_pack"), + DN_Str8Lit("Extra/dn_csv"), + DN_Str8Lit("Extra/dn_helpers"), }; for (DN_ForIndexU(type, FileType_Count)) { - DN_OSTLSTMem tmem = DN_OS_TLSPushTMem(nullptr); - DN_Str8Builder builder = DN_Str8BuilderFromTLS(); - for (DN_ForItCArray(it, File const, FILES)) { - if (it.data->type != type) - continue; - - // NOTE: Parse the include files in the *_inc.[h|cpp] files - DN_Str8 path = DN_OS_PathFFromTLS("%S/%S", dn_root_dir, it.data->file_name); - { - DN_OSErrSink *err = DN_OS_ErrSinkBeginDefault(); - DN_Str8 file_buffer = DN_OS_FileReadAllTLS(path, err); - DN_OS_ErrSinkEndAndExitIfErrorF(err, -1, "Failed to load file"); - - // NOTE: Walk the top-level dn_*_inc.[h|cpp] files - for (DN_Str8 walker = file_buffer;;) { - DN_Str8BSplitResult split = DN_Str8BSplit(walker, DN_Str8Lit("\n")); - if (split.lhs.size == 0) - break; - - // NOTE: Parse the line, if it was a #include, extract it into this string - DN_Str8 include_file = {}; - { - walker = split.rhs; - DN_Str8 line = DN_Str8TrimTailWhitespace(split.lhs); - - // NOTE: Comment out any #include "dn_.*" matches if we encounter one - DN_Str8FindResult find = DN_Str8FindStr8(line, DN_Str8Lit("#include \""), DN_Str8EqCase_Sensitive); - { - if (find.found && DN_Str8FindStr8(line, DN_Str8Lit("dn_"), DN_Str8EqCase_Sensitive).found) { - line = DN_Str8FromTLSF("%S// DN: Single header generator inlined this file => %S", find.start_to_before_match, DN_Str8TrimWhitespaceAround(find.match_to_end_of_buffer)); - include_file = DN_Str8BSplit(find.after_match_to_end_of_buffer, DN_Str8Lit("\"")).lhs; - DN_Assert(include_file.size); - } - } - - // NOTE: Record the line - DN_Str8BuilderAppendRef(&builder, line); - DN_Str8BuilderAppendRef(&builder, DN_Str8Lit("\n")); - } - - if (include_file.size) { // NOTE: If the line was a include file, we will inline the included file - DN_Str8 include_path = DN_OS_PathFFromTLS("%S/%S", dn_root_dir, include_file); - AppendCppFileLineByLine(&builder, include_path); - } - } - } - } - - DN_Str8 extra_files[] = { - DN_Str8Lit("Extra/dn_math"), - DN_Str8Lit("Extra/dn_async"), - DN_Str8Lit("Extra/dn_bin_pack"), - DN_Str8Lit("Extra/dn_csv"), - DN_Str8Lit("Extra/dn_hash"), - DN_Str8Lit("Extra/dn_helpers"), - }; - DN_Str8 suffix = type == FileType_Header ? DN_Str8Lit("h") : DN_Str8Lit("cpp"); - for (DN_ForItCArray(extra_it, DN_Str8, extra_files)) { - DN_Str8 extra_path = DN_OS_PathFFromTLS("%S/%S.%S", dn_root_dir, *extra_it.data, suffix); + DN_TCScratch scratch = DN_TCScratchBegin(nullptr, 0); + DN_Str8Builder builder = DN_Str8BuilderFromArena(&scratch.arena); + DN_Str8 suffix = type == FileType_Header ? DN_Str8Lit("h") : DN_Str8Lit("cpp"); + for (DN_ForItCArray(extra_it, DN_Str8 const, REL_FILE_PATHS)) { + DN_Str8 extra_path = DN_OS_PathF(&scratch.arena, "%S/%S.%S", dn_root_dir, *extra_it.data, suffix); AppendCppFileLineByLine(&builder, extra_path); } DN_Date date = DN_OS_DateLocalTimeNow(); 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_Str8BuilderBuildFromTLS(&builder)); - DN_Str8 single_header_path = DN_OS_PathFFromTLS("%S/dn_single_header.%S", output_dir, suffix); - DN_OSErrSink *err = DN_OS_ErrSinkBeginDefault(); + DN_Str8 buffer = DN_Str8TrimWhitespaceAround(DN_Str8BuilderBuild(&builder, &scratch.arena)); + DN_Str8 single_header_path = DN_OS_PathF(&scratch.arena, "%S/dn_single_header.%S", output_dir, suffix); + DN_ErrSink *err = DN_TCErrSinkBeginDefault(); DN_OS_FileWriteAllSafe(single_header_path, buffer, err); - DN_OS_ErrSinkEndAndExitIfErrorF(err, -1, "Failed to write Single header file '%S'", single_header_path); + DN_ErrSinkEndExitIfErrorF(err, -1, "Failed to write Single header file '%S'", single_header_path); } }