Introduce new intrusive container macros

This commit is contained in:
doylet 2025-06-19 21:59:39 +10:00
parent 1720cae8db
commit a01b773655
5 changed files with 708 additions and 552 deletions

View File

@ -2,6 +2,94 @@
#include "../dn_base_inc.h"
DN_API void *DN_CArray2_MakeArray(void *data, DN_USize *size, DN_USize max, DN_USize data_size, DN_USize make_size, DN_ZeroMem zero_mem)
{
void *result = nullptr;
DN_USize new_size = *size + make_size;
if (new_size <= max) {
result = DN_CAST(char *) data + (data_size * size[0]);
*size = new_size;
if (zero_mem == DN_ZeroMem_Yes)
DN_Memset(result, 0, data_size * make_size);
}
return result;
}
DN_API bool DN_CArray2_GrowIfNeededFromPool(void **data, DN_USize size, DN_USize *max, DN_USize data_size, DN_Pool *pool)
{
bool result = true;
if (size >= *max) {
DN_USize new_max = DN_Max(*max * 2, 8);
DN_USize bytes_to_alloc = data_size * new_max;
void *buffer = DN_Pool_NewArray(pool, DN_U8, bytes_to_alloc);
if (buffer) {
DN_USize bytes_to_copy = data_size * size;
DN_Memcpy(buffer, *data, bytes_to_copy);
DN_Pool_Dealloc(pool, *data);
*data = buffer;
*max = new_max;
} else {
result = false;
}
}
return result;
}
DN_API DN_ArrayEraseResult DN_CArray2_EraseRange(void *data, DN_USize *size, DN_USize elem_size, DN_USize begin_index, DN_ISize count, DN_ArrayErase erase)
{
DN_ArrayEraseResult result = {};
if (!data || !size || *size == 0 || count == 0)
return result;
// Compute the range to erase
DN_USize start = 0, end = 0;
if (count < 0) {
DN_USize abs_count = DN_Abs(count);
start = begin_index >= abs_count ? begin_index - abs_count + 1 : 0;
end = begin_index >= abs_count ? begin_index + 1 : 0;
} else {
start = begin_index;
end = begin_index + count;
}
// Clamp indices to valid bounds
start = DN_Min(start, *size);
end = DN_Min(end, *size);
// Erase the range [start, end)
DN_USize erase_count = end > start ? end - start : 0;
if (erase_count) {
char *dest = (char *)data + (elem_size * start);
char *array_end = (char *)data + (elem_size * *size);
char *src = dest + (elem_size * erase_count);
if (erase == DN_ArrayErase_Stable) {
DN_USize move_size = array_end - src;
DN_Memmove(dest, src, move_size);
} else {
char *unstable_src = array_end - (elem_size * erase_count);
DN_USize move_size = array_end - unstable_src;
DN_Memcpy(dest, unstable_src, move_size);
}
*size -= erase_count;
}
result.items_erased = erase_count;
result.it_index = start;
return result;
}
DN_API void *DN_CSLList_Detach(void **link, void **next)
{
void *result = *link;
if (*link) {
*link = *next;
*next = nullptr;
}
return result;
}
DN_API bool DN_Ring_HasSpace(DN_Ring const *ring, DN_U64 size)
{
DN_U64 avail = ring->write_pos - ring->read_pos;

View File

@ -159,6 +159,64 @@ template <typename T> struct DN_List
};
#endif // !defined(DN_NO_LIST)
// NOTE: Macros for operating on data structures that are embedded into a C style struct or from a
// set of defined variables from the available scope. Keep it stupid simple, structs and functions.
// Minimal amount of container types with flexible construction leads to less duplicated container
// code and less template meta-programming.
//
// LArray => Literal Array
// Define a C array and size:
//
// ```
// MyStruct buffer[TB_ASType_Count] = {};
// DN_USize size = 0;
// MyStruct *item = DN_LArray_Make(buffer, size, DN_ArrayCountU(buffer), DN_ZeroMem_No);
// ```
//
// IArray => Intrusive Array
// Define a struct with the members 'data', 'size' and 'max':
//
// ```
// struct MyArray {
// MyStruct *data;
// DN_USize size;
// DN_USize max;
// } my_array = {};
//
// MyStruct *item = DN_IArray_Make(&my_array, MyArray, DN_ZeroMem_No);
// ```
// ISLList => Intrusive Singly Linked List
// Define a struct with the members 'next':
//
// ```
// struct MyLinkItem {
// int data;
// MyLinkItem *next;
// } my_link = {};
//
// MyLinkItem *first_item = DN_ISLList_Detach(&my_link, MyLinkItem);
// ```
#define DN_ISLList_Detach(list) (decltype(list)) DN_CSLList_Detach((void **)&(list), (void **)&(list)->next)
#define DN_LArray_MakeArray(c_array, size, max, count, zero_mem) (decltype(&(c_array)[0])) DN_CArray2_MakeArray(c_array, size, max, sizeof(c_array[0]), count, zero_mem)
#define DN_LArray_MakeArrayZ(c_array, size, max, count) DN_LArray_MakeArray(c_array, size, max, count, DN_ZeroMem_Yes)
#define DN_LArray_Make(c_array, size, max, zero_mem) DN_LArray_MakeArray(c_array, size, max, 1, zero_mem)
#define DN_LArray_MakeZ(c_array, size, max) DN_LArray_Make(c_array, size, max, DN_ZeroMem_Yes)
#define DN_IArray_Front(array) (array)->data
#define DN_IArray_GrowIfNeededFromPool(array, pool) DN_CArray2_GrowIfNeededFromPool((void **)(&(array)->data), (array)->size, &(array)->max, sizeof((array)->data[0]), pool)
#define DN_IArray_MakeArray(array, count, zero_mem) DN_LArray_MakeArray((array)->data, &(array)->size, (array)->max, count, zero_mem)
#define DN_IArray_MakeArrayZ(array, count) DN_LArray_MakeArray(array, count, DN_ZeroMem_Yes)
#define DN_IArray_Make(array, zero_mem) DN_IArray_MakeArray(array, 1, zero_mem)
#define DN_IArray_MakeZ(array) DN_IArray_Make(array, DN_ZeroMem_Yes)
DN_API DN_ArrayEraseResult DN_CArray2_EraseRange (void *data, DN_USize *size, DN_USize elem_size, DN_USize begin_index, DN_ISize count, DN_ArrayErase erase);
DN_API void *DN_CArray2_MakeArray (void *data, DN_USize *size, DN_USize max, DN_USize data_size, DN_USize make_size, DN_ZeroMem zero_mem);
DN_API bool DN_CArray2_GrowIfNeededFromPool(void **data, DN_USize size, DN_USize *max, DN_USize data_size, DN_Pool *pool);
DN_API void *DN_CSLList_Detach (void **link, void **next);
DN_API bool DN_Ring_HasSpace (DN_Ring const *ring, DN_U64 size);
DN_API bool DN_Ring_HasData (DN_Ring const *ring, DN_U64 size);
DN_API void DN_Ring_Write (DN_Ring *ring, void const *src, DN_U64 src_size);

