test: Organize unit tests

This commit is contained in:
doyle 2021-07-22 19:59:27 +10:00
parent 9f9f9b52aa
commit b536f407b8
2 changed files with 957 additions and 743 deletions

View File

@ -1,74 +1,78 @@
// -------------------------------------------------------------------------------------------------
// NOTE: Dqn
// -------------------------------------------------------------------------------------------------
// General all-purpose utility library.
//
// NOTE: Preprocessor Config
// -----------------------------------------------------------------------------
// NOTE: Configuration
// -----------------------------------------------------------------------------
// #define DQN_IMPLEMENTATION
// Define this in one and only one C++ file to enable the implementation
// code of the header file
//
// #define DQN_NO_ASSERT
// Turn all assertion macros to no-ops
//
// #define DQN_NO_WIN32_MINIMAL_HEADER
// Define this to stop this library from defining a minimal subset of Win32
// prototypes and definitions in this file. Useful for stopping redefinition
// of symbols if another library includes "Windows.h"
//
// #define DQN_NO_WIN32_SHLWAPI_H
// See DQN_NO_WIN32_MINIMAL_HEADER. Useful if another library includes
// "shlwapi.h"
//
// #define DQN_STATIC_API
// Apply static to all function definitions and disable external linkage to
// other translation units.
//
// #define DQN_STB_SPRINTF_HEADER_ONLY
// Define this to stop this library from defining
// STB_SPRINTF_IMPLEMENTATION. Useful if another library uses and includes
// "stb_sprintf.h"
//
// #define DQN_MEMZERO_DEBUG_BYTE 0xDA
// By defining 'DQN_MEMZERO_DEBUG_BYTE' to some byte value this will enable
// functions that receive Dqn_ZeroMem::No to memset the non-zeroed memory to
// 'DQN_MEMZERO_DEBUG_BYTE' to help detect holding pointers to invalid memory,
// i.e. holding pointers to an array element that was popped from the array.
//
// #define DQN_ALLOCATION_TRACING 1
// When defined to 0 all tracing code is compiled out.
//
// When defined to 1, some allocating calls in the library will automatically
// get passed in the file name, function name, line number and an optional tag.
//
// For data structures that have a 'Dqn_AllocationTracer' member, the caller
// can set the 'Dqn_AllocationTracer' to log allocations every time they are
// made in the data structure.
//
// 'Tagged' variants of functions accept as the last parameter, a 'tag' that is
// the descriptor/name to describe the allocation. All extra parameters and
// tags are compiled out when tracing is disabled.
//
// #define DQN_ALLOCATOR_DEFAULT_TO_NULL
// If defined, zero initialising an allocator uses the null allocator (i.e.
// crash on allocation). This forces the user to specify explicitly which
// allocator to use, for example.
//
// Dqn_Allocator allocator = {};
// Dqn_Allocator_Allocate(allocator, ...) // <- This asserts and crashes
//
// So you have to explicitly do
//
// Dqn_Allocator allocator = {};
// allocator.type = Dqn_AllocatorType::Heap;
//
// or
//
// Dqn_Allocator allocator = Dqn_AllocatorHeap()
//
// When not defined a zero initialised allocator will use the Heap
// Dqn_Allocator via malloc, realloc, free.
//
// -------------------------------------------------------------------------------------------------
/*
#define DQN_IMPLEMENTATION Define this in one and only one C++ file to enable the
implementation code of the header file
#define DQN_NO_ASSERT Turn all assertion macros to no-ops
#define DQN_NO_WIN32_WINDOWS_H Define this to stop this library from defining a minimal subset
of Win32 prototypes and definitions in this file. Useful for
stopping redefinition of symbols if another library includes
"Windows.h"
#define DQN_NO_WIN32_SHLWAPI_H See DQN_NO_WIN32_WINDOWS_H. Useful if another library includes
"shlwapi.h"
#define DQN_STATIC_API Apply static to all function definitions and disable external
linkage to other translation units.
#define DQN_STB_SPRINTF_HEADER_ONLY Define this to stop this library from defining
STB_SPRINTF_IMPLEMENTATION. Useful if another library uses and
includes "stb_sprintf.h"
#define DQN_MEMZERO_DEBUG_BYTE 0xDA
By defining 'DQN_MEMZERO_DEBUG_BYTE' to some byte value this will enable
functions that receive Dqn_ZeroMem::No to memset the non-zeroed memory to
'DQN_MEMZERO_DEBUG_BYTE' to help detect holding pointers to invalid memory,
i.e. holding pointers to an array element that was popped from the array.
#define DQN_ALLOCATION_TRACING 1
When defined to 0 all tracing code is compiled out.
When defined to 1, some allocating calls in the library will automatically
get passed in the file name, function name, line number and an optional tag.
For data structures that have a 'Dqn_AllocationTracer' member, the caller
can set the 'Dqn_AllocationTracer' to log allocations every time they are
made in the data structure.
'Tagged' variants of functions accept as the last parameter, a 'tag' that is
the descriptor/name to describe the allocation. All extra parameters and
tags are compiled out when tracing is disabled.
#define DQN_ALLOCATOR_DEFAULT_TO_NULL
If defined, zero initialising an allocator uses the null allocator (i.e.
crash on allocation). This forces the user to specify explicitly which
allocator to use, for example.
Dqn_Allocator allocator = {};
Dqn_Allocator_Allocate(allocator, ...) // <- This asserts and crashes
So you have to explicitly do
Dqn_Allocator allocator = {};
allocator.type = Dqn_AllocatorType::Heap;
or
Dqn_Allocator allocator = Dqn_AllocatorHeap()
When not defined a zero initialised allocator will use the Heap
Dqn_Allocator via malloc, realloc, free.
*/
// -------------------------------------------------------------------------------------------------
//
// NOTE: Library Config
//
// -------------------------------------------------------------------------------------------------
/*
Dqn library logs errors and outputs through Dqn_Log(...). This is
@ -383,7 +387,7 @@ static_assert(sizeof(void *) == sizeof(Dqn_usize), "Require: Pointer can be held
//
// ------------------------------------------------------------------------------------------------
#if defined(DQN_OS_WIN32)
#if !defined(DQN_NO_WIN32_WINDOWS_H)
#if !defined(DQN_NO_WIN32_MINIMAL_HEADER)
// Taken from Windows.h
typedef unsigned long DWORD;
typedef unsigned short WORD;
@ -515,12 +519,12 @@ void Dqn_TicketMutex_Begin (Dqn_TicketMutex *mutex);
void Dqn_TicketMutex_End (Dqn_TicketMutex *mutex);
// NOTE: Advance API, more granular functions, the basic sequence to use the API is
/*
#if 0
Dqn_TicketMutex mutex = {};
unsigned int ticket = Dqn_TicketMutex_MakeTicket(&mutex);
Dqn_TicketMutex_BeginTicket(&mutex, ticket); // Blocking call until we attain the lock
Dqn_TicketMutex_End(&mutex);
*/
#endif
unsigned int Dqn_TicketMutex_MakeTicket (Dqn_TicketMutex *mutex);
void Dqn_TicketMutex_BeginTicket (const Dqn_TicketMutex *mutex, unsigned int ticket);
Dqn_b32 Dqn_TicketMutex_CanLock (const Dqn_TicketMutex *mutex, unsigned int ticket);
@ -530,23 +534,29 @@ Dqn_b32 Dqn_TicketMutex_CanLock (const Dqn_TicketMutex *mutex, u
// NOTE: stb_sprintf
//
// -------------------------------------------------------------------------------------------------
// stb_sprintf - v1.05 - public domain snprintf() implementation
// 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 : h ll j z t I64 I32 I
// 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:
//
@ -624,8 +634,6 @@ 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
@ -670,46 +678,77 @@ PERFORMANCE vs MSVC 2008 32-/64-bit (GCC is even slower than MSVC):
"...512 char string..." ( 35.0x/32.5x faster!)
*/
#if defined(__has_feature)
#if __has_feature(address_sanitizer)
#define STBI__ASAN __attribute__((no_sanitize("address")))
#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 STBI__ASAN
#define STBI__ASAN
#ifndef STBSP__ASAN
#define STBSP__ASAN
#endif
#ifdef STB_SPRINTF_STATIC
#define STBSP__PUBLICDEC static
#define STBSP__PUBLICDEF static STBI__ASAN
#define STBSP__PUBLICDEF static STBSP__ASAN
#else
#ifdef __cplusplus
#define STBSP__PUBLICDEC extern "C"
#define STBSP__PUBLICDEF extern "C" STBI__ASAN
#define STBSP__PUBLICDEF extern "C" STBSP__ASAN
#else
#define STBSP__PUBLICDEC extern
#define STBSP__PUBLICDEF STBI__ASAN
#define STBSP__PUBLICDEF STBSP__ASAN
#endif
#endif
#include <stdarg.h> // for va_list()
#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(char *buf, void *user, int len);
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__PUBLICDEF int STB_SPRINTF_DECORATE(vsprintf)(char *buf, char const *fmt, va_list va);
STBSP__PUBLICDEF int STB_SPRINTF_DECORATE(vsnprintf)(char *buf, int count, char const *fmt, va_list va);
STBSP__PUBLICDEF int STB_SPRINTF_DECORATE(sprintf)(char *buf, char const *fmt, ...);
STBSP__PUBLICDEF int STB_SPRINTF_DECORATE(snprintf)(char *buf, int count, char const *fmt, ...);
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);
STBSP__PUBLICDEF int STB_SPRINTF_DECORATE(vsprintfcb)(STBSP_SPRINTFCB *callback, void *user, char *buf, char const *fmt, va_list va);
STBSP__PUBLICDEF void STB_SPRINTF_DECORATE(set_separators)(char comma, char period);
#endif // STB_SPRINTF_H_INCLUDE
// -------------------------------------------------------------------------------------------------
@ -1134,7 +1173,7 @@ DQN_API Dqn_String Dqn_String__InitArenaFmt (Dqn_ArenaAllocator *arena D
#define Dqn_String_InitArenaTaggedFmtV( arena, tag, fmt, ...) Dqn_String__InitArenaFmtV(arena DQN_CALL_SITE(tag), fmt, ## __VA_ARGS__)
#define Dqn_String_InitArenaFmtV( arena, fmt, ...) Dqn_String__InitArenaFmtV(arena DQN_CALL_SITE(""), fmt, ## __VA_ARGS__)
DQN_API Dqn_String Dqn_String__InitArenaFmtV (Dqn_ArenaAllocator *arena DQN_CALL_SITE_ARGS, char const *fmt, va_list va DQN_CALL_SITE_ARGS);
DQN_API Dqn_String Dqn_String__InitArenaFmtV (Dqn_ArenaAllocator *arena, char const *fmt, va_list va DQN_CALL_SITE_ARGS);
DQN_API Dqn_String Dqn_String_Allocate (Dqn_Allocator *allocator, Dqn_isize size, Dqn_ZeroMem zero_mem);
DQN_API Dqn_String Dqn_String_ArenaAllocate (Dqn_ArenaAllocator *arena, Dqn_isize size, Dqn_ZeroMem zero_mem);
@ -1142,7 +1181,11 @@ DQN_API Dqn_b32 Dqn_String_Compare (Dqn_String const lhs, Dqn_S
DQN_API Dqn_b32 Dqn_String_CompareCaseInsensitive(Dqn_String const lhs, Dqn_String const rhs);
// allocator: (Optional) When null, the string is allocated with DQN_MALLOC, result should be freed with DQN_FREE.
DQN_API Dqn_String Dqn_String_Copy (Dqn_String const src, Dqn_Allocator *allocator);
#define Dqn_String_Copy( src, allocator) Dqn_String__Copy(src, allocator DQN_CALL_SITE(""))
#define Dqn_String_ArenaCopy( src, arena) Dqn_String__ArenaCopy(src, arena DQN_CALL_SITE(""))
DQN_API Dqn_String Dqn_String__Copy (Dqn_String const src, Dqn_Allocator *allocator DQN_CALL_SITE_ARGS);
DQN_API Dqn_String Dqn_String__ArenaCopy (Dqn_String const src, Dqn_ArenaAllocator *arena DQN_CALL_SITE_ARGS);
DQN_API Dqn_String Dqn_String_TrimWhitespaceAround (Dqn_String src);
DQN_API Dqn_b32 operator== (Dqn_String const &lhs, Dqn_String const &rhs);
@ -1156,6 +1199,9 @@ DQN_API void Dqn_String_Free (Dqn_String *string, Dqn_Allo
DQN_API Dqn_b32 Dqn_String_StartsWith(Dqn_String string, Dqn_String prefix);
DQN_API Dqn_Slice<Dqn_String> Dqn_String_Split (Dqn_String src, Dqn_Allocator *allocator);
DQN_API Dqn_u64 Dqn_String_ToU64 (Dqn_String str);
DQN_API Dqn_i64 Dqn_String_ToI64 (Dqn_String str);
// -------------------------------------------------------------------------------------------------
//
@ -1552,10 +1598,18 @@ DQN_API Dqn_u64 Dqn_Safe_MulU64 (Dqn_u64 a, Dqn_u64 b);
DQN_API int Dqn_Safe_TruncateISizeToInt (Dqn_isize val);
DQN_API Dqn_i32 Dqn_Safe_TruncateISizeToI32 (Dqn_isize val);
DQN_API Dqn_i8 Dqn_Safe_TruncateISizeToI8 (Dqn_isize val);
DQN_API Dqn_u32 Dqn_Safe_TruncateUSizeToU32 (Dqn_u64 val);
DQN_API Dqn_u32 Dqn_Safe_TruncateUSizeToU32 (Dqn_usize val);
DQN_API int Dqn_Safe_TruncateUSizeToI32 (Dqn_usize val);
DQN_API int Dqn_Safe_TruncateUSizeToInt (Dqn_usize val);
DQN_API Dqn_isize Dqn_Safe_TruncateUSizeToISize(Dqn_usize val);
DQN_API Dqn_u32 Dqn_Safe_TruncateU64ToU32 (Dqn_u64 val);
DQN_API Dqn_u16 Dqn_Safe_TruncateU64ToU16 (Dqn_u64 val);
DQN_API Dqn_u8 Dqn_Safe_TruncateU64ToU8 (Dqn_u64 val);
DQN_API Dqn_i64 Dqn_Safe_TruncateU64ToI64 (Dqn_u64 val);
DQN_API Dqn_i32 Dqn_Safe_TruncateU64ToI32 (Dqn_u64 val);
DQN_API Dqn_i16 Dqn_Safe_TruncateU64ToI16 (Dqn_u64 val);
DQN_API Dqn_i8 Dqn_Safe_TruncateU64ToI8 (Dqn_u64 val);
DQN_API int Dqn_Safe_TruncateU64ToInt (Dqn_u64 val);
// -------------------------------------------------------------------------------------------------
//
@ -1865,6 +1919,7 @@ template <typename T> struct Dqn_Array
template <typename T> DQN_API Dqn_Array<T> Dqn_Array_InitWithMemory (T *memory, Dqn_isize max, Dqn_isize size = 0);
#define Dqn_Array_InitWithAllocatorNoGrow(allocator, Type, max, size, zero_mem) Dqn_Array__InitWithAllocatorNoGrow<Type>(allocator, max, size, zero_mem DQN_CALL_SITE(""))
#define Dqn_Array_InitWithArenaNoGrow( arena, Type, max, size, zero_mem) Dqn_Array__InitWithArenaNoGrow<Type>( arena, max, size, zero_mem DQN_CALL_SITE(""))
#define Dqn_Array_Reserve( array, size) Dqn_Array__Reserve(array, size DQN_CALL_SITE(""))
template <typename T> DQN_API void Dqn_Array_Free (Dqn_Array<T> *a);
@ -2782,6 +2837,14 @@ DQN_API Dqn_Array<T> Dqn_Array__InitWithAllocatorNoGrow(Dqn_Allocator *allocator
return result;
}
template <typename T>
DQN_API Dqn_Array<T> Dqn_Array__InitWithArenaNoGrow(Dqn_ArenaAllocator *arena, Dqn_isize max, Dqn_isize size, Dqn_ZeroMem zero_mem DQN_CALL_SITE_ARGS)
{
T *memory = DQN_CAST(T *)Dqn_ArenaAllocator__Allocate(arena, sizeof(T) * max, alignof(T), zero_mem DQN_CALL_SITE_ARGS_INPUT);
Dqn_Array<T> result = Dqn_Array_InitWithMemory(memory, max, size);
return result;
}
template <typename T>
DQN_API bool Dqn_Array__Reserve(Dqn_Array<T> *a, Dqn_isize size DQN_CALL_SITE_ARGS)
{
@ -3007,7 +3070,7 @@ Dqn_b32 Dqn_List_Iterate(Dqn_List<T> *list, Dqn_ListIterator<T> *iterator)
extern "C" int PathFileExistsA(char const *path);
#endif // !defined(DQN_NO_WIN32_SHWLAPI_H)
#if !defined(DQN_NO_WIN32_WINDOWS_H)
#if !defined(DQN_NO_WIN32_MINIMAL_HEADER)
#pragma comment(lib, "shlwapi.lib")
// Taken from Windows.h
@ -3082,7 +3145,7 @@ Dqn_b32 Dqn_List_Iterate(Dqn_List<T> *list, Dqn_ListIterator<T> *iterator)
//
// NOTE: MultiByteToWideChar
//
#define CP_UTF8 65001 // UTF-8 translation
#define CP_UTF8 65001 // UTF-8 translation
//
// NOTE: FormatMessageA
@ -3110,8 +3173,6 @@ Dqn_b32 Dqn_List_Iterate(Dqn_List<T> *list, Dqn_ListIterator<T> *iterator)
//
extern "C"
{
long _InterlockedExchangeAdd (long volatile *addend, long value);
__int64 _InterlockedExchangeAdd64(__int64 volatile *addend, __int64 value);
BOOL CopyFileA (char const *existing_file_name, char const *new_file_name, BOOL fail_if_exists);
BOOL FreeLibrary (void *lib_module);
BOOL QueryPerformanceCounter (LARGE_INTEGER *performance_count);
@ -3300,9 +3361,9 @@ DQN_API void Dqn_LogV(Dqn_LogType type,
// NOTE: Use the callback version of stb_sprintf to allow us to chunk logs and print arbitrary
// sized format strings without needing to size it up first.
auto stb_vsprintf_callback = [](char *buf, void *user, int len) -> char * {
auto stb_vsprintf_callback = [](char const *buf, void *user, int len) -> char * {
fprintf(DQN_CAST(FILE *)user, "%.*s", len, buf);
return buf;
return DQN_CAST(char *)buf;
};
char stb_buffer[STB_SPRINTF_MIN * 2] = {};
@ -3723,14 +3784,14 @@ DQN_API Dqn_String Dqn_String__InitArenaFmt(Dqn_ArenaAllocator *arena DQN_CALL_S
DQN_API Dqn_String Dqn_String__InitArenaFmtV(Dqn_ArenaAllocator *arena DQN_CALL_SITE_ARGS, char const *fmt, va_list va DQN_CALL_SITE_ARGS)
{
Dqn_Allocator allocator = Dqn_Allocator_InitWithArena(arena);
Dqn_String result = Dqn_String__InitFmtV(&allocator, fmt, va DQN_CALL_SITE_ARGS_INPUT);
Dqn_String result = Dqn_String__InitFmtV(&allocator, fmt, va DQN_CALL_SITE_ARGS_INPUT);
return result;
}
DQN_API Dqn_String Dqn_String_Allocate(Dqn_Allocator *allocator, Dqn_isize size, Dqn_ZeroMem zero_mem)
{
Dqn_String result = {};
result.str = Dqn_Allocator_NewArray(allocator, char, size, zero_mem);
result.str = Dqn_Allocator_NewArray(allocator, char, size + 1, zero_mem);
result.cap = size;
return result;
}
@ -3738,7 +3799,7 @@ DQN_API Dqn_String Dqn_String_Allocate(Dqn_Allocator *allocator, Dqn_isize size,
DQN_API Dqn_String Dqn_String_ArenaAllocate(Dqn_ArenaAllocator *arena, Dqn_isize size, Dqn_ZeroMem zero_mem)
{
Dqn_String result = {};
result.str = Dqn_ArenaAllocator_NewArray(arena, char, size, zero_mem);
result.str = Dqn_ArenaAllocator_NewArray(arena, char, size + 1, zero_mem);
result.cap = size;
return result;
}
@ -3759,13 +3820,23 @@ DQN_API Dqn_b32 Dqn_String_CompareCaseInsensitive(Dqn_String const lhs, Dqn_Stri
return result;
}
#define Dqn_String_Copy(src, allocator) Dqn_String__Copy(src, allocator DQN_CALL_SITE(""))
DQN_API Dqn_String Dqn_String__ArenaCopy(Dqn_String const src, Dqn_ArenaAllocator *arena DQN_CALL_SITE_ARGS)
{
Dqn_String result = src;
result.str = DQN_CAST(char *)Dqn_ArenaAllocator_Allocate(arena, result.size + 1, alignof(char), Dqn_ZeroMem::No DQN_CALL_SITE_ARGS_INPUT);
result.cap = result.size;
DQN_MEMCOPY(result.str, src.str, DQN_CAST(size_t)result.size);
result.str[result.size] = 0;
return result;
}
DQN_API Dqn_String Dqn_String__Copy(Dqn_String const src, Dqn_Allocator *allocator DQN_CALL_SITE_ARGS)
{
Dqn_String result = src;
result.str = allocator ? DQN_CAST(char *)Dqn_Allocator__Allocate(allocator, result.size, alignof(char), Dqn_ZeroMem::No DQN_CALL_SITE_ARGS_INPUT) :
DQN_CAST(char *)DQN_MALLOC(result.size);
result.cap = result.size;
result.str = allocator ? DQN_CAST(char *)Dqn_Allocator__Allocate(allocator, result.size + 1, alignof(char), Dqn_ZeroMem::No DQN_CALL_SITE_ARGS_INPUT) :
DQN_CAST(char *)DQN_MALLOC(result.size + 1);
result.cap = result.size;
result.str[result.size] = 0;
DQN_MEMCOPY(result.str, src.str, DQN_CAST(size_t)result.size);
return result;
}
@ -3877,6 +3948,18 @@ DQN_API Dqn_Slice<Dqn_String> Dqn_String_Split(Dqn_String src, Dqn_Allocator *al
return result;
}
DQN_API Dqn_u64 Dqn_String_ToU64(Dqn_String str)
{
Dqn_u64 result = Dqn_Str_ToU64(str.str, DQN_CAST(int)str.size);
return result;
}
DQN_API Dqn_i64 Dqn_String_ToI64(Dqn_String str)
{
Dqn_i64 result = Dqn_Str_ToI64(str.str, DQN_CAST(int)str.size);
return result;
}
// -------------------------------------------------------------------------------------------------
//
// NOTE: Dqn_ArenaAllocator
@ -4024,11 +4107,11 @@ DQN_API void Dqn_ArenaAllocator_ResetUsage(Dqn_ArenaAllocator *arena, Dqn_ZeroMe
DQN_API Dqn_ArenaAllocatorRegion Dqn_ArenaAllocator_BeginRegion(Dqn_ArenaAllocator *arena)
{
Dqn_ArenaAllocatorRegion result = {};
result.arena = arena;
result.curr_mem_block = arena->curr_mem_block;
result.curr_mem_block_used = (arena->curr_mem_block) ? arena->curr_mem_block->used : 0;
result.top_mem_block = arena->top_mem_block;
Dqn_ArenaAllocatorRegion result = {};
result.arena = arena;
result.curr_mem_block = arena->curr_mem_block;
result.curr_mem_block_used = (arena->curr_mem_block) ? arena->curr_mem_block->used : 0;
result.top_mem_block = arena->top_mem_block;
return result;
}
@ -4629,14 +4712,14 @@ DQN_API Dqn_b32 Dqn_Bit_IsNotSet(Dqn_u64 bits, Dqn_u64 bits_to_check)
// -------------------------------------------------------------------------------------------------
DQN_API Dqn_i64 Dqn_Safe_AddI64(Dqn_i64 a, Dqn_i64 b)
{
DQN_ASSERT_MSG(a <= DQN_I64_MAX - b, "%I64u <= %I64u", a, DQN_I64_MAX - b);
DQN_ASSERT_MSG(a <= DQN_I64_MAX - b, "%I64d <= %I64d", a, DQN_I64_MAX - b);
Dqn_i64 result = (a <= DQN_I64_MAX - b) ? (a + b) : DQN_I64_MAX;
return result;
}
DQN_API Dqn_i64 Dqn_Safe_MulI64(Dqn_i64 a, Dqn_i64 b)
{
DQN_ASSERT_MSG(a <= DQN_I64_MAX / b , "%I64u <= %I64u", a, DQN_I64_MAX / b);
DQN_ASSERT_MSG(a <= DQN_I64_MAX / b , "%I64d <= %I64d", a, DQN_I64_MAX / b);
Dqn_i64 result = (a <= DQN_I64_MAX / b) ? (a * b) : DQN_I64_MAX;
return result;
}
@ -4644,7 +4727,7 @@ DQN_API Dqn_i64 Dqn_Safe_MulI64(Dqn_i64 a, Dqn_i64 b)
DQN_API Dqn_u64 Dqn_Safe_AddU64(Dqn_u64 a, Dqn_u64 b)
{
DQN_ASSERT_MSG(a <= DQN_U64_MAX - b, "%I64u <= %I64u", a, DQN_U64_MAX - b);
Dqn_u64 result = (a <= DQN_U64_MAX / b) ? (a + b) : DQN_U64_MAX;
Dqn_u64 result = (a <= DQN_U64_MAX - b) ? (a + b) : DQN_U64_MAX;
return result;
}
@ -4657,7 +4740,7 @@ DQN_API Dqn_u64 Dqn_Safe_SubU64(Dqn_u64 a, Dqn_u64 b)
DQN_API Dqn_u32 Dqn_Safe_SubU32(Dqn_u32 a, Dqn_u32 b)
{
DQN_ASSERT_MSG(a >= b, "%I64u >= %I64u", a, b);
DQN_ASSERT_MSG(a >= b, "%I32u >= %I32u", a, b);
Dqn_u32 result = (a >= b) ? (a - b) : 0;
return result;
}
@ -4671,47 +4754,103 @@ DQN_API Dqn_u64 Dqn_Safe_MulU64(Dqn_u64 a, Dqn_u64 b)
DQN_API int Dqn_Safe_TruncateISizeToInt(Dqn_isize val)
{
DQN_ASSERT_MSG(val >= DQN_I32_MIN && val <= DQN_I32_MAX, "%I64d >= %I64d && %I64d <= %I64d", val, DQN_I32_MAX, val, DQN_I32_MAX);
DQN_ASSERT_MSG(val >= DQN_I32_MIN && val <= DQN_I32_MAX, "%zd >= %zd && %zd <= %zd", val, DQN_I32_MAX, val, DQN_I32_MAX);
auto result = (val >= DQN_I32_MIN && val <= DQN_I32_MAX) ? DQN_CAST(int)val : 0;
return result;
}
DQN_API Dqn_i32 Dqn_Safe_TruncateISizeToI32(Dqn_isize val)
{
DQN_ASSERT_MSG(val >= DQN_I32_MIN && val <= DQN_I32_MAX, "%I64d >= %I64d && %I64d <= %I64d", val, DQN_I32_MIN, val, DQN_I32_MAX);
DQN_ASSERT_MSG(val >= DQN_I32_MIN && val <= DQN_I32_MAX, "%zd >= %zd && %zd <= %zd", val, DQN_I32_MIN, val, DQN_I32_MAX);
auto result = (val >= DQN_I32_MIN && val <= DQN_I32_MAX) ? DQN_CAST(Dqn_i32)val : 0;
return result;
}
DQN_API Dqn_u32 Dqn_Safe_TruncateUSizeToU32(Dqn_u64 val)
DQN_API Dqn_u32 Dqn_Safe_TruncateUSizeToU32(Dqn_usize val)
{
DQN_ASSERT_MSG(val <= DQN_U32_MAX, "%I64u <= %I64u", val, DQN_U32_MAX);
DQN_ASSERT_MSG(val <= DQN_U32_MAX, "%zu <= %zu", val, DQN_U32_MAX);
auto result = (val <= DQN_U32_MAX) ? DQN_CAST(Dqn_u32)val : DQN_U32_MAX;
return result;
}
DQN_API Dqn_i32 Dqn_Safe_TruncateUSizeToI32(Dqn_usize val)
{
DQN_ASSERT_MSG(val <= DQN_I32_MAX, "%I64u <= %I64d", val, DQN_I32_MAX);
DQN_ASSERT_MSG(val <= DQN_I32_MAX, "%zu <= %zu", val, DQN_I32_MAX);
auto result = (val <= DQN_I32_MAX) ? DQN_CAST(int)val : DQN_I32_MAX;
return result;
}
DQN_API int Dqn_Safe_TruncateUSizeToInt(Dqn_usize val)
{
DQN_ASSERT_MSG(val <= DQN_I32_MAX, "%I64u <= %I64d", val, DQN_I32_MAX);
DQN_ASSERT_MSG(val <= DQN_I32_MAX, "%zu <= %zu", val, DQN_I32_MAX);
auto result = (val <= DQN_I32_MAX) ? DQN_CAST(int)val : DQN_I32_MAX;
return result;
}
DQN_API Dqn_isize Dqn_Safe_TruncateUSizeToISize(Dqn_usize val)
{
DQN_ASSERT_MSG(val <= DQN_ISIZE_MAX, "%I64u <= %I64u", val, DQN_CAST(Dqn_usize)DQN_ISIZE_MAX);
DQN_ASSERT_MSG(val <= DQN_ISIZE_MAX, "%zu <= %zu", val, DQN_CAST(Dqn_usize)DQN_ISIZE_MAX);
auto result = (val <= DQN_ISIZE_MAX) ? DQN_CAST(Dqn_isize)val : DQN_ISIZE_MAX;
return result;
}
DQN_API Dqn_u32 Dqn_Safe_TruncateU64ToU32(Dqn_u64 val)
{
DQN_ASSERT_MSG(val <= DQN_U32_MAX, "%I64u <= %I64u", val, DQN_U32_MAX);
auto result = (val <= DQN_U32_MAX) ? DQN_CAST(Dqn_u32)val : DQN_U32_MAX;
return result;
}
DQN_API Dqn_u16 Dqn_Safe_TruncateU64ToU16(Dqn_u64 val)
{
DQN_ASSERT_MSG(val <= DQN_U16_MAX, "%I64u <= %I64u", val, DQN_U16_MAX);
auto result = (val <= DQN_U16_MAX) ? DQN_CAST(Dqn_u16)val : DQN_U16_MAX;
return result;
}
DQN_API Dqn_u8 Dqn_Safe_TruncateU64ToU8(Dqn_u64 val)
{
DQN_ASSERT_MSG(val <= DQN_U8_MAX, "%I64u <= %I64u", val, DQN_U8_MAX);
auto result = (val <= DQN_U8_MAX) ? DQN_CAST(Dqn_u8)val : DQN_U8_MAX;
return result;
}
DQN_API Dqn_i64 Dqn_Safe_TruncateU64ToI64(Dqn_u64 val)
{
DQN_ASSERT_MSG(val <= DQN_I64_MAX, "%I64u <= %I64d", val, DQN_I64_MAX);
auto result = (val <= DQN_I64_MAX) ? DQN_CAST(Dqn_i64)val : DQN_I64_MAX;
return result;
}
DQN_API Dqn_i32 Dqn_Safe_TruncateU64ToI32(Dqn_u64 val)
{
DQN_ASSERT_MSG(val <= DQN_I32_MAX, "%I64u <= %I64d", val, DQN_I32_MAX);
auto result = (val <= DQN_I32_MAX) ? DQN_CAST(Dqn_i32)val : DQN_I32_MAX;
return result;
}
DQN_API Dqn_i16 Dqn_Safe_TruncateU64ToI16(Dqn_u64 val)
{
DQN_ASSERT_MSG(val <= DQN_I16_MAX, "%I64u <= %I64d", val, DQN_I16_MAX);
auto result = (val <= DQN_I16_MAX) ? DQN_CAST(Dqn_i16)val : DQN_I16_MAX;
return result;
}
DQN_API Dqn_i8 Dqn_Safe_TruncateU64ToI8(Dqn_u64 val)
{
DQN_ASSERT_MSG(val <= DQN_I8_MAX, "%I64u <= %I64d", val, DQN_I8_MAX);
auto result = (val <= DQN_I8_MAX) ? DQN_CAST(Dqn_i8)val : DQN_I8_MAX;
return result;
}
DQN_API int Dqn_Safe_TruncateU64ToInt(Dqn_u64 val)
{
DQN_ASSERT_MSG(val <= DQN_I32_MAX, "%I64u <= %I64d", val, DQN_I32_MAX);
auto result = (val <= DQN_I32_MAX) ? DQN_CAST(int)val : DQN_I32_MAX;
return result;
}
// -------------------------------------------------------------------------------------------------
//
// NOTE: Dqn_Char
@ -5697,7 +5836,6 @@ DQN_API Dqn_MurmurHash3_128 Dqn_MurmurHash3_x64_128(void const *key, int len, Dq
#endif // DQN_IMPLEMENTATION
#ifdef STB_SPRINTF_IMPLEMENTATION
#include <stdlib.h> // for va_arg()
#define stbsp__uint32 unsigned int
#define stbsp__int32 signed int
@ -5712,7 +5850,7 @@ DQN_API Dqn_MurmurHash3_128 Dqn_MurmurHash3_x64_128(void const *key, int len, Dq
#define stbsp__uint16 unsigned short
#ifndef stbsp__uintptr
#if defined(__ppc64__) || defined(__aarch64__) || defined(_M_X64) || defined(__x86_64__) || defined(__x86_64)
#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
@ -5740,9 +5878,18 @@ static stbsp__int32 stbsp__real_to_parts(stbsp__int64 *bits, stbsp__int32 *expo,
static char stbsp__period = '.';
static char stbsp__comma = ',';
static char stbsp__digitpair[201] =
"0001020304050607080910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576"
"7778798081828384858687888990919293949596979899";
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)
{
@ -5779,6 +5926,46 @@ static void stbsp__lead_sign(stbsp__uint32 fl, char *sign)
}
}
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";
@ -5848,7 +6035,17 @@ STBSP__PUBLICDEF int STB_SPRINTF_DECORATE(vsprintfcb)(STBSP_SPRINTFCB *callback,
if (callback)
if ((STB_SPRINTF_MIN - (int)(bf - buf)) < 4)
goto schk1;
*(stbsp__uint32 *)bf = v;
#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;
}
@ -5950,9 +6147,12 @@ STBSP__PUBLICDEF int STB_SPRINTF_DECORATE(vsprintfcb)(STBSP_SPRINTFCB *callback,
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;
@ -5961,13 +6161,16 @@ STBSP__PUBLICDEF int STB_SPRINTF_DECORATE(vsprintfcb)(STBSP_SPRINTFCB *callback,
break;
// are we 64-bit on intmax? (c99)
case 'j':
fl |= STBSP__INTMAX;
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(char *) == 8) ? STBSP__INTMAX : 0);
fl |= (sizeof(ptrdiff_t) == 8) ? STBSP__INTMAX : 0;
++f;
break;
// are we 64-bit (msft style)
@ -6006,37 +6209,9 @@ STBSP__PUBLICDEF int STB_SPRINTF_DECORATE(vsprintfcb)(STBSP_SPRINTFCB *callback,
s = va_arg(va, char *);
if (s == 0)
s = (char *)"null";
// get the length
sn = s;
for (;;) {
if ((((stbsp__uintptr)sn) & 3) == 0)
break;
lchk:
if (sn[0] == 0)
goto ld;
++sn;
}
n = 0xffffffff;
if (pr >= 0) {
n = (stbsp__uint32)(sn - s);
if (n >= (stbsp__uint32)pr)
goto ld;
n = ((stbsp__uint32)(pr - n)) >> 2;
}
while (n) {
stbsp__uint32 v = *(stbsp__uint32 *)sn;
if ((v - 0x01010101) & (~v) & 0x80808080UL)
goto lchk;
sn += 4;
--n;
}
goto lchk;
ld:
l = (stbsp__uint32)(sn - s);
// clamp to precision
if (l > (stbsp__uint32)pr)
l = pr;
// 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;
@ -6077,8 +6252,8 @@ STBSP__PUBLICDEF int STB_SPRINTF_DECORATE(vsprintfcb)(STBSP_SPRINTFCB *callback,
lead[0] = 0;
tail[0] = 0;
pr = 0;
dp = 0;
cs = 0;
STBSP__NOTUSED(dp);
goto scopy;
#else
case 'A': // hex float
@ -6182,11 +6357,11 @@ STBSP__PUBLICDEF int STB_SPRINTF_DECORATE(vsprintfcb)(STBSP_SPRINTFCB *callback,
--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 sematics for %f
// 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) ? l : pr);
pr = -dp + ((pr > (stbsp__int32)l) ? (stbsp__int32) l : pr);
}
goto dofloatfromg;
@ -6473,7 +6648,7 @@ STBSP__PUBLICDEF int STB_SPRINTF_DECORATE(vsprintfcb)(STBSP_SPRINTFCB *callback,
lead[0] = 0;
if (pr == 0) {
l = 0;
cs = (((l >> 4) & 15)) << 24;
cs = 0;
goto scopy;
}
}
@ -6546,7 +6721,7 @@ STBSP__PUBLICDEF int STB_SPRINTF_DECORATE(vsprintfcb)(STBSP_SPRINTFCB *callback,
if ((fl & STBSP__TRIPLET_COMMA) == 0) {
do {
s -= 2;
*(stbsp__uint16 *)s = *(stbsp__uint16 *)&stbsp__digitpair[(n % 100) * 2];
*(stbsp__uint16 *)s = *(stbsp__uint16 *)&stbsp__digitpair.pair[(n % 100) * 2];
n /= 100;
} while (n);
}
@ -6701,7 +6876,7 @@ STBSP__PUBLICDEF int STB_SPRINTF_DECORATE(vsprintfcb)(STBSP_SPRINTFCB *callback,
stbsp__cb_buf_clamp(i, n);
n -= i;
STBSP__UNALIGNED(while (i >= 4) {
*(stbsp__uint32 *)bf = *(stbsp__uint32 *)s;
*(stbsp__uint32 volatile *)bf = *(stbsp__uint32 volatile *)s;
bf += 4;
s += 4;
i -= 4;
@ -6831,19 +7006,22 @@ STBSP__PUBLICDEF int STB_SPRINTF_DECORATE(sprintf)(char *buf, char const *fmt, .
typedef struct stbsp__context {
char *buf;
int count;
int length;
char tmp[STB_SPRINTF_MIN];
} stbsp__context;
static char *stbsp__clamp_callback(char *buf, void *user, int len)
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) {
char *s, *d, *se;
const char *s, *se;
char *d;
d = c->buf;
s = buf;
se = buf + len;
@ -6856,38 +7034,36 @@ static char *stbsp__clamp_callback(char *buf, void *user, int len)
}
if (c->count <= 0)
return 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( char * buf, void * user, int len )
static char * stbsp__count_clamp_callback( const char * buf, void * user, int len )
{
(void)buf;
stbsp__context * c = (stbsp__context*)user;
(void) sizeof(buf);
c->count += len;
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;
int l;
if ( (count == 0) && !buf )
{
c.count = 0;
c.length = 0;
STB_SPRINTF_DECORATE( vsprintfcb )( stbsp__count_clamp_callback, &c, c.tmp, fmt, va );
l = c.count;
}
else
{
if ( count == 0 )
return 0;
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 );
@ -6898,7 +7074,7 @@ STBSP__PUBLICDEF int STB_SPRINTF_DECORATE( vsnprintf )( char * buf, int count, c
buf[l] = 0;
}
return l;
return c.length;
}
STBSP__PUBLICDEF int STB_SPRINTF_DECORATE(snprintf)(char *buf, int count, char const *fmt, ...)
@ -6945,7 +7121,7 @@ static stbsp__int32 stbsp__real_to_parts(stbsp__int64 *bits, stbsp__int32 *expo,
*bits = b & ((((stbsp__uint64)1) << 52) - 1);
*expo = (stbsp__int32)(((b >> 52) & 2047) - 1023);
return (stbsp__int32)(b >> 63);
return (stbsp__int32)((stbsp__uint64) b >> 63);
}
static double const stbsp__bot[23] = {
@ -7059,7 +7235,7 @@ static stbsp__uint64 const stbsp__powten[20] = {
#define stbsp__ddtoS64(ob, xh, xl) \
{ \
double ahi = 0, alo, vh, t; \
ob = (stbsp__int64)ph; \
ob = (stbsp__int64)xh; \
vh = (double)ob; \
ahi = (xh - vh); \
t = (ahi - xh); \
@ -7155,7 +7331,7 @@ static stbsp__int32 stbsp__real_to_str(char const **start, stbsp__uint32 *len, c
d = value;
STBSP__COPYFP(bits, d);
expo = (stbsp__int32)((bits >> 52) & 2047);
ng = (stbsp__int32)(bits >> 63);
ng = (stbsp__int32)((stbsp__uint64) bits >> 63);
if (ng)
d = -d;
@ -7169,7 +7345,7 @@ static stbsp__int32 stbsp__real_to_str(char const **start, stbsp__uint32 *len, c
if (expo == 0) // is zero or denormal
{
if ((bits << 1) == 0) // do zero
if (((stbsp__uint64) bits << 1) == 0) // do zero
{
*decimal_pos = 1;
*start = out;
@ -7265,7 +7441,7 @@ static stbsp__int32 stbsp__real_to_str(char const **start, stbsp__uint32 *len, c
}
while (n) {
out -= 2;
*(stbsp__uint16 *)out = *(stbsp__uint16 *)&stbsp__digitpair[(n % 100) * 2];
*(stbsp__uint16 *)out = *(stbsp__uint16 *)&stbsp__digitpair.pair[(n % 100) * 2];
n /= 100;
e += 2;
}

File diff suppressed because it is too large Load Diff