// Generated by the DN single header generator 2025-06-26 22:13:42 #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. // DN: Single header generator inlined this file => #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 inlined this file => #include "Base/dn_base.h" #if !defined(DN_BASE_H) #define DN_BASE_H // 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++ #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++ #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++ #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_SecondsToMs(val) ((val) * 1000) #define DN_MinutesToSec(val) ((val) * 60ULL) #define DN_HoursToSec(val) (DN_MinutesToSec(val) * 60ULL) #define DN_DaysToSec(val) (DN_HoursToSec(val) * 24ULL) #define DN_WeeksToSec(val) (DN_DaysToSec(val) * 7ULL) #define DN_YearsToSec(val) (DN_WeeksToSec(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: 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: 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 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_ZeroMem { DN_ZeroMem_No, // Memory can be handed out without zero-ing it out DN_ZeroMem_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 char const *begin() const { return data; } char const *end() const { return data + size; } char *begin() { return data; } char *end() { return data + 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 #if defined(__cplusplus) wchar_t const *begin() const { return data; } // Const begin iterator for range-for loops wchar_t const *end() const { return data + size; } // Const end iterator for range-for loops wchar_t *begin() { return data; } // Begin iterator for range-for loops wchar_t *end() { return data + size; } // End iterator for range-for loops #endif }; 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; } }; // NOTE: DN_CallSite /////////////////////////////////////////////////////////////////////////////// struct DN_CallSite { DN_Str8 file; DN_Str8 function; DN_U32 line; }; #define DN_CALL_SITE \ DN_CallSite \ { \ DN_STR8(__FILE__), DN_STR8(__func__), __LINE__ \ } // NOTE: Intrinsics //////////////////////////////////////////////////////////////////////////////// // NOTE: DN_Atomic_Add/Exchange return the previous value store in the target #if defined(DN_COMPILER_MSVC) || defined(DN_COMPILER_CLANG_CL) #include #define DN_Atomic_CompareExchange64(dest, desired_val, prev_val) _InterlockedCompareExchange64((__int64 volatile *)dest, desired_val, prev_val) #define DN_Atomic_CompareExchange32(dest, desired_val, prev_val) _InterlockedCompareExchange((long volatile *)dest, desired_val, prev_val) #define DN_Atomic_LoadU64(target) *(target) #define DN_Atomic_LoadU32(target) *(target) #define DN_Atomic_AddU32(target, value) _InterlockedExchangeAdd((long volatile *)target, value) #define DN_Atomic_AddU64(target, value) _InterlockedExchangeAdd64((__int64 volatile *)target, value) #define DN_Atomic_SubU32(target, value) DN_Atomic_AddU32(DN_CAST(long volatile *) target, (long)-value) #define DN_Atomic_SubU64(target, value) DN_Atomic_AddU64(target, (DN_U64) - value) #define DN_CountLeadingZerosU64(value) __lzcnt64(value) #define DN_CPU_TSC() __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) #include #else #include #endif #define DN_Atomic_LoadU64(target) __atomic_load_n(x, __ATOMIC_SEQ_CST) #define DN_Atomic_LoadU32(target) __atomic_load_n(x, __ATOMIC_SEQ_CST) #define DN_Atomic_AddU32(target, value) __atomic_fetch_add(target, value, __ATOMIC_ACQ_REL) #define DN_Atomic_AddU64(target, value) __atomic_fetch_add(target, value, __ATOMIC_ACQ_REL) #define DN_Atomic_SubU32(target, value) __atomic_fetch_sub(target, value, __ATOMIC_ACQ_REL) #define DN_Atomic_SubU64(target, value) __atomic_fetch_sub(target, value, __ATOMIC_ACQ_REL) #define DN_CountLeadingZerosU64(value) __builtin_clzll(value) #if defined(DN_COMPILER_GCC) #define DN_CPU_TSC() __rdtsc() #else #define DN_CPU_TSC() __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(DN_PLATFORM_ARM64) 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]; }; extern DN_CPUFeatureDecl g_dn_cpu_feature_decl[DN_CPUFeature_Count]; #endif // DN_PLATFORM_ARM64 // NOTE: DN_TicketMutex //////////////////////////////////////////////////////////////////////////// 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 }; // NOTE: Intrinsics //////////////////////////////////////////////////////////////////////////////// DN_FORCE_INLINE DN_U64 DN_Atomic_SetValue64 (DN_U64 volatile *target, DN_U64 value); DN_FORCE_INLINE DN_U32 DN_Atomic_SetValue32 (DN_U32 volatile *target, DN_U32 value); #if !defined (DN_PLATFORM_ARM64) DN_API DN_CPUIDResult DN_CPU_ID (DN_CPUIDArgs args); DN_API DN_USize DN_CPU_HasFeatureArray (DN_CPUReport const *report, DN_CPUFeatureQuery *features, DN_USize features_size); DN_API bool DN_CPU_HasFeature (DN_CPUReport const *report, DN_CPUFeature feature); DN_API bool DN_CPU_HasAllFeatures (DN_CPUReport const *report, DN_CPUFeature const *features, DN_USize features_size); template bool DN_CPU_HasAllFeaturesCArray(DN_CPUReport const *report, DN_CPUFeature const (&features)[N]); DN_API void DN_CPU_SetFeature (DN_CPUReport *report, DN_CPUFeature feature); DN_API DN_CPUReport DN_CPU_Report (); #endif // NOTE: DN_TicketMutex //////////////////////////////////////////////////////////////////////////// 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); // NOTE: DN_DLList ///////////////////////////////////////////////////////////////////////////////// #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_Arena_New(arena, T, DN_ZeroMem_Yes); \ DN_DLList_Init(list); \ } while (0) #define DN_DLList_InitPool(list, T, pool) \ do { \ (list) = DN_Pool_New(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 // NOTE: Intrinsics //////////////////////////////////////////////////////////////////////////////// DN_FORCE_INLINE DN_U64 DN_Atomic_SetValue64(DN_U64 volatile *target, DN_U64 value) { #if defined(DN_COMPILER_MSVC) || defined(DN_COMPILER_CLANG_CL) __int64 result; do { result = *target; } while (DN_Atomic_CompareExchange64(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_FORCE_INLINE DN_U32 DN_Atomic_SetValue32(DN_U32 volatile *target, DN_U32 value) { #if defined(DN_COMPILER_MSVC) || defined(DN_COMPILER_CLANG_CL) long result; do { result = *target; } while (DN_Atomic_CompareExchange32(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 } template bool DN_CPU_HasAllFeaturesCArray(DN_CPUReport const *report, DN_CPUFeature const (&features)[N]) { bool result = DN_CPU_HasAllFeatures(report, features, N); return result; } // NOTE: DN_Bit //////////////////////////////////////////////////////////////////////////////////// DN_API void DN_Bit_UnsetInplace (DN_USize *flags, DN_USize bitfield); DN_API void DN_Bit_SetInplace (DN_USize *flags, DN_USize bitfield); DN_API bool DN_Bit_IsSet (DN_USize bits, DN_USize bits_to_set); DN_API bool DN_Bit_IsNotSet (DN_USize bits, DN_USize bits_to_check); #define DN_Bit_ClearNextLSB(value) (value) & ((value) - 1) // NOTE: DN_Safe /////////////////////////////////////////////////////////////////////////////////// DN_API DN_I64 DN_Safe_AddI64 (DN_I64 a, DN_I64 b); DN_API DN_I64 DN_Safe_MulI64 (DN_I64 a, DN_I64 b); DN_API DN_U64 DN_Safe_AddU64 (DN_U64 a, DN_U64 b); DN_API DN_U64 DN_Safe_MulU64 (DN_U64 a, DN_U64 b); DN_API DN_U64 DN_Safe_SubU64 (DN_U64 a, DN_U64 b); DN_API DN_U32 DN_Safe_SubU32 (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); // NOTE: DN_Asan /////////////////////////////////////////////////////////////////////////////////// DN_API void DN_ASAN_PoisonMemoryRegion (void const volatile *ptr, DN_USize size); DN_API void DN_ASAN_UnpoisonMemoryRegion (void const volatile *ptr, DN_USize size); #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 // 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; }; DN_API DN_Str8 DN_StackTrace_WalkStr8FromHeap (DN_U16 limit, DN_U16 skip); DN_API DN_StackTraceWalkResult DN_StackTrace_Walk (struct DN_Arena *arena, DN_U16 limit); DN_API bool DN_StackTrace_WalkResultIterate(DN_StackTraceWalkResultIterator *it, DN_StackTraceWalkResult const *walk); DN_API DN_Str8 DN_StackTrace_WalkResultToStr8 (struct DN_Arena *arena, DN_StackTraceWalkResult const *walk, DN_U16 skip); DN_API DN_Str8 DN_StackTrace_WalkStr8 (struct DN_Arena *arena, DN_U16 limit, DN_U16 skip); DN_API DN_Str8 DN_StackTrace_WalkStr8FromHeap (DN_U16 limit, DN_U16 skip); DN_API DN_Slice DN_StackTrace_GetFrames (struct DN_Arena *arena, DN_U16 limit); DN_API DN_StackTraceFrame DN_StackTrace_RawFrameToFrame (struct DN_Arena *arena, DN_StackTraceRawFrame raw_frame); DN_API void DN_StackTrace_Print (DN_U16 limit); DN_API void DN_StackTrace_ReloadSymbols (); #endif // 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_HardAssert(expr) DN_HardAssertF(expr, "") #if defined(DN_FREESTANDING) #define DN_HardAssertF(expr, fmt, ...) \ do { \ if (!(expr)) { \ DN_DebugBreak; \ (*(int *)0) = 0; \ } \ } while (0) #else #define DN_HardAssertF(expr, fmt, ...) \ do { \ if (!(expr)) { \ DN_Str8 stack_trace_ = DN_StackTrace_WalkStr8FromHeap(128 /*limit*/, 2 /*skip*/); \ DN_LOG_ErrorF("Hard assertion [" #expr "], stack trace was:\n\n%.*s\n\n" fmt, \ DN_STR_FMT(stack_trace_), \ ##__VA_ARGS__); \ DN_DebugBreak; \ } \ } while (0) #endif #if defined(DN_NO_ASSERT) #define DN_Assert(...) #define DN_AssertOnce(...) #define DN_AssertF(...) #define DN_AssertFOnce(...) #else #if defined(DN_FREESTANDING) #define DN_AssertF(expr, fmt, ...) \ do { \ if (!(expr)) { \ DN_DebugBreak; \ (*(int *)0) = 0; \ } \ } while (0) #else #define DN_AssertF(expr, fmt, ...) \ do { \ if (!(expr)) { \ DN_Str8 stack_trace_ = DN_StackTrace_WalkStr8FromHeap(128 /*limit*/, 2 /*skip*/); \ DN_LOG_ErrorF("Assertion [" #expr "], stack trace was:\n\n%.*s\n\n" fmt, \ DN_STR_FMT(stack_trace_), \ ##__VA_ARGS__); \ DN_DebugBreak; \ } \ } while (0) #endif #define DN_AssertFOnce(expr, fmt, ...) \ do { \ static bool once = true; \ if (!(expr) && once) { \ once = false; \ DN_Str8 stack_trace_ = DN_StackTrace_WalkStr8FromHeap(128 /*limit*/, 2 /*skip*/); \ DN_LOG_ErrorF("Assertion [" #expr "], stack trace was:\n\n%.*s\n\n" fmt, \ DN_STR_FMT(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") // NOTE: Check macro /////////////////////////////////////////////////////////////////////////////// #define DN_Check(expr) DN_CheckF(expr, "") #if defined(DN_FREESTANDING) #define DN_CheckF(expr, fmt, ...) (expr) #else #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_StackTrace_Print(128 /*limit*/), DN_DebugBreak, false)) #endif #endif #endif // DN: Single header generator inlined this file => #include "Base/dn_base_mem.h" #if !defined(DN_BASE_MEM_H) #define DN_BASE_MEM_H // DN: Single header generator commented out this header => #include "../dn_clangd.h" 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 struct DN_ArenaBlock { DN_ArenaBlock *prev; DN_U64 used; DN_U64 commit; DN_U64 reserve; DN_U64 reserve_sum; }; typedef uint32_t 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; }; 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); // NOTE: DN_Arena ////////////////////////////////////////////////////////////////////////////////// DN_API DN_Arena DN_Arena_InitFromBuffer (void *buffer, DN_USize size, DN_ArenaFlags flags); DN_API DN_Arena DN_Arena_InitFromMemFuncs (DN_U64 reserve, DN_U64 commit, DN_ArenaFlags flags, DN_ArenaMemFuncs mem_funcs); DN_API void DN_Arena_Deinit (DN_Arena *arena); DN_API bool DN_Arena_Commit (DN_Arena *arena, DN_U64 size); DN_API bool DN_Arena_CommitTo (DN_Arena *arena, DN_U64 pos); DN_API bool DN_Arena_Grow (DN_Arena *arena, DN_U64 reserve, DN_U64 commit); DN_API void * DN_Arena_Alloc (DN_Arena *arena, DN_U64 size, uint8_t align, DN_ZeroMem zero_mem); DN_API void * DN_Arena_AllocContiguous (DN_Arena *arena, DN_U64 size, uint8_t align, DN_ZeroMem zero_mem); DN_API void * DN_Arena_Copy (DN_Arena *arena, void const *data, DN_U64 size, uint8_t align); DN_API void DN_Arena_PopTo (DN_Arena *arena, DN_U64 init_used); DN_API void DN_Arena_Pop (DN_Arena *arena, DN_U64 amount); DN_API DN_U64 DN_Arena_Pos (DN_Arena const *arena); DN_API void DN_Arena_Clear (DN_Arena *arena); DN_API bool DN_Arena_OwnsPtr (DN_Arena const *arena, void *ptr); DN_API DN_ArenaStats DN_Arena_SumStatsArray (DN_ArenaStats const *array, DN_USize size); DN_API DN_ArenaStats DN_Arena_SumStats (DN_ArenaStats lhs, DN_ArenaStats rhs); DN_API DN_ArenaStats DN_Arena_SumArenaArrayToStats (DN_Arena const *array, DN_USize size); DN_API DN_ArenaTempMem DN_Arena_TempMemBegin (DN_Arena *arena); DN_API void DN_Arena_TempMemEnd (DN_ArenaTempMem mem); #define DN_Arena_New_Frame(T, zero_mem) (T *)DN_Arena_Alloc(DN_OS_TLSGet()->frame_arena, sizeof(T), alignof(T), zero_mem) #define DN_Arena_New(arena, T, zero_mem) (T *)DN_Arena_Alloc(arena, sizeof(T), alignof(T), zero_mem) #define DN_Arena_NewArray(arena, T, count, zero_mem) (T *)DN_Arena_Alloc(arena, sizeof(T) * (count), alignof(T), zero_mem) #define DN_Arena_NewCopy(arena, T, src) (T *)DN_Arena_Copy (arena, (src), sizeof(T), alignof(T)) #define DN_Arena_NewArrayCopy(arena, T, src, count) (T *)DN_Arena_Copy (arena, (src), sizeof(T) * (count), alignof(T)) #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]; uint8_t align; }; // NOTE: DN_Pool /////////////////////////////////////////////////////////////////////////////////// DN_API DN_Pool DN_Pool_Init (DN_Arena *arena, uint8_t align); DN_API bool DN_Pool_IsValid (DN_Pool const *pool); DN_API void * DN_Pool_Alloc (DN_Pool *pool, DN_USize size); DN_API DN_Str8 DN_Pool_AllocStr8FV (DN_Pool *pool, DN_FMT_ATTRIB char const *fmt, va_list args); DN_API DN_Str8 DN_Pool_AllocStr8F (DN_Pool *pool, DN_FMT_ATTRIB char const *fmt, ...); DN_API DN_Str8 DN_Pool_AllocStr8Copy (DN_Pool *pool, DN_Str8 string); DN_API void DN_Pool_Dealloc (DN_Pool *pool, void *ptr); DN_API void * DN_Pool_Copy (DN_Pool *pool, void const *data, DN_U64 size, uint8_t align); #define DN_Pool_New(pool, T) (T *)DN_Pool_Alloc(pool, sizeof(T)) #define DN_Pool_NewArray(pool, T, count) (T *)DN_Pool_Alloc(pool, count * sizeof(T)) #define DN_Pool_NewCopy(arena, T, src) (T *)DN_Pool_Copy (arena, (src), sizeof(T), alignof(T)) #define DN_Pool_NewArrayCopy(arena, T, src, count) (T *)DN_Pool_Copy (arena, (src), sizeof(T) * (count), alignof(T)) // NOTE: DN_Debug ////////////////////////////////////////////////////////////////////////////////// #if defined(DN_LEAK_TRACKING) && !defined(DN_FREESTANDING) DN_API void DN_Debug_TrackAlloc (void *ptr, DN_USize size, bool alloc_can_leak); DN_API void DN_Debug_TrackDealloc(void *ptr); DN_API void DN_Debug_DumpLeaks (); #else #define DN_Debug_TrackAlloc(ptr, size, alloc_can_leak) do { (void)ptr; (void)size; (void)alloc_can_leak; } while (0) #define DN_Debug_TrackDealloc(ptr) do { (void)ptr; } while (0) #define DN_Debug_DumpLeaks() do { } while (0) #endif #endif // !defined(DN_BASE_MEM_H) // DN: Single header generator inlined this file => #include "Base/dn_base_log.h" #if !defined(DN_BASE_LOG_H) #define DN_BASE_LOG_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_string.h" #if !defined(DN_BASE_STRING_H) #define DN_BASE_STRING_H #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 // 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__) #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_base_string.h // //////////////////////////////////////////////////////////////////////////////////////////////////// */ // NOTE: DN_Str8 ////////////////////////////////////////////////////////////////////////////////// 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_Str8BinarySplitResult { 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_Str8IsAll { DN_Str8IsAll_Digits, DN_Str8IsAll_Hex, }; enum DN_Str8EqCase { DN_Str8EqCase_Sensitive, DN_Str8EqCase_Insensitive, }; 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_Str8ToU64Result { bool success; uint64_t value; }; struct DN_Str8ToI64Result { bool success; int64_t value; }; struct DN_Str8DotTruncateResult { bool truncated; DN_Str8 str8; }; // NOTE: DN_FStr8 ////////////////////////////////////////////////////////////////////////////////// #if !defined(DN_NO_FSTR8) template struct DN_FStr8 { char data[N + 1]; DN_USize size; char *begin() { return data; } char *end() { return data + size; } char const *begin() const { return data; } char const *end() const { return data + size; } }; #endif // !defined(DN_NO_FSTR8) 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, }; // NOTE: DN_CStr8 ////////////////////////////////////////////////////////////////////////////////// template constexpr DN_USize DN_CStr8_ArrayUCount (char const (&literal)[N]) { (void)literal; return N - 1; } template constexpr DN_USize DN_CStr8_ArrayICount (char const (&literal)[N]) { (void)literal; return N - 1; } DN_API DN_USize DN_CStr8_FSize (DN_FMT_ATTRIB char const *fmt, ...); DN_API DN_USize DN_CStr8_FVSize (DN_FMT_ATTRIB char const *fmt, va_list args); DN_API DN_USize DN_CStr8_Size (char const *a); DN_API DN_USize DN_CStr16_Size (wchar_t const *a); // NOTE: DN_Str16 ////////////////////////////////////////////////////////////////////////////////// #define DN_STR16(string) DN_Str16{(wchar_t *)(string), sizeof(string)/sizeof(string[0]) - 1} #define DN_Str16_HasData(string) ((string).data && (string).size) #if defined(__cplusplus) DN_API bool operator== (DN_Str16 const &lhs, DN_Str16 const &rhs); DN_API bool operator!= (DN_Str16 const &lhs, DN_Str16 const &rhs); #endif // NOTE: DN_Str8 /////////////////////////////////////////////////////////////////////////////////// #define DN_STR8(string) DN_Str8{(char *)(string), (sizeof(string) - 1)} #define DN_STR_FMT(string) (int)((string).size), (string).data #define DN_Str8_Init(data, size) DN_Str8{(char *)(data), (size_t)(size)} DN_API DN_Str8 DN_Str8_InitCStr8 (char const *src); #define DN_Str8_HasData(string) ((string).data && (string).size) DN_API bool DN_Str8_IsAll (DN_Str8 string, DN_Str8IsAll is_all); DN_API DN_Str8 DN_Str8_InitF (DN_Arena *arena, DN_FMT_ATTRIB char const *fmt, ...); DN_API DN_Str8 DN_Str8_InitFV (DN_Arena *arena, DN_FMT_ATTRIB char const *fmt, va_list args); DN_API DN_Str8 DN_Str8_Alloc (DN_Arena *arena, DN_USize size, DN_ZeroMem zero_mem); DN_API DN_Str8 DN_Str8_Copy (DN_Arena *arena, DN_Str8 string); DN_API char * DN_Str8_End (DN_Str8 string); DN_API DN_Str8 DN_Str8_Slice (DN_Str8 string, DN_USize offset, DN_USize size); DN_API DN_Str8 DN_Str8_Advance (DN_Str8 string, DN_USize amount); DN_API DN_Str8 DN_Str8_NextLine (DN_Str8 string); DN_API DN_Str8BinarySplitResult DN_Str8_BinarySplitArray (DN_Str8 string, DN_Str8 const *find, DN_USize find_size); DN_API DN_Str8BinarySplitResult DN_Str8_BinarySplit (DN_Str8 string, DN_Str8 find); DN_API DN_Str8BinarySplitResult DN_Str8_BinarySplitLastArray (DN_Str8 string, DN_Str8 const *find, DN_USize find_size); DN_API DN_Str8BinarySplitResult DN_Str8_BinarySplitLast (DN_Str8 string, DN_Str8 find); DN_API DN_USize DN_Str8_Split (DN_Str8 string, DN_Str8 delimiter, DN_Str8 *splits, DN_USize splits_count, DN_Str8SplitIncludeEmptyStrings mode); DN_API DN_Slice DN_Str8_SplitAlloc (DN_Arena *arena, DN_Str8 string, DN_Str8 delimiter, DN_Str8SplitIncludeEmptyStrings mode); DN_API DN_Str8FindResult DN_Str8_FindStr8Array (DN_Str8 string, DN_Str8 const *find, DN_USize find_size, DN_Str8EqCase eq_case); DN_API DN_Str8FindResult DN_Str8_FindStr8 (DN_Str8 string, DN_Str8 find, DN_Str8EqCase eq_case); DN_API DN_Str8FindResult DN_Str8_Find (DN_Str8 string, uint32_t flags); DN_API DN_Str8 DN_Str8_Segment (DN_Arena *arena, DN_Str8 src, DN_USize segment_size, char segment_char); DN_API DN_Str8 DN_Str8_ReverseSegment (DN_Arena *arena, DN_Str8 src, DN_USize segment_size, char segment_char); DN_API bool DN_Str8_Eq (DN_Str8 lhs, DN_Str8 rhs, DN_Str8EqCase eq_case = DN_Str8EqCase_Sensitive); DN_API bool DN_Str8_EqInsensitive (DN_Str8 lhs, DN_Str8 rhs); DN_API bool DN_Str8_StartsWith (DN_Str8 string, DN_Str8 prefix, DN_Str8EqCase eq_case = DN_Str8EqCase_Sensitive); DN_API bool DN_Str8_StartsWithInsensitive (DN_Str8 string, DN_Str8 prefix); DN_API bool DN_Str8_EndsWith (DN_Str8 string, DN_Str8 prefix, DN_Str8EqCase eq_case = DN_Str8EqCase_Sensitive); DN_API bool DN_Str8_EndsWithInsensitive (DN_Str8 string, DN_Str8 prefix); DN_API bool DN_Str8_HasChar (DN_Str8 string, char ch); DN_API DN_Str8 DN_Str8_TrimPrefix (DN_Str8 string, DN_Str8 prefix, DN_Str8EqCase eq_case = DN_Str8EqCase_Sensitive); DN_API DN_Str8 DN_Str8_TrimHexPrefix (DN_Str8 string); DN_API DN_Str8 DN_Str8_TrimSuffix (DN_Str8 string, DN_Str8 suffix, DN_Str8EqCase eq_case = DN_Str8EqCase_Sensitive); DN_API DN_Str8 DN_Str8_TrimAround (DN_Str8 string, DN_Str8 trim_string); DN_API DN_Str8 DN_Str8_TrimHeadWhitespace (DN_Str8 string); DN_API DN_Str8 DN_Str8_TrimTailWhitespace (DN_Str8 string); DN_API DN_Str8 DN_Str8_TrimWhitespaceAround (DN_Str8 string); DN_API DN_Str8 DN_Str8_TrimByteOrderMark (DN_Str8 string); DN_API DN_Str8 DN_Str8_FileNameFromPath (DN_Str8 path); DN_API DN_Str8 DN_Str8_FileNameNoExtension (DN_Str8 path); DN_API DN_Str8 DN_Str8_FilePathNoExtension (DN_Str8 path); DN_API DN_Str8 DN_Str8_FileExtension (DN_Str8 path); DN_API DN_Str8 DN_Str8_FileDirectoryFromPath (DN_Str8 path); DN_API DN_Str8ToU64Result DN_Str8_ToU64 (DN_Str8 string, char separator); DN_API DN_Str8ToI64Result DN_Str8_ToI64 (DN_Str8 string, char separator); DN_API DN_Str8 DN_Str8_AppendF (DN_Arena *arena, DN_Str8 string, char const *fmt, ...); DN_API DN_Str8 DN_Str8_AppendFV (DN_Arena *arena, DN_Str8 string, char const *fmt, va_list args); DN_API DN_Str8 DN_Str8_FillF (DN_Arena *arena, DN_USize count, char const *fmt, ...); DN_API DN_Str8 DN_Str8_FillFV (DN_Arena *arena, DN_USize count, char const *fmt, va_list args); DN_API void DN_Str8_Remove (DN_Str8 *string, DN_USize offset, DN_USize size); DN_API DN_Str8DotTruncateResult DN_Str8_DotTruncateMiddle (DN_Arena *arena, DN_Str8 str8, uint32_t side_size, DN_Str8 truncator); DN_API DN_Str8 DN_Str8_Lower (DN_Arena *arena, DN_Str8 string); DN_API DN_Str8 DN_Str8_Upper (DN_Arena *arena, DN_Str8 string); #if defined(__cplusplus) DN_API bool operator== (DN_Str8 const &lhs, DN_Str8 const &rhs); DN_API bool operator!= (DN_Str8 const &lhs, DN_Str8 const &rhs); #endif // NOTE: DN_Str8Builder //////////////////////////////////////////////////////////////////////////// DN_API DN_Str8Builder DN_Str8Builder_Init (DN_Arena *arena); DN_API DN_Str8Builder DN_Str8Builder_InitArrayRef (DN_Arena *arena, DN_Str8 const *strings, DN_USize size); DN_API DN_Str8Builder DN_Str8Builder_InitArrayCopy (DN_Arena *arena, DN_Str8 const *strings, DN_USize size); template DN_Str8Builder DN_Str8Builder_InitCArrayRef (DN_Arena *arena, DN_Str8 const (&array)[N]); template DN_Str8Builder DN_Str8Builder_InitCArrayCopy (DN_Arena *arena, DN_Str8 const (&array)[N]); DN_API bool DN_Str8Builder_AddArrayRef (DN_Str8Builder *builder, DN_Str8 const *strings, DN_USize size, DN_Str8BuilderAdd add); DN_API bool DN_Str8Builder_AddArrayCopy (DN_Str8Builder *builder, DN_Str8 const *strings, DN_USize size, DN_Str8BuilderAdd add); DN_API bool DN_Str8Builder_AddFV (DN_Str8Builder *builder, DN_Str8BuilderAdd add, DN_FMT_ATTRIB char const *fmt, va_list args); #define DN_Str8Builder_AppendArrayRef(builder, strings, size) DN_Str8Builder_AddArrayRef(builder, strings, size, DN_Str8BuilderAdd_Append) #define DN_Str8Builder_AppendArrayCopy(builder, strings, size) DN_Str8Builder_AddArrayCopy(builder, strings, size, DN_Str8BuilderAdd_Append) #define DN_Str8Builder_AppendSliceRef(builder, slice) DN_Str8Builder_AddArrayRef(builder, slice.data, slice.size, DN_Str8BuilderAdd_Append) #define DN_Str8Builder_AppendSliceCopy(builder, slice) DN_Str8Builder_AddArrayCopy(builder, slice.data, slice.size, DN_Str8BuilderAdd_Append) DN_API bool DN_Str8Builder_AppendRef (DN_Str8Builder *builder, DN_Str8 string); DN_API bool DN_Str8Builder_AppendCopy (DN_Str8Builder *builder, DN_Str8 string); #define DN_Str8Builder_AppendFV(builder, fmt, args) DN_Str8Builder_AddFV(builder, DN_Str8BuilderAdd_Append, fmt, args) DN_API bool DN_Str8Builder_AppendF (DN_Str8Builder *builder, DN_FMT_ATTRIB char const *fmt, ...); DN_API bool DN_Str8Builder_AppendBytesRef (DN_Str8Builder *builder, void const *ptr, DN_USize size); DN_API bool DN_Str8Builder_AppendBytesCopy (DN_Str8Builder *builder, void const *ptr, DN_USize size); DN_API bool DN_Str8Builder_AppendBuilderRef (DN_Str8Builder *dest, DN_Str8Builder const *src); DN_API bool DN_Str8Builder_AppendBuilderCopy (DN_Str8Builder *dest, DN_Str8Builder const *src); #define DN_Str8Builder_PrependArrayRef(builder, strings, size) DN_Str8Builder_AddArrayRef(builder, strings, size, DN_Str8BuilderAdd_Prepend) #define DN_Str8Builder_PrependArrayCopy(builder, strings, size) DN_Str8Builder_AddArrayCopy(builder, strings, size, DN_Str8BuilderAdd_Prepend) #define DN_Str8Builder_PrependSliceRef(builder, slice) DN_Str8Builder_AddArrayRef(builder, slice.data, slice.size, DN_Str8BuilderAdd_Prepend) #define DN_Str8Builder_PrependSliceCopy(builder, slice) DN_Str8Builder_AddArrayCopy(builder, slice.data, slice.size, DN_Str8BuilderAdd_Prepend) DN_API bool DN_Str8Builder_PrependRef (DN_Str8Builder *builder, DN_Str8 string); DN_API bool DN_Str8Builder_PrependCopy (DN_Str8Builder *builder, DN_Str8 string); #define DN_Str8Builder_PrependFV(builder, fmt, args) DN_Str8Builder_AddFV(builder, DN_Str8BuilderAdd_Prepend, fmt, args) DN_API bool DN_Str8Builder_PrependF (DN_Str8Builder *builder, DN_FMT_ATTRIB char const *fmt, ...); DN_API bool DN_Str8Builder_Erase (DN_Str8Builder *builder, DN_Str8 string); DN_API DN_Str8Builder DN_Str8Builder_Copy (DN_Arena *arena, DN_Str8Builder const *builder); DN_API DN_Str8 DN_Str8Builder_Build (DN_Str8Builder const *builder, DN_Arena *arena); DN_API DN_Str8 DN_Str8Builder_BuildDelimited (DN_Str8Builder const *builder, DN_Str8 delimiter, DN_Arena *arena); DN_API DN_Slice DN_Str8Builder_BuildSlice (DN_Str8Builder const *builder, DN_Arena *arena); // NOTE: DN_FStr8 ////////////////////////////////////////////////////////////////////////////////// #if !defined(DN_NO_FSTR8) template DN_FStr8 DN_FStr8_InitF (DN_FMT_ATTRIB char const *fmt, ...); template DN_FStr8 DN_FStr8_InitFV (char const *fmt, va_list args); template DN_USize DN_FStr8_Max (DN_FStr8 const *string); template void DN_FStr8_Clear (DN_FStr8 *string); template bool DN_FStr8_AddFV (DN_FStr8 *string, DN_FMT_ATTRIB char const *fmt, va_list va); template bool DN_FStr8_AddF (DN_FStr8 *string, DN_FMT_ATTRIB char const *fmt, ...); template bool DN_FStr8_AddCStr8 (DN_FStr8 *string, char const *value, DN_USize size); template bool DN_FStr8_Add (DN_FStr8 *string, DN_Str8 value); template DN_Str8 DN_FStr8_ToStr8 (DN_FStr8 const *string); template bool DN_FStr8_Eq (DN_FStr8 const *lhs, DN_FStr8 const *rhs, DN_Str8EqCase eq_case); template bool DN_FStr8_EqStr8 (DN_FStr8 const *lhs, DN_Str8 rhs, DN_Str8EqCase eq_case); template bool DN_FStr8_EqInsensitive (DN_FStr8 const *lhs, DN_FStr8 const *rhs); template bool DN_FStr8_EqStr8Insensitive (DN_FStr8 const *lhs, DN_Str8 rhs); template bool DN_FStr8_EqFStr8 (DN_FStr8 const *lhs, DN_FStr8 const *rhs, DN_Str8EqCase eq_case); template bool DN_FStr8_EqFStr8Insensitive (DN_FStr8 const *lhs, DN_FStr8 const *rhs); template bool operator== (DN_FStr8 const &lhs, DN_FStr8 const &rhs); template bool operator!= (DN_FStr8 const &lhs, DN_FStr8 const &rhs); template bool operator== (DN_FStr8 const &lhs, DN_Str8 const &rhs); template bool operator!= (DN_FStr8 const &lhs, DN_Str8 const &rhs); #endif // !defined(DN_NO_FSTR8) // NOTE: DN_Char /////////////////////////////////////////////////////////////////////////////////// struct DN_CharHexToU8 { bool success; uint8_t value; }; DN_API bool DN_Char_IsAlphabet (char ch); DN_API bool DN_Char_IsDigit (char ch); DN_API bool DN_Char_IsAlphaNum (char ch); DN_API bool DN_Char_IsWhitespace (char ch); DN_API bool DN_Char_IsHex (char ch); DN_API DN_CharHexToU8 DN_Char_HexToU8 (char ch); DN_API char DN_Char_ToHex (char ch); DN_API char DN_Char_ToHexUnchecked (char ch); DN_API char DN_Char_ToLower (char ch); DN_API char DN_Char_ToUpper (char ch); // NOTE: DN_UTF //////////////////////////////////////////////////////////////////////////////////// DN_API int DN_UTF8_EncodeCodepoint (uint8_t utf8[4], uint32_t codepoint); DN_API int DN_UTF16_EncodeCodepoint (uint16_t utf16[2], uint32_t codepoint); // NOTE: DN_Str8Builder /////////////////////////////////////////////////////////////////////////// template DN_Str8Builder DN_Str8Builder_InitCArrayRef(DN_Arena *arena, DN_Str8 const (&array)[N]) { DN_Str8Builder result = DN_Str8Builder_InitArrayRef(arena, array, N); return result; } template DN_Str8Builder DN_Str8Builder_InitCArrayCopy(DN_Arena *arena, DN_Str8 const (&array)[N]) { DN_Str8Builder result = DN_Str8Builder_InitArrayCopy(arena, array, N); return result; } template bool DN_Str8Builder_AddCArrayRef(DN_Str8Builder *builder, DN_Str8 const (&array)[N], DN_Str8BuilderAdd add) { bool result = DN_Str8Builder_AddArrayRef(builder, array, N, add); return result; } template bool DN_Str8Builder_AddCArrayCopy(DN_Str8Builder *builder, DN_Str8 const (&array)[N], DN_Str8BuilderAdd add) { bool result = DN_Str8Builder_AddArrayCopy(builder, array, N, add); return result; } #if !defined(DN_NO_FSTR8) // NOTE: DN_FStr8 ////////////////////////////////////////////////////////////////////////////////// template DN_FStr8 DN_FStr8_InitF(DN_FMT_ATTRIB char const *fmt, ...) { DN_FStr8 result = {}; if (fmt) { va_list args; va_start(args, fmt); DN_FStr8_AddFV(&result, fmt, args); va_end(args); } return result; } template DN_FStr8 DN_FStr8_InitFV(char const *fmt, va_list args) { DN_FStr8 result = {}; DN_FStr8_AddFV(&result, fmt, args); return result; } template DN_USize DN_FStr8_Max(DN_FStr8 const *) { DN_USize result = N; return result; } template void DN_FStr8_Clear(DN_FStr8 *string) { *string = {}; } template bool DN_FStr8_AddFV(DN_FStr8 *string, DN_FMT_ATTRIB char const *fmt, va_list args) { bool result = false; if (!string || !fmt) return result; DN_USize require = DN_CStr8_FVSize(fmt, args) + 1 /*null_terminate*/; DN_USize space = (N + 1) - string->size; result = require <= space; string->size += DN_VSNPrintF(string->data + string->size, DN_CAST(int) space, fmt, args); // NOTE: snprintf returns the required size of the format string // irrespective of if there's space or not. string->size = DN_Min(string->size, N); return result; } template bool DN_FStr8_AddF(DN_FStr8 *string, DN_FMT_ATTRIB char const *fmt, ...) { bool result = false; if (!string || !fmt) return result; va_list args; va_start(args, fmt); result = DN_FStr8_AddFV(string, fmt, args); va_end(args); return result; } template bool DN_FStr8_AddCStr8(DN_FStr8 *string, char const *src, DN_USize size) { DN_Assert(string->size <= N); bool result = false; if (!string || !src || size == 0 || string->size >= N) return result; DN_USize space = N - string->size; result = size <= space; DN_Memcpy(string->data + string->size, src, DN_Min(space, size)); string->size = DN_Min(string->size + size, N); string->data[string->size] = 0; return result; } template bool DN_FStr8_Add(DN_FStr8 *string, DN_Str8 src) { bool result = DN_FStr8_AddCStr8(string, src.data, src.size); return result; } template DN_Str8 DN_FStr8_ToStr8(DN_FStr8 const *string) { DN_Str8 result = {}; if (!string || string->size <= 0) return result; result.data = DN_CAST(char *) string->data; result.size = string->size; return result; } template bool DN_FStr8_Eq(DN_FStr8 const *lhs, DN_FStr8 const *rhs, DN_Str8EqCase eq_case) { DN_Str8 lhs_s8 = DN_FStr8_ToStr8(lhs); DN_Str8 rhs_s8 = DN_FStr8_ToStr8(rhs); bool result = DN_Str8_Eq(lhs_s8, rhs_s8, eq_case); return result; } template bool DN_FStr8_EqStr8(DN_FStr8 const *lhs, DN_Str8 rhs, DN_Str8EqCase eq_case) { DN_Str8 lhs_s8 = DN_FStr8_ToStr8(lhs); bool result = DN_Str8_Eq(lhs_s8, rhs, eq_case); return result; } template bool DN_FStr8_EqInsensitive(DN_FStr8 const *lhs, DN_FStr8 const *rhs) { DN_Str8 lhs_s8 = DN_FStr8_ToStr8(lhs); DN_Str8 rhs_s8 = DN_FStr8_ToStr8(rhs); bool result = DN_Str8_Eq(lhs_s8, rhs_s8, DN_Str8EqCase_Insensitive); return result; } template bool DN_FStr8_EqStr8Insensitive(DN_FStr8 const *lhs, DN_Str8 rhs) { DN_Str8 lhs_s8 = DN_FStr8_ToStr8(lhs); bool result = DN_Str8_Eq(lhs_s8, rhs, DN_Str8EqCase_Insensitive); return result; } template bool DN_FStr8_EqFStr8(DN_FStr8 const *lhs, DN_FStr8 const *rhs, DN_Str8EqCase eq_case) { DN_Str8 lhs_s8 = DN_FStr8_ToStr8(lhs); DN_Str8 rhs_s8 = DN_FStr8_ToStr8(rhs); bool result = DN_Str8_Eq(lhs_s8, rhs_s8, eq_case); return result; } template bool DN_FStr8_EqFStr8Insensitive(DN_FStr8 const *lhs, DN_FStr8 const *rhs) { DN_Str8 lhs_s8 = DN_FStr8_ToStr8(lhs); DN_Str8 rhs_s8 = DN_FStr8_ToStr8(rhs); bool result = DN_Str8_Eq(lhs_s8, rhs_s8, DN_Str8EqCase_Insensitive); return result; } template bool operator==(DN_FStr8 const &lhs, DN_FStr8 const &rhs) { bool result = DN_FStr8_Eq(&lhs, &rhs, DN_Str8EqCase_Sensitive); return result; } template bool operator!=(DN_FStr8 const &lhs, DN_FStr8 const &rhs) { bool result = !(lhs == rhs); return result; } template bool operator==(DN_FStr8 const &lhs, DN_Str8 const &rhs) { bool result = DN_Str8_Eq(DN_FStr8_ToStr8(&lhs), rhs, DN_Str8EqCase_Insensitive); return result; } template bool operator!=(DN_FStr8 const &lhs, DN_Str8 const &rhs) { bool result = !(lhs == rhs); return result; } #endif // !defined(DN_NO_FSTR8) #endif // !defined(DN_BASE_STRING_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_ZeroMem_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_ZeroMem_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_ISLList_Detach(list) (decltype(list)) DN_CSLList_Detach((void **)&(list), (void **)&(list)->next) #define DN_LArray_MakeArray(c_array, size, max, count, zero_mem) (decltype(&(c_array)[0])) DN_CArray2_MakeArray(c_array, size, max, sizeof((c_array)[0]), count, zero_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_ZeroMem_Yes) #define DN_LArray_Make(c_array, size, max, zero_mem) (decltype(&(c_array)[0])) DN_CArray2_MakeArray(c_array, size, max, sizeof((c_array)[0]), 1, zero_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_ZeroMem_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_IArray_Front(array) (array)->data #define DN_IArray_GrowIfNeededFromPool(array, pool) DN_CArray2_GrowIfNeededFromPool((void **)(&(array)->data), (array)->size, &(array)->max, sizeof((array)->data[0]), pool) #define DN_IArray_MakeArray(array, count, zero_mem) (decltype(&((array)->data)[0])) DN_CArray2_MakeArray((array)->data, &(array)->size, (array)->max, sizeof(((array)->data)[0]), count, zero_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_ZeroMem_Yes) #define DN_IArray_Make(array, zero_mem) (decltype(&((array)->data)[0])) DN_CArray2_MakeArray((array)->data, &(array)->size, (array)->max, sizeof(((array)->data)[0]), 1, zero_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_ZeroMem_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, size, begin_index, count, erase) DN_CArray2_EraseRange((array)->data, &(array)->size, sizeof(((array)->data)[0]), begin_index, count, erase) 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_ZeroMem zero_mem); DN_API void *DN_CArray2_AddArray (void *data, DN_USize *size, DN_USize max, DN_USize data_size, void *elems, DN_USize elems_count, DN_ArrayAdd add); 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_ZeroMem zero_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_ZeroMem zero_mem); template DN_SArray DN_SArray_InitSlice (DN_Arena *arena, DN_Slice slice, DN_USize size, DN_ZeroMem zero_mem); template DN_SArray DN_SArray_InitCArray (DN_Arena *arena, T const (&array)[N], DN_USize size, DN_ZeroMem); 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_ZeroMem zero_mem); template T * DN_SArray_Make (DN_SArray *array, DN_ZeroMem zero_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_ZeroMem zero_mem); template T * DN_FArray_Make (DN_FArray *array, DN_ZeroMem zero_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_ZeroMem zero_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_ZeroMem zero_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_convert.h" #if !defined(DN_BASE_CONVERT_H) #define DN_BASE_CONVERT_H struct DN_CVTU64Str8 { char data[27 + 1]; // NOTE(dn): 27 is the maximum size of DN_U64 including a separator DN_U8 size; }; enum DN_CVTU64ByteSizeType { DN_CVTU64ByteSizeType_B, DN_CVTU64ByteSizeType_KiB, DN_CVTU64ByteSizeType_MiB, DN_CVTU64ByteSizeType_GiB, DN_CVTU64ByteSizeType_TiB, DN_CVTU64ByteSizeType_Count, DN_CVTU64ByteSizeType_Auto, }; struct DN_CVTU64ByteSize { DN_CVTU64ByteSizeType type; DN_Str8 suffix; // "KiB", "MiB", "GiB" .. e.t.c DN_F64 bytes; }; struct DN_CVTU64HexStr8 { char data[2 /*0x*/ + 16 /*hex*/ + 1 /*null-terminator*/]; DN_U8 size; }; typedef DN_U32 DN_CVTHexU64Str8Flags; enum DN_CVTHexU64Str8Flags_ { DN_CVTHexU64Str8Flags_Nil = 0, DN_CVTHexU64Str8Flags_0xPrefix = 1 << 0, /// Add the '0x' prefix from the string DN_CVTHexU64Str8Flags_UppercaseHex = 1 << 1, /// Use uppercase ascii characters for hex }; typedef DN_U32 DN_CVTU64AgeUnit; enum DN_CVTU64AgeUnit_ { DN_CVTU64AgeUnit_Sec = 1 << 0, DN_CVTU64AgeUnit_Min = 1 << 1, DN_CVTU64AgeUnit_Hr = 1 << 2, DN_CVTU64AgeUnit_Day = 1 << 3, DN_CVTU64AgeUnit_Week = 1 << 4, DN_CVTU64AgeUnit_Year = 1 << 5, DN_CVTU64AgeUnit_HMS = DN_CVTU64AgeUnit_Sec | DN_CVTU64AgeUnit_Min | DN_CVTU64AgeUnit_Hr, DN_CVTU64AgeUnit_All = DN_CVTU64AgeUnit_HMS | DN_CVTU64AgeUnit_Day | DN_CVTU64AgeUnit_Week | DN_CVTU64AgeUnit_Year, }; DN_API int DN_CVT_FmtBuffer3DotTruncate (char *buffer, int size, DN_FMT_ATTRIB char const *fmt, ...); DN_API DN_CVTU64Str8 DN_CVT_U64ToStr8 (DN_U64 val, char separator); DN_API DN_CVTU64ByteSize DN_CVT_U64ToByteSize (DN_U64 bytes, DN_CVTU64ByteSizeType type); DN_API DN_Str8 DN_CVT_U64ToByteSizeStr8 (DN_Arena *arena, DN_U64 bytes, DN_CVTU64ByteSizeType desired_type); DN_API DN_Str8 DN_CVT_U64ByteSizeTypeString (DN_CVTU64ByteSizeType type); DN_API DN_Str8 DN_CVT_U64ToAge (DN_Arena *arena, DN_U64 age_s, DN_CVTU64AgeUnit unit); DN_API DN_Str8 DN_CVT_F64ToAge (DN_Arena *arena, DN_F64 age_s, DN_CVTU64AgeUnit unit); DN_API DN_U64 DN_CVT_HexToU64 (DN_Str8 hex); DN_API DN_Str8 DN_CVT_U64ToHex (DN_Arena *arena, DN_U64 number, DN_CVTHexU64Str8Flags flags); DN_API DN_CVTU64HexStr8 DN_CVT_U64ToHexStr8 (DN_U64 number, DN_U32 flags); DN_API bool DN_CVT_BytesToHexPtr (void const *src, DN_USize src_size, char *dest, DN_USize dest_size); DN_API DN_Str8 DN_CVT_BytesToHex (DN_Arena *arena, void const *src, DN_USize size); #define DN_CVT_BytesToHexFromTLS(...) DN_CVT_BytesToHex(DN_OS_TLSTopArena(), __VA_ARGS__) DN_API DN_USize DN_CVT_HexToBytesPtrUnchecked (DN_Str8 hex, void *dest, DN_USize dest_size); DN_API DN_USize DN_CVT_HexToBytesPtr (DN_Str8 hex, void *dest, DN_USize dest_size); DN_API DN_Str8 DN_CVT_HexToBytesUnchecked (DN_Arena *arena, DN_Str8 hex); #define DN_CVT_HexToBytesUncheckedFromTLS(...) DN_CVT_HexToBytesUnchecked(DN_OS_TLSTopArena(), __VA_ARGS__) DN_API DN_Str8 DN_CVT_HexToBytes (DN_Arena *arena, DN_Str8 hex); #define DN_CVT_HexToBytesFromTLS(...) DN_CVT_HexToBytes(DN_OS_TLSTopArena(), __VA_ARGS__) #endif // defined(DN_BASE_CONVERT_H) #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(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) 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 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(uint32_t error_code); DN_API DN_W32Error DN_W32_ErrorCodeToMsg (DN_Arena *arena, uint32_t error_code); DN_API DN_W32Error DN_W32_ErrorCodeToMsgAlloc (uint32_t 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) // DN: Single header generator inlined this file => #include "OS/dn_os_posix.h" #pragma once #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; }; DN_API void DN_Posix_ThreadSetName(DN_Str8 name); DN_API DN_POSIXProcSelfStatus DN_Posix_ProcSelfStatus(); #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 // 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; }; // NOTE: DN_OSTLS //////////////////////////////////////////////////////////////////////////////////// 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) // NOTE: DN_OS_ErrSink //////////////////////////////////////////////////////////////////////////// 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 #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 // NOTE: DN_OSDate ///////////////////////////////////////////////////////////////////////////////// struct DN_OSDateTimeStr8 { char date[DN_ArrayCountU("YYYY-MM-SS")]; DN_U8 date_size; char hms[DN_ArrayCountU("HH:MM:SS")]; DN_U8 hms_size; }; struct DN_OSDateTime { DN_U8 day; DN_U8 month; DN_U16 year; DN_U8 hour; DN_U8 minutes; DN_U8 seconds; }; struct DN_OSTimer /// Record time between two time-points using the OS's performance counter. { DN_U64 start; DN_U64 end; }; #if !defined(DN_NO_OS_FILE_API) // 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, }; #endif // DN_NO_OS_FILE_API // NOTE: DN_OSPath //////////////////////////////////////////////////////////////////////////////// #if !defined(DN_OSPathSeperator) #if defined(DN_OS_WIN32) #define DN_OSPathSeperator "\\" #else #define DN_OSPathSeperator "/" #endif #define DN_OSPathSeperatorString DN_STR8(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_FStr8<64> 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_OSInitArgs { DN_U64 tls_reserve; DN_U64 tls_commit; DN_U64 tls_err_sink_reserve; DN_U64 tls_err_sink_commit; }; 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_Init (DN_OSCore *os, DN_OSInitArgs *args); DN_API void DN_OS_EmitLogsWithOSPrintFunctions(DN_OSCore *os); DN_API void DN_OS_DumpThreadContextArenaStat (DN_Str8 file_path); // NOTE: Memory //////////////////////////////////////////////////////////////////////////////////// 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); // NOTE: Heap DN_API void * DN_OS_MemAlloc (DN_USize size, DN_ZeroMem zero_mem); DN_API void DN_OS_MemDealloc (void *ptr); // NOTE: DN_OSDate ///////////////////////////////////////////////////////////////////////////////// DN_API DN_OSDateTime DN_OS_DateLocalTimeNow (); DN_API DN_OSDateTimeStr8 DN_OS_DateLocalTimeStr8Now(char date_separator = '-', char hms_separator = ':'); DN_API DN_OSDateTimeStr8 DN_OS_DateLocalTimeStr8 (DN_OSDateTime 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_OSDateTime DN_OS_DateUnixTimeSToDate (DN_U64 time); DN_API DN_U64 DN_OS_DateLocalToUnixTimeS(DN_OSDateTime date); DN_API DN_U64 DN_OS_DateToUnixTimeS (DN_OSDateTime date); DN_API bool DN_OS_DateIsValid (DN_OSDateTime date); // NOTE: Other ///////////////////////////////////////////////////////////////////////////////////// DN_API bool DN_OS_SecureRNGBytes (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); // NOTE: Counters ////////////////////////////////////////////////////////////////////////////////// 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); #if !defined(DN_NO_OS_FILE_API) // NOTE: File system paths ///////////////////////////////////////////////////////////////////////// DN_API DN_OSPathInfo DN_OS_PathInfo (DN_Str8 path); DN_API bool DN_OS_FileIsOlderThan(DN_Str8 file, DN_Str8 check_against); DN_API bool DN_OS_PathDelete (DN_Str8 path); DN_API bool DN_OS_FileExists (DN_Str8 path); DN_API bool DN_OS_CopyFile (DN_Str8 src, DN_Str8 dest, bool overwrite, DN_OSErrSink *err); DN_API bool DN_OS_MoveFile (DN_Str8 src, DN_Str8 dest, bool overwrite, DN_OSErrSink *err); DN_API bool DN_OS_MakeDir (DN_Str8 path); DN_API bool DN_OS_DirExists (DN_Str8 path); DN_API bool DN_OS_DirIterate (DN_Str8 path, DN_OSDirIterator *it); // NOTE: R/W Stream API //////////////////////////////////////////////////////////////////////////// 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); // NOTE: R/W Entire File /////////////////////////////////////////////////////////////////////////// DN_API DN_Str8 DN_OS_ReadAll (DN_Arena *arena, DN_Str8 path, DN_OSErrSink *err); #define DN_OS_ReadAllFromTLS(...) DN_OS_ReadAll(DN_OS_TLSTopArena(), ##__VA_ARGS__) DN_API bool DN_OS_WriteAll (DN_Str8 path, DN_Str8 buffer, DN_OSErrSink *err); DN_API bool DN_OS_WriteAllFV (DN_Str8 path, DN_OSErrSink *err, DN_FMT_ATTRIB char const *fmt, va_list args); DN_API bool DN_OS_WriteAllF (DN_Str8 path, DN_OSErrSink *err, DN_FMT_ATTRIB char const *fmt, ...); DN_API bool DN_OS_WriteAllSafe (DN_Str8 path, DN_Str8 buffer, DN_OSErrSink *err); DN_API bool DN_OS_WriteAllSafeFV (DN_Str8 path, DN_OSErrSink *err, DN_FMT_ATTRIB char const *fmt, va_list args); DN_API bool DN_OS_WriteAllSafeF (DN_Str8 path, DN_OSErrSink *err, DN_FMT_ATTRIB char const *fmt, ...); #endif // !defined(DN_NO_OS_FILE_API) // NOTE: File system paths ///////////////////////////////////////////////////////////////////////// DN_API bool DN_OS_PathAddRef (DN_Arena *arena, DN_OSPath *fs_path, DN_Str8 path); #define DN_OS_PathAddRefFromTLS(...) DN_OS_PathAddRef(DN_OS_TLSTopArena(), ##__VA_ARGS__) #define DN_OS_PathAddRefFromFrame(...) DN_OS_PathAddRef(DN_OS_TLSFrameArena(), ##__VA_ARGS__) 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_STR8("/")) #define DN_OS_PathBuildBackSlash(allocator, fs_path) DN_OS_PathBuildWithSeparator(allocator, fs_path, DN_STR8("\\")) #define DN_OS_PathBuild(allocator, fs_path) DN_OS_PathBuildWithSeparator(allocator, fs_path, DN_OSPathSeparatorString) // NOTE: DN_OSExec ///////////////////////////////////////////////////////////////////////////////// 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 DN_API DN_Arena DN_Arena_InitFromOSHeap(DN_U64 size, DN_ArenaFlags flags); DN_API DN_Arena DN_Arena_InitFromOSVMem(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 // 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_ZeroMem zero_mem); template T * DN_VArray_Make (DN_VArray *array, DN_ZeroMem zero_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_ZeroMem zero_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 // NOTE: DN_Str8 /////////////////////////////////////////////////////////////////////////////////// DN_API DN_Str8 DN_Str8_InitFFromFrame (DN_FMT_ATTRIB char const *fmt, ...); DN_API DN_Str8 DN_Str8_InitFFromOSHeap (DN_FMT_ATTRIB char const *fmt, ...); DN_API DN_Str8 DN_Str8_InitFFromTLS (DN_FMT_ATTRIB char const *fmt, ...); DN_API DN_Str8 DN_Str8_InitFVFromFrame (DN_FMT_ATTRIB char const *fmt, va_list args); DN_API DN_Str8 DN_Str8_InitFVFromTLS (DN_FMT_ATTRIB char const *fmt, va_list args); DN_API DN_Str8 DN_Str8_AllocFromFrame (DN_USize size, DN_ZeroMem zero_mem); DN_API DN_Str8 DN_Str8_AllocFromOSHeap (DN_USize size, DN_ZeroMem zero_mem); DN_API DN_Str8 DN_Str8_AllocFromTLS (DN_USize size, DN_ZeroMem zero_mem); DN_API DN_Str8 DN_Str8_CopyFromFrame (DN_Arena *arena, DN_Str8 string); DN_API DN_Str8 DN_Str8_CopyFromTLS (DN_Arena *arena, DN_Str8 string); DN_API DN_Slice DN_Str8_SplitAllocFromFrame (DN_Str8 string, DN_Str8 delimiter, DN_Str8SplitIncludeEmptyStrings mode); DN_API DN_Slice DN_Str8_SplitAllocFromTLS (DN_Str8 string, DN_Str8 delimiter, DN_Str8SplitIncludeEmptyStrings mode); DN_API DN_Str8 DN_Str8_SegmentFromFrame (DN_Str8 src, DN_USize segment_size, char segment_char); DN_API DN_Str8 DN_Str8_SegmentFromTLS (DN_Str8 src, DN_USize segment_size, char segment_char); DN_API DN_Str8 DN_Str8_ReverseSegmentFromFrame (DN_Str8 src, DN_USize segment_size, char segment_char); DN_API DN_Str8 DN_Str8_ReverseSegmentFromTLS (DN_Str8 src, DN_USize segment_size, char segment_char); DN_API DN_Str8 DN_Str8_AppendFFromFrame (DN_Str8 string, char const *fmt, ...); DN_API DN_Str8 DN_Str8_AppendFFromTLS (DN_Str8 string, char const *fmt, ...); DN_API DN_Str8 DN_Str8_FillFFromFrame (DN_Str8 string, char const *fmt, ...); DN_API DN_Str8 DN_Str8_FillFFromTLS (DN_Str8 string, char const *fmt, ...); DN_API DN_Str8DotTruncateResult DN_Str8_DotTruncateMiddleFromFrame (DN_Str8 str8, uint32_t side_size, DN_Str8 truncator); DN_API DN_Str8DotTruncateResult DN_Str8_DotTruncateMiddleFromTLS (DN_Str8 str8, uint32_t side_size, DN_Str8 truncator); DN_API DN_Str8 DN_Str8_PadNewLines (DN_Arena *arena, DN_Str8 src, DN_Str8 pad); DN_API DN_Str8 DN_Str8_PadNewLinesFromFrame (DN_Str8 src, DN_Str8 pad); DN_API DN_Str8 DN_Str8_PadNewLinesFromTLS (DN_Str8 src, DN_Str8 pad); DN_API DN_Str8 DN_Str8_UpperFromFrame (DN_Str8 string); DN_API DN_Str8 DN_Str8_UpperFromTLS (DN_Str8 string); DN_API DN_Str8 DN_Str8_LowerFromFrame (DN_Str8 string); DN_API DN_Str8 DN_Str8_LowerFromTLS (DN_Str8 string); DN_API DN_Str8 DN_Str8_Replace (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_Str8_ReplaceInsensitive (DN_Str8 string, DN_Str8 find, DN_Str8 replace, DN_USize start_index, DN_Arena *arena); // NOTE: DN_Str8Builder //////////////////////////////////////////////////////////////////////////// DN_API DN_Str8Builder DN_Str8Builder_InitFromFrame () { return DN_Str8Builder_Init(DN_OS_TLSGet()->frame_arena); } DN_API DN_Str8Builder DN_Str8Builder_InitFromTLS () { return DN_Str8Builder_Init(DN_OS_TLSTopArena()); } DN_API DN_Str8Builder DN_Str8Builder_InitArrayRefFromFrame (DN_Str8 const *strings, DN_USize size) { return DN_Str8Builder_InitArrayRef(DN_OS_TLSGet()->frame_arena, strings, size); } DN_API DN_Str8Builder DN_Str8Builder_InitArrayRefFromTLS (DN_Str8 const *strings, DN_USize size) { return DN_Str8Builder_InitArrayRef(DN_OS_TLSTopArena(), strings, size); } DN_API DN_Str8Builder DN_Str8Builder_InitArrayCopyFromFrame (DN_Str8 const *strings, DN_USize size) { return DN_Str8Builder_InitArrayCopy(DN_OS_TLSGet()->frame_arena, strings, size); } DN_API DN_Str8Builder DN_Str8Builder_InitArrayCopyFromTLS (DN_Str8 const *strings, DN_USize size) { return DN_Str8Builder_InitArrayCopy(DN_OS_TLSTopArena(), strings, size); } DN_API DN_Str8Builder DN_Str8Builder_CopyFromFrame (DN_Str8Builder const *builder) { return DN_Str8Builder_Copy(DN_OS_TLSGet()->frame_arena, builder); } DN_API DN_Str8Builder DN_Str8Builder_CopyFromTLS (DN_Str8Builder const *builder) { return DN_Str8Builder_Copy(DN_OS_TLSTopArena(), builder); } DN_API DN_Str8 DN_Str8Builder_BuildFromFrame (DN_Str8Builder const *builder) { return DN_Str8Builder_Build(builder, DN_OS_TLSGet()->frame_arena); } DN_API DN_Slice DN_Str8Builder_BuildFromOSHeap (DN_Str8Builder const *builder, DN_Arena *arena); DN_API DN_Str8 DN_Str8Builder_BuildFromTLS (DN_Str8Builder const *builder) { return DN_Str8Builder_Build(builder, DN_OS_TLSTopArena()); } DN_API DN_Str8 DN_Str8Builder_BuildDelimitedFromFrame(DN_Str8Builder const *builder, DN_Str8 delimiter) { return DN_Str8Builder_BuildDelimited(builder, delimiter, DN_OS_TLSGet()->frame_arena); } DN_API DN_Str8 DN_Str8Builder_BuildDelimitedFromTLS (DN_Str8Builder const *builder, DN_Str8 delimiter) { return DN_Str8Builder_BuildDelimited(builder, delimiter, DN_OS_TLSTopArena()); } DN_API DN_Slice DN_Str8Builder_BuildSliceFromFrame (DN_Str8Builder const *builder) { return DN_Str8Builder_BuildSlice(builder, DN_OS_TLSGet()->frame_arena); } DN_API DN_Slice DN_Str8Builder_BuildSliceFromTLS (DN_Str8Builder const *builder) { return DN_Str8Builder_BuildSlice(builder, DN_OS_TLSTopArena()); } #endif // !defined(DN_OS_STRING_H) #endif // DN_OS_INC_H #if !defined(DN_CORE_INC_H) #define DN_CORE_INC_H // DN: Single header generator inlined this file => #include "Core/dn_core_debug.h" #if !defined(DN_CORE_DEBUG_H) #define DN_CORE_DEBUG_H // NOTE: DN_StackTrace ///////////////////////////////////////////////////////////////////////////// // NOTE: DN_Debug ////////////////////////////////////////////////////////////////////////////////// enum DN_DebugAllocFlag { DN_DebugAllocFlag_Freed = 1 << 0, DN_DebugAllocFlag_LeakPermitted = 1 << 1, }; struct DN_DebugAlloc { 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_DebugAllocFlag` }; static_assert(sizeof(DN_DebugAlloc) == 64 || sizeof(DN_DebugAlloc) == 32, // NOTE: 64 bit vs 32 bit pointers respectively "We aim to keep the allocation record as light as possible as " "memory tracking can get expensive. Enforce that there is no " "unexpected padding."); // NOTE: DN_Profiler /////////////////////////////////////////////////////////////////////////////// #if !defined(DN_NO_PROFILER) #if !defined(DN_PROFILER_ANCHOR_BUFFER_SIZE) #define DN_PROFILER_ANCHOR_BUFFER_SIZE 256 #endif 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; }; #if defined(__cplusplus) struct DN_ProfilerZoneScope { DN_ProfilerZoneScope(DN_Str8 name, DN_U16 anchor_index); ~DN_ProfilerZoneScope(); DN_ProfilerZone zone; }; #define DN_Profiler_ZoneScopeAtIndex(name, anchor_index) auto DN_UniqueName(profile_zone_) = DN_ProfilerZoneScope(DN_STR8(name), anchor_index) #define DN_Profiler_ZoneScope(name) DN_Profiler_ZoneScopeAtIndex(name, __COUNTER__ + 1) #endif #define DN_Profiler_ZoneBlockIndex(name, index) \ for (DN_ProfilerZone DN_UniqueName(profile_zone__) = DN_Profiler_BeginZoneAtIndex(name, index), DN_UniqueName(dummy__) = {}; \ DN_UniqueName(dummy__).begin_tsc == 0; \ DN_Profiler_EndZone(DN_UniqueName(profile_zone__)), DN_UniqueName(dummy__).begin_tsc = 1) #define DN_Profiler_ZoneBlock(name) DN_Profiler_ZoneBlockIndex(DN_STR8(name), __COUNTER__ + 1) enum DN_ProfilerAnchorBuffer { DN_ProfilerAnchorBuffer_Back, DN_ProfilerAnchorBuffer_Front, }; struct DN_Profiler { DN_ProfilerAnchor anchors[2][DN_PROFILER_ANCHOR_BUFFER_SIZE]; DN_U8 active_anchor_buffer; DN_U16 parent_zone; }; DN_API DN_ProfilerAnchor * DN_Profiler_ReadBuffer (); DN_API DN_ProfilerAnchor * DN_Profiler_WriteBuffer (); #define DN_Profiler_BeginZone(name) DN_Profiler_BeginZoneAtIndex(DN_STR8(name), __COUNTER__ + 1) DN_API DN_ProfilerZone DN_Profiler_BeginZoneAtIndex (DN_Str8 name, DN_U16 anchor_index); DN_API void DN_Profiler_EndZone (DN_ProfilerZone zone); DN_API DN_ProfilerAnchor * DN_Profiler_AnchorBuffer (DN_ProfilerAnchorBuffer buffer); DN_API void DN_Profiler_SwapAnchorBuffer (); DN_API void DN_Profiler_Dump (DN_U64 tsc_per_second); #endif // !defined(DN_NO_PROFILER) #endif // DN_CORE_DEBUG_H // DN: Single header generator inlined this file => #include "Core/dn_core.h" #if !defined(DN_CORE_H) #define DN_CORE_H // NOTE: DN_Core /////////////////////////////////////////////////////////////////////////////////// // Book-keeping data for the library and allow customisation of certain features // provided. struct DN_Core { // NOTE: Leak Tracing ////////////////////////////////////////////////////////////////////////// #if defined(DN_LEAK_TRACKING) DN_DSMap alloc_table; DN_TicketMutex alloc_table_mutex; DN_Arena alloc_table_arena; #endif DN_U64 alloc_table_bytes_allocated_for_stack_traces; // NOTE: Profiler ////////////////////////////////////////////////////////////////////////////// #if !defined(DN_NO_PROFILER) DN_Profiler * profiler; DN_Profiler profiler_default_instance; #endif }; enum DN_CoreOnInit { DN_CoreOnInit_Nil = 0, DN_CoreOnInit_LogLibFeatures = 1 << 0, DN_CoreOnInit_LogCPUFeatures = 1 << 1, DN_CoreOnInit_LogAllFeatures = DN_CoreOnInit_LogLibFeatures | DN_CoreOnInit_LogCPUFeatures, }; DN_API void DN_Core_Init (DN_Core *core, DN_CoreOnInit on_init); DN_API void DN_Core_BeginFrame (); #if !defined(DN_NO_PROFILER) DN_API void DN_Core_SetProfiler (DN_Profiler *profiler); #endif #endif // !defined(DN_CORE_H) #endif // !defined(DN_CORE_INC_H)