Simplify memstack api

This commit is contained in:
Doyle 2018-09-02 21:17:14 +10:00
parent 4f665562f1
commit 43bc710dbd
5 changed files with 208 additions and 337 deletions

View File

@ -5,7 +5,7 @@ FILE_SCOPE void DqnMemStack_Test()
// Check Alignment
if (1)
{
auto stack = DqnMemStack(DQN_MEGABYTE(1), Dqn::ZeroClear::Yes, DqnMemStack::Flag::BoundsGuard);
auto stack = DqnMemStack(DQN_MEGABYTE(1), Dqn::ZeroMem::Yes, DqnMemStack::Flag::BoundsGuard);
i32 const ALIGN64 = 64;
i32 const ALIGN16 = 16;
@ -45,7 +45,7 @@ FILE_SCOPE void DqnMemStack_Test()
// Check Non-Expandable
if (1)
{
auto stack = DqnMemStack(DQN_MEGABYTE(1), Dqn::ZeroClear::Yes, DqnMemStack::Flag::NonExpandable);
auto stack = DqnMemStack(DQN_MEGABYTE(1), Dqn::ZeroMem::Yes, DqnMemStack::Flag::NonExpandable);
auto *result1 = stack.Push(DQN_MEGABYTE(2));
DQN_ASSERT(result1 == nullptr);
DQN_ASSERT(stack.block->prev_block == nullptr);
@ -57,7 +57,7 @@ FILE_SCOPE void DqnMemStack_Test()
// Check Expansion
if (1)
{
auto stack = DqnMemStack(DQN_MEGABYTE(1), Dqn::ZeroClear::Yes);
auto stack = DqnMemStack(DQN_MEGABYTE(1), Dqn::ZeroMem::Yes);
DQN_ASSERT(stack.tracker.bounds_guard_size == 0);
auto *old_block = stack.block;
@ -82,31 +82,31 @@ FILE_SCOPE void DqnMemStack_Test()
// Check temporary regions
if (1)
{
auto stack = DqnMemStack(DQN_MEGABYTE(1), Dqn::ZeroClear::Yes, DqnMemStack::Flag::BoundsGuard);
auto stack = DqnMemStack(DQN_MEGABYTE(1), Dqn::ZeroMem::Yes, DqnMemStack::Flag::BoundsGuard);
DqnMemStack::Block *blockToReturnTo = stack.block;
auto headBefore = blockToReturnTo->head;
auto tail_before = blockToReturnTo->tail;
DqnMemStack::Block *block_to_return_to = stack.block;
auto head_before = block_to_return_to->head;
auto tail_before = block_to_return_to->tail;
if (1)
{
auto memGuard1 = stack.TempRegionGuard();
auto mem_guard1 = stack.MemRegionScope();
auto *result2 = stack.Push(100);
auto *result3 = stack.Push(100);
auto *result4 = stack.Push(100);
DQN_ASSERT(result2 && result3 && result4);
DQN_ASSERT(stack.block->head != headBefore);
DQN_ASSERT(stack.block->head != head_before);
DQN_ASSERT(stack.block->tail == tail_before);
DQN_ASSERT(stack.block->memory == blockToReturnTo->memory);
DQN_ASSERT(stack.block->memory == block_to_return_to->memory);
// Force allocation of new block
auto *result5 = stack.Push(DQN_MEGABYTE(5));
DQN_ASSERT(result5);
DQN_ASSERT(stack.block != blockToReturnTo);
DQN_ASSERT(stack.tmp_region_count == 1);
DQN_ASSERT(stack.block != block_to_return_to);
DQN_ASSERT(stack.mem_region_count == 1);
}
DQN_ASSERT(stack.block == blockToReturnTo);
DQN_ASSERT(stack.block->head == headBefore);
DQN_ASSERT(stack.block == block_to_return_to);
DQN_ASSERT(stack.block->head == head_before);
DQN_ASSERT(stack.block->tail == tail_before);
stack.Free();
@ -115,32 +115,32 @@ FILE_SCOPE void DqnMemStack_Test()
// Check temporary regions keep state
if (1)
{
auto stack = DqnMemStack(DQN_MEGABYTE(1), Dqn::ZeroClear::Yes, DqnMemStack::Flag::BoundsGuard);
DqnMemStack::Block *blockToReturnTo = stack.block;
auto headBefore = blockToReturnTo->head;
auto tail_before = blockToReturnTo->tail;
auto stack = DqnMemStack(DQN_MEGABYTE(1), Dqn::ZeroMem::Yes, DqnMemStack::Flag::BoundsGuard);
DqnMemStack::Block *block_to_return_to = stack.block;
auto head_before = block_to_return_to->head;
auto tail_before = block_to_return_to->tail;
if (1)
{
auto memGuard1 = stack.TempRegionGuard();
auto mem_guard1 = stack.MemRegionScope();
auto *result2 = stack.Push(100);
auto *result3 = stack.Push(100);
auto *result4 = stack.Push(100);
DQN_ASSERT(result2 && result3 && result4);
DQN_ASSERT(stack.block->head != headBefore);
DQN_ASSERT(stack.block->head != head_before);
DQN_ASSERT(stack.block->tail == tail_before);
DQN_ASSERT(stack.block->memory == blockToReturnTo->memory);
DQN_ASSERT(stack.block->memory == block_to_return_to->memory);
// Force allocation of new block
auto *result5 = stack.Push(DQN_MEGABYTE(5));
DQN_ASSERT(result5);
DQN_ASSERT(stack.block != blockToReturnTo);
DQN_ASSERT(stack.tmp_region_count == 1);
memGuard1.region.keep_head_changes = true;
DQN_ASSERT(stack.block != block_to_return_to);
DQN_ASSERT(stack.mem_region_count == 1);
stack.MemRegionSave(&mem_guard1);
}
DQN_ASSERT(stack.block != blockToReturnTo);
DQN_ASSERT(stack.block->prev_block == blockToReturnTo);
DQN_ASSERT(stack.tmp_region_count == 0);
DQN_ASSERT(stack.block != block_to_return_to);
DQN_ASSERT(stack.block->prev_block == block_to_return_to);
DQN_ASSERT(stack.mem_region_count == 0);
stack.Free();
}
@ -148,17 +148,17 @@ FILE_SCOPE void DqnMemStack_Test()
// Check temporary regions with tail and head pushes
if (1)
{
auto stack = DqnMemStack(DQN_MEGABYTE(1), Dqn::ZeroClear::Yes, DqnMemStack::Flag::BoundsGuard);
auto stack = DqnMemStack(DQN_MEGABYTE(1), Dqn::ZeroMem::Yes, DqnMemStack::Flag::BoundsGuard);
auto *pop1 = stack.Push(222);
auto *pop2 = stack.Push(333, DqnMemStack::PushType::Tail);
DqnMemStack::Block *blockToReturnTo = stack.block;
auto headBefore = blockToReturnTo->head;
auto tail_before = blockToReturnTo->tail;
DqnMemStack::Block *block_to_return_to = stack.block;
auto head_before = block_to_return_to->head;
auto tail_before = block_to_return_to->tail;
if (1)
{
auto memGuard1 = stack.TempRegionGuard();
auto mem_guard1 = stack.MemRegionScope();
auto *result2 = stack.Push(100);
auto *result3 = stack.Push(100, DqnMemStack::PushType::Tail);
auto *result4 = stack.Push(100);
@ -166,19 +166,19 @@ FILE_SCOPE void DqnMemStack_Test()
DQN_ASSERT(result2 && result3 && result4 && result5);
DQN_ASSERT(result3 > result5);
DQN_ASSERT(result2 < result4);
DQN_ASSERT(stack.block->head > headBefore && stack.block->head < stack.block->tail);
DQN_ASSERT(stack.block->head > head_before && stack.block->head < stack.block->tail);
DQN_ASSERT(stack.block->tail >= stack.block->head && stack.block->tail < (stack.block->memory + stack.block->size));
DQN_ASSERT(stack.block->memory == blockToReturnTo->memory);
DQN_ASSERT(stack.block->memory == block_to_return_to->memory);
// Force allocation of new block
auto *result6 = stack.Push(DQN_MEGABYTE(5));
DQN_ASSERT(result6);
DQN_ASSERT(stack.block != blockToReturnTo);
DQN_ASSERT(stack.tmp_region_count == 1);
DQN_ASSERT(stack.block != block_to_return_to);
DQN_ASSERT(stack.mem_region_count == 1);
}
DQN_ASSERT(stack.block == blockToReturnTo);
DQN_ASSERT(stack.block->head == headBefore);
DQN_ASSERT(stack.block == block_to_return_to);
DQN_ASSERT(stack.block->head == head_before);
DQN_ASSERT(stack.block->tail == tail_before);
stack.Pop(pop1);
@ -188,7 +188,7 @@ FILE_SCOPE void DqnMemStack_Test()
stack.Free();
}
Log(Status::Ok, "Temporary regions return state and/or keep changes if requested.");
Log(Status::Ok, "Temporary regions revert state and save state");
}
// Check Fixed Mem Init
@ -199,11 +199,11 @@ FILE_SCOPE void DqnMemStack_Test()
{
isize const buf_size = sizeof(DqnMemStack::Block) * 5;
char buf[buf_size] = {};
auto stack = DqnMemStack(&buf, buf_size, Dqn::ZeroClear::No);
auto stack = DqnMemStack(&buf, buf_size, Dqn::ZeroMem::No);
DQN_ASSERT(stack.block);
DQN_ASSERT(stack.block->prev_block == false);
DQN_ASSERT(stack.tmp_region_count == 0);
DQN_ASSERT(stack.mem_region_count == 0);
DQN_ASSERT(stack.flags == DqnMemStack::Flag::NonExpandable);
auto *result1 = stack.Push(32);
@ -214,7 +214,7 @@ FILE_SCOPE void DqnMemStack_Test()
DQN_ASSERT(result2 == nullptr);
DQN_ASSERT(stack.block);
DQN_ASSERT(stack.block->prev_block == false);
DQN_ASSERT(stack.tmp_region_count == 0);
DQN_ASSERT(stack.mem_region_count == 0);
DQN_ASSERT(stack.flags == DqnMemStack::Flag::NonExpandable);
stack.Free();
@ -229,7 +229,7 @@ FILE_SCOPE void DqnMemStack_Test()
usize size = 32;
usize additional_size = DqnMemStack::MINIMUM_BLOCK_SIZE;
auto stack = DqnMemStack(size, Dqn::ZeroClear::Yes, 0);
auto stack = DqnMemStack(size, Dqn::ZeroMem::Yes, 0);
auto *block1 = stack.block;
size += additional_size;
@ -256,14 +256,14 @@ FILE_SCOPE void DqnMemStack_Test()
DQN_ASSERT(block2->prev_block == block1);
DQN_ASSERT(block1->prev_block == nullptr);
DQN_ASSERT(stack.FreeMemBlock(block4));
DQN_ASSERT(stack.FreeBlock(block4));
DQN_ASSERT(stack.block == block5);
DQN_ASSERT(block5->prev_block == block3);
DQN_ASSERT(block3->prev_block == block2);
DQN_ASSERT(block2->prev_block == block1);
DQN_ASSERT(block1->prev_block == nullptr);
DQN_ASSERT(stack.FreeMemBlock(block5));
DQN_ASSERT(stack.FreeBlock(block5));
DQN_ASSERT(stack.block == block3);
DQN_ASSERT(block3->prev_block == block2);
DQN_ASSERT(block2->prev_block == block1);
@ -277,7 +277,7 @@ FILE_SCOPE void DqnMemStack_Test()
// Check bounds guard places magic values
if (1)
{
auto stack = DqnMemStack(DQN_MEGABYTE(1), Dqn::ZeroClear::Yes, DqnMemStack::Flag::BoundsGuard);
auto stack = DqnMemStack(DQN_MEGABYTE(1), Dqn::ZeroMem::Yes, DqnMemStack::Flag::BoundsGuard);
char *result = static_cast<char *>(stack.Push(64));
// TODO(doyle): check head and tail are adjacent to the bounds of the allocation
@ -295,17 +295,17 @@ FILE_SCOPE void DqnMemStack_Test()
// Push to tail and head
if (1)
{
DqnMemStack stack = DqnMemStack(DQN_MEGABYTE(1), Dqn::ZeroClear::Yes, DqnMemStack::Flag::BoundsGuard);
DqnMemStack stack = DqnMemStack(DQN_MEGABYTE(1), Dqn::ZeroMem::Yes, DqnMemStack::Flag::BoundsGuard);
auto *result1 = stack.Push(100);
auto *result2 = stack.Push(100, DqnMemStack::PushType::Tail);
auto *headBefore = stack.block->head;
auto *head_before = stack.block->head;
auto *tail_before = stack.block->tail;
DQN_ASSERT(result2 && result1);
DQN_ASSERT(result2 != result1 && result1 < result2);
stack.Pop(result2);
DQN_ASSERT(headBefore == stack.block->head)
DQN_ASSERT(head_before == stack.block->head)
DQN_ASSERT(tail_before != stack.block->tail)
stack.Pop(result1);
@ -322,7 +322,7 @@ FILE_SCOPE void DqnMemStack_Test()
// Push too much to tail causes expansion
if (1)
{
DqnMemStack stack = DqnMemStack(DQN_MEGABYTE(1), Dqn::ZeroClear::Yes, DqnMemStack::Flag::BoundsGuard);
DqnMemStack stack = DqnMemStack(DQN_MEGABYTE(1), Dqn::ZeroMem::Yes, DqnMemStack::Flag::BoundsGuard);
auto *result1 = stack.Push(100);
DQN_ASSERT(stack.block->prev_block == nullptr);
@ -352,7 +352,7 @@ FILE_SCOPE void DqnMemStack_Test()
// Push too much to tail fails to expand when non expandable
if (1)
{
DqnMemStack stack = DqnMemStack(DQN_MEGABYTE(1), Dqn::ZeroClear::Yes, DqnMemStack::Flag::NonExpandable);
DqnMemStack stack = DqnMemStack(DQN_MEGABYTE(1), Dqn::ZeroMem::Yes, DqnMemStack::Flag::NonExpandable);
auto *result1 = stack.Push(100);
DQN_ASSERT(stack.block->prev_block == nullptr);
@ -390,11 +390,11 @@ FILE_SCOPE void DqnMemStack_Test()
// Using push on head
if (1)
{
DqnMemStack stack = DqnMemStack(DQN_MEGABYTE(1), Dqn::ZeroClear::Yes, DqnMemStack::Flag::BoundsGuard);
DqnMemStack stack = DqnMemStack(DQN_MEGABYTE(1), Dqn::ZeroMem::Yes, DqnMemStack::Flag::BoundsGuard);
auto *api = &stack.myHeadAPI;
auto *block_before = stack.block;
auto *headBefore = stack.block->head;
auto *head_before = stack.block->head;
isize buf_size = 16;
char *buf = (char *)stack.Push(buf_size);
@ -408,19 +408,19 @@ FILE_SCOPE void DqnMemStack_Test()
DqnMem_Set(buf, '@', buf_size);
DQN_ASSERT(block_before == stack.block);
DQN_ASSERT(headBefore < stack.block->head);
DQN_ASSERT(head_before < stack.block->head);
stack.Pop(buf);
DQN_ASSERT(block_before == stack.block);
DQN_ASSERT(headBefore == stack.block->head);
DQN_ASSERT(headBefore == stack.block->memory);
DQN_ASSERT(head_before == stack.block->head);
DQN_ASSERT(head_before == stack.block->memory);
stack.Free();
}
// Using push on tail
if (1)
{
DqnMemStack stack(DQN_MEGABYTE(1), Dqn::ZeroClear::Yes, DqnMemStack::Flag::BoundsGuard);
DqnMemStack stack(DQN_MEGABYTE(1), Dqn::ZeroMem::Yes, DqnMemStack::Flag::BoundsGuard);
auto *api = &stack.myHeadAPI;
auto *block_before = stack.block;
@ -455,11 +455,11 @@ FILE_SCOPE void DqnMemStack_Test()
// Using push on head
if (1)
{
auto stack = DqnMemStack(DQN_MEGABYTE(1), Dqn::ZeroClear::Yes, DqnMemStack::Flag::BoundsGuard);
auto stack = DqnMemStack(DQN_MEGABYTE(1), Dqn::ZeroMem::Yes, DqnMemStack::Flag::BoundsGuard);
auto *api = &stack.myHeadAPI;
auto *block_before = stack.block;
auto *headBefore = stack.block->head;
auto *head_before = stack.block->head;
isize buf_size = 16;
char *buf = (char *)stack.Push(buf_size);
@ -476,15 +476,15 @@ FILE_SCOPE void DqnMemStack_Test()
stack.Pop(buf);
DQN_ASSERT(block_before == stack.block);
DQN_ASSERT(headBefore == stack.block->head);
DQN_ASSERT(headBefore == stack.block->memory);
DQN_ASSERT(head_before == stack.block->head);
DQN_ASSERT(head_before == stack.block->memory);
stack.Free();
}
// Using push on tail
if (1)
{
DqnMemStack stack = DqnMemStack(DQN_MEGABYTE(1), Dqn::ZeroClear::Yes, DqnMemStack::Flag::BoundsGuard);
DqnMemStack stack = DqnMemStack(DQN_MEGABYTE(1), Dqn::ZeroMem::Yes, DqnMemStack::Flag::BoundsGuard);
auto *api = &stack.myHeadAPI;
auto *block_before = stack.block;

View File

@ -651,7 +651,7 @@ void DqnString_Test()
if (1)
{
DqnString str = "hello world";
DQN_DEFER(str.Free());
DQN_DEFER { str.Free(); };
str = "hello world2";
str.Append(", hello again");
str.Append(", and hello again");
@ -666,7 +666,7 @@ void DqnString_Test()
{
DqnString str = DQN_BUFFER_STR_LIT("hello world");
DQN_DEFER(str.Free());
DQN_DEFER { str.Free(); };
DQN_ASSERT(DqnStr_Cmp(str.str, "hello world") == 0);
Log(Status::Ok, "Copy constructor DqnSlice<char>");
@ -680,7 +680,7 @@ void DqnString_Test()
DqnBuffer<char const> helloSlice = DQN_BUFFER_STR_LIT("hello");
str = helloSlice;
DQN_DEFER(str.Free());
DQN_DEFER { str.Free(); };
DQN_ASSERT(DqnStr_Cmp(str.str, "hello") == 0);
Log(Status::Ok, "Copy constructor (DqnFixedString<>)");
@ -688,7 +688,7 @@ void DqnString_Test()
{
DqnString str = DQN_BUFFER_STR_LIT("hello world");
DQN_DEFER(str.Free());
DQN_DEFER { str.Free(); };
DQN_ASSERT(str.Sprintf("hello %s", "sailor"));
DQN_ASSERTM(DqnStr_Cmp(str.str, "hello sailor") == 0, "Result: %s", str.str);
@ -698,7 +698,7 @@ void DqnString_Test()
{
{
DqnString str = DQN_BUFFER_STR_LIT("hello world");
DQN_DEFER(str.Free());
DQN_DEFER { str.Free(); };
DQN_ASSERT(str.Sprintf("hello %s", "sailor"));
str += DQN_BUFFER_STR_LIT(".end");
DQN_ASSERTM(DqnStr_Cmp(str.str, "hello sailor.end") == 0, "Result: %s", str.str);
@ -706,7 +706,7 @@ void DqnString_Test()
{
DqnString str = DQN_BUFFER_STR_LIT("hello world");
DQN_DEFER(str.Free());
DQN_DEFER { str.Free(); };
DQN_ASSERT(str.Sprintf("hello %s", "sailor"));
DQN_ASSERT(str.SprintfAppend(" %d, %d", 100, 200));
DQN_ASSERT(DqnStr_Cmp(str.str, "hello sailor 100, 200") == 0);
@ -728,7 +728,7 @@ void DqnString_Test()
{
DqnString str = DQN_BUFFER_STR_LIT("hello world");
DQN_DEFER(str.Free());
DQN_DEFER { str.Free(); };
DQN_ASSERT(str.Sprintf("hello %s", "sailor"));
str = str + " end" + DQN_BUFFER_STR_LIT(" of");
DQN_ASSERT(DqnStr_Cmp(str.str, "hello sailor end of") == 0);
@ -738,7 +738,7 @@ void DqnString_Test()
{
DqnString str = "localhost";
DQN_DEFER(str.Free());
DQN_DEFER { str.Free(); };
str.SprintfAppend(":%d", 16832);
str += "/json_rpc";
DQN_ASSERT(str.len == 24 && DqnStr_Cmp("localhost:16832/json_rpc", str.str) == 0);
@ -1299,9 +1299,8 @@ void DqnArray_Test()
if (1)
{
auto stack =
DqnMemStack(DQN_MEGABYTE(1), Dqn::ZeroClear::Yes, DqnMemStack::Flag::BoundsGuard);
DQN_DEFER(stack.Free());
auto stack = DqnMemStack(DQN_MEGABYTE(1), Dqn::ZeroMem::Yes, DqnMemStack::Flag::BoundsGuard);
DQN_DEFER { stack.Free(); };
#if 0
if (1)
{
@ -1432,12 +1431,12 @@ void DqnFile_Test()
size_t bytesToWrite = DqnStr_Len(writeData[i]);
u8 *dataToWrite = (u8 *)(writeData[i]);
size_t bytesWritten = file->Write(dataToWrite, bytesToWrite, 0);
size_t bytesWritten = file->Write(dataToWrite, bytesToWrite);
DQN_ASSERT(bytesWritten == bytesToWrite);
file->Close();
}
auto memstack = DqnMemStack(DQN_MEGABYTE(1), Dqn::ZeroClear::Yes, DqnMemStack::Flag::BoundsGuard);
auto memstack = DqnMemStack(DQN_MEGABYTE(1), Dqn::ZeroMem::Yes, DqnMemStack::Flag::BoundsGuard);
// Read data back in
for (u32 i = 0; i < DQN_ARRAY_COUNT(file_names); i++)
{
@ -1573,7 +1572,7 @@ FILE_SCOPE void DqnJobQueue_Test()
LOG_HEADER();
global_debug_counter = 0;
auto memstack = DqnMemStack(DQN_MEGABYTE(1), Dqn::ZeroClear::Yes, DqnMemStack::Flag::BoundsGuard);
auto memstack = DqnMemStack(DQN_MEGABYTE(1), Dqn::ZeroMem::Yes, DqnMemStack::Flag::BoundsGuard);
u32 num_threads, num_cores;
DqnOS_GetThreadsAndCores(&num_cores, &num_threads);
@ -1617,7 +1616,7 @@ void DqnQuickSort_Test()
auto state = DqnRndPCG();
if (1)
{
auto stack = DqnMemStack(DQN_KILOBYTE(1), Dqn::ZeroClear::Yes, DqnMemStack::Flag::BoundsGuard);
auto stack = DqnMemStack(DQN_KILOBYTE(1), Dqn::ZeroMem::Yes, DqnMemStack::Flag::BoundsGuard);
// Create array of ints
u32 num_ints = 1000000;

View File

@ -11,7 +11,7 @@ void DqnVHashTable_Test()
Block block = {};
DqnVHashTable<Height, Block> table = {};
DQN_DEFER(table.Free());
DQN_DEFER { table.Free(); };
table.Set(12, block);
Block *getResult = table.Get(12);
@ -32,7 +32,7 @@ void DqnVHashTable_Test()
{
Block blocks[] = {{0}, {1}, {2}, {3}, {4}};
DqnVHashTable<Height, Block> table = {};
DQN_DEFER(table.Free());
DQN_DEFER { table.Free(); };
table.Set(1, blocks[0]);
table.Set(2, blocks[1]);

362
dqn.h
View File

@ -169,27 +169,27 @@ using f32 = float;
#define DQN_SIZEOF(decl) (isize)sizeof(decl)
template <typename Proc>
struct DqnDefer__
struct DqnDefer_
{
DqnDefer__(Proc p) : proc(p) { }
~DqnDefer__() { proc(); }
DqnDefer_(Proc p) : proc(p) { }
~DqnDefer_() { proc(); }
Proc proc;
};
template <typename Proc>
DqnDefer__<Proc> DqnDeferFunc__(Proc p)
struct DqnDeferHelper_
{
return DqnDefer__<Proc>(p);
}
template <typename Proc>
DqnDefer_<Proc> operator+(Proc proc) { return DqnDefer_<Proc>(proc); };
};
#define DQN_DEFER(code) auto DQN_UNIQUE_NAME(dqnDeferLambda__) = DqnDeferFunc__([&]()->void {code;})
#define DQN_DEFER const auto DQN_UNIQUE_NAME(dqn_defer_lambda_) = DqnDeferHelper_() + [&]()
// #Dqn Namespace
namespace Dqn
{
enum struct ZeroClear { No = 0, Yes = 1};
enum struct IgnoreCase { No = 0, Yes = 1};
FILE_SCOPE const bool IS_DEBUG = true;
enum struct ZeroMem { No = 0, Yes = 1};
enum struct IgnoreCase { No = 0, Yes = 1};
FILE_SCOPE const bool IsDebug = true;
}; // namespace Dqn
// #External Code
@ -1276,17 +1276,16 @@ struct DqnArray
isize max;
T *data;
DqnArray () = default;
DqnArray (DqnAllocator *allocator) { *this = {}; this->allocator = allocator; }
// ~DqnArray () { if (this->data && this->mem_api) this->mem_api->Free(data); }
DqnArray () = default;
DqnArray (DqnAllocator *allocator) { *this = {}; this->allocator = allocator; }
DqnArray (T *data_, isize max_, isize len_ = 0) { *this = {}; this->allocator = nullptr; this->data = data_; this->max = max_; this->len = len_; }
void UseMemory (T *data_, isize max_, isize len_ = 0) { this->mem_api = nullptr; this->data = data_; this->max = max_; this->len = len_; }
void Clear (Dqn::ZeroClear clear = Dqn::ZeroClear::No) { if (!data) return; len = 0; if (clear == Dqn::ZeroClear::Yes) DqnMem_Clear(data, 0, sizeof(T) * max); }
void Free () { if (data) { allocator->Free(data); } *this = {}; }
T *Front () { DQN_ASSERT(len > 0); return data + 0; }
T *Back () { DQN_ASSERT(len > 0); return data + (len - 1); }
void Resize (isize new_len) { if (new_len > max) Reserve(GrowCapacity_(new_len)); len = new_len; }
void Resize (isize new_len, T const *v) { if (new_len > max) Reserve(GrowCapacity_(new_len)); if (new_len > len) for (isize n = len; n < new_len; n++) data[n] = *v; len = new_len; }
void Clear (Dqn::ZeroMem clear = Dqn::ZeroMem::No) { if (!data) return; len = 0; if (clear == Dqn::ZeroMem::Yes) DqnMem_Clear(data, 0, sizeof(T) * max); }
void Free () { if (data) { allocator->Free(data); } *this = {}; }
T *Front () { DQN_ASSERT(len > 0); return data + 0; }
T *Back () { DQN_ASSERT(len > 0); return data + (len - 1); }
void Resize (isize new_len) { if (new_len > max) Reserve(GrowCapacity_(new_len)); len = new_len; }
void Resize (isize new_len, T const *v) { if (new_len > max) Reserve(GrowCapacity_(new_len)); if (new_len > len) for (isize n = len; n < new_len; n++) data[n] = *v; len = new_len; }
void Reserve (isize new_max);
T *Make (isize len = 1) { len += len; if (len > max) Reserve(GrowCapacity_(len)); return &data[len - len]; }
T *Push (T const &v) { if (len + 1 > max) Reserve(GrowCapacity_(len + 1)); data[len++] = v; return data + (len-1); }
@ -1459,16 +1458,16 @@ struct DqnMemStack
DqnAllocator *block_allocator; // Read: Allocator used to allocator blocks for this memory stack
Block *block; // Read: Memory block allocated for the stack
u32 flags; // Read
i32 tmp_region_count;// Read: The number of temp memory regions in use
i32 mem_region_count;// Read: The number of temp memory regions in use
DqnMemStack() = default;
// Uses fixed memory, will be sourced from the buffer and assert after buffer is full.
DqnMemStack(void *mem, isize size, Dqn::ZeroClear clear, u32 flags_ = 0);
DqnMemStack(void *mem, isize size, Dqn::ZeroMem clear, u32 flags_ = 0);
// Memory Stack capable of expanding when full, but only if NonExpandable flag is not set.
DqnMemStack (isize size, Dqn::ZeroClear clear, u32 flags_ = 0, DqnAllocator *block_allocator_ = DQN_DEFAULT_ALLOCATOR) { LazyInit(size, clear, flags_, block_allocator_); }
void LazyInit(isize size, Dqn::ZeroClear clear, u32 flags_ = 0, DqnAllocator *block_allocator_ = DQN_DEFAULT_ALLOCATOR);
DqnMemStack (isize size, Dqn::ZeroMem clear, u32 flags_ = 0, DqnAllocator *block_allocator_ = DQN_DEFAULT_ALLOCATOR) { LazyInit(size, clear, flags_, block_allocator_); }
void LazyInit(isize size, Dqn::ZeroMem clear, u32 flags_ = 0, DqnAllocator *block_allocator_ = DQN_DEFAULT_ALLOCATOR);
// Allocation API
// =============================================================================================
@ -1476,69 +1475,45 @@ struct DqnMemStack
// Allocate memory from the MemStack.
// alignment: Ptr returned from allocator is aligned to this value and MUST be power of 2.
// return: nullptr if out of space OR stack is using fixed memory/size OR stack full and platform malloc fails.
// return: nullptr if out of space OR stack is using fixed memory/size and out of memory OR stack full and malloc fails (or flags prevent expansion).
void *Push (isize size, PushType push_type = PushType::Default, u8 alignment = 4);
void SetDefaultAllocate(PushType type) { if (type == PushType::Default) return; if (type == PushType::Head) flags |= Flag::DefaultAllocateTail; else flags &= ~Flag::DefaultAllocateTail; }
// Frees the given ptr. It MUST be the last allocated item in the stack, asserts otherwise.
void Pop (void *ptr, Dqn::ZeroClear clear = Dqn::ZeroClear::No);
// Frees all blocks belonging to this stack.
void Free ();
// Frees the specified block belonging to the stack.
// return: FALSE if block doesn't belong this into calls DqnMem_Free() or invalid args.
bool FreeMemBlock (Block *mem_block);
// Frees the last-most memory block. If last block, free that block making the MemStack blockless.
// Next allocate will attach a block.
bool FreeLastBlock ();
// Reverts the stack and its usage back to the first block
void Reset ();
void ResetTail ();
// Reset the current memory block usage to 0.
void ClearCurrBlock(Dqn::ZeroClear clear = Dqn::ZeroClear::No);
Info GetInfo () const;
void SetDefaultAllocate(PushType type) { if (type == PushType::Default) return; if (type == PushType::Head) flags &= ~Flag::DefaultAllocateTail; else flags |= Flag::DefaultAllocateTail; }
void Pop (void *ptr, Dqn::ZeroMem zero = Dqn::ZeroMem::No); // Free the ptr. MUST be the last allocated ptr on the block head or tail, assert otherwise.
void PopBlock () { FreeBlock(block); }
void Free () { if (flags & Flag::BoundsGuard) tracker.allocations.Free(); while (block_allocator && block) PopBlock(); }
bool FreeBlock (DqnMemStack::Block *mem_block);
void Reset (Dqn::ZeroMem zero) { while(block && block->prev_block) PopBlock(); ClearCurrBlock(zero); }
void ResetTail (); // Reset just the tail
void ClearCurrBlock (Dqn::ZeroMem zero = Dqn::ZeroMem::No); // Reset the current memory block usage to 0.
Info GetInfo () const;
// Temporary Memory Regions API
// =============================================================================================
// TODO(doyle): Look into a way of "preventing/guarding" against anual calls to free/clear in temp regions
struct TempRegion
// Revert all allocations between the Begin() and End() regions. Guard version is RAII'ed.
enum struct RegionIsScoped { Yes, No };
struct MemRegion
{
DqnMemStack *stack; // Stack associated with this TempRegion
Block *starting_block; // Remember the block to revert to and its memory usage.
DqnMemStack *stack; // Stack associated with this MemRegion
Block *starting_block; // The block to revert back to
char *starting_block_head;
char *starting_block_tail;
bool keep_head_changes = false;
bool keep_tail_changes = false;
};
struct TempRegionGuard_
struct MemRegionScoped
{
TempRegionGuard_(DqnMemStack *stack);
~TempRegionGuard_();
TempRegion region;
MemRegionScoped(DqnMemStack *stack) { region = stack->MemRegionBegin(); }
~MemRegionScoped() { if (region.stack) region.stack->MemRegionEnd(region); }
MemRegion region;
};
// Revert all allocations between the Begin() and End() regions. Guard version is RAII'ed.
TempRegion TempRegionBegin ();
void TempRegionEnd (TempRegion region);
TempRegionGuard_ TempRegionGuard ();
MemRegion MemRegionBegin ();
void MemRegionEnd (MemRegion region);
MemRegionScoped MemRegionScope () { return MemRegionScoped(this); };
// Keep allocations that have occurred since Begin(). End() does not need to be called anymore.
void TempRegionKeepChanges(TempRegion region);
void *MallocHead (size_t size) { return Push(size); }
void *CallocHead (size_t size) { void *result = Push(size); DqnMem_Clear(result, 0, size); }
void FreeHead (void *ptr) { (void)ptr; return; }
void *ReallocHead(void *ptr, size_t size) { DqnPtrHeader *header = tracker.PtrToHeader((char *)ptr); void *result = Push(size); DqnMem_Copy(result, ptr, header->alloc_amount); return result; }
void *MallocTail (size_t size) { return Push(size, PushType::Tail); }
void *CallocTail (size_t size) { void *result = Push(size, PushType::Tail); DqnMem_Clear(result, 0, size); }
void FreeTail (void *ptr) { (void)ptr; return; }
void *ReallocTail(void *ptr, size_t size) { DqnPtrHeader *header = tracker.PtrToHeader((char *)ptr); void *result = Push(size, PushType::Tail); DqnMem_Copy(result, ptr, header->alloc_amount); return result; }
void MemRegionSave (MemRegion *region) { DQN_ASSERT(region->stack == this); region->stack = nullptr; mem_region_count--; DQN_ASSERT(mem_region_count >= 0); }
void MemRegionSave (MemRegionScoped *scope) { MemRegionSave(&scope->region); }
};
// #DqnHash API
@ -1830,7 +1805,7 @@ struct DqnString
int VSprintfAppend (char const *fmt, va_list va) { return VSprintfAtOffset(fmt, va, len/*offset*/); }
void NullTerminate () { str[len] = 0; } // NOTE: If you modify the storage directly, this can be handy.
void Clear (Dqn::ZeroClear clear = Dqn::ZeroClear::No) { if (clear == Dqn::ZeroClear::Yes) DqnMem_Set(str, 0, max); len = max = 0; NullTerminate(); }
void Clear (Dqn::ZeroMem clear = Dqn::ZeroMem::No) { if (clear == Dqn::ZeroMem::Yes) DqnMem_Set(str, 0, max); len = max = 0; NullTerminate(); }
void Free () { if (str) allocator->Free(str); str = nullptr; }
void Resize (int new_max) { if (new_max > max) Reserve(new_max); len = DQN_MIN(new_max, len); NullTerminate(); }
void Reserve (int new_max);
@ -1886,15 +1861,14 @@ struct DqnFixedString
int VSprintfAppend (char const *fmt, va_list va) { return VSprintfAtOffset(fmt, va, len/*offset*/); }
void NullTerminate () { str[len] = 0; } // NOTE: If you modify the storage directly, this can be handy.
void Clear (Dqn::ZeroClear clear = Dqn::ZeroClear::No) { if (clear == Dqn::ZeroClear::Yes) DqnMem_Set(str, 0, MAX); *this = {}; }
void Clear (Dqn::ZeroMem clear = Dqn::ZeroMem::No) { if (clear == Dqn::ZeroMem::Yes) DqnMem_Set(str, 0, MAX); *this = {}; }
int VSprintfAtOffset(char const *fmt, va_list va, int offset)
{
if (Dqn::IsDebug) DQN_ASSERT(Dqn_vsnprintf(nullptr, 0, fmt, va) < MAX);
char *start = str + offset;
int result = Dqn_vsnprintf(start, static_cast<int>((str + MAX) - start), fmt, va);
len = (offset + result);
if (Dqn::IS_DEBUG) DQN_ASSERT(Dqn_vsnprintf(nullptr, 0, fmt, va) < MAX);
return result;
}
};
@ -2034,7 +2008,7 @@ struct DqnVArray
void LazyInit (isize size) { *this = {}; if (data) return; len = 0; max = size; data = (T *)DqnOS_VAlloc(max * sizeof(T)); DQN_ALWAYS_ASSERT(data); }
// ~DqnVArray () { if (data) DqnOS_VFree(data, sizeof(T) * max); }
void Clear (Dqn::ZeroClear clear = Dqn::ZeroClear::No) { if (data) { len = 0; if (clear == Dqn::ZeroClear::Yes) DqnMem_Clear(data, 0, sizeof(T) * max); } }
void Clear (Dqn::ZeroMem clear = Dqn::ZeroMem::No) { if (data) { len = 0; if (clear == Dqn::ZeroMem::Yes) DqnMem_Clear(data, 0, sizeof(T) * max); } }
void Free () { if (data) { DqnOS_VFree(data, sizeof(T) * max); } *this = {}; }
T *Front () { return (len > 0) ? (data + 0) : nullptr; }
T *Back () { return (len > 0) ? (data + (len - 1)) : nullptr; }
@ -2183,8 +2157,8 @@ struct DqnVHashTable
Entry &operator* () const { return *GetCurrEntry(); }
Iterator &operator++();
Iterator &operator--() { if (--index_in_bucket < 0) { index_in_bucket = 0; num_used_buckets = DQN_MAX(--num_used_buckets, 0); } entry = GetCurrEntry(); return *this; }
Iterator operator++(int) { Iterator result = *this; ++(*this); return result; }
Iterator operator--(int) { Iterator result = *this; --(*this); return result; }
Iterator operator++(int) { Iterator result = *this; ++(*this); return result; } // postfix
Iterator operator--(int) { Iterator result = *this; --(*this); return result; } // postfix
Iterator operator+ (int offset) const { Iterator result = *this; DQN_FOR_EACH(i, DQN_ABS(offset)) { (offset > 0) ? ++result : --result; } return result; } // TODO(doyle): Improve
Iterator operator- (int offset) const { Iterator result = *this; DQN_FOR_EACH(i, DQN_ABS(offset)) { (offset > 0) ? --result : ++result; } return result; } // TODO(doyle): Improve
@ -2194,10 +2168,8 @@ struct DqnVHashTable
isize index_in_bucket;
};
Iterator Begin() { return begin(); }
Iterator End() { return end(); }
Iterator begin() { return Iterator(this); }
Iterator end() { return Iterator(this, num_buckets, DQN_ARRAY_COUNT(this->buckets[0].entries)); }
Iterator begin() { return Iterator(this); }
Iterator end() { return Iterator(this, num_buckets, DQN_ARRAY_COUNT(this->buckets[0].entries)); }
};
DQN_VHASH_TABLE_TEMPLATE DQN_VHASH_TABLE_DECL::Iterator::Iterator(DqnVHashTable *table_,
@ -2368,6 +2340,7 @@ struct DqnFile
u32 flags;
void *handle;
usize size;
int curr_write_offset;
// API
// ==============================================================================================
@ -2379,9 +2352,9 @@ struct DqnFile
bool Open(char const *path, u32 const flags_, Action const action);
bool Open(wchar_t const *path, u32 const flags_, Action const action);
// fileOffset: The byte offset to starting writing from.
// file_offset: The byte offset to starting writing from.
// return: The number of bytes written. 0 if invalid args or it failed to write.
usize Write(u8 const *buf, usize const num_bytes_to_write, usize const fileOffset);
usize Write(u8 const *buf, usize const num_bytes_to_write);
// IMPORTANT: You may want to allocate size+1 for null-terminating the file contents when reading into a buffer.
// return: The number of bytes read. 0 if invalid args or it failed to read.
@ -2551,7 +2524,7 @@ DQN_CATALOG_TEMPLATE T *DQN_CATALOG_DECL::GetIfUpdated(DqnCatalogPath const &fil
DQN_CATALOG_TEMPLATE bool DQN_CATALOG_DECL::PollAssets()
{
bool result = false;
for (auto it = this->asset_table.Begin(); it != this->asset_table.End(); ++it)
for (auto it = this->asset_table.begin(); it != this->asset_table.end(); ++it)
{
DqnCatalogPath const *file = &it.entry->key;
Entry *entry = &it.entry->item;
@ -2731,7 +2704,7 @@ DQN_FILE_SCOPE void DqnWin32_OutputDebugString(const char *const fmt_str, ...);
// buf: Filled with the path to the executable file.
// return: The offset to the last backslash. -1 if buf_len was not large enough or buf is null. (i.e.
// buf + offsetToLastSlash + 1, gives C:/Path/)
DQN_FILE_SCOPE i32 DqnWin32_GetEXEDirectory(char *const buf, const u32 buf_len);
DQN_FILE_SCOPE i32 DqnWin32_GetExeDirectory(wchar_t *const buf, const u32 buf_len);
#endif // DQN_IS_WIN32
#endif // DQN_PLATFORM_H
#endif // DQN_PLATFORM_HEADER
@ -2948,9 +2921,9 @@ void DqnMemTracker::CheckAllocations() const
// #DqnMemStack
// =================================================================================================
DQN_FILE_SCOPE DqnMemStack::Block *
DqnMemStack__AllocateBlock(isize size, Dqn::ZeroClear clear, DqnAllocator *allocator)
DqnMemStack__AllocateBlock(isize size, Dqn::ZeroMem clear, DqnAllocator *allocator)
{
bool zero = clear == Dqn::ZeroClear::Yes;
bool zero = clear == Dqn::ZeroMem::Yes;
isize total_size = sizeof(DqnMemStack::Block) + size;
auto *result = zero ? static_cast<DqnMemStack::Block *>(allocator->Calloc(1, total_size))
: static_cast<DqnMemStack::Block *>(allocator->Malloc(total_size));
@ -2961,13 +2934,13 @@ DqnMemStack__AllocateBlock(isize size, Dqn::ZeroClear clear, DqnAllocator *alloc
return result;
}
DqnMemStack::DqnMemStack(void *mem, isize size, Dqn::ZeroClear clear, u32 flags_)
DqnMemStack::DqnMemStack(void *mem, isize size, Dqn::ZeroMem clear, u32 flags_)
{
DQN_ALWAYS_ASSERTM(mem, "Supplied fixed memory buffer is nullptr, initialise with fixed memory failed");
DQN_ALWAYS_ASSERTM(size > DQN_SIZEOF(DqnMemStack::Block), "(%zu < %zu) Buffer too small for block metadata", size, DQN_SIZEOF(DqnMemStack::Block));
*this = {};
if (clear == Dqn::ZeroClear::Yes)
if (clear == Dqn::ZeroMem::Yes)
DqnMem_Set(mem, 0, size);
char *block_offset = static_cast<char *>(mem) + sizeof(*this->block);
@ -2981,7 +2954,7 @@ DqnMemStack::DqnMemStack(void *mem, isize size, Dqn::ZeroClear clear, u32 flags_
this->tracker.Init(bounds_guard);
}
void DqnMemStack::LazyInit(isize size, Dqn::ZeroClear clear, u32 flags_, DqnAllocator *block_allocator_)
void DqnMemStack::LazyInit(isize size, Dqn::ZeroMem clear, u32 flags_, DqnAllocator *block_allocator_)
{
DQN_ALWAYS_ASSERTM(size > 0, "%zu <= 0", size);
*this = {};
@ -3001,7 +2974,7 @@ void *DqnMemStack::Push(isize size, PushType push_type, u8 alignment)
return nullptr;
if (!this->block)
LazyInit(MINIMUM_BLOCK_SIZE, Dqn::ZeroClear::Yes, Flag::DefaultFlags, DQN_DEFAULT_ALLOCATOR);
LazyInit(MINIMUM_BLOCK_SIZE, Dqn::ZeroMem::Yes, Flag::DefaultFlags, DQN_DEFAULT_ALLOCATOR);
isize size_to_alloc = this->tracker.GetAllocationSize(size, alignment);
bool push_to_head = true;
@ -3033,7 +3006,7 @@ void *DqnMemStack::Push(isize size, PushType push_type, u8 alignment)
}
isize new_block_size = DQN_MAX(size_to_alloc, MINIMUM_BLOCK_SIZE);
Block *new_block = DqnMemStack__AllocateBlock(new_block_size, Dqn::ZeroClear::No, this->block_allocator);
Block *new_block = DqnMemStack__AllocateBlock(new_block_size, Dqn::ZeroMem::No, this->block_allocator);
new_block->prev_block = this->block;
this->block = new_block;
}
@ -3114,7 +3087,7 @@ FILE_SCOPE void DqnMemStack__KillTrackedPtrsInBlock(DqnMemTracker *tracker, DqnM
DqnMemStack__KillTrackedPtrsInRange(tracker, block_start, block_end);
}
void DqnMemStack::Pop(void *ptr, Dqn::ZeroClear clear)
void DqnMemStack::Pop(void *ptr, Dqn::ZeroMem clear)
{
if (!ptr) return;
@ -3147,28 +3120,17 @@ void DqnMemStack::Pop(void *ptr, Dqn::ZeroClear clear)
DQN_ASSERT(this->block->tail <= block_end);
}
if (clear == Dqn::ZeroClear::Yes)
if (clear == Dqn::ZeroMem::Yes)
DqnMem_Set(start, 0, end - start);
if (this->block->tail == block_end && this->block->head == this->block->memory)
{
if (this->block->prev_block)
{
this->FreeLastBlock();
}
this->PopBlock();
}
}
void DqnMemStack::Free()
{
if (Dqn_BitIsSet(this->flags, Flag::BoundsGuard))
this->tracker.allocations.Free();
while (this->block_allocator && this->block)
this->FreeLastBlock();
}
bool DqnMemStack::FreeMemBlock(DqnMemStack::Block *mem_block)
bool DqnMemStack::FreeBlock(DqnMemStack::Block *mem_block)
{
if (!mem_block || !this->block)
return false;
@ -3193,7 +3155,7 @@ bool DqnMemStack::FreeMemBlock(DqnMemStack::Block *mem_block)
this->block_allocator->Free(block_to_free);
// No more blocks, then last block has been freed
if (!this->block) DQN_ASSERT(this->tmp_region_count == 0);
if (!this->block) DQN_ASSERT(this->mem_region_count == 0);
return true;
}
@ -3212,38 +3174,19 @@ void DqnMemStack::ResetTail()
this->block->tail = end;
}
void DqnMemStack::Reset()
{
while(this->block && this->block->prev_block)
{
this->FreeLastBlock();
}
this->ClearCurrBlock(Dqn::ZeroClear::No);
}
bool DqnMemStack::FreeLastBlock()
{
bool result = this->FreeMemBlock(this->block);
return result;
}
void DqnMemStack::ClearCurrBlock(Dqn::ZeroClear clear)
void DqnMemStack::ClearCurrBlock(Dqn::ZeroMem zero)
{
if (this->block)
{
if (Dqn_BitIsSet(this->flags, Flag::BoundsGuard))
{
DqnMemStack__KillTrackedPtrsInBlock(&this->tracker, this->block);
}
this->block->head = this->block->memory;
this->block->tail = this->block->memory + this->block->size;
if (clear == Dqn::ZeroClear::Yes)
if (zero == Dqn::ZeroMem::Yes)
{
DqnMem_Clear(this->block->memory, 0, this->block->size);
}
}
}
@ -3270,118 +3213,45 @@ DqnMemStack::Info DqnMemStack::GetInfo() const
return result;
}
DqnMemStack::TempRegion DqnMemStack::TempRegionBegin()
DqnMemStack::MemRegion DqnMemStack::MemRegionBegin()
{
TempRegion result = {};
result.stack = this;
result.starting_block = this->block;
result.starting_block_head = (this->block) ? this->block->head : nullptr;
result.starting_block_tail = (this->block) ? this->block->tail : nullptr;
MemRegion result = {};
result.stack = this;
if (this->block)
{
result.starting_block = this->block;
result.starting_block_head = this->block->head;
result.starting_block_tail = this->block->tail;
}
this->tmp_region_count++;
this->mem_region_count++;
return result;
}
void DqnMemStack::TempRegionEnd(TempRegion region)
void DqnMemStack::MemRegionEnd(MemRegion region)
{
DQN_ASSERT(region.stack == this);
this->tmp_region_count--;
DQN_ASSERT(this->tmp_region_count >= 0);
this->mem_region_count--;
DQN_ASSERT(this->mem_region_count >= 0);
if (region.keep_head_changes && region.keep_tail_changes)
{
return;
}
while (this->block != region.starting_block)
this->PopBlock();
// Free blocks until you find the first block with changes in the head or tail, this is the
// block we want to start preserving allocation data for keepHead/TailChanges.
if (region.keep_head_changes)
if (this->block)
{
while (this->block && this->block->head == this->block->memory)
this->FreeLastBlock();
}
else if (region.keep_tail_changes)
{
while (this->block && this->block->tail == (this->block->memory + this->block->size))
this->FreeLastBlock();
}
else
{
while (this->block != region.starting_block)
this->FreeLastBlock();
}
this->block->head = region.starting_block_head;
this->block->tail = region.starting_block_tail;
for (Block *block_ = this->block; block_; block_ = block_->prev_block)
{
if (block_ == region.starting_block)
if (this->flags & DqnMemStack::Flag::BoundsGuard)
{
if (region.keep_head_changes)
{
block_->tail = region.starting_block_tail;
}
else if (region.keep_tail_changes)
{
block_->head = region.starting_block_head;
}
else
{
block_->head = region.starting_block_head;
block_->tail = region.starting_block_tail;
}
if (Dqn_BitIsSet(this->flags, DqnMemStack::Flag::BoundsGuard))
{
char *block_start = this->block->head;
char *block_end = this->block->tail;
DqnMemStack__KillTrackedPtrsInRange(&this->tracker, block_start, block_end);
}
break;
}
else
{
if (region.keep_head_changes || region.keep_tail_changes)
{
char *block_start = nullptr;
char *block_end = nullptr;
if (region.keep_head_changes)
{
block_start = block_->tail;
block_end = block_->memory + block_->size;
block_->tail = block_end;
}
else
{
block_start = block_->memory;
block_end = block_->memory + block_->size;
block_->head = block_start;
}
if (Dqn_BitIsSet(this->flags, DqnMemStack::Flag::BoundsGuard))
{
DqnMemStack__KillTrackedPtrsInRange(&this->tracker, block_start, block_end);
}
}
char *block_start = this->block->head;
char *block_end = this->block->tail;
DqnMemStack__KillTrackedPtrsInRange(&this->tracker, block_start, block_end);
}
}
}
DqnMemStack::TempRegionGuard_ DqnMemStack::TempRegionGuard()
{
return TempRegionGuard_(this);
}
DqnMemStack::TempRegionGuard_::TempRegionGuard_(DqnMemStack *stack)
{
this->region = stack->TempRegionBegin();
}
DqnMemStack::TempRegionGuard_::~TempRegionGuard_()
{
DqnMemStack *const stack = this->region.stack;
stack->TempRegionEnd(this->region);
}
// #DqnHash
// =================================================================================================
// Taken from GingerBill single file library @ github.com/gingerbill/gb
@ -5332,7 +5202,7 @@ char const *DqnLogger::Log(Type type, Context const log_context, char const *fmt
{
va_list va;
va_start(va, fmt);
DQN_DEFER(va_end(va));
DQN_DEFER { va_end(va); };
LOCAL_PERSIST DqnFixedString2048 fmt_msg;
fmt_msg.Clear();
@ -7413,7 +7283,7 @@ DQN_FILE__LIST_DIR(DqnFile__PlatformListDir)
return nullptr;
}
DQN_DEFER(FindClose(find_handle));
DQN_DEFER { FindClose(find_handle); };
bool stay_in_loop = true;
while (stay_in_loop)
{
@ -7453,7 +7323,7 @@ DQN_FILE__LIST_DIR(DqnFile__PlatformListDir)
return nullptr;
}
DQN_DEFER(FindClose(find_handle));
DQN_DEFER { FindClose(find_handle); };
char **list = (char **)allocator->Calloc(1, sizeof(*list) * (curr_num_files));
if (!list)
@ -7506,7 +7376,7 @@ FILE_SCOPE bool DqnFile__UnixGetFileSize(char const *path, usize *size)
// But there can also be zero-byte files, we can't be sure. So manual check by counting bytes
if (size && FILE *file = fopen(path, "rb"))
{
DQN_DEFER(fclose(file));
DQN_DEFER { fclose(file); };
while (fgetc(file) != EOF)
{
(*size)++;
@ -7586,7 +7456,7 @@ DQN_FILE__LIST_DIR(DqnFile__PlatformListDir)
{
DIR *const dir_handle = opendir(dir);
if (!dir_handle) return nullptr;
DQN_DEFER(closedir(dir_handle));
DQN_DEFER { closedir(dir_handle); };
struct dirent *dir_file = readdir(dir_handle);
while (dir_file)
@ -7606,7 +7476,7 @@ DQN_FILE__LIST_DIR(DqnFile__PlatformListDir)
{
DIR *const dir_handle = opendir(dir);
if (!dir_handle) return nullptr;
DQN_DEFER(closedir(dir_handle));
DQN_DEFER { closedir(dir_handle); };
char **list = (char **)allocator->Calloc(1, sizeof(*list) * curr_num_files);
if (!list)
@ -7670,13 +7540,14 @@ bool DqnFile::Open(wchar_t const *path, u32 flags_, Action action)
#endif
}
usize DqnFile::Write(u8 const *buf, usize num_bytes_to_write, usize fileOffset)
usize DqnFile::Write(u8 const *buf, usize num_bytes_to_write)
{
// TODO(doyle): Implement when it's needed
DQN_ASSERTM(fileOffset == 0, "File writing into offset is not implemented.");
usize file_offset = 0;
usize num_bytes_written = 0;
#if defined(DQN_IS_WIN32)
DQN_ALWAYS_ASSERTM(file_offset == 0, "File writing into offset is not implemented.");
DWORD bytes_to_write = (DWORD)num_bytes_to_write;
DWORD bytes_written;
BOOL result = WriteFile(this->handle, (void *)buf, bytes_to_write, &bytes_written, nullptr);
@ -7692,7 +7563,6 @@ usize DqnFile::Write(u8 const *buf, usize num_bytes_to_write, usize fileOffset)
const usize ITEMS_TO_WRITE = 1;
if (fwrite(buf, num_bytes_to_write, ITEMS_TO_WRITE, (FILE *)this->handle) == ITEMS_TO_WRITE)
{
rewind((FILE *)this->handle);
num_bytes_written = ITEMS_TO_WRITE * num_bytes_to_write;
}
#endif
@ -7781,7 +7651,7 @@ DQN_FILE_SCOPE u8 *DqnFile_ReadAll(wchar_t const *path, usize *buf_size, DqnMemS
DQN_LOGE("Could not open file: %s", path);
return result;
}
DQN_DEFER(file.Close());
DQN_DEFER { file.Close(); };
result = static_cast<u8 *>(stack->Push(file.size, push_type));
usize bytes_read = file.Read(result, file.size);
@ -7806,7 +7676,7 @@ DQN_FILE_SCOPE u8 *DqnFile_ReadAll(char const *path, usize *buf_size, DqnMemStac
DQN_LOGE("Could not open file: %s", path);
return result;
}
DQN_DEFER(file.Close());
DQN_DEFER { file.Close(); };
result = static_cast<u8 *>(stack->Push(file.size, push_type));
usize bytes_read = file.Read(result, file.size);
@ -7831,8 +7701,8 @@ DQN_FILE_SCOPE bool DqnFile_WriteAll(char const *path, u8 const *buf, usize cons
return false;
}
DQN_DEFER(file.Close());
usize bytes_written = file.Write(buf, buf_size, 0);
DQN_DEFER { file.Close(); };
usize bytes_written = file.Write(buf, buf_size);
if (bytes_written != buf_size)
{
DQN_LOGE("Bytes written did not match the buffer size, %zu != %zu", bytes_written, buf_size);
@ -7851,8 +7721,8 @@ DQN_FILE_SCOPE bool DqnFile_WriteAll(wchar_t const *path, u8 const *buf, usize c
return false;
}
DQN_DEFER(file.Close());
usize bytes_written = file.Write(buf, buf_size, 0);
DQN_DEFER { file.Close(); };
usize bytes_written = file.Write(buf, buf_size);
if (bytes_written != buf_size)
{
DQN_LOGE("Bytes written did not match the buffer size, %zu != %zu", bytes_written, buf_size);
@ -7866,7 +7736,7 @@ DQN_FILE_SCOPE bool DqnFile_ReadAll(wchar_t const *path, u8 *buf, usize buf_size
{
DqnFile file = {};
bool result = file.Open(path, DqnFile::Flag::FileRead, DqnFile::Action::OpenOnly);
DQN_DEFER(file.Close());
DQN_DEFER { file.Close(); };
// TODO(doyle): Logging
if (file.size > buf_size || !result)
@ -7884,7 +7754,7 @@ DQN_FILE_SCOPE bool DqnFile_ReadAll(char const *path, u8 *buf, usize buf_size)
{
DqnFile file = {};
bool result = file.Open(path, DqnFile::Flag::FileRead, DqnFile::Action::OpenOnly);
DQN_DEFER(file.Close());
DQN_DEFER { file.Close(); };
if (!result || file.size > buf_size)
{
@ -8671,10 +8541,10 @@ DQN_FILE_SCOPE void DqnWin32_OutputDebugString(char const *fmt_str, ...)
OutputDebugStringA(str);
}
DQN_FILE_SCOPE i32 DqnWin32_GetEXEDirectory(char *buf, u32 buf_len)
DQN_FILE_SCOPE i32 DqnWin32_GetExeDirectory(wchar_t *buf, u32 buf_len)
{
if (!buf || buf_len == 0) return -1;
u32 copied_len = GetModuleFileNameA(nullptr, buf, buf_len);
u32 copied_len = GetModuleFileNameW(nullptr, buf, buf_len);
if (copied_len == buf_len) return -1;
// NOTE: Should always work if GetModuleFileName works and we're running an

View File

@ -1,27 +1,19 @@
<?xml version="1.0" encoding="utf-8"?>
<AutoVisualizer xmlns="http://schemas.microsoft.com/vstudio/debugger/natvis/2010">
<Type Name="DqnArray&lt;*&gt;">
<DisplayString>{{count={count}/{max}}}</DisplayString>
<DisplayString>{{len={len}/{max}}}</DisplayString>
<Expand>
<Item Name="[count]">count</Item>
<Item Name="[len]">len</Item>
<Item Name="[max]">max</Item>
<ArrayItems>
<Size>count</Size>
<Size>len</Size>
<ValuePointer>data</ValuePointer>
</ArrayItems>
</Expand>
</Type>
<Type Name="DqnMemStack::Block">
<DisplayString>{{used={used}/{size} prevBlock={prevBlock}}}</DisplayString>
</Type>
<Type Name="DqnMemAPI">
<DisplayString>{{bytesAllocated={bytesAllocated} lifetimeBytesAllocated={lifetimeBytesAllocated} lifetimeBytesFreed={lifetimeBytesFreed}}}</DisplayString>
</Type>
<Type Name="DqnHashTable&lt;*&gt;">
<DisplayString>{{numEntries={numEntries} numFreeEntries={numFreeEntries} usedEntriesIndex={usedEntriesIndex}}}</DisplayString>
<DisplayString>{{used={head-tail}/{size} prev_block={prev_block}}}</DisplayString>
</Type>
<Type Name="DqnSlice&lt;*&gt;">
@ -29,6 +21,16 @@
<StringView>data,s</StringView>
</Type>
<Type Name="DqnBuffer&lt;*&gt;">
<DisplayString>{len={len} data={data,[len]}}</DisplayString>
<StringView>data,s</StringView>
</Type>
<Type Name="DqnFixedString&lt;*&gt;">
<DisplayString>{{len={len} {str,s}}}</DisplayString>
<StringView>str,s</StringView>
</Type>
<Type Name="DqnString">
<DisplayString>{{len={len}/{max} {str,s}}}</DisplayString>
<StringView>str,s</StringView>