7510 lines
338 KiB
C++
7510 lines
338 KiB
C++
// Generated by the DN single header generator 2025-06-28 20:52:01
|
|
|
|
#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 <Windows.h> 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 <Windows.h> (requires dn_os_inc.h)
|
|
// If you are building DN for the Windows platform, <Windows.h> 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
|
|
// <Windows.h> to improve compilation times. This can be disabled by defining:
|
|
//
|
|
// DN_NO_WINDOWS_H_REPLACEMENT_HEADER
|
|
//
|
|
// To instead use <Windows.h>. DN automatically detects if <Windows.h> 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 <sanitizer/asan_interface.h>
|
|
#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 <stdarg.h> // va_list
|
|
#include <stdio.h>
|
|
#include <stdint.h>
|
|
#include <limits.h>
|
|
#include <inttypes.h> // PRIu64...
|
|
|
|
#if !defined(DN_OS_WIN32)
|
|
#include <stdlib.h> // 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 <string.h>
|
|
#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 <math.h>
|
|
#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 <signal.h>
|
|
#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 <typename Procedure>
|
|
struct DN_Defer
|
|
{
|
|
Procedure proc;
|
|
DN_Defer(Procedure p) : proc(p) {}
|
|
~DN_Defer() { proc(); }
|
|
};
|
|
|
|
struct DN_DeferHelper
|
|
{
|
|
template <typename Lambda>
|
|
DN_Defer<Lambda> operator+(Lambda lambda) { return DN_Defer<Lambda>(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 <typename T>
|
|
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 <intrin.h>
|
|
#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 <emmintrin.h>
|
|
#else
|
|
#include <x86intrin.h>
|
|
#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 <DN_USize N>
|
|
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 <DN_USize N>
|
|
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_StackTraceFrame> 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 <stdarg.h> // for va_arg(), va_list()
|
|
#include <stddef.h> // 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 <DN_USize N>
|
|
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 <DN_USize N> constexpr DN_USize DN_CStr8_ArrayUCount (char const (&literal)[N]) { (void)literal; return N - 1; }
|
|
template <DN_USize N> 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> 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_USize N> DN_Str8Builder DN_Str8Builder_InitCArrayRef (DN_Arena *arena, DN_Str8 const (&array)[N]);
|
|
template <DN_USize N> 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_Str8> DN_Str8Builder_BuildSlice (DN_Str8Builder const *builder, DN_Arena *arena);
|
|
|
|
// NOTE: DN_FStr8 //////////////////////////////////////////////////////////////////////////////////
|
|
#if !defined(DN_NO_FSTR8)
|
|
template <DN_USize N> DN_FStr8<N> DN_FStr8_InitF (DN_FMT_ATTRIB char const *fmt, ...);
|
|
template <DN_USize N> DN_FStr8<N> DN_FStr8_InitFV (char const *fmt, va_list args);
|
|
template <DN_USize N> DN_USize DN_FStr8_Max (DN_FStr8<N> const *string);
|
|
template <DN_USize N> void DN_FStr8_Clear (DN_FStr8<N> *string);
|
|
template <DN_USize N> bool DN_FStr8_AddFV (DN_FStr8<N> *string, DN_FMT_ATTRIB char const *fmt, va_list va);
|
|
template <DN_USize N> bool DN_FStr8_AddF (DN_FStr8<N> *string, DN_FMT_ATTRIB char const *fmt, ...);
|
|
template <DN_USize N> bool DN_FStr8_AddCStr8 (DN_FStr8<N> *string, char const *value, DN_USize size);
|
|
template <DN_USize N> bool DN_FStr8_Add (DN_FStr8<N> *string, DN_Str8 value);
|
|
template <DN_USize N> DN_Str8 DN_FStr8_ToStr8 (DN_FStr8<N> const *string);
|
|
template <DN_USize N> bool DN_FStr8_Eq (DN_FStr8<N> const *lhs, DN_FStr8<N> const *rhs, DN_Str8EqCase eq_case);
|
|
template <DN_USize N> bool DN_FStr8_EqStr8 (DN_FStr8<N> const *lhs, DN_Str8 rhs, DN_Str8EqCase eq_case);
|
|
template <DN_USize N> bool DN_FStr8_EqInsensitive (DN_FStr8<N> const *lhs, DN_FStr8<N> const *rhs);
|
|
template <DN_USize N> bool DN_FStr8_EqStr8Insensitive (DN_FStr8<N> const *lhs, DN_Str8 rhs);
|
|
template <DN_USize A, DN_USize B> bool DN_FStr8_EqFStr8 (DN_FStr8<A> const *lhs, DN_FStr8<B> const *rhs, DN_Str8EqCase eq_case);
|
|
template <DN_USize A, DN_USize B> bool DN_FStr8_EqFStr8Insensitive (DN_FStr8<A> const *lhs, DN_FStr8<B> const *rhs);
|
|
template <DN_USize N> bool operator== (DN_FStr8<N> const &lhs, DN_FStr8<N> const &rhs);
|
|
template <DN_USize N> bool operator!= (DN_FStr8<N> const &lhs, DN_FStr8<N> const &rhs);
|
|
template <DN_USize N> bool operator== (DN_FStr8<N> const &lhs, DN_Str8 const &rhs);
|
|
template <DN_USize N> bool operator!= (DN_FStr8<N> 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_USize N>
|
|
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_USize N>
|
|
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 <DN_USize N>
|
|
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 <DN_USize N>
|
|
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_USize N>
|
|
DN_FStr8<N> DN_FStr8_InitF(DN_FMT_ATTRIB char const *fmt, ...)
|
|
{
|
|
DN_FStr8<N> result = {};
|
|
if (fmt) {
|
|
va_list args;
|
|
va_start(args, fmt);
|
|
DN_FStr8_AddFV(&result, fmt, args);
|
|
va_end(args);
|
|
}
|
|
return result;
|
|
}
|
|
|
|
template <DN_USize N>
|
|
DN_FStr8<N> DN_FStr8_InitFV(char const *fmt, va_list args)
|
|
{
|
|
DN_FStr8<N> result = {};
|
|
DN_FStr8_AddFV(&result, fmt, args);
|
|
return result;
|
|
}
|
|
|
|
template <DN_USize N>
|
|
DN_USize DN_FStr8_Max(DN_FStr8<N> const *)
|
|
{
|
|
DN_USize result = N;
|
|
return result;
|
|
}
|
|
|
|
template <DN_USize N>
|
|
void DN_FStr8_Clear(DN_FStr8<N> *string)
|
|
{
|
|
*string = {};
|
|
}
|
|
|
|
template <DN_USize N>
|
|
bool DN_FStr8_AddFV(DN_FStr8<N> *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 <DN_USize N>
|
|
bool DN_FStr8_AddF(DN_FStr8<N> *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 <DN_USize N>
|
|
bool DN_FStr8_AddCStr8(DN_FStr8<N> *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 <DN_USize N>
|
|
bool DN_FStr8_Add(DN_FStr8<N> *string, DN_Str8 src)
|
|
{
|
|
bool result = DN_FStr8_AddCStr8(string, src.data, src.size);
|
|
return result;
|
|
}
|
|
|
|
template <DN_USize N>
|
|
DN_Str8 DN_FStr8_ToStr8(DN_FStr8<N> 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 <DN_USize N>
|
|
bool DN_FStr8_Eq(DN_FStr8<N> const *lhs, DN_FStr8<N> 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 <DN_USize N>
|
|
bool DN_FStr8_EqStr8(DN_FStr8<N> 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 <DN_USize N>
|
|
bool DN_FStr8_EqInsensitive(DN_FStr8<N> const *lhs, DN_FStr8<N> 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 <DN_USize N>
|
|
bool DN_FStr8_EqStr8Insensitive(DN_FStr8<N> 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 <DN_USize A, DN_USize B>
|
|
bool DN_FStr8_EqFStr8(DN_FStr8<A> const *lhs, DN_FStr8<B> 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 <DN_USize A, DN_USize B>
|
|
bool DN_FStr8_EqFStr8Insensitive(DN_FStr8<A> const *lhs, DN_FStr8<B> 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 <DN_USize N>
|
|
bool operator==(DN_FStr8<N> const &lhs, DN_FStr8<N> const &rhs)
|
|
{
|
|
bool result = DN_FStr8_Eq(&lhs, &rhs, DN_Str8EqCase_Sensitive);
|
|
return result;
|
|
}
|
|
|
|
template <DN_USize N>
|
|
bool operator!=(DN_FStr8<N> const &lhs, DN_FStr8<N> const &rhs)
|
|
{
|
|
bool result = !(lhs == rhs);
|
|
return result;
|
|
}
|
|
|
|
template <DN_USize N>
|
|
bool operator==(DN_FStr8<N> const &lhs, DN_Str8 const &rhs)
|
|
{
|
|
bool result = DN_Str8_Eq(DN_FStr8_ToStr8(&lhs), rhs, DN_Str8EqCase_Insensitive);
|
|
return result;
|
|
}
|
|
|
|
template <DN_USize N>
|
|
bool operator!=(DN_FStr8<N> 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 <typename T> 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 <typename T> 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 <typename T, DN_USize N> 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 <typename T> using DN_FArray8 = DN_FArray<T, 8>;
|
|
template <typename T> using DN_FArray16 = DN_FArray<T, 16>;
|
|
template <typename T> using DN_FArray32 = DN_FArray<T, 32>;
|
|
template <typename T> using DN_FArray64 = DN_FArray<T, 64>;
|
|
#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 <typename T>
|
|
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 <typename T> struct DN_DSMap
|
|
{
|
|
DN_U32 *hash_to_slot; // Mapping from hash to a index in the slots array
|
|
DN_DSMapSlot<T> *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 <typename T> struct DN_DSMapResult
|
|
{
|
|
bool found;
|
|
DN_DSMapSlot<T> *slot;
|
|
T *value;
|
|
};
|
|
#endif // !defined(DN_NO_DSMAP)
|
|
|
|
#if !defined(DN_NO_LIST)
|
|
// NOTE: DN_List ///////////////////////////////////////////////////////////////////////////////////
|
|
template <typename T> struct DN_ListChunk
|
|
{
|
|
T *data;
|
|
DN_USize size;
|
|
DN_USize count;
|
|
DN_ListChunk<T> *next;
|
|
DN_ListChunk<T> *prev;
|
|
};
|
|
|
|
template <typename T> struct DN_ListIterator
|
|
{
|
|
DN_B32 init; // True if DN_List_Iterate has been called at-least once on this iterator
|
|
DN_ListChunk<T> *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 <typename T> 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<T> *head;
|
|
DN_ListChunk<T> *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_LArray_Erase(c_array, size, index, erase) DN_CArray2_EraseRange(c_array, size, sizeof((c_array)[0]), index, 1, 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)
|
|
#define DN_IArray_Erase(array, size, index, erase) DN_CArray2_EraseRange((array)->data, &(array)->size, sizeof(((array)->data)[0]), index, 1, 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 <typename T> DN_ArrayEraseResult DN_CArray_EraseRange (T *data, DN_USize *size, DN_USize begin_index, DN_ISize count, DN_ArrayErase erase);
|
|
template <typename T> T * DN_CArray_MakeArray (T *data, DN_USize *size, DN_USize max, DN_USize count, DN_ZeroMem zero_mem);
|
|
template <typename T> T * DN_CArray_InsertArray (T *data, DN_USize *size, DN_USize max, DN_USize index, T const *items, DN_USize count);
|
|
template <typename T> T DN_CArray_PopFront (T *data, DN_USize *size, DN_USize count);
|
|
template <typename T> T DN_CArray_PopBack (T *data, DN_USize *size, DN_USize count);
|
|
template <typename T> DN_ArrayFindResult<T> DN_CArray_Find (T *data, DN_USize size, T const &value);
|
|
|
|
// NOTE: DN_SArray /////////////////////////////////////////////////////////////////////////////////
|
|
#if !defined(DN_NO_SARRAY)
|
|
template <typename T> DN_SArray<T> DN_SArray_Init (DN_Arena *arena, DN_USize size, DN_ZeroMem zero_mem);
|
|
template <typename T> DN_SArray<T> DN_SArray_InitSlice (DN_Arena *arena, DN_Slice<T> slice, DN_USize size, DN_ZeroMem zero_mem);
|
|
template <typename T, size_t N> DN_SArray<T> DN_SArray_InitCArray (DN_Arena *arena, T const (&array)[N], DN_USize size, DN_ZeroMem);
|
|
template <typename T> DN_SArray<T> DN_SArray_InitBuffer (T* buffer, DN_USize size);
|
|
template <typename T> bool DN_SArray_IsValid (DN_SArray<T> const *array);
|
|
template <typename T> DN_Slice<T> DN_SArray_Slice (DN_SArray<T> const *array);
|
|
template <typename T> T * DN_SArray_AddArray (DN_SArray<T> *array, T const *items, DN_USize count);
|
|
template <typename T, DN_USize N> T * DN_SArray_AddCArray (DN_SArray<T> *array, T const (&items)[N]);
|
|
template <typename T> T * DN_SArray_Add (DN_SArray<T> *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 <typename T> T * DN_SArray_MakeArray (DN_SArray<T> *array, DN_USize count, DN_ZeroMem zero_mem);
|
|
template <typename T> T * DN_SArray_Make (DN_SArray<T> *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 <typename T> T * DN_SArray_InsertArray (DN_SArray<T> *array, DN_USize index, T const *items, DN_USize count);
|
|
template <typename T, DN_USize N> T * DN_SArray_InsertCArray (DN_SArray<T> *array, DN_USize index, T const (&items)[N]);
|
|
template <typename T> T * DN_SArray_Insert (DN_SArray<T> *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 <typename T> T DN_SArray_PopFront (DN_SArray<T> *array, DN_USize count);
|
|
template <typename T> T DN_SArray_PopBack (DN_SArray<T> *array, DN_USize count);
|
|
template <typename T> DN_ArrayEraseResult DN_SArray_EraseRange (DN_SArray<T> *array, DN_USize begin_index, DN_ISize count, DN_ArrayErase erase);
|
|
template <typename T> void DN_SArray_Clear (DN_SArray<T> *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 <typename T, DN_USize N> DN_FArray<T, N> DN_FArray_Init (T const *array, DN_USize count);
|
|
#define DN_FArray_HasData(array) ((array).data && (array).size)
|
|
template <typename T, DN_USize N> DN_FArray<T, N> DN_FArray_InitSlice (DN_Slice<T> slice);
|
|
template <typename T, DN_USize N, DN_USize K> DN_FArray<T, N> DN_FArray_InitCArray (T const (&items)[K]);
|
|
template <typename T, DN_USize N> bool DN_FArray_IsValid (DN_FArray<T, N> const *array);
|
|
template <typename T, DN_USize N> DN_USize DN_FArray_Max (DN_FArray<T, N> const *) { return N; }
|
|
template <typename T, DN_USize N> DN_Slice<T> DN_FArray_Slice (DN_FArray<T, N> const *array);
|
|
template <typename T, DN_USize N> T * DN_FArray_AddArray (DN_FArray<T, N> *array, T const *items, DN_USize count);
|
|
template <typename T, DN_USize N, DN_USize K> T * DN_FArray_AddCArray (DN_FArray<T, N> *array, T const (&items)[K]);
|
|
template <typename T, DN_USize N> T * DN_FArray_Add (DN_FArray<T, N> *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 <typename T, DN_USize N> T * DN_FArray_MakeArray (DN_FArray<T, N> *array, DN_USize count, DN_ZeroMem zero_mem);
|
|
template <typename T, DN_USize N> T * DN_FArray_Make (DN_FArray<T, N> *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 <typename T, DN_USize N> T * DN_FArray_InsertArray (DN_FArray<T, N> *array, T const &item, DN_USize index);
|
|
template <typename T, DN_USize N, DN_USize K> T * DN_FArray_InsertCArray (DN_FArray<T, N> *array, DN_USize index, T const (&items)[K]);
|
|
template <typename T, DN_USize N> T * DN_FArray_Insert (DN_FArray<T, N> *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 <typename T, DN_USize N> T DN_FArray_PopFront (DN_FArray<T, N> *array, DN_USize count);
|
|
template <typename T, DN_USize N> T DN_FArray_PopBack (DN_FArray<T, N> *array, DN_USize count);
|
|
template <typename T, DN_USize N> DN_ArrayFindResult<T> DN_FArray_Find (DN_FArray<T, N> *array, T const &find);
|
|
template <typename T, DN_USize N> DN_ArrayEraseResult DN_FArray_EraseRange (DN_FArray<T, N> *array, DN_USize begin_index, DN_ISize count, DN_ArrayErase erase);
|
|
template <typename T, DN_USize N> void DN_FArray_Clear (DN_FArray<T, N> *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 <typename T> DN_Slice<T> DN_Slice_Init (T* const data, DN_USize size);
|
|
template <typename T, DN_USize N> DN_Slice<T> DN_Slice_InitCArrayCopy (DN_Arena *arena, T const (&array)[N]);
|
|
template <typename T> DN_Slice<T> DN_Slice_Copy (DN_Arena *arena, DN_Slice<T> slice);
|
|
template <typename T> DN_Slice<T> DN_Slice_CopyPtr (DN_Arena *arena, T* const data, DN_USize size);
|
|
template <typename T> DN_Slice<T> DN_Slice_Alloc (DN_Arena *arena, DN_USize size, DN_ZeroMem zero_mem);
|
|
DN_Str8 DN_Slice_Str8Render (DN_Arena *arena, DN_Slice<DN_Str8> array, DN_Str8 separator);
|
|
DN_Str8 DN_Slice_Str8RenderSpaceSeparated (DN_Arena *arena, DN_Slice<DN_Str8> array);
|
|
DN_Str16 DN_Slice_Str16Render (DN_Arena *arena, DN_Slice<DN_Str16> array, DN_Str16 separator);
|
|
DN_Str16 DN_Slice_Str16RenderSpaceSeparated(DN_Arena *arena, DN_Slice<DN_Str16> array);
|
|
#endif // !defined(DN_NO_SLICE)
|
|
|
|
#if !defined(DN_NO_DSMAP)
|
|
template <typename T> DN_DSMap<T> DN_DSMap_Init (DN_Arena *arena, DN_U32 size, DN_DSMapFlags flags);
|
|
template <typename T> void DN_DSMap_Deinit (DN_DSMap<T> *map, DN_ZeroMem zero_mem);
|
|
template <typename T> bool DN_DSMap_IsValid (DN_DSMap<T> const *map);
|
|
template <typename T> DN_U32 DN_DSMap_Hash (DN_DSMap<T> const *map, DN_DSMapKey key);
|
|
template <typename T> DN_U32 DN_DSMap_HashToSlotIndex (DN_DSMap<T> const *map, DN_DSMapKey key);
|
|
template <typename T> DN_DSMapResult<T> DN_DSMap_Find (DN_DSMap<T> const *map, DN_DSMapKey key);
|
|
template <typename T> DN_DSMapResult<T> DN_DSMap_Make (DN_DSMap<T> *map, DN_DSMapKey key);
|
|
template <typename T> DN_DSMapResult<T> DN_DSMap_Set (DN_DSMap<T> *map, DN_DSMapKey key, T const &value);
|
|
template <typename T> DN_DSMapResult<T> DN_DSMap_FindKeyU64 (DN_DSMap<T> const *map, DN_U64 key);
|
|
template <typename T> DN_DSMapResult<T> DN_DSMap_MakeKeyU64 (DN_DSMap<T> *map, DN_U64 key);
|
|
template <typename T> DN_DSMapResult<T> DN_DSMap_SetKeyU64 (DN_DSMap<T> *map, DN_U64 key, T const &value);
|
|
template <typename T> DN_DSMapResult<T> DN_DSMap_FindKeyStr8 (DN_DSMap<T> const *map, DN_Str8 key);
|
|
template <typename T> DN_DSMapResult<T> DN_DSMap_MakeKeyStr8 (DN_DSMap<T> *map, DN_Str8 key);
|
|
template <typename T> DN_DSMapResult<T> DN_DSMap_SetKeyStr8 (DN_DSMap<T> *map, DN_Str8 key, T const &value);
|
|
template <typename T> bool DN_DSMap_Resize (DN_DSMap<T> *map, DN_U32 size);
|
|
template <typename T> bool DN_DSMap_Erase (DN_DSMap<T> *map, DN_DSMapKey key);
|
|
template <typename T> bool DN_DSMap_EraseKeyU64 (DN_DSMap<T> *map, DN_U64 key);
|
|
template <typename T> bool DN_DSMap_EraseKeyStr8 (DN_DSMap<T> *map, DN_Str8 key);
|
|
template <typename T> DN_DSMapKey DN_DSMap_KeyBuffer (DN_DSMap<T> const *map, void const *data, DN_U32 size);
|
|
template <typename T> DN_DSMapKey DN_DSMap_KeyBufferAsU64NoHash (DN_DSMap<T> const *map, void const *data, DN_U32 size);
|
|
template <typename T> DN_DSMapKey DN_DSMap_KeyU64 (DN_DSMap<T> const *map, DN_U64 u64);
|
|
template <typename T> DN_DSMapKey DN_DSMap_KeyStr8 (DN_DSMap<T> 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 <typename T> DN_List<T> DN_List_Init (DN_USize chunk_size);
|
|
template <typename T, size_t N> DN_List<T> DN_List_InitCArray (DN_Arena *arena, DN_USize chunk_size, T const (&array)[N]);
|
|
template <typename T> T * DN_List_At (DN_List<T> *list, DN_USize index, DN_ListChunk<T> **at_chunk);
|
|
template <typename T> void DN_List_Clear (DN_List<T> *list);
|
|
template <typename T> bool DN_List_Iterate (DN_List<T> *list, DN_ListIterator<T> *it, DN_USize start_index);
|
|
template <typename T> T * DN_List_MakeArena (DN_List<T> *list, DN_Arena *arena, DN_USize count);
|
|
template <typename T> T * DN_List_MakePool (DN_List<T> *list, DN_Pool *pool, DN_USize count);
|
|
template <typename T> T * DN_List_AddArena (DN_List<T> *list, DN_Arena *arena, T const &value);
|
|
template <typename T> T * DN_List_AddPool (DN_List<T> *list, DN_Pool *pool, T const &value);
|
|
template <typename T> void DN_List_AddListArena (DN_List<T> *list, DN_Arena *arena, DN_List<T> other);
|
|
template <typename T> void DN_List_AddListArena (DN_List<T> *list, DN_Pool *pool, DN_List<T> other);
|
|
template <typename T> DN_Slice<T> DN_List_ToSliceCopy (DN_List<T> 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 <Windows.h> // LONG
|
|
#include <bcrypt.h> // DN_OS_SecureRNGBytes -> BCryptOpenAlgorithmProvider ... etc
|
|
#include <shellapi.h> // DN_Win_MakeProcessDPIAware -> SetProcessDpiAwareProc
|
|
#include <shlwapi.h> // PathRelativePathTO
|
|
#include <pathcch.h> // PathCchCanonicalizeEx
|
|
#include <winhttp.h> // WinHttp*
|
|
#include <psapi.h> // PROCESS_MEMORY_COUNTERS_EX2
|
|
#include <commdlg.h> // OPENFILENAMEW
|
|
#include <DbgHelp.h>
|
|
#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 <pthread.h>
|
|
#include <semaphore.h>
|
|
|
|
/*
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// $$$$$$\ $$$$$$\ $$$$$$$\ $$$$$$\ $$$$$$\ $$$$$$\ $$\ $$\
|
|
// $$ __$$\ $$ __$$\ $$ __$$\ $$ __$$\ $$ __$$\ \_$$ _|$$ | $$ |
|
|
// $$ / $$ |$$ / \__| $$ | $$ |$$ / $$ |$$ / \__| $$ | \$$\ $$ |
|
|
// $$ | $$ |\$$$$$$\ $$$$$$$ |$$ | $$ |\$$$$$$\ $$ | \$$$$ /
|
|
// $$ | $$ | \____$$\ $$ ____/ $$ | $$ | \____$$\ $$ | $$ $$<
|
|
// $$ | $$ |$$\ $$ | $$ | $$ | $$ |$$\ $$ | $$ | $$ /\$$\
|
|
// $$$$$$ |\$$$$$$ | $$ | $$$$$$ |\$$$$$$ |$$$$$$\ $$ / $$ |
|
|
// \______/ \______/ \__| \______/ \______/ \______|\__| \__|
|
|
//
|
|
// 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 <new> // operator new
|
|
|
|
#if !defined(DN_OS_WIN32) || defined(DN_OS_WIN32_USE_PTHREADS)
|
|
#include <pthread.h>
|
|
#include <semaphore.h>
|
|
#endif
|
|
|
|
#if defined(DN_PLATFORM_POSIX) || defined(DN_PLATFORM_EMSCRIPTEN)
|
|
#include <errno.h> // errno
|
|
#include <fcntl.h> // O_RDONLY ... etc
|
|
#include <sys/ioctl.h> // ioctl
|
|
#include <sys/mman.h> // mmap
|
|
#include <sys/random.h> // getrandom
|
|
#include <sys/stat.h> // stat
|
|
#include <sys/types.h> // pid_t
|
|
#include <sys/wait.h> // waitpid
|
|
#include <time.h> // clock_gettime, nanosleep
|
|
#include <unistd.h> // access, gettid, write
|
|
|
|
#if !defined(DN_PLATFORM_EMSCRIPTEN)
|
|
#include <linux/fs.h> // FICLONE
|
|
#include <sys/sendfile.h> // sendfile
|
|
#endif
|
|
#endif
|
|
|
|
#if defined(DN_PLATFORM_EMSCRIPTEN)
|
|
#include <emscripten/fetch.h> // 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<DN_Str8> 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<DN_Str8> cmd_line, DN_OSExecArgs *args, DN_OSErrSink *err);
|
|
DN_API DN_OSExecResult DN_OS_Exec (DN_Slice<DN_Str8> cmd_line, DN_OSExecArgs *args, DN_Arena *arena, DN_OSErrSink *err);
|
|
DN_API DN_OSExecResult DN_OS_ExecOrAbort (DN_Slice<DN_Str8> 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 <typename T> 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 <typename T> DN_VArray<T> DN_VArray_InitByteSize (DN_USize byte_size);
|
|
template <typename T> DN_VArray<T> DN_VArray_Init (DN_USize max);
|
|
template <typename T> DN_VArray<T> DN_VArray_InitSlice (DN_Slice<T> slice, DN_USize max);
|
|
template <typename T, DN_USize N> DN_VArray<T> DN_VArray_InitCArray (T const (&items)[N], DN_USize max);
|
|
template <typename T> void DN_VArray_Deinit (DN_VArray<T> *array);
|
|
template <typename T> bool DN_VArray_IsValid (DN_VArray<T> const *array);
|
|
template <typename T> DN_Slice<T> DN_VArray_Slice (DN_VArray<T> const *array);
|
|
template <typename T> bool DN_VArray_Reserve (DN_VArray<T> *array, DN_USize count);
|
|
template <typename T> T * DN_VArray_AddArray (DN_VArray<T> *array, T const *items, DN_USize count);
|
|
template <typename T, DN_USize N> T * DN_VArray_AddCArray (DN_VArray<T> *array, T const (&items)[N]);
|
|
template <typename T> T * DN_VArray_Add (DN_VArray<T> *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 <typename T> T * DN_VArray_MakeArray (DN_VArray<T> *array, DN_USize count, DN_ZeroMem zero_mem);
|
|
template <typename T> T * DN_VArray_Make (DN_VArray<T> *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 <typename T> T * DN_VArray_InsertArray (DN_VArray<T> *array, DN_USize index, T const *items, DN_USize count);
|
|
template <typename T, DN_USize N> T * DN_VArray_InsertCArray (DN_VArray<T> *array, DN_USize index, T const (&items)[N]);
|
|
template <typename T> T * DN_VArray_Insert (DN_VArray<T> *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 <typename T> T DN_VArray_PopFront (DN_VArray<T> *array, DN_USize count);
|
|
template <typename T> T DN_VArray_PopBack (DN_VArray<T> *array, DN_USize count);
|
|
template <typename T> DN_ArrayEraseResult DN_VArray_EraseRange (DN_VArray<T> *array, DN_USize begin_index, DN_ISize count, DN_ArrayErase erase);
|
|
template <typename T> void DN_VArray_Clear (DN_VArray<T> *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> DN_Str8_SplitAllocFromFrame (DN_Str8 string, DN_Str8 delimiter, DN_Str8SplitIncludeEmptyStrings mode);
|
|
DN_API DN_Slice<DN_Str8> 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_Str8> 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_Str8> DN_Str8Builder_BuildSliceFromFrame (DN_Str8Builder const *builder) { return DN_Str8Builder_BuildSlice(builder, DN_OS_TLSGet()->frame_arena); }
|
|
DN_API DN_Slice<DN_Str8> 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<DN_DebugAlloc> 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)
|
|
#if !defined(DN_MATH_H)
|
|
#define DN_MATH_H
|
|
|
|
DN_MSVC_WARNING_PUSH
|
|
DN_MSVC_WARNING_DISABLE(4201) // warning C4201: nonstandard extension used: nameless struct/union
|
|
#if !defined(DN_NO_V2)
|
|
// NOTE: DN_V2 /////////////////////////////////////////////////////////////////////////////////////
|
|
union DN_V2I32
|
|
{
|
|
struct { int32_t x, y; };
|
|
struct { int32_t w, h; };
|
|
int32_t data[2];
|
|
};
|
|
|
|
union DN_V2U16
|
|
{
|
|
struct { uint16_t x, y; };
|
|
struct { uint16_t w, h; };
|
|
uint16_t data[2];
|
|
};
|
|
|
|
union DN_V2F32
|
|
{
|
|
struct { DN_F32 x, y; };
|
|
struct { DN_F32 w, h; };
|
|
DN_F32 data[2];
|
|
};
|
|
#endif // !defined(DN_NO_V2)
|
|
|
|
#if !defined(DN_NO_V3)
|
|
// NOTE: DN_V3 /////////////////////////////////////////////////////////////////////////////////////
|
|
union DN_V3F32
|
|
{
|
|
struct { DN_F32 x, y, z; };
|
|
struct { DN_F32 r, g, b; };
|
|
DN_F32 data[3];
|
|
};
|
|
|
|
#endif // !defined(DN_NO_V3)
|
|
|
|
#if !defined(DN_NO_V4)
|
|
// NOTE: DN_V4 /////////////////////////////////////////////////////////////////////////////////////
|
|
union DN_V4F32
|
|
{
|
|
struct { DN_F32 x, y, z, w; };
|
|
struct { DN_F32 r, g, b, a; };
|
|
#if !defined(DN_NO_V3)
|
|
DN_V3F32 rgb;
|
|
DN_V3F32 xyz;
|
|
#endif
|
|
DN_F32 data[4];
|
|
};
|
|
#endif // !defined(DN_NO_V4)
|
|
DN_MSVC_WARNING_POP
|
|
|
|
#if !defined(DN_NO_M4)
|
|
// NOTE: DN_M4 /////////////////////////////////////////////////////////////////////////////////////
|
|
struct DN_M4
|
|
{
|
|
DN_F32 columns[4][4]; // Column major matrix
|
|
};
|
|
#endif // !defined(DN_M4)
|
|
|
|
// NOTE: DN_M2x3 ///////////////////////////////////////////////////////////////////////////////////
|
|
union DN_M2x3
|
|
{
|
|
DN_F32 e[6];
|
|
DN_F32 row[2][3];
|
|
};
|
|
|
|
// NOTE: DN_Rect ///////////////////////////////////////////////////////////////////////////////////
|
|
#if !defined(DN_NO_RECT)
|
|
#if defined(DN_NO_V2)
|
|
#error "Rectangles requires V2, DN_NO_V2 must not be defined"
|
|
#endif
|
|
struct DN_Rect
|
|
{
|
|
DN_V2F32 pos, size;
|
|
};
|
|
|
|
struct DN_RectMinMax
|
|
{
|
|
DN_V2F32 min, max;
|
|
};
|
|
|
|
enum DN_RectCutClip
|
|
{
|
|
DN_RectCutClip_No,
|
|
DN_RectCutClip_Yes,
|
|
};
|
|
|
|
enum DN_RectCutSide
|
|
{
|
|
DN_RectCutSide_Left,
|
|
DN_RectCutSide_Right,
|
|
DN_RectCutSide_Top,
|
|
DN_RectCutSide_Bottom,
|
|
};
|
|
|
|
struct DN_RectCut
|
|
{
|
|
DN_Rect* rect;
|
|
DN_RectCutSide side;
|
|
};
|
|
#endif // !defined(DN_NO_RECT)
|
|
|
|
// NOTE: Other /////////////////////////////////////////////////////////////////////////////////////
|
|
// NOTE: API
|
|
struct DN_RaycastLineIntersectV2Result
|
|
{
|
|
bool hit; // True if there was an intersection, false if the lines are parallel
|
|
DN_F32 t_a; // Distance along `dir_a` that the intersection occurred, e.g. `origin_a + (dir_a * t_a)`
|
|
DN_F32 t_b; // Distance along `dir_b` that the intersection occurred, e.g. `origin_b + (dir_b * t_b)`
|
|
};
|
|
|
|
#if !defined(DN_NO_V2)
|
|
// NOTE: DN_V2 /////////////////////////////////////////////////////////////////////////////////////
|
|
#define DN_V2I32_Zero DN_LITERAL(DN_V2I32){{(int32_t)(0), (int32_t)(0)}}
|
|
#define DN_V2I32_One DN_LITERAL(DN_V2I32){{(int32_t)(1), (int32_t)(1)}}
|
|
#define DN_V2I32_Init1N(x) DN_LITERAL(DN_V2I32){{(int32_t)(x), (int32_t)(x)}}
|
|
#define DN_V2I32_Init2N(x, y) DN_LITERAL(DN_V2I32){{(int32_t)(x), (int32_t)(y)}}
|
|
#define DN_V2I32_InitV2(xy) DN_LITERAL(DN_V2I32){{(int32_t)(xy).x, (int32_t)(xy).y}}
|
|
|
|
DN_API bool operator!= (DN_V2I32 lhs, DN_V2I32 rhs);
|
|
DN_API bool operator== (DN_V2I32 lhs, DN_V2I32 rhs);
|
|
DN_API bool operator>= (DN_V2I32 lhs, DN_V2I32 rhs);
|
|
DN_API bool operator<= (DN_V2I32 lhs, DN_V2I32 rhs);
|
|
DN_API bool operator< (DN_V2I32 lhs, DN_V2I32 rhs);
|
|
DN_API bool operator> (DN_V2I32 lhs, DN_V2I32 rhs);
|
|
DN_API DN_V2I32 operator- (DN_V2I32 lhs, DN_V2I32 rhs);
|
|
DN_API DN_V2I32 operator- (DN_V2I32 lhs);
|
|
DN_API DN_V2I32 operator+ (DN_V2I32 lhs, DN_V2I32 rhs);
|
|
DN_API DN_V2I32 operator* (DN_V2I32 lhs, DN_V2I32 rhs);
|
|
DN_API DN_V2I32 operator* (DN_V2I32 lhs, DN_F32 rhs);
|
|
DN_API DN_V2I32 operator* (DN_V2I32 lhs, int32_t rhs);
|
|
DN_API DN_V2I32 operator/ (DN_V2I32 lhs, DN_V2I32 rhs);
|
|
DN_API DN_V2I32 operator/ (DN_V2I32 lhs, DN_F32 rhs);
|
|
DN_API DN_V2I32 operator/ (DN_V2I32 lhs, int32_t rhs);
|
|
DN_API DN_V2I32 & operator*= (DN_V2I32& lhs, DN_V2I32 rhs);
|
|
DN_API DN_V2I32 & operator*= (DN_V2I32& lhs, DN_F32 rhs);
|
|
DN_API DN_V2I32 & operator*= (DN_V2I32& lhs, int32_t rhs);
|
|
DN_API DN_V2I32 & operator/= (DN_V2I32& lhs, DN_V2I32 rhs);
|
|
DN_API DN_V2I32 & operator/= (DN_V2I32& lhs, DN_F32 rhs);
|
|
DN_API DN_V2I32 & operator/= (DN_V2I32& lhs, int32_t rhs);
|
|
DN_API DN_V2I32 & operator-= (DN_V2I32& lhs, DN_V2I32 rhs);
|
|
DN_API DN_V2I32 & operator+= (DN_V2I32& lhs, DN_V2I32 rhs);
|
|
|
|
DN_API DN_V2I32 DN_V2I32_Min (DN_V2I32 a, DN_V2I32 b);
|
|
DN_API DN_V2I32 DN_V2I32_Max (DN_V2I32 a, DN_V2I32 b);
|
|
DN_API DN_V2I32 DN_V2I32_Abs (DN_V2I32 a);
|
|
|
|
#define DN_V2U16_Zero DN_LITERAL(DN_V2U16){{(uint16_t)(0), (uint16_t)(0)}}
|
|
#define DN_V2U16_One DN_LITERAL(DN_V2U16){{(uint16_t)(1), (uint16_t)(1)}}
|
|
#define DN_V2U16_Init1N(x) DN_LITERAL(DN_V2U16){{(uint16_t)(x), (uint16_t)(x)}}
|
|
#define DN_V2U16_Init2N(x, y) DN_LITERAL(DN_V2U16){{(uint16_t)(x), (uint16_t)(y)}}
|
|
|
|
DN_API bool operator!= (DN_V2U16 lhs, DN_V2U16 rhs);
|
|
DN_API bool operator== (DN_V2U16 lhs, DN_V2U16 rhs);
|
|
DN_API bool operator>= (DN_V2U16 lhs, DN_V2U16 rhs);
|
|
DN_API bool operator<= (DN_V2U16 lhs, DN_V2U16 rhs);
|
|
DN_API bool operator< (DN_V2U16 lhs, DN_V2U16 rhs);
|
|
DN_API bool operator> (DN_V2U16 lhs, DN_V2U16 rhs);
|
|
DN_API DN_V2U16 operator- (DN_V2U16 lhs, DN_V2U16 rhs);
|
|
DN_API DN_V2U16 operator+ (DN_V2U16 lhs, DN_V2U16 rhs);
|
|
DN_API DN_V2U16 operator* (DN_V2U16 lhs, DN_V2U16 rhs);
|
|
DN_API DN_V2U16 operator* (DN_V2U16 lhs, DN_F32 rhs);
|
|
DN_API DN_V2U16 operator* (DN_V2U16 lhs, int32_t rhs);
|
|
DN_API DN_V2U16 operator/ (DN_V2U16 lhs, DN_V2U16 rhs);
|
|
DN_API DN_V2U16 operator/ (DN_V2U16 lhs, DN_F32 rhs);
|
|
DN_API DN_V2U16 operator/ (DN_V2U16 lhs, int32_t rhs);
|
|
DN_API DN_V2U16 & operator*= (DN_V2U16& lhs, DN_V2U16 rhs);
|
|
DN_API DN_V2U16 & operator*= (DN_V2U16& lhs, DN_F32 rhs);
|
|
DN_API DN_V2U16 & operator*= (DN_V2U16& lhs, int32_t rhs);
|
|
DN_API DN_V2U16 & operator/= (DN_V2U16& lhs, DN_V2U16 rhs);
|
|
DN_API DN_V2U16 & operator/= (DN_V2U16& lhs, DN_F32 rhs);
|
|
DN_API DN_V2U16 & operator/= (DN_V2U16& lhs, int32_t rhs);
|
|
DN_API DN_V2U16 & operator-= (DN_V2U16& lhs, DN_V2U16 rhs);
|
|
DN_API DN_V2U16 & operator+= (DN_V2U16& lhs, DN_V2U16 rhs);
|
|
|
|
#define DN_V2F32_Zero DN_LITERAL(DN_V2F32){{(DN_F32)(0), (DN_F32)(0)}}
|
|
#define DN_V2F32_One DN_LITERAL(DN_V2F32){{(DN_F32)(1), (DN_F32)(1)}}
|
|
#define DN_V2F32_Init1N(x) DN_LITERAL(DN_V2F32){{(DN_F32)(x), (DN_F32)(x)}}
|
|
#define DN_V2F32_Init2N(x, y) DN_LITERAL(DN_V2F32){{(DN_F32)(x), (DN_F32)(y)}}
|
|
#define DN_V2F32_InitV2I32(xy) DN_LITERAL(DN_V2F32){{(DN_F32)(xy).x, (DN_F32)(xy).y}}
|
|
|
|
DN_API bool operator!= (DN_V2F32 lhs, DN_V2F32 rhs);
|
|
DN_API bool operator== (DN_V2F32 lhs, DN_V2F32 rhs);
|
|
DN_API bool operator>= (DN_V2F32 lhs, DN_V2F32 rhs);
|
|
DN_API bool operator<= (DN_V2F32 lhs, DN_V2F32 rhs);
|
|
DN_API bool operator< (DN_V2F32 lhs, DN_V2F32 rhs);
|
|
DN_API bool operator> (DN_V2F32 lhs, DN_V2F32 rhs);
|
|
|
|
DN_API DN_V2F32 operator- (DN_V2F32 lhs);
|
|
DN_API DN_V2F32 operator- (DN_V2F32 lhs, DN_V2F32 rhs);
|
|
DN_API DN_V2F32 operator- (DN_V2F32 lhs, DN_V2I32 rhs);
|
|
DN_API DN_V2F32 operator- (DN_V2F32 lhs, DN_F32 rhs);
|
|
DN_API DN_V2F32 operator- (DN_V2F32 lhs, int32_t rhs);
|
|
|
|
DN_API DN_V2F32 operator+ (DN_V2F32 lhs, DN_V2F32 rhs);
|
|
DN_API DN_V2F32 operator+ (DN_V2F32 lhs, DN_V2I32 rhs);
|
|
DN_API DN_V2F32 operator+ (DN_V2F32 lhs, DN_F32 rhs);
|
|
DN_API DN_V2F32 operator+ (DN_V2F32 lhs, int32_t rhs);
|
|
|
|
DN_API DN_V2F32 operator* (DN_V2F32 lhs, DN_V2F32 rhs);
|
|
DN_API DN_V2F32 operator* (DN_V2F32 lhs, DN_V2I32 rhs);
|
|
DN_API DN_V2F32 operator* (DN_V2F32 lhs, DN_F32 rhs);
|
|
DN_API DN_V2F32 operator* (DN_V2F32 lhs, int32_t rhs);
|
|
|
|
DN_API DN_V2F32 operator/ (DN_V2F32 lhs, DN_V2F32 rhs);
|
|
DN_API DN_V2F32 operator/ (DN_V2F32 lhs, DN_V2I32 rhs);
|
|
DN_API DN_V2F32 operator/ (DN_V2F32 lhs, DN_F32 rhs);
|
|
DN_API DN_V2F32 operator/ (DN_V2F32 lhs, int32_t rhs);
|
|
|
|
DN_API DN_V2F32 & operator*= (DN_V2F32& lhs, DN_V2F32 rhs);
|
|
DN_API DN_V2F32 & operator*= (DN_V2F32& lhs, DN_V2I32 rhs);
|
|
DN_API DN_V2F32 & operator*= (DN_V2F32& lhs, DN_F32 rhs);
|
|
DN_API DN_V2F32 & operator*= (DN_V2F32& lhs, int32_t rhs);
|
|
|
|
DN_API DN_V2F32 & operator/= (DN_V2F32& lhs, DN_V2F32 rhs);
|
|
DN_API DN_V2F32 & operator/= (DN_V2F32& lhs, DN_V2I32 rhs);
|
|
DN_API DN_V2F32 & operator/= (DN_V2F32& lhs, DN_F32 rhs);
|
|
DN_API DN_V2F32 & operator/= (DN_V2F32& lhs, int32_t rhs);
|
|
|
|
DN_API DN_V2F32 & operator-= (DN_V2F32& lhs, DN_V2F32 rhs);
|
|
DN_API DN_V2F32 & operator-= (DN_V2F32& lhs, DN_V2I32 rhs);
|
|
DN_API DN_V2F32 & operator-= (DN_V2F32& lhs, DN_F32 rhs);
|
|
DN_API DN_V2F32 & operator-= (DN_V2F32& lhs, int32_t rhs);
|
|
|
|
DN_API DN_V2F32 & operator+= (DN_V2F32& lhs, DN_V2F32 rhs);
|
|
DN_API DN_V2F32 & operator+= (DN_V2F32& lhs, DN_V2I32 rhs);
|
|
DN_API DN_V2F32 & operator+= (DN_V2F32& lhs, DN_F32 rhs);
|
|
DN_API DN_V2F32 & operator+= (DN_V2F32& lhs, int32_t rhs);
|
|
|
|
DN_API DN_V2F32 DN_V2F32_Min (DN_V2F32 a, DN_V2F32 b);
|
|
DN_API DN_V2F32 DN_V2F32_Max (DN_V2F32 a, DN_V2F32 b);
|
|
DN_API DN_V2F32 DN_V2F32_Abs (DN_V2F32 a);
|
|
DN_API DN_F32 DN_V2F32_Dot (DN_V2F32 a, DN_V2F32 b);
|
|
DN_API DN_F32 DN_V2F32_LengthSq_V2x2 (DN_V2F32 lhs, DN_V2F32 rhs);
|
|
DN_API DN_F32 DN_V2F32_Length_V2x2 (DN_V2F32 lhs, DN_V2F32 rhs);
|
|
DN_API DN_F32 DN_V2F32_LengthSq (DN_V2F32 lhs);
|
|
DN_API DN_F32 DN_V2F32_Length (DN_V2F32 lhs);
|
|
DN_API DN_V2F32 DN_V2F32_Normalise (DN_V2F32 a);
|
|
DN_API DN_V2F32 DN_V2F32_Perpendicular (DN_V2F32 a);
|
|
DN_API DN_V2F32 DN_V2F32_Reflect (DN_V2F32 in, DN_V2F32 surface);
|
|
DN_API DN_F32 DN_V2F32_Area (DN_V2F32 a);
|
|
#endif // !defined(DN_NO_V2)
|
|
#if !defined(DN_NO_V3)
|
|
// NOTE: DN_V3 /////////////////////////////////////////////////////////////////////////////////////
|
|
#define DN_V3F32_Init1N(x) DN_LITERAL(DN_V3F32){{(DN_F32)(x), (DN_F32)(x), (DN_F32)(x)}}
|
|
#define DN_V3F32_Init3F32(x, y, z) DN_LITERAL(DN_V3F32){{(DN_F32)(x), (DN_F32)(y), (DN_F32)(z)}}
|
|
#define DN_V3F32_InitV2F32_1F32(xy, z) DN_LITERAL(DN_V3F32){{(DN_F32)(xy.x), (DN_F32)(xy.y), (DN_F32)(z)}}
|
|
|
|
DN_API bool operator== (DN_V3F32 lhs, DN_V3F32 rhs);
|
|
DN_API bool operator!= (DN_V3F32 lhs, DN_V3F32 rhs);
|
|
DN_API bool operator>= (DN_V3F32 lhs, DN_V3F32 rhs);
|
|
DN_API bool operator<= (DN_V3F32 lhs, DN_V3F32 rhs);
|
|
DN_API bool operator< (DN_V3F32 lhs, DN_V3F32 rhs);
|
|
DN_API bool operator> (DN_V3F32 lhs, DN_V3F32 rhs);
|
|
DN_API DN_V3F32 operator- (DN_V3F32 lhs, DN_V3F32 rhs);
|
|
DN_API DN_V3F32 operator- (DN_V3F32 lhs);
|
|
DN_API DN_V3F32 operator+ (DN_V3F32 lhs, DN_V3F32 rhs);
|
|
DN_API DN_V3F32 operator* (DN_V3F32 lhs, DN_V3F32 rhs);
|
|
DN_API DN_V3F32 operator* (DN_V3F32 lhs, DN_F32 rhs);
|
|
DN_API DN_V3F32 operator* (DN_V3F32 lhs, int32_t rhs);
|
|
DN_API DN_V3F32 operator/ (DN_V3F32 lhs, DN_V3F32 rhs);
|
|
DN_API DN_V3F32 operator/ (DN_V3F32 lhs, DN_F32 rhs);
|
|
DN_API DN_V3F32 operator/ (DN_V3F32 lhs, int32_t rhs);
|
|
DN_API DN_V3F32 & operator*= (DN_V3F32 &lhs, DN_V3F32 rhs);
|
|
DN_API DN_V3F32 & operator*= (DN_V3F32 &lhs, DN_F32 rhs);
|
|
DN_API DN_V3F32 & operator*= (DN_V3F32 &lhs, int32_t rhs);
|
|
DN_API DN_V3F32 & operator/= (DN_V3F32 &lhs, DN_V3F32 rhs);
|
|
DN_API DN_V3F32 & operator/= (DN_V3F32 &lhs, DN_F32 rhs);
|
|
DN_API DN_V3F32 & operator/= (DN_V3F32 &lhs, int32_t rhs);
|
|
DN_API DN_V3F32 & operator-= (DN_V3F32 &lhs, DN_V3F32 rhs);
|
|
DN_API DN_V3F32 & operator+= (DN_V3F32 &lhs, DN_V3F32 rhs);
|
|
DN_API DN_F32 DN_V3F32_LengthSq (DN_V3F32 a);
|
|
DN_API DN_F32 DN_V3F32_Length (DN_V3F32 a);
|
|
DN_API DN_V3F32 DN_V3F32_Normalise (DN_V3F32 a);
|
|
#endif // !defined(DN_NO_V3)
|
|
#if !defined(DN_NO_V4)
|
|
// NOTE: DN_V4 /////////////////////////////////////////////////////////////////////////////////////
|
|
#define DN_V4F32_Init1N(x) DN_LITERAL(DN_V4F32){{(DN_F32)(x), (DN_F32)(x), (DN_F32)(x), (DN_F32)(x)}}
|
|
#define DN_V4F32_Init4N(x, y, z, w) DN_LITERAL(DN_V4F32){{(DN_F32)(x), (DN_F32)(y), (DN_F32)(z), (DN_F32)(w)}}
|
|
#define DN_V4F32_InitV3_1N(xyz, w) DN_LITERAL(DN_V4F32){{xyz.x, xyz.y, xyz.z, w}}
|
|
DN_API bool operator== (DN_V4F32 lhs, DN_V4F32 rhs);
|
|
DN_API bool operator!= (DN_V4F32 lhs, DN_V4F32 rhs);
|
|
DN_API bool operator<= (DN_V4F32 lhs, DN_V4F32 rhs);
|
|
DN_API bool operator< (DN_V4F32 lhs, DN_V4F32 rhs);
|
|
DN_API bool operator> (DN_V4F32 lhs, DN_V4F32 rhs);
|
|
DN_API DN_V4F32 operator- (DN_V4F32 lhs, DN_V4F32 rhs);
|
|
DN_API DN_V4F32 operator- (DN_V4F32 lhs);
|
|
DN_API DN_V4F32 operator+ (DN_V4F32 lhs, DN_V4F32 rhs);
|
|
DN_API DN_V4F32 operator* (DN_V4F32 lhs, DN_V4F32 rhs);
|
|
DN_API DN_V4F32 operator* (DN_V4F32 lhs, DN_F32 rhs);
|
|
DN_API DN_V4F32 operator* (DN_V4F32 lhs, int32_t rhs);
|
|
DN_API DN_V4F32 operator/ (DN_V4F32 lhs, DN_F32 rhs);
|
|
DN_API DN_V4F32 & operator*= (DN_V4F32 &lhs, DN_V4F32 rhs);
|
|
DN_API DN_V4F32 & operator*= (DN_V4F32 &lhs, DN_F32 rhs);
|
|
DN_API DN_V4F32 & operator*= (DN_V4F32 &lhs, int32_t rhs);
|
|
DN_API DN_V4F32 & operator-= (DN_V4F32 &lhs, DN_V4F32 rhs);
|
|
DN_API DN_V4F32 & operator+= (DN_V4F32 &lhs, DN_V4F32 rhs);
|
|
#endif // !defined(DN_NO_V4)
|
|
#if !defined(DN_NO_M4)
|
|
// NOTE: DN_M4 /////////////////////////////////////////////////////////////////////////////////////
|
|
DN_API DN_F32 DN_V4F32Dot (DN_V4F32 a, DN_V4F32 b);
|
|
DN_API DN_M4 DN_M4_Identity ();
|
|
DN_API DN_M4 DN_M4_ScaleF (DN_F32 x, DN_F32 y, DN_F32 z);
|
|
DN_API DN_M4 DN_M4_Scale (DN_V3F32 xyz);
|
|
DN_API DN_M4 DN_M4_TranslateF (DN_F32 x, DN_F32 y, DN_F32 z);
|
|
DN_API DN_M4 DN_M4_Translate (DN_V3F32 xyz);
|
|
DN_API DN_M4 DN_M4_Transpose (DN_M4 mat);
|
|
DN_API DN_M4 DN_M4_Rotate (DN_V3F32 axis, DN_F32 radians);
|
|
DN_API DN_M4 DN_M4_Orthographic (DN_F32 left, DN_F32 right, DN_F32 bottom, DN_F32 top, DN_F32 z_near, DN_F32 z_far);
|
|
DN_API DN_M4 DN_M4_Perspective (DN_F32 fov /*radians*/, DN_F32 aspect, DN_F32 z_near, DN_F32 z_far);
|
|
DN_API DN_M4 DN_M4_Add (DN_M4 lhs, DN_M4 rhs);
|
|
DN_API DN_M4 DN_M4_Sub (DN_M4 lhs, DN_M4 rhs);
|
|
DN_API DN_M4 DN_M4_Mul (DN_M4 lhs, DN_M4 rhs);
|
|
DN_API DN_M4 DN_M4_Div (DN_M4 lhs, DN_M4 rhs);
|
|
DN_API DN_M4 DN_M4_AddF (DN_M4 lhs, DN_F32 rhs);
|
|
DN_API DN_M4 DN_M4_SubF (DN_M4 lhs, DN_F32 rhs);
|
|
DN_API DN_M4 DN_M4_MulF (DN_M4 lhs, DN_F32 rhs);
|
|
DN_API DN_M4 DN_M4_DivF (DN_M4 lhs, DN_F32 rhs);
|
|
#if !defined(DN_NO_FSTR8)
|
|
DN_API DN_FStr8<256> DN_M4_ColumnMajorString (DN_M4 mat);
|
|
#endif
|
|
#endif // !defined(DN_NO_M4)
|
|
// NOTE: DN_M2x3 ///////////////////////////////////////////////////////////////////////////////////
|
|
DN_API bool operator== (DN_M2x3 const &lhs, DN_M2x3 const &rhs);
|
|
DN_API bool operator!= (DN_M2x3 const &lhs, DN_M2x3 const &rhs);
|
|
DN_API DN_M2x3 DN_M2x3_Identity ();
|
|
DN_API DN_M2x3 DN_M2x3_Translate (DN_V2F32 offset);
|
|
DN_API DN_M2x3 DN_M2x3_Scale (DN_V2F32 scale);
|
|
DN_API DN_M2x3 DN_M2x3_Rotate (DN_F32 radians);
|
|
DN_API DN_M2x3 DN_M2x3_Mul (DN_M2x3 m1, DN_M2x3 m2);
|
|
DN_API DN_V2F32 DN_M2x3_Mul2F32 (DN_M2x3 m1, DN_F32 x, DN_F32 y);
|
|
DN_API DN_V2F32 DN_M2x3_MulV2 (DN_M2x3 m1, DN_V2F32 v2);
|
|
#if !defined(DN_NO_RECT)
|
|
// NOTE: DN_Rect ///////////////////////////////////////////////////////////////////////////////////
|
|
#define DN_Rect_Init2V2(pos, size) DN_LITERAL(DN_Rect){(pos), (size)}
|
|
#define DN_Rect_Init4N(x, y, w, h) DN_LITERAL(DN_Rect){DN_LITERAL(DN_V2F32){{x, y}}, DN_LITERAL(DN_V2F32){{w, h}}}
|
|
|
|
DN_API bool operator== (const DN_Rect& lhs, const DN_Rect& rhs);
|
|
DN_API DN_V2F32 DN_Rect_Center (DN_Rect rect);
|
|
DN_API bool DN_Rect_ContainsPoint (DN_Rect rect, DN_V2F32 p);
|
|
DN_API bool DN_Rect_ContainsRect (DN_Rect a, DN_Rect b);
|
|
DN_API DN_Rect DN_Rect_Expand (DN_Rect a, DN_F32 amount);
|
|
DN_API DN_Rect DN_Rect_ExpandV2 (DN_Rect a, DN_V2F32 amount);
|
|
DN_API bool DN_Rect_Intersects (DN_Rect a, DN_Rect b);
|
|
DN_API DN_Rect DN_Rect_Intersection (DN_Rect a, DN_Rect b);
|
|
DN_API DN_Rect DN_Rect_Union (DN_Rect a, DN_Rect b);
|
|
DN_API DN_RectMinMax DN_Rect_MinMax (DN_Rect a);
|
|
DN_API DN_F32 DN_Rect_Area (DN_Rect a);
|
|
DN_API DN_V2F32 DN_Rect_InterpolatedPoint (DN_Rect rect, DN_V2F32 t01);
|
|
DN_API DN_V2F32 DN_Rect_TopLeft (DN_Rect rect);
|
|
DN_API DN_V2F32 DN_Rect_TopRight (DN_Rect rect);
|
|
DN_API DN_V2F32 DN_Rect_BottomLeft (DN_Rect rect);
|
|
DN_API DN_V2F32 DN_Rect_BottomRight (DN_Rect rect);
|
|
|
|
DN_API DN_Rect DN_Rect_CutLeftClip (DN_Rect *rect, DN_F32 amount, DN_RectCutClip clip);
|
|
DN_API DN_Rect DN_Rect_CutRightClip (DN_Rect *rect, DN_F32 amount, DN_RectCutClip clip);
|
|
DN_API DN_Rect DN_Rect_CutTopClip (DN_Rect *rect, DN_F32 amount, DN_RectCutClip clip);
|
|
DN_API DN_Rect DN_Rect_CutBottomClip (DN_Rect *rect, DN_F32 amount, DN_RectCutClip clip);
|
|
|
|
#define DN_Rect_CutLeft(rect, amount) DN_Rect_CutLeftClip(rect, amount, DN_RectCutClip_Yes)
|
|
#define DN_Rect_CutRight(rect, amount) DN_Rect_CutRightClip(rect, amount, DN_RectCutClip_Yes)
|
|
#define DN_Rect_CutTop(rect, amount) DN_Rect_CutTopClip(rect, amount, DN_RectCutClip_Yes)
|
|
#define DN_Rect_CutBottom(rect, amount) DN_Rect_CutBottomClip(rect, amount, DN_RectCutClip_Yes)
|
|
|
|
#define DN_Rect_CutLeftNoClip(rect, amount) DN_Rect_CutLeftClip(rect, amount, DN_RectCutClip_No)
|
|
#define DN_Rect_CutRightNoClip(rect, amount) DN_Rect_CutRightClip(rect, amount, DN_RectCutClip_No)
|
|
#define DN_Rect_CutTopNoClip(rect, amount) DN_Rect_CutTopClip(rect, amount, DN_RectCutClip_No)
|
|
#define DN_Rect_CutBottomNoClip(rect, amount) DN_Rect_CutBottomClip(rect, amount, DN_RectCutClip_No)
|
|
|
|
DN_API DN_Rect DN_RectCut_Cut (DN_RectCut rect_cut, DN_V2F32 size, DN_RectCutClip clip);
|
|
#define DN_RectCut_Init(rect, side) DN_LITERAL(DN_RectCut){rect, side}
|
|
#define DN_RectCut_Left(rect) DN_LITERAL(DN_RectCut){rect, DN_RectCutSide_Left}
|
|
#define DN_RectCut_Right(rect) DN_LITERAL(DN_RectCut){rect, DN_RectCutSide_Right}
|
|
#define DN_RectCut_Top(rect) DN_LITERAL(DN_RectCut){rect, DN_RectCutSide_Top}
|
|
#define DN_RectCut_Bottom(rect) DN_LITERAL(DN_RectCut){rect, DN_RectCutSide_Bottom}
|
|
#endif // !defined(DN_NO_RECT)
|
|
// NOTE: Other /////////////////////////////////////////////////////////////////////////////////////
|
|
DN_API DN_RaycastLineIntersectV2Result DN_Raycast_LineIntersectV2(DN_V2F32 origin_a, DN_V2F32 dir_a, DN_V2F32 origin_b, DN_V2F32 dir_b);
|
|
DN_API DN_V2F32 DN_Lerp_V2F32 (DN_V2F32 a, DN_F32 t, DN_V2F32 b);
|
|
DN_API DN_F32 DN_Lerp_F32 (DN_F32 a, DN_F32 t, DN_F32 b);
|
|
|
|
#endif // !defined(DN_MATH_H)
|
|
#if !defined(DN_ASYNC_H)
|
|
#define DN_ASYNC_H
|
|
|
|
// DN: Single header generator commented out this header => #include "../dn_base_inc.h"
|
|
// DN: Single header generator commented out this header => #include "../dn_os_inc.h"
|
|
|
|
enum DN_ASYNCPriority
|
|
{
|
|
DN_ASYNCPriority_Low,
|
|
DN_ASYNCPriority_High,
|
|
DN_ASYNCPriority_Count,
|
|
};
|
|
|
|
struct DN_ASYNCCore
|
|
{
|
|
DN_OSMutex ring_mutex;
|
|
DN_OSConditionVariable ring_write_cv;
|
|
DN_OSSemaphore worker_sem;
|
|
DN_Ring ring;
|
|
DN_OSThread *threads;
|
|
DN_U32 thread_count;
|
|
DN_U32 busy_threads;
|
|
DN_U32 join_threads;
|
|
};
|
|
|
|
typedef void(DN_ASYNCWorkFunc)(void *input);
|
|
|
|
struct DN_ASYNCWork
|
|
{
|
|
DN_ASYNCWorkFunc *func;
|
|
void *input;
|
|
void *output;
|
|
};
|
|
|
|
struct DN_ASYNCJob
|
|
{
|
|
DN_ASYNCWork work;
|
|
DN_OSSemaphore completion_sem;
|
|
};
|
|
|
|
struct DN_ASYNCTask
|
|
{
|
|
DN_ASYNCWork work;
|
|
};
|
|
|
|
DN_API void DN_ASYNC_Init (DN_ASYNCCore *async, char *base, DN_USize base_size, DN_OSThread *threads, DN_U32 threads_size);
|
|
DN_API void DN_ASYNC_Deinit (DN_ASYNCCore *async);
|
|
DN_API bool DN_ASYNC_QueueWork(DN_ASYNCCore *async, DN_ASYNCWorkFunc *func, void *input, DN_U64 wait_time_ms);
|
|
DN_API DN_OSSemaphore DN_ASYNC_QueueTask(DN_ASYNCCore *async, DN_ASYNCWorkFunc *func, void *input, DN_U64 wait_time_ms);
|
|
DN_API void DN_ASYNC_WaitTask (DN_OSSemaphore *sem, DN_U32 timeout_ms);
|
|
|
|
#endif // DN_ASYNC_H
|
|
#if !defined(DN_BIN_PACK_H)
|
|
#define DN_BIN_PACK_H
|
|
|
|
#if !defined(DN_BASE_INC_H)
|
|
#error dn_base_inc.h must be included before this
|
|
#endif
|
|
|
|
enum DN_BinPackMode
|
|
{
|
|
DN_BinPackMode_Serialise,
|
|
DN_BinPackMode_Deserialise,
|
|
};
|
|
|
|
struct DN_BinPack
|
|
{
|
|
DN_Str8Builder writer;
|
|
DN_Str8 read;
|
|
DN_USize read_index;
|
|
};
|
|
|
|
DN_API void DN_BinPack_U64 (DN_BinPack *pack, DN_BinPackMode mode, DN_U64 *item);
|
|
DN_API void DN_BinPack_U32 (DN_BinPack *pack, DN_BinPackMode mode, DN_U32 *item);
|
|
DN_API void DN_BinPack_U16 (DN_BinPack *pack, DN_BinPackMode mode, DN_U16 *item);
|
|
DN_API void DN_BinPack_U8 (DN_BinPack *pack, DN_BinPackMode mode, DN_U8 *item);
|
|
DN_API void DN_BinPack_I64 (DN_BinPack *pack, DN_BinPackMode mode, DN_I64 *item);
|
|
DN_API void DN_BinPack_I32 (DN_BinPack *pack, DN_BinPackMode mode, DN_I32 *item);
|
|
DN_API void DN_BinPack_I16 (DN_BinPack *pack, DN_BinPackMode mode, DN_I16 *item);
|
|
DN_API void DN_BinPack_I8 (DN_BinPack *pack, DN_BinPackMode mode, DN_I8 *item);
|
|
DN_API void DN_BinPack_F64 (DN_BinPack *pack, DN_BinPackMode mode, DN_F64 *item);
|
|
DN_API void DN_BinPack_F32 (DN_BinPack *pack, DN_BinPackMode mode, DN_F32 *item);
|
|
#if defined(DN_MATH_H)
|
|
DN_API void DN_BinPack_V2 (DN_BinPack *pack, DN_BinPackMode mode, DN_V2F32 *item);
|
|
DN_API void DN_BinPack_V4 (DN_BinPack *pack, DN_BinPackMode mode, DN_V4F32 *item);
|
|
#endif
|
|
DN_API void DN_BinPack_Bool (DN_BinPack *pack, DN_BinPackMode mode, bool *item);
|
|
DN_API void DN_BinPack_Str8 (DN_BinPack *pack, DN_Arena *arena, DN_BinPackMode mode, DN_Str8 *string);
|
|
DN_API void DN_BinPack_Str8Pool(DN_BinPack *pack, DN_Pool *pool, DN_BinPackMode mode, DN_Str8 *string);
|
|
template <DN_USize N> DN_API void DN_BinPack_FStr8 (DN_BinPack *pack, DN_BinPackMode mode, DN_FStr8<N> *string);
|
|
DN_API void DN_BinPack_Bytes (DN_BinPack *pack, DN_Arena *arena, DN_BinPackMode mode, void **ptr, DN_USize *size);
|
|
DN_API void DN_BinPack_CArray (DN_BinPack *pack, DN_BinPackMode mode, void *ptr, DN_USize size);
|
|
DN_API DN_Str8 DN_BinPack_Build (DN_BinPack const *pack, DN_Arena *arena);
|
|
|
|
#endif // !defined(DN_BIN_PACK_H)
|
|
#if !defined(DN_CSV_H)
|
|
#define DN_CSV_H
|
|
|
|
enum DN_CSVSerialise
|
|
{
|
|
DN_CSVSerialise_Read,
|
|
DN_CSVSerialise_Write,
|
|
};
|
|
|
|
struct DN_CSVTokeniser
|
|
{
|
|
bool bad;
|
|
DN_Str8 string;
|
|
char delimiter;
|
|
char const *it;
|
|
bool end_of_line;
|
|
};
|
|
|
|
struct DN_CSVPack
|
|
{
|
|
DN_Str8Builder write_builder;
|
|
DN_USize write_column;
|
|
DN_CSVTokeniser read_tokeniser;
|
|
};
|
|
|
|
#endif // !defined(DN_CSV_H)
|
|
#if !defined(DN_HASH_H)
|
|
#define DN_HASH_H
|
|
|
|
/*
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// $$\ $$\ $$$$$$\ $$$$$$\ $$\ $$\
|
|
// $$ | $$ |$$ __$$\ $$ __$$\ $$ | $$ |
|
|
// $$ | $$ |$$ / $$ |$$ / \__|$$ | $$ |
|
|
// $$$$$$$$ |$$$$$$$$ |\$$$$$$\ $$$$$$$$ |
|
|
// $$ __$$ |$$ __$$ | \____$$\ $$ __$$ |
|
|
// $$ | $$ |$$ | $$ |$$\ $$ |$$ | $$ |
|
|
// $$ | $$ |$$ | $$ |\$$$$$$ |$$ | $$ |
|
|
// \__| \__|\__| \__| \______/ \__| \__|
|
|
//
|
|
// dn_hash.h -- Hashing functions
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
*/
|
|
|
|
// NOTE: DN_FNV1A //////////////////////////////////////////////////////////////////////////////////
|
|
#if !defined(DN_FNV1A32_SEED)
|
|
#define DN_FNV1A32_SEED 2166136261U
|
|
#endif
|
|
|
|
#if !defined(DN_FNV1A64_SEED)
|
|
#define DN_FNV1A64_SEED 14695981039346656037ULL
|
|
#endif
|
|
|
|
// NOTE: DN_MurmurHash3 ////////////////////////////////////////////////////////////////////////////
|
|
struct DN_MurmurHash3 { uint64_t e[2]; };
|
|
|
|
// NOTE: DN_FNV1A //////////////////////////////////////////////////////////////////////////////////
|
|
DN_API uint32_t DN_FNV1A32_Hash (void const *bytes, DN_USize size);
|
|
DN_API uint64_t DN_FNV1A64_Hash (void const *bytes, DN_USize size);
|
|
DN_API uint32_t DN_FNV1A32_Iterate (void const *bytes, DN_USize size, uint32_t hash);
|
|
DN_API uint64_t DN_FNV1A64_Iterate (void const *bytes, DN_USize size, uint64_t hash);
|
|
|
|
// NOTE: DN_MurmurHash3 ////////////////////////////////////////////////////////////////////////////
|
|
DN_API uint32_t DN_MurmurHash3_x86U32 (void const *key, int len, uint32_t seed);
|
|
DN_API DN_MurmurHash3 DN_MurmurHash3_x64U128 (void const *key, int len, uint32_t seed);
|
|
#define DN_MurmurHash3_x64U128AsU64(key, len, seed) (DN_MurmurHash3_x64U128(key, len, seed).e[0])
|
|
#define DN_MurmurHash3_x64U128AsU32(key, len, seed) (DN_CAST(uint32_t)DN_MurmurHash3_x64U128(key, len, seed).e[0])
|
|
|
|
#endif // !defined(DN_HASH_H)
|
|
#if !defined(DN_HELPERS_H)
|
|
#define DN_HELPERS_H
|
|
|
|
#if !defined(DN_BASE_H)
|
|
#error dn_base_inc.h must be included before this
|
|
#endif
|
|
|
|
#if !defined(DN_MATH_H)
|
|
#error dn_math.h must be included before this
|
|
#endif
|
|
|
|
/*
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// $$\ $$\ $$$$$$$$\ $$\ $$$$$$$\ $$$$$$$$\ $$$$$$$\ $$$$$$\
|
|
// $$ | $$ |$$ _____|$$ | $$ __$$\ $$ _____|$$ __$$\ $$ __$$\
|
|
// $$ | $$ |$$ | $$ | $$ | $$ |$$ | $$ | $$ |$$ / \__|
|
|
// $$$$$$$$ |$$$$$\ $$ | $$$$$$$ |$$$$$\ $$$$$$$ |\$$$$$$\
|
|
// $$ __$$ |$$ __| $$ | $$ ____/ $$ __| $$ __$$< \____$$\
|
|
// $$ | $$ |$$ | $$ | $$ | $$ | $$ | $$ |$$\ $$ |
|
|
// $$ | $$ |$$$$$$$$\ $$$$$$$$\ $$ | $$$$$$$$\ $$ | $$ |\$$$$$$ |
|
|
// \__| \__|\________|\________|\__| \________|\__| \__| \______/
|
|
//
|
|
// dn_helpers.h -- Helper functions/data structures
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
*/
|
|
|
|
// NOTE: DN_PCG32 //////////////////////////////////////////////////////////////////////////////////
|
|
struct DN_PCG32 { uint64_t state; };
|
|
|
|
#if !defined(DN_NO_JSON_BUILDER)
|
|
// NOTE: DN_JSONBuilder ////////////////////////////////////////////////////////////////////////////
|
|
enum DN_JSONBuilderItem
|
|
{
|
|
DN_JSONBuilderItem_Empty,
|
|
DN_JSONBuilderItem_OpenContainer,
|
|
DN_JSONBuilderItem_CloseContainer,
|
|
DN_JSONBuilderItem_KeyValue,
|
|
};
|
|
|
|
struct DN_JSONBuilder
|
|
{
|
|
bool use_stdout; // When set, ignore the string builder and dump immediately to stdout
|
|
DN_Str8Builder string_builder; // (Internal)
|
|
int indent_level; // (Internal)
|
|
int spaces_per_indent; // The number of spaces per indent level
|
|
DN_JSONBuilderItem last_item;
|
|
};
|
|
#endif // !defined(DN_NO_JSON_BUIDLER)
|
|
|
|
// NOTE: DN_BinarySearch ///////////////////////////////////////////////////////////////////////////
|
|
template <typename T>
|
|
using DN_BinarySearchLessThanProc = bool(T const &lhs, T const &rhs);
|
|
|
|
template <typename T>
|
|
bool DN_BinarySearch_DefaultLessThan(T const &lhs, T const &rhs);
|
|
|
|
enum DN_BinarySearchType
|
|
{
|
|
// Index of the match. If no match is found, found is set to false and the
|
|
// index is set to the index where the match should be inserted/exist, if
|
|
// it were in the array
|
|
DN_BinarySearchType_Match,
|
|
|
|
// Index of the first element in the array that is `element >= find`. If no such
|
|
// item is found or the array is empty, then, the index is set to the array
|
|
// size and found is set to `false`.
|
|
//
|
|
// For example:
|
|
// int array[] = {0, 1, 2, 3, 4, 5};
|
|
// DN_BinarySearchResult result = DN_BinarySearch(array, DN_ArrayCountU(array), 4, DN_BinarySearchType_LowerBound);
|
|
// printf("%zu\n", result.index); // Prints index '4'
|
|
|
|
DN_BinarySearchType_LowerBound,
|
|
|
|
// Index of the first element in the array that is `element > find`. If no such
|
|
// item is found or the array is empty, then, the index is set to the array
|
|
// size and found is set to `false`.
|
|
//
|
|
// For example:
|
|
// int array[] = {0, 1, 2, 3, 4, 5};
|
|
// DN_BinarySearchResult result = DN_BinarySearch(array, DN_ArrayCountU(array), 4, DN_BinarySearchType_UpperBound);
|
|
// printf("%zu\n", result.index); // Prints index '5'
|
|
|
|
DN_BinarySearchType_UpperBound,
|
|
};
|
|
|
|
struct DN_BinarySearchResult
|
|
{
|
|
bool found;
|
|
DN_USize index;
|
|
};
|
|
|
|
template <typename T>
|
|
using DN_QSortLessThanProc = bool(T const &a, T const &b, void *user_context);
|
|
|
|
// NOTE: Misc //////////////////////////////////////////////////////////////////////////////////////
|
|
// NOTE: DN_JobQueue ///////////////////////////////////////////////////////////////////////////////
|
|
typedef void(DN_JobQueueFunc)(DN_OSThread *thread, void *user_context);
|
|
struct DN_Job
|
|
{
|
|
DN_JobQueueFunc *func; // The function to invoke for the job
|
|
void *user_context; // Pointer user can set to use in their `job_func`
|
|
uint64_t elapsed_tsc;
|
|
uint16_t user_tag; // Arbitrary value the user can set to identiy the type of `user_context` this job has
|
|
bool add_to_completion_queue; // When true, on job completion, job must be dequeued from the completion queue via `GetFinishedJobs`
|
|
};
|
|
|
|
#if !defined(DN_JOB_QUEUE_SPMC_SIZE)
|
|
#define DN_JOB_QUEUE_SPMC_SIZE 128
|
|
#endif
|
|
|
|
struct DN_JobQueueSPMC
|
|
{
|
|
DN_OSMutex mutex;
|
|
DN_OSSemaphore thread_wait_for_job_semaphore;
|
|
DN_OSSemaphore wait_for_completion_semaphore;
|
|
DN_U32 threads_waiting_for_completion;
|
|
|
|
DN_Job jobs[DN_JOB_QUEUE_SPMC_SIZE];
|
|
DN_B32 quit;
|
|
DN_U32 quit_exit_code;
|
|
DN_U32 volatile read_index;
|
|
DN_U32 volatile finish_index;
|
|
DN_U32 volatile write_index;
|
|
|
|
DN_OSSemaphore complete_queue_write_semaphore;
|
|
DN_Job complete_queue[DN_JOB_QUEUE_SPMC_SIZE];
|
|
DN_U32 volatile complete_read_index;
|
|
DN_U32 volatile complete_write_index;
|
|
};
|
|
|
|
// NOTE: DN_PCG32 //////////////////////////////////////////////////////////////////////////////////
|
|
DN_API DN_PCG32 DN_PCG32_Init (uint64_t seed);
|
|
DN_API uint32_t DN_PCG32_Next (DN_PCG32 *rng);
|
|
DN_API uint64_t DN_PCG32_Next64 (DN_PCG32 *rng);
|
|
DN_API uint32_t DN_PCG32_Range (DN_PCG32 *rng, uint32_t low, uint32_t high);
|
|
DN_API DN_F32 DN_PCG32_NextF32 (DN_PCG32 *rng);
|
|
DN_API DN_F64 DN_PCG32_NextF64 (DN_PCG32 *rng);
|
|
DN_API void DN_PCG32_Advance (DN_PCG32 *rng, uint64_t delta);
|
|
|
|
#if !defined(DN_NO_JSON_BUILDER)
|
|
// NOTE: DN_JSONBuilder ////////////////////////////////////////////////////////////////////////////
|
|
#define DN_JSONBuilder_Object(builder) \
|
|
DN_DeferLoop(DN_JSONBuilder_ObjectBegin(builder), \
|
|
DN_JSONBuilder_ObjectEnd(builder))
|
|
|
|
#define DN_JSONBuilder_ObjectNamed(builder, name) \
|
|
DN_DeferLoop(DN_JSONBuilder_ObjectBeginNamed(builder, name), \
|
|
DN_JSONBuilder_ObjectEnd(builder))
|
|
|
|
#define DN_JSONBuilder_Array(builder) \
|
|
DN_DeferLoop(DN_JSONBuilder_ArrayBegin(builder), \
|
|
DN_JSONBuilder_ArrayEnd(builder))
|
|
|
|
#define DN_JSONBuilder_ArrayNamed(builder, name) \
|
|
DN_DeferLoop(DN_JSONBuilder_ArrayBeginNamed(builder, name), \
|
|
DN_JSONBuilder_ArrayEnd(builder))
|
|
|
|
DN_API DN_JSONBuilder DN_JSONBuilder_Init (DN_Arena *arena, int spaces_per_indent);
|
|
DN_API DN_Str8 DN_JSONBuilder_Build (DN_JSONBuilder const *builder, DN_Arena *arena);
|
|
DN_API void DN_JSONBuilder_KeyValue (DN_JSONBuilder *builder, DN_Str8 key, DN_Str8 value);
|
|
DN_API void DN_JSONBuilder_KeyValueF (DN_JSONBuilder *builder, DN_Str8 key, char const *value_fmt, ...);
|
|
DN_API void DN_JSONBuilder_ObjectBeginNamed (DN_JSONBuilder *builder, DN_Str8 name);
|
|
DN_API void DN_JSONBuilder_ObjectEnd (DN_JSONBuilder *builder);
|
|
DN_API void DN_JSONBuilder_ArrayBeginNamed (DN_JSONBuilder *builder, DN_Str8 name);
|
|
DN_API void DN_JSONBuilder_ArrayEnd (DN_JSONBuilder *builder);
|
|
DN_API void DN_JSONBuilder_Str8Named (DN_JSONBuilder *builder, DN_Str8 key, DN_Str8 value);
|
|
DN_API void DN_JSONBuilder_LiteralNamed (DN_JSONBuilder *builder, DN_Str8 key, DN_Str8 value);
|
|
DN_API void DN_JSONBuilder_U64Named (DN_JSONBuilder *builder, DN_Str8 key, uint64_t value);
|
|
DN_API void DN_JSONBuilder_I64Named (DN_JSONBuilder *builder, DN_Str8 key, int64_t value);
|
|
DN_API void DN_JSONBuilder_F64Named (DN_JSONBuilder *builder, DN_Str8 key, double value, int decimal_places);
|
|
DN_API void DN_JSONBuilder_BoolNamed (DN_JSONBuilder *builder, DN_Str8 key, bool value);
|
|
|
|
#define DN_JSONBuilder_ObjectBegin(builder) DN_JSONBuilder_ObjectBeginNamed(builder, DN_STR8(""))
|
|
#define DN_JSONBuilder_ArrayBegin(builder) DN_JSONBuilder_ArrayBeginNamed(builder, DN_STR8(""))
|
|
#define DN_JSONBuilder_Str8(builder, value) DN_JSONBuilder_Str8Named(builder, DN_STR8(""), value)
|
|
#define DN_JSONBuilder_Literal(builder, value) DN_JSONBuilder_LiteralNamed(builder, DN_STR8(""), value)
|
|
#define DN_JSONBuilder_U64(builder, value) DN_JSONBuilder_U64Named(builder, DN_STR8(""), value)
|
|
#define DN_JSONBuilder_I64(builder, value) DN_JSONBuilder_I64Named(builder, DN_STR8(""), value)
|
|
#define DN_JSONBuilder_F64(builder, value) DN_JSONBuilder_F64Named(builder, DN_STR8(""), value)
|
|
#define DN_JSONBuilder_Bool(builder, value) DN_JSONBuilder_BoolNamed(builder, DN_STR8(""), value)
|
|
#endif // !defined(DN_NO_JSON_BUILDER)
|
|
|
|
// NOTE: DN_BinarySearch ///////////////////////////////////////////////////////////////////////////
|
|
template <typename T> bool DN_BinarySearch_DefaultLessThan(T const &lhs, T const &rhs);
|
|
template <typename T> DN_BinarySearchResult DN_BinarySearch (T const *array,
|
|
DN_USize array_size,
|
|
T const &find,
|
|
DN_BinarySearchType type = DN_BinarySearchType_Match,
|
|
DN_BinarySearchLessThanProc<T> less_than = DN_BinarySearch_DefaultLessThan);
|
|
|
|
// NOTE: DN_QSort //////////////////////////////////////////////////////////////////////////////////
|
|
template <typename T> bool DN_QSort_DefaultLessThan(T const &lhs, T const &rhs);
|
|
template <typename T> void DN_QSort (T *array,
|
|
DN_USize array_size,
|
|
void *user_context,
|
|
DN_QSortLessThanProc<T> less_than = DN_QSort_DefaultLessThan);
|
|
|
|
// NOTE: DN_JobQueue ///////////////////////////////////////////////////////////////////////////////
|
|
DN_API DN_JobQueueSPMC DN_OS_JobQueueSPMCInit ();
|
|
DN_API bool DN_OS_JobQueueSPMCCanAdd (DN_JobQueueSPMC const *queue, uint32_t count);
|
|
DN_API bool DN_OS_JobQueueSPMCAddArray (DN_JobQueueSPMC *queue, DN_Job *jobs, uint32_t count);
|
|
DN_API bool DN_OS_JobQueueSPMCAdd (DN_JobQueueSPMC *queue, DN_Job job);
|
|
DN_API void DN_OS_JobQueueSPMCWaitForCompletion (DN_JobQueueSPMC *queue);
|
|
DN_API int32_t DN_OS_JobQueueSPMCThread (DN_OSThread *thread);
|
|
DN_API DN_USize DN_OS_JobQueueSPMCGetFinishedJobs (DN_JobQueueSPMC *queue, DN_Job *jobs, DN_USize jobs_size);
|
|
|
|
// NOTE: DN_BinarySearch ///////////////////////////////////////////////////////////////////////////
|
|
template <typename T>
|
|
bool DN_BinarySearch_DefaultLessThan(T const &lhs, T const &rhs)
|
|
{
|
|
bool result = lhs < rhs;
|
|
return result;
|
|
}
|
|
|
|
template <typename T>
|
|
DN_BinarySearchResult DN_BinarySearch(T const *array,
|
|
DN_USize array_size,
|
|
T const &find,
|
|
DN_BinarySearchType type,
|
|
DN_BinarySearchLessThanProc<T> less_than)
|
|
{
|
|
DN_BinarySearchResult result = {};
|
|
if (!array || array_size <= 0 || !less_than)
|
|
return result;
|
|
|
|
T const *end = array + array_size;
|
|
T const *first = array;
|
|
T const *last = end;
|
|
while (first != last) {
|
|
DN_USize count = last - first;
|
|
T const *it = first + (count / 2);
|
|
|
|
bool advance_first = false;
|
|
if (type == DN_BinarySearchType_UpperBound)
|
|
advance_first = !less_than(find, it[0]);
|
|
else
|
|
advance_first = less_than(it[0], find);
|
|
|
|
if (advance_first)
|
|
first = it + 1;
|
|
else
|
|
last = it;
|
|
}
|
|
|
|
switch (type) {
|
|
case DN_BinarySearchType_Match: {
|
|
result.found = first != end && !less_than(find, *first);
|
|
} break;
|
|
|
|
case DN_BinarySearchType_LowerBound: /*FALLTHRU*/
|
|
case DN_BinarySearchType_UpperBound: {
|
|
result.found = first != end;
|
|
} break;
|
|
}
|
|
|
|
result.index = first - array;
|
|
return result;
|
|
}
|
|
|
|
// NOTE: DN_QSort //////////////////////////////////////////////////////////////////////////////////
|
|
template <typename T>
|
|
bool DN_QSort_DefaultLessThan(T const &lhs, T const &rhs, void *user_context)
|
|
{
|
|
(void)user_context;
|
|
bool result = lhs < rhs;
|
|
return result;
|
|
}
|
|
|
|
template <typename T>
|
|
void DN_QSort(T *array, DN_USize array_size, void *user_context, DN_QSortLessThanProc<T> less_than)
|
|
{
|
|
if (!array || array_size <= 1 || !less_than)
|
|
return;
|
|
|
|
// NOTE: Insertion Sort, under 24->32 is an optimal amount /////////////////////////////////////
|
|
const DN_USize QSORT_THRESHOLD = 24;
|
|
if (array_size < QSORT_THRESHOLD) {
|
|
for (DN_USize item_to_insert_index = 1; item_to_insert_index < array_size; item_to_insert_index++) {
|
|
for (DN_USize index = 0; index < item_to_insert_index; index++) {
|
|
if (!less_than(array[index], array[item_to_insert_index], user_context)) {
|
|
T item_to_insert = array[item_to_insert_index];
|
|
for (DN_USize i = item_to_insert_index; i > index; i--)
|
|
array[i] = array[i - 1];
|
|
|
|
array[index] = item_to_insert;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
return;
|
|
}
|
|
|
|
// NOTE: Quick sort, under 24->32 is an optimal amount /////////////////////////////////////////
|
|
DN_USize last_index = array_size - 1;
|
|
DN_USize pivot_index = array_size / 2;
|
|
DN_USize partition_index = 0;
|
|
DN_USize start_index = 0;
|
|
|
|
// Swap pivot with last index, so pivot is always at the end of the array.
|
|
// This makes logic much simpler.
|
|
DN_Swap(array[last_index], array[pivot_index]);
|
|
pivot_index = last_index;
|
|
|
|
// 4^, 8, 7, 5, 2, 3, 6
|
|
if (less_than(array[start_index], array[pivot_index], user_context))
|
|
partition_index++;
|
|
start_index++;
|
|
|
|
// 4, |8, 7, 5^, 2, 3, 6*
|
|
// 4, 5, |7, 8, 2^, 3, 6*
|
|
// 4, 5, 2, |8, 7, ^3, 6*
|
|
// 4, 5, 2, 3, |7, 8, ^6*
|
|
for (DN_USize index = start_index; index < last_index; index++) {
|
|
if (less_than(array[index], array[pivot_index], user_context)) {
|
|
DN_Swap(array[partition_index], array[index]);
|
|
partition_index++;
|
|
}
|
|
}
|
|
|
|
// Move pivot to right of partition
|
|
// 4, 5, 2, 3, |6, 8, ^7*
|
|
DN_Swap(array[partition_index], array[pivot_index]);
|
|
DN_QSort(array, partition_index, user_context, less_than);
|
|
|
|
// Skip the value at partion index since that is guaranteed to be sorted.
|
|
// 4, 5, 2, 3, (x), 8, 7
|
|
DN_USize one_after_partition_index = partition_index + 1;
|
|
DN_QSort(array + one_after_partition_index, (array_size - one_after_partition_index), user_context, less_than);
|
|
}
|
|
|
|
#endif // !defined(DN_HELPERS_H)
|