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 // NOTE: Library Config
//
// ------------------------------------------------------------------------------------------------- // -------------------------------------------------------------------------------------------------
/* /*
Dqn library logs errors and outputs through Dqn_Log(...). This is 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_OS_WIN32)
#if !defined(DQN_NO_WIN32_WINDOWS_H) #if !defined(DQN_NO_WIN32_MINIMAL_HEADER)
// Taken from Windows.h // Taken from Windows.h
typedef unsigned long DWORD; typedef unsigned long DWORD;
typedef unsigned short WORD; typedef unsigned short WORD;
@ -515,12 +519,12 @@ void Dqn_TicketMutex_Begin (Dqn_TicketMutex *mutex);
void Dqn_TicketMutex_End (Dqn_TicketMutex *mutex); void Dqn_TicketMutex_End (Dqn_TicketMutex *mutex);
// NOTE: Advance API, more granular functions, the basic sequence to use the API is // NOTE: Advance API, more granular functions, the basic sequence to use the API is
/* #if 0
Dqn_TicketMutex mutex = {}; Dqn_TicketMutex mutex = {};
unsigned int ticket = Dqn_TicketMutex_MakeTicket(&mutex); unsigned int ticket = Dqn_TicketMutex_MakeTicket(&mutex);
Dqn_TicketMutex_BeginTicket(&mutex, ticket); // Blocking call until we attain the lock Dqn_TicketMutex_BeginTicket(&mutex, ticket); // Blocking call until we attain the lock
Dqn_TicketMutex_End(&mutex); Dqn_TicketMutex_End(&mutex);
*/ #endif
unsigned int Dqn_TicketMutex_MakeTicket (Dqn_TicketMutex *mutex); unsigned int Dqn_TicketMutex_MakeTicket (Dqn_TicketMutex *mutex);
void Dqn_TicketMutex_BeginTicket (const Dqn_TicketMutex *mutex, unsigned int ticket); void Dqn_TicketMutex_BeginTicket (const Dqn_TicketMutex *mutex, unsigned int ticket);
Dqn_b32 Dqn_TicketMutex_CanLock (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 // 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 // originally by Jeff Roberts / RAD Game Tools, 2015/10/20
// http://github.com/nothings/stb // http://github.com/nothings/stb
// //
// allowed types: sc uidBboXx p AaGgEef n // 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: // Contributors:
// Fabian "ryg" Giesen (reformatting) // Fabian "ryg" Giesen (reformatting)
// github:aganm (attribute format)
// //
// Contributors (bugfixes): // Contributors (bugfixes):
// github:d26435 // github:d26435
// github:trex78 // github:trex78
// github:account-login
// Jari Komppa (SI suffixes) // Jari Komppa (SI suffixes)
// Rohit Nirmal // Rohit Nirmal
// Marcin Wojdyr // Marcin Wojdyr
// Leonard Ritter // Leonard Ritter
// Stefano Zanotti
// Adam Allison
// Arvid Gerstmann
// Markus Kolb
// //
// LICENSE: // LICENSE:
// //
@ -624,8 +634,6 @@ doesn't either).
If you don't need float or doubles at all, define STB_SPRINTF_NOFLOAT If you don't need float or doubles at all, define STB_SPRINTF_NOFLOAT
and you'll save 4K of code space. and you'll save 4K of code space.
64-BIT INTS: 64-BIT INTS:
============ ============
This library also supports 64-bit integers and you can use MSVC style or 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!) "...512 char string..." ( 35.0x/32.5x faster!)
*/ */
#if defined(__has_feature) #if defined(__clang__)
#if defined(__has_feature) && defined(__has_attribute)
#if __has_feature(address_sanitizer) #if __has_feature(address_sanitizer)
#define STBI__ASAN __attribute__((no_sanitize("address"))) #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 #endif
#ifndef STBI__ASAN #endif
#define STBI__ASAN #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 #endif
#ifdef STB_SPRINTF_STATIC #ifdef STB_SPRINTF_STATIC
#define STBSP__PUBLICDEC static #define STBSP__PUBLICDEC static
#define STBSP__PUBLICDEF static STBI__ASAN #define STBSP__PUBLICDEF static STBSP__ASAN
#else #else
#ifdef __cplusplus #ifdef __cplusplus
#define STBSP__PUBLICDEC extern "C" #define STBSP__PUBLICDEC extern "C"
#define STBSP__PUBLICDEF extern "C" STBI__ASAN #define STBSP__PUBLICDEF extern "C" STBSP__ASAN
#else #else
#define STBSP__PUBLICDEC extern #define STBSP__PUBLICDEC extern
#define STBSP__PUBLICDEF STBI__ASAN #define STBSP__PUBLICDEF STBSP__ASAN
#endif #endif
#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 #ifndef STB_SPRINTF_MIN
#define STB_SPRINTF_MIN 512 // how many characters per callback #define STB_SPRINTF_MIN 512 // how many characters per callback
#endif #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 #ifndef STB_SPRINTF_DECORATE
#define STB_SPRINTF_DECORATE(name) stbsp_##name // define this before including if you want to change the names #define STB_SPRINTF_DECORATE(name) stbsp_##name // define this before including if you want to change the names
#endif #endif
STBSP__PUBLICDEF int STB_SPRINTF_DECORATE(vsprintf)(char *buf, char const *fmt, va_list va); STBSP__PUBLICDEC 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__PUBLICDEC 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__PUBLICDEC int STB_SPRINTF_DECORATE(sprintf)(char *buf, char const *fmt, ...) STBSP__ATTRIBUTE_FORMAT(2,3);
STBSP__PUBLICDEF int STB_SPRINTF_DECORATE(snprintf)(char *buf, int count, char const *fmt, ...); 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 #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_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__) #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_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); 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); 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. // 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_String Dqn_String_TrimWhitespaceAround (Dqn_String src);
DQN_API Dqn_b32 operator== (Dqn_String const &lhs, Dqn_String const &rhs); 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_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_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 int Dqn_Safe_TruncateISizeToInt (Dqn_isize val);
DQN_API Dqn_i32 Dqn_Safe_TruncateISizeToI32 (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_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_TruncateUSizeToI32 (Dqn_usize val);
DQN_API int Dqn_Safe_TruncateUSizeToInt (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_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); 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_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("")) #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); 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; 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> template <typename T>
DQN_API bool Dqn_Array__Reserve(Dqn_Array<T> *a, Dqn_isize size DQN_CALL_SITE_ARGS) 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); extern "C" int PathFileExistsA(char const *path);
#endif // !defined(DQN_NO_WIN32_SHWLAPI_H) #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") #pragma comment(lib, "shlwapi.lib")
// Taken from Windows.h // Taken from Windows.h
@ -3110,8 +3173,6 @@ Dqn_b32 Dqn_List_Iterate(Dqn_List<T> *list, Dqn_ListIterator<T> *iterator)
// //
extern "C" 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 CopyFileA (char const *existing_file_name, char const *new_file_name, BOOL fail_if_exists);
BOOL FreeLibrary (void *lib_module); BOOL FreeLibrary (void *lib_module);
BOOL QueryPerformanceCounter (LARGE_INTEGER *performance_count); 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 // 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. // 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); fprintf(DQN_CAST(FILE *)user, "%.*s", len, buf);
return buf; return DQN_CAST(char *)buf;
}; };
char stb_buffer[STB_SPRINTF_MIN * 2] = {}; char stb_buffer[STB_SPRINTF_MIN * 2] = {};
@ -3730,7 +3791,7 @@ DQN_API Dqn_String Dqn_String__InitArenaFmtV(Dqn_ArenaAllocator *arena DQN_CALL_
DQN_API Dqn_String Dqn_String_Allocate(Dqn_Allocator *allocator, Dqn_isize size, Dqn_ZeroMem zero_mem) DQN_API Dqn_String Dqn_String_Allocate(Dqn_Allocator *allocator, Dqn_isize size, Dqn_ZeroMem zero_mem)
{ {
Dqn_String result = {}; 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; result.cap = size;
return result; 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_API Dqn_String Dqn_String_ArenaAllocate(Dqn_ArenaAllocator *arena, Dqn_isize size, Dqn_ZeroMem zero_mem)
{ {
Dqn_String result = {}; 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; result.cap = size;
return result; return result;
} }
@ -3759,13 +3820,23 @@ DQN_API Dqn_b32 Dqn_String_CompareCaseInsensitive(Dqn_String const lhs, Dqn_Stri
return result; 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_API Dqn_String Dqn_String__Copy(Dqn_String const src, Dqn_Allocator *allocator DQN_CALL_SITE_ARGS)
{ {
Dqn_String result = src; 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) : 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); DQN_CAST(char *)DQN_MALLOC(result.size + 1);
result.cap = result.size; result.cap = result.size;
result.str[result.size] = 0;
DQN_MEMCOPY(result.str, src.str, DQN_CAST(size_t)result.size); DQN_MEMCOPY(result.str, src.str, DQN_CAST(size_t)result.size);
return result; return result;
} }
@ -3877,6 +3948,18 @@ DQN_API Dqn_Slice<Dqn_String> Dqn_String_Split(Dqn_String src, Dqn_Allocator *al
return result; 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 // NOTE: Dqn_ArenaAllocator
@ -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_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; Dqn_i64 result = (a <= DQN_I64_MAX - b) ? (a + b) : DQN_I64_MAX;
return result; return result;
} }
DQN_API Dqn_i64 Dqn_Safe_MulI64(Dqn_i64 a, Dqn_i64 b) 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; Dqn_i64 result = (a <= DQN_I64_MAX / b) ? (a * b) : DQN_I64_MAX;
return result; 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_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_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; 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_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; Dqn_u32 result = (a >= b) ? (a - b) : 0;
return result; 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_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; auto result = (val >= DQN_I32_MIN && val <= DQN_I32_MAX) ? DQN_CAST(int)val : 0;
return result; return result;
} }
DQN_API Dqn_i32 Dqn_Safe_TruncateISizeToI32(Dqn_isize val) 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; auto result = (val >= DQN_I32_MIN && val <= DQN_I32_MAX) ? DQN_CAST(Dqn_i32)val : 0;
return result; 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; auto result = (val <= DQN_U32_MAX) ? DQN_CAST(Dqn_u32)val : DQN_U32_MAX;
return result; return result;
} }
DQN_API Dqn_i32 Dqn_Safe_TruncateUSizeToI32(Dqn_usize val) 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; auto result = (val <= DQN_I32_MAX) ? DQN_CAST(int)val : DQN_I32_MAX;
return result; return result;
} }
DQN_API int Dqn_Safe_TruncateUSizeToInt(Dqn_usize val) 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; auto result = (val <= DQN_I32_MAX) ? DQN_CAST(int)val : DQN_I32_MAX;
return result; return result;
} }
DQN_API Dqn_isize Dqn_Safe_TruncateUSizeToISize(Dqn_usize val) 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; auto result = (val <= DQN_ISIZE_MAX) ? DQN_CAST(Dqn_isize)val : DQN_ISIZE_MAX;
return result; 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 // 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 #endif // DQN_IMPLEMENTATION
#ifdef STB_SPRINTF_IMPLEMENTATION #ifdef STB_SPRINTF_IMPLEMENTATION
#include <stdlib.h> // for va_arg()
#define stbsp__uint32 unsigned int #define stbsp__uint32 unsigned int
#define stbsp__int32 signed 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 #define stbsp__uint16 unsigned short
#ifndef stbsp__uintptr #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 #define stbsp__uintptr stbsp__uint64
#else #else
#define stbsp__uintptr stbsp__uint32 #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__period = '.';
static char stbsp__comma = ','; static char stbsp__comma = ',';
static char stbsp__digitpair[201] = static struct
"0001020304050607080910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576" {
"7778798081828384858687888990919293949596979899"; short temp; // force next field to be 2-byte aligned
char pair[201];
} stbsp__digitpair =
{
0,
"00010203040506070809101112131415161718192021222324"
"25262728293031323334353637383940414243444546474849"
"50515253545556575859606162636465666768697071727374"
"75767778798081828384858687888990919293949596979899"
};
STBSP__PUBLICDEF void STB_SPRINTF_DECORATE(set_separators)(char pcomma, char pperiod) STBSP__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) STBSP__PUBLICDEF int STB_SPRINTF_DECORATE(vsprintfcb)(STBSP_SPRINTFCB *callback, void *user, char *buf, char const *fmt, va_list va)
{ {
static char hex[] = "0123456789abcdefxp"; static char hex[] = "0123456789abcdefxp";
@ -5848,7 +6035,17 @@ STBSP__PUBLICDEF int STB_SPRINTF_DECORATE(vsprintfcb)(STBSP_SPRINTFCB *callback,
if (callback) if (callback)
if ((STB_SPRINTF_MIN - (int)(bf - buf)) < 4) if ((STB_SPRINTF_MIN - (int)(bf - buf)) < 4)
goto schk1; goto schk1;
#ifdef STB_SPRINTF_NOUNALIGNED
if(((stbsp__uintptr)bf) & 3) {
bf[0] = f[0];
bf[1] = f[1];
bf[2] = f[2];
bf[3] = f[3];
} else
#endif
{
*(stbsp__uint32 *)bf = v; *(stbsp__uint32 *)bf = v;
}
bf += 4; bf += 4;
f += 4; f += 4;
} }
@ -5950,9 +6147,12 @@ STBSP__PUBLICDEF int STB_SPRINTF_DECORATE(vsprintfcb)(STBSP_SPRINTFCB *callback,
case 'h': case 'h':
fl |= STBSP__HALFWIDTH; fl |= STBSP__HALFWIDTH;
++f; ++f;
if (f[0] == 'h')
++f; // QUARTERWIDTH
break; break;
// are we 64-bit (unix style) // are we 64-bit (unix style)
case 'l': case 'l':
fl |= ((sizeof(long) == 8) ? STBSP__INTMAX : 0);
++f; ++f;
if (f[0] == 'l') { if (f[0] == 'l') {
fl |= STBSP__INTMAX; fl |= STBSP__INTMAX;
@ -5961,13 +6161,16 @@ STBSP__PUBLICDEF int STB_SPRINTF_DECORATE(vsprintfcb)(STBSP_SPRINTFCB *callback,
break; break;
// are we 64-bit on intmax? (c99) // are we 64-bit on intmax? (c99)
case 'j': case 'j':
fl |= STBSP__INTMAX; fl |= (sizeof(size_t) == 8) ? STBSP__INTMAX : 0;
++f; ++f;
break; break;
// are we 64-bit on size_t or ptrdiff_t? (c99) // are we 64-bit on size_t or ptrdiff_t? (c99)
case 'z': case 'z':
fl |= (sizeof(ptrdiff_t) == 8) ? STBSP__INTMAX : 0;
++f;
break;
case 't': case 't':
fl |= ((sizeof(char *) == 8) ? STBSP__INTMAX : 0); fl |= (sizeof(ptrdiff_t) == 8) ? STBSP__INTMAX : 0;
++f; ++f;
break; break;
// are we 64-bit (msft style) // 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 *); s = va_arg(va, char *);
if (s == 0) if (s == 0)
s = (char *)"null"; s = (char *)"null";
// get the length // get the length, limited to desired precision
sn = s; // always limit to ~0u chars since our counts are 32b
for (;;) { l = stbsp__strlen_limited(s, (pr >= 0) ? pr : ~0u);
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;
lead[0] = 0; lead[0] = 0;
tail[0] = 0; tail[0] = 0;
pr = 0; pr = 0;
@ -6077,8 +6252,8 @@ STBSP__PUBLICDEF int STB_SPRINTF_DECORATE(vsprintfcb)(STBSP_SPRINTFCB *callback,
lead[0] = 0; lead[0] = 0;
tail[0] = 0; tail[0] = 0;
pr = 0; pr = 0;
dp = 0;
cs = 0; cs = 0;
STBSP__NOTUSED(dp);
goto scopy; goto scopy;
#else #else
case 'A': // hex float 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 --pr; // when using %e, there is one digit before the decimal
goto doexpfromg; 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) { if (dp > 0) {
pr = (dp < (stbsp__int32)l) ? l - dp : 0; pr = (dp < (stbsp__int32)l) ? l - dp : 0;
} else { } else {
pr = -dp + ((pr > (stbsp__int32)l) ? l : pr); pr = -dp + ((pr > (stbsp__int32)l) ? (stbsp__int32) l : pr);
} }
goto dofloatfromg; goto dofloatfromg;
@ -6473,7 +6648,7 @@ STBSP__PUBLICDEF int STB_SPRINTF_DECORATE(vsprintfcb)(STBSP_SPRINTFCB *callback,
lead[0] = 0; lead[0] = 0;
if (pr == 0) { if (pr == 0) {
l = 0; l = 0;
cs = (((l >> 4) & 15)) << 24; cs = 0;
goto scopy; goto scopy;
} }
} }
@ -6546,7 +6721,7 @@ STBSP__PUBLICDEF int STB_SPRINTF_DECORATE(vsprintfcb)(STBSP_SPRINTFCB *callback,
if ((fl & STBSP__TRIPLET_COMMA) == 0) { if ((fl & STBSP__TRIPLET_COMMA) == 0) {
do { do {
s -= 2; 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; n /= 100;
} while (n); } while (n);
} }
@ -6701,7 +6876,7 @@ STBSP__PUBLICDEF int STB_SPRINTF_DECORATE(vsprintfcb)(STBSP_SPRINTFCB *callback,
stbsp__cb_buf_clamp(i, n); stbsp__cb_buf_clamp(i, n);
n -= i; n -= i;
STBSP__UNALIGNED(while (i >= 4) { STBSP__UNALIGNED(while (i >= 4) {
*(stbsp__uint32 *)bf = *(stbsp__uint32 *)s; *(stbsp__uint32 volatile *)bf = *(stbsp__uint32 volatile *)s;
bf += 4; bf += 4;
s += 4; s += 4;
i -= 4; i -= 4;
@ -6831,19 +7006,22 @@ STBSP__PUBLICDEF int STB_SPRINTF_DECORATE(sprintf)(char *buf, char const *fmt, .
typedef struct stbsp__context { typedef struct stbsp__context {
char *buf; char *buf;
int count; int count;
int length;
char tmp[STB_SPRINTF_MIN]; char tmp[STB_SPRINTF_MIN];
} stbsp__context; } 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; stbsp__context *c = (stbsp__context *)user;
c->length += len;
if (len > c->count) if (len > c->count)
len = c->count; len = c->count;
if (len) { if (len) {
if (buf != c->buf) { if (buf != c->buf) {
char *s, *d, *se; const char *s, *se;
char *d;
d = c->buf; d = c->buf;
s = buf; s = buf;
se = buf + len; se = buf + len;
@ -6856,38 +7034,36 @@ static char *stbsp__clamp_callback(char *buf, void *user, int len)
} }
if (c->count <= 0) 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 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; 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 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__PUBLICDEF int STB_SPRINTF_DECORATE( vsnprintf )( char * buf, int count, char const * fmt, va_list va )
{ {
stbsp__context c; stbsp__context c;
int l;
if ( (count == 0) && !buf ) if ( (count == 0) && !buf )
{ {
c.count = 0; c.length = 0;
STB_SPRINTF_DECORATE( vsprintfcb )( stbsp__count_clamp_callback, &c, c.tmp, fmt, va ); STB_SPRINTF_DECORATE( vsprintfcb )( stbsp__count_clamp_callback, &c, c.tmp, fmt, va );
l = c.count;
} }
else else
{ {
if ( count == 0 ) int l;
return 0;
c.buf = buf; c.buf = buf;
c.count = count; c.count = count;
c.length = 0;
STB_SPRINTF_DECORATE( vsprintfcb )( stbsp__clamp_callback, &c, stbsp__clamp_callback(0,&c,0), fmt, va ); 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; buf[l] = 0;
} }
return l; return c.length;
} }
STBSP__PUBLICDEF int STB_SPRINTF_DECORATE(snprintf)(char *buf, int count, char const *fmt, ...) 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); *bits = b & ((((stbsp__uint64)1) << 52) - 1);
*expo = (stbsp__int32)(((b >> 52) & 2047) - 1023); *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] = { static double const stbsp__bot[23] = {
@ -7059,7 +7235,7 @@ static stbsp__uint64 const stbsp__powten[20] = {
#define stbsp__ddtoS64(ob, xh, xl) \ #define stbsp__ddtoS64(ob, xh, xl) \
{ \ { \
double ahi = 0, alo, vh, t; \ double ahi = 0, alo, vh, t; \
ob = (stbsp__int64)ph; \ ob = (stbsp__int64)xh; \
vh = (double)ob; \ vh = (double)ob; \
ahi = (xh - vh); \ ahi = (xh - vh); \
t = (ahi - xh); \ t = (ahi - xh); \
@ -7155,7 +7331,7 @@ static stbsp__int32 stbsp__real_to_str(char const **start, stbsp__uint32 *len, c
d = value; d = value;
STBSP__COPYFP(bits, d); STBSP__COPYFP(bits, d);
expo = (stbsp__int32)((bits >> 52) & 2047); expo = (stbsp__int32)((bits >> 52) & 2047);
ng = (stbsp__int32)(bits >> 63); ng = (stbsp__int32)((stbsp__uint64) bits >> 63);
if (ng) if (ng)
d = -d; 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 (expo == 0) // is zero or denormal
{ {
if ((bits << 1) == 0) // do zero if (((stbsp__uint64) bits << 1) == 0) // do zero
{ {
*decimal_pos = 1; *decimal_pos = 1;
*start = out; *start = out;
@ -7265,7 +7441,7 @@ static stbsp__int32 stbsp__real_to_str(char const **start, stbsp__uint32 *len, c
} }
while (n) { while (n) {
out -= 2; 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; n /= 100;
e += 2; e += 2;
} }

View File

@ -136,14 +136,9 @@ void Dqn_TestState_PrintResult(Dqn_TestState const *result)
} }
} }
static void Dqn_Test_UnitTests() void Dqn_Test_Allocator()
{ {
Dqn_TestingState testing_state = {}; Dqn_TestingState testing_state = {};
// ---------------------------------------------------------------------------------------------
// NOTE: Dqn_Allocator
// ---------------------------------------------------------------------------------------------
{
DQN_TEST_DECLARE_GROUP_SCOPED(testing_state, "Dqn_Allocator"); DQN_TEST_DECLARE_GROUP_SCOPED(testing_state, "Dqn_Allocator");
// NOTE: Various allocator test // NOTE: Various allocator test
@ -242,10 +237,9 @@ static void Dqn_Test_UnitTests()
} }
} }
// --------------------------------------------------------------------------------------------- void Dqn_Test_Array()
// NOTE: Dqn_Array
// ---------------------------------------------------------------------------------------------
{ {
Dqn_TestingState testing_state = {};
DQN_TEST_DECLARE_GROUP_SCOPED(testing_state, "Dqn_Array"); DQN_TEST_DECLARE_GROUP_SCOPED(testing_state, "Dqn_Array");
// NOTE: Dqn_Array_InitWithMemory // NOTE: Dqn_Array_InitWithMemory
{ {
@ -371,10 +365,112 @@ static void Dqn_Test_UnitTests()
} }
} }
// --------------------------------------------------------------------------------------------- void Dqn_Test_FixedArray()
// NOTE: Dqn_Rect
// ---------------------------------------------------------------------------------------------
{ {
Dqn_TestingState testing_state = {};
DQN_TEST_DECLARE_GROUP_SCOPED(testing_state, "Dqn_FixedArray");
// NOTE: Dqn_FixedArray_Init
{
DQN_TEST_START_SCOPE(testing_state, "Initialise from raw array");
int raw_array[] = {1, 2};
auto array = Dqn_FixedArray_Init<int, 4>(raw_array, (int)Dqn_ArrayCount(raw_array));
DQN_TEST_EXPECT(testing_state, array.size == 2);
DQN_TEST_EXPECT(testing_state, array[0] == 1);
DQN_TEST_EXPECT(testing_state, array[1] == 2);
}
// NOTE: Dqn_FixedArray_EraseStable
{
DQN_TEST_START_SCOPE(testing_state, "Erase stable 1 element from array");
int raw_array[] = {1, 2, 3};
auto array = Dqn_FixedArray_Init<int, 4>(raw_array, (int)Dqn_ArrayCount(raw_array));
Dqn_FixedArray_EraseStable(&array, 1);
DQN_TEST_EXPECT(testing_state, array.size == 2);
DQN_TEST_EXPECT(testing_state, array[0] == 1);
DQN_TEST_EXPECT(testing_state, array[1] == 3);
}
// NOTE: Dqn_FixedArray_EraseUnstable
{
DQN_TEST_START_SCOPE(testing_state, "Erase unstable 1 element from array");
int raw_array[] = {1, 2, 3};
auto array = Dqn_FixedArray_Init<int, 4>(raw_array, (int)Dqn_ArrayCount(raw_array));
Dqn_FixedArray_EraseUnstable(&array, 0);
DQN_TEST_EXPECT(testing_state, array.size == 2);
DQN_TEST_EXPECT(testing_state, array[0] == 3);
DQN_TEST_EXPECT(testing_state, array[1] == 2);
}
// NOTE: Dqn_FixedArray_Add
{
DQN_TEST_START_SCOPE(testing_state, "Add 1 element to array");
int const ITEM = 2;
int raw_array[] = {1};
auto array = Dqn_FixedArray_Init<int, 4>(raw_array, (int)Dqn_ArrayCount(raw_array));
Dqn_FixedArray_Add(&array, ITEM);
DQN_TEST_EXPECT(testing_state, array.size == 2);
DQN_TEST_EXPECT(testing_state, array[0] == 1);
DQN_TEST_EXPECT(testing_state, array[1] == ITEM);
}
// NOTE: Dqn_FixedArray_Clear
{
DQN_TEST_START_SCOPE(testing_state, "Clear array");
int raw_array[] = {1};
auto array = Dqn_FixedArray_Init<int, 4>(raw_array, (int)Dqn_ArrayCount(raw_array));
Dqn_FixedArray_Clear(&array);
DQN_TEST_EXPECT(testing_state, array.size == 0);
}
}
void Dqn_Test_FixedString()
{
Dqn_TestingState testing_state = {};
DQN_TEST_DECLARE_GROUP_SCOPED(testing_state, "Dqn_FixedString");
// NOTE: Dqn_FixedString_Append
{
DQN_TEST_START_SCOPE(testing_state, "Append too much fails");
Dqn_FixedString<4> str = {};
DQN_TEST_EXPECT_MSG(testing_state, Dqn_FixedString_Append(&str, "abcd") == false, "We need space for the null-terminator");
}
// NOTE: Dqn_FixedString_AppendFmt
{
DQN_TEST_START_SCOPE(testing_state, "Append format string too much fails");
Dqn_FixedString<4> str = {};
DQN_TEST_EXPECT_MSG(testing_state, Dqn_FixedString_AppendFmt(&str, "abcd") == false, "We need space for the null-terminator");
}
}
void Dqn_Test_M4()
{
Dqn_TestingState testing_state = {};
DQN_TEST_DECLARE_GROUP_SCOPED(testing_state, "Dqn_M4");
{
DQN_TEST_START_SCOPE(testing_state, "Simple translate and scale matrix");
Dqn_M4 translate = Dqn_M4_TranslateF(1, 2, 3);
Dqn_M4 scale = Dqn_M4_ScaleF(2, 2, 2);
Dqn_M4 result = Dqn_M4_Mul(translate, scale);
const Dqn_M4 EXPECT = {{
{2, 0, 0, 0},
{0, 2, 0, 0},
{0, 0, 2, 0},
{1, 2, 3, 1},
}};
DQN_TEST_EXPECT_MSG(testing_state,
memcmp(result.columns, EXPECT.columns, sizeof(EXPECT)) == 0,
"\nresult =\n%s\nexpected =\n%s",
Dqn_M4_ColumnMajorString(result).str,
Dqn_M4_ColumnMajorString(EXPECT).str);
}
}
void Dqn_Test_Rect()
{
Dqn_TestingState testing_state = {};
DQN_TEST_DECLARE_GROUP_SCOPED(testing_state, "Dqn_Rect"); DQN_TEST_DECLARE_GROUP_SCOPED(testing_state, "Dqn_Rect");
// NOTE: Dqn_Rect_Intersection // NOTE: Dqn_Rect_Intersection
{ {
@ -501,10 +597,156 @@ static void Dqn_Test_UnitTests()
} }
} }
void Dqn_Test_Str()
{
Dqn_TestingState testing_state = {};
// --------------------------------------------------------------------------------------------- // ---------------------------------------------------------------------------------------------
// NOTE: Dqn_StringBuilder // NOTE: Dqn_Str_ToI64
// --------------------------------------------------------------------------------------------- // ---------------------------------------------------------------------------------------------
{ {
DQN_TEST_DECLARE_GROUP_SCOPED(testing_state, "Dqn_Str_ToI64");
{
DQN_TEST_START_SCOPE(testing_state, "Convert nullptr");
Dqn_i64 result = Dqn_Str_ToI64(nullptr);
DQN_TEST_EXPECT(testing_state, result == 0);
}
{
DQN_TEST_START_SCOPE(testing_state, "Convert empty string");
Dqn_i64 result = Dqn_Str_ToI64("");
DQN_TEST_EXPECT(testing_state, result == 0);
}
{
DQN_TEST_START_SCOPE(testing_state, "Convert \"1\"");
Dqn_i64 result = Dqn_Str_ToI64("1");
DQN_TEST_EXPECT(testing_state, result == 1);
}
{
DQN_TEST_START_SCOPE(testing_state, "Convert \"-0\"");
Dqn_i64 result = Dqn_Str_ToI64("-0");
DQN_TEST_EXPECT(testing_state, result == 0);
}
{
DQN_TEST_START_SCOPE(testing_state, "Convert \"-1\"");
Dqn_i64 result = Dqn_Str_ToI64("-1");
DQN_TEST_EXPECT(testing_state, result == -1);
}
{
DQN_TEST_START_SCOPE(testing_state, "Convert \"1.2\"");
Dqn_i64 result = Dqn_Str_ToI64("1.2");
DQN_TEST_EXPECT(testing_state, result == 1);
}
{
DQN_TEST_START_SCOPE(testing_state, "Convert \"1,234\"");
Dqn_i64 result = Dqn_Str_ToI64("1,234");
DQN_TEST_EXPECT(testing_state, result == 1234);
}
{
DQN_TEST_START_SCOPE(testing_state, "Convert \"1,2\"");
Dqn_i64 result = Dqn_Str_ToI64("1,2");
DQN_TEST_EXPECT(testing_state, result == 12);
}
{
DQN_TEST_START_SCOPE(testing_state, "Convert \"12a3\"");
Dqn_i64 result = Dqn_Str_ToI64("12a3");
DQN_TEST_EXPECT(testing_state, result == 12);
}
}
// ---------------------------------------------------------------------------------------------
// NOTE: Dqn_Str_ToU64
// ---------------------------------------------------------------------------------------------
{
DQN_TEST_DECLARE_GROUP_SCOPED(testing_state, "Dqn_Str_ToU64");
{
DQN_TEST_START_SCOPE(testing_state, "Convert nullptr");
Dqn_u64 result = Dqn_Str_ToU64(nullptr);
DQN_TEST_EXPECT_MSG(testing_state, result == 0, "result: %zu", result);
}
{
DQN_TEST_START_SCOPE(testing_state, "Convert empty string");
Dqn_u64 result = Dqn_Str_ToU64("");
DQN_TEST_EXPECT_MSG(testing_state, result == 0, "result: %zu", result);
}
{
DQN_TEST_START_SCOPE(testing_state, "Convert \"1\"");
Dqn_u64 result = Dqn_Str_ToU64("1");
DQN_TEST_EXPECT_MSG(testing_state, result == 1, "result: %zu", result);
}
{
DQN_TEST_START_SCOPE(testing_state, "Convert \"-0\"");
Dqn_u64 result = Dqn_Str_ToU64("-0");
DQN_TEST_EXPECT_MSG(testing_state, result == 0, "result: %zu", result);
}
{
DQN_TEST_START_SCOPE(testing_state, "Convert \"-1\"");
Dqn_u64 result = Dqn_Str_ToU64("-1");
DQN_TEST_EXPECT_MSG(testing_state, result == 0, "result: %zu", result);
}
{
DQN_TEST_START_SCOPE(testing_state, "Convert \"1.2\"");
Dqn_u64 result = Dqn_Str_ToU64("1.2");
DQN_TEST_EXPECT_MSG(testing_state, result == 1, "result: %zu", result);
}
{
DQN_TEST_START_SCOPE(testing_state, "Convert \"1,234\"");
Dqn_u64 result = Dqn_Str_ToU64("1,234");
DQN_TEST_EXPECT_MSG(testing_state, result == 1234, "result: %zu", result);
}
{
DQN_TEST_START_SCOPE(testing_state, "Convert \"1,2\"");
Dqn_u64 result = Dqn_Str_ToU64("1,2");
DQN_TEST_EXPECT_MSG(testing_state, result == 12, "result: %zu", result);
}
{
DQN_TEST_START_SCOPE(testing_state, "Convert \"12a3\"");
Dqn_u64 result = Dqn_Str_ToU64("12a3");
DQN_TEST_EXPECT_MSG(testing_state, result == 12, "result: %zu", result);
}
}
// ---------------------------------------------------------------------------------------------
// NOTE: Dqn_Str_Find
// ---------------------------------------------------------------------------------------------
{
DQN_TEST_DECLARE_GROUP_SCOPED(testing_state, "Dqn_Str_Find");
{
DQN_TEST_START_SCOPE(testing_state, "String (char) is not in buffer");
char const buf[] = "836a35becd4e74b66a0d6844d51f1a63018c7ebc44cf7e109e8e4bba57eefb55";
char const find[] = "2";
char const *result = Dqn_Str_Find(buf, find, Dqn_CharCountI(buf), Dqn_CharCountI(find));
DQN_TEST_EXPECT(testing_state, result == nullptr);
}
{
DQN_TEST_START_SCOPE(testing_state, "String (char) is in buffer");
char const buf[] = "836a35becd4e74b66a0d6844d51f1a63018c7ebc44cf7e109e8e4bba57eefb55";
char const find[] = "6";
char const *result = Dqn_Str_Find(buf, find, Dqn_CharCountI(buf), Dqn_CharCountI(find));
DQN_TEST_EXPECT(testing_state, result != nullptr);
DQN_TEST_EXPECT(testing_state, result[0] == '6' && result[1] == 'a');
}
}
}
void Dqn_Test_StringBuilder()
{
Dqn_TestingState testing_state = {};
DQN_TEST_DECLARE_GROUP_SCOPED(testing_state, "Dqn_StringBuilder"); DQN_TEST_DECLARE_GROUP_SCOPED(testing_state, "Dqn_StringBuilder");
Dqn_Allocator allocator = Dqn_Allocator_InitWithHeap(); Dqn_Allocator allocator = Dqn_Allocator_InitWithHeap();
// NOTE: Dqn_StringBuilder_Append // NOTE: Dqn_StringBuilder_Append
@ -650,261 +892,57 @@ static void Dqn_Test_UnitTests()
} }
} }
// --------------------------------------------------------------------------------------------- void Dqn_Test_TicketMutex()
// NOTE: Dqn_FixedArray
// ---------------------------------------------------------------------------------------------
{ {
DQN_TEST_DECLARE_GROUP_SCOPED(testing_state, "Dqn_FixedArray"); Dqn_TestingState testing_state = {};
// NOTE: Dqn_FixedArray_Init DQN_TEST_DECLARE_GROUP_SCOPED(testing_state, "Dqn_TicketMutex");
{ {
DQN_TEST_START_SCOPE(testing_state, "Initialise from raw array"); // TODO: We don't have a meaningful test but since atomics are
int raw_array[] = {1, 2}; // implemented with a macro this ensures that we test that they are
auto array = Dqn_FixedArray_Init<int, 4>(raw_array, (int)Dqn_ArrayCount(raw_array)); // written correctly.
DQN_TEST_EXPECT(testing_state, array.size == 2); DQN_TEST_START_SCOPE(testing_state, "Ticket mutex start and stop");
DQN_TEST_EXPECT(testing_state, array[0] == 1); Dqn_TicketMutex mutex = {};
DQN_TEST_EXPECT(testing_state, array[1] == 2); Dqn_TicketMutex_Begin(&mutex);
} Dqn_TicketMutex_End(&mutex);
DQN_TEST_EXPECT(testing_state, mutex.ticket == mutex.serving + 1);
// NOTE: Dqn_FixedArray_EraseStable
{
DQN_TEST_START_SCOPE(testing_state, "Erase stable 1 element from array");
int raw_array[] = {1, 2, 3};
auto array = Dqn_FixedArray_Init<int, 4>(raw_array, (int)Dqn_ArrayCount(raw_array));
Dqn_FixedArray_EraseStable(&array, 1);
DQN_TEST_EXPECT(testing_state, array.size == 2);
DQN_TEST_EXPECT(testing_state, array[0] == 1);
DQN_TEST_EXPECT(testing_state, array[1] == 3);
}
// NOTE: Dqn_FixedArray_EraseUnstable
{
DQN_TEST_START_SCOPE(testing_state, "Erase unstable 1 element from array");
int raw_array[] = {1, 2, 3};
auto array = Dqn_FixedArray_Init<int, 4>(raw_array, (int)Dqn_ArrayCount(raw_array));
Dqn_FixedArray_EraseUnstable(&array, 0);
DQN_TEST_EXPECT(testing_state, array.size == 2);
DQN_TEST_EXPECT(testing_state, array[0] == 3);
DQN_TEST_EXPECT(testing_state, array[1] == 2);
}
// NOTE: Dqn_FixedArray_Add
{
DQN_TEST_START_SCOPE(testing_state, "Add 1 element to array");
int const ITEM = 2;
int raw_array[] = {1};
auto array = Dqn_FixedArray_Init<int, 4>(raw_array, (int)Dqn_ArrayCount(raw_array));
Dqn_FixedArray_Add(&array, ITEM);
DQN_TEST_EXPECT(testing_state, array.size == 2);
DQN_TEST_EXPECT(testing_state, array[0] == 1);
DQN_TEST_EXPECT(testing_state, array[1] == ITEM);
}
// NOTE: Dqn_FixedArray_Clear
{
DQN_TEST_START_SCOPE(testing_state, "Clear array");
int raw_array[] = {1};
auto array = Dqn_FixedArray_Init<int, 4>(raw_array, (int)Dqn_ArrayCount(raw_array));
Dqn_FixedArray_Clear(&array);
DQN_TEST_EXPECT(testing_state, array.size == 0);
}
}
// ---------------------------------------------------------------------------------------------
// NOTE: Dqn_FixedString
// ---------------------------------------------------------------------------------------------
{
DQN_TEST_DECLARE_GROUP_SCOPED(testing_state, "Dqn_FixedString");
// NOTE: Dqn_FixedString_Append
{
DQN_TEST_START_SCOPE(testing_state, "Append too much fails");
Dqn_FixedString<4> str = {};
DQN_TEST_EXPECT_MSG(testing_state, Dqn_FixedString_Append(&str, "abcd") == false, "We need space for the null-terminator");
}
// NOTE: Dqn_FixedString_AppendFmt
{
DQN_TEST_START_SCOPE(testing_state, "Append format string too much fails");
Dqn_FixedString<4> str = {};
DQN_TEST_EXPECT_MSG(testing_state, Dqn_FixedString_AppendFmt(&str, "abcd") == false, "We need space for the null-terminator");
}
}
// ---------------------------------------------------------------------------------------------
// NOTE: Dqn_Str_ToI64
// ---------------------------------------------------------------------------------------------
{
DQN_TEST_DECLARE_GROUP_SCOPED(testing_state, "Dqn_Str_ToI64");
{
DQN_TEST_START_SCOPE(testing_state, "Convert nullptr");
Dqn_i64 result = Dqn_Str_ToI64(nullptr);
DQN_TEST_EXPECT(testing_state, result == 0);
} }
{ {
DQN_TEST_START_SCOPE(testing_state, "Convert empty string"); DQN_TEST_START_SCOPE(testing_state, "Ticket mutex start and stop w/ advanced API");
Dqn_i64 result = Dqn_Str_ToI64(""); Dqn_TicketMutex mutex = {};
DQN_TEST_EXPECT(testing_state, result == 0); unsigned int ticket_a = Dqn_TicketMutex_MakeTicket(&mutex);
} unsigned int ticket_b = Dqn_TicketMutex_MakeTicket(&mutex);
DQN_TEST_EXPECT(testing_state, DQN_CAST(bool)Dqn_TicketMutex_CanLock(&mutex, ticket_b) == false);
DQN_TEST_EXPECT(testing_state, DQN_CAST(bool)Dqn_TicketMutex_CanLock(&mutex, ticket_a) == true);
{ Dqn_TicketMutex_BeginTicket(&mutex, ticket_a);
DQN_TEST_START_SCOPE(testing_state, "Convert \"1\""); Dqn_TicketMutex_End(&mutex);
Dqn_i64 result = Dqn_Str_ToI64("1"); Dqn_TicketMutex_BeginTicket(&mutex, ticket_b);
DQN_TEST_EXPECT(testing_state, result == 1); Dqn_TicketMutex_End(&mutex);
}
{ DQN_TEST_EXPECT(testing_state, mutex.ticket == mutex.serving + 1);
DQN_TEST_START_SCOPE(testing_state, "Convert \"-0\""); DQN_TEST_EXPECT(testing_state, mutex.ticket == ticket_b + 1);
Dqn_i64 result = Dqn_Str_ToI64("-0");
DQN_TEST_EXPECT(testing_state, result == 0);
}
{
DQN_TEST_START_SCOPE(testing_state, "Convert \"-1\"");
Dqn_i64 result = Dqn_Str_ToI64("-1");
DQN_TEST_EXPECT(testing_state, result == -1);
}
{
DQN_TEST_START_SCOPE(testing_state, "Convert \"1.2\"");
Dqn_i64 result = Dqn_Str_ToI64("1.2");
DQN_TEST_EXPECT(testing_state, result == 1);
}
{
DQN_TEST_START_SCOPE(testing_state, "Convert \"1,234\"");
Dqn_i64 result = Dqn_Str_ToI64("1,234");
DQN_TEST_EXPECT(testing_state, result == 1234);
}
{
DQN_TEST_START_SCOPE(testing_state, "Convert \"1,2\"");
Dqn_i64 result = Dqn_Str_ToI64("1,2");
DQN_TEST_EXPECT(testing_state, result == 12);
}
{
DQN_TEST_START_SCOPE(testing_state, "Convert \"12a3\"");
Dqn_i64 result = Dqn_Str_ToI64("12a3");
DQN_TEST_EXPECT(testing_state, result == 12);
} }
} }
// --------------------------------------------------------------------------------------------- void Dqn_Test_RunSuite()
// NOTE: Dqn_Str_ToU64
// ---------------------------------------------------------------------------------------------
{ {
DQN_TEST_DECLARE_GROUP_SCOPED(testing_state, "Dqn_Str_ToU64"); Dqn_Test_Allocator();
{ Dqn_Test_Array();
DQN_TEST_START_SCOPE(testing_state, "Convert nullptr"); Dqn_Test_FixedArray();
Dqn_u64 result = Dqn_Str_ToU64(nullptr); Dqn_Test_FixedString();
DQN_TEST_EXPECT_MSG(testing_state, result == 0, "result: %zu", result); Dqn_Test_M4();
} Dqn_Test_Rect();
Dqn_Test_Str();
{ Dqn_Test_StringBuilder();
DQN_TEST_START_SCOPE(testing_state, "Convert empty string"); Dqn_Test_TicketMutex();
Dqn_u64 result = Dqn_Str_ToU64("");
DQN_TEST_EXPECT_MSG(testing_state, result == 0, "result: %zu", result);
}
{
DQN_TEST_START_SCOPE(testing_state, "Convert \"1\"");
Dqn_u64 result = Dqn_Str_ToU64("1");
DQN_TEST_EXPECT_MSG(testing_state, result == 1, "result: %zu", result);
}
{
DQN_TEST_START_SCOPE(testing_state, "Convert \"-0\"");
Dqn_u64 result = Dqn_Str_ToU64("-0");
DQN_TEST_EXPECT_MSG(testing_state, result == 0, "result: %zu", result);
}
{
DQN_TEST_START_SCOPE(testing_state, "Convert \"-1\"");
Dqn_u64 result = Dqn_Str_ToU64("-1");
DQN_TEST_EXPECT_MSG(testing_state, result == 0, "result: %zu", result);
}
{
DQN_TEST_START_SCOPE(testing_state, "Convert \"1.2\"");
Dqn_u64 result = Dqn_Str_ToU64("1.2");
DQN_TEST_EXPECT_MSG(testing_state, result == 1, "result: %zu", result);
}
{
DQN_TEST_START_SCOPE(testing_state, "Convert \"1,234\"");
Dqn_u64 result = Dqn_Str_ToU64("1,234");
DQN_TEST_EXPECT_MSG(testing_state, result == 1234, "result: %zu", result);
}
{
DQN_TEST_START_SCOPE(testing_state, "Convert \"1,2\"");
Dqn_u64 result = Dqn_Str_ToU64("1,2");
DQN_TEST_EXPECT_MSG(testing_state, result == 12, "result: %zu", result);
}
{
DQN_TEST_START_SCOPE(testing_state, "Convert \"12a3\"");
Dqn_u64 result = Dqn_Str_ToU64("12a3");
DQN_TEST_EXPECT_MSG(testing_state, result == 12, "result: %zu", result);
}
}
// ---------------------------------------------------------------------------------------------
// NOTE: Dqn_Str_Find
// ---------------------------------------------------------------------------------------------
{
DQN_TEST_DECLARE_GROUP_SCOPED(testing_state, "Dqn_Str_Find");
{
DQN_TEST_START_SCOPE(testing_state, "String (char) is not in buffer");
char const buf[] = "836a35becd4e74b66a0d6844d51f1a63018c7ebc44cf7e109e8e4bba57eefb55";
char const find[] = "2";
char const *result = Dqn_Str_Find(buf, find, Dqn_CharCountI(buf), Dqn_CharCountI(find));
DQN_TEST_EXPECT(testing_state, result == nullptr);
}
{
DQN_TEST_START_SCOPE(testing_state, "String (char) is in buffer");
char const buf[] = "836a35becd4e74b66a0d6844d51f1a63018c7ebc44cf7e109e8e4bba57eefb55";
char const find[] = "6";
char const *result = Dqn_Str_Find(buf, find, Dqn_CharCountI(buf), Dqn_CharCountI(find));
DQN_TEST_EXPECT(testing_state, result != nullptr);
DQN_TEST_EXPECT(testing_state, result[0] == '6' && result[1] == 'a');
}
}
// ---------------------------------------------------------------------------------------------
// NOTE: Dqn_M4
// ---------------------------------------------------------------------------------------------
{
DQN_TEST_DECLARE_GROUP_SCOPED(testing_state, "Dqn_M4");
{
DQN_TEST_START_SCOPE(testing_state, "Simple translate and scale matrix");
Dqn_M4 translate = Dqn_M4_TranslateF(1, 2, 3);
Dqn_M4 scale = Dqn_M4_ScaleF(2, 2, 2);
Dqn_M4 result = Dqn_M4_Mul(translate, scale);
const Dqn_M4 EXPECT = {{
{2, 0, 0, 0},
{0, 2, 0, 0},
{0, 0, 2, 0},
{1, 2, 3, 1},
}};
DQN_TEST_EXPECT_MSG(testing_state,
memcmp(result.columns, EXPECT.columns, sizeof(EXPECT)) == 0,
"\nresult =\n%s\nexpected =\n%s",
Dqn_M4_ColumnMajorString(result).str,
Dqn_M4_ColumnMajorString(EXPECT).str);
}
}
} }
#if defined(DQN_TEST_WITH_MAIN) #if defined(DQN_TEST_WITH_MAIN)
int main(int argc, char *argv[]) int main(int argc, char *argv[])
{ {
(void)argv; (void)argc; (void)argv; (void)argc;
Dqn_Test_UnitTests(); Dqn_Test_RunSuite();
return 0; return 0;
} }
#endif #endif