Add unit tests for allocators/arrays

This commit is contained in:
doyle 2019-09-19 21:49:11 +10:00
parent b34226498c
commit d31c63cbb7
4 changed files with 488 additions and 68 deletions

View File

@ -14,5 +14,5 @@ REM Tp Treat header file as CPP source file
cl /MT /EHa /GR- /Od /Oi /Z7 /W4 /WX /wd4201 /D DQN_HEADER_IMPLEMENTATION /Tp ../Code/DqnHeader.h /link /nologo cl /MT /EHa /GR- /Od /Oi /Z7 /W4 /WX /wd4201 /D DQN_HEADER_IMPLEMENTATION /Tp ../Code/DqnHeader.h /link /nologo
DqnHeader.exe ..\Code\Dqn.h > ..\Code\DqnHeader_Generated.h DqnHeader.exe ..\Code\Dqn.h > ..\Code\DqnHeader_Generated.h
cl /MT /EHa /GR- /Od /Oi /Z7 /W4 /WX /wd4201 /D DQN_IMPLEMENTATION ../Code/Dqn_UnitTests.cpp /link /nologo cl /MT /EHa /GR- /Od /Oi /Z7 /W4 /WX /wd4201 ../Code/Dqn_UnitTests.cpp /link /nologo
popd popd

View File