File diff suppressed because it is too large Load Diff

View File

@ -124,13 +124,13 @@ DN_API DN_Arena *DN_OS_TLSTopArena()
DN_API void DN_OS_TLSBeginFrame(DN_Arena *frame_arena)
{
DN_OSTLS *tls = DN_OS_TLSGet();
DN_OSTLS *tls = DN_OS_TLSGet();
tls->frame_arena = frame_arena;
}
DN_API DN_Arena *DN_OS_TLSFrameArena()
{
DN_OSTLS *tls = DN_OS_TLSGet();
DN_OSTLS *tls = DN_OS_TLSGet();
DN_Arena *result = tls->frame_arena;
DN_AssertF(result, "Frame arena must be set by calling DN_OS_TLSBeginFrame at the beginning of the frame");
return result;

View File

@ -79,10 +79,10 @@
#define DN_UT_COLOR_RESET "\x1b[0m"
#define DN_UT_Test(test, fmt, ...) \
for (int dummy_ = (DN_UT_BeginF((test), fmt, ##__VA_ARGS__), 0); \
(void)dummy_, (test)->state == DN_UTState_TestBegun; \
DN_UT_End(test))
#define DN_UT_Test(test, fmt, ...) \
int dummy_ = (DN_UT_BeginF((test), fmt, ##__VA_ARGS__), 0); \
(void)dummy_, (test)->state == DN_UTState_TestBegun; \
DN_UT_End(test)
#define DN_UT_AssertF(test, expr, fmt, ...) \
DN_UT_AssertAtF((test), __FILE__, __LINE__, (expr), fmt, ##__VA_ARGS__)