test: Organize unit tests
This commit is contained in:
parent
9f9f9b52aa
commit
b536f407b8
524
Code/Dqn.h
524
Code/Dqn.h
@ -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 defined(__clang__)
|
||||
#if defined(__has_feature) && defined(__has_attribute)
|
||||
#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
|
||||
#ifndef STBI__ASAN
|
||||
#define STBI__ASAN
|
||||
#endif
|
||||
#elif defined(__GNUC__) && (__GNUC__ >= 5 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8))
|
||||
#if defined(__SANITIZE_ADDRESS__) && __SANITIZE_ADDRESS__
|
||||
#define STBSP__ASAN __attribute__((__no_sanitize_address__))
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef STBSP__ASAN
|
||||
#define STBSP__ASAN
|
||||
#endif
|
||||
|
||||
#ifdef STB_SPRINTF_STATIC
|
||||
#define STBSP__PUBLICDEC static
|
||||
#define STBSP__PUBLICDEF static 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
|
||||
@ -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] = {};
|
||||
@ -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_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.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
|
||||
@ -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;
|
||||
#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;
|
||||
}
|
||||
|
@ -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 = {};
|
||||
|
||||
// ---------------------------------------------------------------------------------------------
|
||||
// NOTE: Dqn_Allocator
|
||||
// ---------------------------------------------------------------------------------------------
|
||||
{
|
||||
DQN_TEST_DECLARE_GROUP_SCOPED(testing_state, "Dqn_Allocator");
|
||||
|
||||
// NOTE: Various allocator test
|
||||
@ -242,10 +237,9 @@ static void Dqn_Test_UnitTests()
|
||||
}
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------------------------
|
||||
// NOTE: Dqn_Array
|
||||
// ---------------------------------------------------------------------------------------------
|
||||
void Dqn_Test_Array()
|
||||
{
|
||||
Dqn_TestingState testing_state = {};
|
||||
DQN_TEST_DECLARE_GROUP_SCOPED(testing_state, "Dqn_Array");
|
||||
// NOTE: Dqn_Array_InitWithMemory
|
||||
{
|
||||
@ -371,10 +365,112 @@ static void Dqn_Test_UnitTests()
|
||||
}
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------------------------
|
||||
// NOTE: Dqn_Rect
|
||||
// ---------------------------------------------------------------------------------------------
|
||||
void Dqn_Test_FixedArray()
|
||||
{
|
||||
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");
|
||||
// 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_Allocator allocator = Dqn_Allocator_InitWithHeap();
|
||||
// NOTE: Dqn_StringBuilder_Append
|
||||
@ -650,261 +892,57 @@ static void Dqn_Test_UnitTests()
|
||||
}
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------------------------
|
||||
// NOTE: Dqn_FixedArray
|
||||
// ---------------------------------------------------------------------------------------------
|
||||
void Dqn_Test_TicketMutex()
|
||||
{
|
||||
DQN_TEST_DECLARE_GROUP_SCOPED(testing_state, "Dqn_FixedArray");
|
||||
// NOTE: Dqn_FixedArray_Init
|
||||
Dqn_TestingState testing_state = {};
|
||||
DQN_TEST_DECLARE_GROUP_SCOPED(testing_state, "Dqn_TicketMutex");
|
||||
{
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------------------------
|
||||
// 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);
|
||||
// TODO: We don't have a meaningful test but since atomics are
|
||||
// implemented with a macro this ensures that we test that they are
|
||||
// written correctly.
|
||||
DQN_TEST_START_SCOPE(testing_state, "Ticket mutex start and stop");
|
||||
Dqn_TicketMutex mutex = {};
|
||||
Dqn_TicketMutex_Begin(&mutex);
|
||||
Dqn_TicketMutex_End(&mutex);
|
||||
DQN_TEST_EXPECT(testing_state, mutex.ticket == mutex.serving + 1);
|
||||
}
|
||||
|
||||
{
|
||||
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, "Ticket mutex start and stop w/ advanced API");
|
||||
Dqn_TicketMutex mutex = {};
|
||||
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_TEST_START_SCOPE(testing_state, "Convert \"1\"");
|
||||
Dqn_i64 result = Dqn_Str_ToI64("1");
|
||||
DQN_TEST_EXPECT(testing_state, result == 1);
|
||||
}
|
||||
Dqn_TicketMutex_BeginTicket(&mutex, ticket_a);
|
||||
Dqn_TicketMutex_End(&mutex);
|
||||
Dqn_TicketMutex_BeginTicket(&mutex, ticket_b);
|
||||
Dqn_TicketMutex_End(&mutex);
|
||||
|
||||
{
|
||||
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);
|
||||
DQN_TEST_EXPECT(testing_state, mutex.ticket == mutex.serving + 1);
|
||||
DQN_TEST_EXPECT(testing_state, mutex.ticket == ticket_b + 1);
|
||||
}
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------------------------
|
||||
// NOTE: Dqn_Str_ToU64
|
||||
// ---------------------------------------------------------------------------------------------
|
||||
void Dqn_Test_RunSuite()
|
||||
{
|
||||
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');
|
||||
}
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------------------------
|
||||
// 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);
|
||||
}
|
||||
}
|
||||
Dqn_Test_Allocator();
|
||||
Dqn_Test_Array();
|
||||
Dqn_Test_FixedArray();
|
||||
Dqn_Test_FixedString();
|
||||
Dqn_Test_M4();
|
||||
Dqn_Test_Rect();
|
||||
Dqn_Test_Str();
|
||||
Dqn_Test_StringBuilder();
|
||||
Dqn_Test_TicketMutex();
|
||||
}
|
||||
|
||||
#if defined(DQN_TEST_WITH_MAIN)
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
(void)argv; (void)argc;
|
||||
Dqn_Test_UnitTests();
|
||||
Dqn_Test_RunSuite();
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
Loading…
Reference in New Issue
Block a user