@ -1,3 +1,7 @@
// #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
#if defined(DQN_IMPLEMENTATION) #if defined(DQN_IMPLEMENTATION)
#define STB_SPRINTF_IMPLEMENTATION #define STB_SPRINTF_IMPLEMENTATION
#endif #endif
@ -198,6 +202,7 @@ STBSP__PUBLICDEF void STB_SPRINTF_DECORATE(set_separators)(char comma, char peri
// @ NOTE: Typedefs, Macros, Utils // @ NOTE: Typedefs, Macros, Utils
// @ // @
// @ ------------------------------------------------------------------------------------------------- // @ -------------------------------------------------------------------------------------------------
#define DQN_CAST(val) (val)
#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))
@ -606,12 +611,12 @@ struct Dqn_MemArenaScopedRegion
#define DQN_DEBUG_PARAMS #define DQN_DEBUG_PARAMS
#endif #endif
#define DQN_MEM_ARENA_ALLOC(arena, size) Dqn_MemArena_Alloc(arena, size DQN_DEBUG_PARAMS); #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_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_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); #define DQN_MEM_ARENA_RESERVE(arena, size) Dqn_MemArena_Reserve(arena, size DQN_DEBUG_PARAMS)
#define DQN_MEM_ARENA_RESERVE_FROM(arena, src, size) Dqn_MemArena_ReserveFrom(arena, src, size DQN_DEBUG_PARAMS); #define DQN_MEM_ARENA_RESERVE_FROM(arena, src, size) Dqn_MemArena_ReserveFrom(arena, src, size DQN_DEBUG_PARAMS)
#define DQN_MEM_ARENA_CLEAR_USED(arena) Dqn_MemArena_ClearUsed(arena DQN_DEBUG_PARAMS); #define DQN_MEM_ARENA_CLEAR_USED(arena) Dqn_MemArena_ClearUsed(arena DQN_DEBUG_PARAMS)
#define DQN_MEM_ARENA_FREE(arena) Dqn_MemArena_Free #define DQN_MEM_ARENA_FREE(arena) Dqn_MemArena_Free
DQN_HEADER_COPY_END DQN_HEADER_COPY_END
@ -1057,17 +1062,36 @@ template <typename T, int MAX_> T *Dqn_FixedStack_Push (Dqn_FixedStack<T, MAX_
template <typename T, int MAX_> void Dqn_FixedStack_Clear(Dqn_FixedStack<T, MAX_> *array) { Dqn_FixedArray_Clear(array); } template <typename T, int MAX_> void Dqn_FixedStack_Clear(Dqn_FixedStack<T, MAX_> *array) { Dqn_FixedArray_Clear(array); }
DQN_HEADER_COPY_END DQN_HEADER_COPY_END
DQN_HEADER_COPY_BEGIN
enum struct Dqn_Allocator_Type
{
Heap, // Malloc, realloc, free
XHeap, // Malloc realloc, free, crash on failure
Arena,
NullAllocator,
};
struct Dqn_Allocator
{
Dqn_Allocator_Type type;
void *data;
};
DQN_HEADER_COPY_END
// @ ------------------------------------------------------------------------------------------------- // @ -------------------------------------------------------------------------------------------------
// @ // @
// @ NOTE: Dqn_StaticArray // @ NOTE: Dqn_Array
// @ // @
// @ ------------------------------------------------------------------------------------------------- // @ -------------------------------------------------------------------------------------------------
DQN_HEADER_COPY_BEGIN DQN_HEADER_COPY_BEGIN
template <typename T> struct Dqn_StaticArray // TODO(doyle): Make this either initialised from memory or dynamically allocating
template <typename T> struct Dqn_Array
{ {
Dqn_Allocator allocator;
T *data; T *data;
Dqn_isize len; Dqn_isize len;
Dqn_isize max; 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 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 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 *begin () const { return data; }
@ -1079,15 +1103,101 @@ template <typename T> struct Dqn_StaticArray
}; };
DQN_HEADER_COPY_END DQN_HEADER_COPY_END
DQN_HEADER_COPY_PROTOTYPE(template <typename T> Dqn_StaticArray<T> , Dqn_StaticArray_InitMemory (T *memory, Dqn_isize max, Dqn_isize len = 0)) { Dqn_StaticArray<T> result = {}; result.data = memory; result.len = len; result.max = max; return result; } DQN_HEADER_COPY_PROTOTYPE(template <typename T> Dqn_Array<T>, Dqn_Array_InitMemory(T *memory, Dqn_isize max, Dqn_isize len = 0))
DQN_HEADER_COPY_PROTOTYPE(template <typename T> T *, Dqn_StaticArray_Add (Dqn_StaticArray<T> *a, T const *items, Dqn_isize num)) { DQN_ASSERT(a->len + num <= a->max); T *result = static_cast<T *>(Dqn_MemCopy(a->data + a->len, items, sizeof(T) * num)); a->len += num; return result; } {
DQN_HEADER_COPY_PROTOTYPE(template <typename T> T *, Dqn_StaticArray_Add (Dqn_StaticArray<T> *a, T const item)) { DQN_ASSERT(a->len < a->max); a->data[a->len++] = item; return &a->data[a->len - 1]; } Dqn_Array<T> result = {};
DQN_HEADER_COPY_PROTOTYPE(template <typename T> T *, Dqn_StaticArray_Make (Dqn_StaticArray<T> *a, Dqn_isize num)) { DQN_ASSERT(a->len + num <= a->max); T *result = a->data + a->len; a->len += num; return result;} result.allocator = Dqn_Allocator_NullAllocator();
DQN_HEADER_COPY_PROTOTYPE(template <typename T> void , Dqn_StaticArray_Clear (Dqn_StaticArray<T> *a)) { a->len = 0; } result.data = memory;
DQN_HEADER_COPY_PROTOTYPE(template <typename T> void , Dqn_StaticArray_EraseStable (Dqn_StaticArray<T> *a, Dqn_isize index)) { Dqn__EraseStableFromCArray<T>(a->data, a->len--, a->max, index); } result.len = len;
DQN_HEADER_COPY_PROTOTYPE(template <typename T> void , Dqn_StaticArray_EraseUnstable(Dqn_StaticArray<T> *a, Dqn_isize index)) { DQN_ASSERT(index >= 0 && index < a->len); if (--a->len == 0) return; a->data[index] = a->data[a->len]; } result.max = max;
DQN_HEADER_COPY_PROTOTYPE(template <typename T> void , Dqn_StaticArray_Pop (Dqn_StaticArray<T> *a, Dqn_isize num)) { DQN_ASSERT(a->len - num >= 0); a->len -= num; } return result;
DQN_HEADER_COPY_PROTOTYPE(template <typename T> T *, Dqn_StaticArray_Peek (Dqn_StaticArray<T> *a)) { T *result = (a->len == 0) ? nullptr : a->data + (a->len - 1); 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;
T *result = static_cast<T *>(Dqn_MemCopy(a->data + a->len, items, sizeof(T) * num));
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;
}
// @ ------------------------------------------------------------------------------------------------- // @ -------------------------------------------------------------------------------------------------
// @ // @
@ -1163,9 +1273,11 @@ struct Dqn_U64Str
int len; int len;
}; };
DQN_HEADER_COPY_END DQN_HEADER_COPY_END
#undef _CRT_SECURE_NO_WARNINGS
#endif // DQN_H #endif // DQN_H
#ifdef DQN_IMPLEMENTATION #ifdef DQN_IMPLEMENTATION
#define _CRT_SECURE_NO_WARNINGS
#include <math.h> #include <math.h>
#include <memory.h> #include <memory.h>
#include <stdio.h> #include <stdio.h>
@ -1451,6 +1563,114 @@ Dqn_MemArenaScopedRegion::~Dqn_MemArenaScopedRegion()
this->arena->curr_mem_block->used = this->curr_mem_block_used; this->arena->curr_mem_block->used = this->curr_mem_block_used;
} }
// @ -------------------------------------------------------------------------------------------------
// @
// @ NOTE: Dqn_Allocator
// @
// @ -------------------------------------------------------------------------------------------------
DQN_HEADER_COPY_PROTOTYPE(Dqn_Allocator, Dqn_Allocator_NullAllocator())
{
Dqn_Allocator result = {};
result.type = Dqn_Allocator_Type::NullAllocator;
return result;
}
DQN_HEADER_COPY_PROTOTYPE(Dqn_Allocator, Dqn_Allocator_HeapAllocator())
{
Dqn_Allocator result = {};
result.type = Dqn_Allocator_Type::Heap;
return result;
}
DQN_HEADER_COPY_PROTOTYPE(Dqn_Allocator, Dqn_Allocator_XHeapAllocator())
{
Dqn_Allocator result = {};
result.type = Dqn_Allocator_Type::XHeap;
return result;
}
DQN_HEADER_COPY_PROTOTYPE(Dqn_Allocator, Dqn_Allocator_ArenaAllocator(Dqn_MemArena *arena))
{
Dqn_Allocator result = {};
result.type = Dqn_Allocator_Type::Arena;
result.data = arena;
return result;
}
DQN_HEADER_COPY_PROTOTYPE(void *, Dqn_Allocator_Allocate(Dqn_Allocator *allocator, Dqn_usize size))
{
void *result = nullptr;
switch (allocator->type)
{
default: break;
case Dqn_Allocator_Type::Heap:
case Dqn_Allocator_Type::XHeap:
{
result = malloc(size);
if (!result && allocator->type == Dqn_Allocator_Type::XHeap)
DQN_ASSERT(result);
}
break;
case Dqn_Allocator_Type::Arena:
{
auto *arena = static_cast<Dqn_MemArena *>(allocator->data);
result = DQN_MEM_ARENA_ALLOC(arena, size);
}
break;
}
return result;
}
DQN_HEADER_COPY_PROTOTYPE(void *, Dqn_Allocator_Realloc(Dqn_Allocator *allocator, void *old_ptr, Dqn_isize old_size, Dqn_isize new_size))
{
void *result = nullptr;
switch (allocator->type)
{
default: break;
case Dqn_Allocator_Type::Heap:
case Dqn_Allocator_Type::XHeap:
{
result = realloc(old_ptr, new_size);
if (!result && allocator->type == Dqn_Allocator_Type::XHeap)
DQN_ASSERT(result);
}
break;
case Dqn_Allocator_Type::Arena:
{
auto *arena = static_cast<Dqn_MemArena *>(allocator->data);
if (DQN_MEM_ARENA_RESERVE(arena, new_size))
{
result = DQN_MEM_ARENA_ALLOC(arena, new_size);
if (result) memcpy(result, old_ptr, old_size);
}
}
break;
}
return result;
}
DQN_HEADER_COPY_PROTOTYPE(void, Dqn_Allocator_Free(Dqn_Allocator *allocator, void *ptr))
{
switch (allocator->type)
{
default: break;
case Dqn_Allocator_Type::Heap:
case Dqn_Allocator_Type::XHeap:
{
free(ptr);
}
break;
case Dqn_Allocator_Type::Arena:
break;
}
}
// @ ------------------------------------------------------------------------------------------------- // @ -------------------------------------------------------------------------------------------------
// @ // @
// @ NOTE: Vectors // @ NOTE: Vectors
@ -1842,8 +2062,9 @@ DQN_HEADER_COPY_PROTOTYPE(Dqn_b32, Dqn_Char_IsWhitespace(char ch))
// @ NOTE: String Helpers // @ NOTE: String Helpers
// @ // @
// @ ------------------------------------------------------------------------------------------------- // @ -------------------------------------------------------------------------------------------------
DQN_HEADER_COPY_PROTOTYPE(Dqn_b32, Dqn_Str_Equals(char const *a, Dqn_isize a_len, char const *b, Dqn_isize b_len = -1)) 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))
{ {
if (a_len == -1) a_len = strlen(a);
if (b_len == -1) b_len = strlen(b); if (b_len == -1) b_len = strlen(b);
if (a_len != b_len) return false; if (a_len != b_len) return false;
return (strncmp(a, b, a_len) == 0); return (strncmp(a, b, a_len) == 0);
@ -2081,6 +2302,7 @@ DQN_HEADER_COPY_PROTOTYPE(char *, Dqn_File_ReadWithArena(Dqn_MemArena *arena, ch
if (file_size) *file_size = file_size_; if (file_size) *file_size = file_size_;
return result; return result;
} }
#undef _CRT_SECURE_NO_WARNINGS
#endif // DQN_IMPLEMENTATION #endif // DQN_IMPLEMENTATION
#ifdef STB_SPRINTF_IMPLEMENTATION #ifdef STB_SPRINTF_IMPLEMENTATION

View File

@ -252,12 +252,12 @@ struct Dqn_MemArenaScopedRegion
#define DQN_DEBUG_PARAMS #define DQN_DEBUG_PARAMS
#endif #endif
#define DQN_MEM_ARENA_ALLOC(arena, size) Dqn_MemArena_Alloc(arena, size DQN_DEBUG_PARAMS); #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_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_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); #define DQN_MEM_ARENA_RESERVE(arena, size) Dqn_MemArena_Reserve(arena, size DQN_DEBUG_PARAMS)
#define DQN_MEM_ARENA_RESERVE_FROM(arena, src, size) Dqn_MemArena_ReserveFrom(arena, src, size DQN_DEBUG_PARAMS); #define DQN_MEM_ARENA_RESERVE_FROM(arena, src, size) Dqn_MemArena_ReserveFrom(arena, src, size DQN_DEBUG_PARAMS)
#define DQN_MEM_ARENA_CLEAR_USED(arena) Dqn_MemArena_ClearUsed(arena DQN_DEBUG_PARAMS); #define DQN_MEM_ARENA_CLEAR_USED(arena) Dqn_MemArena_ClearUsed(arena DQN_DEBUG_PARAMS)
#define DQN_MEM_ARENA_FREE(arena) Dqn_MemArena_Free #define DQN_MEM_ARENA_FREE(arena) Dqn_MemArena_Free
// ------------------------------------------------------------------------------------------------- // -------------------------------------------------------------------------------------------------
@ -362,16 +362,33 @@ template <typename T, int MAX_> T *Dqn_FixedStack_Peek (Dqn_FixedStack<T, MAX_
template <typename T, int MAX_> T *Dqn_FixedStack_Push (Dqn_FixedStack<T, MAX_> *array, T item) { return Dqn_FixedArray_Add(array, item); } template <typename T, int MAX_> T *Dqn_FixedStack_Push (Dqn_FixedStack<T, MAX_> *array, T item) { return Dqn_FixedArray_Add(array, item); }
template <typename T, int MAX_> void Dqn_FixedStack_Clear(Dqn_FixedStack<T, MAX_> *array) { Dqn_FixedArray_Clear(array); } template <typename T, int MAX_> void Dqn_FixedStack_Clear(Dqn_FixedStack<T, MAX_> *array) { Dqn_FixedArray_Clear(array); }
// ------------------------------------------------------------------------------------------------- enum struct Dqn_Allocator_Type
//
// NOTE: Dqn_StaticArray
//
// -------------------------------------------------------------------------------------------------
template <typename T> struct Dqn_StaticArray
{ {
Heap, // Malloc, realloc, free
XHeap, // Malloc realloc, free, crash on failure
Arena,
NullAllocator,
};
struct Dqn_Allocator
{
Dqn_Allocator_Type type;
void *data;
};
// -------------------------------------------------------------------------------------------------
//
// NOTE: Dqn_Array
//
// -------------------------------------------------------------------------------------------------
// TODO(doyle): Make this either initialised from memory or dynamically allocating
template <typename T> struct Dqn_Array
{
Dqn_Allocator allocator;
T *data; T *data;
Dqn_isize len; Dqn_isize len;
Dqn_isize max; 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 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 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 *begin () const { return data; }
@ -382,15 +399,17 @@ template <typename T> struct Dqn_StaticArray
T *operator+(Dqn_isize i) { 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; }
}; };
template <typename T> Dqn_StaticArray<T> Dqn_StaticArray_InitMemory (T *memory, Dqn_isize max, Dqn_isize len = 0); template <typename T> Dqn_Array<T> Dqn_Array_InitMemory(T *memory, Dqn_isize max, Dqn_isize len = 0);
template <typename T> T * Dqn_StaticArray_Add (Dqn_StaticArray<T> *a, T const *items, Dqn_isize num); template <typename T> bool Dqn_Array_Reserve(Dqn_Array<T> *a, Dqn_isize size);
template <typename T> T * Dqn_StaticArray_Add (Dqn_StaticArray<T> *a, T const item); template <typename T> void Dqn_Array_Free(Dqn_Array<T> *a);
template <typename T> T * Dqn_StaticArray_Make (Dqn_StaticArray<T> *a, Dqn_isize num); template <typename T> T * Dqn_Array_Add(Dqn_Array<T> *a, T const *items, Dqn_isize num);
template <typename T> void Dqn_StaticArray_Clear (Dqn_StaticArray<T> *a); template <typename T> T * Dqn_Array_Add(Dqn_Array<T> *a, T const item);
template <typename T> void Dqn_StaticArray_EraseStable (Dqn_StaticArray<T> *a, Dqn_isize index); template <typename T> T * Dqn_Array_Make(Dqn_Array<T> *a, Dqn_isize num);
template <typename T> void Dqn_StaticArray_EraseUnstable(Dqn_StaticArray<T> *a, Dqn_isize index); template <typename T> void Dqn_Array_Clear(Dqn_Array<T> *a, bool zero_mem = false);
template <typename T> void Dqn_StaticArray_Pop (Dqn_StaticArray<T> *a, Dqn_isize num); template <typename T> void Dqn_Array_EraseStable(Dqn_Array<T> *a, Dqn_isize index);
template <typename T> T * Dqn_StaticArray_Peek (Dqn_StaticArray<T> *a); template <typename T> void Dqn_Array_EraseUnstable(Dqn_Array<T> *a, Dqn_isize index);
template <typename T> void Dqn_Array_Pop(Dqn_Array<T> *a, Dqn_isize num);
template <typename T> T * Dqn_Array_Peek(Dqn_Array<T> *a);
// ------------------------------------------------------------------------------------------------- // -------------------------------------------------------------------------------------------------
// //
// NOTE: Dqn_FixedString // NOTE: Dqn_FixedString
@ -468,6 +487,18 @@ void Dqn_MemArena_ClearUsed(Dqn_MemArena *a
Dqn_MemArenaScopedRegion Dqn_MemArena_MakeScopedRegion(Dqn_MemArena *arena); Dqn_MemArenaScopedRegion Dqn_MemArena_MakeScopedRegion(Dqn_MemArena *arena);
// ------------------------------------------------------------------------------------------------- // -------------------------------------------------------------------------------------------------
// //
// NOTE: Dqn_Allocator
//
// -------------------------------------------------------------------------------------------------
Dqn_Allocator Dqn_Allocator_NullAllocator();
Dqn_Allocator Dqn_Allocator_HeapAllocator();
Dqn_Allocator Dqn_Allocator_XHeapAllocator();
Dqn_Allocator Dqn_Allocator_ArenaAllocator(Dqn_MemArena *arena);
void * Dqn_Allocator_Allocate(Dqn_Allocator *allocator, Dqn_usize size);
void * Dqn_Allocator_Realloc(Dqn_Allocator *allocator, void *old_ptr, Dqn_isize old_size, Dqn_isize new_size);
void Dqn_Allocator_Free(Dqn_Allocator *allocator, void *ptr);
// -------------------------------------------------------------------------------------------------
//
// NOTE: Vectors // NOTE: Vectors
// //
// ------------------------------------------------------------------------------------------------- // -------------------------------------------------------------------------------------------------
@ -549,7 +580,7 @@ Dqn_b32 Dqn_Char_IsWhitespace(char ch);
// NOTE: String Helpers // NOTE: String Helpers
// //
// ------------------------------------------------------------------------------------------------- // -------------------------------------------------------------------------------------------------
Dqn_b32 Dqn_Str_Equals(char const *a, Dqn_isize a_len, char const *b, Dqn_isize b_len = -1); Dqn_b32 Dqn_Str_Equals(char const *a, char const *b, Dqn_isize a_len = -1, Dqn_isize b_len = -1);
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); 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);
char const * Dqn_Str_Find(char const *buf, char const *find, Dqn_isize buf_len = -1, Dqn_isize find_len = -1); char const * Dqn_Str_Find(char const *buf, char const *find, Dqn_isize buf_len = -1, Dqn_isize find_len = -1);
Dqn_b32 Dqn_Str_Match(char const *src, char const *find, int find_len); Dqn_b32 Dqn_Str_Match(char const *src, char const *find, int find_len);

View File

@ -1,5 +1,5 @@
#define DQN_USE_PRIMITIVE_TYPEDEFS #define DQN_USE_PRIMITIVE_TYPEDEFS
#define _CRT_SECURE_NO_WARNINGS #define DQN_IMPLEMENTATION
#include "Dqn.h" #include "Dqn.h"
struct TestState struct TestState
@ -106,6 +106,173 @@ void TestState_PrintResult(TestState const *result)
FILE_SCOPE void UnitTests() FILE_SCOPE void UnitTests()
{ {
TestingState testing_state = {}; TestingState testing_state = {};
// ---------------------------------------------------------------------------------------------
//
// NOTE: Dqn_Allocator
//
// ---------------------------------------------------------------------------------------------
{
TEST_DECLARE_GROUP_SCOPED(testing_state, "Dqn_Allocator");
{
TEST_START_SCOPE(testing_state, "HeapAllocator - Allocate Small");
Dqn_Allocator allocator = Dqn_Allocator_HeapAllocator();
char constexpr EXPECT[] = "hello_world";
char *buf = DQN_CAST(char *)Dqn_Allocator_Allocate(&allocator, Dqn_ArrayCount(EXPECT));
DQN_DEFER { Dqn_Allocator_Free(&allocator, buf); };
memcpy(buf, EXPECT, Dqn_ArrayCount(EXPECT));
TEST_EXPECT_MSG(testing_state, memcmp(EXPECT, buf, Dqn_ArrayCount(EXPECT)) == 0, "buf: %s, expect: %s", buf, EXPECT);
}
{
TEST_START_SCOPE(testing_state, "XHeapAllocator - Allocate Small");
Dqn_Allocator allocator = Dqn_Allocator_XHeapAllocator();
char constexpr EXPECT[] = "hello_world";
char *buf = DQN_CAST(char *)Dqn_Allocator_Allocate(&allocator, Dqn_ArrayCount(EXPECT));
DQN_DEFER { Dqn_Allocator_Free(&allocator, buf); };
memcpy(buf, EXPECT, Dqn_ArrayCount(EXPECT));
TEST_EXPECT_MSG(testing_state, memcmp(EXPECT, buf, Dqn_ArrayCount(EXPECT)) == 0, "buf: %s, expect: %s", buf, EXPECT);
}
{
TEST_START_SCOPE(testing_state, "ArenaAllocator - Allocate Small");
Dqn_MemArena arena = {};
Dqn_Allocator allocator = Dqn_Allocator_ArenaAllocator(&arena);
char constexpr EXPECT[] = "hello_world";
char *buf = DQN_CAST(char *)Dqn_Allocator_Allocate(&allocator, Dqn_ArrayCount(EXPECT));
DQN_DEFER { Dqn_Allocator_Free(&allocator, buf); };
memcpy(buf, EXPECT, Dqn_ArrayCount(EXPECT));
TEST_EXPECT_MSG(testing_state, memcmp(EXPECT, buf, Dqn_ArrayCount(EXPECT)) == 0, "buf: %s, expect: %s", buf, EXPECT);
}
}
// ---------------------------------------------------------------------------------------------
//
// NOTE: Dqn_Array
//
// ---------------------------------------------------------------------------------------------
{
TEST_DECLARE_GROUP_SCOPED(testing_state, "Dqn_Array");
// NOTE: Dqn_Array_InitMemory
{
{
TEST_START_SCOPE(testing_state, "Fixed Memory: Test add single item and can't allocate more");
int memory[4] = {};
Dqn_Array<int> array = Dqn_Array_InitMemory(memory, Dqn_ArrayCount(memory), 0 /*len*/);
Dqn_Array_Add(&array, 1);
Dqn_Array_Add(&array, 2);
Dqn_Array_Add(&array, 3);
Dqn_Array_Add(&array, 4);
TEST_EXPECT_MSG(testing_state, array.data[0] == 1, "array.data %d", array.data[0]);
TEST_EXPECT_MSG(testing_state, array.data[1] == 2, "array.data %d", array.data[1]);
TEST_EXPECT_MSG(testing_state, array.data[2] == 3, "array.data %d", array.data[2]);
TEST_EXPECT_MSG(testing_state, array.data[3] == 4, "array.data %d", array.data[3]);
TEST_EXPECT_MSG(testing_state, array.len == 4, "array.len: %d", array.len);
int *added_item = Dqn_Array_Add(&array, 5);
TEST_EXPECT(testing_state, added_item == nullptr);
TEST_EXPECT_MSG(testing_state, array.len == 4, "array.len: %d", array.len);
TEST_EXPECT_MSG(testing_state, array.max == 4, "array.max: %d", array.max);
}
{
TEST_START_SCOPE(testing_state, "Fixed Memory: Test add array of items");
int memory[4] = {};
int DATA[] = {1, 2, 3};
Dqn_Array<int> array = Dqn_Array_InitMemory(memory, Dqn_ArrayCount(memory), 0 /*len*/);
Dqn_Array_Add(&array, DATA, Dqn_ArrayCount(DATA));
TEST_EXPECT_MSG(testing_state, array.data[0] == 1, "array.data %d", array.data[0]);
TEST_EXPECT_MSG(testing_state, array.data[1] == 2, "array.data %d", array.data[1]);
TEST_EXPECT_MSG(testing_state, array.data[2] == 3, "array.data %d", array.data[2]);
TEST_EXPECT_MSG(testing_state, array.len == 3, "array.len: %d", array.len);
TEST_EXPECT_MSG(testing_state, array.max == 4, "array.max: %d", array.max);
}
{
TEST_START_SCOPE(testing_state, "Fixed Memory: Test clear and clear with memory zeroed");
int memory[4] = {};
int DATA[] = {1, 2, 3};
Dqn_Array<int> array = Dqn_Array_InitMemory(memory, Dqn_ArrayCount(memory), 0 /*len*/);
Dqn_Array_Add(&array, DATA, Dqn_ArrayCount(DATA));
Dqn_Array_Clear(&array, false /*zero_mem*/);
TEST_EXPECT_MSG(testing_state, array.len == 0, "array.len: %d", array.len);
TEST_EXPECT_MSG(testing_state, array.max == 4, "array.max: %d", array.max);
TEST_EXPECT_MSG(testing_state, array.data[0] == 1, "array.data %d. Clear but don't zero memory so old values should still remain", array.data[0]);
Dqn_Array_Clear(&array, true /*zero_mem*/);
TEST_EXPECT_MSG(testing_state, array.data[0] == 0, "array.data %d. Clear but zero memory old values should not remain", array.data[0]);
}
{
TEST_START_SCOPE(testing_state, "Fixed Memory: Test erase stable and erase unstable");
int memory[4] = {};
int DATA[] = {1, 2, 3, 4};
Dqn_Array<int> array = Dqn_Array_InitMemory(memory, Dqn_ArrayCount(memory), 0 /*len*/);
Dqn_Array_Add(&array, DATA, Dqn_ArrayCount(DATA));
Dqn_Array_EraseUnstable(&array, 1);
TEST_EXPECT_MSG(testing_state, array.data[0] == 1, "array.data %d", array.data[0]);
TEST_EXPECT_MSG(testing_state, array.data[1] == 4, "array.data %d", array.data[1]);
TEST_EXPECT_MSG(testing_state, array.data[2] == 3, "array.data %d", array.data[2]);
TEST_EXPECT_MSG(testing_state, array.len == 3, "array.len: %d", array.len);
Dqn_Array_EraseStable(&array, 0);
TEST_EXPECT_MSG(testing_state, array.data[0] == 4, "array.data: %d", array.data[0]);
TEST_EXPECT_MSG(testing_state, array.data[1] == 3, "array.data: %d", array.data[1]);
TEST_EXPECT_MSG(testing_state, array.len == 2, "array.len: %d", array.len);
}
{
TEST_START_SCOPE(testing_state, "Fixed Memory: Test array pop and peek");
int memory[4] = {};
int DATA[] = {1, 2, 3};
Dqn_Array<int> array = Dqn_Array_InitMemory(memory, Dqn_ArrayCount(memory), 0 /*len*/);
Dqn_Array_Add(&array, DATA, Dqn_ArrayCount(DATA));
Dqn_Array_Pop(&array, 2);
TEST_EXPECT_MSG(testing_state, array.data[0] == 1, "array.data: %d", array.data[0]);
TEST_EXPECT_MSG(testing_state, array.len == 1, "array.len: %d", array.len);
TEST_EXPECT_MSG(testing_state, array.max == 4, "array.max: %d", array.max);
int *peek_item = Dqn_Array_Peek(&array);
TEST_EXPECT_MSG(testing_state, *peek_item == 1, "peek: %d", *peek_item);
TEST_EXPECT_MSG(testing_state, array.len == 1, "array.len: %d", array.len);
TEST_EXPECT_MSG(testing_state, array.max == 4, "array.max: %d", array.max);
}
{
TEST_START_SCOPE(testing_state, "Fixed Memory: Test free on fixed memory array does nothing");
int memory[4] = {};
Dqn_Array<int> array = Dqn_Array_InitMemory(memory, Dqn_ArrayCount(memory), 0 /*len*/);
DQN_DEFER { Dqn_Array_Free(&array); };
}
}
// NOTE: Dynamic Memory: Dqn_Array
{
{
TEST_START_SCOPE(testing_state, "Dynamic Memory: Test reserve and over commit reallocates");
Dqn_Array<int> array = {};
DQN_DEFER { Dqn_Array_Free(&array); };
Dqn_Array_Reserve(&array, 4);
TEST_EXPECT_MSG(testing_state, array.len == 0, "array.len: %d", array.len);
TEST_EXPECT_MSG(testing_state, array.max == 4, "array.max: %d", array.max);
int DATA[] = {1, 2, 3, 4};
Dqn_Array_Add(&array, DATA, Dqn_ArrayCount(DATA));
TEST_EXPECT_MSG(testing_state, array.data[0] == 1, "array.data: %d", array.data[0]);
TEST_EXPECT_MSG(testing_state, array.data[1] == 2, "array.data: %d", array.data[1]);
TEST_EXPECT_MSG(testing_state, array.data[2] == 3, "array.data: %d", array.data[2]);
TEST_EXPECT_MSG(testing_state, array.data[3] == 4, "array.data: %d", array.data[3]);
TEST_EXPECT_MSG(testing_state, array.len == 4, "array.len: %d", array.len);
int *added_item = Dqn_Array_Add(&array, 5);
TEST_EXPECT_MSG(testing_state, *added_item == 5, "added_item: %d", *added_item);
TEST_EXPECT_MSG(testing_state, array.data[4] == 5, "array.data: %d", array.data[4]);
TEST_EXPECT_MSG(testing_state, array.len == 5, "array.len: %d", array.len);
TEST_EXPECT_MSG(testing_state, array.max >= 5, "array.max: %d", array.max);
}
}
}
// --------------------------------------------------------------------------------------------- // ---------------------------------------------------------------------------------------------
// //
// NOTE: Dqn_StringBuilder // NOTE: Dqn_StringBuilder