Rewrite Dqn_StringBuilder, stddef for ptrdiff_t
This commit is contained in:
parent
2f681515f6
commit
927937df98
635
Code/Dqn.h
635
Code/Dqn.h
@ -19,17 +19,214 @@
|
|||||||
|
|
||||||
// Otherwise if not defined, Dqn_Allocator allocator = {}; will by default use malloc, realloc, free
|
// Otherwise if not defined, Dqn_Allocator allocator = {}; will by default use malloc, realloc, free
|
||||||
|
|
||||||
|
#if defined(_MSC_VER)
|
||||||
|
#if defined(_CRT_SECURE_NO_WARNINGS)
|
||||||
|
#define DQN_CRT_SECURE_NO_WARNINGS_PREVIOUSLY_DEFINED
|
||||||
|
#else
|
||||||
|
#define _CRT_SECURE_NO_WARNINGS
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// -------------------------------------------------------------------------------------------------
|
||||||
|
//
|
||||||
|
// 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 8K with float support, and 4K without.
|
||||||
|
As a comparison, when using MSVC static libs, calling sprintf drags
|
||||||
|
in 16K.
|
||||||
|
|
||||||
|
API:
|
||||||
|
====
|
||||||
|
int stbsp_sprintf( char * buf, char const * fmt, ... )
|
||||||
|
int stbsp_snprintf( char * buf, int count, char const * fmt, ... )
|
||||||
|
Convert an arg list into a buffer. stbsp_snprintf always returns
|
||||||
|
a zero-terminated string (unlike regular snprintf).
|
||||||
|
|
||||||
|
int stbsp_vsprintf( char * buf, char const * fmt, va_list va )
|
||||||
|
int stbsp_vsnprintf( char * buf, int count, char const * fmt, va_list va )
|
||||||
|
Convert a va_list arg list into a buffer. stbsp_vsnprintf always returns
|
||||||
|
a zero-terminated string (unlike regular snprintf).
|
||||||
|
|
||||||
|
int stbsp_vsprintfcb( STBSP_SPRINTFCB * callback, void * user, char * buf, char const * fmt, va_list va )
|
||||||
|
typedef char * STBSP_SPRINTFCB( char const * buf, void * user, int len );
|
||||||
|
Convert into a buffer, calling back every STB_SPRINTF_MIN chars.
|
||||||
|
Your callback can then copy the chars out, print them or whatever.
|
||||||
|
This function is actually the workhorse for everything else.
|
||||||
|
The buffer you pass in must hold at least STB_SPRINTF_MIN characters.
|
||||||
|
// you return the next buffer to use or 0 to stop converting
|
||||||
|
|
||||||
|
void stbsp_set_separators( char comma, char period )
|
||||||
|
Set the comma and period characters to use.
|
||||||
|
|
||||||
|
FLOATS/DOUBLES:
|
||||||
|
===============
|
||||||
|
This code uses a internal float->ascii conversion method that uses
|
||||||
|
doubles with error correction (double-doubles, for ~105 bits of
|
||||||
|
precision). This conversion is round-trip perfect - that is, an atof
|
||||||
|
of the values output here will give you the bit-exact double back.
|
||||||
|
|
||||||
|
One difference is that our insignificant digits will be different than
|
||||||
|
with MSVC or GCC (but they don't match each other either). We also
|
||||||
|
don't attempt to find the minimum length matching float (pre-MSVC15
|
||||||
|
doesn't either).
|
||||||
|
|
||||||
|
If you don't need float or doubles at all, define STB_SPRINTF_NOFLOAT
|
||||||
|
and you'll save 4K of code space.
|
||||||
|
|
||||||
|
64-BIT INTS:
|
||||||
|
============
|
||||||
|
This library also supports 64-bit integers and you can use MSVC style or
|
||||||
|
GCC style indicators (%I64d or %lld). It supports the C99 specifiers
|
||||||
|
for size_t and ptr_diff_t (%jd %zd) as well.
|
||||||
|
|
||||||
|
EXTRAS:
|
||||||
|
=======
|
||||||
|
Like some GCCs, for integers and floats, you can use a ' (single quote)
|
||||||
|
specifier and commas will be inserted on the thousands: "%'d" on 12345
|
||||||
|
would print 12,345.
|
||||||
|
|
||||||
|
For integers and floats, you can use a "$" specifier and the number
|
||||||
|
will be converted to float and then divided to get kilo, mega, giga or
|
||||||
|
tera and then printed, so "%$d" 1000 is "1.0 k", "%$.2d" 2536000 is
|
||||||
|
"2.53 M", etc. For byte values, use two $:s, like "%$$d" to turn
|
||||||
|
2536000 to "2.42 Mi". If you prefer JEDEC suffixes to SI ones, use three
|
||||||
|
$:s: "%$$$d" -> "2.42 M". To remove the space between the number and the
|
||||||
|
suffix, add "_" specifier: "%_$d" -> "2.53M".
|
||||||
|
|
||||||
|
In addition to octal and hexadecimal conversions, you can print
|
||||||
|
integers in binary: "%b" for 256 would print 100.
|
||||||
|
|
||||||
|
PERFORMANCE vs MSVC 2008 32-/64-bit (GCC is even slower than MSVC):
|
||||||
|
===================================================================
|
||||||
|
"%d" across all 32-bit ints (4.8x/4.0x faster than 32-/64-bit MSVC)
|
||||||
|
"%24d" across all 32-bit ints (4.5x/4.2x faster)
|
||||||
|
"%x" across all 32-bit ints (4.5x/3.8x faster)
|
||||||
|
"%08x" across all 32-bit ints (4.3x/3.8x faster)
|
||||||
|
"%f" across e-10 to e+10 floats (7.3x/6.0x faster)
|
||||||
|
"%e" across e-10 to e+10 floats (8.1x/6.0x faster)
|
||||||
|
"%g" across e-10 to e+10 floats (10.0x/7.1x faster)
|
||||||
|
"%f" for values near e-300 (7.9x/6.5x faster)
|
||||||
|
"%f" for values near e+300 (10.0x/9.1x faster)
|
||||||
|
"%e" for values near e-300 (10.1x/7.0x faster)
|
||||||
|
"%e" for values near e+300 (9.2x/6.0x faster)
|
||||||
|
"%.320f" for values near e-300 (12.6x/11.2x faster)
|
||||||
|
"%a" for random values (8.6x/4.3x faster)
|
||||||
|
"%I64d" for 64-bits with 32-bit values (4.8x/3.4x faster)
|
||||||
|
"%I64d" for 64-bits > 32-bit values (4.9x/5.5x faster)
|
||||||
|
"%s%s%s" for 64 char strings (7.1x/7.3x faster)
|
||||||
|
"...512 char string..." ( 35.0x/32.5x faster!)
|
||||||
|
*/
|
||||||
|
|
||||||
|
#if defined(__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
|
||||||
|
|
||||||
|
// -------------------------------------------------------------------------------------------------
|
||||||
|
//
|
||||||
|
// DQN
|
||||||
|
//
|
||||||
|
// -------------------------------------------------------------------------------------------------
|
||||||
#ifndef DQN_H
|
#ifndef DQN_H
|
||||||
#define DQN_H
|
#define DQN_H
|
||||||
|
|
||||||
#if defined(_MSC_VER)
|
|
||||||
#define _CRT_SECURE_NO_WARNINGS
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include <float.h> // FLT_MAX
|
#include <float.h> // FLT_MAX
|
||||||
#include <stdint.h> // uint/int typedefs
|
#include <stdint.h> // uint/int typedefs
|
||||||
#include <string.h> // memset, memcmp, strlen, strcmp
|
#include <string.h> // memset, memcmp, strlen, strcmp
|
||||||
#include <stdarg.h> // va_list
|
#include <stdarg.h> // va_list
|
||||||
|
#include <limits.h> // INT_MIN/MAX etc
|
||||||
|
#include <stddef.h> // ptrdiff_t
|
||||||
|
|
||||||
#undef DQN_HEADER_IMPLEMENTATION
|
#undef DQN_HEADER_IMPLEMENTATION
|
||||||
#include "DqnHeader.h"
|
#include "DqnHeader.h"
|
||||||
@ -165,16 +362,16 @@ const Dqn_f32 DQN_F32_MAX = FLT_MAX;
|
|||||||
const Dqn_isize DQN_ISIZE_MAX = PTRDIFF_MAX;
|
const Dqn_isize DQN_ISIZE_MAX = PTRDIFF_MAX;
|
||||||
const Dqn_usize DQN_USIZE_MAX = SIZE_MAX;
|
const Dqn_usize DQN_USIZE_MAX = SIZE_MAX;
|
||||||
|
|
||||||
template <typename T, Dqn_usize N>
|
template <typename T, Dqn_isize N>
|
||||||
DQN_HEADER_COPY_PROTOTYPE(constexpr Dqn_usize, Dqn_ArrayCount(T const (&)[N])) { return N; }
|
DQN_HEADER_COPY_PROTOTYPE(constexpr Dqn_usize, Dqn_ArrayCount(T const (&)[N])) { return N; }
|
||||||
|
|
||||||
template <typename T, Dqn_usize N>
|
template <typename T, Dqn_isize N>
|
||||||
DQN_HEADER_COPY_PROTOTYPE(constexpr Dqn_isize, Dqn_ArrayCountI(T const (&)[N])) { return N; }
|
DQN_HEADER_COPY_PROTOTYPE(constexpr Dqn_isize, Dqn_ArrayCountI(T const (&)[N])) { return N; }
|
||||||
|
|
||||||
template <Dqn_usize N>
|
template <Dqn_isize N>
|
||||||
DQN_HEADER_COPY_PROTOTYPE(constexpr Dqn_usize, Dqn_CharCount(char const (&)[N])) { return N - 1; }
|
DQN_HEADER_COPY_PROTOTYPE(constexpr Dqn_usize, Dqn_CharCount(char const (&)[N])) { return N - 1; }
|
||||||
|
|
||||||
template <Dqn_usize N>
|
template <Dqn_isize N>
|
||||||
DQN_HEADER_COPY_PROTOTYPE(constexpr Dqn_isize, Dqn_CharCountI(char const (&)[N])) { return N - 1; }
|
DQN_HEADER_COPY_PROTOTYPE(constexpr Dqn_isize, Dqn_CharCountI(char const (&)[N])) { return N - 1; }
|
||||||
|
|
||||||
template <typename Procedure>
|
template <typename Procedure>
|
||||||
@ -602,158 +799,132 @@ DQN_HEADER_COPY_END
|
|||||||
// @
|
// @
|
||||||
// @ -------------------------------------------------------------------------------------------------
|
// @ -------------------------------------------------------------------------------------------------
|
||||||
DQN_HEADER_COPY_BEGIN
|
DQN_HEADER_COPY_BEGIN
|
||||||
struct Dqn_StringBuilderBuffer
|
struct Dqn_StringBuilderBlock
|
||||||
{
|
{
|
||||||
char *mem;
|
char *mem;
|
||||||
Dqn_isize size;
|
Dqn_isize size;
|
||||||
Dqn_isize used;
|
Dqn_isize used;
|
||||||
Dqn_StringBuilderBuffer *next;
|
Dqn_StringBuilderBlock *next;
|
||||||
};
|
};
|
||||||
|
|
||||||
Dqn_isize constexpr DQN_STRING_BUILDER_MIN_MEM_BUF_ALLOC_SIZE = DQN_KILOBYTES(4);
|
Dqn_isize constexpr DQN_STRING_BUILDER_MIN_BLOCK_SIZE = DQN_KILOBYTES(4);
|
||||||
template <Dqn_usize N = DQN_KILOBYTES(16)>
|
template <Dqn_isize N = DQN_KILOBYTES(16)>
|
||||||
struct Dqn_StringBuilder
|
struct Dqn_StringBuilder
|
||||||
{
|
{
|
||||||
Dqn_Allocator allocator;
|
Dqn_Allocator allocator;
|
||||||
char fixed_mem[N];
|
char fixed_mem[N];
|
||||||
Dqn_isize fixed_mem_used;
|
Dqn_StringBuilderBlock fixed_mem_block;
|
||||||
Dqn_StringBuilderBuffer *next_mem_buf;
|
Dqn_StringBuilderBlock *last_mem_block;
|
||||||
Dqn_StringBuilderBuffer *last_mem_buf;
|
|
||||||
Dqn_isize string_len;
|
|
||||||
};
|
};
|
||||||
DQN_HEADER_COPY_END
|
DQN_HEADER_COPY_END
|
||||||
|
|
||||||
template <Dqn_usize N> DQN_FILE_SCOPE char *Dqn_StringBuilder__GetWriteBufferAndUpdateUsage(Dqn_StringBuilder<N> *builder, Dqn_isize size_required)
|
template <Dqn_isize N>
|
||||||
|
void Dqn_StringBuilder__LazyInitialise(Dqn_StringBuilder<N> *builder)
|
||||||
{
|
{
|
||||||
char *result = builder->fixed_mem + builder->fixed_mem_used;
|
builder->fixed_mem_block.mem = builder->fixed_mem;
|
||||||
Dqn_isize space = Dqn_ArrayCountI(builder->fixed_mem) - builder->fixed_mem_used;
|
builder->fixed_mem_block.size = Dqn_ArrayCount(builder->fixed_mem);
|
||||||
Dqn_isize *usage = &builder->fixed_mem_used;
|
builder->fixed_mem_block.used = 0;
|
||||||
|
builder->fixed_mem_block.next = nullptr;
|
||||||
|
builder->last_mem_block = &builder->fixed_mem_block;
|
||||||
|
}
|
||||||
|
|
||||||
if (builder->last_mem_buf)
|
// @ size_required: The length of the string not including the null terminator.
|
||||||
|
template <Dqn_isize N> DQN_FILE_SCOPE char *Dqn_StringBuilder_AllocateWriteBuffer(Dqn_StringBuilder<N> *builder, Dqn_isize size_required)
|
||||||
|
{
|
||||||
|
if (!builder->fixed_mem_block.mem)
|
||||||
{
|
{
|
||||||
Dqn_StringBuilderBuffer *last_buf = builder->last_mem_buf;
|
DQN_ASSERT(!builder->last_mem_block);
|
||||||
result = last_buf->mem + last_buf->used;
|
Dqn_StringBuilder__LazyInitialise(builder);
|
||||||
space = last_buf->size - last_buf->used;
|
|
||||||
usage = &last_buf->used;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (space < size_required)
|
Dqn_StringBuilderBlock *block = builder->last_mem_block;
|
||||||
|
Dqn_b32 new_block_needed = (block->size - block->used) < size_required;
|
||||||
|
if (new_block_needed)
|
||||||
{
|
{
|
||||||
// NOTE: Need to allocate new buf
|
Dqn_isize allocation_size = DQN_MAX(size_required, DQN_STRING_BUILDER_MIN_BLOCK_SIZE);
|
||||||
Dqn_isize allocation_size = DQN_ISIZEOF(*builder->last_mem_buf) + DQN_MAX(size_required, DQN_STRING_BUILDER_MIN_MEM_BUF_ALLOC_SIZE);
|
block = Dqn_Allocator_AllocateType<Dqn_StringBuilderBlock>(&builder->allocator, 1);
|
||||||
void *memory = Dqn_Allocator_Allocate(&builder->allocator, allocation_size, alignof(Dqn_StringBuilderBuffer));
|
if (!block) return nullptr;
|
||||||
if (!memory) return nullptr;
|
|
||||||
auto *new_buf = DQN_CAST(Dqn_StringBuilderBuffer *)memory;
|
|
||||||
*new_buf = {};
|
|
||||||
new_buf->mem = DQN_CAST(char *)memory + sizeof(*new_buf);
|
|
||||||
new_buf->size = allocation_size;
|
|
||||||
result = new_buf->mem;
|
|
||||||
usage = &new_buf->used;
|
|
||||||
|
|
||||||
if (builder->last_mem_buf)
|
*block = {};
|
||||||
{
|
block->mem = DQN_CAST(char *)Dqn_Allocator_Allocate(&builder->allocator, allocation_size, alignof(char));
|
||||||
builder->last_mem_buf->next = new_buf;
|
block->size = allocation_size;
|
||||||
}
|
builder->last_mem_block->next = block;
|
||||||
else
|
builder->last_mem_block = builder->last_mem_block->next;
|
||||||
{
|
|
||||||
builder->next_mem_buf = new_buf;
|
|
||||||
builder->last_mem_buf = new_buf;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (size_required > 0 && *usage > 0 && result[-1] == 0)
|
char *result = block->mem + block->used;
|
||||||
{
|
block->used += size_required;
|
||||||
// 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;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <Dqn_usize N> DQN_FILE_SCOPE void Dqn_StringBuilder__BuildOutput(Dqn_StringBuilder<N> const *builder, char *dest, Dqn_isize dest_size)
|
// @ The necessary length to build the string, it returns the length not including the null-terminator
|
||||||
|
DQN_HEADER_COPY_PROTOTYPE(template <Dqn_isize N> Dqn_isize, Dqn_StringBuilder_BuildLength(Dqn_StringBuilder<N> const *builder))
|
||||||
{
|
{
|
||||||
// NOTE: No data appended to builder, just allocate am empty string. But
|
Dqn_isize result = 0;
|
||||||
// always allocate, so we avoid adding making nullptr part of the possible
|
for (Dqn_StringBuilderBlock const *block = &builder->fixed_mem_block;
|
||||||
// return values and makes using Dqn_StringBuilder more complex.
|
block;
|
||||||
if (dest_size == 1)
|
block = block->next)
|
||||||
{
|
{
|
||||||
dest[0] = 0;
|
result += block->used;
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!dest)
|
|
||||||
{
|
|
||||||
DQN_ASSERT(dest);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
char const *end = dest + dest_size;
|
|
||||||
char *buf_ptr = dest;
|
|
||||||
|
|
||||||
DQN_MEMCOPY(buf_ptr, builder->fixed_mem, builder->fixed_mem_used);
|
|
||||||
buf_ptr += builder->fixed_mem_used;
|
|
||||||
|
|
||||||
Dqn_isize remaining_space = end - buf_ptr;
|
|
||||||
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
|
|
||||||
DQN_MEMCOPY(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);
|
|
||||||
}
|
|
||||||
|
|
||||||
// @ The necessary length to build the string, it returns the length including the null-terminator
|
|
||||||
DQN_HEADER_COPY_PROTOTYPE(template <Dqn_usize N> Dqn_isize, Dqn_StringBuilder_BuildLen(Dqn_StringBuilder<N> const *builder))
|
|
||||||
{
|
|
||||||
Dqn_isize result = builder->string_len + 1;
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
DQN_HEADER_COPY_PROTOTYPE(template <Dqn_usize N> void, Dqn_StringBuilder_BuildInBuffer(Dqn_StringBuilder<N> const *builder, char *dest, Dqn_usize dest_size))
|
DQN_HEADER_COPY_PROTOTYPE(template <Dqn_isize N> void, Dqn_StringBuilder_BuildToDest(Dqn_StringBuilder<N> const *builder, char *dest, Dqn_usize dest_size))
|
||||||
{
|
{
|
||||||
Dqn_StringBuilder__BuildOutput(builder, dest, dest_size);
|
if (!dest) return;
|
||||||
|
if (dest_size == 1) { dest[0] = 0; return; }
|
||||||
|
|
||||||
|
char *ptr = dest;
|
||||||
|
char const *end = dest + dest_size;
|
||||||
|
Dqn_isize remaining_space = end - ptr;
|
||||||
|
for (Dqn_StringBuilderBlock const *block = &builder->fixed_mem_block;
|
||||||
|
block && remaining_space > 0;
|
||||||
|
block = block->next, remaining_space = end - ptr)
|
||||||
|
{
|
||||||
|
Dqn_isize num_bytes = block->used;
|
||||||
|
Dqn_isize bytes_to_copy = DQN_MIN(num_bytes, remaining_space);
|
||||||
|
DQN_MEMCOPY(ptr, block->mem, bytes_to_copy);
|
||||||
|
ptr += bytes_to_copy;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (remaining_space > 0) ptr[ 0] = 0; // Append null terminator
|
||||||
|
else ptr[-1] = 0; // Oops ran out of space. Terminate the output prematurely.
|
||||||
}
|
}
|
||||||
|
|
||||||
DQN_HEADER_COPY_PROTOTYPE(template <Dqn_usize N> char *, Dqn_StringBuilder_Build(Dqn_StringBuilder<N> *builder, Dqn_Allocator *allocator, Dqn_isize *len = nullptr))
|
DQN_HEADER_COPY_PROTOTYPE(template <Dqn_isize N> char *, Dqn_StringBuilder_Build(Dqn_StringBuilder<N> *builder, Dqn_Allocator *allocator, Dqn_isize *len = nullptr))
|
||||||
{
|
{
|
||||||
Dqn_isize len_w_null_terminator = Dqn_StringBuilder_BuildLen(builder);
|
Dqn_isize len_ = 0;
|
||||||
auto *result = DQN_CAST(char *)Dqn_Allocator_Allocate(allocator, len_w_null_terminator, alignof(char));
|
if (!len) len = &len_;
|
||||||
if (len) *len = (len_w_null_terminator - 1);
|
*len = Dqn_StringBuilder_BuildLength(builder);
|
||||||
Dqn_StringBuilder__BuildOutput(builder, result, len_w_null_terminator);
|
auto *result = DQN_CAST(char *)Dqn_Allocator_Allocate(allocator, *len + 1, alignof(char));
|
||||||
|
Dqn_StringBuilder_BuildToDest(builder, result, *len + 1);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
DQN_HEADER_COPY_PROTOTYPE(template <Dqn_usize N> Dqn_String, Dqn_StringBuilder_BuildString(Dqn_StringBuilder<N> *builder, Dqn_Allocator *allocator))
|
DQN_HEADER_COPY_PROTOTYPE(template <Dqn_isize N> Dqn_String, Dqn_StringBuilder_BuildString(Dqn_StringBuilder<N> *builder, Dqn_Allocator *allocator))
|
||||||
{
|
{
|
||||||
Dqn_String result = {};
|
Dqn_String result = {};
|
||||||
result.str = Dqn_StringBuilder_Build(builder, allocator, &result.len);
|
result.str = Dqn_StringBuilder_Build(builder, allocator, &result.len);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
DQN_HEADER_COPY_PROTOTYPE(template <Dqn_usize N> void, Dqn_StringBuilder_VFmtAppend(Dqn_StringBuilder<N> *builder, char const *fmt, va_list va))
|
DQN_HEADER_COPY_PROTOTYPE(template <Dqn_isize N> void, Dqn_StringBuilder_VFmtAppend(Dqn_StringBuilder<N> *builder, char const *fmt, va_list va))
|
||||||
{
|
{
|
||||||
if (!fmt) return;
|
if (!fmt) return;
|
||||||
va_list va2;
|
va_list va2;
|
||||||
va_copy(va2, va);
|
va_copy(va2, va);
|
||||||
Dqn_isize require = stbsp_vsnprintf(nullptr, 0, fmt, va) + 1;
|
Dqn_isize len = stbsp_vsnprintf(nullptr, 0, fmt, va);
|
||||||
char *buf = Dqn_StringBuilder__GetWriteBufferAndUpdateUsage(builder, require);
|
char *buf = Dqn_StringBuilder_AllocateWriteBuffer(builder, len + 1);
|
||||||
stbsp_vsnprintf(buf, static_cast<int>(require), fmt, va2);
|
stbsp_vsnprintf(buf, static_cast<int>(len + 1), fmt, va2);
|
||||||
va_end(va2);
|
va_end(va2);
|
||||||
builder->string_len += (require - 1); // -1 to exclude null terminator
|
|
||||||
|
DQN_ASSERT(builder->last_mem_block->used >= 0);
|
||||||
|
builder->last_mem_block->used--; // stbsp_vsnprintf null terminates, back out the null-terminator from the mem block
|
||||||
}
|
}
|
||||||
|
|
||||||
DQN_HEADER_COPY_PROTOTYPE(template <Dqn_usize N> void, Dqn_StringBuilder_FmtAppend(Dqn_StringBuilder<N> *builder, char const *fmt, ...))
|
DQN_HEADER_COPY_PROTOTYPE(template <Dqn_isize N> void, Dqn_StringBuilder_FmtAppend(Dqn_StringBuilder<N> *builder, char const *fmt, ...))
|
||||||
{
|
{
|
||||||
va_list va;
|
va_list va;
|
||||||
va_start(va, fmt);
|
va_start(va, fmt);
|
||||||
@ -761,51 +932,39 @@ DQN_HEADER_COPY_PROTOTYPE(template <Dqn_usize N> void, Dqn_StringBuilder_FmtAppe
|
|||||||
va_end(va);
|
va_end(va);
|
||||||
}
|
}
|
||||||
|
|
||||||
DQN_HEADER_COPY_PROTOTYPE(template <Dqn_usize N> void, Dqn_StringBuilder_Append(Dqn_StringBuilder<N> *builder, char const *str, Dqn_isize len = -1))
|
DQN_HEADER_COPY_PROTOTYPE(template <Dqn_isize N> void, Dqn_StringBuilder_Append(Dqn_StringBuilder<N> *builder, char const *str, Dqn_isize len = -1))
|
||||||
{
|
{
|
||||||
if (!str) return;
|
if (!str) return;
|
||||||
if (len == -1) len = DQN_CAST(Dqn_isize)strlen(str);
|
if (len == -1) len = DQN_CAST(Dqn_isize)strlen(str);
|
||||||
if (len == 0) return;
|
if (len == 0) return;
|
||||||
|
char *buf = Dqn_StringBuilder_AllocateWriteBuffer(builder, len);
|
||||||
Dqn_isize len_w_null_terminator = len + 1;
|
|
||||||
char *buf = Dqn_StringBuilder__GetWriteBufferAndUpdateUsage(builder, len_w_null_terminator);
|
|
||||||
DQN_MEMCOPY(buf, str, len);
|
DQN_MEMCOPY(buf, str, len);
|
||||||
builder->string_len += len;
|
|
||||||
buf[len] = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
DQN_HEADER_COPY_PROTOTYPE(template <Dqn_usize N> void, Dqn_StringBuilder_AppendString(Dqn_StringBuilder<N> *builder, Dqn_String const string))
|
DQN_HEADER_COPY_PROTOTYPE(template <Dqn_isize N> void, Dqn_StringBuilder_AppendString(Dqn_StringBuilder<N> *builder, Dqn_String const string))
|
||||||
{
|
{
|
||||||
if (!string.str || string.len == 0) return;
|
if (!string.str || string.len == 0) return;
|
||||||
Dqn_isize len_w_null_terminator = string.len + 1;
|
char *buf = Dqn_StringBuilder_AllocateWriteBuffer(builder, string.len);
|
||||||
char *buf = Dqn_StringBuilder__GetWriteBufferAndUpdateUsage(builder, len_w_null_terminator);
|
|
||||||
DQN_MEMCOPY(buf, string.str, string.len);
|
DQN_MEMCOPY(buf, string.str, string.len);
|
||||||
builder->string_len += string.len;
|
|
||||||
buf[string.len] = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
DQN_HEADER_COPY_PROTOTYPE(template <Dqn_usize N> void, Dqn_StringBuilder_AppendChar(Dqn_StringBuilder<N> *builder, char ch))
|
DQN_HEADER_COPY_PROTOTYPE(template <Dqn_isize N> void, Dqn_StringBuilder_AppendChar(Dqn_StringBuilder<N> *builder, char ch))
|
||||||
{
|
{
|
||||||
char *buf = Dqn_StringBuilder__GetWriteBufferAndUpdateUsage(builder, 1 + 1 /*null terminator*/);
|
char *buf = Dqn_StringBuilder_AllocateWriteBuffer(builder, 1);
|
||||||
*buf++ = ch;
|
*buf++ = ch;
|
||||||
builder->string_len++;
|
|
||||||
buf[1] = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
DQN_HEADER_COPY_PROTOTYPE(template <Dqn_usize N> void, Dqn_StringBuilder_Free(Dqn_StringBuilder<N> *builder))
|
DQN_HEADER_COPY_PROTOTYPE(template <Dqn_isize N> void, Dqn_StringBuilder_Free(Dqn_StringBuilder<N> *builder))
|
||||||
{
|
{
|
||||||
for (Dqn_StringBuilderBuffer *buffer = builder->next_mem_buf;
|
for (Dqn_StringBuilderBlock *block = builder->fixed_mem_block.next;
|
||||||
buffer;
|
block;
|
||||||
)
|
block = block->next)
|
||||||
{
|
{
|
||||||
Dqn_StringBuilderBuffer *buffer_to_free = buffer;
|
Dqn_StringBuilderBlock *block_to_free = block;
|
||||||
buffer = buffer->next;
|
Dqn_Allocator_Free(&builder->allocator, block_to_free->mem);
|
||||||
Dqn_Allocator_Free(&builder->allocator, buffer_to_free);
|
Dqn_Allocator_Free(&builder->allocator, block_to_free);
|
||||||
}
|
}
|
||||||
|
Dqn_StringBuilder__LazyInitialise(builder);
|
||||||
builder->next_mem_buf = builder->last_mem_buf = nullptr;
|
|
||||||
builder->fixed_mem_used = 0;
|
|
||||||
builder->string_len = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// @ -------------------------------------------------------------------------------------------------
|
// @ -------------------------------------------------------------------------------------------------
|
||||||
@ -1172,6 +1331,7 @@ struct Dqn_FixedString
|
|||||||
{
|
{
|
||||||
union { char data[MAX_]; char str[MAX_]; char buf[MAX_]; };
|
union { char data[MAX_]; char str[MAX_]; char buf[MAX_]; };
|
||||||
Dqn_isize len;
|
Dqn_isize len;
|
||||||
|
Dqn_isize max = MAX_;
|
||||||
|
|
||||||
Dqn_FixedString() { data[0] = 0; len = 0; }
|
Dqn_FixedString() { data[0] = 0; len = 0; }
|
||||||
Dqn_FixedString(char const *fmt, ...)
|
Dqn_FixedString(char const *fmt, ...)
|
||||||
@ -1269,197 +1429,8 @@ struct Dqn_U64Str
|
|||||||
int len;
|
int len;
|
||||||
};
|
};
|
||||||
DQN_HEADER_COPY_END
|
DQN_HEADER_COPY_END
|
||||||
#if defined(_MSC_VER)
|
|
||||||
#undef _CRT_SECURE_NO_WARNINGS
|
|
||||||
#endif
|
|
||||||
#endif // DQN_H
|
#endif // DQN_H
|
||||||
|
|
||||||
// -------------------------------------------------------------------------------------------------
|
|
||||||
//
|
|
||||||
// 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 8K with float support, and 4K without.
|
|
||||||
As a comparison, when using MSVC static libs, calling sprintf drags
|
|
||||||
in 16K.
|
|
||||||
|
|
||||||
API:
|
|
||||||
====
|
|
||||||
int stbsp_sprintf( char * buf, char const * fmt, ... )
|
|
||||||
int stbsp_snprintf( char * buf, int count, char const * fmt, ... )
|
|
||||||
Convert an arg list into a buffer. stbsp_snprintf always returns
|
|
||||||
a zero-terminated string (unlike regular snprintf).
|
|
||||||
|
|
||||||
int stbsp_vsprintf( char * buf, char const * fmt, va_list va )
|
|
||||||
int stbsp_vsnprintf( char * buf, int count, char const * fmt, va_list va )
|
|
||||||
Convert a va_list arg list into a buffer. stbsp_vsnprintf always returns
|
|
||||||
a zero-terminated string (unlike regular snprintf).
|
|
||||||
|
|
||||||
int stbsp_vsprintfcb( STBSP_SPRINTFCB * callback, void * user, char * buf, char const * fmt, va_list va )
|
|
||||||
typedef char * STBSP_SPRINTFCB( char const * buf, void * user, int len );
|
|
||||||
Convert into a buffer, calling back every STB_SPRINTF_MIN chars.
|
|
||||||
Your callback can then copy the chars out, print them or whatever.
|
|
||||||
This function is actually the workhorse for everything else.
|
|
||||||
The buffer you pass in must hold at least STB_SPRINTF_MIN characters.
|
|
||||||
// you return the next buffer to use or 0 to stop converting
|
|
||||||
|
|
||||||
void stbsp_set_separators( char comma, char period )
|
|
||||||
Set the comma and period characters to use.
|
|
||||||
|
|
||||||
FLOATS/DOUBLES:
|
|
||||||
===============
|
|
||||||
This code uses a internal float->ascii conversion method that uses
|
|
||||||
doubles with error correction (double-doubles, for ~105 bits of
|
|
||||||
precision). This conversion is round-trip perfect - that is, an atof
|
|
||||||
of the values output here will give you the bit-exact double back.
|
|
||||||
|
|
||||||
One difference is that our insignificant digits will be different than
|
|
||||||
with MSVC or GCC (but they don't match each other either). We also
|
|
||||||
don't attempt to find the minimum length matching float (pre-MSVC15
|
|
||||||
doesn't either).
|
|
||||||
|
|
||||||
If you don't need float or doubles at all, define STB_SPRINTF_NOFLOAT
|
|
||||||
and you'll save 4K of code space.
|
|
||||||
|
|
||||||
64-BIT INTS:
|
|
||||||
============
|
|
||||||
This library also supports 64-bit integers and you can use MSVC style or
|
|
||||||
GCC style indicators (%I64d or %lld). It supports the C99 specifiers
|
|
||||||
for size_t and ptr_diff_t (%jd %zd) as well.
|
|
||||||
|
|
||||||
EXTRAS:
|
|
||||||
=======
|
|
||||||
Like some GCCs, for integers and floats, you can use a ' (single quote)
|
|
||||||
specifier and commas will be inserted on the thousands: "%'d" on 12345
|
|
||||||
would print 12,345.
|
|
||||||
|
|
||||||
For integers and floats, you can use a "$" specifier and the number
|
|
||||||
will be converted to float and then divided to get kilo, mega, giga or
|
|
||||||
tera and then printed, so "%$d" 1000 is "1.0 k", "%$.2d" 2536000 is
|
|
||||||
"2.53 M", etc. For byte values, use two $:s, like "%$$d" to turn
|
|
||||||
2536000 to "2.42 Mi". If you prefer JEDEC suffixes to SI ones, use three
|
|
||||||
$:s: "%$$$d" -> "2.42 M". To remove the space between the number and the
|
|
||||||
suffix, add "_" specifier: "%_$d" -> "2.53M".
|
|
||||||
|
|
||||||
In addition to octal and hexadecimal conversions, you can print
|
|
||||||
integers in binary: "%b" for 256 would print 100.
|
|
||||||
|
|
||||||
PERFORMANCE vs MSVC 2008 32-/64-bit (GCC is even slower than MSVC):
|
|
||||||
===================================================================
|
|
||||||
"%d" across all 32-bit ints (4.8x/4.0x faster than 32-/64-bit MSVC)
|
|
||||||
"%24d" across all 32-bit ints (4.5x/4.2x faster)
|
|
||||||
"%x" across all 32-bit ints (4.5x/3.8x faster)
|
|
||||||
"%08x" across all 32-bit ints (4.3x/3.8x faster)
|
|
||||||
"%f" across e-10 to e+10 floats (7.3x/6.0x faster)
|
|
||||||
"%e" across e-10 to e+10 floats (8.1x/6.0x faster)
|
|
||||||
"%g" across e-10 to e+10 floats (10.0x/7.1x faster)
|
|
||||||
"%f" for values near e-300 (7.9x/6.5x faster)
|
|
||||||
"%f" for values near e+300 (10.0x/9.1x faster)
|
|
||||||
"%e" for values near e-300 (10.1x/7.0x faster)
|
|
||||||
"%e" for values near e+300 (9.2x/6.0x faster)
|
|
||||||
"%.320f" for values near e-300 (12.6x/11.2x faster)
|
|
||||||
"%a" for random values (8.6x/4.3x faster)
|
|
||||||
"%I64d" for 64-bits with 32-bit values (4.8x/3.4x faster)
|
|
||||||
"%I64d" for 64-bits > 32-bit values (4.9x/5.5x faster)
|
|
||||||
"%s%s%s" for 64 char strings (7.1x/7.3x faster)
|
|
||||||
"...512 char string..." ( 35.0x/32.5x faster!)
|
|
||||||
*/
|
|
||||||
|
|
||||||
#if defined(__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
|
|
||||||
|
|
||||||
#ifdef DQN_IMPLEMENTATION
|
#ifdef DQN_IMPLEMENTATION
|
||||||
#define STB_SPRINTF_IMPLEMENTATION
|
#define STB_SPRINTF_IMPLEMENTATION
|
||||||
#include <stdio.h> // fprintf, FILE, stdout, stderr
|
#include <stdio.h> // fprintf, FILE, stdout, stderr
|
||||||
@ -1494,6 +1465,7 @@ DQN_HEADER_COPY_PROTOTYPE(char *, Dqn_U64Str_ToStr(Dqn_u64 val, Dqn_U64Str *resu
|
|||||||
return result->str;
|
return result->str;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// @ -------------------------------------------------------------------------------------------------
|
// @ -------------------------------------------------------------------------------------------------
|
||||||
// @
|
// @
|
||||||
// @ NOTE: Logging
|
// @ NOTE: Logging
|
||||||
@ -1616,7 +1588,7 @@ DQN_HEADER_COPY_PROTOTYPE(void *, Dqn_Allocator_Allocate(Dqn_Allocator *allocato
|
|||||||
char *result = nullptr;
|
char *result = nullptr;
|
||||||
switch (allocator->type)
|
switch (allocator->type)
|
||||||
{
|
{
|
||||||
case Dqn_Allocator_Type::Null: DQN_ASSERT(DQN_INVALID_CODE_PATH);
|
case Dqn_Allocator_Type::Null:
|
||||||
default: break;
|
default: break;
|
||||||
|
|
||||||
case Dqn_Allocator_Type::Heap:
|
case Dqn_Allocator_Type::Heap:
|
||||||
@ -4369,3 +4341,8 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|||||||
------------------------------------------------------------------------------
|
------------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#if defined(_MSC_VER)
|
||||||
|
#if !defined(DQN_CRT_SECURE_NO_WARNINGS_PREVIOUSLY_DEFINED)
|
||||||
|
#undef _CRT_SECURE_NO_WARNINGS
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
Loading…
Reference in New Issue
Block a user