1892 lines
50 KiB
C
1892 lines
50 KiB
C
/*
|
|
**
|
|
** TODO: instructions will go here
|
|
**
|
|
*/
|
|
|
|
#if !defined(MR4TH_BASE_H)
|
|
#define MR4TH_BASE_H 1
|
|
|
|
////////////////////////////////////////////////
|
|
////////////////////////////////////////////////
|
|
////////////////// MACROS //////////////////
|
|
////////////////////////////////////////////////
|
|
////////////////////////////////////////////////
|
|
|
|
////////////////////////////////
|
|
// Build Mode Defaults & Checks
|
|
|
|
#if !defined(MR4TH_DISABLE_UNITY_BUILD)
|
|
# define MR4TH_DISABLE_UNITY_BUILD 0
|
|
#endif
|
|
#if !defined(MR4TH_CORE_MODE)
|
|
# define MR4TH_CORE_MODE 0
|
|
#endif
|
|
#if !defined(MR4TH_PLUGIN_MODE)
|
|
# define MR4TH_PLUGIN_MODE 0
|
|
#endif
|
|
#if !defined(MR4TH_STANDALONE_MODE)
|
|
# define MR4TH_STANDALONE_MODE 0
|
|
#endif
|
|
#if !defined(MR4TH_PROFILING_PROVIDER)
|
|
# define MR4TH_PROFILING_PROVIDER 0
|
|
#endif
|
|
|
|
#if !MR4TH_CORE_MODE && !MR4TH_PLUGIN_MODE && !MR4TH_STANDALONE_MODE
|
|
# undef MR4TH_STANDALONE_MODE
|
|
# define MR4TH_STANDALONE_MODE 1
|
|
#endif
|
|
|
|
#if (MR4TH_CORE_MODE && MR4TH_PLUGIN_MODE)
|
|
# error conflicing mr4th build mode
|
|
#endif
|
|
#if (MR4TH_CORE_MODE && MR4TH_STANDALONE_MODE)
|
|
# error conflicing mr4th build mode
|
|
#endif
|
|
#if (MR4TH_PLUGIN_MODE && MR4TH_STANDALONE_MODE)
|
|
# error conflicing mr4th build mode
|
|
#endif
|
|
|
|
////////////////////////////////
|
|
// Context Cracking
|
|
|
|
// development settings
|
|
#if !defined(MR4TH_ASSERTS)
|
|
# define MR4TH_ASSERTS 0
|
|
#endif
|
|
#if !defined(MR4TH_SANITIZER)
|
|
# define MR4TH_SANITIZER 0
|
|
#endif
|
|
#if !defined(MR4TH_PROFILING_MANUAL)
|
|
# define MR4TH_PROFILING_MANUAL 0
|
|
#endif
|
|
#if !defined(MR4TH_PROFILING_AUTO)
|
|
# define MR4TH_PROFILING_AUTO 0
|
|
#endif
|
|
|
|
#if defined(MR4TH_PROFILING_USER)
|
|
# error the user should not set MR4TH_PROFILING_USER, instead set MR4TH_PROFILING_MANUAL or MR4TH_PROFILING_AUTO
|
|
#endif
|
|
|
|
#if MR4TH_PROFILING_MANUAL || MR4TH_PROFILING_AUTO
|
|
# define MR4TH_PROFILING_USER 1
|
|
#else
|
|
# define MR4TH_PROFILING_USER 0
|
|
#endif
|
|
|
|
// untangle compiler, os, & architecture
|
|
#if defined(__clang__)
|
|
# define COMPILER_CLANG 1
|
|
|
|
# if defined(_WIN32)
|
|
# define OS_WINDOWS 1
|
|
# elif defined(__gnu_linux__)
|
|
# define OS_LINUX 1
|
|
# elif defined(__APPLE__) && defined(__MACH__)
|
|
# define OS_MAC 1
|
|
# else
|
|
# error missing OS detection
|
|
# endif
|
|
|
|
# if defined(__amd64__)
|
|
# define ARCH_X64 1
|
|
// TODO(allen): verify this works on clang
|
|
# elif defined(__i386__)
|
|
# define ARCH_X86 1
|
|
// TODO(allen): verify this works on clang
|
|
# elif defined(__arm__)
|
|
# define ARCH_ARM 1
|
|
// TODO(allen): verify this works on clang
|
|
# elif defined(__aarch64__)
|
|
# define ARCH_ARM64 1
|
|
# else
|
|
# error missing ARCH detection
|
|
# endif
|
|
|
|
#elif defined(_MSC_VER)
|
|
# define COMPILER_CL 1
|
|
|
|
# if defined(_WIN32)
|
|
# define OS_WINDOWS 1
|
|
# else
|
|
# error missing OS detection
|
|
# endif
|
|
|
|
# if defined(_M_AMD64)
|
|
# define ARCH_X64 1
|
|
# elif defined(_M_I86)
|
|
# define ARCH_X86 1
|
|
# elif defined(_M_ARM)
|
|
# define ARCH_ARM 1
|
|
// TODO(allen): ARM64?
|
|
# else
|
|
# error missing ARCH detection
|
|
# endif
|
|
|
|
#elif defined(__GNUC__)
|
|
# define COMPILER_GCC 1
|
|
|
|
# if defined(_WIN32)
|
|
# define OS_WINDOWS 1
|
|
# elif defined(__gnu_linux__)
|
|
# define OS_LINUX 1
|
|
# elif defined(__APPLE__) && defined(__MACH__)
|
|
# define OS_MAC 1
|
|
# else
|
|
# error missing OS detection
|
|
# endif
|
|
|
|
# if defined(__amd64__)
|
|
# define ARCH_X64 1
|
|
# elif defined(__i386__)
|
|
# define ARCH_X86 1
|
|
# elif defined(__arm__)
|
|
# define ARCH_ARM 1
|
|
# elif defined(__aarch64__)
|
|
# define ARCH_ARM64 1
|
|
# else
|
|
# error missing ARCH detection
|
|
# endif
|
|
|
|
#else
|
|
# error no context cracking for this compiler
|
|
#endif
|
|
|
|
#if !defined(COMPILER_CL)
|
|
# define COMPILER_CL 0
|
|
#endif
|
|
#if !defined(COMPILER_CLANG)
|
|
# define COMPILER_CLANG 0
|
|
#endif
|
|
#if !defined(COMPILER_GCC)
|
|
# define COMPILER_GCC 0
|
|
#endif
|
|
#if !defined(OS_WINDOWS)
|
|
# define OS_WINDOWS 0
|
|
#endif
|
|
#if !defined(OS_LINUX)
|
|
# define OS_LINUX 0
|
|
#endif
|
|
#if !defined(OS_MAC)
|
|
# define OS_MAC 0
|
|
#endif
|
|
#if !defined(ARCH_X64)
|
|
# define ARCH_X64 0
|
|
#endif
|
|
#if !defined(ARCH_X86)
|
|
# define ARCH_X86 0
|
|
#endif
|
|
#if !defined(ARCH_ARM)
|
|
# define ARCH_ARM 0
|
|
#endif
|
|
#if !defined(ARCH_ARM64)
|
|
# define ARCH_ARM64 0
|
|
#endif
|
|
|
|
|
|
// language
|
|
#if defined(__cplusplus)
|
|
# define LANG_CXX 1
|
|
#else
|
|
# define LANG_C 1
|
|
#endif
|
|
|
|
#if !defined(LANG_CXX)
|
|
# define LANG_CXX 0
|
|
#endif
|
|
#if !defined(LANG_C)
|
|
# define LANG_C 0
|
|
#endif
|
|
|
|
|
|
// language version: C
|
|
#if LANG_C
|
|
# if !defined(__STDC_VERSION__)
|
|
# define LANGVER_C90 1
|
|
# elif (__STDC_VERSION__ == 199901)
|
|
# define LANGVER_C99 1
|
|
# elif (__STDC_VERSION__ == 201112)
|
|
# define LANGVER_C11 1
|
|
# elif (__STDC_VERSION__ == 201710)
|
|
# define LANGVER_C17 1
|
|
# elif (__STDC_VERSION__ == 202000)
|
|
# define LANGVER_C23 1
|
|
# else
|
|
# error unrecorgnized C version
|
|
# endif
|
|
#endif
|
|
|
|
#if !defined(LANGVER_C90)
|
|
# define LANGVER_C90 0
|
|
#endif
|
|
#if !defined(LANGVER_C99)
|
|
# define LANGVER_C99 0
|
|
#endif
|
|
#if !defined(LANGVER_C11)
|
|
# define LANGVER_C11 0
|
|
#endif
|
|
#if !defined(LANGVER_C17)
|
|
# define LANGVER_C17 0
|
|
#endif
|
|
#if !defined(LANGVER_C23)
|
|
# define LANGVER_C23 0
|
|
#endif
|
|
|
|
|
|
// language version: C++
|
|
#if LANG_CXX
|
|
# if (__cplusplus == 199711)
|
|
# define LANGVER_CXX98 1
|
|
# elif (__cplusplus == 201103)
|
|
# define LANGVER_CXX11 1
|
|
# elif (__cplusplus == 201402)
|
|
# define LANGVER_CXX14 1
|
|
# elif (__cplusplus == 201703)
|
|
# define LANGVER_CXX17 1
|
|
# elif (__cplusplus == 202002)
|
|
# define LANGVER_CXX20 1
|
|
# elif (__cplusplus == 202302)
|
|
# define LANGVER_CXX23 1
|
|
# else
|
|
# error unrecorgnized C++ version
|
|
# endif
|
|
#endif
|
|
|
|
#if !defined(LANGVER_CXX98)
|
|
# define LANGVER_CXX98 0
|
|
#endif
|
|
#if !defined(LANGVER_CXX11)
|
|
# define LANGVER_CXX11 0
|
|
#endif
|
|
#if !defined(LANGVER_CXX14)
|
|
# define LANGVER_CXX14 0
|
|
#endif
|
|
#if !defined(LANGVER_CXX17)
|
|
# define LANGVER_CXX17 0
|
|
#endif
|
|
#if !defined(LANGVER_CXX20)
|
|
# define LANGVER_CXX20 0
|
|
#endif
|
|
#if !defined(LANGVER_CXX23)
|
|
# define LANGVER_CXX23 0
|
|
#endif
|
|
|
|
// determine intrinsics mode
|
|
#if OS_WINDOWS
|
|
# if COMPILER_CL || COMPILER_CLANG
|
|
# define INTRINSICS_MICROSOFT 1
|
|
# endif
|
|
#endif
|
|
#if OS_LINUX
|
|
# if COMPILER_CLANG || COMPILER_GCC
|
|
# define INTRINSICS_BUILT_IN 1
|
|
# endif
|
|
#endif
|
|
|
|
#if !defined(INTRINSICS_MICROSOFT)
|
|
# define INTRINSICS_MICROSOFT 0
|
|
#endif
|
|
#if !defined(INTRINSICS_BUILT_IN)
|
|
# define INTRINSICS_BUILT_IN 0
|
|
#endif
|
|
|
|
// setup pointer size macro
|
|
#if ARCH_X64 || ARCH_ARM64
|
|
# define ARCH_ADDRSIZE 64
|
|
#else
|
|
# define ARCH_ADDRSIZE 32
|
|
#endif
|
|
|
|
|
|
#define ARCH_LITTLE_ENDIAN 1
|
|
#define ARCH_BIG_ENDIAN 0
|
|
|
|
// TODO(allen): target image format
|
|
|
|
////////////////////////////////
|
|
// Macros: Symbol Markers
|
|
|
|
// linkage, storage, & other "attribute" like things
|
|
|
|
#define MR4TH_SYMBOL_STATIC static
|
|
|
|
#if LANG_CXX
|
|
# define MR4TH_SYMBOL_LINK extern "C"
|
|
#else
|
|
# define MR4TH_SYMBOL_LINK extern
|
|
#endif
|
|
|
|
#if OS_WINDOWS
|
|
# define MR4TH_SYMBOL_EXPORT __declspec(dllexport)
|
|
#elif OS_LINUX || OS_MAC
|
|
# define MR4TH_SYMBOL_EXPORT __attribute__((visibility("default")))
|
|
#else
|
|
# error MR4TH_SYMBOL_EXPORT not defined for this OS
|
|
#endif
|
|
|
|
#if OS_WINDOWS
|
|
# define MR4TH_SYM_IMPORT __declspec(dllimport)
|
|
#elif OS_LINUX || OS_MAC
|
|
# define MR4TH_SYM_IMPORT
|
|
#else
|
|
# error MR4TH_SYMBOL_IMPORT not defined for this OS
|
|
#endif
|
|
|
|
#if COMPILER_CL
|
|
# define MR4TH_THREADVAR __declspec(thread)
|
|
#elif COMPILER_CLANG || COMPILER_GCC
|
|
# define MR4TH_THREADVAR __thread
|
|
#else
|
|
# error MR4TH_THREADVAR not defined for this compiler
|
|
#endif
|
|
|
|
#if COMPILER_CLANG || COMPILER_GCC
|
|
# if OS_MAC
|
|
# define MR4TH_SEC_R(N) __attribute__((__section__("__TEXT,"N)))
|
|
# define MR4TH_SEC_RW(N) __attribute__((__section__("__READ,"N)))
|
|
# else
|
|
# define MR4TH_SEC_R(N) __attribute__((__section__(N)))
|
|
# define MR4TH_SEC_RW(N) __attribute__((__section__(N)))
|
|
# endif
|
|
#elif COMPILER_CL
|
|
# define MR4TH_SEC_R(N) __declspec(allocate(N))
|
|
# define MR4TH_SEC_RW(N) __declspec(allocate(N))
|
|
#else
|
|
# error MR4TH_SEC_R/MR4TH_SEC_RW not defined for this compiler/OS
|
|
#endif
|
|
|
|
#if COMPILER_CLANG || COMPILER_GCC
|
|
#if OS_WINDOWS
|
|
# define MR4TH_READ_ONLY MR4TH_SEC_R(".rdata") const
|
|
#else
|
|
# define MR4TH_READ_ONLY MR4TH_SEC_R(".rodata") const
|
|
#endif
|
|
#elif COMPILER_CL
|
|
# pragma section(".m4rdata",read)
|
|
# define MR4TH_READ_ONLY MR4TH_SEC_R(".m4rdata") const
|
|
#else
|
|
# define MR4TH_READ_ONLY
|
|
# error MR4TH_READ_ONLY not defined for this compiler
|
|
#endif
|
|
|
|
// symbol kinds
|
|
|
|
#if MR4TH_DISABLE_UNITY_BUILD
|
|
# define MR4TH_SYMBOL MR4TH_SYMBOL_LINK
|
|
#else
|
|
# define MR4TH_SYMBOL MR4TH_SYMBOL_STATIC
|
|
#endif
|
|
|
|
#if MR4TH_CORE_MODE
|
|
# define MR4TH_SYMBOL_MUST_SHARE MR4TH_SYMBOL_EXPORT
|
|
#elif MR4TH_PLUGIN_MODE
|
|
# define MR4TH_SYMBOL_MUST_SHARE MR4TH_SYMBOL_IMPORT
|
|
#else
|
|
# define MR4TH_SYMBOL_MUST_SHARE MR4TH_SYMBOL
|
|
#endif
|
|
|
|
// align-as
|
|
|
|
#if COMPILER_CL
|
|
# define MR4TH_ALIGN_AS_LIT(n) __declspec(align(n))
|
|
#elif COMPILER_CLANG || COMPILER_GCC
|
|
# define MR4TH_ALIGN_AS_LIT(n) __attribute__(( __aligned__(n) ))
|
|
#else
|
|
# error MR4TH_ALIGN_AS_LIT not defined for this compiler
|
|
#endif
|
|
|
|
// do-not-eliminate
|
|
|
|
#if OS_WINDOWS
|
|
|
|
# define MR4TH_DO_NOT_ELIMINATE__S0(N) __pragma(comment(linker,"/include:" #N))
|
|
# define MR4TH_DO_NOT_ELIMINATE__S1(N) MR4TH_DO_NOT_ELIMINATE__S0(N)
|
|
# define MR4TH_DO_NOT_ELIMINATE(N) MR4TH_DO_NOT_ELIMINATE__S1(N)
|
|
|
|
#else
|
|
|
|
# define MR4TH_DO_NOT_ELIMINATE(N)
|
|
|
|
#endif
|
|
|
|
// before-main abstraction
|
|
|
|
#if OS_WINDOWS
|
|
|
|
# pragma section(".CRT$XCU", read)
|
|
|
|
# if LANG_CXX
|
|
|
|
# define MR4TH_BEFORE_MAIN_(n) \
|
|
static void n(void); \
|
|
__declspec(allocate(".CRT$XCU")) \
|
|
__pragma(comment(linker,"/include:" #n "__")) \
|
|
extern "C" void (*n##__)(void); \
|
|
void (*n##__)(void) = n; \
|
|
static void n(void)
|
|
|
|
# else
|
|
|
|
# define MR4TH_BEFORE_MAIN_(n) \
|
|
static void n(void); \
|
|
__declspec(allocate(".CRT$XCU")) \
|
|
__pragma(comment(linker,"/include:" #n "__")) \
|
|
void (*n##__)(void) = n; \
|
|
static void n(void)
|
|
|
|
# endif
|
|
|
|
# define MR4TH_BEFORE_MAIN(n) MR4TH_BEFORE_MAIN_(n)
|
|
|
|
#elif OS_LINUX
|
|
|
|
# define MR4TH_BEFORE_MAIN(n) \
|
|
__attribute__((constructor)) static void n(void)
|
|
|
|
#else
|
|
# error MR4TH_BEFORE_MAIN missing for this OS
|
|
#endif
|
|
|
|
// sanitizer
|
|
|
|
#if COMPILER_CLANG && MR4TH_SANITIZER
|
|
# include <sanitizer/asan_interface.h>
|
|
#endif
|
|
|
|
#if MR4TH_SANITIZER
|
|
# define AsanPoison(p,z) __asan_poison_memory_region((p),(z))
|
|
# define AsanUnpoison(p,z) __asan_unpoison_memory_region((p),(z))
|
|
#else
|
|
# define AsanPoison(p,z)
|
|
# define AsanUnpoison(p,z)
|
|
#endif
|
|
|
|
|
|
////////////////////////////////
|
|
// Macros: Common Expressions
|
|
|
|
// macro writing utilities
|
|
|
|
#define Stmnt(S) do{ S }while(0)
|
|
|
|
#define Stringify_(S) #S
|
|
#define Stringify(S) Stringify_(S)
|
|
#define Glue_(A,B) A##B
|
|
#define Glue(A,B) Glue_(A,B)
|
|
|
|
// assert
|
|
|
|
#if !defined(AssertBreak)
|
|
# define AssertBreak() (*(volatile int*)0 = 0)
|
|
#endif
|
|
|
|
#if MR4TH_ASSERTS
|
|
# define Assert(c) Stmnt( if (!(c)){ AssertBreak(); } )
|
|
#else
|
|
# define Assert(c)
|
|
#endif
|
|
|
|
#define StaticAssert(c,l) typedef U8 Glue(l,__LINE__) [(c)?1:-1]
|
|
|
|
// memory operations
|
|
|
|
#define MemoryZero(p,z) memory_zero((p), (z))
|
|
#define MemoryZeroStruct(p) MemoryZero((p), sizeof(*(p)))
|
|
#define MemoryZeroArray(p) MemoryZero((p), sizeof(p))
|
|
#define MemoryZeroRange(f,o) MemoryZero((f), (U8*)(o) - (U8*)(f))
|
|
|
|
#define MemoryMatch(a,b,z) (memory_match((a),(b),(z)))
|
|
|
|
#define MemoryCopy(d,s,z) memory_move((d), (s), (z))
|
|
#define MemoryCopyStruct(d,s) MemoryCopy((d),(s),Min(sizeof(*(d)),sizeof(*(s))))
|
|
#define MemoryCopyArray(d,s) MemoryCopy((d),(s),Min(sizeof(s),sizeof(d)))
|
|
|
|
// misc expressions
|
|
|
|
#define ArrayCount(a) (sizeof(a)/sizeof(*(a)))
|
|
|
|
#define IntFromPtr(p) (UAddr)(p)
|
|
#define PtrFromInt(n) (void*)((UAddr)(n))
|
|
#define PtrDif(a,b) ((U8*)(a) - (U8*)(b))
|
|
|
|
#define Member(T,m) (((T*)0)->m)
|
|
#define AddrOfMember(T,m) (void*)(&Member(T,m))
|
|
#define OffsetOfMember(T,m) IntFromPtr(&Member(T,m))
|
|
#define OffsetOfMemberV(s,m) PtrDif(&s->m, s)
|
|
#define MemberAddr(T,m) AddrOfMember(T,m)
|
|
#define MemberOff(T,m) OffsetOfMember(T,m)
|
|
|
|
#define Min(a,b) (((a)<(b))?(a):(b))
|
|
#define Max(a,b) (((a)>(b))?(a):(b))
|
|
#define Clamp(a,x,b) (((x)<(a))?(a):((b)<(x))?(b):(x))
|
|
#define ClampTop(a,b) Min(a,b)
|
|
#define ClampBot(a,b) Max(a,b)
|
|
|
|
#define Swap(T,a,b) Stmnt( T t_ = (a); (a) = (b); (b) = t_; )
|
|
|
|
#define SignedIntFromCompare(a,b) (S32)( ((b)<(a)) - ((a)<(b)) )
|
|
|
|
#define AlignUpPow2(x,p) (((x) + (p) - 1)&~((p) - 1))
|
|
#define AlignDownPow2(x,p) ((x)&~((p) - 1))
|
|
#define IsPow2OrZero(x) (((x)&((x)-1)) == 0)
|
|
|
|
#define CeilIntDiv(n,d) (((n) + (d) - 1)/(d))
|
|
|
|
#define KB(x) ((U64)(x) << 10llu)
|
|
#define MB(x) ((U64)(x) << 20llu)
|
|
#define GB(x) ((U64)(x) << 30llu)
|
|
#define TB(x) ((U64)(x) << 40llu)
|
|
|
|
#define Thousand(x) ((x)*1000llu)
|
|
#define Million(x) ((x)*1000000llu)
|
|
#define Billion(x) ((x)*1000000000llu)
|
|
#define Trillion(x) ((x)*1000000000000llu)
|
|
|
|
#define AsciiID4(a,b,c,d) (((d) << 24) | ((c) << 16) | ((b) << 8) | (a))
|
|
|
|
#if LANG_CXX
|
|
# define CLiteral(T) T
|
|
#else
|
|
# define CLiteral(T) (T)
|
|
#endif
|
|
|
|
////////////////////////////////
|
|
// Macros: Linked Lists
|
|
|
|
#define DLLPushBack_NPZ(f,l,n,next,prev,nil)\
|
|
(((f) == (nil))?\
|
|
((f)=(l)=(n),(n)->next=(n)->prev=(nil)):\
|
|
((n)->prev=(l),(l)->next=(n),(l)=(n),(n)->next=(nil)))
|
|
|
|
#define DLLPushBack(f,l,n) DLLPushBack_NPZ(f,l,n,next,prev,0)
|
|
#define DLLPushFront(f,l,n) DLLPushBack_NPZ(l,f,n,prev,next,0)
|
|
|
|
#define DLLInsert_NPZ(f,l,p,n,next,prev,nil) \
|
|
(((p) != (l))?\
|
|
((n)->next = (p)->next,\
|
|
(n)->prev = (p),\
|
|
(p)->next->prev = (n),\
|
|
(p)->next = (n))\
|
|
:((n)->next = (nil),\
|
|
(n)->prev = (l),\
|
|
(l)->next = (n),\
|
|
(l) = (n)))
|
|
|
|
#define DLLInsert(f,l,p,n) DLLInsert_NPZ(f,l,p,n,next,prev,0)
|
|
|
|
#define DLLRemove_NPZ(f,l,n,next,prev,nil)\
|
|
((f)==(n)?\
|
|
((f)==(l)?\
|
|
((f)=(l)=(nil)):\
|
|
((f)=(f)->next,(f)->prev=(nil))):\
|
|
(l)==(n)?\
|
|
((l)=(l)->prev,(l)->next=(nil)):\
|
|
((n)->next->prev=(n)->prev,\
|
|
(n)->prev->next=(n)->next))
|
|
|
|
#define DLLRemove(f,l,n) DLLRemove_NPZ(f,l,n,next,prev,0)
|
|
|
|
#define SLLQueuePush_NZ(f,l,n,next,nil) (((f)==(nil)?\
|
|
(f)=(l)=(n):\
|
|
((l)->next=(n),(l)=(n))),\
|
|
(n)->next=(nil))
|
|
#define SLLQueuePush(f,l,n) SLLQueuePush_NZ(f,l,n,next,0)
|
|
|
|
#define SLLQueuePushFront_NZ(f,l,n,next,nil) ((f)==(nil)?\
|
|
((f)=(l)=(n),(n)->next=(nil)):\
|
|
((n)->next=(f),(f)=(n)))
|
|
#define SLLQueuePushFront(f,l,n) SLLQueuePushFront_NZ(f,l,n,next,0)
|
|
|
|
#define SLLQueuePop_NZ(f,l,next,nil) ((f)==(l)?\
|
|
(f)=(l)=(nil):\
|
|
((f)=(f)->next))
|
|
#define SLLQueuePop(f,l) SLLQueuePop_NZ(f,l,next,0)
|
|
|
|
#define SLLStackPush_N(f,n,next) ((n)->next=(f),(f)=(n))
|
|
#define SLLStackPush(f,n) SLLStackPush_N(f,n,next)
|
|
|
|
#define SLLStackPop_NZ(f,next,nil) ((f)==(nil)?(nil):\
|
|
((f)=(f)->next))
|
|
#define SLLStackPop(f) SLLStackPop_NZ(f,next,0)
|
|
|
|
|
|
////////////////////////////////////////////////
|
|
////////////////////////////////////////////////
|
|
////////////////// TYPES ///////////////////
|
|
////////////////////////////////////////////////
|
|
////////////////////////////////////////////////
|
|
|
|
////////////////////////////////
|
|
// Types: Basic
|
|
|
|
#include <stddef.h>
|
|
#include <stdint.h>
|
|
#include <stdarg.h>
|
|
|
|
typedef int8_t S8;
|
|
typedef int16_t S16;
|
|
typedef int32_t S32;
|
|
typedef int64_t S64;
|
|
typedef uint8_t U8;
|
|
typedef uint16_t U16;
|
|
typedef uint32_t U32;
|
|
typedef uint64_t U64;
|
|
typedef S8 B8;
|
|
typedef S16 B16;
|
|
typedef S32 B32;
|
|
typedef S64 B64;
|
|
typedef float F32;
|
|
typedef double F64;
|
|
|
|
#if ARCH_ADDRSIZE == 32
|
|
typedef U32 UAddr;
|
|
typedef S32 SAddr;
|
|
#elif ARCH_ADDRSIZE == 64
|
|
typedef U64 UAddr;
|
|
typedef S64 SAddr;
|
|
#else
|
|
# error UAddr and SAddr not defined for this architecture
|
|
#endif
|
|
|
|
typedef void VoidFunc(void);
|
|
|
|
////////////////////////////////
|
|
// Types: Symbolic Constants
|
|
|
|
typedef enum Axis{
|
|
Axis_X = 0,
|
|
Axis_Y = 1,
|
|
Axis_Z = 2,
|
|
Axis_W = 3
|
|
} Axis;
|
|
|
|
typedef enum Side{
|
|
Side_Min = 0,
|
|
Side_Max = 1
|
|
} Side;
|
|
|
|
typedef enum OperatingSystem{
|
|
OperatingSystem_Null = 0,
|
|
OperatingSystem_Windows = 1,
|
|
OperatingSystem_Linux = 2,
|
|
OperatingSystem_Mac = 3,
|
|
OperatingSystem_COUNT
|
|
} OperatingSystem;
|
|
|
|
typedef enum Architecture{
|
|
Architecture_Null = 0,
|
|
Architecture_X64 = 1,
|
|
Architecture_X86 = 2,
|
|
Architecture_Arm = 3,
|
|
Architecture_Arm64 = 4,
|
|
Architecture_COUNT
|
|
} Architecture;
|
|
|
|
typedef enum Month{
|
|
Month_Jan = 1,
|
|
Month_Feb = 2,
|
|
Month_Mar = 3,
|
|
Month_Apr = 4,
|
|
Month_May = 5,
|
|
Month_Jun = 6,
|
|
Month_Jul = 7,
|
|
Month_Aug = 8,
|
|
Month_Sep = 9,
|
|
Month_Oct = 10,
|
|
Month_Nov = 11,
|
|
Month_Dec = 12,
|
|
} Month;
|
|
|
|
typedef enum DayOfWeek{
|
|
DayOfWeek_Sunday = 0,
|
|
DayOfWeek_Monday = 1,
|
|
DayOfWeek_Tuesday = 2,
|
|
DayOfWeek_Wednesday = 3,
|
|
DayOfWeek_Thursday = 4,
|
|
DayOfWeek_Friday = 5,
|
|
DayOfWeek_Saturday = 6
|
|
} DayOfWeek;
|
|
|
|
typedef U32 DataAccessFlags;
|
|
enum{
|
|
DataAccessFlag_Read = (1 << 0),
|
|
DataAccessFlag_Write = (1 << 1),
|
|
DataAccessFlag_Execute = (1 << 2),
|
|
};
|
|
|
|
////////////////////////////////
|
|
// Types: Compound Types
|
|
|
|
typedef struct V2F32{
|
|
F32 x;
|
|
F32 y;
|
|
} V2F32;
|
|
|
|
typedef struct V3F32{
|
|
F32 x;
|
|
F32 y;
|
|
F32 z;
|
|
} V3F32;
|
|
|
|
typedef struct V4F32{
|
|
F32 x;
|
|
F32 y;
|
|
F32 z;
|
|
F32 w;
|
|
} V4F32;
|
|
|
|
typedef struct RangeF32{
|
|
F32 min;
|
|
F32 max;
|
|
} RangeF32;
|
|
|
|
typedef struct RectF32{
|
|
union{
|
|
struct{
|
|
F32 x0;
|
|
F32 y0;
|
|
F32 x1;
|
|
F32 y1;
|
|
};
|
|
struct{
|
|
V2F32 p0;
|
|
V2F32 p1;
|
|
};
|
|
};
|
|
} RectF32;
|
|
|
|
////////////////////////////////
|
|
// Types: Time
|
|
|
|
typedef U64 DenseTime;
|
|
|
|
typedef struct DateTime{
|
|
U16 msec; // [0,999]
|
|
U8 sec; // [0,60]
|
|
U8 min; // [0,59]
|
|
U8 hour; // [0,23]
|
|
U8 day; // [1,31]
|
|
U8 mon; // [1,12]
|
|
S16 year; // 1 = 1 CE; 2020 = 2020 CE; 0 = 1 BCE; -100 = 101 BCE; etc.
|
|
} DateTime;
|
|
|
|
////////////////////////////////
|
|
// Types: File Properties
|
|
|
|
typedef U32 FilePropertyFlags;
|
|
enum{
|
|
FilePropertyFlag_IsFolder = (1 << 0),
|
|
};
|
|
|
|
typedef struct FileProperties{
|
|
U64 size;
|
|
FilePropertyFlags flags;
|
|
DenseTime create_time;
|
|
DenseTime modify_time;
|
|
DataAccessFlags access;
|
|
} FileProperties;
|
|
|
|
|
|
////////////////////////////////
|
|
// Types: Arena
|
|
|
|
typedef struct Arena Arena;
|
|
|
|
typedef struct ArenaTemp{
|
|
Arena *arena;
|
|
U64 pos;
|
|
} ArenaTemp;
|
|
|
|
|
|
////////////////////////////////
|
|
// Types: String
|
|
|
|
typedef struct String8{
|
|
U8 *str;
|
|
U64 size;
|
|
} String8;
|
|
|
|
typedef struct String8Node{
|
|
struct String8Node *next;
|
|
String8 string;
|
|
} String8Node;
|
|
|
|
typedef struct String8List{
|
|
String8Node *first;
|
|
String8Node *last;
|
|
U64 node_count;
|
|
U64 total_size;
|
|
} String8List;
|
|
|
|
typedef struct StringJoin{
|
|
String8 pre;
|
|
String8 mid;
|
|
String8 post;
|
|
} StringJoin;
|
|
|
|
typedef U32 StringMatchFlags;
|
|
enum{
|
|
StringMatchFlag_NoCase = (1 << 0),
|
|
StringMatchFlag_PrefixMatch = (1 << 1),
|
|
};
|
|
|
|
typedef struct String16{
|
|
U16 *str;
|
|
U64 size;
|
|
} String16;
|
|
|
|
typedef struct String32{
|
|
U32 *str;
|
|
U64 size;
|
|
} String32;
|
|
|
|
#define str8_expand(s) (int)((s).size), ((s).str)
|
|
|
|
typedef struct StringDecode{
|
|
U32 codepoint;
|
|
U32 size;
|
|
} StringDecode;
|
|
|
|
////////////////////////////////
|
|
// Types: Stream
|
|
|
|
typedef struct STREAM STREAM;
|
|
typedef void STREAM_Handle;
|
|
|
|
////////////////////////////////
|
|
// Types: Buffer
|
|
|
|
typedef struct BUFFER{
|
|
void *base;
|
|
U64 size;
|
|
U64 commit_pos;
|
|
} BUFFER;
|
|
|
|
#define BUFFER_TYPED(T, name) union{ BUFFER buffer; T *ptr; } name
|
|
|
|
////////////////////////////////
|
|
// Types: Hash Table
|
|
|
|
typedef struct HASH_Node{
|
|
struct HASH_Node *next;
|
|
U64 hash;
|
|
U64 val;
|
|
} HASH_Node;
|
|
|
|
////////////////////////////////
|
|
// Types: Log
|
|
|
|
typedef void LOG_LogToProc(void *uptr, String8 str);
|
|
|
|
typedef struct LOG_Node{
|
|
struct LOG_Node *next;
|
|
U64 pos;
|
|
String8List log;
|
|
LOG_LogToProc *logto;
|
|
void *uptr;
|
|
} LOG_Node;
|
|
|
|
typedef struct LOG_ThreadVars{
|
|
Arena *arena;
|
|
LOG_Node *stack;
|
|
} LOG_ThreadVars;
|
|
|
|
////////////////////////////////
|
|
// Types: Error
|
|
|
|
typedef struct ER_Node{
|
|
struct ER_Node *next;
|
|
U64 pos;
|
|
String8 error;
|
|
} ER_Node;
|
|
|
|
typedef struct ER_ThreadVars{
|
|
Arena *arena;
|
|
ER_Node *stack;
|
|
U64 over_stack;
|
|
} ER_ThreadVars;
|
|
|
|
|
|
////////////////////////////////////////////////
|
|
////////////////////////////////////////////////
|
|
//////////////// CONSTANTS /////////////////
|
|
////////////////////////////////////////////////
|
|
////////////////////////////////////////////////
|
|
|
|
#define min_S8 ((S8) 0x80)
|
|
#define min_S16 ((S16)0x8000)
|
|
#define min_S32 ((S32)0x80000000)
|
|
#define min_S64 ((S64)0x8000000000000000llu)
|
|
|
|
#define max_S8 ((S8) 0x7f)
|
|
#define max_S16 ((S16)0x7fff)
|
|
#define max_S32 ((S32)0x7fffffff)
|
|
#define max_S64 ((S64)0x7fffffffffffffffllu)
|
|
|
|
#define max_U8 0xff
|
|
#define max_U16 0xffff
|
|
#define max_U32 0xffffffff
|
|
#define max_U64 0xffffffffffffffffllu
|
|
|
|
#define machine_epsilon_F32 1.1920929e-7f
|
|
#define pi_F32 3.14159265359f
|
|
#define tau_F32 6.28318530718f
|
|
#define e_F32 2.71828182846f
|
|
#define gold_big_F32 1.61803398875f
|
|
#define gold_small_F32 0.61803398875f
|
|
|
|
#define machine_epsilon_F64 2.220446e-16
|
|
#define pi_F64 3.14159265359
|
|
#define tau_F64 6.28318530718
|
|
#define e_F64 2.71828182846
|
|
#define gold_big_F64 1.61803398875
|
|
#define gold_small_F64 0.61803398875
|
|
|
|
#define inf_F32_as_U32 0x7f800000
|
|
#define neg_inf_F32_as_U32 0xff800000
|
|
#define inf_F64_as_U64 0x7ff0000000000000
|
|
#define neg_inf_F64_as_U64 0xfff0000000000000
|
|
|
|
#define set_inf_F32(x) (*(U32*)(&(x)) = inf_F32_as_U32)
|
|
#define set_neg_inf_F32(x) (*(U32*)(&(x)) = neg_inf_F32_as_U32)
|
|
#define set_inf_F64(x) (*(U64*)(&(x)) = inf_F64_as_U64)
|
|
#define set_neg_inf_F64(x) (*(U64*)(&(x)) = neg_inf_F64_as_U64)
|
|
|
|
|
|
////////////////////////////////////////////////
|
|
////////////////////////////////////////////////
|
|
//////////////// INTRINSICS ////////////////
|
|
////////////////////////////////////////////////
|
|
////////////////////////////////////////////////
|
|
|
|
#if INTRINSICS_MICROSOFT
|
|
|
|
# include <intrin.h>
|
|
# define intrinsic_rdtsc() __rdtsc()
|
|
# define intrinsic_maxbit(o,x) _BitScanReverse64((o),(x))
|
|
|
|
#elif INTRINSICS_BUILT_IN
|
|
|
|
# define intrinsic_rdtsc() __rdtsc()
|
|
# define intrinsic_maxbit(o,x) (*(o) = __builtin_clzll(x),(x)!=0)
|
|
|
|
#endif
|
|
|
|
|
|
////////////////////////////////////////////////
|
|
////////////////////////////////////////////////
|
|
/////////////// DECLARATIONS ///////////////
|
|
////////////////////////////////////////////////
|
|
////////////////////////////////////////////////
|
|
|
|
////////////////////////////////
|
|
// Functions: Numerical/Math
|
|
|
|
// float infinity/NaN
|
|
|
|
MR4TH_SYMBOL B32 is_inf_or_nan_F32(F32 x);
|
|
MR4TH_SYMBOL B32 is_inf_or_nan_F64(F64 x);
|
|
|
|
// float signs, rounding, and modulus
|
|
|
|
MR4TH_SYMBOL F32 abs_F32(F32 x);
|
|
MR4TH_SYMBOL F32 sign_F32(F32 x);
|
|
|
|
MR4TH_SYMBOL F32 trunc_F32(F32 x);
|
|
MR4TH_SYMBOL F32 floor_F32(F32 x);
|
|
MR4TH_SYMBOL F32 ceil_F32(F32 x);
|
|
MR4TH_SYMBOL F32 nearest_F32(F32 x);
|
|
MR4TH_SYMBOL F32 mod_F32(F32 x, F32 m);
|
|
MR4TH_SYMBOL F32 frac_F32(F32 x);
|
|
|
|
MR4TH_SYMBOL F64 abs_F64(F64 x);
|
|
MR4TH_SYMBOL F64 sign_F64(F64 x);
|
|
|
|
MR4TH_SYMBOL F64 trunc_F64(F64 x);
|
|
MR4TH_SYMBOL F64 floor_F64(F64 x);
|
|
MR4TH_SYMBOL F64 ceil_F64(F64 x);
|
|
MR4TH_SYMBOL F64 nearest_F64(F64 x);
|
|
MR4TH_SYMBOL F64 mod_F64(F64 x, F64 m);
|
|
MR4TH_SYMBOL F64 frac_F64(F64 x);
|
|
|
|
// transcendental functions
|
|
|
|
MR4TH_SYMBOL F32 sin_F32(F32 x);
|
|
MR4TH_SYMBOL F32 cos_F32(F32 x);
|
|
MR4TH_SYMBOL F32 tan_F32(F32 x);
|
|
MR4TH_SYMBOL F32 atan_F32(F32 x);
|
|
MR4TH_SYMBOL F32 atan2_F32(F32 x, F32 y);
|
|
|
|
MR4TH_SYMBOL F32 sqrt_F32(F32 x);
|
|
MR4TH_SYMBOL F32 inv_sqrt_F32(F32 x);
|
|
MR4TH_SYMBOL F32 ln_F32(F32 x);
|
|
MR4TH_SYMBOL F32 pow_F32(F32 base, F32 x);
|
|
|
|
MR4TH_SYMBOL F64 sin_F64(F64 x);
|
|
MR4TH_SYMBOL F64 cos_F64(F64 x);
|
|
MR4TH_SYMBOL F64 tan_F64(F64 x);
|
|
MR4TH_SYMBOL F64 atan_F64(F64 x);
|
|
MR4TH_SYMBOL F64 atan2_F64(F64 x, F64 y);
|
|
|
|
MR4TH_SYMBOL F64 sqrt_F64(F64 x);
|
|
MR4TH_SYMBOL F64 inv_sqrt_F64(F64 x);
|
|
MR4TH_SYMBOL F64 ln_F64(F64 x);
|
|
MR4TH_SYMBOL F64 pow_F64(F64 base, F64 x);
|
|
|
|
// linear interpolation
|
|
|
|
MR4TH_SYMBOL F32 lerp(F32 a, F32 t, F32 b);
|
|
MR4TH_SYMBOL F32 unlerp(F32 a, F32 x, F32 b);
|
|
|
|
// integer rounding & truncating
|
|
|
|
MR4TH_SYMBOL U32 next_pow2_U32(U32 x);
|
|
MR4TH_SYMBOL S32 sign_extend_S32(S32 x, U32 bitidx);
|
|
|
|
MR4TH_SYMBOL U64 next_pow2_U64(U32 x);
|
|
MR4TH_SYMBOL S64 sign_extend_S64(S64 x, U32 bitidx);
|
|
|
|
////////////////////////////////
|
|
// Functions: Compound Types
|
|
|
|
// vector macros
|
|
|
|
#define v2(x,y) CLiteral(V2F32){(x),(y)}
|
|
#define v3(x,y,z) CLiteral(V3F32){(x),(y),(z)}
|
|
#define v4(x,y,z,w) CLiteral(V4F32){(x),(y),(z),(w)}
|
|
|
|
#define v2_expanded(v) ((v).x), ((v).y)
|
|
#define v3_expanded(v) ((v).x), ((v).y), ((v).z)
|
|
#define v4_expanded(v) ((v).x), ((v).y), ((v).z), ((v).w)
|
|
#define rect_expanded(r) ((r).x0), ((r).y0), ((r).x1), ((r).y1)
|
|
|
|
#define v2_exop_scalar(sc, op, v) ((sc) op ((v).x)), ((sc) op ((v).y))
|
|
#define v3_exop_scalar(sc, op, v) ((sc) op ((v).x)), ((sc) op ((v).y)), ((sc) op ((v).z))
|
|
#define v4_exop_scalar(sc, op, v) ((sc) op ((v).x)), ((sc) op ((v).y)), ((sc) op ((v).z)), ((sc) op ((v).w))
|
|
|
|
#define v2_exop(v1, op, v2) ((v1).x op ((v2).x)), ((v1).y op ((v2).y))
|
|
#define v3_exop(v1, op, v2) ((v1).x op ((v2).x)), ((v1).y op ((v2).y)), ((v1).z op ((v2).z))
|
|
#define v4_exop(v1, op, v2) ((v1).x op ((v2).x)), ((v1).y op ((v2).y)), ((v1).z op ((v2).z)), ((v1).w op ((v2).w))
|
|
|
|
#define v2_op_scalar(sc, op, v) CLiteral(V2F32){ v2_exop_scalar(sc,op,v) }
|
|
#define v3_op_scalar(sc, op, v) CLiteral(V3F32){ v3_exop_scalar(sc,op,v) }
|
|
#define v4_op_scalar(sc, op, v) CLiteral(V4F32){ v4_exop_scalar(sc,op,v) }
|
|
|
|
#define v2_op(v1, op, v2) CLiteral(V2F32){ v2_exop(v1,op,v2) }
|
|
#define v3_op(v1, op, v2) CLiteral(V3F32){ v3_exop(v1,op,v2) }
|
|
#define v4_op(v1, op, v2) CLiteral(V4F32){ v4_exop(v1,op,v2) }
|
|
|
|
#define sc_lerp(s1, l, s2) ((s1) + (l)*((s2) - (s1)))
|
|
#define v2_lerp(v1, l, v2) v2( sc_lerp((v1).x, l, (v2).x), sc_lerp((v1).y, l, (v2).y) )
|
|
#define v3_lerp(v1, l, v2) v3( sc_lerp((v1).x, l, (v2).x), sc_lerp((v1).y, l, (v2).y), sc_lerp((v1).z, l, (v2).z) )
|
|
#define v4_lerp(v1, l, v2) v4( sc_lerp((v1).x, l, (v2).x), sc_lerp((v1).y, l, (v2).y), sc_lerp((v1).z, l, (v2).z), sc_lerp((v1).w, l, (v2).w) )
|
|
|
|
#define v2_dim_from_rect(r) CLiteral(V2F32){ (r).x1 - (r).x0, (r).y1 - (r).y0 }
|
|
|
|
// range macros
|
|
|
|
#define rangef32(min,max) CLiteral(RangeF32){(min),(max)}
|
|
|
|
// 2d vectors
|
|
|
|
MR4TH_SYMBOL V2F32 v2_polar(F32 theta, F32 radius);
|
|
MR4TH_SYMBOL F32 angle_from_v2f32(V2F32 v);
|
|
|
|
MR4TH_SYMBOL V2F32 v2_unit(V2F32 v);
|
|
|
|
// 3d vectors
|
|
|
|
MR4TH_SYMBOL V3F32 v3_spherical(F32 theta_xz, F32 theta_yz, F32 radius);
|
|
MR4TH_SYMBOL V3F32 v3_cross(V3F32 a, V3F32 b);
|
|
|
|
MR4TH_SYMBOL V3F32 v3_unit(V3F32 v);
|
|
|
|
// 4x4 matrix
|
|
|
|
MR4TH_SYMBOL B32 mat4x4_inv(F32 *in, F32 *out);
|
|
MR4TH_SYMBOL void mat4x4_mul(F32 *a, F32 *b, F32 *out);
|
|
|
|
////////////////////////////////
|
|
// Functions: Memory Operations
|
|
|
|
MR4TH_SYMBOL void memory_zero(void *ptr, U64 size);
|
|
MR4TH_SYMBOL void memory_fill(void *ptr, U64 size, U8 fillbyte);
|
|
MR4TH_SYMBOL B32 memory_match(void *a, void *b, U64 size);
|
|
MR4TH_SYMBOL void*memory_move(void *a, void *b, U64 size);
|
|
|
|
////////////////////////////////
|
|
// Functions: Symbolic Constants
|
|
|
|
MR4TH_SYMBOL OperatingSystem operating_system_from_context(void);
|
|
MR4TH_SYMBOL Architecture architecture_from_context(void);
|
|
|
|
MR4TH_SYMBOL char* string_from_operating_system(OperatingSystem os);
|
|
MR4TH_SYMBOL char* string_from_architecture(Architecture arch);
|
|
MR4TH_SYMBOL char* string_from_month(Month month);
|
|
MR4TH_SYMBOL char* string_from_day_of_week(DayOfWeek day_of_week);
|
|
|
|
////////////////////////////////
|
|
// Functions: Time
|
|
|
|
MR4TH_SYMBOL DenseTime dense_time_from_date_time(DateTime *date_time);
|
|
MR4TH_SYMBOL DateTime date_time_from_dense_time(DenseTime dense_time);
|
|
|
|
////////////////////////////////
|
|
// Functions: Arenas
|
|
|
|
// arena core
|
|
|
|
MR4TH_SYMBOL_MUST_SHARE Arena* arena_new(U64 reserve_size, U64 alignment, B32 growing);
|
|
MR4TH_SYMBOL_MUST_SHARE void arena_release(Arena *arena);
|
|
MR4TH_SYMBOL_MUST_SHARE void* arena_push_no_zero(Arena *arena, U64 size);
|
|
MR4TH_SYMBOL_MUST_SHARE void arena_pop_to(Arena *arena, U64 pos);
|
|
MR4TH_SYMBOL_MUST_SHARE U64 arena_current_pos(Arena *arena);
|
|
MR4TH_SYMBOL_MUST_SHARE U64 arena_current_align(Arena *arena);
|
|
MR4TH_SYMBOL_MUST_SHARE void arena_set_align(Arena *arena, U64 alignment);
|
|
|
|
MR4TH_SYMBOL_MUST_SHARE ArenaTemp arena_get_scratch(Arena **conflict_array, U32 count);
|
|
|
|
// arena helpers
|
|
|
|
MR4TH_SYMBOL Arena* arena_alloc(void);
|
|
MR4TH_SYMBOL void* arena_push(Arena *arena, U64 size);
|
|
MR4TH_SYMBOL void arena_pop_amount(Arena *arena, U64 amount);
|
|
MR4TH_SYMBOL void arena_align(Arena *arena, U64 pow2_align);
|
|
|
|
#define push_array(a,T,c) (T*)arena_push((a), sizeof(T)*(c))
|
|
#define push_array_no_zero(a,T,c) (T*)arena_push_no_zero((a), sizeof(T)*(c))
|
|
|
|
#define push_array_copy(a,T,c,p) (T*)(MemoryCopy(push_array(a,T,c), (p), sizeof(T)*(c)))
|
|
|
|
MR4TH_SYMBOL ArenaTemp arena_begin_temp(Arena *arena);
|
|
MR4TH_SYMBOL void arena_end_temp(ArenaTemp *temp);
|
|
|
|
#define arena_release_scratch(temp) arena_end_temp(temp)
|
|
|
|
////////////////////////////////
|
|
// Functions: Strings
|
|
|
|
// characters
|
|
|
|
MR4TH_SYMBOL B32 char_is_whitespace(U8 c);
|
|
MR4TH_SYMBOL B32 char_is_slash(U8 c);
|
|
MR4TH_SYMBOL B32 char_is_digit(U8 c);
|
|
|
|
MR4TH_SYMBOL U8 char_to_uppercase(U8 c);
|
|
MR4TH_SYMBOL U8 char_to_lowercase(U8 c);
|
|
|
|
// in-place constructors
|
|
|
|
#define str8(p,z) CLiteral(String8){(U8*)(p), (z)}
|
|
|
|
MR4TH_SYMBOL String8 str8_range(U8 *first, U8 *opl);
|
|
MR4TH_SYMBOL String8 str8_cstring(U8 *cstr);
|
|
MR4TH_SYMBOL String8 str8_cstring_capped(U8 *cstr, U8 *opl);
|
|
|
|
MR4TH_SYMBOL String16 str16_cstring(U16 *cstr);
|
|
|
|
// literal constructors
|
|
|
|
#define str8_lit(s) CLiteral(String8){(U8*)(s), sizeof(s) - 1}
|
|
#define str8_lit_const(s) {(U8*)(s), sizeof(s) - 1}
|
|
|
|
// compound constructors
|
|
|
|
MR4TH_SYMBOL void str8_list_push(Arena *arena, String8List *list, String8 string);
|
|
MR4TH_SYMBOL void str8_list_push_front(Arena *arena, String8List *list, String8 string);
|
|
|
|
MR4TH_SYMBOL String8List str8_list_copy(Arena *arena, String8List *list);
|
|
MR4TH_SYMBOL String8 str8_join(Arena *arena, String8List *list, StringJoin *optional_join);
|
|
MR4TH_SYMBOL String8List str8_split(Arena *arena, String8 string, U8 *split_characters, U32 count);
|
|
|
|
MR4TH_SYMBOL String8 str8_pushfv(Arena *arena, char *fmt, va_list args);
|
|
MR4TH_SYMBOL String8 str8_pushf(Arena *arena, char *fmt, ...);
|
|
MR4TH_SYMBOL void str8_list_pushf(Arena *arena, String8List *list, char *fmt, ...);
|
|
|
|
MR4TH_SYMBOL String8 str8_push_copy(Arena *arena, String8 string);
|
|
|
|
// substrings
|
|
|
|
MR4TH_SYMBOL String8 str8_prefix(String8 str, U64 size);
|
|
MR4TH_SYMBOL String8 str8_chop(String8 str, U64 amount);
|
|
MR4TH_SYMBOL String8 str8_postfix(String8 str, U64 size);
|
|
MR4TH_SYMBOL String8 str8_skip(String8 str, U64 amount);
|
|
|
|
MR4TH_SYMBOL String8 str8_skip_chop_whitespace(String8 str);
|
|
|
|
// hash
|
|
|
|
MR4TH_SYMBOL U64 str8_hash(String8 str);
|
|
|
|
// compare
|
|
|
|
MR4TH_SYMBOL B32 str8_match(String8 a, String8 b, StringMatchFlags flags);
|
|
|
|
// path helpers
|
|
|
|
MR4TH_SYMBOL String8 str8_chop_last_slash(String8 string);
|
|
MR4TH_SYMBOL String8 str8_file_name_from_path(String8 full_file_name);
|
|
MR4TH_SYMBOL String8 str8_base_name_from_file_name(String8 file_name);
|
|
|
|
// stylized constructors
|
|
|
|
MR4TH_SYMBOL String8 str8_join_flags(Arena *arena, String8List *list);
|
|
|
|
// unicode
|
|
|
|
MR4TH_SYMBOL StringDecode str_decode_utf8(U8 *str, U32 cap);
|
|
MR4TH_SYMBOL U32 str_encode_utf8(U8 *dst, U32 codepoint);
|
|
MR4TH_SYMBOL StringDecode str_decode_utf16(U16 *str, U32 cap);
|
|
MR4TH_SYMBOL U32 str_encode_utf16(U16 *dst, U32 codepoint);
|
|
|
|
MR4TH_SYMBOL String32 str32_from_str8(Arena *arena, String8 string);
|
|
MR4TH_SYMBOL String8 str8_from_str32(Arena *arena, String32 string);
|
|
MR4TH_SYMBOL String16 str16_from_str8(Arena *arena, String8 string);
|
|
MR4TH_SYMBOL String8 str8_from_str16(Arena *arena, String16 string);
|
|
|
|
// numeric conversion
|
|
|
|
MR4TH_SYMBOL B32 str8_is_u64(String8 string, U32 radix);
|
|
|
|
MR4TH_SYMBOL U64 u64_from_str8(String8 string, U32 radix);
|
|
MR4TH_SYMBOL U64 u64_from_str8_c_syntax(String8 string);
|
|
MR4TH_SYMBOL S64 s64_from_str8_c_syntax(String8 string);
|
|
MR4TH_SYMBOL F64 f64_from_str8(String8 string);
|
|
|
|
////////////////////////////////
|
|
// Functions: Stream
|
|
|
|
// stream core
|
|
|
|
MR4TH_SYMBOL_MUST_SHARE STREAM* stream_new(void);
|
|
MR4TH_SYMBOL_MUST_SHARE void stream_release(STREAM *stream);
|
|
|
|
MR4TH_SYMBOL_MUST_SHARE void stream_clear(STREAM *stream);
|
|
MR4TH_SYMBOL_MUST_SHARE void stream_write(STREAM *stream, String8 data);
|
|
MR4TH_SYMBOL_MUST_SHARE U8* stream_alloc(STREAM *stream, U64 size);
|
|
|
|
MR4TH_SYMBOL_MUST_SHARE U64 stream_total_size(STREAM *stream);
|
|
MR4TH_SYMBOL_MUST_SHARE STREAM_Handle* stream_next_chunk(STREAM *stream, STREAM_Handle *handle, String8 *chunk_out);
|
|
|
|
// stream helpers
|
|
|
|
MR4TH_SYMBOL String8 stream_read(Arena *arena, STREAM *stream);
|
|
|
|
MR4TH_SYMBOL void stream_printfv(STREAM *stream, char *fmt, va_list args);
|
|
MR4TH_SYMBOL void stream_printf(STREAM *stream, char *fmt, ...);
|
|
|
|
////////////////////////////////
|
|
// Functions: Buffer
|
|
|
|
MR4TH_SYMBOL void buffer_alloc(BUFFER *buffer, U64 reserve_size);
|
|
MR4TH_SYMBOL void buffer_release(BUFFER *buffer);
|
|
MR4TH_SYMBOL void buffer_reset(BUFFER *buffer);
|
|
|
|
MR4TH_SYMBOL void buffer_commit_off__call(BUFFER *buffer, U64 off);
|
|
|
|
#define buffer_commit_off(b, off) \
|
|
if ((b)->commit_pos < (off) && (off) <= (b)->size){ \
|
|
buffer_commit_off__call((b),(off)); }
|
|
|
|
#define buffer_typed_commit_idx(b, idx) \
|
|
buffer_commit_off(&(b)->buffer, (idx)*sizeof(*(b)->ptr))
|
|
|
|
////////////////////////////////
|
|
// Types: Hash Table
|
|
|
|
MR4TH_SYMBOL void hash_buckets_init(BUFFER *buckets, U64 count);
|
|
MR4TH_SYMBOL HASH_Node* hash_buckets_first(BUFFER *buckets, U64 hash);
|
|
MR4TH_SYMBOL void hash_buckets_expand(BUFFER *buckets, U64 capacity);
|
|
MR4TH_SYMBOL void hash_buckets_insert(Arena *arena, BUFFER *buckets, U64 hash, U64 val);
|
|
|
|
////////////////////////////////
|
|
// Functions: Log
|
|
|
|
MR4TH_SYMBOL void log_accum_begin(LOG_LogToProc *proc, void *uptr);
|
|
MR4TH_SYMBOL B32 log_gathering(void);
|
|
MR4TH_SYMBOL void log_emit(String8 message);
|
|
MR4TH_SYMBOL void log_emitf(char *fmt, ...);
|
|
MR4TH_SYMBOL String8 log_accum_end(Arena *arena);
|
|
|
|
////////////////////////////////
|
|
// Functions: Errors
|
|
|
|
MR4TH_SYMBOL void er_accum_begin(void);
|
|
MR4TH_SYMBOL void er_emit(String8 error);
|
|
MR4TH_SYMBOL void er_emitf(char *fmt, ...);
|
|
MR4TH_SYMBOL String8 er_accum_end(Arena *arena);
|
|
|
|
|
|
////////////////////////////////////////////////
|
|
////////////////////////////////////////////////
|
|
///////// DECLARATIONS PROFILING ///////////
|
|
////////////////////////////////////////////////
|
|
////////////////////////////////////////////////
|
|
|
|
////////////////////////////////
|
|
// Profiling: Implementable Interface
|
|
|
|
#if MR4TH_PROFILING_USER || MR4TH_PROFILING_PROVIDER
|
|
|
|
MR4TH_SYMBOL_LINK void prof_open(char *name);
|
|
MR4TH_SYMBOL_LINK void prof_close(void);
|
|
MR4TH_SYMBOL_LINK void prof_thread_begin(void);
|
|
MR4TH_SYMBOL_LINK void prof_thread_end(void);
|
|
MR4TH_SYMBOL_LINK void prof_thread_flush(void);
|
|
MR4TH_SYMBOL_LINK void prof_begin(char *name, U32 len);
|
|
MR4TH_SYMBOL_LINK void prof_end(void);
|
|
|
|
#endif
|
|
|
|
////////////////////////////////
|
|
// Profiling: User Interface
|
|
|
|
#if MR4TH_PROFILING_USER
|
|
# define ProfOpen(n) prof_open((char*)(n))
|
|
# define ProfClose() prof_close()
|
|
# define ProfThreadBegin() prof_thread_begin()
|
|
# define ProfThreadEnd() prof_thread_end()
|
|
# define ProfThreadFlush() prof_thread_flush()
|
|
# define ProfBegin(n) prof_begin((n), sizeof(n) - 1)
|
|
# define ProfEnd() prof_end()
|
|
#else
|
|
# define ProfOpen(n)
|
|
# define ProfClose()
|
|
# define ProfThreadBegin()
|
|
# define ProfThreadEnd()
|
|
# define ProfThreadFlush()
|
|
# define ProfBegin(n)
|
|
# define ProfEnd()
|
|
#endif
|
|
|
|
#if MR4TH_PROFILING_MANUAL
|
|
# define ProfBeginManual(n) ProfBegin(n)
|
|
# define ProfEndManual() ProfEnd()
|
|
#else
|
|
# define ProfBeginManual(n)
|
|
# define ProfEndManual()
|
|
#endif
|
|
|
|
#define ProfBeginFunc() ProfBeginManual(__FUNCTION__)
|
|
#define ProfEndFunc() ProfEndManual()
|
|
|
|
|
|
|
|
////////////////////////////////////////////////
|
|
////////////////////////////////////////////////
|
|
/////// DECLARATIONS OS ABSTRACTION ////////
|
|
////////////////////////////////////////////////
|
|
////////////////////////////////////////////////
|
|
|
|
////////////////////////////////
|
|
// Shared Types
|
|
|
|
typedef struct OS_FileIter{
|
|
U8 v[640];
|
|
} OS_FileIter;
|
|
|
|
typedef enum OS_SystemPath{
|
|
OS_SystemPath_CurrentDirectory = 0,
|
|
OS_SystemPath_Binary = 1,
|
|
OS_SystemPath_UserData = 2,
|
|
OS_SystemPath_TempData = 3,
|
|
OS_SystemPath_COUNT
|
|
} OS_SystemPath;
|
|
|
|
typedef void OS_Library;
|
|
|
|
typedef struct OS_VRange{
|
|
void *addr;
|
|
U64 size;
|
|
} OS_VRange;
|
|
|
|
////////////////////////////////
|
|
// Implementable Functions: Process Setup
|
|
|
|
MR4TH_SYMBOL void os_main_init(int argc, char **argv);
|
|
MR4TH_SYMBOL String8List os_command_line_arguments(void);
|
|
MR4TH_SYMBOL void os_exit_process(U32 code);
|
|
|
|
////////////////////////////////
|
|
// Implementable Functions: Memory Functions
|
|
|
|
MR4TH_SYMBOL void* os_memory_reserve(U64 size);
|
|
MR4TH_SYMBOL B32 os_memory_commit(void *ptr, U64 size);
|
|
MR4TH_SYMBOL void os_memory_decommit(void *ptr, U64 size);
|
|
MR4TH_SYMBOL void os_memory_release(void *ptr, U64 size);
|
|
|
|
MR4TH_SYMBOL B32 os_memory_protect(void *ptr, U64 size, DataAccessFlags access_flags);
|
|
|
|
////////////////////////////////
|
|
// Implementable Functions: File Handling
|
|
|
|
MR4TH_SYMBOL String8 os_file_read(Arena *arena, String8 file_name);
|
|
|
|
typedef String8 OS_FileWriteCallback(void *udata);
|
|
MR4TH_SYMBOL B32 os_file_write_callback(String8 file_name, void *udata, OS_FileWriteCallback *callback);
|
|
|
|
MR4TH_SYMBOL FileProperties os_file_properties(String8 file_name);
|
|
|
|
MR4TH_SYMBOL B32 os_file_delete(String8 file_name);
|
|
MR4TH_SYMBOL B32 os_file_rename(String8 og_name, String8 new_name);
|
|
MR4TH_SYMBOL B32 os_file_make_directory(String8 path);
|
|
MR4TH_SYMBOL B32 os_file_delete_directory(String8 path);
|
|
|
|
MR4TH_SYMBOL OS_FileIter os_file_iter_init(Arena *arena, String8 path);
|
|
MR4TH_SYMBOL B32 os_file_iter_next(Arena *arena, OS_FileIter *iter,
|
|
String8 *name_out, FileProperties *prop_out);
|
|
MR4TH_SYMBOL void os_file_iter_end(OS_FileIter *iter);
|
|
|
|
MR4TH_SYMBOL String8 os_file_path(Arena *arena, OS_SystemPath path);
|
|
|
|
MR4TH_SYMBOL void os_set_current_directory(String8 path);
|
|
|
|
////////////////////////////////
|
|
// Implementable Functions: Time
|
|
|
|
MR4TH_SYMBOL DateTime os_now_universal_time(void);
|
|
MR4TH_SYMBOL DateTime os_local_time_from_universal(DateTime *date_time);
|
|
MR4TH_SYMBOL DateTime os_universal_time_from_local(DateTime *date_time);
|
|
|
|
MR4TH_SYMBOL U32 os_time_stamp_32_from_date_time(DateTime *date_time);
|
|
|
|
MR4TH_SYMBOL U64 os_now_ticks(void);
|
|
MR4TH_SYMBOL void os_get_microseconds_per_tick(U64 *usecs_out, U64 *ticks_out);
|
|
MR4TH_SYMBOL void os_sleep_milliseconds(U32 t);
|
|
|
|
////////////////////////////////
|
|
// Implementable Functions: Libraries
|
|
|
|
MR4TH_SYMBOL OS_Library* os_lib_load(String8 path);
|
|
MR4TH_SYMBOL VoidFunc* os_lib_get_proc(OS_Library *lib, char *name);
|
|
MR4TH_SYMBOL void os_lib_release(OS_Library *lib);
|
|
|
|
MR4TH_SYMBOL OS_Library* os_lib_from_addr(void *addr);
|
|
MR4TH_SYMBOL OS_VRange os_lib_image_range(OS_Library *lib);
|
|
|
|
////////////////////////////////
|
|
// Implementable Functions: Entropy
|
|
|
|
MR4TH_SYMBOL void os_get_entropy(void *data, U64 size);
|
|
|
|
////////////////////////////////
|
|
// Helper Functions: File Handling
|
|
|
|
MR4TH_SYMBOL B32 os_file_write(String8 file_name, String8 data);
|
|
MR4TH_SYMBOL B32 os_file_write_list(String8 file_name, String8Node *first_node);
|
|
MR4TH_SYMBOL B32 os_file_write_stream(String8 file_name, STREAM *stream);
|
|
|
|
////////////////////////////////
|
|
// Helper Functions: Libraries
|
|
|
|
MR4TH_SYMBOL OS_VRange os_this_image(void);
|
|
|
|
|
|
|
|
/*******************************
|
|
** Begin Base Win32 **
|
|
*******************************/
|
|
|
|
#if OS_WINDOWS
|
|
|
|
////////////////////////////////
|
|
// Win32 Includes
|
|
|
|
#include <Windows.h>
|
|
#include <userenv.h>
|
|
#include <psapi.h>
|
|
|
|
////////////////////////////////
|
|
// Win32 Types
|
|
|
|
typedef struct W32_FileIter{
|
|
HANDLE handle;
|
|
WIN32_FIND_DATAW find_data;
|
|
B32 done;
|
|
} W32_FileIter;
|
|
StaticAssert(sizeof(W32_FileIter) <= sizeof(OS_FileIter), w32_fileiter);
|
|
|
|
////////////////////////////////
|
|
// Win32 Functions: Specialized Init for WinMain
|
|
|
|
MR4TH_SYMBOL void w32_WinMain_init(HINSTANCE hInstance,
|
|
HINSTANCE hPrevInstance,
|
|
LPSTR lpCmdLine,
|
|
int nShowCmd);
|
|
|
|
MR4TH_SYMBOL HINSTANCE w32_get_instance(void);
|
|
|
|
////////////////////////////////
|
|
// Win32 Functions: Time Helpers
|
|
|
|
MR4TH_SYMBOL DateTime w32_date_time_from_system_time(SYSTEMTIME *in);
|
|
MR4TH_SYMBOL SYSTEMTIME w32_system_time_from_date_time(DateTime *in);
|
|
MR4TH_SYMBOL DenseTime w32_dense_time_from_file_time(FILETIME *file_time);
|
|
|
|
////////////////////////////////
|
|
// Win32 Functions: File Helpers
|
|
|
|
MR4TH_SYMBOL FilePropertyFlags w32_prop_flags_from_attribs(DWORD attribs);
|
|
MR4TH_SYMBOL DataAccessFlags w32_access_from_attributes(DWORD attribs);
|
|
|
|
////////////////////////////////
|
|
// Win32 Helper Macro
|
|
|
|
#define W32_PROC_ADDR(v,m,s) (*(PROC*)(&(v))) = GetProcAddress((m),(s))
|
|
|
|
#endif /* OS_WINDOWS */
|
|
|
|
/*******************************
|
|
** End Base Win32 **
|
|
*******************************/
|
|
|
|
|
|
|
|
/*******************************
|
|
** Begin Base Linux **
|
|
*******************************/
|
|
|
|
#if OS_LINUX
|
|
|
|
////////////////////////////////
|
|
// Linux Includes
|
|
|
|
#include <stdlib.h>
|
|
#include <stdio.h>
|
|
#include <linux/limits.h>
|
|
#include <limits.h>
|
|
#include <fcntl.h>
|
|
#include <unistd.h>
|
|
#include <sys/types.h>
|
|
#include <sys/mman.h>
|
|
#include <sys/stat.h>
|
|
#include <sys/random.h>
|
|
#include <time.h>
|
|
#include <dirent.h>
|
|
#include <dlfcn.h>
|
|
#include <errno.h>
|
|
#include <string.h>
|
|
|
|
////////////////////////////////
|
|
// Linux Types
|
|
|
|
typedef struct LNX_FileIter{
|
|
DIR *dir;
|
|
struct dirent *dp;
|
|
String8 path;
|
|
} LNX_FileIter;
|
|
StaticAssert(sizeof(LNX_FileIter) <= sizeof(OS_FileIter), lnx_fileiter);
|
|
|
|
////////////////////////////////
|
|
// Linux Functions: Time Helpers
|
|
|
|
MR4TH_SYMBOL DateTime lnx_date_time_from_tm(struct tm *tm);
|
|
MR4TH_SYMBOL DenseTime lnx_dense_time_from_time_t(time_t time);
|
|
MR4TH_SYMBOL struct tm lnx_tm_from_date_time(DateTime *date_time);
|
|
|
|
////////////////////////////////
|
|
// Linux Functions: File Helpers
|
|
|
|
MR4TH_SYMBOL FilePropertyFlags lnx_prop_flags_from_mode(mode_t mode);
|
|
MR4TH_SYMBOL DataAccessFlags lnx_access_from_mode(mode_t mode);
|
|
MR4TH_SYMBOL FileProperties lnx_file_properties_from_stat(struct stat *st);
|
|
|
|
MR4TH_SYMBOL String8 lnx_proc_file_read(Arena *arena, char *path);
|
|
|
|
#endif /* OS_LINUX */
|
|
|
|
/*******************************
|
|
** End Base Linux **
|
|
*******************************/
|
|
|
|
|
|
////////////////////////////////////////////////
|
|
////////////////////////////////////////////////
|
|
///////////////// M4 Printf ////////////////
|
|
////////////////////////////////////////////////
|
|
////////////////////////////////////////////////
|
|
|
|
// stb_sprintf.h 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.
|
|
NOTE(allen): MODIFICATION - I've hard coded that this copy *does* use floats
|
|
|
|
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
|
|
#endif
|
|
|
|
#ifndef STBSP__ASAN
|
|
#define STBSP__ASAN
|
|
#endif
|
|
|
|
#ifdef STB_SPRINTF_STATIC
|
|
#define STBSP__PUBLICDEC static
|
|
#define STBSP__PUBLICDEF static STBSP__ASAN
|
|
#else
|
|
#ifdef __cplusplus
|
|
#define STBSP__PUBLICDEC extern "C"
|
|
#define STBSP__PUBLICDEF extern "C" STBSP__ASAN
|
|
#else
|
|
#define STBSP__PUBLICDEC extern
|
|
#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 <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);
|
|
|
|
STBSP__PUBLICDEC int m4_vsprintf(char *buf, char const *fmt, va_list va);
|
|
STBSP__PUBLICDEC int m4_vsnprintf(char *buf, int count, char const *fmt, va_list va);
|
|
STBSP__PUBLICDEC int m4_sprintf(char *buf, char const *fmt, ...) STBSP__ATTRIBUTE_FORMAT(2,3);
|
|
STBSP__PUBLICDEC int m4_snprintf(char *buf, int count, char const *fmt, ...) STBSP__ATTRIBUTE_FORMAT(3,4);
|
|
|
|
STBSP__PUBLICDEC int m4_vsprintfcb(STBSP_SPRINTFCB *callback, void *user, char *buf, char const *fmt, va_list va);
|
|
STBSP__PUBLICDEC void m4_set_separators(char comma, char period);
|
|
|
|
/*
|
|
** NOTE(allen): sprintf modifications notes
|
|
**
|
|
** Legend for specifier allocation:
|
|
** [ ] - specifier is free for use
|
|
** [#] - used by stb_sprintf default
|
|
** [$] - used by built-in custom printing logic
|
|
**
|
|
** Specifier allocation:
|
|
** a[#] - hex float
|
|
** A[#] - hex float
|
|
** b[#] - binary
|
|
** B[#] - binary
|
|
** c[#] - char
|
|
** C[ ]
|
|
** d[#] - integer
|
|
** D[ ]
|
|
** e[#] - float
|
|
** E[#] - float
|
|
** f[#] - float
|
|
** F[ ]
|
|
** g[#] - float
|
|
** G[#] - float
|
|
** h[#] - half width
|
|
** H[ ]
|
|
** i[#] - integer
|
|
** I[#] - size[Microsoft-Style]
|
|
** j[#] - size[size_t]
|
|
** J[ ]
|
|
** k[ ]
|
|
** K[ ]
|
|
** l[#] - size[long]/size[long long]
|
|
** L[ ]
|
|
** m[ ]
|
|
** M[ ]
|
|
** n[#] - write-bytes
|
|
** N[$] - indentation
|
|
** o[#] - octal
|
|
** O[ ]
|
|
** p[ ]
|
|
** P[ ]
|
|
** q[ ]
|
|
** Q[ ]
|
|
** r[ ]
|
|
** R[ ]
|
|
** s[#] - cstr
|
|
** S[$] - String8
|
|
** t[#] - size[ptrdiff_t]
|
|
** T[ ]
|
|
** u[#] - unsigned integer
|
|
** U[ ]
|
|
** v[ ]
|
|
** V[ ]
|
|
** w[ ]
|
|
** W[ ]
|
|
** x[#] - hex
|
|
** X[#] - hex
|
|
** y[ ]
|
|
** Y[ ]
|
|
** z[#] - size[size_t]
|
|
** Z[ ]
|
|
** 0[#] - leading zeroes
|
|
** 1[ ]
|
|
** 2[ ]
|
|
** 3[ ]
|
|
** 4[ ]
|
|
** 5[ ]
|
|
** 6[ ]
|
|
** 7[ ]
|
|
** 8[ ]
|
|
** 9[ ]
|
|
** $[$] - memory size (modified from stb_sprintf.h)
|
|
** ?[ ]
|
|
**
|
|
*/
|
|
|
|
#endif /* MR4TH_BASE_H */
|
|
|
|
/*
|
|
** TODO:
|
|
** [ ] m4_printf plugins experiment
|
|
**
|
|
** [ ] unicode support
|
|
** [ ] high performance encode/decode factorization
|
|
** [ ] unicode string conversions should take string lists "Better unicode conversions here"
|
|
** [ ] math implementation replacements
|
|
** [ ] clib elimination option
|
|
** [x] manually implement memset,memcmp,memmove
|
|
** [x] basic C implementations
|
|
** [ ] high performance implementations (hand written assembly perhaps? -- or at least use vector intrinsics)
|
|
** [ ] necessary stubs for clib elimination
|
|
** [ ] Test out the usage process
|
|
** [ ] default (unity build standalone)
|
|
** [ ] standalone multi-unit
|
|
** [ ] core & plugin
|
|
** [ ] Write instructions
|
|
** [ ] Write examples
|
|
**
|
|
** [ ] Multi-threading primitives
|
|
** [ ] Thread-safe STREAM
|
|
*/
|