From ce63bb7755f6ab954642a0b5813e366a9715c5a0 Mon Sep 17 00:00:00 2001 From: doyle Date: Sun, 5 Apr 2020 08:50:30 +1000 Subject: [PATCH] Default allocator = null, move allocator definitions Allocator is null by default, this is to catch any unwanted used of the heap. --- Code/Dqn.h | 203 ++++++++++++++++++++++------------------- Code/DqnHeader.h | 1 + Code/Dqn_UnitTests.cpp | 14 +-- 3 files changed, 119 insertions(+), 99 deletions(-) diff --git a/Code/Dqn.h b/Code/Dqn.h index 20562d5..62f7f62 100644 --- a/Code/Dqn.h +++ b/Code/Dqn.h @@ -592,16 +592,14 @@ DQN_HEADER_COPY_PROTOTYPE(template T *, Dqn_MemZero(T *src)) // @ // @ ------------------------------------------------------------------------------------------------- // @ Custom allocations must include Dqn_AllocateMetadata before the aligned_ptr, see Dqn_AllocateMetadata for more information - DQN_HEADER_COPY_BEGIN -// NOTE: The default allocator is the heap allocator enum struct Dqn_Allocator_Type { + Null, Heap, // Malloc, realloc, free XHeap, // Malloc realloc, free, crash on failure Arena, Custom, - Null, }; #define DQN_ALLOCATOR_ALLOCATE_PROC(name) void *name(Dqn_isize size, Dqn_u8 alignment) @@ -630,76 +628,8 @@ struct Dqn_Allocator Dqn_Allocator_ReallocProc *realloc; Dqn_Allocator_FreeProc *free; }; - DQN_HEADER_COPY_END -// @ ------------------------------------------------------------------------------------------------- -// @ -// @ NOTE: Dqn_AllocatorMetadata -// @ -// @ ------------------------------------------------------------------------------------------------- -// @ Custom Dqn_Allocator implementations must include allocation metadata exactly (aligned_ptr - sizeof(Dqn_AllocatorMetadata)) bytes from the aligned ptr. -DQN_HEADER_COPY_BEGIN -struct Dqn_AllocateMetadata -{ - Dqn_u8 alignment; - Dqn_u8 offset; // Subtract offset from aligned ptr to return to the allocation ptr -}; -DQN_HEADER_COPY_END - -// @ ------------------------------------------------------------------------------------------------- -// @ -// @ NOTE: Dqn_MemArena -// @ -// @ ------------------------------------------------------------------------------------------------- -DQN_HEADER_COPY_BEGIN -struct Dqn_MemBlock -{ - void *memory; - Dqn_usize size; - Dqn_usize used; - Dqn_MemBlock *prev; - Dqn_MemBlock *next; -}; - -struct Dqn_MemArena -{ - // NOTE: Configuration (fill once after "Zero Initialisation {}") - int min_block_size = DQN_KILOBYTES(4); - Dqn_Allocator allocator; - - // NOTE: Read Only - Dqn_MemBlock *curr_mem_block; - Dqn_MemBlock *top_mem_block; - Dqn_usize highest_used_mark; - int total_allocated_mem_blocks; -}; - -struct Dqn_MemArenaScopedRegion -{ - Dqn_MemArenaScopedRegion(Dqn_MemArena *arena); - ~Dqn_MemArenaScopedRegion(); - Dqn_MemArena *arena; - Dqn_MemBlock *curr_mem_block; - Dqn_usize curr_mem_block_used; - Dqn_MemBlock *top_mem_block; -}; - -void * Dqn_MemArena_Allocate(Dqn_MemArena *arena, Dqn_usize size, Dqn_u8 alignment); -Dqn_b32 Dqn_MemArena_Reserve(Dqn_MemArena *arena, Dqn_usize size); -DQN_HEADER_COPY_PROTOTYPE(template T *, Dqn_MemArena_AllocateType(Dqn_MemArena *arena, Dqn_isize num)) -{ - auto *result = DQN_CAST(T *)Dqn_MemArena_Allocate(arena, sizeof(T) * num, alignof(T)); - return result; -} - -DQN_HEADER_COPY_END - -// @ ------------------------------------------------------------------------------------------------- -// @ -// @ NOTE: Dqn_Allocator -// @ -// @ ------------------------------------------------------------------------------------------------- DQN_HEADER_COPY_PROTOTYPE(Dqn_Allocator, inline Dqn_Allocator_Null()) { Dqn_Allocator result = {}; @@ -737,6 +667,73 @@ DQN_HEADER_COPY_PROTOTYPE(template T *, Dqn_Allocator_AllocateType( } +// @ ------------------------------------------------------------------------------------------------- +// @ +// @ NOTE: Dqn_AllocatorMetadata +// @ +// @ ------------------------------------------------------------------------------------------------- +// @ Custom Dqn_Allocator implementations must include allocation metadata exactly (aligned_ptr - sizeof(Dqn_AllocatorMetadata)) bytes from the aligned ptr. +DQN_HEADER_COPY_BEGIN +struct Dqn_AllocateMetadata +{ + Dqn_u8 alignment; + Dqn_u8 offset; // Subtract offset from aligned ptr to return to the allocation ptr +}; +DQN_HEADER_COPY_END + +// @ ------------------------------------------------------------------------------------------------- +// @ +// @ NOTE: Dqn_MemArena +// @ +// @ ------------------------------------------------------------------------------------------------- +DQN_HEADER_COPY_BEGIN +struct Dqn_MemBlock +{ + void *memory; + Dqn_usize size; + Dqn_usize used; + Dqn_MemBlock *prev; + Dqn_MemBlock *next; +}; + +Dqn_usize const DQN_MEM_ARENA_DEFAULT_MIN_BLOCK_SIZE = DQN_KILOBYTES(4); +struct Dqn_MemArena +{ + // NOTE: Configuration (fill once after "Zero Initialisation {}") + Dqn_usize min_block_size; + Dqn_Allocator allocator; + + // NOTE: Read Only + Dqn_MemBlock *curr_mem_block; + Dqn_MemBlock *top_mem_block; + Dqn_usize highest_used_mark; + int total_allocated_mem_blocks; +}; + +struct Dqn_MemArenaRegion +{ + Dqn_MemArena *arena; + Dqn_MemBlock *curr_mem_block; + Dqn_usize curr_mem_block_used; + Dqn_MemBlock *top_mem_block; +}; + +struct Dqn_MemArenaScopedRegion +{ + Dqn_MemArenaScopedRegion(Dqn_MemArena *arena); + ~Dqn_MemArenaScopedRegion(); + Dqn_MemArenaRegion region; +}; + +void * Dqn_MemArena_Allocate(Dqn_MemArena *arena, Dqn_usize size, Dqn_u8 alignment); +Dqn_b32 Dqn_MemArena_Reserve(Dqn_MemArena *arena, Dqn_usize size); +DQN_HEADER_COPY_PROTOTYPE(template T *, Dqn_MemArena_AllocateType(Dqn_MemArena *arena, Dqn_isize num)) +{ + auto *result = DQN_CAST(T *)Dqn_MemArena_Allocate(arena, sizeof(T) * num, alignof(T)); + return result; +} + +DQN_HEADER_COPY_END // @ ------------------------------------------------------------------------------------------------- // @ // @ NOTE: String @@ -849,6 +846,12 @@ template DQN_FILE_SCOPE void Dqn_StringBuilder__BuildOutput(Dqn_St return; } + if (!dest) + { + DQN_ASSERT(dest); + return; + } + char const *end = dest + dest_size; char *buf_ptr = dest; @@ -1576,7 +1579,7 @@ DQN_HEADER_COPY_PROTOTYPE(void *, Dqn_Allocator_Allocate(Dqn_Allocator *allocato char *result = nullptr; switch (allocator->type) { - case Dqn_Allocator_Type::Null: + case Dqn_Allocator_Type::Null: DQN_ASSERT(DQN_INVALID_CODE_PATH); default: break; case Dqn_Allocator_Type::Heap: @@ -1707,8 +1710,10 @@ DQN_HEADER_COPY_PROTOTYPE(void, Dqn_Allocator_Free(Dqn_Allocator *allocator, voi // @ ------------------------------------------------------------------------------------------------- DQN_FILE_SCOPE Dqn_MemBlock *Dqn_MemArena__AllocateBlock(Dqn_MemArena *arena, Dqn_usize requested_size) { - DQN_ASSERT(arena->min_block_size > 0); - Dqn_usize mem_block_size = DQN_MAX(DQN_CAST(Dqn_usize)arena->min_block_size, requested_size); + Dqn_usize min_block_size = arena->min_block_size; + if (min_block_size == 0) min_block_size = DQN_MEM_ARENA_DEFAULT_MIN_BLOCK_SIZE; + + Dqn_usize mem_block_size = DQN_MAX(min_block_size, requested_size); Dqn_usize const allocate_size = sizeof(*arena->curr_mem_block) + mem_block_size; auto *result = DQN_CAST(Dqn_MemBlock *)Dqn_Allocator_Allocate(&arena->allocator, allocate_size, alignof(Dqn_MemBlock)); if (!result) return result; @@ -1845,34 +1850,48 @@ DQN_HEADER_COPY_PROTOTYPE(void, Dqn_MemArena_ResetUsage(Dqn_MemArena *arena, Dqn } } -DQN_HEADER_COPY_PROTOTYPE(Dqn_MemArenaScopedRegion, Dqn_MemArena_MakeScopedRegion(Dqn_MemArena *arena)) +Dqn_MemArenaRegion Dqn_MemArena_BeginRegion(Dqn_MemArena *arena) { - return Dqn_MemArenaScopedRegion(arena); + Dqn_MemArenaRegion result = {}; + result.arena = arena; + result.curr_mem_block = arena->curr_mem_block; + result.curr_mem_block_used = (arena->curr_mem_block) ? arena->curr_mem_block->used : 0; + result.top_mem_block = arena->top_mem_block; + return result; +} + +void Dqn_MemArena_EndRegion(Dqn_MemArenaRegion region) +{ + while (region.top_mem_block != region.arena->top_mem_block) + { + Dqn_MemBlock *block_to_free = region.arena->top_mem_block; + if (region.arena->curr_mem_block == block_to_free) + region.arena->curr_mem_block = block_to_free->prev; + region.arena->top_mem_block = block_to_free->prev; + Dqn_MemArena__FreeBlock(region.arena, block_to_free); + } + + for (Dqn_MemBlock *mem_block = region.arena->top_mem_block; mem_block != region.curr_mem_block; mem_block = mem_block->prev) + mem_block->used = 0; + + if (region.arena->curr_mem_block) + region.arena->curr_mem_block->used = region.curr_mem_block_used; + region = {}; } Dqn_MemArenaScopedRegion::Dqn_MemArenaScopedRegion(Dqn_MemArena *arena) { - this->arena = arena; - this->curr_mem_block = arena->curr_mem_block; - this->curr_mem_block_used = (arena->curr_mem_block) ? arena->curr_mem_block->used : 0; - this->top_mem_block = arena->top_mem_block; + this->region = Dqn_MemArena_BeginRegion(arena); } Dqn_MemArenaScopedRegion::~Dqn_MemArenaScopedRegion() { - while (this->top_mem_block != this->arena->top_mem_block) - { - Dqn_MemBlock *block_to_free = this->arena->top_mem_block; - if (this->arena->curr_mem_block == block_to_free) - this->arena->curr_mem_block = block_to_free->prev; - this->arena->top_mem_block = block_to_free->prev; - Dqn_MemArena__FreeBlock(this->arena, block_to_free); - } + Dqn_MemArena_EndRegion(this->region); +} - for (Dqn_MemBlock *mem_block = this->arena->top_mem_block; mem_block != this->curr_mem_block; mem_block = mem_block->prev) - mem_block->used = 0; - - this->arena->curr_mem_block->used = this->curr_mem_block_used; +Dqn_MemArenaScopedRegion Dqn_MemArena_MakeScopedRegion(Dqn_MemArena *arena) +{ + return Dqn_MemArenaScopedRegion(arena); } // @ ------------------------------------------------------------------------------------------------- diff --git a/Code/DqnHeader.h b/Code/DqnHeader.h index b6b817c..8d9e136 100644 --- a/Code/DqnHeader.h +++ b/Code/DqnHeader.h @@ -164,6 +164,7 @@ int main(int argc, char *argv[]) } Dqn_MemArena arena = {}; + arena.allocator = Dqn_Allocator_XHeap(); Dqn_Allocator allocator = Dqn_Allocator_Arena(&arena); Dqn_MemArena_Reserve(&arena, DQN_MEGABYTES(16)); for (isize arg_index = 1; arg_index < argc; ++arg_index) diff --git a/Code/Dqn_UnitTests.cpp b/Code/Dqn_UnitTests.cpp index 1bc4294..cebf62f 100644 --- a/Code/Dqn_UnitTests.cpp +++ b/Code/Dqn_UnitTests.cpp @@ -228,12 +228,12 @@ FILE_SCOPE void UnitTests() // --------------------------------------------------------------------------------------------- { TEST_DECLARE_GROUP_SCOPED(testing_state, "Dqn_Array"); - // NOTE: Dqn_Array_InitWithMemory + // 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 array = Dqn_Array_InitWithMemory(memory, Dqn_ArrayCount(memory), 0 /*len*/); + Dqn_Array 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); @@ -254,7 +254,7 @@ FILE_SCOPE void UnitTests() TEST_START_SCOPE(testing_state, "Fixed Memory: Test add array of items"); int memory[4] = {}; int DATA[] = {1, 2, 3}; - Dqn_Array array = Dqn_Array_InitWithMemory(memory, Dqn_ArrayCount(memory), 0 /*len*/); + Dqn_Array 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]); @@ -267,7 +267,7 @@ FILE_SCOPE void UnitTests() TEST_START_SCOPE(testing_state, "Fixed Memory: Test clear and clear with memory zeroed"); int memory[4] = {}; int DATA[] = {1, 2, 3}; - Dqn_Array array = Dqn_Array_InitWithMemory(memory, Dqn_ArrayCount(memory), 0 /*len*/); + Dqn_Array 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); @@ -282,7 +282,7 @@ FILE_SCOPE void UnitTests() TEST_START_SCOPE(testing_state, "Fixed Memory: Test erase stable and erase unstable"); int memory[4] = {}; int DATA[] = {1, 2, 3, 4}; - Dqn_Array array = Dqn_Array_InitWithMemory(memory, Dqn_ArrayCount(memory), 0 /*len*/); + Dqn_Array 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]); @@ -300,7 +300,7 @@ FILE_SCOPE void UnitTests() TEST_START_SCOPE(testing_state, "Fixed Memory: Test array pop and peek"); int memory[4] = {}; int DATA[] = {1, 2, 3}; - Dqn_Array array = Dqn_Array_InitWithMemory(memory, Dqn_ArrayCount(memory), 0 /*len*/); + Dqn_Array 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]); @@ -316,7 +316,7 @@ FILE_SCOPE void UnitTests() { TEST_START_SCOPE(testing_state, "Fixed Memory: Test free on fixed memory array does nothing"); int memory[4] = {}; - Dqn_Array array = Dqn_Array_InitWithMemory(memory, Dqn_ArrayCount(memory), 0 /*len*/); + Dqn_Array array = Dqn_Array_InitMemory(memory, Dqn_ArrayCount(memory), 0 /*len*/); DQN_DEFER { Dqn_Array_Free(&array); }; } }