635 lines
18 KiB
C
635 lines
18 KiB
C
#ifndef BASE_H
|
|
#define BASE_H
|
|
|
|
#if !defined(MR4TH_SYMBOL)
|
|
# define MR4TH_SYMBOL static
|
|
#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
|
|
|
|
#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
|
|
|
|
// setup pointer size macro
|
|
#if ARCH_X64 || ARCH_ARM64
|
|
# define ARCH_ADDRSIZE 64
|
|
#else
|
|
# define ARCH_ADDRSIZE 32
|
|
#endif
|
|
|
|
////////////////////////////////
|
|
// Macros: Assert
|
|
|
|
#if !defined(AssertBreak)
|
|
# define AssertBreak() (*(volatile int*)0 = 0)
|
|
#endif
|
|
|
|
#define Assert(c) do{ if (!(c)){ AssertBreak(); } }while(0)
|
|
|
|
#define StaticAssert(c,l) typedef U8 Glue(l,__LINE__) [(c)?1:-1]
|
|
|
|
////////////////////////////////
|
|
// Macros: Memory
|
|
|
|
#include <string.h>
|
|
|
|
#define MemoryZero(p,z) memset((p), 0, (z))
|
|
#define MemoryZeroStruct(p) MemoryZero((p), sizeof(*(p)))
|
|
#define MemoryZeroArray(p) MemoryZero((p), sizeof(p))
|
|
#define MemoryZeroTyped(p,c) MemoryZero((p), sizeof(*(p))*(c))
|
|
|
|
#define MemoryMatch(a,b,z) (memcmp((a),(b),(z)) == 0)
|
|
|
|
#define MemoryCopy(d,s,z) memmove((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)))
|
|
#define MemoryCopyTyped(d,s,c) MemoryCopy((d),(s),Min(sizeof(*(d)),sizeof(*(s)))*(c))
|
|
|
|
////////////////////////////////
|
|
// 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)
|
|
|
|
|
|
////////////////////////////////
|
|
// Macros: Common 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 AlignUpPow2(x,p) (((x) + (p) - 1)&~((p) - 1))
|
|
#define AlignDownPow2(x,p) ((x)&~((p) - 1))
|
|
#define IsPow2OrZero(x) (((x)&((x)-1)) == 0)
|
|
|
|
#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 KB(x) ((U64)(x) << 10)
|
|
#define MB(x) ((U64)(x) << 20)
|
|
#define GB(x) ((U64)(x) << 30)
|
|
#define TB(x) ((U64)(x) << 40llu)
|
|
|
|
////////////////////////////////
|
|
// Types: Basic
|
|
|
|
#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: Arena
|
|
|
|
typedef struct Arena{
|
|
struct Arena *current;
|
|
struct Arena *prev;
|
|
U64 alignment;
|
|
B8 growing;
|
|
U8 filler[7];
|
|
U64 base_pos;
|
|
U64 chunk_cap;
|
|
U64 chunk_pos;
|
|
U64 chunk_commit_pos;
|
|
} Arena;
|
|
|
|
typedef struct ArenaTemp{
|
|
Arena *arena;
|
|
U64 pos;
|
|
} ArenaTemp;
|
|
|
|
////////////////////////////////
|
|
// Types: String
|
|
|
|
typedef struct String8{
|
|
U8 *str;
|
|
U64 size;
|
|
} String8;
|
|
|
|
////////////////////////////////
|
|
// Types: Stream
|
|
|
|
#include <stdio.h>
|
|
|
|
typedef void STREAM_Handle;
|
|
|
|
typedef struct STREAM_Node{
|
|
struct STREAM_Node *next;
|
|
U64 size;
|
|
U8 data[0];
|
|
} STREAM_Node;
|
|
|
|
#define STREAM_NODE_FROM_DATA(d) (STREAM_Node*)((U8*)(d) - sizeof(STREAM_Node))
|
|
|
|
typedef struct STREAM{
|
|
Arena *arena;
|
|
U64 clear_pos;
|
|
STREAM_Node *first_node;
|
|
STREAM_Node *last_node;
|
|
U64 buffer_cap;
|
|
U64 total_size;
|
|
STREAM_Node *unused_node;
|
|
} STREAM;
|
|
|
|
#define STREAM_ALLOC_SIZE MB(16)
|
|
|
|
|
|
////////////////////////////////
|
|
// Functions: Arenas
|
|
|
|
// arena core
|
|
|
|
MR4TH_SYMBOL Arena* arena_alloc_reserve(U64 reserve_size, B32 growing);
|
|
MR4TH_SYMBOL Arena* arena_alloc(void);
|
|
MR4TH_SYMBOL void arena_release(Arena *arena);
|
|
MR4TH_SYMBOL void* arena_push_no_zero(Arena *arena, U64 size);
|
|
MR4TH_SYMBOL void arena_pop_to(Arena *arena, U64 pos);
|
|
MR4TH_SYMBOL U64 arena_current_pos(Arena *arena);
|
|
|
|
MR4TH_SYMBOL void* arena_push(Arena *arena, U64 size);
|
|
MR4TH_SYMBOL void arena_align(Arena *arena, U64 pow2_align);
|
|
MR4TH_SYMBOL void arena_pop_amount(Arena *arena, U64 amount);
|
|
|
|
#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,s,c) \
|
|
(T*)memory_move(push_array_no_zero(a,T,c), (s), sizeof(T)*(c))
|
|
|
|
// arena temp
|
|
|
|
MR4TH_SYMBOL ArenaTemp arena_begin_temp(Arena *arena);
|
|
MR4TH_SYMBOL void arena_end_temp(ArenaTemp *temp);
|
|
|
|
// scratch
|
|
|
|
MR4TH_SYMBOL ArenaTemp arena_get_scratch(Arena **conflict_array, U32 count);
|
|
#define arena_release_scratch(temp) arena_end_temp(temp)
|
|
|
|
////////////////////////////////
|
|
// Functions: Strings
|
|
|
|
MR4TH_SYMBOL String8 str8(U8 *str, U64 size);
|
|
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);
|
|
|
|
#define str8_lit(s) str8((U8*)(s), sizeof(s) - 1)
|
|
#define str8_struct(s) str8((U8*)(s), sizeof(*(s)))
|
|
#define str8_array(s) str8((U8*)(s), sizeof(s))
|
|
#define str8_lit_const(s) { (U8*)(s), sizeof(s) - 1 }
|
|
|
|
MR4TH_SYMBOL U32 u32_from_str8_base10(String8 string);
|
|
|
|
////////////////////////////////
|
|
// Functions: Stream
|
|
|
|
// stream core
|
|
|
|
MR4TH_SYMBOL STREAM* stream_new(void);
|
|
MR4TH_SYMBOL void stream_release(STREAM *stream);
|
|
|
|
MR4TH_SYMBOL void stream_clear(STREAM *stream);
|
|
MR4TH_SYMBOL void stream_write(STREAM *stream, String8 data);
|
|
MR4TH_SYMBOL U8* stream_allocate(STREAM *stream, U64 size);
|
|
|
|
MR4TH_SYMBOL U64 stream_total_size(STREAM *stream);
|
|
MR4TH_SYMBOL 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, ...);
|
|
|
|
MR4TH_SYMBOL void stream_fprint(FILE *file, STREAM *stream);
|
|
|
|
|
|
|
|
////////////////////////////////
|
|
// 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);
|
|
|
|
|
|
#if OS_WINDOWS
|
|
|
|
////////////////////////////////
|
|
// Win32: Includes
|
|
|
|
#include <Windows.h>
|
|
#include <userenv.h>
|
|
#include <psapi.h>
|
|
|
|
|
|
#elif OS_LINUX
|
|
|
|
|
|
////////////////////////////////
|
|
// Linux: Includes
|
|
|
|
#include <sys/mman.h>
|
|
|
|
|
|
// OS Missing
|
|
#else
|
|
# error not implemented on this OS
|
|
#endif
|
|
|
|
|
|
|
|
////////////////////////////////////////////////
|
|
////////////////////////////////////////////////
|
|
/// stb_sprintf.h STB_SPRINTF_H_INCLUDE ////
|
|
////////////////////////////////////////////////
|
|
////////////////////////////////////////////////
|
|
|
|
#define STB_SPRINTF_DECORATE(name) m4_##name
|
|
|
|
/*
|
|
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 <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 //BASE_H
|