2019-09-23 13:21:14 +00:00
// #define DQN_ENABLE_ASSERTS to enable DQN_ASSERT, otherwise compile out and use non aborting asserts where appropriate
2019-09-19 11:49:11 +00:00
// #define DQN_USE_PRIMITIVE_TYPEDEFS to enable typical typedefs such as i32 = int32_t .. etc
// #define DQN_IMPLEMENTATION in one and only one C++ file to enable the header file
# define _CRT_SECURE_NO_WARNINGS // NOTE: Undefined at end of header file
2019-08-24 05:43:14 +00:00
2019-08-24 01:39:12 +00:00
// -------------------------------------------------------------------------------------------------
//
// NOTE: stb_sprintf
//
// -------------------------------------------------------------------------------------------------
// stb_sprintf - v1.05 - 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
//
// Contributors:
// Fabian "ryg" Giesen (reformatting)
//
// Contributors (bugfixes):
// github:d26435
// github:trex78
// Jari Komppa (SI suffixes)
// Rohit Nirmal
// Marcin Wojdyr
// Leonard Ritter
//
// LICENSE:
//
// See end of file for license information.
# ifndef STB_SPRINTF_H_INCLUDE
# define STB_SPRINTF_H_INCLUDE
/*
Single file sprintf replacement .
Originally written by Jeff Roberts at RAD Game Tools - 2015 / 10 / 20.
Hereby placed in public domain .
This is a full sprintf replacement that supports everything that
the C runtime sprintfs support , including float / double , 64 - bit integers ,
hex floats , field parameters ( % * . * d stuff ) , length reads backs , etc .
Why would you need this if sprintf already exists ? Well , first off ,
it ' s * much * faster ( see below ) . It ' s also much smaller than the CRT
versions code - space - wise . We ' ve also added some simple improvements
that are super handy ( commas in thousands , callbacks at buffer full ,
for example ) . Finally , the format strings for MSVC and GCC differ
for 64 - bit integers ( among other small things ) , so this lets you use
the same format strings in cross platform code .
It uses the standard single file trick of being both the header file
and the source itself . If you just include it normally , you just get
the header file function definitions . To get the code , you include
it from a C or C + + file and define STB_SPRINTF_IMPLEMENTATION first .
It only uses va_args macros from the C runtime to do it ' s work . It
does cast doubles to S64s and shifts and divides U64s , which does
drag in CRT code on most platforms .
It compiles to roughly 8 K with float support , and 4 K without .
As a comparison , when using MSVC static libs , calling sprintf drags
in 16 K .
API :
= = = =
int stbsp_sprintf ( char * buf , char const * fmt , . . . )
int stbsp_snprintf ( char * buf , int count , char const * fmt , . . . )
Convert an arg list into a buffer . stbsp_snprintf always returns
a zero - terminated string ( unlike regular snprintf ) .
int stbsp_vsprintf ( char * buf , char const * fmt , va_list va )
int stbsp_vsnprintf ( char * buf , int count , char const * fmt , va_list va )
Convert a va_list arg list into a buffer . stbsp_vsnprintf always returns
a zero - terminated string ( unlike regular snprintf ) .
int stbsp_vsprintfcb ( STBSP_SPRINTFCB * callback , void * user , char * buf , char const * fmt , va_list va )
typedef char * STBSP_SPRINTFCB ( char const * buf , void * user , int len ) ;
Convert into a buffer , calling back every STB_SPRINTF_MIN chars .
Your callback can then copy the chars out , print them or whatever .
This function is actually the workhorse for everything else .
The buffer you pass in must hold at least STB_SPRINTF_MIN characters .
// you return the next buffer to use or 0 to stop converting
void stbsp_set_separators ( char comma , char period )
Set the comma and period characters to use .
FLOATS / DOUBLES :
= = = = = = = = = = = = = = =
This code uses a internal float - > ascii conversion method that uses
doubles with error correction ( double - doubles , for ~ 105 bits of
precision ) . This conversion is round - trip perfect - that is , an atof
of the values output here will give you the bit - exact double back .
One difference is that our insignificant digits will be different than
with MSVC or GCC ( but they don ' t match each other either ) . We also
don ' t attempt to find the minimum length matching float ( pre - MSVC15
doesn ' t either ) .
If you don ' t need float or doubles at all , define STB_SPRINTF_NOFLOAT
and you ' ll save 4 K of code space .
64 - BIT INTS :
= = = = = = = = = = = =
This library also supports 64 - bit integers and you can use MSVC style or
GCC style indicators ( % I64d or % lld ) . It supports the C99 specifiers
for size_t and ptr_diff_t ( % jd % zd ) as well .
EXTRAS :
= = = = = = =
Like some GCCs , for integers and floats , you can use a ' ( single quote )
specifier and commas will be inserted on the thousands : " %'d " on 12345
would print 12 , 345.
For integers and floats , you can use a " $ " specifier and the number
will be converted to float and then divided to get kilo , mega , giga or
tera and then printed , so " %$d " 1000 is " 1.0 k " , " %$.2d " 2536000 is
" 2.53 M " , etc . For byte values , use two $ : s , like " %$$d " to turn
2536000 to " 2.42 Mi " . If you prefer JEDEC suffixes to SI ones , use three
$ : s : " %$$$d " - > " 2.42 M " . To remove the space between the number and the
suffix , add " _ " specifier : " %_$d " - > " 2.53M " .
In addition to octal and hexadecimal conversions , you can print
integers in binary : " %b " for 256 would print 100.
PERFORMANCE vs MSVC 2008 32 - / 64 - bit ( GCC is even slower than MSVC ) :
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
" %d " across all 32 - bit ints ( 4.8 x / 4.0 x faster than 32 - / 64 - bit MSVC )
" %24d " across all 32 - bit ints ( 4.5 x / 4.2 x faster )
" %x " across all 32 - bit ints ( 4.5 x / 3.8 x faster )
" %08x " across all 32 - bit ints ( 4.3 x / 3.8 x faster )
" %f " across e - 10 to e + 10 floats ( 7.3 x / 6.0 x faster )
" %e " across e - 10 to e + 10 floats ( 8.1 x / 6.0 x faster )
" %g " across e - 10 to e + 10 floats ( 10.0 x / 7.1 x faster )
" %f " for values near e - 300 ( 7.9 x / 6.5 x faster )
" %f " for values near e + 300 ( 10.0 x / 9.1 x faster )
" %e " for values near e - 300 ( 10.1 x / 7.0 x faster )
" %e " for values near e + 300 ( 9.2 x / 6.0 x faster )
" %.320f " for values near e - 300 ( 12.6 x / 11.2 x faster )
" %a " for random values ( 8.6 x / 4.3 x faster )
" %I64d " for 64 - bits with 32 - bit values ( 4.8 x / 3.4 x faster )
" %I64d " for 64 - bits > 32 - bit values ( 4.9 x / 5.5 x faster )
" %s%s%s " for 64 char strings ( 7.1 x / 7.3 x faster )
" ...512 char string... " ( 35.0 x / 32.5 x faster ! )
*/
# if defined(__has_feature)
# if __has_feature(address_sanitizer)
# define STBI__ASAN __attribute__((no_sanitize("address")))
# endif
# endif
# ifndef STBI__ASAN
# define STBI__ASAN
# endif
# ifdef STB_SPRINTF_STATIC
# define STBSP__PUBLICDEC static
# define STBSP__PUBLICDEF static STBI__ASAN
# else
# ifdef __cplusplus
# define STBSP__PUBLICDEC extern "C"
# define STBSP__PUBLICDEF extern "C" STBI__ASAN
# else
# define STBSP__PUBLICDEC extern
# define STBSP__PUBLICDEF STBI__ASAN
# endif
# endif
# include <stdarg.h> // for va_list()
# 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 ) ;
# 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__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
# ifndef DQN_H
# define DQN_H
2019-08-26 13:24:22 +00:00
# undef DQN_HEADER_IMPLEMENTATION
# include "DqnHeader.h"
// @ -------------------------------------------------------------------------------------------------
// @
// @ NOTE: Typedefs, Macros, Utils
// @
// @ -------------------------------------------------------------------------------------------------
2019-09-19 11:49:11 +00:00
# define DQN_CAST(val) (val)
2019-08-24 01:39:12 +00:00
# define DQN_ABS(val) (((val) < 0) ? (-(val)) : (val))
# define DQN_SQUARED(val) ((val) * (val))
2019-08-24 03:38:58 +00:00
# define DQN_MIN(a, b) ((a < b) ? (a) : (b))
# define DQN_MAX(a, b) ((a > b) ? (a) : (b))
2019-08-24 01:39:12 +00:00
# define DQN_SWAP(a, b) \
do \
{ \
auto tmp = a ; \
a = b ; \
b = tmp ; \
} while ( 0 )
2019-10-29 11:22:35 +00:00
# define DQN_LEN_AND_STR(string) Dqn_CharCount(str), string
# define DQN_STR_AND_LEN(string) string, Dqn_CharCount(string)
# define DQN_STR_AND_LEN_I(string) string, (int)Dqn_CharCount(string)
# define DQN_FOR_EACH(i, limit) for (Dqn_isize (i) = 0; (i) < (Dqn_isize)(limit); ++(i))
# define DQN_FOR_EACH_REVERSE(i, limit) for (Dqn_isize (i) = (Dqn_isize)(limit-1); (i) >= 0; --(i))
# define DQN_FOR_EACH_ITERATOR(it_name, array, num) for (auto it_name = array; it_name != (array + num); it_name++)
2019-08-24 01:39:12 +00:00
# define DQN_BYTES(val) (val)
# define DQN_KILOBYTES(val) (1024ULL * DQN_BYTES(val))
# define DQN_MEGABYTES(val) (1024ULL * DQN_KILOBYTES(val))
# define DQN_GIGABYTES(val) (1024ULL * DQN_MEGABYTES(val))
2019-11-01 13:00:39 +00:00
# define DQN_MINS_TO_S(val) ((val) * 60ULL)
# define DQN_HOURS_TO_S(val) (DQN_MINS_TO_S(val) * 60ULL)
# define DQN_DAYS_TO_S(val) (DQN_HOURS_TO_S(val) * 24ULL)
# define DQN_YEARS_TO_S(val) (DQN_DAYS_TO_S(val) * 365ULL)
2019-10-29 11:22:35 +00:00
# define DQN_ARRAY_COUNT(array) (sizeof(array) / sizeof(array[0]))
2019-09-20 06:03:09 +00:00
# ifdef _MSC_VER
2020-01-17 15:01:25 +00:00
# define DQN_DEBUG_BREAK __debugbreak()
2019-09-20 06:03:09 +00:00
# else
# include <signal.h>
2020-01-17 15:01:25 +00:00
# define DQN_DEBUG_BREAK raise(SIGTRAP)
2019-09-20 06:03:09 +00:00
# endif
2019-08-24 01:39:12 +00:00
# define DQN_INVALID_CODE_PATH 0
2019-09-23 13:21:14 +00:00
# if defined(DQN_ENABLE_ASSERTS)
# define DQN_ASSERT(expr) DQN_ASSERT_MSG(expr, "")
# define DQN_ASSERT_MSG(expr, fmt, ...) \
if ( ! ( expr ) ) \
{ \
DQN_LOG_E ( " Assert: [ " # expr " ] " fmt , # # __VA_ARGS__ ) ; \
2020-01-17 15:01:25 +00:00
DQN_DEBUG_BREAK ; \
2019-09-23 13:21:14 +00:00
}
# define DQN_IF_ASSERT(expr) DQN_IF_ASSERT_MSG(expr, "")
# define DQN_IF_ASSERT_MSG(expr, fmt, ...) \
DQN_ASSERT_MSG ( expr , fmt , # # __VA_ARGS__ ) ; \
if ( 0 )
# else
# define DQN_ASSERT(expr)
# define DQN_ASSERT_MSG(expr, fmt, ...)
# define DQN_IF_ASSERT(expr) DQN_IF_ASSERT_MSG(expr, "")
# define DQN_IF_ASSERT_MSG(expr, fmt, ...) \
if ( ! ( expr ) & & DQN_LOG_E ( " Soft assert: [ " # expr " ] " fmt , # # __VA_ARGS__ ) )
# endif
2019-08-24 01:39:12 +00:00
# define DQN_SECONDS_TO_MS(val) ((val) * 1000.0f)
# define DQN_MATH_PI 3.14159265359f
# define DQN_DEGREE_TO_RADIAN(val) (val) * (DQN_MATH_PI / 180.0f)
# include <float.h>
2019-09-20 06:03:09 +00:00
# include <stddef.h>
# include <stdint.h>
# include <stdlib.h>
# include <string.h>
2019-08-24 01:39:12 +00:00
2019-08-27 12:17:59 +00:00
# if defined(DQN_USE_PRIMITIVE_TYPEDEFS)
2019-08-27 12:32:04 +00:00
# define FILE_SCOPE static
# define LOCAL_PERSIST static
2019-08-24 01:39:12 +00:00
using usize = size_t ;
using isize = ptrdiff_t ;
using f64 = double ;
using f32 = float ;
using i64 = int64_t ;
using i32 = int32_t ;
using i16 = int16_t ;
using i8 = int8_t ;
using uchar = unsigned char ;
using uint = unsigned int ;
using u64 = uint64_t ;
using u32 = uint32_t ;
using u16 = uint16_t ;
using u8 = uint8_t ;
using b32 = int32_t ;
2020-01-17 15:01:25 +00:00
using b8 = int8_t ;
2019-08-24 01:39:12 +00:00
const i32 I32_MAX = INT32_MAX ;
const u32 U32_MAX = UINT32_MAX ;
const f32 F32_MAX = FLT_MAX ;
const isize ISIZE_MAX = PTRDIFF_MAX ;
const usize USIZE_MAX = SIZE_MAX ;
2019-08-27 12:17:59 +00:00
# endif
2019-08-27 12:32:04 +00:00
# define DQN_FILE_SCOPE static
# define DQN_LOCAL_PERSIST static
2019-08-27 12:17:59 +00:00
using Dqn_usize = size_t ;
using Dqn_isize = ptrdiff_t ;
using Dqn_f64 = double ;
using Dqn_f32 = float ;
using Dqn_i64 = int64_t ;
using Dqn_i32 = int32_t ;
using Dqn_i16 = int16_t ;
using Dqn_i8 = int8_t ;
using Dqn_uchar = unsigned char ;
using Dqn_uint = unsigned int ;
using Dqn_u64 = uint64_t ;
using Dqn_u32 = uint32_t ;
using Dqn_u16 = uint16_t ;
using Dqn_u8 = uint8_t ;
using Dqn_b32 = int32_t ;
2019-08-24 01:39:12 +00:00
2019-08-27 12:17:59 +00:00
const Dqn_i32 DQN_I32_MAX = INT32_MAX ;
const Dqn_u32 DQN_U32_MAX = UINT32_MAX ;
const Dqn_f32 DQN_F32_MAX = FLT_MAX ;
const Dqn_isize DQN_ISIZE_MAX = PTRDIFF_MAX ;
const Dqn_usize DQN_USIZE_MAX = SIZE_MAX ;
2019-08-26 13:24:22 +00:00
2019-08-27 12:17:59 +00:00
template < typename T , Dqn_usize N >
DQN_HEADER_COPY_PROTOTYPE ( constexpr Dqn_usize , Dqn_ArrayCount ( T const ( & ) [ N ] ) ) { return N ; }
2019-08-26 13:24:22 +00:00
2019-08-27 12:17:59 +00:00
template < typename T , Dqn_usize N >
DQN_HEADER_COPY_PROTOTYPE ( constexpr Dqn_isize , Dqn_ArrayCountI ( T const ( & ) [ N ] ) ) { return N ; }
2019-08-26 13:24:22 +00:00
2019-08-27 12:17:59 +00:00
template < Dqn_usize N >
DQN_HEADER_COPY_PROTOTYPE ( constexpr Dqn_usize , Dqn_CharCount ( char const ( & ) [ N ] ) ) { return N - 1 ; }
template < Dqn_usize N >
DQN_HEADER_COPY_PROTOTYPE ( constexpr Dqn_isize , Dqn_CharCountI ( char const ( & ) [ N ] ) ) { return N - 1 ; }
2019-08-24 01:39:12 +00:00
template < typename Procedure >
struct DqnDefer
{
Procedure proc ;
DqnDefer ( Procedure p ) : proc ( p ) { }
~ DqnDefer ( ) { proc ( ) ; }
} ;
struct DqnDeferHelper
{
template < typename Lambda >
DqnDefer < Lambda > operator + ( Lambda lambda ) { return DqnDefer < Lambda > ( lambda ) ; } ;
} ;
2019-09-23 13:21:14 +00:00
# define DQN_TOKEN_COMBINE2(x, y) x ## y
# define DQN_TOKEN_COMBINE(x, y) DQN_TOKEN_COMBINE2(x, y)
# define DQN_UNIQUE_NAME(prefix) DQN_TOKEN_COMBINE(prefix, __COUNTER__)
2019-08-24 01:39:12 +00:00
# define DQN_DEFER const auto DQN_UNIQUE_NAME(defer_lambda_) = DqnDeferHelper() + [&]()
2019-10-29 11:22:35 +00:00
enum struct Dqn_ZeroMem { No , Yes } ;
2019-08-24 01:39:12 +00:00
enum struct Dqn_LogType
{
Debug ,
Error ,
Warning ,
Info ,
Memory ,
} ;
2019-08-26 13:56:50 +00:00
// @ -------------------------------------------------------------------------------------------------
// @
// @ NOTE: Logging
// @
// @ -------------------------------------------------------------------------------------------------
2019-08-26 13:24:22 +00:00
DQN_HEADER_COPY_PROTOTYPE ( constexpr inline char const * , Dqn_LogTypeTag ( Dqn_LogType type ) )
2019-08-24 01:39:12 +00:00
{
if ( type = = Dqn_LogType : : Debug ) return " DBG " ;
else if ( type = = Dqn_LogType : : Error ) return " ERR " ;
else if ( type = = Dqn_LogType : : Warning ) return " WARN " ;
else if ( type = = Dqn_LogType : : Info ) return " INFO " ;
else if ( type = = Dqn_LogType : : Memory ) return " MEM " ;
return " XXX " ;
}
2019-08-26 13:56:50 +00:00
DQN_HEADER_COPY_BEGIN
2019-08-24 01:39:12 +00:00
// NOTE: Set the callback to get called whenever a log message has been printed
2019-08-27 12:17:59 +00:00
# define DQN_LOG_CALLBACK(name) void name(Dqn_LogType type, char const *file, Dqn_usize file_len, char const *func, Dqn_usize func_len, Dqn_usize line, char const *log_str)
2019-08-24 01:39:12 +00:00
typedef DQN_LOG_CALLBACK ( Dqn_LogCallback ) ;
Dqn_LogCallback * Dqn_log_callback ;
# define DQN_LOG_E(fmt, ...) Dqn_Log(Dqn_LogType::Error, DQN_STR_AND_LEN(__FILE__), DQN_STR_AND_LEN(__func__), __LINE__, fmt, ## __VA_ARGS__)
# define DQN_LOG_D(fmt, ...) Dqn_Log(Dqn_LogType::Debug, DQN_STR_AND_LEN(__FILE__), DQN_STR_AND_LEN(__func__), __LINE__, fmt, ## __VA_ARGS__)
# define DQN_LOG_W(fmt, ...) Dqn_Log(Dqn_LogType::Warning, DQN_STR_AND_LEN(__FILE__), DQN_STR_AND_LEN(__func__), __LINE__, fmt, ## __VA_ARGS__)
# define DQN_LOG_I(fmt, ...) Dqn_Log(Dqn_LogType::Info, DQN_STR_AND_LEN(__FILE__), DQN_STR_AND_LEN(__func__), __LINE__, fmt, ## __VA_ARGS__)
2019-10-29 11:22:35 +00:00
# define DQN_LOG_M(fmt, ...) Dqn_Log(Dqn_LogType::Memory, DQN_STR_AND_LEN(__FILE__), DQN_STR_AND_LEN(__func__), __LINE__, fmt, ## __VA_ARGS__)
2019-08-24 01:39:12 +00:00
# define DQN_LOG(log_type, fmt, ...) Dqn_Log(log_type, DQN_STR_AND_LEN(__FILE__), DQN_STR_AND_LEN(__func__), __LINE__, fmt, ## __VA_ARGS__)
2019-08-26 13:56:50 +00:00
DQN_HEADER_COPY_END
2019-08-26 13:24:22 +00:00
// @ -------------------------------------------------------------------------------------------------
// @
// @ NOTE: Math
// @
// @ -------------------------------------------------------------------------------------------------
2019-08-26 13:56:50 +00:00
DQN_HEADER_COPY_BEGIN
2019-08-24 01:39:12 +00:00
union Dqn_V2I
{
2019-08-27 12:17:59 +00:00
struct { Dqn_i32 x , y ; } ;
struct { Dqn_i32 w , h ; } ;
struct { Dqn_i32 min , max ; } ;
Dqn_i32 e [ 2 ] ;
2019-08-24 01:39:12 +00:00
2019-09-20 06:03:09 +00:00
Dqn_V2I ( ) = default ;
2019-08-27 12:17:59 +00:00
constexpr Dqn_V2I ( Dqn_f32 x_ , Dqn_f32 y_ ) : x ( ( Dqn_i32 ) x_ ) , y ( ( Dqn_i32 ) y_ ) { }
constexpr Dqn_V2I ( Dqn_i32 x_ , Dqn_i32 y_ ) : x ( x_ ) , y ( y_ ) { }
constexpr Dqn_V2I ( Dqn_i32 xy ) : x ( xy ) , y ( xy ) { }
2019-08-24 01:39:12 +00:00
constexpr bool operator ! = ( Dqn_V2I other ) const { return ! ( * this = = other ) ; }
constexpr bool operator = = ( Dqn_V2I other ) const { return ( x = = other . x ) & & ( y = = other . y ) ; }
constexpr bool operator > = ( Dqn_V2I other ) const { return ( x > = other . x ) & & ( y > = other . y ) ; }
constexpr bool operator < = ( Dqn_V2I other ) const { return ( x < = other . x ) & & ( y < = other . y ) ; }
constexpr bool operator < ( Dqn_V2I other ) const { return ( x < other . x ) & & ( y < other . y ) ; }
constexpr bool operator > ( Dqn_V2I other ) const { return ( x > other . x ) & & ( y > other . y ) ; }
constexpr Dqn_V2I operator - ( Dqn_V2I other ) const { Dqn_V2I result ( x - other . x , y - other . y ) ; return result ; }
constexpr Dqn_V2I operator + ( Dqn_V2I other ) const { Dqn_V2I result ( x + other . x , y + other . y ) ; return result ; }
constexpr Dqn_V2I operator * ( Dqn_V2I other ) const { Dqn_V2I result ( x * other . x , y * other . y ) ; return result ; }
2019-08-27 12:17:59 +00:00
constexpr Dqn_V2I operator * ( Dqn_f32 other ) const { Dqn_V2I result ( x * other , y * other ) ; return result ; }
constexpr Dqn_V2I operator * ( Dqn_i32 other ) const { Dqn_V2I result ( x * other , y * other ) ; return result ; }
2019-08-24 01:39:12 +00:00
constexpr Dqn_V2I operator / ( Dqn_V2I other ) const { Dqn_V2I result ( x / other . x , y / other . y ) ; return result ; }
2019-08-27 12:17:59 +00:00
constexpr Dqn_V2I operator / ( Dqn_f32 other ) const { Dqn_V2I result ( x / other , y / other ) ; return result ; }
constexpr Dqn_V2I operator / ( Dqn_i32 other ) const { Dqn_V2I result ( x / other , y / other ) ; return result ; }
2019-08-24 01:39:12 +00:00
constexpr Dqn_V2I & operator * = ( Dqn_V2I other ) { * this = * this * other ; return * this ; }
2019-08-27 12:17:59 +00:00
constexpr Dqn_V2I & operator * = ( Dqn_f32 other ) { * this = * this * other ; return * this ; }
constexpr Dqn_V2I & operator * = ( Dqn_i32 other ) { * this = * this * other ; return * this ; }
2019-08-24 01:39:12 +00:00
constexpr Dqn_V2I & operator - = ( Dqn_V2I other ) { * this = * this - other ; return * this ; }
constexpr Dqn_V2I & operator + = ( Dqn_V2I other ) { * this = * this + other ; return * this ; }
} ;
union Dqn_V2
{
2019-08-27 12:17:59 +00:00
struct { Dqn_f32 x , y ; } ;
struct { Dqn_f32 w , h ; } ;
struct { Dqn_f32 min , max ; } ;
Dqn_f32 e [ 2 ] ;
2019-08-24 01:39:12 +00:00
2019-09-20 06:03:09 +00:00
Dqn_V2 ( ) = default ;
2019-08-27 12:17:59 +00:00
constexpr Dqn_V2 ( Dqn_f32 a ) : x ( a ) , y ( a ) { }
constexpr Dqn_V2 ( Dqn_i32 a ) : x ( ( Dqn_f32 ) a ) , y ( ( Dqn_f32 ) a ) { }
constexpr Dqn_V2 ( Dqn_f32 x_ , Dqn_f32 y_ ) : x ( x_ ) , y ( y_ ) { }
constexpr Dqn_V2 ( Dqn_i32 x_ , Dqn_i32 y_ ) : x ( ( Dqn_f32 ) x_ ) , y ( ( Dqn_f32 ) y_ ) { }
constexpr Dqn_V2 ( Dqn_V2I a ) : x ( ( Dqn_f32 ) a . x ) , y ( ( Dqn_f32 ) a . y ) { }
2019-08-24 01:39:12 +00:00
constexpr bool operator ! = ( Dqn_V2 other ) const { return ! ( * this = = other ) ; }
constexpr bool operator = = ( Dqn_V2 other ) const { return ( x = = other . x ) & & ( y = = other . y ) ; }
constexpr bool operator > = ( Dqn_V2 other ) const { return ( x > = other . x ) & & ( y > = other . y ) ; }
constexpr bool operator < = ( Dqn_V2 other ) const { return ( x < = other . x ) & & ( y < = other . y ) ; }
constexpr bool operator < ( Dqn_V2 other ) const { return ( x < other . x ) & & ( y < other . y ) ; }
constexpr bool operator > ( Dqn_V2 other ) const { return ( x > other . x ) & & ( y > other . y ) ; }
constexpr Dqn_V2 operator - ( Dqn_V2 other ) const { Dqn_V2 result ( x - other . x , y - other . y ) ; return result ; }
constexpr Dqn_V2 operator + ( Dqn_V2 other ) const { Dqn_V2 result ( x + other . x , y + other . y ) ; return result ; }
constexpr Dqn_V2 operator * ( Dqn_V2 other ) const { Dqn_V2 result ( x * other . x , y * other . y ) ; return result ; }
2019-08-27 12:17:59 +00:00
constexpr Dqn_V2 operator * ( Dqn_f32 other ) const { Dqn_V2 result ( x * other , y * other ) ; return result ; }
constexpr Dqn_V2 operator * ( Dqn_i32 other ) const { Dqn_V2 result ( x * other , y * other ) ; return result ; }
2019-08-24 01:39:12 +00:00
constexpr Dqn_V2 operator / ( Dqn_V2 other ) const { Dqn_V2 result ( x / other . x , y / other . y ) ; return result ; }
2019-08-27 12:17:59 +00:00
constexpr Dqn_V2 operator / ( Dqn_f32 other ) const { Dqn_V2 result ( x / other , y / other ) ; return result ; }
constexpr Dqn_V2 operator / ( Dqn_i32 other ) const { Dqn_V2 result ( x / other , y / other ) ; return result ; }
2019-08-24 01:39:12 +00:00
constexpr Dqn_V2 & operator * = ( Dqn_V2 other ) { * this = * this * other ; return * this ; }
2019-08-27 12:17:59 +00:00
constexpr Dqn_V2 & operator * = ( Dqn_f32 other ) { * this = * this * other ; return * this ; }
constexpr Dqn_V2 & operator * = ( Dqn_i32 other ) { * this = * this * other ; return * this ; }
2019-08-24 01:39:12 +00:00
constexpr Dqn_V2 & operator / = ( Dqn_V2 other ) { * this = * this / other ; return * this ; }
2019-08-27 12:17:59 +00:00
constexpr Dqn_V2 & operator / = ( Dqn_f32 other ) { * this = * this / other ; return * this ; }
constexpr Dqn_V2 & operator / = ( Dqn_i32 other ) { * this = * this / other ; return * this ; }
2019-08-24 01:39:12 +00:00
constexpr Dqn_V2 & operator - = ( Dqn_V2 other ) { * this = * this - other ; return * this ; }
constexpr Dqn_V2 & operator + = ( Dqn_V2 other ) { * this = * this + other ; return * this ; }
} ;
union Dqn_V3
{
2019-08-27 12:17:59 +00:00
struct { Dqn_f32 x , y , z ; } ;
struct { Dqn_f32 r , g , b ; } ;
2019-08-24 01:39:12 +00:00
Dqn_V2 xy ;
2019-08-27 12:17:59 +00:00
Dqn_f32 e [ 3 ] ;
2019-08-24 01:39:12 +00:00
2019-09-20 06:03:09 +00:00
Dqn_V3 ( ) = default ;
2019-08-27 12:17:59 +00:00
constexpr Dqn_V3 ( Dqn_f32 a ) : x ( a ) , y ( a ) , z ( a ) { }
constexpr Dqn_V3 ( Dqn_i32 a ) : x ( ( Dqn_f32 ) a ) , y ( ( Dqn_f32 ) a ) , z ( ( Dqn_f32 ) a ) { }
constexpr Dqn_V3 ( Dqn_f32 x_ , Dqn_f32 y_ , Dqn_f32 z_ ) : x ( x_ ) , y ( y_ ) , z ( z_ ) { }
constexpr Dqn_V3 ( Dqn_i32 x_ , Dqn_i32 y_ , Dqn_f32 z_ ) : x ( ( Dqn_f32 ) x_ ) , y ( ( Dqn_f32 ) y_ ) , z ( ( Dqn_f32 ) z_ ) { }
constexpr Dqn_V3 ( Dqn_V2 xy , Dqn_f32 z_ ) : x ( xy . x ) , y ( xy . y ) , z ( z_ ) { }
constexpr bool operator ! = ( Dqn_V3 other ) const { return ! ( * this = = other ) ; }
constexpr bool operator = = ( Dqn_V3 other ) const { return ( x = = other . x ) & & ( y = = other . y ) & & ( z = = other . z ) ; }
constexpr bool operator > = ( Dqn_V3 other ) const { return ( x > = other . x ) & & ( y > = other . y ) & & ( z > = other . z ) ; }
constexpr bool operator < = ( Dqn_V3 other ) const { return ( x < = other . x ) & & ( y < = other . y ) & & ( z < = other . z ) ; }
constexpr bool operator < ( Dqn_V3 other ) const { return ( x < other . x ) & & ( y < other . y ) & & ( z < other . z ) ; }
constexpr bool operator > ( Dqn_V3 other ) const { return ( x > other . x ) & & ( y > other . y ) & & ( z > other . z ) ; }
constexpr Dqn_V3 operator - ( Dqn_V3 other ) const { Dqn_V3 result ( x - other . x , y - other . y , z - other . z ) ; return result ; }
constexpr Dqn_V3 operator + ( Dqn_V3 other ) const { Dqn_V3 result ( x + other . x , y + other . y , z + other . z ) ; return result ; }
constexpr Dqn_V3 operator * ( Dqn_V3 other ) const { Dqn_V3 result ( x * other . x , y * other . y , z * other . z ) ; return result ; }
constexpr Dqn_V3 operator * ( Dqn_f32 other ) const { Dqn_V3 result ( x * other , y * other , z * other ) ; return result ; }
constexpr Dqn_V3 operator * ( Dqn_i32 other ) const { Dqn_V3 result ( x * other , y * other , z * other ) ; return result ; }
constexpr Dqn_V3 operator / ( Dqn_V3 other ) const { Dqn_V3 result ( x / other . x , y / other . y , z / other . z ) ; return result ; }
constexpr Dqn_V3 operator / ( Dqn_f32 other ) const { Dqn_V3 result ( x / other , y / other , z / other ) ; return result ; }
constexpr Dqn_V3 operator / ( Dqn_i32 other ) const { Dqn_V3 result ( x / other , y / other , z / other ) ; return result ; }
constexpr Dqn_V3 & operator * = ( Dqn_V3 other ) { * this = * this * other ; return * this ; }
constexpr Dqn_V3 & operator * = ( Dqn_f32 other ) { * this = * this * other ; return * this ; }
constexpr Dqn_V3 & operator * = ( Dqn_i32 other ) { * this = * this * other ; return * this ; }
constexpr Dqn_V3 & operator / = ( Dqn_V3 other ) { * this = * this / other ; return * this ; }
constexpr Dqn_V3 & operator / = ( Dqn_f32 other ) { * this = * this / other ; return * this ; }
constexpr Dqn_V3 & operator / = ( Dqn_i32 other ) { * this = * this / other ; return * this ; }
constexpr Dqn_V3 & operator - = ( Dqn_V3 other ) { * this = * this - other ; return * this ; }
constexpr Dqn_V3 & operator + = ( Dqn_V3 other ) { * this = * this + other ; return * this ; }
2019-08-24 01:39:12 +00:00
} ;
union Dqn_V4
{
2019-08-27 12:17:59 +00:00
struct { Dqn_f32 x , y , z , w ; } ;
struct { Dqn_f32 r , g , b , a ; } ;
2019-08-24 01:39:12 +00:00
Dqn_V3 rgb ;
2019-08-27 12:17:59 +00:00
Dqn_f32 e [ 4 ] ;
2019-08-24 01:39:12 +00:00
2019-09-20 06:03:09 +00:00
Dqn_V4 ( ) = default ;
2019-08-27 12:17:59 +00:00
constexpr Dqn_V4 ( Dqn_f32 xyzw ) : x ( xyzw ) , y ( xyzw ) , z ( xyzw ) , w ( xyzw ) { }
constexpr Dqn_V4 ( Dqn_f32 x_ , Dqn_f32 y_ , Dqn_f32 z_ , Dqn_f32 w_ ) : x ( x_ ) , y ( y_ ) , z ( z_ ) , w ( w_ ) { }
constexpr Dqn_V4 ( Dqn_i32 x_ , Dqn_i32 y_ , Dqn_i32 z_ , Dqn_i32 w_ ) : x ( ( Dqn_f32 ) x_ ) , y ( ( Dqn_f32 ) y_ ) , z ( ( Dqn_f32 ) z_ ) , w ( ( Dqn_f32 ) w_ ) { }
constexpr Dqn_V4 ( Dqn_V3 xyz , Dqn_f32 w_ ) : x ( xyz . x ) , y ( xyz . y ) , z ( xyz . z ) , w ( w_ ) { }
2019-08-24 01:39:12 +00:00
constexpr bool operator ! = ( Dqn_V4 other ) const { return ! ( * this = = other ) ; }
constexpr bool operator = = ( Dqn_V4 other ) const { return ( x = = other . x ) & & ( y = = other . y ) & & ( z = = other . z ) & & ( w = = other . w ) ; }
constexpr bool operator > = ( Dqn_V4 other ) const { return ( x > = other . x ) & & ( y > = other . y ) & & ( z > = other . z ) & & ( w > = other . w ) ; }
constexpr bool operator < = ( Dqn_V4 other ) const { return ( x < = other . x ) & & ( y < = other . y ) & & ( z < = other . z ) & & ( w < = other . w ) ; }
constexpr bool operator < ( Dqn_V4 other ) const { return ( x < other . x ) & & ( y < other . y ) & & ( z < other . z ) & & ( w < other . w ) ; }
constexpr bool operator > ( Dqn_V4 other ) const { return ( x > other . x ) & & ( y > other . y ) & & ( z > other . z ) & & ( w > other . w ) ; }
constexpr Dqn_V4 operator - ( Dqn_V4 other ) const { Dqn_V4 result ( x - other . x , y - other . y , z - other . z , w - other . w ) ; return result ; }
constexpr Dqn_V4 operator + ( Dqn_V4 other ) const { Dqn_V4 result ( x + other . x , y + other . y , z + other . z , w + other . w ) ; return result ; }
constexpr Dqn_V4 operator * ( Dqn_V4 other ) const { Dqn_V4 result ( x * other . x , y * other . y , z * other . z , w * other . w ) ; return result ; }
2019-08-27 12:17:59 +00:00
constexpr Dqn_V4 operator * ( Dqn_f32 other ) const { Dqn_V4 result ( x * other , y * other , z * other , w * other ) ; return result ; }
constexpr Dqn_V4 operator * ( Dqn_i32 other ) const { Dqn_V4 result ( x * other , y * other , z * other , w * other ) ; return result ; }
constexpr Dqn_V4 operator / ( Dqn_f32 other ) const { Dqn_V4 result ( x / other , y / other , z / other , w / other ) ; return result ; }
2019-08-24 01:39:12 +00:00
constexpr Dqn_V4 & operator * = ( Dqn_V4 other ) { * this = * this * other ; return * this ; }
2019-08-27 12:17:59 +00:00
constexpr Dqn_V4 & operator * = ( Dqn_f32 other ) { * this = * this * other ; return * this ; }
constexpr Dqn_V4 & operator * = ( Dqn_i32 other ) { * this = * this * other ; return * this ; }
2019-08-24 01:39:12 +00:00
constexpr Dqn_V4 & operator - = ( Dqn_V4 other ) { * this = * this - other ; return * this ; }
constexpr Dqn_V4 & operator + = ( Dqn_V4 other ) { * this = * this + other ; return * this ; }
} ;
struct Dqn_Rect
{
Dqn_V2 min , max ;
Dqn_Rect ( ) = default ;
Dqn_Rect ( Dqn_V2 min , Dqn_V2 max ) : min ( min ) , max ( max ) { }
Dqn_Rect ( Dqn_V2I min , Dqn_V2I max ) : min ( min ) , max ( max ) { }
} ;
struct Dqn_RectI32
{
Dqn_V2I min , max ;
Dqn_RectI32 ( ) = default ;
Dqn_RectI32 ( Dqn_V2I min , Dqn_V2I max ) : min ( min ) , max ( max ) { }
} ;
union Dqn_Mat4
{
2019-08-27 12:17:59 +00:00
Dqn_f32 e [ 16 ] ;
2019-08-24 01:39:12 +00:00
Dqn_V4 row [ 4 ] ;
2019-08-27 12:17:59 +00:00
Dqn_f32 row_major [ 4 ] [ 4 ] ;
Dqn_f32 operator [ ] ( Dqn_usize i ) const { return e [ i ] ; }
2019-08-24 01:39:12 +00:00
} ;
2019-08-26 13:56:50 +00:00
DQN_HEADER_COPY_END
2019-08-24 01:39:12 +00:00
2019-08-27 12:17:59 +00:00
DQN_HEADER_COPY_PROTOTYPE ( template < typename T > int , Dqn_MemCmpType ( T const * ptr1 , T const * ptr2 ) )
2019-08-24 01:39:12 +00:00
{
int result = memcmp ( ptr1 , ptr2 , sizeof ( T ) ) ;
return result ;
}
2019-08-27 12:17:59 +00:00
DQN_HEADER_COPY_PROTOTYPE ( template < typename T > T * , Dqn_MemZero ( T * src ) )
2019-08-24 01:39:12 +00:00
{
2019-09-21 00:14:03 +00:00
T * result = DQN_CAST ( T * ) memset ( src , 0 , sizeof ( T ) ) ;
2019-08-24 01:39:12 +00:00
return result ;
}
2019-09-20 11:29:57 +00:00
// @ -------------------------------------------------------------------------------------------------
// @
// @ NOTE: Dqn_Allocator
// @
// @ -------------------------------------------------------------------------------------------------
DQN_HEADER_COPY_BEGIN
// NOTE: The default allocator is the heap allocator
enum struct Dqn_Allocator_Type
{
Heap , // Malloc, realloc, free
XHeap , // Malloc realloc, free, crash on failure
Arena ,
2019-10-29 11:22:35 +00:00
Custom ,
2020-02-08 07:47:48 +00:00
Null ,
2019-09-20 11:29:57 +00:00
} ;
2019-10-29 11:22:35 +00:00
# define DQN_ALLOCATOR_ALLOCATE_PROC(name) void *name(Dqn_usize size)
# define DQN_ALLOCATOR_REALLOC_PROC(name) void *name(void *old_ptr, Dqn_usize old_size, Dqn_usize new_size)
# define DQN_ALLOCATOR_FREE_PROC(name) void name(void *ptr)
typedef DQN_ALLOCATOR_ALLOCATE_PROC ( Dqn_Allocator_AllocateProc ) ;
typedef DQN_ALLOCATOR_REALLOC_PROC ( Dqn_Allocator_ReallocProc ) ;
typedef DQN_ALLOCATOR_FREE_PROC ( Dqn_Allocator_FreeProc ) ;
2019-09-20 11:29:57 +00:00
struct Dqn_Allocator
{
Dqn_Allocator_Type type ;
void * data ;
2019-10-29 11:22:35 +00:00
2020-02-22 14:19:59 +00:00
isize bytes_allocated ;
isize total_bytes_allocated ;
isize allocations ;
isize total_allocations ;
2019-10-29 11:22:35 +00:00
// NOTE: Only required if type == Dqn_Allocator_Type::Custom
Dqn_Allocator_AllocateProc * allocate ;
Dqn_Allocator_ReallocProc * realloc ;
Dqn_Allocator_FreeProc * free ;
2019-09-20 11:29:57 +00:00
} ;
2019-10-29 11:22:35 +00:00
2019-09-20 11:29:57 +00:00
DQN_HEADER_COPY_END
2019-08-26 13:24:22 +00:00
// @ -------------------------------------------------------------------------------------------------
// @
// @ NOTE: Dqn_MemArena
// @
// @ -------------------------------------------------------------------------------------------------
2019-08-27 12:17:59 +00:00
DQN_HEADER_COPY_BEGIN
struct Dqn_MemBlock
2019-08-24 01:39:12 +00:00
{
2019-08-27 12:17:59 +00:00
void * memory ;
2019-09-20 11:29:57 +00:00
Dqn_usize size ;
Dqn_usize used ;
2019-08-27 12:17:59 +00:00
Dqn_MemBlock * prev ;
Dqn_MemBlock * next ;
2019-08-24 01:39:12 +00:00
} ;
2019-08-24 04:20:53 +00:00
struct Dqn_MemArena
2019-08-24 01:39:12 +00:00
{
2019-09-20 11:29:57 +00:00
// NOTE: Configuration (fill once after "Zero Initialisation {}")
int min_block_size = DQN_KILOBYTES ( 4 ) ;
Dqn_Allocator allocator ;
2019-08-24 01:39:12 +00:00
// NOTE: Read Only
2019-08-27 12:17:59 +00:00
Dqn_MemBlock * curr_mem_block ;
Dqn_MemBlock * top_mem_block ;
2019-09-20 11:29:57 +00:00
Dqn_usize highest_used_mark ;
2019-08-27 12:17:59 +00:00
int total_allocated_mem_blocks ;
2019-08-24 01:39:12 +00:00
} ;
2019-08-24 04:20:53 +00:00
struct Dqn_MemArenaScopedRegion
2019-08-24 01:39:12 +00:00
{
2019-08-24 04:20:53 +00:00
Dqn_MemArenaScopedRegion ( Dqn_MemArena * arena ) ;
~ Dqn_MemArenaScopedRegion ( ) ;
Dqn_MemArena * arena ;
2019-08-27 12:17:59 +00:00
Dqn_MemBlock * curr_mem_block ;
2019-09-10 11:35:18 +00:00
Dqn_usize curr_mem_block_used ;
2019-08-27 12:17:59 +00:00
Dqn_MemBlock * top_mem_block ;
2019-08-24 01:39:12 +00:00
} ;
2019-08-27 12:17:59 +00:00
# if defined(DQN_DEBUG_DQN_MEM_ARENA_LOGGING)
# define DQN_DEBUG_ARGS , char const *file, Dqn_isize file_len, char const *func, Dqn_isize func_len, Dqn_isize line
2019-08-24 01:39:12 +00:00
# define DQN_DEBUG_PARAMS , DQN_STR_AND_LEN(__FILE__), DQN_STR_AND_LEN(__func__), __LINE__
# else
# define DQN_DEBUG_ARGS
# define DQN_DEBUG_PARAMS
# endif
2020-02-08 07:47:48 +00:00
# define DQN_MEM_ARENA_INIT_WITH_ALLOCATOR(allocator, size) Dqn_MemArena_InitWithAllocator(allocator, size DQN_DEBUG_PARAMS)
# define DQN_MEM_ARENA_INIT_MEMORY(src, size) Dqn_MemArena_InitMemory(src, size DQN_DEBUG_PARAMS)
2019-09-19 11:49:11 +00:00
# define DQN_MEM_ARENA_ALLOC(arena, size) Dqn_MemArena_Alloc(arena, size DQN_DEBUG_PARAMS)
# define DQN_MEM_ARENA_ALLOC_ARRAY(arena, T, num) (T *)Dqn_MemArena_Alloc(arena, sizeof(T) * num DQN_DEBUG_PARAMS)
# define DQN_MEM_ARENA_ALLOC_STRUCT(arena, T) (T *)Dqn_MemArena_Alloc(arena, sizeof(T) DQN_DEBUG_PARAMS)
# define DQN_MEM_ARENA_RESERVE(arena, size) Dqn_MemArena_Reserve(arena, size DQN_DEBUG_PARAMS)
2019-09-23 13:21:14 +00:00
# define DQN_MEM_ARENA_FREE(arena) Dqn_MemArena_Free(arena)
2019-08-26 13:56:50 +00:00
DQN_HEADER_COPY_END
2019-08-24 01:39:12 +00:00
2019-09-24 04:13:29 +00:00
// @ -------------------------------------------------------------------------------------------------
// @
// @ NOTE: Dqn_Allocator
// @
// @ -------------------------------------------------------------------------------------------------
2020-02-08 07:47:48 +00:00
DQN_HEADER_COPY_PROTOTYPE ( Dqn_Allocator , inline Dqn_Allocator_Null ( ) )
2019-09-24 04:13:29 +00:00
{
Dqn_Allocator result = { } ;
2020-02-08 07:47:48 +00:00
result . type = Dqn_Allocator_Type : : Null ;
2019-09-24 04:13:29 +00:00
return result ;
}
2020-02-08 07:47:48 +00:00
DQN_HEADER_COPY_PROTOTYPE ( Dqn_Allocator , inline Dqn_Allocator_Heap ( ) )
2019-09-24 04:13:29 +00:00
{
Dqn_Allocator result = { } ;
result . type = Dqn_Allocator_Type : : Heap ;
return result ;
}
2020-02-08 07:47:48 +00:00
DQN_HEADER_COPY_PROTOTYPE ( Dqn_Allocator , inline Dqn_Allocator_XHeap ( ) )
2019-09-24 04:13:29 +00:00
{
Dqn_Allocator result = { } ;
result . type = Dqn_Allocator_Type : : XHeap ;
return result ;
}
2020-02-08 07:47:48 +00:00
DQN_HEADER_COPY_PROTOTYPE ( Dqn_Allocator , inline Dqn_Allocator_Arena ( Dqn_MemArena * arena ) )
2019-09-24 04:13:29 +00:00
{
Dqn_Allocator result = { } ;
result . type = Dqn_Allocator_Type : : Arena ;
result . data = arena ;
return result ;
}
2020-02-08 07:47:48 +00:00
// @ -------------------------------------------------------------------------------------------------
// @
// @ NOTE: String
// @
// @ -------------------------------------------------------------------------------------------------
DQN_HEADER_COPY_BEGIN
struct Dqn_String
{
2020-02-22 14:19:59 +00:00
union {
// NOTE: To appease GCC, Clang can't assign C string literal to char *
// Only UB if you try modify a string originally declared const
char const * str_ ;
char * str ;
} ;
2020-02-08 07:47:48 +00:00
Dqn_isize len ;
char const * begin ( ) const { return str ; }
char const * end ( ) const { return str + len ; }
char * begin ( ) { return str ; }
char * end ( ) { return str + len ; }
} ;
# define DQN_STRING_LITERAL(string) {string, Dqn_CharCountI(string)}
DQN_HEADER_COPY_END
2019-09-10 11:35:18 +00:00
// @ -------------------------------------------------------------------------------------------------
// @
// @ NOTE: String Builder
// @
// @ -------------------------------------------------------------------------------------------------
DQN_HEADER_COPY_BEGIN
2019-08-24 03:38:58 +00:00
struct Dqn_StringBuilderBuffer
2019-08-24 01:39:12 +00:00
{
2019-08-24 03:38:58 +00:00
char * mem ;
2019-09-20 11:29:57 +00:00
Dqn_usize size ;
2020-01-31 10:02:26 +00:00
Dqn_usize used ;
2019-08-24 03:38:58 +00:00
Dqn_StringBuilderBuffer * next ;
2019-08-24 01:39:12 +00:00
} ;
2019-08-27 12:17:59 +00:00
Dqn_usize constexpr DQN_STRING_BUILDER_MIN_MEM_BUF_ALLOC_SIZE = DQN_KILOBYTES ( 4 ) ;
template < Dqn_usize N = DQN_KILOBYTES ( 16 ) >
2019-08-24 03:38:58 +00:00
struct Dqn_StringBuilder
2019-08-24 01:39:12 +00:00
{
2019-09-20 11:29:57 +00:00
Dqn_Allocator allocator ;
2019-08-24 03:38:58 +00:00
char fixed_mem [ N ] ;
2019-09-20 11:29:57 +00:00
Dqn_usize fixed_mem_used ;
2019-08-24 03:38:58 +00:00
Dqn_StringBuilderBuffer * next_mem_buf ;
Dqn_StringBuilderBuffer * last_mem_buf ;
2019-09-10 11:35:18 +00:00
Dqn_isize string_len ;
2019-08-24 01:39:12 +00:00
} ;
2019-09-10 11:35:18 +00:00
DQN_HEADER_COPY_END
2019-08-24 01:39:12 +00:00
2019-08-27 12:32:04 +00:00
template < Dqn_usize N > DQN_FILE_SCOPE char * Dqn_StringBuilder__GetWriteBufferAndUpdateUsage ( Dqn_StringBuilder < N > * builder , Dqn_usize size_required )
2019-08-24 05:43:14 +00:00
{
char * result = builder - > fixed_mem + builder - > fixed_mem_used ;
2019-08-27 12:17:59 +00:00
Dqn_usize space = Dqn_ArrayCount ( builder - > fixed_mem ) - builder - > fixed_mem_used ;
Dqn_usize * usage = & builder - > fixed_mem_used ;
2019-08-24 05:43:14 +00:00
if ( builder - > last_mem_buf )
{
Dqn_StringBuilderBuffer * last_buf = builder - > last_mem_buf ;
2019-09-20 11:29:57 +00:00
result = last_buf - > mem + last_buf - > used ;
space = last_buf - > size - last_buf - > used ;
usage = & last_buf - > used ;
2019-08-24 05:43:14 +00:00
}
if ( space < size_required )
{
// NOTE: Need to allocate new buf
2019-08-27 12:17:59 +00:00
Dqn_usize allocation_size = sizeof ( * builder - > last_mem_buf ) + DQN_MAX ( size_required , DQN_STRING_BUILDER_MIN_MEM_BUF_ALLOC_SIZE ) ;
2019-09-20 11:29:57 +00:00
void * memory = Dqn_Allocator_Allocate ( & builder - > allocator , allocation_size ) ;
if ( ! memory ) return nullptr ;
auto * new_buf = DQN_CAST ( Dqn_StringBuilderBuffer * ) memory ;
2019-08-24 05:43:14 +00:00
* new_buf = { } ;
2019-09-20 11:29:57 +00:00
new_buf - > mem = DQN_CAST ( char * ) memory + sizeof ( * new_buf ) ;
2019-08-24 05:43:14 +00:00
new_buf - > size = allocation_size ;
result = new_buf - > mem ;
usage = & new_buf - > used ;
if ( builder - > last_mem_buf )
{
builder - > last_mem_buf - > next = new_buf ;
}
else
{
builder - > next_mem_buf = new_buf ;
builder - > last_mem_buf = new_buf ;
}
}
if ( size_required > 0 & & * usage > 0 & & result [ - 1 ] = = 0 )
{
// NOTE: Not first time writing into buffer using sprintf, sprintf always writes a null terminator, so we must
// subtract one
( * usage ) - - ;
result - - ;
}
* usage + = size_required ;
return result ;
}
2019-08-27 12:32:04 +00:00
template < Dqn_usize N > DQN_FILE_SCOPE void Dqn_StringBuilder__BuildOutput ( Dqn_StringBuilder < N > const * builder , char * dest , Dqn_isize dest_size )
2019-08-24 05:43:14 +00:00
{
// NOTE: No data appended to builder, just allocate am empty string. But
// always allocate, so we avoid adding making nullptr part of the possible
// return values and makes using Dqn_StringBuilder more complex.
if ( dest_size = = 1 )
{
dest [ 0 ] = 0 ;
return ;
}
char const * end = dest + dest_size ;
char * buf_ptr = dest ;
memcpy ( buf_ptr , builder - > fixed_mem , builder - > fixed_mem_used ) ;
buf_ptr + = builder - > fixed_mem_used ;
2019-08-27 12:17:59 +00:00
Dqn_isize remaining_space = end - buf_ptr ;
2019-08-24 05:43:14 +00:00
DQN_ASSERT ( remaining_space > = 0 ) ;
for ( Dqn_StringBuilderBuffer * string_buf = builder - > next_mem_buf ;
string_buf & & remaining_space > 0 ;
string_buf = string_buf - > next )
{
buf_ptr - - ; // We always copy the null terminator from the buffers, so if we know we have another buffer to copy from, remove the null terminator
memcpy ( buf_ptr , string_buf - > mem , string_buf - > used ) ;
buf_ptr + = string_buf - > used ;
remaining_space = end - buf_ptr ;
DQN_ASSERT ( remaining_space > = 0 ) ;
}
DQN_ASSERT ( buf_ptr = = dest + dest_size ) ;
}
2019-08-26 13:24:22 +00:00
// @ The necessary length to build the string, it returns the length including the null-terminator
2019-08-27 12:17:59 +00:00
DQN_HEADER_COPY_PROTOTYPE ( template < Dqn_usize N > Dqn_isize , Dqn_StringBuilder_BuildLen ( Dqn_StringBuilder < N > const * builder ) )
2019-08-24 05:43:14 +00:00
{
2019-08-27 12:17:59 +00:00
Dqn_isize result = builder - > string_len + 1 ;
2019-08-24 05:43:14 +00:00
return result ;
}
2019-08-27 12:17:59 +00:00
DQN_HEADER_COPY_PROTOTYPE ( template < Dqn_usize N > void , Dqn_StringBuilder_BuildInBuffer ( Dqn_StringBuilder < N > const * builder , char * dest , Dqn_usize dest_size ) )
2019-08-24 05:43:14 +00:00
{
Dqn_StringBuilder__BuildOutput ( builder , dest , dest_size ) ;
}
2020-02-08 07:47:48 +00:00
DQN_HEADER_COPY_PROTOTYPE ( template < Dqn_usize N > char * , Dqn_StringBuilder_Build ( Dqn_StringBuilder < N > * builder , Dqn_Allocator * allocator , Dqn_isize * len = nullptr ) )
2019-08-24 05:43:14 +00:00
{
2019-08-27 12:17:59 +00:00
Dqn_isize len_w_null_terminator = Dqn_StringBuilder_BuildLen ( builder ) ;
2020-02-08 07:47:48 +00:00
auto * result = DQN_CAST ( char * ) Dqn_Allocator_Allocate ( allocator , sizeof ( char ) * len_w_null_terminator ) ;
2020-02-22 14:19:59 +00:00
if ( len ) * len = ( len_w_null_terminator - 1 ) ;
2019-08-24 05:43:14 +00:00
Dqn_StringBuilder__BuildOutput ( builder , result , len_w_null_terminator ) ;
return result ;
}
2020-02-08 07:47:48 +00:00
DQN_HEADER_COPY_PROTOTYPE ( template < Dqn_usize N > Dqn_String , Dqn_StringBuilder_BuildString ( Dqn_StringBuilder < N > * builder , Dqn_Allocator * allocator ) )
2019-08-24 05:43:14 +00:00
{
2020-02-08 07:47:48 +00:00
Dqn_String result = { } ;
2020-02-22 14:19:59 +00:00
result . str = Dqn_StringBuilder_Build ( builder , allocator , & result . len ) ;
2019-08-24 05:43:14 +00:00
return result ;
}
2019-08-27 12:17:59 +00:00
DQN_HEADER_COPY_PROTOTYPE ( template < Dqn_usize N > void , Dqn_StringBuilder_VFmtAppend ( Dqn_StringBuilder < N > * builder , char const * fmt , va_list va ) )
2019-08-24 05:43:14 +00:00
{
if ( ! fmt ) return ;
2019-08-27 12:17:59 +00:00
Dqn_isize require = stbsp_vsnprintf ( nullptr , 0 , fmt , va ) + 1 ;
2019-08-24 05:43:14 +00:00
char * buf = Dqn_StringBuilder__GetWriteBufferAndUpdateUsage ( builder , require ) ;
stbsp_vsnprintf ( buf , static_cast < int > ( require ) , fmt , va ) ;
builder - > string_len + = ( require - 1 ) ; // -1 to exclude null terminator
}
2019-08-27 12:17:59 +00:00
DQN_HEADER_COPY_PROTOTYPE ( template < Dqn_usize N > void , Dqn_StringBuilder_FmtAppend ( Dqn_StringBuilder < N > * builder , char const * fmt , . . . ) )
2019-08-24 05:43:14 +00:00
{
va_list va ;
va_start ( va , fmt ) ;
Dqn_StringBuilder_VFmtAppend ( builder , fmt , va ) ;
va_end ( va ) ;
}
2019-08-27 12:17:59 +00:00
DQN_HEADER_COPY_PROTOTYPE ( template < Dqn_usize N > void , Dqn_StringBuilder_Append ( Dqn_StringBuilder < N > * builder , char const * str , Dqn_isize len = - 1 ) )
2019-08-24 05:43:14 +00:00
{
if ( ! str ) return ;
2020-01-31 10:02:26 +00:00
if ( len = = - 1 ) len = DQN_CAST ( Dqn_isize ) strlen ( str ) ;
2020-02-22 14:19:59 +00:00
if ( len = = 0 ) return ;
2019-08-27 12:17:59 +00:00
Dqn_isize len_w_null_terminator = len + 1 ;
2019-08-24 05:43:14 +00:00
char * buf = Dqn_StringBuilder__GetWriteBufferAndUpdateUsage ( builder , len_w_null_terminator ) ;
2019-09-20 06:03:09 +00:00
memcpy ( buf , str , len ) ;
2019-08-24 05:43:14 +00:00
builder - > string_len + = len ;
buf [ len ] = 0 ;
}
2020-02-22 14:19:59 +00:00
DQN_HEADER_COPY_PROTOTYPE ( template < Dqn_usize N > void , Dqn_StringBuilder_AppendString ( Dqn_StringBuilder < N > * builder , Dqn_String const string ) )
{
if ( ! string . str | | string . len = = 0 ) return ;
Dqn_isize len_w_null_terminator = string . len + 1 ;
char * buf = Dqn_StringBuilder__GetWriteBufferAndUpdateUsage ( builder , len_w_null_terminator ) ;
memcpy ( buf , string . str , string . len ) ;
builder - > string_len + = string . len ;
buf [ string . len ] = 0 ;
}
2019-08-27 12:17:59 +00:00
DQN_HEADER_COPY_PROTOTYPE ( template < Dqn_usize N > void , Dqn_StringBuilder_AppendChar ( Dqn_StringBuilder < N > * builder , char ch ) )
2019-08-24 05:43:14 +00:00
{
char * buf = Dqn_StringBuilder__GetWriteBufferAndUpdateUsage ( builder , 1 + 1 /*null terminator*/ ) ;
* buf + + = ch ;
builder - > string_len + + ;
buf [ 1 ] = 0 ;
}
2019-09-20 11:29:57 +00:00
DQN_HEADER_COPY_PROTOTYPE ( template < Dqn_usize N > void , Dqn_StringBuilder_Free ( Dqn_StringBuilder < N > * builder ) )
{
for ( Dqn_StringBuilderBuffer * buffer = builder - > next_mem_buf ;
buffer ;
)
{
2019-09-30 12:58:02 +00:00
Dqn_StringBuilderBuffer * buffer_to_free = buffer ;
buffer = buffer - > next ;
2019-09-20 11:29:57 +00:00
Dqn_Allocator_Free ( & builder - > allocator , buffer_to_free ) ;
}
builder - > next_mem_buf = builder - > last_mem_buf = nullptr ;
builder - > fixed_mem_used = 0 ;
builder - > string_len = 0 ;
}
2019-08-26 13:24:22 +00:00
// @ -------------------------------------------------------------------------------------------------
// @
2019-08-27 12:17:59 +00:00
// @ NOTE: Dqn_Slices
2019-08-26 13:24:22 +00:00
// @
// @ -------------------------------------------------------------------------------------------------
2019-08-24 01:39:12 +00:00
template < typename T >
2019-08-27 12:17:59 +00:00
struct Dqn_Slice
2019-08-24 01:39:12 +00:00
{
2020-02-08 07:47:48 +00:00
T * data ;
Dqn_isize len ;
2019-08-24 01:39:12 +00:00
2019-08-27 12:17:59 +00:00
T const & operator [ ] ( Dqn_isize i ) const { DQN_ASSERT_MSG ( i > = 0 & & i < len , " %d >= 0 && %d < %d " , i , len ) ; return data [ i ] ; }
T & operator [ ] ( Dqn_isize i ) { DQN_ASSERT_MSG ( i > = 0 & & i < len , " %d >= 0 && %d < %d " , i , len ) ; return data [ i ] ; }
2020-02-08 07:47:48 +00:00
T const * begin ( ) const { return data ; }
T const * end ( ) const { return data + len ; }
T * begin ( ) { return data ; }
T * end ( ) { return data + len ; }
2019-08-27 12:17:59 +00:00
T const * operator + ( Dqn_isize i ) const { DQN_ASSERT_MSG ( i > = 0 & & i < len , " %d >= 0 && %d < %d " , i , len ) ; return data + i ; }
T * operator + ( Dqn_isize i ) { DQN_ASSERT_MSG ( i > = 0 & & i < len , " %d >= 0 && %d < %d " , i , len ) ; return data + i ; }
2019-08-24 01:39:12 +00:00
} ;
2019-08-27 12:17:59 +00:00
DQN_HEADER_COPY_PROTOTYPE ( template < typename T > inline Dqn_Slice < T > , Dqn_Slice_CopyNullTerminated ( Dqn_MemArena * arena , T const * src , Dqn_isize len ) )
2019-08-24 01:39:12 +00:00
{
2019-08-27 12:17:59 +00:00
Dqn_Slice < T > result = { } ;
2019-08-24 01:39:12 +00:00
result . len = len ;
2019-08-27 12:17:59 +00:00
result . buf = DQN_MEM_ARENA_ALLOC_ARRAY ( arena , T , len + 1 ) ;
2019-09-20 06:03:09 +00:00
memcpy ( result . buf , src , len * sizeof ( T ) ) ;
2019-08-24 01:39:12 +00:00
result . buf [ len ] = 0 ;
return result ;
}
2019-08-27 12:17:59 +00:00
DQN_HEADER_COPY_PROTOTYPE ( template < typename T > inline Dqn_Slice < T > , Dqn_Slice_CopyNullTerminated ( Dqn_MemArena * arena , Dqn_Slice < T > const src ) )
2019-08-24 01:39:12 +00:00
{
2019-08-27 12:17:59 +00:00
Dqn_Slice < T > result = Dqn_Slice_CopyNullTerminated ( arena , src . buf , src . len ) ;
2019-08-24 01:39:12 +00:00
return result ;
}
2019-08-27 12:17:59 +00:00
DQN_HEADER_COPY_PROTOTYPE ( template < typename T > inline Dqn_Slice < T > , Dqn_Slice_Copy ( Dqn_MemArena * arena , T const * src , Dqn_isize len ) )
2019-08-24 01:39:12 +00:00
{
2019-08-27 12:17:59 +00:00
Dqn_Slice < T > result = { } ;
2019-08-24 01:39:12 +00:00
result . len = len ;
2019-08-27 12:17:59 +00:00
result . buf = DQN_MEM_ARENA_ALLOC_ARRAY ( arena , T , len ) ;
2019-09-23 13:21:14 +00:00
memcpy ( result . buf , src , len * sizeof ( T ) ) ;
2019-08-24 01:39:12 +00:00
return result ;
}
2019-08-27 12:17:59 +00:00
DQN_HEADER_COPY_PROTOTYPE ( template < typename T > inline Dqn_Slice < T > , Dqn_Slice_Copy ( Dqn_MemArena * arena , Dqn_Slice < T > const src ) )
2019-08-24 01:39:12 +00:00
{
2019-08-27 12:17:59 +00:00
Dqn_Slice < T > result = Dqn_Slice_Copy ( arena , src . buf , src . len ) ;
2019-08-24 01:39:12 +00:00
return result ;
}
2019-08-27 12:17:59 +00:00
DQN_HEADER_COPY_PROTOTYPE ( template < typename T > inline bool , Dqn_Slice_Equals ( Dqn_Slice < T > const a , Dqn_Slice < T > const b ) )
{
bool result = false ;
if ( a . len ! = b . len ) return result ;
result = ( memcmp ( a . buf , b . buf , a . len ) = = 0 ) ;
return result ;
}
2019-08-26 13:24:22 +00:00
// @ -------------------------------------------------------------------------------------------------
// @
// @ NOTE: Dqn_FixedArray
// @
// @ -------------------------------------------------------------------------------------------------
2019-08-27 12:17:59 +00:00
template < typename T > void Dqn__EraseStableFromCArray ( T * array , Dqn_isize len , Dqn_isize max , Dqn_isize index )
{
DQN_ASSERT ( index > = 0 & & index < len ) ;
2019-09-23 13:21:14 +00:00
DQN_ASSERT ( len < = max ) ; ( void ) max ;
2019-08-27 12:17:59 +00:00
Dqn_isize next_index = DQN_MIN ( index + 1 , len ) ;
Dqn_usize bytes_to_copy = ( len - next_index ) * sizeof ( T ) ;
2019-09-20 06:03:09 +00:00
memmove ( array + index , array + next_index , bytes_to_copy ) ;
2019-08-27 12:17:59 +00:00
}
DQN_HEADER_COPY_BEGIN
2019-08-26 13:24:22 +00:00
# define DQN_FIXED_ARRAY_TEMPLATE template <typename T, int MAX_>
# define DQN_FIXED_ARRAY_TEMPLATE_DECL Dqn_FixedArray<T, MAX_>
DQN_FIXED_ARRAY_TEMPLATE struct Dqn_FixedArray
2019-08-24 01:39:12 +00:00
{
2019-09-23 13:21:14 +00:00
T data [ MAX_ ] ;
Dqn_isize len ;
2019-08-27 12:17:59 +00:00
2019-09-23 13:21:14 +00:00
T & operator [ ] ( Dqn_isize i ) { DQN_ASSERT_MSG ( i > = 0 & & i < = len , " %jd >= 0 && %jd < %jd " , i , len ) ; return data [ i ] ; }
2019-08-27 12:17:59 +00:00
T * begin ( ) { return data ; }
T * end ( ) { return data + len ; }
2019-09-23 13:21:14 +00:00
T * operator + ( Dqn_isize i ) { DQN_ASSERT_MSG ( i > = 0 & & i < = len , " %jd >= 0 && %jd < %jd " , i , len ) ; return data + i ; }
2019-08-27 12:17:59 +00:00
2019-09-23 13:21:14 +00:00
T const & operator [ ] ( Dqn_isize i ) const { DQN_ASSERT_MSG ( i > = 0 & & i < = len , " %jd >= 0 && %jd < %jd " , i , i , len ) ; return data [ i ] ; }
2019-08-27 12:17:59 +00:00
T const * begin ( ) const { return data ; }
T const * end ( ) const { return data + len ; }
2019-09-23 13:21:14 +00:00
T const * operator + ( Dqn_isize i ) const { DQN_ASSERT_MSG ( i > = 0 & & i < = len , " %jd >= 0 && %jd < %jd " , i , len ) ; return data + i ; }
2019-08-24 01:39:12 +00:00
} ;
2019-08-27 12:17:59 +00:00
DQN_HEADER_COPY_END
2019-08-26 13:24:22 +00:00
2019-09-23 13:21:14 +00:00
DQN_FIXED_ARRAY_TEMPLATE
DQN_HEADER_COPY_PROTOTYPE ( int , Dqn_FixedArray_Capacity ( DQN_FIXED_ARRAY_TEMPLATE_DECL * ) )
{
int result = MAX_ ;
return result ;
}
2019-08-26 13:24:22 +00:00
DQN_FIXED_ARRAY_TEMPLATE
DQN_HEADER_COPY_PROTOTYPE ( DQN_FIXED_ARRAY_TEMPLATE_DECL , Dqn_FixedArray_Init ( T const * item , int num ) )
{
DQN_FIXED_ARRAY_TEMPLATE_DECL result = { } ;
Dqn_FixedArray_Add ( & result , item , num ) ;
return result ;
}
DQN_FIXED_ARRAY_TEMPLATE
2019-08-27 12:17:59 +00:00
DQN_HEADER_COPY_PROTOTYPE ( T * , Dqn_FixedArray_Add ( DQN_FIXED_ARRAY_TEMPLATE_DECL * a , T const * items , Dqn_isize num ) )
2019-08-26 13:24:22 +00:00
{
DQN_ASSERT ( a - > len + num < = MAX_ ) ;
2019-09-20 06:03:09 +00:00
T * result = static_cast < T * > ( memcpy ( a - > data + a - > len , items , sizeof ( T ) * num ) ) ;
2019-08-26 13:24:22 +00:00
a - > len + = num ;
return result ;
}
DQN_FIXED_ARRAY_TEMPLATE
DQN_HEADER_COPY_PROTOTYPE ( T * , Dqn_FixedArray_Add ( DQN_FIXED_ARRAY_TEMPLATE_DECL * a , T const item ) )
{
DQN_ASSERT ( a - > len < MAX_ ) ;
a - > data [ a - > len + + ] = item ;
return & a - > data [ a - > len - 1 ] ;
}
DQN_FIXED_ARRAY_TEMPLATE
2019-08-27 12:17:59 +00:00
DQN_HEADER_COPY_PROTOTYPE ( T * , Dqn_FixedArray_Make ( DQN_FIXED_ARRAY_TEMPLATE_DECL * a , Dqn_isize num ) )
2019-08-26 13:24:22 +00:00
{
DQN_ASSERT ( a - > len + num < = MAX_ ) ;
T * result = a - > data + a - > len ;
a - > len + = num ;
return result ;
}
DQN_FIXED_ARRAY_TEMPLATE
DQN_HEADER_COPY_PROTOTYPE ( void , Dqn_FixedArray_Clear ( DQN_FIXED_ARRAY_TEMPLATE_DECL * a ) )
{
a - > len = 0 ;
}
DQN_FIXED_ARRAY_TEMPLATE
2019-08-27 12:17:59 +00:00
DQN_HEADER_COPY_PROTOTYPE ( void , Dqn_FixedArray_EraseStable ( DQN_FIXED_ARRAY_TEMPLATE_DECL * a , Dqn_isize index ) )
2019-08-26 13:24:22 +00:00
{
2019-09-23 13:21:14 +00:00
Dqn__EraseStableFromCArray < T > ( a - > data , a - > len - - , MAX_ , index ) ;
2019-08-26 13:24:22 +00:00
}
DQN_FIXED_ARRAY_TEMPLATE
2019-08-27 12:17:59 +00:00
DQN_HEADER_COPY_PROTOTYPE ( void , Dqn_FixedArray_EraseUnstable ( DQN_FIXED_ARRAY_TEMPLATE_DECL * a , Dqn_isize index ) )
2019-08-26 13:24:22 +00:00
{
DQN_ASSERT ( index > = 0 & & index < a - > len ) ;
if ( - - a - > len = = 0 ) return ;
a - > data [ index ] = a - > data [ a - > len ] ;
}
DQN_FIXED_ARRAY_TEMPLATE
2020-01-17 15:01:25 +00:00
DQN_HEADER_COPY_PROTOTYPE ( void , Dqn_FixedArray_Pop ( DQN_FIXED_ARRAY_TEMPLATE_DECL * a , Dqn_isize num = 1 ) )
2019-08-26 13:24:22 +00:00
{
DQN_ASSERT ( a - > len - num > = 0 ) ;
a - > len - = num ;
}
DQN_FIXED_ARRAY_TEMPLATE
DQN_HEADER_COPY_PROTOTYPE ( T * , Dqn_FixedArray_Peek ( DQN_FIXED_ARRAY_TEMPLATE_DECL * a ) )
{
T * result = ( a - > len = = 0 ) ? nullptr : a - > data + ( a - > len - 1 ) ;
return result ;
}
DQN_FIXED_ARRAY_TEMPLATE
2019-08-27 12:17:59 +00:00
DQN_HEADER_COPY_PROTOTYPE ( Dqn_isize , Dqn_FixedArray_GetIndex ( DQN_FIXED_ARRAY_TEMPLATE_DECL * a , T const * entry ) )
2019-08-26 13:24:22 +00:00
{
2019-08-27 12:17:59 +00:00
Dqn_isize result = a - > end ( ) - entry ;
2019-08-26 13:24:22 +00:00
return result ;
}
2019-08-24 01:39:12 +00:00
template < typename T , int MAX_ , typename EqualityProc >
2019-08-26 13:24:22 +00:00
DQN_HEADER_COPY_PROTOTYPE ( T * , Dqn_FixedArray_Find ( DQN_FIXED_ARRAY_TEMPLATE_DECL * a , EqualityProc IsEqual ) )
2019-08-24 01:39:12 +00:00
{
for ( T & entry : ( * a ) )
{
if ( IsEqual ( & entry ) )
return & entry ;
}
return nullptr ;
}
2019-08-26 13:24:22 +00:00
DQN_FIXED_ARRAY_TEMPLATE
2019-09-20 06:03:09 +00:00
DQN_HEADER_COPY_PROTOTYPE ( T * , Dqn_FixedArray_Find ( DQN_FIXED_ARRAY_TEMPLATE_DECL * a , T * find ) )
2019-08-24 01:39:12 +00:00
{
for ( T & entry : ( * a ) )
{
2019-09-20 06:03:09 +00:00
if ( * find = = entry )
return entry ;
2019-08-24 01:39:12 +00:00
}
return nullptr ;
}
2019-08-26 13:24:22 +00:00
// @ -------------------------------------------------------------------------------------------------
// @
2019-09-19 11:49:11 +00:00
// @ NOTE: Dqn_Array
2019-08-26 13:24:22 +00:00
// @
// @ -------------------------------------------------------------------------------------------------
2019-08-27 12:17:59 +00:00
DQN_HEADER_COPY_BEGIN
2019-09-19 11:49:11 +00:00
// TODO(doyle): Make this either initialised from memory or dynamically allocating
template < typename T > struct Dqn_Array
{
Dqn_Allocator allocator ;
T * data ;
Dqn_isize len ;
Dqn_isize max ;
T const operator [ ] ( Dqn_isize i ) const { DQN_ASSERT_MSG ( i > = 0 & & i < len , " %d >= 0 && %d < %d " , i , len ) ; return data [ i ] ; }
T operator [ ] ( Dqn_isize i ) { DQN_ASSERT_MSG ( i > = 0 & & i < len , " %d >= 0 && %d < %d " , i , len ) ; return data [ i ] ; }
T const * begin ( ) const { return data ; }
T const * end ( ) const { return data + len ; }
T * begin ( ) { return data ; }
T * end ( ) { return data + len ; }
T const * operator + ( Dqn_isize i ) const { DQN_ASSERT_MSG ( i > = 0 & & i < len , " %d >= 0 && %d < %d " , i , len ) ; return data + i ; }
T * operator + ( Dqn_isize i ) { DQN_ASSERT_MSG ( i > = 0 & & i < len , " %d >= 0 && %d < %d " , i , len ) ; return data + i ; }
2019-08-24 01:39:12 +00:00
} ;
2019-08-27 12:17:59 +00:00
DQN_HEADER_COPY_END
2019-09-19 11:49:11 +00:00
DQN_HEADER_COPY_PROTOTYPE ( template < typename T > Dqn_Array < T > , Dqn_Array_InitMemory ( T * memory , Dqn_isize max , Dqn_isize len = 0 ) )
{
Dqn_Array < T > result = { } ;
2020-02-08 07:47:48 +00:00
result . allocator = Dqn_Allocator_Null ( ) ;
2019-09-19 11:49:11 +00:00
result . data = memory ;
result . len = len ;
result . max = max ;
return result ;
}
DQN_HEADER_COPY_PROTOTYPE ( template < typename T > bool , Dqn_Array_Reserve ( Dqn_Array < T > * a , Dqn_isize size ) )
{
if ( size < = a - > len ) return true ;
T * new_ptr = nullptr ;
if ( a - > data ) new_ptr = DQN_CAST ( T * ) Dqn_Allocator_Realloc ( & a - > allocator , a - > data , sizeof ( T ) * a - > max , sizeof ( T ) * size ) ;
else new_ptr = DQN_CAST ( T * ) Dqn_Allocator_Allocate ( & a - > allocator , sizeof ( T ) * size ) ;
if ( ! new_ptr ) return false ;
a - > data = new_ptr ;
a - > max = size ;
return true ;
}
DQN_HEADER_COPY_PROTOTYPE ( template < typename T > void , Dqn_Array_Free ( Dqn_Array < T > * a ) )
{
Dqn_Allocator_Free ( & a - > allocator , a - > data ) ;
}
template < typename T > bool Dqn_Array__GrowIfNeeded ( Dqn_Array < T > * a , Dqn_isize num_to_add )
{
Dqn_isize new_len = a - > len + num_to_add ;
bool result = true ;
if ( new_len > a - > max )
{
Dqn_isize num_items = DQN_MAX ( 4 , DQN_MAX ( new_len , ( a - > max * 2 ) ) ) ;
result = Dqn_Array_Reserve ( a , num_items ) ;
}
return result ;
}
DQN_HEADER_COPY_PROTOTYPE ( template < typename T > T * , Dqn_Array_Add ( Dqn_Array < T > * a , T const * items , Dqn_isize num ) )
{
if ( ! Dqn_Array__GrowIfNeeded ( a , num ) )
return nullptr ;
2019-09-20 06:03:09 +00:00
T * result = static_cast < T * > ( memcpy ( a - > data + a - > len , items , sizeof ( T ) * num ) ) ;
2019-09-19 11:49:11 +00:00
a - > len + = num ;
return result ;
}
DQN_HEADER_COPY_PROTOTYPE ( template < typename T > T * , Dqn_Array_Add ( Dqn_Array < T > * a , T const item ) )
{
if ( ! Dqn_Array__GrowIfNeeded ( a , 1 ) )
return nullptr ;
a - > data [ a - > len + + ] = item ;
return & a - > data [ a - > len - 1 ] ;
}
DQN_HEADER_COPY_PROTOTYPE ( template < typename T > T * , Dqn_Array_Make ( Dqn_Array < T > * a , Dqn_isize num ) )
{
if ( ! Dqn_Array__GrowIfNeeded ( a , num ) )
return nullptr ;
T * result = a - > data + a - > len ;
a - > len + = num ;
return result ;
}
DQN_HEADER_COPY_PROTOTYPE ( template < typename T > void , Dqn_Array_Clear ( Dqn_Array < T > * a , bool zero_mem = false ) )
{
a - > len = 0 ;
if ( zero_mem ) memset ( a - > data , 0 , sizeof ( T ) * a - > max ) ;
}
DQN_HEADER_COPY_PROTOTYPE ( template < typename T > void , Dqn_Array_EraseStable ( Dqn_Array < T > * a , Dqn_isize index ) )
{
Dqn__EraseStableFromCArray < T > ( a - > data , a - > len - - , a - > max , index ) ;
}
DQN_HEADER_COPY_PROTOTYPE ( template < typename T > void ,
Dqn_Array_EraseUnstable ( Dqn_Array < T > * a , Dqn_isize index ) )
{
DQN_ASSERT ( index > = 0 & & index < a - > len ) ;
if ( - - a - > len = = 0 ) return ;
a - > data [ index ] = a - > data [ a - > len ] ;
}
DQN_HEADER_COPY_PROTOTYPE ( template < typename T > void , Dqn_Array_Pop ( Dqn_Array < T > * a , Dqn_isize num ) )
{
DQN_ASSERT ( a - > len - num > = 0 ) ;
a - > len - = num ;
}
DQN_HEADER_COPY_PROTOTYPE ( template < typename T > T * , Dqn_Array_Peek ( Dqn_Array < T > * a ) )
{
T * result = ( a - > len = = 0 ) ? nullptr : a - > data + ( a - > len - 1 ) ;
return result ;
}
2019-08-24 01:39:12 +00:00
2019-08-26 13:24:22 +00:00
// @ -------------------------------------------------------------------------------------------------
// @
// @ NOTE: Dqn_FixedString
// @
// @ -------------------------------------------------------------------------------------------------
2019-08-27 12:17:59 +00:00
DQN_HEADER_COPY_BEGIN
template < Dqn_isize MAX_ >
2019-08-24 04:20:53 +00:00
struct Dqn_FixedString
2019-08-24 01:39:12 +00:00
{
union { char data [ MAX_ ] ; char str [ MAX_ ] ; char buf [ MAX_ ] ; } ;
2019-09-23 13:21:14 +00:00
Dqn_isize len ;
2019-08-24 01:39:12 +00:00
2019-08-24 04:20:53 +00:00
Dqn_FixedString ( ) { data [ 0 ] = 0 ; len = 0 ; }
2019-08-27 12:17:59 +00:00
Dqn_FixedString ( char const * fmt , . . . )
{
* this = { } ;
va_list va ;
va_start ( va , fmt ) ;
Dqn_FixedString_AppendVFmt ( this , fmt , va ) ;
va_end ( va ) ;
}
2019-08-24 01:39:12 +00:00
2019-09-23 13:21:14 +00:00
Dqn_b32 operator = = ( Dqn_FixedString const & other ) const
{
if ( len ! = other . len ) return false ;
bool result = memcmp ( data , other . data , len ) ;
return result ;
}
Dqn_b32 operator ! = ( Dqn_FixedString const & other ) const { return ! ( * this = = other ) ; }
2019-08-27 12:17:59 +00:00
char const & operator [ ] ( Dqn_isize i ) const { DQN_ASSERT_MSG ( i > = 0 & & i < len , " %d >= 0 && %d < %d " , i , len ) ; return data [ i ] ; }
char & operator [ ] ( Dqn_isize i ) { DQN_ASSERT_MSG ( i > = 0 & & i < len , " %d >= 0 && %d < %d " , i , len ) ; return data [ i ] ; }
2019-08-24 01:39:12 +00:00
char const * begin ( ) const { return data ; }
char const * end ( ) const { return data + len ; }
char * begin ( ) { return data ; }
char * end ( ) { return data + len ; }
} ;
2019-08-27 12:17:59 +00:00
DQN_HEADER_COPY_END
2019-08-24 01:39:12 +00:00
2019-09-23 13:21:14 +00:00
DQN_HEADER_COPY_PROTOTYPE ( template < Dqn_isize MAX_ > int , Dqn_FixedString_Capacity ( Dqn_FixedString < MAX_ > * ) )
{
int result = MAX_ ;
return result ;
}
2019-08-27 12:17:59 +00:00
DQN_HEADER_COPY_PROTOTYPE ( template < Dqn_isize MAX_ > void , Dqn_FixedString_Clear ( Dqn_FixedString < MAX_ > * str ) ) { * str = { } ; }
2019-09-23 13:21:14 +00:00
DQN_HEADER_COPY_PROTOTYPE ( template < Dqn_isize MAX_ > Dqn_b32 , Dqn_FixedString_AppendVFmt ( Dqn_FixedString < MAX_ > * str , char const * fmt , va_list va ) )
2019-08-24 01:39:12 +00:00
{
2019-08-27 12:17:59 +00:00
Dqn_isize require = stbsp_vsnprintf ( nullptr , 0 , fmt , va ) + 1 ;
Dqn_isize space = MAX_ - str - > len ;
2019-09-23 13:21:14 +00:00
Dqn_b32 result = require < = space ;
2019-08-24 01:39:12 +00:00
DQN_ASSERT ( require < = space ) ;
str - > len + = stbsp_vsnprintf ( str - > data + str - > len , static_cast < int > ( space ) , fmt , va ) ;
2019-09-23 13:21:14 +00:00
return result ;
2019-08-24 01:39:12 +00:00
}
2019-09-23 13:21:14 +00:00
DQN_HEADER_COPY_PROTOTYPE ( template < Dqn_isize MAX_ > Dqn_b32 , Dqn_FixedString_AppendFmt ( Dqn_FixedString < MAX_ > * str , char const * fmt , . . . ) )
2019-08-24 01:39:12 +00:00
{
va_list va ;
va_start ( va , fmt ) ;
2019-09-23 13:21:14 +00:00
Dqn_b32 result = Dqn_FixedString_AppendVFmt ( str , fmt , va ) ;
2019-08-24 01:39:12 +00:00
va_end ( va ) ;
2019-09-23 13:21:14 +00:00
return result ;
2019-08-24 01:39:12 +00:00
}
2019-09-23 13:21:14 +00:00
DQN_HEADER_COPY_PROTOTYPE ( template < Dqn_isize MAX_ > Dqn_b32 , Dqn_FixedString_Append ( Dqn_FixedString < MAX_ > * str , char const * src , Dqn_isize len = - 1 ) )
2019-08-24 01:39:12 +00:00
{
2020-01-31 10:02:26 +00:00
if ( len = = - 1 ) len = DQN_CAST ( Dqn_isize ) strlen ( src ) ;
2019-08-27 12:17:59 +00:00
Dqn_isize space = MAX_ - str - > len ;
2019-09-23 13:21:14 +00:00
Dqn_b32 result = true ;
DQN_IF_ASSERT_MSG ( len < space , " len: %jd, space: %jd " , len , space )
{
len = space ;
result = false ;
}
2019-08-24 01:39:12 +00:00
memcpy ( str - > data + str - > len , src , len ) ;
str - > len + = len ;
str - > str [ str - > len ] = 0 ;
2019-09-23 13:21:14 +00:00
return result ;
2019-08-24 01:39:12 +00:00
}
2019-08-27 12:17:59 +00:00
// @ -------------------------------------------------------------------------------------------------
// @
2019-09-23 13:21:14 +00:00
// @ NOTE: Dqn_U64Str
2019-08-27 12:17:59 +00:00
// @
// @ -------------------------------------------------------------------------------------------------
DQN_HEADER_COPY_BEGIN
struct Dqn_U64Str
2019-08-24 01:39:12 +00:00
{
// Points to the start of the str in the buffer, not necessarily buf since
// we write into the buffer in reverse
2019-09-30 12:58:02 +00:00
char * str ;
2020-01-31 10:02:26 +00:00
char buf [ 27 ] ; // NOTE(doyle): 27 is the maximum size of Dqn_u64 including commas
int len ;
2019-08-24 01:39:12 +00:00
} ;
2019-08-27 12:17:59 +00:00
DQN_HEADER_COPY_END
2019-09-19 11:49:11 +00:00
# undef _CRT_SECURE_NO_WARNINGS
2019-08-24 01:39:12 +00:00
# endif // DQN_H
# ifdef DQN_IMPLEMENTATION
2019-09-19 11:49:11 +00:00
# define _CRT_SECURE_NO_WARNINGS
2019-09-30 12:58:02 +00:00
# define STB_SPRINTF_IMPLEMENTATION
2019-09-20 06:03:09 +00:00
# include <limits.h>
2019-08-24 01:39:12 +00:00
# include <math.h>
# include <memory.h>
# include <stdio.h>
2020-01-31 10:02:26 +00:00
DQN_HEADER_COPY_PROTOTYPE ( char * , Dqn_U64Str_ToStr ( Dqn_u64 val , Dqn_U64Str * result , Dqn_b32 comma_sep ) )
2019-11-01 13:00:39 +00:00
{
int buf_index = ( int ) ( Dqn_ArrayCount ( result - > buf ) - 1 ) ;
result - > buf [ buf_index - - ] = 0 ;
if ( val = = 0 )
{
result - > buf [ buf_index - - ] = ' 0 ' ;
result - > len = 1 ;
}
else
{
for ( int digit_count = 0 ; val > 0 ; result - > len + + , digit_count + + )
{
if ( comma_sep & & ( digit_count ! = 0 ) & & ( digit_count % 3 = = 0 ) )
{
result - > buf [ buf_index - - ] = ' , ' ;
result - > len + + ;
}
2020-01-31 10:02:26 +00:00
auto digit = DQN_CAST ( char ) ( val % 10 ) ;
2019-11-01 13:00:39 +00:00
result - > buf [ buf_index - - ] = ' 0 ' + digit ;
val / = 10 ;
}
}
result - > str = result - > buf + ( buf_index + 1 ) ;
return result - > str ;
}
2019-08-26 13:24:22 +00:00
// @ -------------------------------------------------------------------------------------------------
// @
// @ NOTE: Logging
// @
// @ -------------------------------------------------------------------------------------------------
2019-08-27 12:17:59 +00:00
DQN_HEADER_COPY_PROTOTYPE ( void , Dqn_LogV ( Dqn_LogType type , char const * file , Dqn_usize file_len , char const * func , Dqn_usize func_len , Dqn_usize line , char const * fmt , va_list va ) )
2019-08-24 01:39:12 +00:00
{
char const * file_ptr = file ;
2020-01-31 10:02:26 +00:00
auto file_ptr_len = DQN_CAST ( Dqn_isize ) file_len ;
for ( Dqn_isize i = ( file_ptr_len - 1 ) ; i > = 0 ; - - i )
2019-08-24 01:39:12 +00:00
{
if ( file_ptr [ i ] = = ' \\ ' | | file_ptr [ i ] = = ' / ' )
{
char const * file_end = file_ptr + file_ptr_len ;
file_ptr = file_ptr + ( i + 1 ) ;
file_ptr_len = static_cast < int > ( file_end - file_ptr ) ;
break ;
}
}
FILE * handle = ( type = = Dqn_LogType : : Error ) ? stderr : stdout ;
fprintf ( handle ,
" %.*s %05zu %.*s %s " ,
( int ) file_ptr_len ,
file_ptr ,
line ,
( int ) func_len ,
func ,
Dqn_LogTypeTag ( type ) ) ;
vfprintf ( handle , fmt , va ) ;
fprintf ( handle , " \n " ) ;
}
2019-09-23 13:21:14 +00:00
// @ return: This returns a boolean as a hack so you can combine it in if expressions. I use it for my IF_ASSERT macro
DQN_HEADER_COPY_PROTOTYPE ( Dqn_b32 , Dqn_Log ( Dqn_LogType type , char const * file , Dqn_usize file_len , char const * func , Dqn_usize func_len , Dqn_usize line , char const * fmt , . . . ) )
2019-08-24 01:39:12 +00:00
{
va_list va ;
va_start ( va , fmt ) ;
Dqn_LogV ( type , file , file_len , func , func_len , line , fmt , va ) ;
va_end ( va ) ;
2019-09-23 13:21:14 +00:00
return true ;
2019-08-24 01:39:12 +00:00
}
2020-02-08 07:47:48 +00:00
void * Dqn_MemArena_Alloc ( Dqn_MemArena * arena , Dqn_usize size DQN_DEBUG_ARGS ) ;
Dqn_b32 Dqn_MemArena_Reserve ( Dqn_MemArena * arena , Dqn_usize size DQN_DEBUG_ARGS ) ;
2019-09-20 11:29:57 +00:00
DQN_HEADER_COPY_PROTOTYPE ( void * , Dqn_Allocator_Allocate ( Dqn_Allocator * allocator , Dqn_usize size ) )
{
void * result = nullptr ;
switch ( allocator - > type )
2019-08-24 01:39:12 +00:00
{
2020-02-08 07:47:48 +00:00
case Dqn_Allocator_Type : : Null :
2019-09-20 11:29:57 +00:00
default : break ;
2020-01-31 10:02:26 +00:00
2019-09-20 11:29:57 +00:00
case Dqn_Allocator_Type : : Heap :
case Dqn_Allocator_Type : : XHeap :
{
2020-02-08 07:47:48 +00:00
result = calloc ( 1 , size ) ;
2019-09-20 11:29:57 +00:00
if ( ! result & & allocator - > type = = Dqn_Allocator_Type : : XHeap )
2019-09-23 13:21:14 +00:00
{
2019-09-20 11:29:57 +00:00
DQN_ASSERT ( result ) ;
2019-09-23 13:21:14 +00:00
}
2019-09-20 11:29:57 +00:00
}
break ;
case Dqn_Allocator_Type : : Arena :
{
auto * arena = static_cast < Dqn_MemArena * > ( allocator - > data ) ;
result = DQN_MEM_ARENA_ALLOC ( arena , size ) ;
}
break ;
2019-10-29 11:22:35 +00:00
case Dqn_Allocator_Type : : Custom :
{
if ( allocator - > allocate )
result = allocator - > allocate ( size ) ;
}
break ;
2019-08-24 01:39:12 +00:00
}
2019-09-20 11:29:57 +00:00
2020-02-22 14:19:59 +00:00
if ( result )
{
allocator - > allocations + + ;
allocator - > total_bytes_allocated + = size ;
}
2019-09-20 11:29:57 +00:00
return result ;
}
DQN_HEADER_COPY_PROTOTYPE ( void * , Dqn_Allocator_Realloc ( Dqn_Allocator * allocator , void * old_ptr , Dqn_isize old_size , Dqn_isize new_size ) )
{
2020-01-31 10:02:26 +00:00
DQN_IF_ASSERT ( old_size > = 0 ) old_size = 0 ;
DQN_IF_ASSERT ( new_size > = 0 ) new_size = 0 ;
2020-02-22 14:19:59 +00:00
DQN_ASSERT ( new_size > old_size ) ;
2020-01-31 10:02:26 +00:00
2019-09-20 11:29:57 +00:00
void * result = nullptr ;
switch ( allocator - > type )
2019-08-24 01:39:12 +00:00
{
2020-02-08 07:47:48 +00:00
case Dqn_Allocator_Type : : Null :
2019-09-20 11:29:57 +00:00
default : break ;
2020-01-31 10:02:26 +00:00
2019-09-20 11:29:57 +00:00
case Dqn_Allocator_Type : : Heap :
case Dqn_Allocator_Type : : XHeap :
{
2020-01-31 10:02:26 +00:00
result = realloc ( old_ptr , DQN_CAST ( size_t ) new_size ) ;
2019-09-20 11:29:57 +00:00
if ( ! result & & allocator - > type = = Dqn_Allocator_Type : : XHeap )
2019-09-23 13:21:14 +00:00
{
2019-09-20 11:29:57 +00:00
DQN_ASSERT ( result ) ;
2019-09-23 13:21:14 +00:00
}
2019-09-20 11:29:57 +00:00
}
break ;
case Dqn_Allocator_Type : : Arena :
{
auto * arena = static_cast < Dqn_MemArena * > ( allocator - > data ) ;
2020-01-31 10:02:26 +00:00
if ( DQN_MEM_ARENA_RESERVE ( arena , DQN_CAST ( size_t ) new_size ) )
2019-09-20 11:29:57 +00:00
{
2020-01-31 10:02:26 +00:00
result = DQN_MEM_ARENA_ALLOC ( arena , DQN_CAST ( size_t ) new_size ) ;
if ( result ) memcpy ( result , old_ptr , DQN_CAST ( size_t ) old_size ) ;
2019-09-20 11:29:57 +00:00
}
}
break ;
2019-10-29 11:22:35 +00:00
case Dqn_Allocator_Type : : Custom :
{
if ( allocator - > realloc )
2020-01-31 10:02:26 +00:00
result = allocator - > realloc ( old_ptr , DQN_CAST ( size_t ) old_size , DQN_CAST ( size_t ) new_size ) ;
2019-10-29 11:22:35 +00:00
}
break ;
2019-08-24 01:39:12 +00:00
}
2020-02-22 14:19:59 +00:00
if ( result )
{
allocator - > total_bytes_allocated + = new_size ;
allocator - > total_allocations + + ;
}
2019-09-20 11:29:57 +00:00
return result ;
}
DQN_HEADER_COPY_PROTOTYPE ( void , Dqn_Allocator_Free ( Dqn_Allocator * allocator , void * ptr ) )
{
switch ( allocator - > type )
{
2020-02-08 07:47:48 +00:00
case Dqn_Allocator_Type : : Null :
2019-09-20 11:29:57 +00:00
default : break ;
2020-01-31 10:02:26 +00:00
2019-09-20 11:29:57 +00:00
case Dqn_Allocator_Type : : Heap :
case Dqn_Allocator_Type : : XHeap :
{
free ( ptr ) ;
}
break ;
2019-10-29 11:22:35 +00:00
case Dqn_Allocator_Type : : Custom :
{
allocator - > free ( ptr ) ;
}
break ;
2019-09-20 11:29:57 +00:00
case Dqn_Allocator_Type : : Arena :
break ;
}
2020-02-22 14:19:59 +00:00
if ( ptr )
{
allocator - > total_allocations + + ;
allocator - > allocations - - ;
DQN_ASSERT ( allocator - > allocations > = 0 ) ;
}
2019-09-20 11:29:57 +00:00
}
// @ -------------------------------------------------------------------------------------------------
// @
// @ NOTE: Dqn_MemArena
// @
// @ -------------------------------------------------------------------------------------------------
DQN_FILE_SCOPE Dqn_MemBlock * Dqn_MemArena__AllocateBlock ( Dqn_MemArena * arena , Dqn_usize requested_size )
{
2020-01-31 10:02:26 +00:00
DQN_ASSERT ( arena - > min_block_size > 0 ) ;
Dqn_usize mem_block_size = DQN_MAX ( DQN_CAST ( Dqn_usize ) arena - > min_block_size , requested_size ) ;
2019-09-20 11:29:57 +00:00
Dqn_usize const allocate_size = sizeof ( * arena - > curr_mem_block ) + mem_block_size ;
Dqn_MemBlock * result = DQN_CAST ( Dqn_MemBlock * ) Dqn_Allocator_Allocate ( & arena - > allocator , allocate_size ) ;
if ( ! result ) return result ;
2019-08-24 01:39:12 +00:00
* result = { } ;
result - > size = mem_block_size ;
2019-09-20 11:29:57 +00:00
result - > memory = DQN_CAST ( Dqn_u8 * ) result + sizeof ( * result ) ;
2019-08-24 01:39:12 +00:00
arena - > total_allocated_mem_blocks + + ;
return result ;
}
2019-08-27 12:32:04 +00:00
DQN_FILE_SCOPE void Dqn_MemArena__FreeBlock ( Dqn_MemArena * arena , Dqn_MemBlock * block )
2019-08-24 01:39:12 +00:00
{
if ( ! block )
return ;
if ( block - > next )
block - > next - > prev = block - > prev ;
if ( block - > prev )
block - > prev - > next = block - > next ;
2019-09-20 11:29:57 +00:00
Dqn_Allocator_Free ( & arena - > allocator , block ) ;
2019-08-24 01:39:12 +00:00
}
2019-08-27 12:32:04 +00:00
DQN_FILE_SCOPE void Dqn_MemArena__AttachBlock ( Dqn_MemArena * arena , Dqn_MemBlock * new_block )
2019-08-24 01:39:12 +00:00
{
2019-09-20 11:29:57 +00:00
if ( arena - > top_mem_block )
{
DQN_ASSERT ( arena - > top_mem_block - > next = = nullptr ) ;
arena - > top_mem_block - > next = new_block ;
new_block - > prev = arena - > top_mem_block ;
arena - > top_mem_block = new_block ;
}
else
2019-08-24 01:39:12 +00:00
{
2019-09-20 11:29:57 +00:00
arena - > top_mem_block = new_block ;
arena - > curr_mem_block = new_block ;
2019-08-24 01:39:12 +00:00
}
}
2019-08-27 12:17:59 +00:00
DQN_HEADER_COPY_PROTOTYPE ( void * , Dqn_MemArena_Alloc ( Dqn_MemArena * arena , Dqn_usize size DQN_DEBUG_ARGS ) )
2019-08-24 01:39:12 +00:00
{
2019-08-27 12:17:59 +00:00
# if defined(DQN_DEBUG_DQN_MEM_ARENA_LOGGING)
2019-08-24 01:39:12 +00:00
( void ) file ; ( void ) file_len ; ( void ) func ; ( void ) func_len ; ( void ) line ;
# endif
2019-08-27 12:17:59 +00:00
Dqn_b32 need_new_mem_block = true ;
for ( Dqn_MemBlock * mem_block = arena - > curr_mem_block ; mem_block ; mem_block = mem_block - > next )
2019-08-24 01:39:12 +00:00
{
2019-08-27 12:17:59 +00:00
Dqn_b32 can_fit_in_block = ( mem_block - > used + size ) < = mem_block - > size ;
2019-08-24 01:39:12 +00:00
if ( can_fit_in_block )
{
arena - > curr_mem_block = mem_block ;
need_new_mem_block = false ;
break ;
}
}
if ( need_new_mem_block )
{
2019-08-27 12:17:59 +00:00
Dqn_MemBlock * new_block = Dqn_MemArena__AllocateBlock ( arena , size ) ;
2019-08-24 01:39:12 +00:00
if ( ! new_block ) return nullptr ;
2019-08-24 04:20:53 +00:00
Dqn_MemArena__AttachBlock ( arena , new_block ) ;
2019-08-24 01:39:12 +00:00
arena - > curr_mem_block = arena - > top_mem_block ;
}
2019-08-27 12:17:59 +00:00
void * result = static_cast < Dqn_u8 * > ( arena - > curr_mem_block - > memory ) + arena - > curr_mem_block - > used ;
2019-08-24 01:39:12 +00:00
arena - > curr_mem_block - > used + = size ;
DQN_ASSERT ( arena - > curr_mem_block - > used < = arena - > curr_mem_block - > size ) ;
return result ;
}
2019-08-26 13:24:22 +00:00
DQN_HEADER_COPY_PROTOTYPE ( void , Dqn_MemArena_Free ( Dqn_MemArena * arena DQN_DEBUG_ARGS ) )
2019-08-24 01:39:12 +00:00
{
2019-08-27 12:17:59 +00:00
# if defined(DQN_DEBUG_DQN_MEM_ARENA_LOGGING)
2019-08-24 01:39:12 +00:00
( void ) file ; ( void ) file_len ; ( void ) func ; ( void ) func_len ; ( void ) line ;
# endif
2019-08-27 12:17:59 +00:00
for ( Dqn_MemBlock * mem_block = arena - > top_mem_block ; mem_block ; )
2019-08-24 01:39:12 +00:00
{
2019-08-27 12:17:59 +00:00
Dqn_MemBlock * block_to_free = mem_block ;
2019-09-20 11:29:57 +00:00
mem_block = block_to_free - > prev ;
2019-08-24 04:20:53 +00:00
Dqn_MemArena__FreeBlock ( arena , block_to_free ) ;
2019-08-24 01:39:12 +00:00
}
2019-09-20 11:29:57 +00:00
auto allocator = arena - > allocator ;
2019-08-24 01:39:12 +00:00
auto highest_used_mark = arena - > highest_used_mark ;
* arena = { } ;
arena - > highest_used_mark = highest_used_mark ;
2019-09-20 11:29:57 +00:00
arena - > allocator = allocator ;
2019-08-24 01:39:12 +00:00
}
2019-08-27 12:17:59 +00:00
DQN_HEADER_COPY_PROTOTYPE ( Dqn_b32 , Dqn_MemArena_Reserve ( Dqn_MemArena * arena , Dqn_usize size DQN_DEBUG_ARGS ) )
2019-08-24 01:39:12 +00:00
{
2019-08-27 12:17:59 +00:00
# if defined(DQN_DEBUG_DQN_MEM_ARENA_LOGGING)
2019-08-24 01:39:12 +00:00
( void ) file ; ( void ) file_len ; ( void ) func ; ( void ) func_len ; ( void ) line ;
# endif
2019-10-29 11:22:35 +00:00
if ( arena - > top_mem_block )
{
Dqn_usize remaining_space = arena - > top_mem_block - > size - arena - > top_mem_block - > used ;
if ( remaining_space > = size ) return true ;
}
2019-08-24 01:39:12 +00:00
2019-08-27 12:17:59 +00:00
Dqn_MemBlock * new_block = Dqn_MemArena__AllocateBlock ( arena , size ) ;
2019-08-24 01:39:12 +00:00
if ( ! new_block ) return false ;
2019-08-24 04:20:53 +00:00
Dqn_MemArena__AttachBlock ( arena , new_block ) ;
2019-08-24 01:39:12 +00:00
return true ;
}
2020-02-08 07:47:48 +00:00
DQN_HEADER_COPY_PROTOTYPE ( Dqn_MemArena , Dqn_MemArena_InitWithAllocator ( Dqn_Allocator allocator , Dqn_usize size DQN_DEBUG_ARGS ) )
2019-10-29 11:22:35 +00:00
{
# if defined(DQN_DEBUG_DQN_MEM_ARENA_LOGGING)
( void ) file ; ( void ) file_len ; ( void ) func ; ( void ) func_len ; ( void ) line ;
# endif
2020-02-08 07:47:48 +00:00
Dqn_MemArena result = { } ;
DQN_ASSERT_MSG ( size > = sizeof ( * result . curr_mem_block ) , " (%zu >= %zu) There needs to be enough space to encode the Dqn_MemBlock struct into the memory buffer " , size , sizeof ( * result . curr_mem_block ) ) ;
result . allocator = allocator ;
Dqn_MemBlock * mem_block = Dqn_MemArena__AllocateBlock ( & result , size ) ;
Dqn_MemArena__AttachBlock ( & result , mem_block ) ;
return result ;
2019-10-29 11:22:35 +00:00
}
2020-02-08 07:47:48 +00:00
DQN_HEADER_COPY_PROTOTYPE ( Dqn_MemArena , Dqn_MemArena_InitMemory ( void * memory , Dqn_usize size DQN_DEBUG_ARGS ) )
2019-08-24 01:39:12 +00:00
{
2019-08-27 12:17:59 +00:00
# if defined(DQN_DEBUG_DQN_MEM_ARENA_LOGGING)
2019-08-24 01:39:12 +00:00
( void ) file ; ( void ) file_len ; ( void ) func ; ( void ) func_len ; ( void ) line ;
# endif
2020-02-08 07:47:48 +00:00
Dqn_MemArena result = { } ;
DQN_ASSERT_MSG ( size > = sizeof ( * result . curr_mem_block ) , " (%zu >= %zu) There needs to be enough space to encode the Dqn_MemBlock struct into the memory buffer " , size , sizeof ( * result . curr_mem_block ) ) ;
result . allocator = Dqn_Allocator_Null ( ) ;
auto * mem_block = DQN_CAST ( Dqn_MemBlock * ) memory ;
* mem_block = { } ;
mem_block - > memory = DQN_CAST ( Dqn_u8 * ) memory + sizeof ( * mem_block ) ;
mem_block - > size = size - sizeof ( * mem_block ) ;
Dqn_MemArena__AttachBlock ( & result , mem_block ) ;
return result ;
2019-08-24 01:39:12 +00:00
}
2019-10-29 11:22:35 +00:00
DQN_HEADER_COPY_PROTOTYPE ( void , Dqn_MemArena_ResetUsage ( Dqn_MemArena * arena , Dqn_ZeroMem zero_mem ) )
{
for ( Dqn_MemBlock * block = arena - > top_mem_block ; block ; block = block - > prev )
{
if ( zero_mem = = Dqn_ZeroMem : : Yes )
memset ( block - > memory , 0 , block - > used ) ;
block - > used = 0 ;
if ( ! block - > prev ) arena - > curr_mem_block = block ;
}
}
2019-08-26 13:24:22 +00:00
DQN_HEADER_COPY_PROTOTYPE ( Dqn_MemArenaScopedRegion , Dqn_MemArena_MakeScopedRegion ( Dqn_MemArena * arena ) )
2019-08-24 01:39:12 +00:00
{
2019-08-24 04:20:53 +00:00
return Dqn_MemArenaScopedRegion ( arena ) ;
2019-08-24 01:39:12 +00:00
}
2019-08-24 04:20:53 +00:00
Dqn_MemArenaScopedRegion : : Dqn_MemArenaScopedRegion ( Dqn_MemArena * arena )
2019-08-24 01:39:12 +00:00
{
this - > arena = arena ;
this - > curr_mem_block = arena - > curr_mem_block ;
this - > curr_mem_block_used = ( arena - > curr_mem_block ) ? arena - > curr_mem_block - > used : 0 ;
this - > top_mem_block = arena - > top_mem_block ;
}
2019-08-24 04:20:53 +00:00
Dqn_MemArenaScopedRegion : : ~ Dqn_MemArenaScopedRegion ( )
2019-08-24 01:39:12 +00:00
{
while ( this - > top_mem_block ! = this - > arena - > top_mem_block )
{
2019-08-27 12:17:59 +00:00
Dqn_MemBlock * block_to_free = this - > arena - > top_mem_block ;
2019-08-26 13:56:50 +00:00
if ( this - > arena - > curr_mem_block = = block_to_free )
this - > arena - > curr_mem_block = block_to_free - > prev ;
2019-08-24 01:39:12 +00:00
this - > arena - > top_mem_block = block_to_free - > prev ;
2019-08-24 04:20:53 +00:00
Dqn_MemArena__FreeBlock ( this - > arena , block_to_free ) ;
2019-08-24 01:39:12 +00:00
}
2019-08-27 12:17:59 +00:00
for ( Dqn_MemBlock * mem_block = this - > arena - > top_mem_block ; mem_block ! = this - > curr_mem_block ; mem_block = mem_block - > prev )
2019-08-24 01:39:12 +00:00
mem_block - > used = 0 ;
this - > arena - > curr_mem_block - > used = this - > curr_mem_block_used ;
}
2020-02-08 07:47:48 +00:00
// @ -------------------------------------------------------------------------------------------------
// @
// @ NOTE: Dqn_Asprintf (Allocate Sprintf)
// @
// @ -------------------------------------------------------------------------------------------------
int Dqn_Safe_TruncateISizeToInt ( Dqn_isize val ) ;
DQN_HEADER_COPY_PROTOTYPE ( Dqn_String , Dqn_Asprintf ( Dqn_Allocator * allocator , char const * fmt , va_list va ) )
{
Dqn_String result = { } ;
result . len = stbsp_vsnprintf ( nullptr , 0 , fmt , va ) + 1 ;
result . str = DQN_CAST ( char * ) Dqn_Allocator_Allocate ( allocator , sizeof ( char ) * result . len ) ;
stbsp_vsnprintf ( result . str , Dqn_Safe_TruncateISizeToInt ( result . len ) , fmt , va ) ;
result . str [ result . len - 1 ] = 0 ;
return result ;
}
DQN_HEADER_COPY_PROTOTYPE ( Dqn_String , Dqn_Asprintf ( Dqn_Allocator * allocator , char const * fmt , . . . ) )
{
va_list va ;
va_start ( va , fmt ) ;
Dqn_String result = Dqn_Asprintf ( allocator , fmt , va ) ;
va_end ( va ) ;
return result ;
}
2019-08-26 13:24:22 +00:00
// @ -------------------------------------------------------------------------------------------------
// @
// @ NOTE: Vectors
// @
// @ -------------------------------------------------------------------------------------------------
DQN_HEADER_COPY_PROTOTYPE ( Dqn_V2I , Dqn_V2_ToV2I ( Dqn_V2 a ) )
2019-08-24 01:39:12 +00:00
{
2019-08-27 12:17:59 +00:00
Dqn_V2I result ( static_cast < Dqn_i32 > ( a . x ) , static_cast < Dqn_i32 > ( a . y ) ) ;
2019-08-24 01:39:12 +00:00
return result ;
}
2019-08-26 13:24:22 +00:00
DQN_HEADER_COPY_PROTOTYPE ( Dqn_V2 , Dqn_V2_Max ( Dqn_V2 a , Dqn_V2 b ) )
2019-08-24 01:39:12 +00:00
{
Dqn_V2 result = Dqn_V2 ( DQN_MAX ( a . x , b . x ) , DQN_MAX ( a . y , b . y ) ) ;
return result ;
}
2019-08-26 13:24:22 +00:00
DQN_HEADER_COPY_PROTOTYPE ( Dqn_V2 , Dqn_V2_Abs ( Dqn_V2 a ) )
2019-08-24 01:39:12 +00:00
{
Dqn_V2 result = Dqn_V2 ( DQN_ABS ( a . x ) , DQN_ABS ( a . y ) ) ;
return result ;
}
2019-08-27 12:17:59 +00:00
DQN_HEADER_COPY_PROTOTYPE ( Dqn_f32 , Dqn_V2_Dot ( Dqn_V2 a , Dqn_V2 b ) )
2019-08-24 01:39:12 +00:00
{
2019-08-27 12:17:59 +00:00
Dqn_f32 result = ( a . x * b . x ) + ( a . y * b . y ) ;
2019-08-24 01:39:12 +00:00
return result ;
}
2019-08-27 12:17:59 +00:00
DQN_HEADER_COPY_PROTOTYPE ( Dqn_f32 , Dqn_V2_LengthSq ( Dqn_V2 a , Dqn_V2 b ) )
2019-08-24 01:39:12 +00:00
{
2019-08-27 12:17:59 +00:00
Dqn_f32 x_side = b . x - a . x ;
Dqn_f32 y_side = b . y - a . y ;
Dqn_f32 result = DQN_SQUARED ( x_side ) + DQN_SQUARED ( y_side ) ;
2019-08-24 01:39:12 +00:00
return result ;
}
2019-08-26 13:24:22 +00:00
DQN_HEADER_COPY_PROTOTYPE ( Dqn_V2 , Dqn_V2_Normalise ( Dqn_V2 a ) )
2019-08-24 01:39:12 +00:00
{
2019-08-27 12:17:59 +00:00
Dqn_f32 length_sq = DQN_SQUARED ( a . x ) + DQN_SQUARED ( a . y ) ;
Dqn_f32 length = sqrtf ( length_sq ) ;
2019-08-24 01:39:12 +00:00
Dqn_V2 result = a / length ;
return result ;
}
2019-08-26 13:24:22 +00:00
DQN_HEADER_COPY_PROTOTYPE ( Dqn_V2 , Dqn_V2_Perpendicular ( Dqn_V2 a ) )
2019-08-24 01:39:12 +00:00
{
Dqn_V2 result = Dqn_V2 ( - a . y , a . x ) ;
return result ;
}
2019-08-27 12:17:59 +00:00
DQN_HEADER_COPY_PROTOTYPE ( Dqn_f32 , Dqn_V4_Dot ( Dqn_V4 const * a , Dqn_V4 const * b ) )
2019-08-24 01:39:12 +00:00
{
2019-08-27 12:17:59 +00:00
Dqn_f32 result = ( a - > x * b - > x ) + ( a - > y * b - > y ) + ( a - > z * b - > z ) + ( a - > w * b - > w ) ;
2019-08-24 01:39:12 +00:00
return result ;
}
2019-08-26 13:24:22 +00:00
// @ -------------------------------------------------------------------------------------------------
// @
// @ NOTE: Rect
// @
// @ -------------------------------------------------------------------------------------------------
DQN_HEADER_COPY_PROTOTYPE ( Dqn_Rect , Dqn_Rect_InitFromPosAndSize ( Dqn_V2 pos , Dqn_V2 size ) )
2019-08-24 01:39:12 +00:00
{
Dqn_Rect result = { } ;
result . min = pos ;
if ( size . w < 0 ) result . min . x - = size . w ;
if ( size . h < 0 ) result . min . y - = size . h ;
result . max = result . min + Dqn_V2_Abs ( size ) ;
return result ;
}
2019-08-26 13:24:22 +00:00
DQN_HEADER_COPY_PROTOTYPE ( Dqn_V2 , Dqn_Rect_Center ( Dqn_Rect rect ) )
2019-08-24 01:39:12 +00:00
{
Dqn_V2 size = rect . max - rect . min ;
Dqn_V2 result = rect . min + ( size * 0.5f ) ;
return result ;
}
2019-08-27 12:17:59 +00:00
DQN_HEADER_COPY_PROTOTYPE ( Dqn_b32 , Dqn_Rect_ContainsPoint ( Dqn_Rect rect , Dqn_V2 p ) )
2019-08-24 01:39:12 +00:00
{
2019-08-27 12:17:59 +00:00
Dqn_b32 result = ( p . x > = rect . min . x & & p . x < = rect . max . x & & p . y > = rect . min . y & & p . y < = rect . max . y ) ;
2019-08-24 01:39:12 +00:00
return result ;
}
2019-08-27 12:17:59 +00:00
DQN_HEADER_COPY_PROTOTYPE ( Dqn_b32 , Dqn_Rect_ContainsRect ( Dqn_Rect a , Dqn_Rect b ) )
2019-08-24 01:39:12 +00:00
{
2019-08-27 12:17:59 +00:00
Dqn_b32 result = ( b . min > = a . min & & b . max < = a . max ) ;
2019-08-24 01:39:12 +00:00
return result ;
}
2019-08-26 13:24:22 +00:00
DQN_HEADER_COPY_PROTOTYPE ( Dqn_V2 , Dqn_Rect_Size ( Dqn_Rect rect ) )
2019-08-24 01:39:12 +00:00
{
Dqn_V2 result = rect . max - rect . min ;
return result ;
}
2019-08-26 13:24:22 +00:00
DQN_HEADER_COPY_PROTOTYPE ( Dqn_Rect , Dqn_Rect_Move ( Dqn_Rect src , Dqn_V2 move_amount ) )
2019-08-24 01:39:12 +00:00
{
Dqn_Rect result = src ;
result . min + = move_amount ;
result . max + = move_amount ;
return result ;
}
2020-01-17 15:01:25 +00:00
DQN_HEADER_COPY_PROTOTYPE ( Dqn_Rect , Dqn_Rect_Intersection ( Dqn_Rect a , Dqn_Rect b ) )
{
Dqn_Rect result = { } ;
if ( a . min . x > = b . min . x & & a . min . x < = b . max . x ) result . min . x = a . min . x ;
else if ( b . min . x > = a . min . x & & b . min . x < = a . max . x ) result . min . x = b . min . x ;
else
{
return result ;
}
if ( a . max . x > = b . min . x & & a . max . x < = b . max . x ) result . max . x = a . max . x ;
else if ( b . max . x > = a . min . x & & b . max . x < = a . max . x ) result . max . x = b . max . x ;
if ( a . min . y > = b . min . y & & a . min . y < = b . max . y ) result . min . y = a . min . y ;
else if ( b . min . y > = a . min . y & & b . min . y < = a . max . y ) result . min . y = b . min . y ;
if ( a . max . y > = b . min . y & & a . max . y < = b . max . y ) result . max . y = a . max . y ;
else if ( b . max . y > = a . min . y & & b . max . y < = a . max . y ) result . max . y = b . max . y ;
return result ;
}
2019-08-26 13:24:22 +00:00
DQN_HEADER_COPY_PROTOTYPE ( Dqn_Rect , Dqn_Rect_Union ( Dqn_Rect a , Dqn_Rect b ) )
2019-08-24 01:39:12 +00:00
{
Dqn_Rect result = { } ;
result . min . x = DQN_MIN ( a . min . x , b . min . x ) ;
result . min . y = DQN_MIN ( a . min . y , b . min . y ) ;
result . max . x = DQN_MAX ( a . max . x , b . max . x ) ;
result . max . y = DQN_MAX ( a . max . y , b . max . y ) ;
return result ;
}
2019-08-26 13:24:22 +00:00
DQN_HEADER_COPY_PROTOTYPE ( Dqn_Rect , Dqn_Rect_FromRectI32 ( Dqn_RectI32 a ) )
2019-08-24 01:39:12 +00:00
{
Dqn_Rect result = Dqn_Rect ( a . min , a . max ) ;
return result ;
}
2019-08-26 13:24:22 +00:00
DQN_HEADER_COPY_PROTOTYPE ( Dqn_V2I , Dqn_RectI32_Size ( Dqn_RectI32 rect ) )
2019-08-24 01:39:12 +00:00
{
Dqn_V2I result = rect . max - rect . min ;
return result ;
}
2019-08-26 13:24:22 +00:00
// @ -------------------------------------------------------------------------------------------------
// @
// @ NOTE: Math Utils
// @
// @ -------------------------------------------------------------------------------------------------
2019-08-27 12:17:59 +00:00
DQN_HEADER_COPY_PROTOTYPE ( Dqn_V2 , Dqn_LerpV2 ( Dqn_V2 a , Dqn_f32 t , Dqn_V2 b ) )
2019-08-24 01:39:12 +00:00
{
Dqn_V2 result = { } ;
result . x = a . x + ( ( b . x - a . x ) * t ) ;
result . y = a . y + ( ( b . y - a . y ) * t ) ;
return result ;
}
2019-08-26 13:24:22 +00:00
// @ -------------------------------------------------------------------------------------------------
// @
// @ NOTE: Dqn_Mat4
// @
// @ -------------------------------------------------------------------------------------------------
DQN_HEADER_COPY_PROTOTYPE ( Dqn_Mat4 , Dqn_Mat4_Identity ( ) )
2019-08-24 01:39:12 +00:00
{
Dqn_Mat4 result =
{
1 , 0 , 0 , 0 ,
0 , 1 , 0 , 0 ,
0 , 0 , 1 , 0 ,
0 , 0 , 0 , 1 ,
} ;
return result ;
}
2019-08-27 12:17:59 +00:00
DQN_HEADER_COPY_PROTOTYPE ( Dqn_Mat4 , Dqn_Mat4_Scale3f ( Dqn_f32 x , Dqn_f32 y , Dqn_f32 z ) )
2019-08-24 01:39:12 +00:00
{
Dqn_Mat4 result =
{
x , 0 , 0 , 0 ,
0 , y , 0 , 0 ,
0 , 0 , z , 0 ,
0 , 0 , 0 , 1 ,
} ;
return result ;
}
2019-08-26 13:24:22 +00:00
DQN_HEADER_COPY_PROTOTYPE ( Dqn_Mat4 , Dqn_Mat4_ScaleV3 ( Dqn_V3 vec ) )
2019-08-24 01:39:12 +00:00
{
Dqn_Mat4 result = Dqn_Mat4_Scale3f ( vec . x , vec . y , vec . z ) ;
return result ;
}
2019-08-27 12:17:59 +00:00
DQN_HEADER_COPY_PROTOTYPE ( Dqn_Mat4 , Dqn_Mat4_Translate3f ( Dqn_f32 x , Dqn_f32 y , Dqn_f32 z ) )
2019-08-24 01:39:12 +00:00
{
Dqn_Mat4 result =
{
1 , 0 , 0 , x ,
0 , 1 , 0 , y ,
0 , 0 , 1 , z ,
0 , 0 , 0 , 1 ,
} ;
return result ;
}
2019-08-26 13:24:22 +00:00
DQN_HEADER_COPY_PROTOTYPE ( Dqn_Mat4 , Dqn_Mat4_TranslateV3 ( Dqn_V3 vec ) )
2019-08-24 01:39:12 +00:00
{
Dqn_Mat4 result = Dqn_Mat4_Translate3f ( vec . x , vec . y , vec . z ) ;
return result ;
}
2019-08-26 13:24:22 +00:00
DQN_HEADER_COPY_PROTOTYPE ( Dqn_Mat4 , operator * ( Dqn_Mat4 const & a , Dqn_Mat4 const & b ) )
2019-08-24 01:39:12 +00:00
{
Dqn_V4 const * row1 = a . row + 0 ;
Dqn_V4 const * row2 = a . row + 1 ;
Dqn_V4 const * row3 = a . row + 2 ;
Dqn_V4 const * row4 = a . row + 3 ;
Dqn_V4 const col1 = Dqn_V4 ( b . row_major [ 0 ] [ 0 ] , b . row_major [ 1 ] [ 0 ] , b . row_major [ 2 ] [ 0 ] , b . row_major [ 3 ] [ 0 ] ) ;
Dqn_V4 const col2 = Dqn_V4 ( b . row_major [ 0 ] [ 1 ] , b . row_major [ 1 ] [ 1 ] , b . row_major [ 2 ] [ 1 ] , b . row_major [ 3 ] [ 1 ] ) ;
Dqn_V4 const col3 = Dqn_V4 ( b . row_major [ 0 ] [ 2 ] , b . row_major [ 1 ] [ 2 ] , b . row_major [ 2 ] [ 2 ] , b . row_major [ 3 ] [ 3 ] ) ;
Dqn_V4 const col4 = Dqn_V4 ( b . row_major [ 0 ] [ 3 ] , b . row_major [ 1 ] [ 3 ] , b . row_major [ 2 ] [ 3 ] , b . row_major [ 3 ] [ 3 ] ) ;
Dqn_Mat4 result =
{
Dqn_V4_Dot ( row1 , & col1 ) , Dqn_V4_Dot ( row1 , & col2 ) , Dqn_V4_Dot ( row1 , & col3 ) , Dqn_V4_Dot ( row1 , & col4 ) ,
Dqn_V4_Dot ( row2 , & col1 ) , Dqn_V4_Dot ( row2 , & col2 ) , Dqn_V4_Dot ( row2 , & col3 ) , Dqn_V4_Dot ( row2 , & col4 ) ,
Dqn_V4_Dot ( row3 , & col1 ) , Dqn_V4_Dot ( row3 , & col2 ) , Dqn_V4_Dot ( row3 , & col3 ) , Dqn_V4_Dot ( row3 , & col4 ) ,
Dqn_V4_Dot ( row4 , & col1 ) , Dqn_V4_Dot ( row4 , & col2 ) , Dqn_V4_Dot ( row4 , & col3 ) , Dqn_V4_Dot ( row4 , & col4 ) ,
} ;
return result ;
}
2019-08-26 13:24:22 +00:00
DQN_HEADER_COPY_PROTOTYPE ( Dqn_V4 , operator * ( Dqn_Mat4 const & mat , Dqn_V4 const & vec ) )
2019-08-24 01:39:12 +00:00
{
2019-08-27 12:17:59 +00:00
Dqn_f32 x = vec . x , y = vec . y , z = vec . z , w = vec . w ;
2019-08-24 01:39:12 +00:00
Dqn_V4 result =
{
( mat [ 0 ] * x ) + ( mat [ 1 ] * y ) + ( mat [ 2 ] * z ) + ( mat [ 3 ] * w ) ,
( mat [ 4 ] * x ) + ( mat [ 5 ] * y ) + ( mat [ 6 ] * z ) + ( mat [ 7 ] * w ) ,
( mat [ 8 ] * x ) + ( mat [ 9 ] * y ) + ( mat [ 10 ] * z ) + ( mat [ 11 ] * w ) ,
( mat [ 12 ] * x ) + ( mat [ 13 ] * y ) + ( mat [ 14 ] * z ) + ( mat [ 15 ] * w ) ,
} ;
return result ;
}
2019-08-26 13:24:22 +00:00
// @ -------------------------------------------------------------------------------------------------
// @
// @ NOTE: Helper Functions
// @
// @ -------------------------------------------------------------------------------------------------
2019-08-27 12:17:59 +00:00
DQN_HEADER_COPY_PROTOTYPE ( void , Dqn_Bit_UnsetInplace ( Dqn_u32 * flags , Dqn_u32 bitfield ) )
2019-08-24 01:39:12 +00:00
{
* flags = ( * flags & ~ bitfield ) ;
}
2019-08-27 12:17:59 +00:00
DQN_HEADER_COPY_PROTOTYPE ( void , Dqn_Bit_SetInplace ( Dqn_u32 * flags , Dqn_u32 bitfield ) )
2019-08-24 01:39:12 +00:00
{
* flags = ( * flags | bitfield ) ;
}
2019-08-27 12:17:59 +00:00
DQN_HEADER_COPY_PROTOTYPE ( Dqn_b32 , Dqn_Bit_IsSet ( Dqn_u32 flags , Dqn_u32 bitfield ) )
2019-08-24 01:39:12 +00:00
{
2020-01-31 10:02:26 +00:00
auto result = DQN_CAST ( Dqn_b32 ) ( ( flags & bitfield ) = = 0 ) ;
2019-08-24 01:39:12 +00:00
return result ;
}
2019-08-27 12:17:59 +00:00
DQN_HEADER_COPY_PROTOTYPE ( Dqn_b32 , Dqn_Bit_IsNotSet ( Dqn_u32 flags , Dqn_u32 bitfield ) )
2019-08-24 01:39:12 +00:00
{
2020-01-31 10:02:26 +00:00
auto result = Dqn_Bit_IsSet ( flags , bitfield ) ;
2019-08-24 01:39:12 +00:00
return result ;
}
2019-08-26 13:24:22 +00:00
// @ -------------------------------------------------------------------------------------------------
// @
// @ NOTE: Safe Arithmetic
// @
// @ -------------------------------------------------------------------------------------------------
2019-08-27 12:17:59 +00:00
DQN_HEADER_COPY_PROTOTYPE ( Dqn_i64 , Dqn_Safe_AddI64 ( Dqn_i64 a , Dqn_i64 b ) )
2019-08-24 01:39:12 +00:00
{
DQN_ASSERT_MSG ( a < = INT64_MAX - b , " %zu <= %zu " , a , INT64_MAX - b ) ;
2019-08-27 12:17:59 +00:00
Dqn_i64 result = a + b ;
2019-08-24 01:39:12 +00:00
return result ;
}
2019-08-27 12:17:59 +00:00
DQN_HEADER_COPY_PROTOTYPE ( Dqn_i64 , Dqn_Safe_MulI64 ( Dqn_i64 a , Dqn_i64 b ) )
2019-08-24 01:39:12 +00:00
{
DQN_ASSERT_MSG ( a < = INT64_MAX / b , " %zu <= %zu " , a , INT64_MAX / b ) ;
2019-08-27 12:17:59 +00:00
Dqn_i64 result = a * b ;
2019-08-24 01:39:12 +00:00
return result ;
}
2019-08-27 12:17:59 +00:00
DQN_HEADER_COPY_PROTOTYPE ( Dqn_u64 , Dqn_Safe_AddU64 ( Dqn_u64 a , Dqn_u64 b ) )
2019-08-24 01:39:12 +00:00
{
DQN_ASSERT_MSG ( a < = UINT64_MAX - b , " %zu <= %zu " , a , UINT64_MAX - b ) ;
2019-08-27 12:17:59 +00:00
Dqn_u64 result = a + b ;
2019-08-24 01:39:12 +00:00
return result ;
}
2019-08-27 12:17:59 +00:00
DQN_HEADER_COPY_PROTOTYPE ( Dqn_u64 , Dqn_Safe_MulU64 ( Dqn_u64 a , Dqn_u64 b ) )
2019-08-24 01:39:12 +00:00
{
DQN_ASSERT_MSG ( a < = UINT64_MAX / b , " %zu <= %zu " , a , UINT64_MAX / b ) ;
2019-08-27 12:17:59 +00:00
Dqn_u64 result = a * b ;
2019-08-24 01:39:12 +00:00
return result ;
}
2019-08-27 12:17:59 +00:00
DQN_HEADER_COPY_PROTOTYPE ( int , Dqn_Safe_TruncateISizeToInt ( Dqn_isize val ) )
2019-08-24 01:39:12 +00:00
{
DQN_ASSERT_MSG ( val > = INT_MIN & & val < = INT_MAX , " %zd >= %zd && %zd <= %zd " , val , INT_MIN , val , INT_MAX ) ;
auto result = ( int ) val ;
return result ;
}
2019-08-27 12:17:59 +00:00
DQN_HEADER_COPY_PROTOTYPE ( Dqn_i32 , Dqn_Safe_TruncateISizeToI32 ( Dqn_isize val ) )
2019-08-24 01:39:12 +00:00
{
DQN_ASSERT_MSG ( val > = INT32_MIN & & val < = INT32_MAX , " %zd >= %zd && %zd <= %zd " , val , INT32_MIN , val , INT32_MAX ) ;
2020-01-31 10:02:26 +00:00
auto result = DQN_CAST ( Dqn_i32 ) val ;
2019-08-24 01:39:12 +00:00
return result ;
}
2019-08-27 12:17:59 +00:00
DQN_HEADER_COPY_PROTOTYPE ( Dqn_i8 , Dqn_Safe_TruncateISizeToI8 ( Dqn_isize val ) )
2019-08-24 01:39:12 +00:00
{
DQN_ASSERT_MSG ( val > = INT8_MIN & & val < = INT8_MAX , " %zd >= %zd && %zd <= %zd " , val , INT8_MIN , val , INT8_MAX ) ;
2020-01-31 10:02:26 +00:00
auto result = DQN_CAST ( Dqn_i8 ) val ;
2019-08-24 01:39:12 +00:00
return result ;
}
2019-08-27 12:17:59 +00:00
DQN_HEADER_COPY_PROTOTYPE ( Dqn_u32 , Dqn_Safe_TruncateUSizeToU32 ( Dqn_u64 val ) )
2019-08-24 01:39:12 +00:00
{
DQN_ASSERT_MSG ( val < = UINT32_MAX , " %zu <= %zu " , val , UINT32_MAX ) ;
2020-01-31 10:02:26 +00:00
auto result = DQN_CAST ( Dqn_u32 ) val ;
2019-08-24 01:39:12 +00:00
return result ;
}
2019-08-27 12:17:59 +00:00
DQN_HEADER_COPY_PROTOTYPE ( int , Dqn_Safe_TruncateUSizeToI32 ( Dqn_usize val ) )
2019-08-24 01:39:12 +00:00
{
DQN_ASSERT_MSG ( val < = INT32_MAX , " %zu <= %zd " , val , INT32_MAX ) ;
2020-01-31 10:02:26 +00:00
auto result = DQN_CAST ( int ) val ;
2019-08-24 01:39:12 +00:00
return result ;
}
2019-08-27 12:17:59 +00:00
DQN_HEADER_COPY_PROTOTYPE ( int , Dqn_Safe_TruncateUSizeToInt ( Dqn_usize val ) )
2019-08-24 01:39:12 +00:00
{
DQN_ASSERT_MSG ( val < = INT_MAX , " %zu <= %zd " , val , INT_MAX ) ;
2020-01-31 10:02:26 +00:00
auto result = DQN_CAST ( int ) val ;
return result ;
}
DQN_HEADER_COPY_PROTOTYPE ( Dqn_isize , Dqn_Safe_TruncateUSizeToISize ( Dqn_usize val ) )
{
2020-02-08 07:47:48 +00:00
DQN_ASSERT_MSG ( val < = DQN_CAST ( Dqn_usize ) DQN_ISIZE_MAX , " %zu <= %zu " , val , DQN_CAST ( Dqn_usize ) DQN_ISIZE_MAX ) ;
2020-01-31 10:02:26 +00:00
auto result = DQN_CAST ( Dqn_isize ) val ;
2019-08-24 01:39:12 +00:00
return result ;
}
2019-08-26 13:24:22 +00:00
// @ -------------------------------------------------------------------------------------------------
// @
// @ NOTE: Char Helpers
// @
// @ -------------------------------------------------------------------------------------------------
2019-08-27 12:17:59 +00:00
DQN_HEADER_COPY_PROTOTYPE ( Dqn_b32 , Dqn_Char_IsAlpha ( char ch ) )
2019-08-24 01:39:12 +00:00
{
2019-08-27 12:17:59 +00:00
Dqn_b32 result = ( ch > = ' A ' & & ch < = ' Z ' ) | | ( ch > = ' a ' & & ch < = ' z ' ) ;
2019-08-24 01:39:12 +00:00
return result ;
}
2019-08-27 12:17:59 +00:00
DQN_HEADER_COPY_PROTOTYPE ( Dqn_b32 , Dqn_Char_IsDigit ( char ch ) )
2019-08-24 01:39:12 +00:00
{
2019-08-27 12:17:59 +00:00
Dqn_b32 result = ( ch > = ' 0 ' & & ch < = ' 9 ' ) ;
2019-08-24 01:39:12 +00:00
return result ;
}
2019-08-27 12:17:59 +00:00
DQN_HEADER_COPY_PROTOTYPE ( Dqn_b32 , Dqn_Char_IsAlphaNum ( char ch ) )
2019-08-24 01:39:12 +00:00
{
2019-08-27 12:17:59 +00:00
Dqn_b32 result = Dqn_Char_IsAlpha ( ch ) | | Dqn_Char_IsDigit ( ch ) ;
2019-08-24 01:39:12 +00:00
return result ;
}
2019-08-27 12:17:59 +00:00
DQN_HEADER_COPY_PROTOTYPE ( Dqn_b32 , Dqn_Char_IsWhitespace ( char ch ) )
2019-08-24 01:39:12 +00:00
{
2019-08-27 12:17:59 +00:00
Dqn_b32 result = ( ch = = ' ' | | ch = = ' \t ' | | ch = = ' \n ' | | ch = = ' \r ' ) ;
2019-08-24 01:39:12 +00:00
return result ;
}
2020-02-08 07:47:48 +00:00
DQN_HEADER_COPY_PROTOTYPE ( char , Dqn_Char_ToLower ( char ch ) )
{
char result = ch ;
if ( result > = ' A ' & & result < = ' Z ' )
result = ' a ' - ' A ' ;
return result ;
}
2019-08-26 13:24:22 +00:00
// @ -------------------------------------------------------------------------------------------------
// @
// @ NOTE: String Helpers
// @
// @ -------------------------------------------------------------------------------------------------
2019-09-19 11:49:11 +00:00
DQN_HEADER_COPY_PROTOTYPE ( Dqn_b32 , Dqn_Str_Equals ( char const * a , char const * b , Dqn_isize a_len = - 1 , Dqn_isize b_len = - 1 ) )
2019-08-24 01:39:12 +00:00
{
2020-01-31 10:02:26 +00:00
if ( a_len = = - 1 ) a_len = DQN_CAST ( Dqn_isize ) strlen ( a ) ;
if ( b_len = = - 1 ) b_len = DQN_CAST ( Dqn_isize ) strlen ( b ) ;
2019-08-24 01:39:12 +00:00
if ( a_len ! = b_len ) return false ;
2020-01-31 10:02:26 +00:00
return ( strncmp ( a , b , DQN_CAST ( size_t ) a_len ) = = 0 ) ;
2019-08-24 01:39:12 +00:00
}
2019-08-27 12:17:59 +00:00
DQN_HEADER_COPY_PROTOTYPE ( char const * , Dqn_Str_FindMulti ( char const * buf , char const * find_list [ ] , Dqn_isize const * find_string_lens , Dqn_isize find_len , Dqn_isize * match_index , Dqn_isize buf_len = - 1 ) )
2019-08-24 01:39:12 +00:00
{
2019-08-26 13:24:22 +00:00
char const * result = nullptr ;
if ( find_len = = 0 ) return result ;
2020-01-31 10:02:26 +00:00
if ( buf_len < 0 ) buf_len = DQN_CAST ( Dqn_isize ) strlen ( buf ) ;
2019-08-24 01:39:12 +00:00
2019-08-26 13:24:22 +00:00
char const * buf_end = buf + buf_len ;
2020-01-17 15:01:25 +00:00
for ( ; buf ! = buf_end ; + + buf )
2019-08-26 13:24:22 +00:00
{
2019-08-27 12:17:59 +00:00
Dqn_isize remaining = static_cast < Dqn_isize > ( buf_end - buf ) ;
2019-08-26 13:24:22 +00:00
DQN_FOR_EACH ( find_index , find_len )
{
char const * find = find_list [ find_index ] ;
2019-08-27 12:17:59 +00:00
Dqn_isize find_str_len = find_string_lens [ find_index ] ;
2019-08-26 13:24:22 +00:00
if ( remaining < find_str_len ) continue ;
2020-01-31 10:02:26 +00:00
if ( strncmp ( buf , find , DQN_CAST ( size_t ) find_str_len ) = = 0 )
2019-08-26 13:24:22 +00:00
{
result = buf ;
* match_index = find_index ;
return result ;
}
}
2019-08-24 01:39:12 +00:00
2019-08-26 13:24:22 +00:00
}
return result ;
}
2019-08-24 01:39:12 +00:00
2019-08-27 12:17:59 +00:00
DQN_HEADER_COPY_PROTOTYPE ( char const * , Dqn_Str_Find ( char const * buf , char const * find , Dqn_isize buf_len = - 1 , Dqn_isize find_len = - 1 ) )
2019-08-26 13:24:22 +00:00
{
if ( find_len = = 0 ) return nullptr ;
2020-01-31 10:02:26 +00:00
if ( buf_len < 0 ) buf_len = DQN_CAST ( Dqn_isize ) strlen ( buf ) ;
if ( find_len < 0 ) find_len = DQN_CAST ( Dqn_isize ) strlen ( find ) ;
2019-08-26 13:24:22 +00:00
char const * buf_end = buf + buf_len ;
char const * result = nullptr ;
2020-01-17 15:01:25 +00:00
for ( ; buf ! = buf_end ; + + buf )
2019-08-24 01:39:12 +00:00
{
2019-08-27 12:17:59 +00:00
Dqn_isize remaining = static_cast < Dqn_isize > ( buf_end - buf ) ;
2019-08-26 13:24:22 +00:00
if ( remaining < find_len ) break ;
2019-08-24 01:39:12 +00:00
2020-01-31 10:02:26 +00:00
if ( strncmp ( buf , find , DQN_CAST ( size_t ) find_len ) = = 0 )
2019-08-26 13:24:22 +00:00
{
result = buf ;
break ;
}
}
return result ;
2019-08-24 01:39:12 +00:00
}
2019-08-27 12:17:59 +00:00
DQN_HEADER_COPY_PROTOTYPE ( Dqn_b32 , Dqn_Str_Match ( char const * src , char const * find , int find_len ) )
2019-08-24 01:39:12 +00:00
{
2019-08-27 12:17:59 +00:00
if ( find_len = = - 1 ) find_len = Dqn_Safe_TruncateUSizeToInt ( strlen ( find ) ) ;
2020-01-31 10:02:26 +00:00
auto result = DQN_CAST ( Dqn_b32 ) ( strncmp ( src , find , DQN_CAST ( size_t ) find_len ) = = 0 ) ;
2019-08-24 01:39:12 +00:00
return result ;
}
2019-08-27 12:17:59 +00:00
DQN_HEADER_COPY_PROTOTYPE ( char const * , Dqn_Str_SkipToChar ( char const * src , char ch ) )
2019-08-24 01:39:12 +00:00
{
char const * result = src ;
while ( result & & result [ 0 ] & & result [ 0 ] ! = ch ) + + result ;
return result ;
}
2019-08-27 12:17:59 +00:00
DQN_HEADER_COPY_PROTOTYPE ( char const * , Dqn_Str_SkipToNextAlphaNum ( char const * src ) )
2019-08-24 01:39:12 +00:00
{
char const * result = src ;
2019-08-27 12:17:59 +00:00
while ( result & & result [ 0 ] & & ! Dqn_Char_IsAlphaNum ( result [ 0 ] ) ) + + result ;
2019-08-24 01:39:12 +00:00
return result ;
}
2019-08-27 12:17:59 +00:00
DQN_HEADER_COPY_PROTOTYPE ( char const * , Dqn_Str_SkipToNextDigit ( char const * src ) )
2019-08-24 01:39:12 +00:00
{
char const * result = src ;
2019-08-27 12:17:59 +00:00
while ( result & & result [ 0 ] & & ! Dqn_Char_IsDigit ( result [ 0 ] ) ) + + result ;
2019-08-24 01:39:12 +00:00
return result ;
}
2019-08-27 12:17:59 +00:00
DQN_HEADER_COPY_PROTOTYPE ( char const * , Dqn_Str_SkipToNextChar ( char const * src ) )
2019-08-24 01:39:12 +00:00
{
char const * result = src ;
2019-08-27 12:17:59 +00:00
while ( result & & result [ 0 ] & & ! Dqn_Char_IsAlpha ( result [ 0 ] ) ) + + result ;
2019-08-24 01:39:12 +00:00
return result ;
}
2019-08-27 12:17:59 +00:00
DQN_HEADER_COPY_PROTOTYPE ( char const * , Dqn_Str_SkipToNextWord ( char const * src ) )
2019-08-24 01:39:12 +00:00
{
char const * result = src ;
2019-08-27 12:17:59 +00:00
while ( result & & result [ 0 ] & & ! Dqn_Char_IsWhitespace ( result [ 0 ] ) ) + + result ;
while ( result & & result [ 0 ] & & Dqn_Char_IsWhitespace ( result [ 0 ] ) ) + + result ;
2019-08-24 01:39:12 +00:00
return result ;
}
2019-08-27 12:17:59 +00:00
DQN_HEADER_COPY_PROTOTYPE ( char const * , Dqn_Str_SkipToNextWhitespace ( char const * src ) )
2019-08-24 01:39:12 +00:00
{
char const * result = src ;
2019-08-27 12:17:59 +00:00
while ( result & & result [ 0 ] & & ! Dqn_Char_IsWhitespace ( result [ 0 ] ) ) + + result ;
2019-08-24 01:39:12 +00:00
return result ;
}
2019-08-27 12:17:59 +00:00
DQN_HEADER_COPY_PROTOTYPE ( char const * , Dqn_Str_SkipWhitespace ( char const * src ) )
2019-08-24 01:39:12 +00:00
{
char const * result = src ;
2019-08-27 12:17:59 +00:00
while ( result & & result [ 0 ] & & Dqn_Char_IsWhitespace ( result [ 0 ] ) ) + + result ;
2019-08-24 01:39:12 +00:00
return result ;
}
2019-08-27 12:17:59 +00:00
DQN_HEADER_COPY_PROTOTYPE ( char const * , Dqn_Str_SkipToCharInPlace ( char const * * src , char ch ) )
2019-08-24 01:39:12 +00:00
{
2019-08-27 12:17:59 +00:00
* src = Dqn_Str_SkipToChar ( * src , ch ) ;
2019-08-24 01:39:12 +00:00
return * src ;
}
2019-08-27 12:17:59 +00:00
DQN_HEADER_COPY_PROTOTYPE ( char const * , Dqn_Str_SkipToNextAlphaNumInPlace ( char const * * src ) )
2019-08-24 01:39:12 +00:00
{
2019-08-27 12:17:59 +00:00
* src = Dqn_Str_SkipToNextAlphaNum ( * src ) ;
2019-08-24 01:39:12 +00:00
return * src ;
}
2019-08-27 12:17:59 +00:00
DQN_HEADER_COPY_PROTOTYPE ( char const * , Dqn_Str_SkipToNextCharInPlace ( char const * * src ) )
2019-08-24 01:39:12 +00:00
{
2019-08-27 12:17:59 +00:00
* src = Dqn_Str_SkipToNextChar ( * src ) ;
2019-08-24 01:39:12 +00:00
return * src ;
}
2019-08-27 12:17:59 +00:00
DQN_HEADER_COPY_PROTOTYPE ( char const * , Dqn_Str_SkipToNextWhitespaceInPlace ( char const * * src ) )
2019-08-24 01:39:12 +00:00
{
2019-08-27 12:17:59 +00:00
* src = Dqn_Str_SkipToNextWhitespace ( * src ) ;
2019-08-24 01:39:12 +00:00
return * src ;
}
2019-08-27 12:17:59 +00:00
DQN_HEADER_COPY_PROTOTYPE ( char const * , Dqn_Str_SkipToNextWordInPlace ( char const * * src ) )
2019-08-24 01:39:12 +00:00
{
2019-08-27 12:17:59 +00:00
* src = Dqn_Str_SkipToNextWord ( * src ) ;
2019-08-24 01:39:12 +00:00
return * src ;
}
2019-08-27 12:17:59 +00:00
DQN_HEADER_COPY_PROTOTYPE ( char const * , Dqn_Str_SkipWhitespaceInPlace ( char const * * src ) )
2019-08-24 01:39:12 +00:00
{
2019-08-27 12:17:59 +00:00
* src = Dqn_Str_SkipWhitespace ( * src ) ;
2019-08-24 01:39:12 +00:00
return * src ;
}
2019-08-27 12:17:59 +00:00
DQN_HEADER_COPY_PROTOTYPE ( Dqn_u64 , Dqn_Str_ToU64 ( char const * buf , int len = - 1 ) )
2019-08-24 01:39:12 +00:00
{
2019-08-27 12:17:59 +00:00
Dqn_u64 result = 0 ;
2019-08-24 01:39:12 +00:00
if ( ! buf ) return result ;
2019-08-27 12:17:59 +00:00
if ( len = = - 1 ) len = Dqn_Safe_TruncateUSizeToInt ( strlen ( buf ) ) ;
2019-08-24 01:39:12 +00:00
if ( len = = 0 ) return result ;
2019-08-27 12:17:59 +00:00
char const * buf_ptr = Dqn_Str_SkipWhitespace ( buf ) ;
2019-08-24 01:39:12 +00:00
len - = static_cast < int > ( buf_ptr - buf ) ;
for ( int buf_index = 0 ; buf_index < len ; + + buf_index )
{
char ch = buf_ptr [ buf_index ] ;
if ( ch = = ' , ' ) continue ;
if ( ch < ' 0 ' | | ch > ' 9 ' ) break ;
2020-01-31 10:02:26 +00:00
Dqn_u64 val = DQN_CAST ( Dqn_u64 ) ( ch - ' 0 ' ) ;
2019-08-27 12:17:59 +00:00
result = Dqn_Safe_AddU64 ( result , val ) ;
result = Dqn_Safe_MulU64 ( result , 10 ) ;
2019-08-24 01:39:12 +00:00
}
result / = 10 ;
return result ;
}
2019-08-27 12:17:59 +00:00
DQN_HEADER_COPY_PROTOTYPE ( Dqn_i64 , Dqn_Str_ToI64 ( char const * buf , int len = - 1 ) )
2019-08-24 01:39:12 +00:00
{
2019-08-27 12:17:59 +00:00
Dqn_i64 result = 0 ;
2019-08-24 01:39:12 +00:00
if ( ! buf ) return result ;
2019-08-27 12:17:59 +00:00
if ( len = = - 1 ) len = Dqn_Safe_TruncateUSizeToInt ( strlen ( buf ) ) ;
2019-08-24 01:39:12 +00:00
if ( len = = 0 ) return result ;
2019-08-27 12:17:59 +00:00
char const * buf_ptr = Dqn_Str_SkipWhitespace ( buf ) ;
2019-08-24 01:39:12 +00:00
len - = static_cast < int > ( buf_ptr - buf ) ;
2019-08-27 12:17:59 +00:00
Dqn_b32 negative = ( buf [ 0 ] = = ' - ' ) ;
2019-08-24 01:39:12 +00:00
if ( negative )
{
+ + buf_ptr ;
- - len ;
}
for ( int buf_index = 0 ; buf_index < len ; + + buf_index )
{
char ch = buf_ptr [ buf_index ] ;
if ( ch = = ' , ' ) continue ;
if ( ch < ' 0 ' | | ch > ' 9 ' ) break ;
2019-08-27 12:17:59 +00:00
Dqn_i64 val = ch - ' 0 ' ;
result = Dqn_Safe_AddI64 ( result , val ) ;
result = Dqn_Safe_MulI64 ( result , 10 ) ;
2019-08-24 01:39:12 +00:00
}
result / = 10 ;
if ( negative ) result * = - 1 ;
return result ;
}
2019-08-26 13:24:22 +00:00
2020-02-08 07:47:48 +00:00
// @ -------------------------------------------------------------------------------------------------
// @
// @ NOTE: Dqn_String
// @
// @ -------------------------------------------------------------------------------------------------
DQN_HEADER_COPY_PROTOTYPE ( Dqn_b32 , Dqn_String_Compare ( Dqn_String const lhs , Dqn_String const rhs ) )
{
Dqn_b32 result = false ;
if ( lhs . len = = rhs . len )
result = ( memcmp ( lhs . str , rhs . str , lhs . len ) = = 0 ) ;
return result ;
}
DQN_HEADER_COPY_PROTOTYPE ( Dqn_b32 , Dqn_String_CompareCaseInsensitive ( Dqn_String const lhs , Dqn_String const rhs ) )
{
Dqn_b32 result = ( lhs . len = = rhs . len ) ;
if ( result )
{
for ( Dqn_isize index = 0 ; index < lhs . len & & result ; index + + )
result = ( Dqn_Char_ToLower ( lhs . str [ index ] ) = = Dqn_Char_ToLower ( rhs . str [ index ] ) ) ;
}
return result ;
}
DQN_HEADER_COPY_PROTOTYPE ( Dqn_String , Dqn_String_Copy ( Dqn_Allocator * allocator , Dqn_String const src ) )
{
Dqn_String result = src ;
result . str = DQN_CAST ( decltype ( result . str ) ) Dqn_Allocator_Allocate ( allocator , sizeof ( * result . str ) * result . len ) ;
memcpy ( result . str , src . str , result . len ) ;
return result ;
}
2019-08-27 12:17:59 +00:00
// @ -------------------------------------------------------------------------------------------------
// @
// @ NOTE: File
// @
// @ -------------------------------------------------------------------------------------------------
DQN_HEADER_COPY_PROTOTYPE ( char * , Dqn_File_ReadWithArena ( Dqn_MemArena * arena , char const * file , Dqn_isize * file_size ) )
2019-08-26 13:24:22 +00:00
{
FILE * file_handle = fopen ( file , " rb " ) ;
fseek ( file_handle , 0 , SEEK_END ) ;
2020-01-31 10:02:26 +00:00
Dqn_isize file_size_ = ftell ( file_handle ) ;
if ( DQN_CAST ( long ) file_size_ = = - 1L )
{
DQN_ASSERT ( DQN_CAST ( long ) file_size_ ! = - 1L ) ;
file_size_ = 0 ;
}
2019-08-26 13:24:22 +00:00
rewind ( file_handle ) ;
2020-01-31 10:02:26 +00:00
auto * result = ( char * ) DQN_MEM_ARENA_ALLOC ( arena , DQN_CAST ( Dqn_usize ) ( file_size_ + 1 ) ) ;
2019-08-26 13:24:22 +00:00
DQN_ASSERT ( result ) ;
result [ file_size_ ] = 0 ;
2020-01-31 10:02:26 +00:00
if ( fread ( result , DQN_CAST ( size_t ) file_size_ , 1 , file_handle ) ! = 1 )
2019-08-26 13:24:22 +00:00
{
2020-01-31 10:02:26 +00:00
fprintf ( stderr , " Failed to fread: %zd bytes into buffer from file: %s \n " , file_size_ , file ) ;
2019-08-26 13:24:22 +00:00
return nullptr ;
}
if ( file_size ) * file_size = file_size_ ;
return result ;
}
2019-10-29 11:22:35 +00:00
// @ -------------------------------------------------------------------------------------------------
// @
// @ NOTE: Utils
// @
// @ -------------------------------------------------------------------------------------------------
# include <time.h>
2020-01-31 10:02:26 +00:00
DQN_HEADER_COPY_PROTOTYPE ( char * , Dqn_EpochTimeToDate ( Dqn_i64 timestamp , char * buf , Dqn_isize buf_len ) )
2019-10-29 11:22:35 +00:00
{
2020-01-31 10:02:26 +00:00
DQN_ASSERT ( buf_len > = 0 ) ;
2019-10-29 11:22:35 +00:00
time_t time = DQN_CAST ( time_t ) timestamp ;
tm * date_time = localtime ( & time ) ;
2020-01-31 10:02:26 +00:00
strftime ( buf , DQN_CAST ( Dqn_usize ) buf_len , " %c " , date_time ) ;
2019-10-29 11:22:35 +00:00
return buf ;
}
2019-09-19 11:49:11 +00:00
# undef _CRT_SECURE_NO_WARNINGS
2019-08-24 01:39:12 +00:00
# endif // DQN_IMPLEMENTATION
# ifdef STB_SPRINTF_IMPLEMENTATION
# include <stdlib.h> // for va_arg()
# define stbsp__uint32 unsigned int
# define stbsp__int32 signed int
# ifdef _MSC_VER
# define stbsp__uint64 unsigned __int64
# define stbsp__int64 signed __int64
# else
# define stbsp__uint64 unsigned long long
# define stbsp__int64 signed long long
# endif
# define stbsp__uint16 unsigned short
# ifndef stbsp__uintptr
# if defined(__ppc64__) || defined(__aarch64__) || defined(_M_X64) || defined(__x86_64__) || defined(__x86_64)
# define stbsp__uintptr stbsp__uint64
# else
# define stbsp__uintptr stbsp__uint32
# endif
# endif
# ifndef STB_SPRINTF_MSVC_MODE // used for MSVC2013 and earlier (MSVC2015 matches GCC)
# if defined(_MSC_VER) && (_MSC_VER < 1900)
# define STB_SPRINTF_MSVC_MODE
# endif
# endif
# ifdef STB_SPRINTF_NOUNALIGNED // define this before inclusion to force stbsp_sprintf to always use aligned accesses
# define STBSP__UNALIGNED(code)
# else
# define STBSP__UNALIGNED(code) code
# endif
# ifndef STB_SPRINTF_NOFLOAT
// internal float utility functions
static stbsp__int32 stbsp__real_to_str ( char const * * start , stbsp__uint32 * len , char * out , stbsp__int32 * decimal_pos , double value , stbsp__uint32 frac_digits ) ;
static stbsp__int32 stbsp__real_to_parts ( stbsp__int64 * bits , stbsp__int32 * expo , double value ) ;
# define STBSP__SPECIAL 0x7000
# endif
static char stbsp__period = ' . ' ;
static char stbsp__comma = ' , ' ;
static char stbsp__digitpair [ 201 ] =
" 0001020304050607080910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576 "
" 7778798081828384858687888990919293949596979899 " ;
STBSP__PUBLICDEF void STB_SPRINTF_DECORATE ( set_separators ) ( char pcomma , char pperiod )
{
stbsp__period = pperiod ;
stbsp__comma = pcomma ;
}
# define STBSP__LEFTJUST 1
# define STBSP__LEADINGPLUS 2
# define STBSP__LEADINGSPACE 4
# define STBSP__LEADING_0X 8
# define STBSP__LEADINGZERO 16
# define STBSP__INTMAX 32
# define STBSP__TRIPLET_COMMA 64
# define STBSP__NEGATIVE 128
# define STBSP__METRIC_SUFFIX 256
# define STBSP__HALFWIDTH 512
# define STBSP__METRIC_NOSPACE 1024
# define STBSP__METRIC_1024 2048
# define STBSP__METRIC_JEDEC 4096
static void stbsp__lead_sign ( stbsp__uint32 fl , char * sign )
{
sign [ 0 ] = 0 ;
if ( fl & STBSP__NEGATIVE ) {
sign [ 0 ] = 1 ;
sign [ 1 ] = ' - ' ;
} else if ( fl & STBSP__LEADINGSPACE ) {
sign [ 0 ] = 1 ;
sign [ 1 ] = ' ' ;
} else if ( fl & STBSP__LEADINGPLUS ) {
sign [ 0 ] = 1 ;
sign [ 1 ] = ' + ' ;
}
}
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 hexu [ ] = " 0123456789ABCDEFXP " ;
char * bf ;
char const * f ;
int tlen = 0 ;
bf = buf ;
f = fmt ;
for ( ; ; ) {
stbsp__int32 fw , pr , tz ;
stbsp__uint32 fl ;
// macros for the callback buffer stuff
# define stbsp__chk_cb_bufL(bytes) \
{ \
int len = ( int ) ( bf - buf ) ; \
if ( ( len + ( bytes ) ) > = STB_SPRINTF_MIN ) { \
tlen + = len ; \
if ( 0 = = ( bf = buf = callback ( buf , user , len ) ) ) \
goto done ; \
} \
}
# define stbsp__chk_cb_buf(bytes) \
{ \
if ( callback ) { \
stbsp__chk_cb_bufL ( bytes ) ; \
} \
}
# define stbsp__flush_cb() \
{ \
stbsp__chk_cb_bufL ( STB_SPRINTF_MIN - 1 ) ; \
} // flush if there is even one byte in the buffer
# define stbsp__cb_buf_clamp(cl, v) \
cl = v ; \
if ( callback ) { \
int lg = STB_SPRINTF_MIN - ( int ) ( bf - buf ) ; \
if ( cl > lg ) \
cl = lg ; \
}
// fast copy everything up to the next % (or end of string)
for ( ; ; ) {
while ( ( ( stbsp__uintptr ) f ) & 3 ) {
schk1 :
if ( f [ 0 ] = = ' % ' )
goto scandd ;
schk2 :
if ( f [ 0 ] = = 0 )
goto endfmt ;
stbsp__chk_cb_buf ( 1 ) ;
* bf + + = f [ 0 ] ;
+ + f ;
}
for ( ; ; ) {
// Check if the next 4 bytes contain %(0x25) or end of string.
// Using the 'hasless' trick:
// https://graphics.stanford.edu/~seander/bithacks.html#HasLessInWord
stbsp__uint32 v , c ;
v = * ( stbsp__uint32 * ) f ;
c = ( ~ v ) & 0x80808080 ;
if ( ( ( v ^ 0x25252525 ) - 0x01010101 ) & c )
goto schk1 ;
if ( ( v - 0x01010101 ) & c )
goto schk2 ;
if ( callback )
if ( ( STB_SPRINTF_MIN - ( int ) ( bf - buf ) ) < 4 )
goto schk1 ;
* ( stbsp__uint32 * ) bf = v ;
bf + = 4 ;
f + = 4 ;
}
}
scandd :
+ + f ;
// ok, we have a percent, read the modifiers first
fw = 0 ;
pr = - 1 ;
fl = 0 ;
tz = 0 ;
// flags
for ( ; ; ) {
switch ( f [ 0 ] ) {
// if we have left justify
case ' - ' :
fl | = STBSP__LEFTJUST ;
+ + f ;
continue ;
// if we have leading plus
case ' + ' :
fl | = STBSP__LEADINGPLUS ;
+ + f ;
continue ;
// if we have leading space
case ' ' :
fl | = STBSP__LEADINGSPACE ;
+ + f ;
continue ;
// if we have leading 0x
case ' # ' :
fl | = STBSP__LEADING_0X ;
+ + f ;
continue ;
// if we have thousand commas
case ' \' ' :
fl | = STBSP__TRIPLET_COMMA ;
+ + f ;
continue ;
// if we have kilo marker (none->kilo->kibi->jedec)
case ' $ ' :
if ( fl & STBSP__METRIC_SUFFIX ) {
if ( fl & STBSP__METRIC_1024 ) {
fl | = STBSP__METRIC_JEDEC ;
} else {
fl | = STBSP__METRIC_1024 ;
}
} else {
fl | = STBSP__METRIC_SUFFIX ;
}
+ + f ;
continue ;
// if we don't want space between metric suffix and number
case ' _ ' :
fl | = STBSP__METRIC_NOSPACE ;
+ + f ;
continue ;
// if we have leading zero
case ' 0 ' :
fl | = STBSP__LEADINGZERO ;
+ + f ;
goto flags_done ;
default : goto flags_done ;
}
}
flags_done :
// get the field width
if ( f [ 0 ] = = ' * ' ) {
fw = va_arg ( va , stbsp__uint32 ) ;
+ + f ;
} else {
while ( ( f [ 0 ] > = ' 0 ' ) & & ( f [ 0 ] < = ' 9 ' ) ) {
fw = fw * 10 + f [ 0 ] - ' 0 ' ;
f + + ;
}
}
// get the precision
if ( f [ 0 ] = = ' . ' ) {
+ + f ;
if ( f [ 0 ] = = ' * ' ) {
pr = va_arg ( va , stbsp__uint32 ) ;
+ + f ;
} else {
pr = 0 ;
while ( ( f [ 0 ] > = ' 0 ' ) & & ( f [ 0 ] < = ' 9 ' ) ) {
pr = pr * 10 + f [ 0 ] - ' 0 ' ;
f + + ;
}
}
}
// handle integer size overrides
switch ( f [ 0 ] ) {
// are we halfwidth?
case ' h ' :
fl | = STBSP__HALFWIDTH ;
+ + f ;
break ;
// are we 64-bit (unix style)
case ' l ' :
+ + f ;
if ( f [ 0 ] = = ' l ' ) {
fl | = STBSP__INTMAX ;
+ + f ;
}
break ;
// are we 64-bit on intmax? (c99)
case ' j ' :
fl | = STBSP__INTMAX ;
+ + f ;
break ;
// are we 64-bit on size_t or ptrdiff_t? (c99)
case ' z ' :
case ' t ' :
fl | = ( ( sizeof ( char * ) = = 8 ) ? STBSP__INTMAX : 0 ) ;
+ + f ;
break ;
// are we 64-bit (msft style)
case ' I ' :
if ( ( f [ 1 ] = = ' 6 ' ) & & ( f [ 2 ] = = ' 4 ' ) ) {
fl | = STBSP__INTMAX ;
f + = 3 ;
} else if ( ( f [ 1 ] = = ' 3 ' ) & & ( f [ 2 ] = = ' 2 ' ) ) {
f + = 3 ;
} else {
fl | = ( ( sizeof ( void * ) = = 8 ) ? STBSP__INTMAX : 0 ) ;
+ + f ;
}
break ;
default : break ;
}
// handle each replacement
switch ( f [ 0 ] ) {
# define STBSP__NUMSZ 512 // big enough for e308 (with commas) or e-307
char num [ STBSP__NUMSZ ] ;
char lead [ 8 ] ;
char tail [ 8 ] ;
char * s ;
char const * h ;
stbsp__uint32 l , n , cs ;
stbsp__uint64 n64 ;
# ifndef STB_SPRINTF_NOFLOAT
double fv ;
# endif
stbsp__int32 dp ;
char const * sn ;
case ' s ' :
// get the string
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 ;
lead [ 0 ] = 0 ;
tail [ 0 ] = 0 ;
pr = 0 ;
dp = 0 ;
cs = 0 ;
// copy the string in
goto scopy ;
case ' c ' : // char
// get the character
s = num + STBSP__NUMSZ - 1 ;
* s = ( char ) va_arg ( va , int ) ;
l = 1 ;
lead [ 0 ] = 0 ;
tail [ 0 ] = 0 ;
pr = 0 ;
dp = 0 ;
cs = 0 ;
goto scopy ;
case ' n ' : // weird write-bytes specifier
{
int * d = va_arg ( va , int * ) ;
* d = tlen + ( int ) ( bf - buf ) ;
} break ;
# ifdef STB_SPRINTF_NOFLOAT
case ' A ' : // float
case ' a ' : // hex float
case ' G ' : // float
case ' g ' : // float
case ' E ' : // float
case ' e ' : // float
case ' f ' : // float
va_arg ( va , double ) ; // eat it
s = ( char * ) " No float " ;
l = 8 ;
lead [ 0 ] = 0 ;
tail [ 0 ] = 0 ;
pr = 0 ;
dp = 0 ;
cs = 0 ;
goto scopy ;
# else
case ' A ' : // hex float
case ' a ' : // hex float
h = ( f [ 0 ] = = ' A ' ) ? hexu : hex ;
fv = va_arg ( va , double ) ;
if ( pr = = - 1 )
pr = 6 ; // default is 6
// read the double into a string
if ( stbsp__real_to_parts ( ( stbsp__int64 * ) & n64 , & dp , fv ) )
fl | = STBSP__NEGATIVE ;
s = num + 64 ;
stbsp__lead_sign ( fl , lead ) ;
if ( dp = = - 1023 )
dp = ( n64 ) ? - 1022 : 0 ;
else
n64 | = ( ( ( stbsp__uint64 ) 1 ) < < 52 ) ;
n64 < < = ( 64 - 56 ) ;
if ( pr < 15 )
n64 + = ( ( ( ( stbsp__uint64 ) 8 ) < < 56 ) > > ( pr * 4 ) ) ;
// add leading chars
# ifdef STB_SPRINTF_MSVC_MODE
* s + + = ' 0 ' ;
* s + + = ' x ' ;
# else
lead [ 1 + lead [ 0 ] ] = ' 0 ' ;
lead [ 2 + lead [ 0 ] ] = ' x ' ;
lead [ 0 ] + = 2 ;
# endif
* s + + = h [ ( n64 > > 60 ) & 15 ] ;
n64 < < = 4 ;
if ( pr )
* s + + = stbsp__period ;
sn = s ;
// print the bits
n = pr ;
if ( n > 13 )
n = 13 ;
if ( pr > ( stbsp__int32 ) n )
tz = pr - n ;
pr = 0 ;
while ( n - - ) {
* s + + = h [ ( n64 > > 60 ) & 15 ] ;
n64 < < = 4 ;
}
// print the expo
tail [ 1 ] = h [ 17 ] ;
if ( dp < 0 ) {
tail [ 2 ] = ' - ' ;
dp = - dp ;
} else
tail [ 2 ] = ' + ' ;
n = ( dp > = 1000 ) ? 6 : ( ( dp > = 100 ) ? 5 : ( ( dp > = 10 ) ? 4 : 3 ) ) ;
tail [ 0 ] = ( char ) n ;
for ( ; ; ) {
tail [ n ] = ' 0 ' + dp % 10 ;
if ( n < = 3 )
break ;
- - n ;
dp / = 10 ;
}
dp = ( int ) ( s - sn ) ;
l = ( int ) ( s - ( num + 64 ) ) ;
s = num + 64 ;
cs = 1 + ( 3 < < 24 ) ;
goto scopy ;
case ' G ' : // float
case ' g ' : // float
h = ( f [ 0 ] = = ' G ' ) ? hexu : hex ;
fv = va_arg ( va , double ) ;
if ( pr = = - 1 )
pr = 6 ;
else if ( pr = = 0 )
pr = 1 ; // default is 6
// read the double into a string
if ( stbsp__real_to_str ( & sn , & l , num , & dp , fv , ( pr - 1 ) | 0x80000000 ) )
fl | = STBSP__NEGATIVE ;
// clamp the precision and delete extra zeros after clamp
n = pr ;
if ( l > ( stbsp__uint32 ) pr )
l = pr ;
while ( ( l > 1 ) & & ( pr ) & & ( sn [ l - 1 ] = = ' 0 ' ) ) {
- - pr ;
- - l ;
}
// should we use %e
if ( ( dp < = - 4 ) | | ( dp > ( stbsp__int32 ) n ) ) {
if ( pr > ( stbsp__int32 ) l )
pr = l - 1 ;
else if ( pr )
- - 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
if ( dp > 0 ) {
pr = ( dp < ( stbsp__int32 ) l ) ? l - dp : 0 ;
} else {
pr = - dp + ( ( pr > ( stbsp__int32 ) l ) ? l : pr ) ;
}
goto dofloatfromg ;
case ' E ' : // float
case ' e ' : // float
h = ( f [ 0 ] = = ' E ' ) ? hexu : hex ;
fv = va_arg ( va , double ) ;
if ( pr = = - 1 )
pr = 6 ; // default is 6
// read the double into a string
if ( stbsp__real_to_str ( & sn , & l , num , & dp , fv , pr | 0x80000000 ) )
fl | = STBSP__NEGATIVE ;
doexpfromg :
tail [ 0 ] = 0 ;
stbsp__lead_sign ( fl , lead ) ;
if ( dp = = STBSP__SPECIAL ) {
s = ( char * ) sn ;
cs = 0 ;
pr = 0 ;
goto scopy ;
}
s = num + 64 ;
// handle leading chars
* s + + = sn [ 0 ] ;
if ( pr )
* s + + = stbsp__period ;
// handle after decimal
if ( ( l - 1 ) > ( stbsp__uint32 ) pr )
l = pr + 1 ;
for ( n = 1 ; n < l ; n + + )
* s + + = sn [ n ] ;
// trailing zeros
tz = pr - ( l - 1 ) ;
pr = 0 ;
// dump expo
tail [ 1 ] = h [ 0xe ] ;
dp - = 1 ;
if ( dp < 0 ) {
tail [ 2 ] = ' - ' ;
dp = - dp ;
} else
tail [ 2 ] = ' + ' ;
# ifdef STB_SPRINTF_MSVC_MODE
n = 5 ;
# else
n = ( dp > = 100 ) ? 5 : 4 ;
# endif
tail [ 0 ] = ( char ) n ;
for ( ; ; ) {
tail [ n ] = ' 0 ' + dp % 10 ;
if ( n < = 3 )
break ;
- - n ;
dp / = 10 ;
}
cs = 1 + ( 3 < < 24 ) ; // how many tens
goto flt_lead ;
case ' f ' : // float
fv = va_arg ( va , double ) ;
doafloat :
// do kilos
if ( fl & STBSP__METRIC_SUFFIX ) {
double divisor ;
divisor = 1000.0f ;
if ( fl & STBSP__METRIC_1024 )
divisor = 1024.0 ;
while ( fl < 0x4000000 ) {
if ( ( fv < divisor ) & & ( fv > - divisor ) )
break ;
fv / = divisor ;
fl + = 0x1000000 ;
}
}
if ( pr = = - 1 )
pr = 6 ; // default is 6
// read the double into a string
if ( stbsp__real_to_str ( & sn , & l , num , & dp , fv , pr ) )
fl | = STBSP__NEGATIVE ;
dofloatfromg :
tail [ 0 ] = 0 ;
stbsp__lead_sign ( fl , lead ) ;
if ( dp = = STBSP__SPECIAL ) {
s = ( char * ) sn ;
cs = 0 ;
pr = 0 ;
goto scopy ;
}
s = num + 64 ;
// handle the three decimal varieties
if ( dp < = 0 ) {
stbsp__int32 i ;
// handle 0.000*000xxxx
* s + + = ' 0 ' ;
if ( pr )
* s + + = stbsp__period ;
n = - dp ;
if ( ( stbsp__int32 ) n > pr )
n = pr ;
i = n ;
while ( i ) {
if ( ( ( ( stbsp__uintptr ) s ) & 3 ) = = 0 )
break ;
* s + + = ' 0 ' ;
- - i ;
}
while ( i > = 4 ) {
* ( stbsp__uint32 * ) s = 0x30303030 ;
s + = 4 ;
i - = 4 ;
}
while ( i ) {
* s + + = ' 0 ' ;
- - i ;
}
if ( ( stbsp__int32 ) ( l + n ) > pr )
l = pr - n ;
i = l ;
while ( i ) {
* s + + = * sn + + ;
- - i ;
}
tz = pr - ( n + l ) ;
cs = 1 + ( 3 < < 24 ) ; // how many tens did we write (for commas below)
} else {
cs = ( fl & STBSP__TRIPLET_COMMA ) ? ( ( 600 - ( stbsp__uint32 ) dp ) % 3 ) : 0 ;
if ( ( stbsp__uint32 ) dp > = l ) {
// handle xxxx000*000.0
n = 0 ;
for ( ; ; ) {
if ( ( fl & STBSP__TRIPLET_COMMA ) & & ( + + cs = = 4 ) ) {
cs = 0 ;
* s + + = stbsp__comma ;
} else {
* s + + = sn [ n ] ;
+ + n ;
if ( n > = l )
break ;
}
}
if ( n < ( stbsp__uint32 ) dp ) {
n = dp - n ;
if ( ( fl & STBSP__TRIPLET_COMMA ) = = 0 ) {
while ( n ) {
if ( ( ( ( stbsp__uintptr ) s ) & 3 ) = = 0 )
break ;
* s + + = ' 0 ' ;
- - n ;
}
while ( n > = 4 ) {
* ( stbsp__uint32 * ) s = 0x30303030 ;
s + = 4 ;
n - = 4 ;
}
}
while ( n ) {
if ( ( fl & STBSP__TRIPLET_COMMA ) & & ( + + cs = = 4 ) ) {
cs = 0 ;
* s + + = stbsp__comma ;
} else {
* s + + = ' 0 ' ;
- - n ;
}
}
}
cs = ( int ) ( s - ( num + 64 ) ) + ( 3 < < 24 ) ; // cs is how many tens
if ( pr ) {
* s + + = stbsp__period ;
tz = pr ;
}
} else {
// handle xxxxx.xxxx000*000
n = 0 ;
for ( ; ; ) {
if ( ( fl & STBSP__TRIPLET_COMMA ) & & ( + + cs = = 4 ) ) {
cs = 0 ;
* s + + = stbsp__comma ;
} else {
* s + + = sn [ n ] ;
+ + n ;
if ( n > = ( stbsp__uint32 ) dp )
break ;
}
}
cs = ( int ) ( s - ( num + 64 ) ) + ( 3 < < 24 ) ; // cs is how many tens
if ( pr )
* s + + = stbsp__period ;
if ( ( l - dp ) > ( stbsp__uint32 ) pr )
l = pr + dp ;
while ( n < l ) {
* s + + = sn [ n ] ;
+ + n ;
}
tz = pr - ( l - dp ) ;
}
}
pr = 0 ;
// handle k,m,g,t
if ( fl & STBSP__METRIC_SUFFIX ) {
char idx ;
idx = 1 ;
if ( fl & STBSP__METRIC_NOSPACE )
idx = 0 ;
tail [ 0 ] = idx ;
tail [ 1 ] = ' ' ;
{
if ( fl > > 24 ) { // SI kilo is 'k', JEDEC and SI kibits are 'K'.
if ( fl & STBSP__METRIC_1024 )
tail [ idx + 1 ] = " _KMGT " [ fl > > 24 ] ;
else
tail [ idx + 1 ] = " _kMGT " [ fl > > 24 ] ;
idx + + ;
// If printing kibits and not in jedec, add the 'i'.
if ( fl & STBSP__METRIC_1024 & & ! ( fl & STBSP__METRIC_JEDEC ) ) {
tail [ idx + 1 ] = ' i ' ;
idx + + ;
}
tail [ 0 ] = idx ;
}
}
} ;
flt_lead :
// get the length that we copied
l = ( stbsp__uint32 ) ( s - ( num + 64 ) ) ;
s = num + 64 ;
goto scopy ;
# endif
case ' B ' : // upper binary
case ' b ' : // lower binary
h = ( f [ 0 ] = = ' B ' ) ? hexu : hex ;
lead [ 0 ] = 0 ;
if ( fl & STBSP__LEADING_0X ) {
lead [ 0 ] = 2 ;
lead [ 1 ] = ' 0 ' ;
lead [ 2 ] = h [ 0xb ] ;
}
l = ( 8 < < 4 ) | ( 1 < < 8 ) ;
goto radixnum ;
case ' o ' : // octal
h = hexu ;
lead [ 0 ] = 0 ;
if ( fl & STBSP__LEADING_0X ) {
lead [ 0 ] = 1 ;
lead [ 1 ] = ' 0 ' ;
}
l = ( 3 < < 4 ) | ( 3 < < 8 ) ;
goto radixnum ;
case ' p ' : // pointer
fl | = ( sizeof ( void * ) = = 8 ) ? STBSP__INTMAX : 0 ;
pr = sizeof ( void * ) * 2 ;
fl & = ~ STBSP__LEADINGZERO ; // 'p' only prints the pointer with zeros
// fall through - to X
case ' X ' : // upper hex
case ' x ' : // lower hex
h = ( f [ 0 ] = = ' X ' ) ? hexu : hex ;
l = ( 4 < < 4 ) | ( 4 < < 8 ) ;
lead [ 0 ] = 0 ;
if ( fl & STBSP__LEADING_0X ) {
lead [ 0 ] = 2 ;
lead [ 1 ] = ' 0 ' ;
lead [ 2 ] = h [ 16 ] ;
}
radixnum :
// get the number
if ( fl & STBSP__INTMAX )
n64 = va_arg ( va , stbsp__uint64 ) ;
else
n64 = va_arg ( va , stbsp__uint32 ) ;
s = num + STBSP__NUMSZ ;
dp = 0 ;
// clear tail, and clear leading if value is zero
tail [ 0 ] = 0 ;
if ( n64 = = 0 ) {
lead [ 0 ] = 0 ;
if ( pr = = 0 ) {
l = 0 ;
cs = ( ( ( l > > 4 ) & 15 ) ) < < 24 ;
goto scopy ;
}
}
// convert to string
for ( ; ; ) {
* - - s = h [ n64 & ( ( 1 < < ( l > > 8 ) ) - 1 ) ] ;
n64 > > = ( l > > 8 ) ;
if ( ! ( ( n64 ) | | ( ( stbsp__int32 ) ( ( num + STBSP__NUMSZ ) - s ) < pr ) ) )
break ;
if ( fl & STBSP__TRIPLET_COMMA ) {
+ + l ;
if ( ( l & 15 ) = = ( ( l > > 4 ) & 15 ) ) {
l & = ~ 15 ;
* - - s = stbsp__comma ;
}
}
} ;
// get the tens and the comma pos
cs = ( stbsp__uint32 ) ( ( num + STBSP__NUMSZ ) - s ) + ( ( ( ( l > > 4 ) & 15 ) ) < < 24 ) ;
// get the length that we copied
l = ( stbsp__uint32 ) ( ( num + STBSP__NUMSZ ) - s ) ;
// copy it
goto scopy ;
case ' u ' : // unsigned
case ' i ' :
case ' d ' : // integer
// get the integer and abs it
if ( fl & STBSP__INTMAX ) {
stbsp__int64 i64 = va_arg ( va , stbsp__int64 ) ;
n64 = ( stbsp__uint64 ) i64 ;
if ( ( f [ 0 ] ! = ' u ' ) & & ( i64 < 0 ) ) {
n64 = ( stbsp__uint64 ) - i64 ;
fl | = STBSP__NEGATIVE ;
}
} else {
stbsp__int32 i = va_arg ( va , stbsp__int32 ) ;
n64 = ( stbsp__uint32 ) i ;
if ( ( f [ 0 ] ! = ' u ' ) & & ( i < 0 ) ) {
n64 = ( stbsp__uint32 ) - i ;
fl | = STBSP__NEGATIVE ;
}
}
# ifndef STB_SPRINTF_NOFLOAT
if ( fl & STBSP__METRIC_SUFFIX ) {
if ( n64 < 1024 )
pr = 0 ;
else if ( pr = = - 1 )
pr = 1 ;
fv = ( double ) ( stbsp__int64 ) n64 ;
goto doafloat ;
}
# endif
// convert to string
s = num + STBSP__NUMSZ ;
l = 0 ;
for ( ; ; ) {
// do in 32-bit chunks (avoid lots of 64-bit divides even with constant denominators)
char * o = s - 8 ;
if ( n64 > = 100000000 ) {
n = ( stbsp__uint32 ) ( n64 % 100000000 ) ;
n64 / = 100000000 ;
} else {
n = ( stbsp__uint32 ) n64 ;
n64 = 0 ;
}
if ( ( fl & STBSP__TRIPLET_COMMA ) = = 0 ) {
do {
s - = 2 ;
* ( stbsp__uint16 * ) s = * ( stbsp__uint16 * ) & stbsp__digitpair [ ( n % 100 ) * 2 ] ;
n / = 100 ;
} while ( n ) ;
}
while ( n ) {
if ( ( fl & STBSP__TRIPLET_COMMA ) & & ( l + + = = 3 ) ) {
l = 0 ;
* - - s = stbsp__comma ;
- - o ;
} else {
* - - s = ( char ) ( n % 10 ) + ' 0 ' ;
n / = 10 ;
}
}
if ( n64 = = 0 ) {
if ( ( s [ 0 ] = = ' 0 ' ) & & ( s ! = ( num + STBSP__NUMSZ ) ) )
+ + s ;
break ;
}
while ( s ! = o )
if ( ( fl & STBSP__TRIPLET_COMMA ) & & ( l + + = = 3 ) ) {
l = 0 ;
* - - s = stbsp__comma ;
- - o ;
} else {
* - - s = ' 0 ' ;
}
}
tail [ 0 ] = 0 ;
stbsp__lead_sign ( fl , lead ) ;
// get the length that we copied
l = ( stbsp__uint32 ) ( ( num + STBSP__NUMSZ ) - s ) ;
if ( l = = 0 ) {
* - - s = ' 0 ' ;
l = 1 ;
}
cs = l + ( 3 < < 24 ) ;
if ( pr < 0 )
pr = 0 ;
scopy :
// get fw=leading/trailing space, pr=leading zeros
if ( pr < ( stbsp__int32 ) l )
pr = l ;
n = pr + lead [ 0 ] + tail [ 0 ] + tz ;
if ( fw < ( stbsp__int32 ) n )
fw = n ;
fw - = n ;
pr - = l ;
// handle right justify and leading zeros
if ( ( fl & STBSP__LEFTJUST ) = = 0 ) {
if ( fl & STBSP__LEADINGZERO ) // if leading zeros, everything is in pr
{
pr = ( fw > pr ) ? fw : pr ;
fw = 0 ;
} else {
fl & = ~ STBSP__TRIPLET_COMMA ; // if no leading zeros, then no commas
}
}
// copy the spaces and/or zeros
if ( fw + pr ) {
stbsp__int32 i ;
stbsp__uint32 c ;
// copy leading spaces (or when doing %8.4d stuff)
if ( ( fl & STBSP__LEFTJUST ) = = 0 )
while ( fw > 0 ) {
stbsp__cb_buf_clamp ( i , fw ) ;
fw - = i ;
while ( i ) {
if ( ( ( ( stbsp__uintptr ) bf ) & 3 ) = = 0 )
break ;
* bf + + = ' ' ;
- - i ;
}
while ( i > = 4 ) {
* ( stbsp__uint32 * ) bf = 0x20202020 ;
bf + = 4 ;
i - = 4 ;
}
while ( i ) {
* bf + + = ' ' ;
- - i ;
}
stbsp__chk_cb_buf ( 1 ) ;
}
// copy leader
sn = lead + 1 ;
while ( lead [ 0 ] ) {
stbsp__cb_buf_clamp ( i , lead [ 0 ] ) ;
lead [ 0 ] - = ( char ) i ;
while ( i ) {
* bf + + = * sn + + ;
- - i ;
}
stbsp__chk_cb_buf ( 1 ) ;
}
// copy leading zeros
c = cs > > 24 ;
cs & = 0xffffff ;
cs = ( fl & STBSP__TRIPLET_COMMA ) ? ( ( stbsp__uint32 ) ( c - ( ( pr + cs ) % ( c + 1 ) ) ) ) : 0 ;
while ( pr > 0 ) {
stbsp__cb_buf_clamp ( i , pr ) ;
pr - = i ;
if ( ( fl & STBSP__TRIPLET_COMMA ) = = 0 ) {
while ( i ) {
if ( ( ( ( stbsp__uintptr ) bf ) & 3 ) = = 0 )
break ;
* bf + + = ' 0 ' ;
- - i ;
}
while ( i > = 4 ) {
* ( stbsp__uint32 * ) bf = 0x30303030 ;
bf + = 4 ;
i - = 4 ;
}
}
while ( i ) {
if ( ( fl & STBSP__TRIPLET_COMMA ) & & ( cs + + = = c ) ) {
cs = 0 ;
* bf + + = stbsp__comma ;
} else
* bf + + = ' 0 ' ;
- - i ;
}
stbsp__chk_cb_buf ( 1 ) ;
}
}
// copy leader if there is still one
sn = lead + 1 ;
while ( lead [ 0 ] ) {
stbsp__int32 i ;
stbsp__cb_buf_clamp ( i , lead [ 0 ] ) ;
lead [ 0 ] - = ( char ) i ;
while ( i ) {
* bf + + = * sn + + ;
- - i ;
}
stbsp__chk_cb_buf ( 1 ) ;
}
// copy the string
n = l ;
while ( n ) {
stbsp__int32 i ;
stbsp__cb_buf_clamp ( i , n ) ;
n - = i ;
STBSP__UNALIGNED ( while ( i > = 4 ) {
* ( stbsp__uint32 * ) bf = * ( stbsp__uint32 * ) s ;
bf + = 4 ;
s + = 4 ;
i - = 4 ;
} )
while ( i ) {
* bf + + = * s + + ;
- - i ;
}
stbsp__chk_cb_buf ( 1 ) ;
}
// copy trailing zeros
while ( tz ) {
stbsp__int32 i ;
stbsp__cb_buf_clamp ( i , tz ) ;
tz - = i ;
while ( i ) {
if ( ( ( ( stbsp__uintptr ) bf ) & 3 ) = = 0 )
break ;
* bf + + = ' 0 ' ;
- - i ;
}
while ( i > = 4 ) {
* ( stbsp__uint32 * ) bf = 0x30303030 ;
bf + = 4 ;
i - = 4 ;
}
while ( i ) {
* bf + + = ' 0 ' ;
- - i ;
}
stbsp__chk_cb_buf ( 1 ) ;
}
// copy tail if there is one
sn = tail + 1 ;
while ( tail [ 0 ] ) {
stbsp__int32 i ;
stbsp__cb_buf_clamp ( i , tail [ 0 ] ) ;
tail [ 0 ] - = ( char ) i ;
while ( i ) {
* bf + + = * sn + + ;
- - i ;
}
stbsp__chk_cb_buf ( 1 ) ;
}
// handle the left justify
if ( fl & STBSP__LEFTJUST )
if ( fw > 0 ) {
while ( fw ) {
stbsp__int32 i ;
stbsp__cb_buf_clamp ( i , fw ) ;
fw - = i ;
while ( i ) {
if ( ( ( ( stbsp__uintptr ) bf ) & 3 ) = = 0 )
break ;
* bf + + = ' ' ;
- - i ;
}
while ( i > = 4 ) {
* ( stbsp__uint32 * ) bf = 0x20202020 ;
bf + = 4 ;
i - = 4 ;
}
while ( i - - )
* bf + + = ' ' ;
stbsp__chk_cb_buf ( 1 ) ;
}
}
break ;
default : // unknown, just copy code
s = num + STBSP__NUMSZ - 1 ;
* s = f [ 0 ] ;
l = 1 ;
fw = fl = 0 ;
lead [ 0 ] = 0 ;
tail [ 0 ] = 0 ;
pr = 0 ;
dp = 0 ;
cs = 0 ;
goto scopy ;
}
+ + f ;
}
endfmt :
if ( ! callback )
* bf = 0 ;
else
stbsp__flush_cb ( ) ;
done :
return tlen + ( int ) ( bf - buf ) ;
}
// cleanup
# undef STBSP__LEFTJUST
# undef STBSP__LEADINGPLUS
# undef STBSP__LEADINGSPACE
# undef STBSP__LEADING_0X
# undef STBSP__LEADINGZERO
# undef STBSP__INTMAX
# undef STBSP__TRIPLET_COMMA
# undef STBSP__NEGATIVE
# undef STBSP__METRIC_SUFFIX
# undef STBSP__NUMSZ
# undef stbsp__chk_cb_bufL
# undef stbsp__chk_cb_buf
# undef stbsp__flush_cb
# undef stbsp__cb_buf_clamp
// ============================================================================
// wrapper functions
STBSP__PUBLICDEF int STB_SPRINTF_DECORATE ( sprintf ) ( char * buf , char const * fmt , . . . )
{
int result ;
va_list va ;
va_start ( va , fmt ) ;
result = STB_SPRINTF_DECORATE ( vsprintfcb ) ( 0 , 0 , buf , fmt , va ) ;
va_end ( va ) ;
return result ;
}
typedef struct stbsp__context {
char * buf ;
int count ;
char tmp [ STB_SPRINTF_MIN ] ;
} stbsp__context ;
static char * stbsp__clamp_callback ( char * buf , void * user , int len )
{
stbsp__context * c = ( stbsp__context * ) user ;
if ( len > c - > count )
len = c - > count ;
if ( len ) {
if ( buf ! = c - > buf ) {
char * s , * d , * se ;
d = c - > buf ;
s = buf ;
se = buf + len ;
do {
* d + + = * s + + ;
} while ( s < se ) ;
}
c - > buf + = len ;
c - > count - = len ;
}
if ( c - > count < = 0 )
return 0 ;
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 )
{
( void ) buf ;
stbsp__context * c = ( stbsp__context * ) user ;
c - > count + = 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 ;
STB_SPRINTF_DECORATE ( vsprintfcb ) ( stbsp__count_clamp_callback , & c , c . tmp , fmt , va ) ;
l = c . count ;
}
else
{
if ( count = = 0 )
return 0 ;
c . buf = buf ;
c . count = count ;
STB_SPRINTF_DECORATE ( vsprintfcb ) ( stbsp__clamp_callback , & c , stbsp__clamp_callback ( 0 , & c , 0 ) , fmt , va ) ;
// zero-terminate
l = ( int ) ( c . buf - buf ) ;
if ( l > = count ) // should never be greater, only equal (or less) than count
l = count - 1 ;
buf [ l ] = 0 ;
}
return l ;
}
STBSP__PUBLICDEF int STB_SPRINTF_DECORATE ( snprintf ) ( char * buf , int count , char const * fmt , . . . )
{
int result ;
va_list va ;
va_start ( va , fmt ) ;
result = STB_SPRINTF_DECORATE ( vsnprintf ) ( buf , count , fmt , va ) ;
va_end ( va ) ;
return result ;
}
STBSP__PUBLICDEF int STB_SPRINTF_DECORATE ( vsprintf ) ( char * buf , char const * fmt , va_list va )
{
return STB_SPRINTF_DECORATE ( vsprintfcb ) ( 0 , 0 , buf , fmt , va ) ;
}
// =======================================================================
// low level float utility functions
# ifndef STB_SPRINTF_NOFLOAT
// copies d to bits w/ strict aliasing (this compiles to nothing on /Ox)
# define STBSP__COPYFP(dest, src) \
{ \
int cn ; \
for ( cn = 0 ; cn < 8 ; cn + + ) \
( ( char * ) & dest ) [ cn ] = ( ( char * ) & src ) [ cn ] ; \
}
// get float info
static stbsp__int32 stbsp__real_to_parts ( stbsp__int64 * bits , stbsp__int32 * expo , double value )
{
double d ;
stbsp__int64 b = 0 ;
// load value and round at the frac_digits
d = value ;
STBSP__COPYFP ( b , d ) ;
* bits = b & ( ( ( ( stbsp__uint64 ) 1 ) < < 52 ) - 1 ) ;
* expo = ( stbsp__int32 ) ( ( ( b > > 52 ) & 2047 ) - 1023 ) ;
return ( stbsp__int32 ) ( b > > 63 ) ;
}
static double const stbsp__bot [ 23 ] = {
1e+000 , 1e+001 , 1e+002 , 1e+003 , 1e+004 , 1e+005 , 1e+006 , 1e+007 , 1e+008 , 1e+009 , 1e+010 , 1e+011 ,
1e+012 , 1e+013 , 1e+014 , 1e+015 , 1e+016 , 1e+017 , 1e+018 , 1e+019 , 1e+020 , 1e+021 , 1e+022
} ;
static double const stbsp__negbot [ 22 ] = {
1e-001 , 1e-002 , 1e-003 , 1e-004 , 1e-005 , 1e-006 , 1e-007 , 1e-008 , 1e-009 , 1e-010 , 1e-011 ,
1e-012 , 1e-013 , 1e-014 , 1e-015 , 1e-016 , 1e-017 , 1e-018 , 1e-019 , 1e-020 , 1e-021 , 1e-022
} ;
static double const stbsp__negboterr [ 22 ] = {
- 5.551115123125783e-018 , - 2.0816681711721684e-019 , - 2.0816681711721686e-020 , - 4.7921736023859299e-021 , - 8.1803053914031305e-022 , 4.5251888174113741e-023 ,
4.5251888174113739e-024 , - 2.0922560830128471e-025 , - 6.2281591457779853e-026 , - 3.6432197315497743e-027 , 6.0503030718060191e-028 , 2.0113352370744385e-029 ,
- 3.0373745563400371e-030 , 1.1806906454401013e-032 , - 7.7705399876661076e-032 , 2.0902213275965398e-033 , - 7.1542424054621921e-034 , - 7.1542424054621926e-035 ,
2.4754073164739869e-036 , 5.4846728545790429e-037 , 9.2462547772103625e-038 , - 4.8596774326570872e-039
} ;
static double const stbsp__top [ 13 ] = {
1e+023 , 1e+046 , 1e+069 , 1e+092 , 1e+115 , 1e+138 , 1e+161 , 1e+184 , 1e+207 , 1e+230 , 1e+253 , 1e+276 , 1e+299
} ;
static double const stbsp__negtop [ 13 ] = {
1e-023 , 1e-046 , 1e-069 , 1e-092 , 1e-115 , 1e-138 , 1e-161 , 1e-184 , 1e-207 , 1e-230 , 1e-253 , 1e-276 , 1e-299
} ;
static double const stbsp__toperr [ 13 ] = {
8388608 ,
6.8601809640529717e+028 ,
- 7.253143638152921e+052 ,
- 4.3377296974619174e+075 ,
- 1.5559416129466825e+098 ,
- 3.2841562489204913e+121 ,
- 3.7745893248228135e+144 ,
- 1.7356668416969134e+167 ,
- 3.8893577551088374e+190 ,
- 9.9566444326005119e+213 ,
6.3641293062232429e+236 ,
- 5.2069140800249813e+259 ,
- 5.2504760255204387e+282
} ;
static double const stbsp__negtoperr [ 13 ] = {
3.9565301985100693e-040 , - 2.299904345391321e-063 , 3.6506201437945798e-086 , 1.1875228833981544e-109 ,
- 5.0644902316928607e-132 , - 6.7156837247865426e-155 , - 2.812077463003139e-178 , - 5.7778912386589953e-201 ,
7.4997100559334532e-224 , - 4.6439668915134491e-247 , - 6.3691100762962136e-270 , - 9.436808465446358e-293 ,
8.0970921678014997e-317
} ;
# if defined(_MSC_VER) && (_MSC_VER <= 1200)
static stbsp__uint64 const stbsp__powten [ 20 ] = {
1 ,
10 ,
100 ,
1000 ,
10000 ,
100000 ,
1000000 ,
10000000 ,
100000000 ,
1000000000 ,
10000000000 ,
100000000000 ,
1000000000000 ,
10000000000000 ,
100000000000000 ,
1000000000000000 ,
10000000000000000 ,
100000000000000000 ,
1000000000000000000 ,
10000000000000000000U
} ;
# define stbsp__tento19th ((stbsp__uint64)1000000000000000000)
# else
static stbsp__uint64 const stbsp__powten [ 20 ] = {
1 ,
10 ,
100 ,
1000 ,
10000 ,
100000 ,
1000000 ,
10000000 ,
100000000 ,
1000000000 ,
10000000000ULL ,
100000000000ULL ,
1000000000000ULL ,
10000000000000ULL ,
100000000000000ULL ,
1000000000000000ULL ,
10000000000000000ULL ,
100000000000000000ULL ,
1000000000000000000ULL ,
10000000000000000000ULL
} ;
# define stbsp__tento19th (1000000000000000000ULL)
# endif
# define stbsp__ddmulthi(oh, ol, xh, yh) \
{ \
double ahi = 0 , alo , bhi = 0 , blo ; \
stbsp__int64 bt ; \
oh = xh * yh ; \
STBSP__COPYFP ( bt , xh ) ; \
bt & = ( ( ~ ( stbsp__uint64 ) 0 ) < < 27 ) ; \
STBSP__COPYFP ( ahi , bt ) ; \
alo = xh - ahi ; \
STBSP__COPYFP ( bt , yh ) ; \
bt & = ( ( ~ ( stbsp__uint64 ) 0 ) < < 27 ) ; \
STBSP__COPYFP ( bhi , bt ) ; \
blo = yh - bhi ; \
ol = ( ( ahi * bhi - oh ) + ahi * blo + alo * bhi ) + alo * blo ; \
}
# define stbsp__ddtoS64(ob, xh, xl) \
{ \
double ahi = 0 , alo , vh , t ; \
ob = ( stbsp__int64 ) ph ; \
vh = ( double ) ob ; \
ahi = ( xh - vh ) ; \
t = ( ahi - xh ) ; \
alo = ( xh - ( ahi - t ) ) - ( vh + t ) ; \
ob + = ( stbsp__int64 ) ( ahi + alo + xl ) ; \
}
# define stbsp__ddrenorm(oh, ol) \
{ \
double s ; \
s = oh + ol ; \
ol = ol - ( s - oh ) ; \
oh = s ; \
}
# define stbsp__ddmultlo(oh, ol, xh, xl, yh, yl) ol = ol + (xh * yl + xl * yh);
# define stbsp__ddmultlos(oh, ol, xh, yl) ol = ol + (xh * yl);
static void stbsp__raise_to_power10 ( double * ohi , double * olo , double d , stbsp__int32 power ) // power can be -323 to +350
{
double ph , pl ;
if ( ( power > = 0 ) & & ( power < = 22 ) ) {
stbsp__ddmulthi ( ph , pl , d , stbsp__bot [ power ] ) ;
} else {
stbsp__int32 e , et , eb ;
double p2h , p2l ;
e = power ;
if ( power < 0 )
e = - e ;
et = ( e * 0x2c9 ) > > 14 ; /* %23 */
if ( et > 13 )
et = 13 ;
eb = e - ( et * 23 ) ;
ph = d ;
pl = 0.0 ;
if ( power < 0 ) {
if ( eb ) {
- - eb ;
stbsp__ddmulthi ( ph , pl , d , stbsp__negbot [ eb ] ) ;
stbsp__ddmultlos ( ph , pl , d , stbsp__negboterr [ eb ] ) ;
}
if ( et ) {
stbsp__ddrenorm ( ph , pl ) ;
- - et ;
stbsp__ddmulthi ( p2h , p2l , ph , stbsp__negtop [ et ] ) ;
stbsp__ddmultlo ( p2h , p2l , ph , pl , stbsp__negtop [ et ] , stbsp__negtoperr [ et ] ) ;
ph = p2h ;
pl = p2l ;
}
} else {
if ( eb ) {
e = eb ;
if ( eb > 22 )
eb = 22 ;
e - = eb ;
stbsp__ddmulthi ( ph , pl , d , stbsp__bot [ eb ] ) ;
if ( e ) {
stbsp__ddrenorm ( ph , pl ) ;
stbsp__ddmulthi ( p2h , p2l , ph , stbsp__bot [ e ] ) ;
stbsp__ddmultlos ( p2h , p2l , stbsp__bot [ e ] , pl ) ;
ph = p2h ;
pl = p2l ;
}
}
if ( et ) {
stbsp__ddrenorm ( ph , pl ) ;
- - et ;
stbsp__ddmulthi ( p2h , p2l , ph , stbsp__top [ et ] ) ;
stbsp__ddmultlo ( p2h , p2l , ph , pl , stbsp__top [ et ] , stbsp__toperr [ et ] ) ;
ph = p2h ;
pl = p2l ;
}
}
}
stbsp__ddrenorm ( ph , pl ) ;
* ohi = ph ;
* olo = pl ;
}
// given a float value, returns the significant bits in bits, and the position of the
// decimal point in decimal_pos. +/-INF and NAN are specified by special values
// returned in the decimal_pos parameter.
// frac_digits is absolute normally, but if you want from first significant digits (got %g and %e), or in 0x80000000
static stbsp__int32 stbsp__real_to_str ( char const * * start , stbsp__uint32 * len , char * out , stbsp__int32 * decimal_pos , double value , stbsp__uint32 frac_digits )
{
double d ;
stbsp__int64 bits = 0 ;
stbsp__int32 expo , e , ng , tens ;
d = value ;
STBSP__COPYFP ( bits , d ) ;
expo = ( stbsp__int32 ) ( ( bits > > 52 ) & 2047 ) ;
ng = ( stbsp__int32 ) ( bits > > 63 ) ;
if ( ng )
d = - d ;
if ( expo = = 2047 ) // is nan or inf?
{
* start = ( bits & ( ( ( ( stbsp__uint64 ) 1 ) < < 52 ) - 1 ) ) ? " NaN " : " Inf " ;
* decimal_pos = STBSP__SPECIAL ;
* len = 3 ;
return ng ;
}
if ( expo = = 0 ) // is zero or denormal
{
if ( ( bits < < 1 ) = = 0 ) // do zero
{
* decimal_pos = 1 ;
* start = out ;
out [ 0 ] = ' 0 ' ;
* len = 1 ;
return ng ;
}
// find the right expo for denormals
{
stbsp__int64 v = ( ( stbsp__uint64 ) 1 ) < < 51 ;
while ( ( bits & v ) = = 0 ) {
- - expo ;
v > > = 1 ;
}
}
}
// find the decimal exponent as well as the decimal bits of the value
{
double ph , pl ;
// log10 estimate - very specifically tweaked to hit or undershoot by no more than 1 of log10 of all expos 1..2046
tens = expo - 1023 ;
tens = ( tens < 0 ) ? ( ( tens * 617 ) / 2048 ) : ( ( ( tens * 1233 ) / 4096 ) + 1 ) ;
// move the significant bits into position and stick them into an int
stbsp__raise_to_power10 ( & ph , & pl , d , 18 - tens ) ;
// get full as much precision from double-double as possible
stbsp__ddtoS64 ( bits , ph , pl ) ;
// check if we undershot
if ( ( ( stbsp__uint64 ) bits ) > = stbsp__tento19th )
+ + tens ;
}
// now do the rounding in integer land
frac_digits = ( frac_digits & 0x80000000 ) ? ( ( frac_digits & 0x7ffffff ) + 1 ) : ( tens + frac_digits ) ;
if ( ( frac_digits < 24 ) ) {
stbsp__uint32 dg = 1 ;
if ( ( stbsp__uint64 ) bits > = stbsp__powten [ 9 ] )
dg = 10 ;
while ( ( stbsp__uint64 ) bits > = stbsp__powten [ dg ] ) {
+ + dg ;
if ( dg = = 20 )
goto noround ;
}
if ( frac_digits < dg ) {
stbsp__uint64 r ;
// add 0.5 at the right position and round
e = dg - frac_digits ;
if ( ( stbsp__uint32 ) e > = 24 )
goto noround ;
r = stbsp__powten [ e ] ;
bits = bits + ( r / 2 ) ;
if ( ( stbsp__uint64 ) bits > = stbsp__powten [ dg ] )
+ + tens ;
bits / = r ;
}
noround : ;
}
// kill long trailing runs of zeros
if ( bits ) {
stbsp__uint32 n ;
for ( ; ; ) {
if ( bits < = 0xffffffff )
break ;
if ( bits % 1000 )
goto donez ;
bits / = 1000 ;
}
n = ( stbsp__uint32 ) bits ;
while ( ( n % 1000 ) = = 0 )
n / = 1000 ;
bits = n ;
donez : ;
}
// convert to string
out + = 64 ;
e = 0 ;
for ( ; ; ) {
stbsp__uint32 n ;
char * o = out - 8 ;
// do the conversion in chunks of U32s (avoid most 64-bit divides, worth it, constant denomiators be damned)
if ( bits > = 100000000 ) {
n = ( stbsp__uint32 ) ( bits % 100000000 ) ;
bits / = 100000000 ;
} else {
n = ( stbsp__uint32 ) bits ;
bits = 0 ;
}
while ( n ) {
out - = 2 ;
* ( stbsp__uint16 * ) out = * ( stbsp__uint16 * ) & stbsp__digitpair [ ( n % 100 ) * 2 ] ;
n / = 100 ;
e + = 2 ;
}
if ( bits = = 0 ) {
if ( ( e ) & & ( out [ 0 ] = = ' 0 ' ) ) {
+ + out ;
- - e ;
}
break ;
}
while ( out ! = o ) {
* - - out = ' 0 ' ;
+ + e ;
}
}
* decimal_pos = tens ;
* start = out ;
* len = e ;
return ng ;
}
# undef stbsp__ddmulthi
# undef stbsp__ddrenorm
# undef stbsp__ddmultlo
# undef stbsp__ddmultlos
# undef STBSP__SPECIAL
# undef STBSP__COPYFP
# endif // STB_SPRINTF_NOFLOAT
// clean up
# undef stbsp__uint16
# undef stbsp__uint32
# undef stbsp__int32
# undef stbsp__uint64
# undef stbsp__int64
# undef STBSP__UNALIGNED
# endif // STB_SPRINTF_IMPLEMENTATION
/*
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
This software is available under 2 licenses - - choose whichever you prefer .
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
ALTERNATIVE A - MIT License
Copyright ( c ) 2017 Sean Barrett
Permission is hereby granted , free of charge , to any person obtaining a copy of
this software and associated documentation files ( the " Software " ) , to deal in
the Software without restriction , including without limitation the rights to
use , copy , modify , merge , publish , distribute , sublicense , and / or sell copies
of the Software , and to permit persons to whom the Software is furnished to do
so , subject to the following conditions :
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software .
THE SOFTWARE IS PROVIDED " AS IS " , WITHOUT WARRANTY OF ANY KIND , EXPRESS OR
IMPLIED , INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY ,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT . IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM , DAMAGES OR OTHER
LIABILITY , WHETHER IN AN ACTION OF CONTRACT , TORT OR OTHERWISE , ARISING FROM ,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE .
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
ALTERNATIVE B - Public Domain ( www . unlicense . org )
This is free and unencumbered software released into the public domain .
Anyone is free to copy , modify , publish , use , compile , sell , or distribute this
software , either in source code form or as a compiled binary , for any purpose ,
commercial or non - commercial , and by any means .
In jurisdictions that recognize copyright laws , the author or authors of this
software dedicate any and all copyright interest in the software to the public
domain . We make this dedication for the benefit of the public at large and to
the detriment of our heirs and successors . We intend this dedication to be an
overt act of relinquishment in perpetuity of all present and future rights to
this software under copyright law .
THE SOFTWARE IS PROVIDED " AS IS " , WITHOUT WARRANTY OF ANY KIND , EXPRESS OR
IMPLIED , INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY ,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT . IN NO EVENT SHALL THE
AUTHORS BE LIABLE FOR ANY CLAIM , DAMAGES OR OTHER LIABILITY , WHETHER IN AN
ACTION OF CONTRACT , TORT OR OTHERWISE , ARISING FROM , OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE .
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
*/