Fix bugs in making linked buffers
This commit is contained in:
parent
bfd3829259
commit
acdf4974f9
130
Code/Dqn.h
130
Code/Dqn.h
@ -196,8 +196,8 @@ STBSP__PUBLICDEF void STB_SPRINTF_DECORATE(set_separators)(char comma, char peri
|
|||||||
// -------------------------------------------------------------------------------------------------
|
// -------------------------------------------------------------------------------------------------
|
||||||
#define DQN_ABS(val) (((val) < 0) ? (-(val)) : (val))
|
#define DQN_ABS(val) (((val) < 0) ? (-(val)) : (val))
|
||||||
#define DQN_SQUARED(val) ((val) * (val))
|
#define DQN_SQUARED(val) ((val) * (val))
|
||||||
#define DQN_MIN(a, b) (a < b) ? (a) : (b)
|
#define DQN_MIN(a, b) ((a < b) ? (a) : (b))
|
||||||
#define DQN_MAX(a, b) (a > b) ? (a) : (b)
|
#define DQN_MAX(a, b) ((a > b) ? (a) : (b))
|
||||||
#define DQN_SWAP(a, b) \
|
#define DQN_SWAP(a, b) \
|
||||||
do \
|
do \
|
||||||
{ \
|
{ \
|
||||||
@ -573,23 +573,25 @@ struct MemArenaScopedRegion
|
|||||||
// NOTE: String Builder
|
// NOTE: String Builder
|
||||||
//
|
//
|
||||||
// -------------------------------------------------------------------------------------------------
|
// -------------------------------------------------------------------------------------------------
|
||||||
struct StringBuilderBuffer
|
struct Dqn_StringBuilderBuffer
|
||||||
{
|
{
|
||||||
char *mem;
|
char *mem;
|
||||||
MemSize size;
|
MemSize size;
|
||||||
MemSize used;
|
MemSize used;
|
||||||
StringBuilderBuffer *next;
|
Dqn_StringBuilderBuffer *next;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct StringBuilder
|
usize constexpr DQN_STRING_BUILDER_MIN_MEM_BUF_ALLOC_SIZE = DQN_KILOBYTES(4);
|
||||||
|
template <size_t N = DQN_KILOBYTES(16)>
|
||||||
|
struct Dqn_StringBuilder
|
||||||
{
|
{
|
||||||
void *(*my_calloc)(size_t bytes);
|
void *(*my_malloc)(size_t bytes) = malloc; // Set to nullptr to disable heap allocation
|
||||||
void (*my_free) (void *ptr, size_t bytes_to_free);
|
void (*my_free) (void *ptr) = free; // Set to nullptr to disable heap allocation
|
||||||
|
|
||||||
char fixed_mem[DQN_KILOBYTES(16)];
|
char fixed_mem[N];
|
||||||
MemSize fixed_mem_used;
|
MemSize fixed_mem_used;
|
||||||
StringBuilderBuffer *next_mem_buf;
|
Dqn_StringBuilderBuffer *next_mem_buf;
|
||||||
StringBuilderBuffer *last_mem_buf;
|
Dqn_StringBuilderBuffer *last_mem_buf;
|
||||||
isize string_len;
|
isize string_len;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -702,7 +704,7 @@ char *Asprintf(T *arena, char const *fmt, ...)
|
|||||||
|
|
||||||
// -------------------------------------------------------------------------------------------------
|
// -------------------------------------------------------------------------------------------------
|
||||||
//
|
//
|
||||||
// NOTE: FixedArray
|
// NOTE: Dqn_FixedArray
|
||||||
//
|
//
|
||||||
// -------------------------------------------------------------------------------------------------
|
// -------------------------------------------------------------------------------------------------
|
||||||
template <typename T> void EraseStableFromCArray(T *array, isize len, isize max, isize index)
|
template <typename T> void EraseStableFromCArray(T *array, isize len, isize max, isize index)
|
||||||
@ -715,7 +717,7 @@ template <typename T> void EraseStableFromCArray(T *array, isize len, isize max,
|
|||||||
}
|
}
|
||||||
|
|
||||||
#define FIXED_ARRAY_TEMPLATE_DECL template <typename T, int MAX_>
|
#define FIXED_ARRAY_TEMPLATE_DECL template <typename T, int MAX_>
|
||||||
FIXED_ARRAY_TEMPLATE_DECL struct FixedArray
|
FIXED_ARRAY_TEMPLATE_DECL struct Dqn_FixedArray
|
||||||
{
|
{
|
||||||
T data[MAX_];
|
T data[MAX_];
|
||||||
isize len;
|
isize len;
|
||||||
@ -729,19 +731,19 @@ FIXED_ARRAY_TEMPLATE_DECL struct FixedArray
|
|||||||
T const *operator+ (isize i) const { DQN_ASSERT_MSG(i >= 0 && i < len, "%d >= 0 && %d < %d", i, len); return data + i; }
|
T const *operator+ (isize i) const { DQN_ASSERT_MSG(i >= 0 && i < len, "%d >= 0 && %d < %d", i, len); return data + i; }
|
||||||
T *operator+ (isize i) { DQN_ASSERT_MSG(i >= 0 && i < len, "%d >= 0 && %d < %d", i, len); return data + i; }
|
T *operator+ (isize i) { DQN_ASSERT_MSG(i >= 0 && i < len, "%d >= 0 && %d < %d", i, len); return data + i; }
|
||||||
};
|
};
|
||||||
FIXED_ARRAY_TEMPLATE_DECL FixedArray<T, MAX_> FixedArray_Init (T const *item, int num) { FixedArray<T, MAX_> result = {}; FixedArray_Add(&result, item, num); return result; }
|
FIXED_ARRAY_TEMPLATE_DECL Dqn_FixedArray<T, MAX_> Dqn_FixedArray_Init (T const *item, int num) { Dqn_FixedArray<T, MAX_> result = {}; Dqn_FixedArray_Add(&result, item, num); return result; }
|
||||||
FIXED_ARRAY_TEMPLATE_DECL T *FixedArray_Add (FixedArray<T, MAX_> *a, T const *items, isize num) { DQN_ASSERT(a->len + num <= MAX_); T *result = static_cast<T *>(Dqn_MemCopy(a->data + a->len, items, sizeof(T) * num)); a->len += num; return result; }
|
FIXED_ARRAY_TEMPLATE_DECL T *Dqn_FixedArray_Add (Dqn_FixedArray<T, MAX_> *a, T const *items, isize num) { DQN_ASSERT(a->len + num <= MAX_); T *result = static_cast<T *>(Dqn_MemCopy(a->data + a->len, items, sizeof(T) * num)); a->len += num; return result; }
|
||||||
FIXED_ARRAY_TEMPLATE_DECL T *FixedArray_Add (FixedArray<T, MAX_> *a, T const item) { DQN_ASSERT(a->len < MAX_); a->data[a->len++] = item; return &a->data[a->len - 1]; }
|
FIXED_ARRAY_TEMPLATE_DECL T *Dqn_FixedArray_Add (Dqn_FixedArray<T, MAX_> *a, T const item) { DQN_ASSERT(a->len < MAX_); a->data[a->len++] = item; return &a->data[a->len - 1]; }
|
||||||
FIXED_ARRAY_TEMPLATE_DECL T *FixedArray_Make (FixedArray<T, MAX_> *a, isize num) { DQN_ASSERT(a->len + num <= MAX_); T *result = a->data + a->len; a->len += num; return result;}
|
FIXED_ARRAY_TEMPLATE_DECL T *Dqn_FixedArray_Make (Dqn_FixedArray<T, MAX_> *a, isize num) { DQN_ASSERT(a->len + num <= MAX_); T *result = a->data + a->len; a->len += num; return result;}
|
||||||
FIXED_ARRAY_TEMPLATE_DECL void FixedArray_Clear (FixedArray<T, MAX_> *a) { a->len = 0; }
|
FIXED_ARRAY_TEMPLATE_DECL void Dqn_FixedArray_Clear (Dqn_FixedArray<T, MAX_> *a) { a->len = 0; }
|
||||||
FIXED_ARRAY_TEMPLATE_DECL void FixedArray_EraseStable (FixedArray<T, MAX_> *a, isize index) { EraseStableFromCArray<T>(a->data, a->len--, a->Max(), index); }
|
FIXED_ARRAY_TEMPLATE_DECL void Dqn_FixedArray_EraseStable (Dqn_FixedArray<T, MAX_> *a, isize index) { EraseStableFromCArray<T>(a->data, a->len--, a->Max(), index); }
|
||||||
FIXED_ARRAY_TEMPLATE_DECL void FixedArray_EraseUnstable(FixedArray<T, MAX_> *a, isize index) { DQN_ASSERT(index >= 0 && index < a->len); if (--a->len == 0) return; a->data[index] = a->data[a->len]; }
|
FIXED_ARRAY_TEMPLATE_DECL void Dqn_FixedArray_EraseUnstable(Dqn_FixedArray<T, MAX_> *a, isize index) { DQN_ASSERT(index >= 0 && index < a->len); if (--a->len == 0) return; a->data[index] = a->data[a->len]; }
|
||||||
FIXED_ARRAY_TEMPLATE_DECL void FixedArray_Pop (FixedArray<T, MAX_> *a, isize num) { DQN_ASSERT(a->len - num >= 0); a->len -= num; }
|
FIXED_ARRAY_TEMPLATE_DECL void Dqn_FixedArray_Pop (Dqn_FixedArray<T, MAX_> *a, isize num) { DQN_ASSERT(a->len - num >= 0); a->len -= num; }
|
||||||
FIXED_ARRAY_TEMPLATE_DECL T *FixedArray_Peek (FixedArray<T, MAX_> *a) { T *result = (a->len == 0) ? nullptr : a->data + (a->len - 1); return result; }
|
FIXED_ARRAY_TEMPLATE_DECL T *Dqn_FixedArray_Peek (Dqn_FixedArray<T, MAX_> *a) { T *result = (a->len == 0) ? nullptr : a->data + (a->len - 1); return result; }
|
||||||
FIXED_ARRAY_TEMPLATE_DECL isize FixedArray_GetIndex (FixedArray<T, MAX_> *a, T const *entry) { isize result = a->end() - entry; return result; }
|
FIXED_ARRAY_TEMPLATE_DECL isize Dqn_FixedArray_GetIndex (Dqn_FixedArray<T, MAX_> *a, T const *entry) { isize result = a->end() - entry; return result; }
|
||||||
|
|
||||||
template <typename T, int MAX_, typename EqualityProc>
|
template <typename T, int MAX_, typename EqualityProc>
|
||||||
T *FixedArray_Find(FixedArray<T, MAX_> *a, EqualityProc IsEqual)
|
T *Dqn_FixedArray_Find(Dqn_FixedArray<T, MAX_> *a, EqualityProc IsEqual)
|
||||||
{
|
{
|
||||||
for (T &entry : (*a))
|
for (T &entry : (*a))
|
||||||
{
|
{
|
||||||
@ -751,7 +753,7 @@ T *FixedArray_Find(FixedArray<T, MAX_> *a, EqualityProc IsEqual)
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
FIXED_ARRAY_TEMPLATE_DECL T *FixedArray_Find(FixedArray<T, MAX_> *a, T *entry)
|
FIXED_ARRAY_TEMPLATE_DECL T *Dqn_FixedArray_Find(Dqn_FixedArray<T, MAX_> *a, T *entry)
|
||||||
{
|
{
|
||||||
for (T &entry : (*a))
|
for (T &entry : (*a))
|
||||||
{
|
{
|
||||||
@ -766,11 +768,11 @@ FIXED_ARRAY_TEMPLATE_DECL T *FixedArray_Find(FixedArray<T, MAX_> *a, T *entry)
|
|||||||
// NOTE: FixedStack
|
// NOTE: FixedStack
|
||||||
//
|
//
|
||||||
// -------------------------------------------------------------------------------------------------
|
// -------------------------------------------------------------------------------------------------
|
||||||
template <typename T, int MAX_> using FixedStack = FixedArray<T, MAX_>;
|
template <typename T, int MAX_> using FixedStack = Dqn_FixedArray<T, MAX_>;
|
||||||
template <typename T, int MAX_> T FixedStack_Pop (FixedStack<T, MAX_> *array) { T result = *FixedArray_Peek(array); FixedArray_Pop(array, 1); return result; }
|
template <typename T, int MAX_> T FixedStack_Pop (FixedStack<T, MAX_> *array) { T result = *Dqn_FixedArray_Peek(array); Dqn_FixedArray_Pop(array, 1); return result; }
|
||||||
template <typename T, int MAX_> T *FixedStack_Peek (FixedStack<T, MAX_> *array) { return FixedArray_Peek(array); }
|
template <typename T, int MAX_> T *FixedStack_Peek (FixedStack<T, MAX_> *array) { return Dqn_FixedArray_Peek(array); }
|
||||||
template <typename T, int MAX_> T *FixedStack_Push (FixedStack<T, MAX_> *array, T item) { return FixedArray_Add(array, item); }
|
template <typename T, int MAX_> T *FixedStack_Push (FixedStack<T, MAX_> *array, T item) { return Dqn_FixedArray_Add(array, item); }
|
||||||
template <typename T, int MAX_> void FixedStack_Clear(FixedStack<T, MAX_> *array) { FixedArray_Clear(array); }
|
template <typename T, int MAX_> void FixedStack_Clear(FixedStack<T, MAX_> *array) { Dqn_FixedArray_Clear(array); }
|
||||||
|
|
||||||
// -------------------------------------------------------------------------------------------------
|
// -------------------------------------------------------------------------------------------------
|
||||||
//
|
//
|
||||||
@ -1169,7 +1171,8 @@ MemArenaScopedRegion::~MemArenaScopedRegion()
|
|||||||
this->arena->curr_mem_block->used = this->curr_mem_block_used;
|
this->arena->curr_mem_block->used = this->curr_mem_block_used;
|
||||||
}
|
}
|
||||||
|
|
||||||
FILE_SCOPE char *StringBuilderGetWriteBufferAndIncrementUsage(StringBuilder *builder, usize size_required)
|
template <size_t N>
|
||||||
|
FILE_SCOPE char *Dqn_StringBuilder__GetWriteBufferAndUpdateUsage(Dqn_StringBuilder<N> *builder, usize size_required)
|
||||||
{
|
{
|
||||||
char *result = builder->fixed_mem + builder->fixed_mem_used;
|
char *result = builder->fixed_mem + builder->fixed_mem_used;
|
||||||
usize space = ArrayCount(builder->fixed_mem) - builder->fixed_mem_used;
|
usize space = ArrayCount(builder->fixed_mem) - builder->fixed_mem_used;
|
||||||
@ -1177,7 +1180,7 @@ FILE_SCOPE char *StringBuilderGetWriteBufferAndIncrementUsage(StringBuilder *bui
|
|||||||
|
|
||||||
if (builder->last_mem_buf)
|
if (builder->last_mem_buf)
|
||||||
{
|
{
|
||||||
StringBuilderBuffer *last_buf = builder->last_mem_buf;
|
Dqn_StringBuilderBuffer *last_buf = builder->last_mem_buf;
|
||||||
result = last_buf->mem + last_buf->used;
|
result = last_buf->mem + last_buf->used;
|
||||||
space = last_buf->size - last_buf->used;
|
space = last_buf->size - last_buf->used;
|
||||||
usage = &last_buf->used;
|
usage = &last_buf->used;
|
||||||
@ -1185,10 +1188,15 @@ FILE_SCOPE char *StringBuilderGetWriteBufferAndIncrementUsage(StringBuilder *bui
|
|||||||
|
|
||||||
if (space < size_required)
|
if (space < size_required)
|
||||||
{
|
{
|
||||||
|
DQN_ASSERT(builder->my_malloc);
|
||||||
|
if (!builder->my_malloc)
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
// NOTE: Need to allocate new buf
|
// NOTE: Need to allocate new buf
|
||||||
usize allocation_size = sizeof(*builder->last_mem_buf) + DQN_MIN(size_required, ArrayCount(builder->fixed_mem));
|
usize allocation_size = sizeof(*builder->last_mem_buf) + DQN_MAX(size_required, DQN_STRING_BUILDER_MIN_MEM_BUF_ALLOC_SIZE);
|
||||||
void *memory = builder->my_calloc(allocation_size);
|
void *memory = builder->my_malloc(allocation_size);
|
||||||
auto *new_buf = reinterpret_cast<StringBuilderBuffer *>(memory);
|
auto *new_buf = reinterpret_cast<Dqn_StringBuilderBuffer *>(memory);
|
||||||
|
*new_buf = {};
|
||||||
new_buf->mem = static_cast<char *>(memory) + sizeof(*new_buf);
|
new_buf->mem = static_cast<char *>(memory) + sizeof(*new_buf);
|
||||||
new_buf->size = allocation_size;
|
new_buf->size = allocation_size;
|
||||||
result = new_buf->mem;
|
result = new_buf->mem;
|
||||||
@ -1217,11 +1225,12 @@ FILE_SCOPE char *StringBuilderGetWriteBufferAndIncrementUsage(StringBuilder *bui
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
FILE_SCOPE void StringBuilderBuildOutput(StringBuilder const *builder, char *dest, isize dest_size)
|
template <usize N>
|
||||||
|
FILE_SCOPE void Dqn_StringBuilder__BuildOutput(Dqn_StringBuilder<N> const *builder, char *dest, isize dest_size)
|
||||||
{
|
{
|
||||||
// NOTE: No data appended to builder, just allocate am empty string. But
|
// NOTE: No data appended to builder, just allocate am empty string. But
|
||||||
// always allocate, so we avoid adding making nullptr part of the possible
|
// always allocate, so we avoid adding making nullptr part of the possible
|
||||||
// return values and makes using StringBuilder more complex.
|
// return values and makes using Dqn_StringBuilder more complex.
|
||||||
if (dest_size == 1)
|
if (dest_size == 1)
|
||||||
{
|
{
|
||||||
dest[0] = 0;
|
dest[0] = 0;
|
||||||
@ -1237,12 +1246,12 @@ FILE_SCOPE void StringBuilderBuildOutput(StringBuilder const *builder, char *des
|
|||||||
isize remaining_space = end - buf_ptr;
|
isize remaining_space = end - buf_ptr;
|
||||||
DQN_ASSERT(remaining_space >= 0);
|
DQN_ASSERT(remaining_space >= 0);
|
||||||
|
|
||||||
for (StringBuilderBuffer *string_buf = builder->next_mem_buf;
|
for (Dqn_StringBuilderBuffer *string_buf = builder->next_mem_buf;
|
||||||
string_buf && remaining_space > 0;
|
string_buf && remaining_space > 0;
|
||||||
string_buf = string_buf->next)
|
string_buf = string_buf->next)
|
||||||
{
|
{
|
||||||
usize bytes_to_copy = DQN_MIN(string_buf->used, (usize)remaining_space);
|
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, bytes_to_copy);
|
memcpy(buf_ptr, string_buf->mem, string_buf->used);
|
||||||
buf_ptr += string_buf->used;
|
buf_ptr += string_buf->used;
|
||||||
|
|
||||||
remaining_space = end - buf_ptr;
|
remaining_space = end - buf_ptr;
|
||||||
@ -1258,68 +1267,75 @@ FILE_SCOPE void StringBuilderBuildOutput(StringBuilder const *builder, char *des
|
|||||||
//
|
//
|
||||||
// -------------------------------------------------------------------------------------------------
|
// -------------------------------------------------------------------------------------------------
|
||||||
// The necessary length to build the string, it returns the length including the null-terminator
|
// The necessary length to build the string, it returns the length including the null-terminator
|
||||||
isize StringBuilder_BuildLen(StringBuilder const *builder)
|
template <usize N>
|
||||||
|
isize Dqn_StringBuilder_BuildLen(Dqn_StringBuilder<N> const *builder)
|
||||||
{
|
{
|
||||||
isize result = builder->string_len + 1;
|
isize result = builder->string_len + 1;
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
void StringBuilder_BuildInBuffer(StringBuilder const *builder, char *dest, usize dest_size)
|
template <usize N>
|
||||||
|
void Dqn_StringBuilder_BuildInBuffer(Dqn_StringBuilder<N> const *builder, char *dest, usize dest_size)
|
||||||
{
|
{
|
||||||
StringBuilderBuildOutput(builder, dest, dest_size);
|
Dqn_StringBuilder__BuildOutput(builder, dest, dest_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
// len: Return the length of the allocated string including the null-terminator
|
// len: Return the length of the allocated string including the null-terminator
|
||||||
char *StringBuilder_BuildFromMalloc(StringBuilder *builder, isize *len = nullptr)
|
template <usize N>
|
||||||
|
char *Dqn_StringBuilder_BuildFromMalloc(Dqn_StringBuilder<N> *builder, isize *len = nullptr)
|
||||||
{
|
{
|
||||||
isize len_w_null_terminator = StringBuilder_BuildLen(builder);
|
isize len_w_null_terminator = Dqn_StringBuilder_BuildLen(builder);
|
||||||
auto *result = static_cast<char *>(malloc(len_w_null_terminator));
|
auto *result = static_cast<char *>(malloc(len_w_null_terminator));
|
||||||
if (len) *len = len_w_null_terminator;
|
if (len) *len = len_w_null_terminator;
|
||||||
StringBuilderBuildOutput(builder, result, len_w_null_terminator);
|
Dqn_StringBuilder__BuildOutput(builder, result, len_w_null_terminator);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
char *StringBuilder_BuildFromArena(StringBuilder *builder, MemArena *arena, isize *len = nullptr)
|
template <usize N>
|
||||||
|
char *Dqn_StringBuilder_BuildFromArena(Dqn_StringBuilder<N> *builder, MemArena *arena, isize *len = nullptr)
|
||||||
{
|
{
|
||||||
isize len_w_null_terminator = StringBuilder_BuildLen(builder);
|
isize len_w_null_terminator = Dqn_StringBuilder_BuildLen(builder);
|
||||||
char *result = MEM_ARENA_ALLOC_ARRAY(arena, char, len_w_null_terminator);
|
char *result = MEM_ARENA_ALLOC_ARRAY(arena, char, len_w_null_terminator);
|
||||||
if (len) *len = len_w_null_terminator;
|
if (len) *len = len_w_null_terminator;
|
||||||
StringBuilderBuildOutput(builder, result, len_w_null_terminator);
|
Dqn_StringBuilder__BuildOutput(builder, result, len_w_null_terminator);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
void StringBuilder_VFmtAppend(StringBuilder *builder, char const *fmt, va_list va)
|
template <usize N>
|
||||||
|
void Dqn_StringBuilder_VFmtAppend(Dqn_StringBuilder<N> *builder, char const *fmt, va_list va)
|
||||||
{
|
{
|
||||||
if (!fmt) return;
|
if (!fmt) return;
|
||||||
isize require = stbsp_vsnprintf(nullptr, 0, fmt, va) + 1;
|
isize require = stbsp_vsnprintf(nullptr, 0, fmt, va) + 1;
|
||||||
char *buf = StringBuilderGetWriteBufferAndIncrementUsage(builder, require);
|
char *buf = Dqn_StringBuilder__GetWriteBufferAndUpdateUsage(builder, require);
|
||||||
stbsp_vsnprintf(buf, static_cast<int>(require), fmt, va);
|
stbsp_vsnprintf(buf, static_cast<int>(require), fmt, va);
|
||||||
builder->string_len += (require - 1); // -1 to exclude null terminator
|
builder->string_len += (require - 1); // -1 to exclude null terminator
|
||||||
}
|
}
|
||||||
|
|
||||||
void StringBuilder_FmtAppend(StringBuilder *builder, char const *fmt, ...)
|
template <usize 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);
|
||||||
StringBuilder_VFmtAppend(builder, fmt, va);
|
Dqn_StringBuilder_VFmtAppend(builder, fmt, va);
|
||||||
va_end(va);
|
va_end(va);
|
||||||
}
|
}
|
||||||
|
|
||||||
void StringBuilder_Append(StringBuilder *builder, char const *str, isize len = -1)
|
template <usize N>
|
||||||
|
void Dqn_StringBuilder_Append(Dqn_StringBuilder<N> *builder, char const *str, isize len = -1)
|
||||||
{
|
{
|
||||||
if (!str) return;
|
if (!str) return;
|
||||||
if (len == -1) len = (isize)strlen(str);
|
if (len == -1) len = (isize)strlen(str);
|
||||||
isize len_w_null_terminator = len + 1;
|
isize len_w_null_terminator = len + 1;
|
||||||
char *buf = StringBuilderGetWriteBufferAndIncrementUsage(builder, len_w_null_terminator);
|
char *buf = Dqn_StringBuilder__GetWriteBufferAndUpdateUsage(builder, len_w_null_terminator);
|
||||||
Dqn_MemCopy(buf, str, len);
|
Dqn_MemCopy(buf, str, len);
|
||||||
builder->string_len += len;
|
builder->string_len += len;
|
||||||
buf[len] = 0;
|
buf[len] = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <usize N>
|
||||||
void StringBuilder_AppendChar(StringBuilder *builder, char ch)
|
void Dqn_StringBuilder_AppendChar(Dqn_StringBuilder<N> *builder, char ch)
|
||||||
{
|
{
|
||||||
char *buf = StringBuilderGetWriteBufferAndIncrementUsage(builder, 1 + 1 /*null terminator*/);
|
char *buf = Dqn_StringBuilder__GetWriteBufferAndUpdateUsage(builder, 1 + 1 /*null terminator*/);
|
||||||
*buf++ = ch;
|
*buf++ = ch;
|
||||||
builder->string_len++;
|
builder->string_len++;
|
||||||
buf[1] = 0;
|
buf[1] = 0;
|
||||||
|
@ -103,23 +103,23 @@ void TestState_PrintResult(TestState const *result)
|
|||||||
|
|
||||||
FILE_SCOPE void UnitTests()
|
FILE_SCOPE void UnitTests()
|
||||||
{
|
{
|
||||||
// ---------------------------------------------------------------------------------------------
|
|
||||||
//
|
|
||||||
// NOTE: StringBuilder
|
|
||||||
//
|
|
||||||
// ---------------------------------------------------------------------------------------------
|
|
||||||
TestingState testing_state = {};
|
TestingState testing_state = {};
|
||||||
|
// ---------------------------------------------------------------------------------------------
|
||||||
|
//
|
||||||
|
// NOTE: Dqn_StringBuilder
|
||||||
|
//
|
||||||
|
// ---------------------------------------------------------------------------------------------
|
||||||
{
|
{
|
||||||
TEST_DECLARE_GROUP_SCOPED(testing_state, "StringBuilder");
|
TEST_DECLARE_GROUP_SCOPED(testing_state, "Dqn_StringBuilder");
|
||||||
// NOTE: StringBuilder_Append
|
// NOTE: Dqn_StringBuilder_Append
|
||||||
{
|
{
|
||||||
{
|
{
|
||||||
TEST_START_SCOPE(testing_state, "Append variable length strings and build using malloc");
|
TEST_START_SCOPE(testing_state, "Append variable length strings and build using malloc");
|
||||||
StringBuilder builder = {};
|
Dqn_StringBuilder<> builder = {};
|
||||||
StringBuilder_Append(&builder, "Abc", 1);
|
Dqn_StringBuilder_Append(&builder, "Abc", 1);
|
||||||
StringBuilder_Append(&builder, "cd");
|
Dqn_StringBuilder_Append(&builder, "cd");
|
||||||
isize len = 0;
|
isize len = 0;
|
||||||
char *result = StringBuilder_BuildFromMalloc(&builder, &len);
|
char *result = Dqn_StringBuilder_BuildFromMalloc(&builder, &len);
|
||||||
DQN_DEFER { free(result); };
|
DQN_DEFER { free(result); };
|
||||||
|
|
||||||
char constexpr EXPECT_STR[] = "Acd";
|
char constexpr EXPECT_STR[] = "Acd";
|
||||||
@ -129,11 +129,11 @@ FILE_SCOPE void UnitTests()
|
|||||||
|
|
||||||
{
|
{
|
||||||
TEST_START_SCOPE(testing_state, "Append empty string and build using malloc");
|
TEST_START_SCOPE(testing_state, "Append empty string and build using malloc");
|
||||||
StringBuilder builder = {};
|
Dqn_StringBuilder<> builder = {};
|
||||||
StringBuilder_Append(&builder, "");
|
Dqn_StringBuilder_Append(&builder, "");
|
||||||
StringBuilder_Append(&builder, "");
|
Dqn_StringBuilder_Append(&builder, "");
|
||||||
isize len = 0;
|
isize len = 0;
|
||||||
char *result = StringBuilder_BuildFromMalloc(&builder, &len);
|
char *result = Dqn_StringBuilder_BuildFromMalloc(&builder, &len);
|
||||||
DQN_DEFER { free(result); };
|
DQN_DEFER { free(result); };
|
||||||
|
|
||||||
char constexpr EXPECT_STR[] = "";
|
char constexpr EXPECT_STR[] = "";
|
||||||
@ -143,11 +143,11 @@ FILE_SCOPE void UnitTests()
|
|||||||
|
|
||||||
{
|
{
|
||||||
TEST_START_SCOPE(testing_state, "Append empty string onto string and build using malloc");
|
TEST_START_SCOPE(testing_state, "Append empty string onto string and build using malloc");
|
||||||
StringBuilder builder = {};
|
Dqn_StringBuilder<> builder = {};
|
||||||
StringBuilder_Append(&builder, "Acd");
|
Dqn_StringBuilder_Append(&builder, "Acd");
|
||||||
StringBuilder_Append(&builder, "");
|
Dqn_StringBuilder_Append(&builder, "");
|
||||||
isize len = 0;
|
isize len = 0;
|
||||||
char *result = StringBuilder_BuildFromMalloc(&builder, &len);
|
char *result = Dqn_StringBuilder_BuildFromMalloc(&builder, &len);
|
||||||
DQN_DEFER { free(result); };
|
DQN_DEFER { free(result); };
|
||||||
|
|
||||||
char constexpr EXPECT_STR[] = "Acd";
|
char constexpr EXPECT_STR[] = "Acd";
|
||||||
@ -157,27 +157,42 @@ FILE_SCOPE void UnitTests()
|
|||||||
|
|
||||||
{
|
{
|
||||||
TEST_START_SCOPE(testing_state, "Append nullptr and build using malloc");
|
TEST_START_SCOPE(testing_state, "Append nullptr and build using malloc");
|
||||||
StringBuilder builder = {};
|
Dqn_StringBuilder<> builder = {};
|
||||||
StringBuilder_Append(&builder, nullptr, 5);
|
Dqn_StringBuilder_Append(&builder, nullptr, 5);
|
||||||
isize len = 0;
|
isize len = 0;
|
||||||
char *result = StringBuilder_BuildFromMalloc(&builder, &len);
|
char *result = Dqn_StringBuilder_BuildFromMalloc(&builder, &len);
|
||||||
DQN_DEFER { free(result); };
|
DQN_DEFER { free(result); };
|
||||||
|
|
||||||
char constexpr EXPECT_STR[] = "";
|
char constexpr EXPECT_STR[] = "";
|
||||||
TEST_EXPECT_MSG(testing_state, len == CharCountI(EXPECT_STR) + 1 /*null terminator*/, "len: %zd", len);
|
TEST_EXPECT_MSG(testing_state, len == CharCountI(EXPECT_STR) + 1 /*null terminator*/, "len: %zd", len);
|
||||||
TEST_EXPECT_MSG(testing_state, strncmp(result, EXPECT_STR, len) == 0, "result: %s", result);
|
TEST_EXPECT_MSG(testing_state, strncmp(result, EXPECT_STR, len) == 0, "result: %s", result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
TEST_START_SCOPE(testing_state, "Append and require new linked buffer and build using malloc");
|
||||||
|
Dqn_StringBuilder<2> builder = {};
|
||||||
|
Dqn_StringBuilder_Append(&builder, "A");
|
||||||
|
Dqn_StringBuilder_Append(&builder, "z"); // Should force a new memory block
|
||||||
|
Dqn_StringBuilder_Append(&builder, "tec");
|
||||||
|
isize len = 0;
|
||||||
|
char *result = Dqn_StringBuilder_BuildFromMalloc(&builder, &len);
|
||||||
|
DQN_DEFER { free(result); };
|
||||||
|
|
||||||
|
char constexpr EXPECT_STR[] = "Aztec";
|
||||||
|
TEST_EXPECT_MSG(testing_state, len == CharCountI(EXPECT_STR) + 1 /*null terminator*/, "len: %zd", len);
|
||||||
|
TEST_EXPECT_MSG(testing_state, strncmp(result, EXPECT_STR, len) == 0, "result: %s", result);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// NOTE: StringBuilder_AppendChar
|
// NOTE: Dqn_StringBuilder_AppendChar
|
||||||
{
|
{
|
||||||
TEST_START_SCOPE(testing_state, "Append char and build using malloc");
|
TEST_START_SCOPE(testing_state, "Append char and build using malloc");
|
||||||
StringBuilder builder = {};
|
Dqn_StringBuilder<> builder = {};
|
||||||
StringBuilder_AppendChar(&builder, 'a');
|
Dqn_StringBuilder_AppendChar(&builder, 'a');
|
||||||
StringBuilder_AppendChar(&builder, 'b');
|
Dqn_StringBuilder_AppendChar(&builder, 'b');
|
||||||
isize len = 0;
|
isize len = 0;
|
||||||
char *result = StringBuilder_BuildFromMalloc(&builder, &len);
|
char *result = Dqn_StringBuilder_BuildFromMalloc(&builder, &len);
|
||||||
DQN_DEFER { free(result); };
|
DQN_DEFER { free(result); };
|
||||||
|
|
||||||
char constexpr EXPECT_STR[] = "ab";
|
char constexpr EXPECT_STR[] = "ab";
|
||||||
@ -185,79 +200,94 @@ FILE_SCOPE void UnitTests()
|
|||||||
TEST_EXPECT_MSG(testing_state, strncmp(result, EXPECT_STR, len) == 0, "result: %s", result);
|
TEST_EXPECT_MSG(testing_state, strncmp(result, EXPECT_STR, len) == 0, "result: %s", result);
|
||||||
}
|
}
|
||||||
|
|
||||||
// NOTE: StringBuilder_FmtAppend
|
// NOTE: Dqn_StringBuilder_FmtAppend
|
||||||
|
{
|
||||||
{
|
{
|
||||||
TEST_START_SCOPE(testing_state, "Append format string and build using malloc");
|
TEST_START_SCOPE(testing_state, "Append format string and build using malloc");
|
||||||
StringBuilder builder = {};
|
Dqn_StringBuilder<> builder = {};
|
||||||
StringBuilder_FmtAppend(&builder, "Number: %d, String: %s, ", 4, "Hello Sailor");
|
Dqn_StringBuilder_FmtAppend(&builder, "Number: %d, String: %s, ", 4, "Hello Sailor");
|
||||||
StringBuilder_FmtAppend(&builder, "Extra Stuff");
|
Dqn_StringBuilder_FmtAppend(&builder, "Extra Stuff");
|
||||||
isize len = 0;
|
isize len = 0;
|
||||||
char *result = StringBuilder_BuildFromMalloc(&builder, &len);
|
char *result = Dqn_StringBuilder_BuildFromMalloc(&builder, &len);
|
||||||
DQN_DEFER { free(result); };
|
DQN_DEFER { free(result); };
|
||||||
|
|
||||||
char constexpr EXPECT_STR[] = "Number: 4, String: Hello Sailor, Extra Stuff";
|
char constexpr EXPECT_STR[] = "Number: 4, String: Hello Sailor, Extra Stuff";
|
||||||
TEST_EXPECT_MSG(testing_state, len == CharCountI(EXPECT_STR) + 1 /*null terminator*/, "len: %zd", len);
|
TEST_EXPECT_MSG(testing_state, len == CharCountI(EXPECT_STR) + 1 /*null terminator*/, "len: %zd", len);
|
||||||
TEST_EXPECT_MSG(testing_state, strncmp(result, EXPECT_STR, len) == 0, "result: %s", result);
|
TEST_EXPECT_MSG(testing_state, strncmp(result, EXPECT_STR, len) == 0, "result: %s", result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
TEST_START_SCOPE(testing_state, "Append nullptr format string and build using malloc");
|
||||||
|
Dqn_StringBuilder<> builder = {};
|
||||||
|
Dqn_StringBuilder_FmtAppend(&builder, nullptr);
|
||||||
|
isize len = 0;
|
||||||
|
char *result = Dqn_StringBuilder_BuildFromMalloc(&builder, &len);
|
||||||
|
DQN_DEFER { free(result); };
|
||||||
|
|
||||||
|
char constexpr EXPECT_STR[] = "";
|
||||||
|
TEST_EXPECT_MSG(testing_state, len == CharCountI(EXPECT_STR) + 1 /*null terminator*/, "len: %zd", len);
|
||||||
|
TEST_EXPECT_MSG(testing_state, strncmp(result, EXPECT_STR, len) == 0, "result: %s", result);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------------------------
|
||||||
//
|
//
|
||||||
// NOTE: FixedArray
|
// NOTE: Dqn_FixedArray
|
||||||
//
|
//
|
||||||
// ---------------------------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------------------------
|
||||||
{
|
{
|
||||||
TEST_DECLARE_GROUP_SCOPED(testing_state, "FixedArray");
|
TEST_DECLARE_GROUP_SCOPED(testing_state, "Dqn_FixedArray");
|
||||||
// NOTE: FixedArray_Init
|
// NOTE: Dqn_FixedArray_Init
|
||||||
{
|
{
|
||||||
TEST_START_SCOPE(testing_state, "Initialise from raw array");
|
TEST_START_SCOPE(testing_state, "Initialise from raw array");
|
||||||
int raw_array[] = {1, 2};
|
int raw_array[] = {1, 2};
|
||||||
auto array = FixedArray_Init<int, 4>(raw_array, (int)ArrayCount(raw_array));
|
auto array = Dqn_FixedArray_Init<int, 4>(raw_array, (int)ArrayCount(raw_array));
|
||||||
TEST_EXPECT(testing_state, array.len == 2);
|
TEST_EXPECT(testing_state, array.len == 2);
|
||||||
TEST_EXPECT(testing_state, array[0] == 1);
|
TEST_EXPECT(testing_state, array[0] == 1);
|
||||||
TEST_EXPECT(testing_state, array[1] == 2);
|
TEST_EXPECT(testing_state, array[1] == 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
// NOTE: FixedArray_EraseStable
|
// NOTE: Dqn_FixedArray_EraseStable
|
||||||
{
|
{
|
||||||
TEST_START_SCOPE(testing_state, "Erase stable 1 element from array");
|
TEST_START_SCOPE(testing_state, "Erase stable 1 element from array");
|
||||||
int raw_array[] = {1, 2, 3};
|
int raw_array[] = {1, 2, 3};
|
||||||
auto array = FixedArray_Init<int, 4>(raw_array, (int)ArrayCount(raw_array));
|
auto array = Dqn_FixedArray_Init<int, 4>(raw_array, (int)ArrayCount(raw_array));
|
||||||
FixedArray_EraseStable(&array, 1);
|
Dqn_FixedArray_EraseStable(&array, 1);
|
||||||
TEST_EXPECT(testing_state, array.len == 2);
|
TEST_EXPECT(testing_state, array.len == 2);
|
||||||
TEST_EXPECT(testing_state, array[0] == 1);
|
TEST_EXPECT(testing_state, array[0] == 1);
|
||||||
TEST_EXPECT(testing_state, array[1] == 3);
|
TEST_EXPECT(testing_state, array[1] == 3);
|
||||||
}
|
}
|
||||||
|
|
||||||
// NOTE: FixedArray_EraseUnstable
|
// NOTE: Dqn_FixedArray_EraseUnstable
|
||||||
{
|
{
|
||||||
TEST_START_SCOPE(testing_state, "Erase unstable 1 element from array");
|
TEST_START_SCOPE(testing_state, "Erase unstable 1 element from array");
|
||||||
int raw_array[] = {1, 2, 3};
|
int raw_array[] = {1, 2, 3};
|
||||||
auto array = FixedArray_Init<int, 4>(raw_array, (int)ArrayCount(raw_array));
|
auto array = Dqn_FixedArray_Init<int, 4>(raw_array, (int)ArrayCount(raw_array));
|
||||||
FixedArray_EraseUnstable(&array, 0);
|
Dqn_FixedArray_EraseUnstable(&array, 0);
|
||||||
TEST_EXPECT(testing_state, array.len == 2);
|
TEST_EXPECT(testing_state, array.len == 2);
|
||||||
TEST_EXPECT(testing_state, array[0] == 3);
|
TEST_EXPECT(testing_state, array[0] == 3);
|
||||||
TEST_EXPECT(testing_state, array[1] == 2);
|
TEST_EXPECT(testing_state, array[1] == 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
// NOTE: FixedArray_Add
|
// NOTE: Dqn_FixedArray_Add
|
||||||
{
|
{
|
||||||
TEST_START_SCOPE(testing_state, "Add 1 element to array");
|
TEST_START_SCOPE(testing_state, "Add 1 element to array");
|
||||||
int const ITEM = 2;
|
int const ITEM = 2;
|
||||||
int raw_array[] = {1};
|
int raw_array[] = {1};
|
||||||
auto array = FixedArray_Init<int, 4>(raw_array, (int)ArrayCount(raw_array));
|
auto array = Dqn_FixedArray_Init<int, 4>(raw_array, (int)ArrayCount(raw_array));
|
||||||
FixedArray_Add(&array, ITEM);
|
Dqn_FixedArray_Add(&array, ITEM);
|
||||||
TEST_EXPECT(testing_state, array.len == 2);
|
TEST_EXPECT(testing_state, array.len == 2);
|
||||||
TEST_EXPECT(testing_state, array[0] == 1);
|
TEST_EXPECT(testing_state, array[0] == 1);
|
||||||
TEST_EXPECT(testing_state, array[1] == ITEM);
|
TEST_EXPECT(testing_state, array[1] == ITEM);
|
||||||
}
|
}
|
||||||
|
|
||||||
// NOTE: FixedArray_Clear
|
// NOTE: Dqn_FixedArray_Clear
|
||||||
{
|
{
|
||||||
TEST_START_SCOPE(testing_state, "Clear array");
|
TEST_START_SCOPE(testing_state, "Clear array");
|
||||||
int raw_array[] = {1};
|
int raw_array[] = {1};
|
||||||
auto array = FixedArray_Init<int, 4>(raw_array, (int)ArrayCount(raw_array));
|
auto array = Dqn_FixedArray_Init<int, 4>(raw_array, (int)ArrayCount(raw_array));
|
||||||
FixedArray_Clear(&array);
|
Dqn_FixedArray_Clear(&array);
|
||||||
TEST_EXPECT(testing_state, array.len == 0);
|
TEST_EXPECT(testing_state, array.len == 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user