Simplify memstack api
This commit is contained in:
parent
4f665562f1
commit
43bc710dbd
124
DqnMemStack.cpp
124
DqnMemStack.cpp
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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]);
|
||||
|
328
dqn.h
328
dqn.h
@ -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 ZeroMem { No = 0, Yes = 1};
|
||||
enum struct IgnoreCase { No = 0, Yes = 1};
|
||||
FILE_SCOPE const bool IS_DEBUG = true;
|
||||
FILE_SCOPE const bool IsDebug = true;
|
||||
}; // namespace Dqn
|
||||
|
||||
// #External Code
|
||||
@ -1278,10 +1278,9 @@ struct DqnArray
|
||||
|
||||
DqnArray () = default;
|
||||
DqnArray (DqnAllocator *allocator) { *this = {}; this->allocator = allocator; }
|
||||
// ~DqnArray () { if (this->data && this->mem_api) this->mem_api->Free(data); }
|
||||
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 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); }
|
||||
@ -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);
|
||||
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,8 +2168,6 @@ 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)); }
|
||||
};
|
||||
@ -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,116 +3213,43 @@ DqnMemStack::Info DqnMemStack::GetInfo() const
|
||||
return result;
|
||||
}
|
||||
|
||||
DqnMemStack::TempRegion DqnMemStack::TempRegionBegin()
|
||||
DqnMemStack::MemRegion DqnMemStack::MemRegionBegin()
|
||||
{
|
||||
TempRegion result = {};
|
||||
MemRegion result = {};
|
||||
result.stack = this;
|
||||
if (this->block)
|
||||
{
|
||||
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;
|
||||
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;
|
||||
}
|
||||
|
||||
// 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)
|
||||
{
|
||||
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->PopBlock();
|
||||
|
||||
for (Block *block_ = this->block; block_; block_ = block_->prev_block)
|
||||
if (this->block)
|
||||
{
|
||||
if (block_ == region.starting_block)
|
||||
{
|
||||
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;
|
||||
}
|
||||
this->block->head = region.starting_block_head;
|
||||
this->block->tail = region.starting_block_tail;
|
||||
|
||||
if (Dqn_BitIsSet(this->flags, DqnMemStack::Flag::BoundsGuard))
|
||||
if (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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
@ -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
|
||||
|
26
dqn.natvis
26
dqn.natvis
@ -1,27 +1,19 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<AutoVisualizer xmlns="http://schemas.microsoft.com/vstudio/debugger/natvis/2010">
|
||||
<Type Name="DqnArray<*>">
|
||||
<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<*>">
|
||||
<DisplayString>{{numEntries={numEntries} numFreeEntries={numFreeEntries} usedEntriesIndex={usedEntriesIndex}}}</DisplayString>
|
||||
<DisplayString>{{used={head-tail}/{size} prev_block={prev_block}}}</DisplayString>
|
||||
</Type>
|
||||
|
||||
<Type Name="DqnSlice<*>">
|
||||
@ -29,6 +21,16 @@
|
||||
<StringView>data,s</StringView>
|
||||
</Type>
|
||||
|
||||
<Type Name="DqnBuffer<*>">
|
||||
<DisplayString>{len={len} data={data,[len]}}</DisplayString>
|
||||
<StringView>data,s</StringView>
|
||||
</Type>
|
||||
|
||||
<Type Name="DqnFixedString<*>">
|
||||
<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>
|
||||
|
Loading…
Reference in New Issue
Block a user