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

View File

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

View File

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

328
dqn.h
View File

@ -169,27 +169,27 @@ using f32 = float;
#define DQN_SIZEOF(decl) (isize)sizeof(decl) #define DQN_SIZEOF(decl) (isize)sizeof(decl)
template <typename Proc> template <typename Proc>
struct DqnDefer__ struct DqnDefer_
{ {
DqnDefer__(Proc p) : proc(p) { } DqnDefer_(Proc p) : proc(p) { }
~DqnDefer__() { proc(); } ~DqnDefer_() { proc(); }
Proc proc; Proc proc;
}; };
template <typename Proc> struct DqnDeferHelper_
DqnDefer__<Proc> DqnDeferFunc__(Proc p)
{ {
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 // #Dqn Namespace
namespace Dqn namespace Dqn
{ {
enum struct ZeroClear { No = 0, Yes = 1}; enum struct ZeroMem { No = 0, Yes = 1};
enum struct IgnoreCase { 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 }; // namespace Dqn
// #External Code // #External Code
@ -1278,10 +1278,9 @@ struct DqnArray
DqnArray () = default; DqnArray () = default;
DqnArray (DqnAllocator *allocator) { *this = {}; this->allocator = allocator; } 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::ZeroMem clear = Dqn::ZeroMem::No) { if (!data) return; len = 0; if (clear == Dqn::ZeroMem::Yes) DqnMem_Clear(data, 0, sizeof(T) * max); }
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 = {}; } void Free () { if (data) { allocator->Free(data); } *this = {}; }
T *Front () { DQN_ASSERT(len > 0); return data + 0; } T *Front () { DQN_ASSERT(len > 0); return data + 0; }
T *Back () { DQN_ASSERT(len > 0); return data + (len - 1); } 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 DqnAllocator *block_allocator; // Read: Allocator used to allocator blocks for this memory stack
Block *block; // Read: Memory block allocated for the stack Block *block; // Read: Memory block allocated for the stack
u32 flags; // Read 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; DqnMemStack() = default;
// Uses fixed memory, will be sourced from the buffer and assert after buffer is full. // 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. // 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_); } 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::ZeroClear clear, u32 flags_ = 0, DqnAllocator *block_allocator_ = DQN_DEFAULT_ALLOCATOR); void LazyInit(isize size, Dqn::ZeroMem clear, u32 flags_ = 0, DqnAllocator *block_allocator_ = DQN_DEFAULT_ALLOCATOR);
// Allocation API // Allocation API
// ============================================================================================= // =============================================================================================
@ -1476,69 +1475,45 @@ struct DqnMemStack
// Allocate memory from the MemStack. // Allocate memory from the MemStack.
// alignment: Ptr returned from allocator is aligned to this value and MUST be power of 2. // 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 *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 SetDefaultAllocate(PushType type) { if (type == PushType::Default) return; if (type == PushType::Head) flags &= ~Flag::DefaultAllocateTail; else flags |= Flag::DefaultAllocateTail; }
void Pop (void *ptr, Dqn::ZeroClear clear = Dqn::ZeroClear::No); 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); }
// Frees all blocks belonging to this stack. void Free () { if (flags & Flag::BoundsGuard) tracker.allocations.Free(); while (block_allocator && block) PopBlock(); }
void Free (); bool FreeBlock (DqnMemStack::Block *mem_block);
void Reset (Dqn::ZeroMem zero) { while(block && block->prev_block) PopBlock(); ClearCurrBlock(zero); }
// Frees the specified block belonging to the stack. void ResetTail (); // Reset just the tail
// return: FALSE if block doesn't belong this into calls DqnMem_Free() or invalid args. void ClearCurrBlock (Dqn::ZeroMem zero = Dqn::ZeroMem::No); // Reset the current memory block usage to 0.
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; Info GetInfo () const;
// Temporary Memory Regions API // Temporary Memory Regions API
// ============================================================================================= // =============================================================================================
// TODO(doyle): Look into a way of "preventing/guarding" against anual calls to free/clear in temp regions // Revert all allocations between the Begin() and End() regions. Guard version is RAII'ed.
struct TempRegion enum struct RegionIsScoped { Yes, No };
struct MemRegion
{ {
DqnMemStack *stack; // Stack associated with this TempRegion DqnMemStack *stack; // Stack associated with this MemRegion
Block *starting_block; // Remember the block to revert to and its memory usage. Block *starting_block; // The block to revert back to
char *starting_block_head; char *starting_block_head;
char *starting_block_tail; char *starting_block_tail;
bool keep_head_changes = false;
bool keep_tail_changes = false;
}; };
struct TempRegionGuard_ struct MemRegionScoped
{ {
TempRegionGuard_(DqnMemStack *stack); MemRegionScoped(DqnMemStack *stack) { region = stack->MemRegionBegin(); }
~TempRegionGuard_(); ~MemRegionScoped() { if (region.stack) region.stack->MemRegionEnd(region); }
TempRegion region; MemRegion region;
}; };
// Revert all allocations between the Begin() and End() regions. Guard version is RAII'ed. MemRegion MemRegionBegin ();
TempRegion TempRegionBegin (); void MemRegionEnd (MemRegion region);
void TempRegionEnd (TempRegion region); MemRegionScoped MemRegionScope () { return MemRegionScoped(this); };
TempRegionGuard_ TempRegionGuard ();
// Keep allocations that have occurred since Begin(). End() does not need to be called anymore. // Keep allocations that have occurred since Begin(). End() does not need to be called anymore.
void TempRegionKeepChanges(TempRegion region); 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); }
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; }
}; };
// #DqnHash API // #DqnHash API
@ -1830,7 +1805,7 @@ struct DqnString
int VSprintfAppend (char const *fmt, va_list va) { return VSprintfAtOffset(fmt, va, len/*offset*/); } 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 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 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 Resize (int new_max) { if (new_max > max) Reserve(new_max); len = DQN_MIN(new_max, len); NullTerminate(); }
void Reserve (int new_max); 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*/); } 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 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) 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; char *start = str + offset;
int result = Dqn_vsnprintf(start, static_cast<int>((str + MAX) - start), fmt, va); int result = Dqn_vsnprintf(start, static_cast<int>((str + MAX) - start), fmt, va);
len = (offset + result); len = (offset + result);
if (Dqn::IS_DEBUG) DQN_ASSERT(Dqn_vsnprintf(nullptr, 0, fmt, va) < MAX);
return result; 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); } 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); } // ~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 = {}; } void Free () { if (data) { DqnOS_VFree(data, sizeof(T) * max); } *this = {}; }
T *Front () { return (len > 0) ? (data + 0) : nullptr; } T *Front () { return (len > 0) ? (data + 0) : nullptr; }
T *Back () { return (len > 0) ? (data + (len - 1)) : nullptr; } T *Back () { return (len > 0) ? (data + (len - 1)) : nullptr; }
@ -2183,8 +2157,8 @@ struct DqnVHashTable
Entry &operator* () const { return *GetCurrEntry(); } Entry &operator* () const { return *GetCurrEntry(); }
Iterator &operator++(); 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--() { 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; } // postfix
Iterator operator--(int) { Iterator result = *this; --(*this); return result; } 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
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; isize index_in_bucket;
}; };
Iterator Begin() { return begin(); }
Iterator End() { return end(); }
Iterator begin() { return Iterator(this); } Iterator begin() { return Iterator(this); }
Iterator end() { return Iterator(this, num_buckets, DQN_ARRAY_COUNT(this->buckets[0].entries)); } Iterator end() { return Iterator(this, num_buckets, DQN_ARRAY_COUNT(this->buckets[0].entries)); }
}; };
@ -2368,6 +2340,7 @@ struct DqnFile
u32 flags; u32 flags;
void *handle; void *handle;
usize size; usize size;
int curr_write_offset;
// API // API
// ============================================================================================== // ==============================================================================================
@ -2379,9 +2352,9 @@ struct DqnFile
bool Open(char const *path, u32 const flags_, Action const action); bool Open(char const *path, u32 const flags_, Action const action);
bool Open(wchar_t 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. // 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. // 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. // 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() DQN_CATALOG_TEMPLATE bool DQN_CATALOG_DECL::PollAssets()
{ {
bool result = false; 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; DqnCatalogPath const *file = &it.entry->key;
Entry *entry = &it.entry->item; 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. // 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. // 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/) // 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_IS_WIN32
#endif // DQN_PLATFORM_H #endif // DQN_PLATFORM_H
#endif // DQN_PLATFORM_HEADER #endif // DQN_PLATFORM_HEADER
@ -2948,9 +2921,9 @@ void DqnMemTracker::CheckAllocations() const
// #DqnMemStack // #DqnMemStack
// ================================================================================================= // =================================================================================================
DQN_FILE_SCOPE DqnMemStack::Block * 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; isize total_size = sizeof(DqnMemStack::Block) + size;
auto *result = zero ? static_cast<DqnMemStack::Block *>(allocator->Calloc(1, total_size)) auto *result = zero ? static_cast<DqnMemStack::Block *>(allocator->Calloc(1, total_size))
: static_cast<DqnMemStack::Block *>(allocator->Malloc(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; 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(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)); DQN_ALWAYS_ASSERTM(size > DQN_SIZEOF(DqnMemStack::Block), "(%zu < %zu) Buffer too small for block metadata", size, DQN_SIZEOF(DqnMemStack::Block));
*this = {}; *this = {};
if (clear == Dqn::ZeroClear::Yes) if (clear == Dqn::ZeroMem::Yes)
DqnMem_Set(mem, 0, size); DqnMem_Set(mem, 0, size);
char *block_offset = static_cast<char *>(mem) + sizeof(*this->block); 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); 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); DQN_ALWAYS_ASSERTM(size > 0, "%zu <= 0", size);
*this = {}; *this = {};
@ -3001,7 +2974,7 @@ void *DqnMemStack::Push(isize size, PushType push_type, u8 alignment)
return nullptr; return nullptr;
if (!this->block) 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); isize size_to_alloc = this->tracker.GetAllocationSize(size, alignment);
bool push_to_head = true; 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); 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; new_block->prev_block = this->block;
this->block = new_block; this->block = new_block;
} }
@ -3114,7 +3087,7 @@ FILE_SCOPE void DqnMemStack__KillTrackedPtrsInBlock(DqnMemTracker *tracker, DqnM
DqnMemStack__KillTrackedPtrsInRange(tracker, block_start, block_end); 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; if (!ptr) return;
@ -3147,28 +3120,17 @@ void DqnMemStack::Pop(void *ptr, Dqn::ZeroClear clear)
DQN_ASSERT(this->block->tail <= block_end); DQN_ASSERT(this->block->tail <= block_end);
} }
if (clear == Dqn::ZeroClear::Yes) if (clear == Dqn::ZeroMem::Yes)
DqnMem_Set(start, 0, end - start); DqnMem_Set(start, 0, end - start);
if (this->block->tail == block_end && this->block->head == this->block->memory) if (this->block->tail == block_end && this->block->head == this->block->memory)
{ {
if (this->block->prev_block) if (this->block->prev_block)
{ this->PopBlock();
this->FreeLastBlock();
}
} }
} }
void DqnMemStack::Free() bool DqnMemStack::FreeBlock(DqnMemStack::Block *mem_block)
{
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)
{ {
if (!mem_block || !this->block) if (!mem_block || !this->block)
return false; return false;
@ -3193,7 +3155,7 @@ bool DqnMemStack::FreeMemBlock(DqnMemStack::Block *mem_block)
this->block_allocator->Free(block_to_free); this->block_allocator->Free(block_to_free);
// No more blocks, then last block has been freed // 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; return true;
} }
@ -3212,38 +3174,19 @@ void DqnMemStack::ResetTail()
this->block->tail = end; this->block->tail = end;
} }
void DqnMemStack::Reset() void DqnMemStack::ClearCurrBlock(Dqn::ZeroMem zero)
{
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)
{ {
if (this->block) if (this->block)
{ {
if (Dqn_BitIsSet(this->flags, Flag::BoundsGuard)) if (Dqn_BitIsSet(this->flags, Flag::BoundsGuard))
{
DqnMemStack__KillTrackedPtrsInBlock(&this->tracker, this->block); DqnMemStack__KillTrackedPtrsInBlock(&this->tracker, this->block);
}
this->block->head = this->block->memory; this->block->head = this->block->memory;
this->block->tail = this->block->memory + this->block->size; 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); DqnMem_Clear(this->block->memory, 0, this->block->size);
} }
} }
} }
@ -3270,116 +3213,43 @@ DqnMemStack::Info DqnMemStack::GetInfo() const
return result; return result;
} }
DqnMemStack::TempRegion DqnMemStack::TempRegionBegin() DqnMemStack::MemRegion DqnMemStack::MemRegionBegin()
{ {
TempRegion result = {}; MemRegion result = {};
result.stack = this; result.stack = this;
if (this->block)
{
result.starting_block = this->block; result.starting_block = this->block;
result.starting_block_head = (this->block) ? this->block->head : nullptr; result.starting_block_head = this->block->head;
result.starting_block_tail = (this->block) ? this->block->tail : nullptr; result.starting_block_tail = this->block->tail;
}
this->tmp_region_count++; this->mem_region_count++;
return result; return result;
} }
void DqnMemStack::TempRegionEnd(TempRegion region) void DqnMemStack::MemRegionEnd(MemRegion region)
{ {
DQN_ASSERT(region.stack == this); DQN_ASSERT(region.stack == this);
this->tmp_region_count--; this->mem_region_count--;
DQN_ASSERT(this->tmp_region_count >= 0); 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) 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) this->block->head = region.starting_block_head;
{ this->block->tail = region.starting_block_tail;
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)) if (this->flags & DqnMemStack::Flag::BoundsGuard)
{ {
char *block_start = this->block->head; char *block_start = this->block->head;
char *block_end = this->block->tail; char *block_end = this->block->tail;
DqnMemStack__KillTrackedPtrsInRange(&this->tracker, block_start, block_end); 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 // #DqnHash
@ -5332,7 +5202,7 @@ char const *DqnLogger::Log(Type type, Context const log_context, char const *fmt
{ {
va_list va; va_list va;
va_start(va, fmt); va_start(va, fmt);
DQN_DEFER(va_end(va)); DQN_DEFER { va_end(va); };
LOCAL_PERSIST DqnFixedString2048 fmt_msg; LOCAL_PERSIST DqnFixedString2048 fmt_msg;
fmt_msg.Clear(); fmt_msg.Clear();
@ -7413,7 +7283,7 @@ DQN_FILE__LIST_DIR(DqnFile__PlatformListDir)
return nullptr; return nullptr;
} }
DQN_DEFER(FindClose(find_handle)); DQN_DEFER { FindClose(find_handle); };
bool stay_in_loop = true; bool stay_in_loop = true;
while (stay_in_loop) while (stay_in_loop)
{ {
@ -7453,7 +7323,7 @@ DQN_FILE__LIST_DIR(DqnFile__PlatformListDir)
return nullptr; return nullptr;
} }
DQN_DEFER(FindClose(find_handle)); DQN_DEFER { FindClose(find_handle); };
char **list = (char **)allocator->Calloc(1, sizeof(*list) * (curr_num_files)); char **list = (char **)allocator->Calloc(1, sizeof(*list) * (curr_num_files));
if (!list) 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 // 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")) if (size && FILE *file = fopen(path, "rb"))
{ {
DQN_DEFER(fclose(file)); DQN_DEFER { fclose(file); };
while (fgetc(file) != EOF) while (fgetc(file) != EOF)
{ {
(*size)++; (*size)++;
@ -7586,7 +7456,7 @@ DQN_FILE__LIST_DIR(DqnFile__PlatformListDir)
{ {
DIR *const dir_handle = opendir(dir); DIR *const dir_handle = opendir(dir);
if (!dir_handle) return nullptr; if (!dir_handle) return nullptr;
DQN_DEFER(closedir(dir_handle)); DQN_DEFER { closedir(dir_handle); };
struct dirent *dir_file = readdir(dir_handle); struct dirent *dir_file = readdir(dir_handle);
while (dir_file) while (dir_file)
@ -7606,7 +7476,7 @@ DQN_FILE__LIST_DIR(DqnFile__PlatformListDir)
{ {
DIR *const dir_handle = opendir(dir); DIR *const dir_handle = opendir(dir);
if (!dir_handle) return nullptr; 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); char **list = (char **)allocator->Calloc(1, sizeof(*list) * curr_num_files);
if (!list) if (!list)
@ -7670,13 +7540,14 @@ bool DqnFile::Open(wchar_t const *path, u32 flags_, Action action)
#endif #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 // 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; usize num_bytes_written = 0;
#if defined(DQN_IS_WIN32) #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_to_write = (DWORD)num_bytes_to_write;
DWORD bytes_written; DWORD bytes_written;
BOOL result = WriteFile(this->handle, (void *)buf, bytes_to_write, &bytes_written, nullptr); 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; const usize ITEMS_TO_WRITE = 1;
if (fwrite(buf, num_bytes_to_write, ITEMS_TO_WRITE, (FILE *)this->handle) == ITEMS_TO_WRITE) 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; num_bytes_written = ITEMS_TO_WRITE * num_bytes_to_write;
} }
#endif #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); DQN_LOGE("Could not open file: %s", path);
return result; return result;
} }
DQN_DEFER(file.Close()); DQN_DEFER { file.Close(); };
result = static_cast<u8 *>(stack->Push(file.size, push_type)); result = static_cast<u8 *>(stack->Push(file.size, push_type));
usize bytes_read = file.Read(result, file.size); 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); DQN_LOGE("Could not open file: %s", path);
return result; return result;
} }
DQN_DEFER(file.Close()); DQN_DEFER { file.Close(); };
result = static_cast<u8 *>(stack->Push(file.size, push_type)); result = static_cast<u8 *>(stack->Push(file.size, push_type));
usize bytes_read = file.Read(result, file.size); 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; return false;
} }
DQN_DEFER(file.Close()); DQN_DEFER { file.Close(); };
usize bytes_written = file.Write(buf, buf_size, 0); usize bytes_written = file.Write(buf, buf_size);
if (bytes_written != buf_size) if (bytes_written != buf_size)
{ {
DQN_LOGE("Bytes written did not match the buffer size, %zu != %zu", 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; return false;
} }
DQN_DEFER(file.Close()); DQN_DEFER { file.Close(); };
usize bytes_written = file.Write(buf, buf_size, 0); usize bytes_written = file.Write(buf, buf_size);
if (bytes_written != buf_size) if (bytes_written != buf_size)
{ {
DQN_LOGE("Bytes written did not match the buffer size, %zu != %zu", 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 = {}; DqnFile file = {};
bool result = file.Open(path, DqnFile::Flag::FileRead, DqnFile::Action::OpenOnly); bool result = file.Open(path, DqnFile::Flag::FileRead, DqnFile::Action::OpenOnly);
DQN_DEFER(file.Close()); DQN_DEFER { file.Close(); };
// TODO(doyle): Logging // TODO(doyle): Logging
if (file.size > buf_size || !result) 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 = {}; DqnFile file = {};
bool result = file.Open(path, DqnFile::Flag::FileRead, DqnFile::Action::OpenOnly); 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) if (!result || file.size > buf_size)
{ {
@ -8671,10 +8541,10 @@ DQN_FILE_SCOPE void DqnWin32_OutputDebugString(char const *fmt_str, ...)
OutputDebugStringA(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; 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; if (copied_len == buf_len) return -1;
// NOTE: Should always work if GetModuleFileName works and we're running an // 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"?> <?xml version="1.0" encoding="utf-8"?>
<AutoVisualizer xmlns="http://schemas.microsoft.com/vstudio/debugger/natvis/2010"> <AutoVisualizer xmlns="http://schemas.microsoft.com/vstudio/debugger/natvis/2010">
<Type Name="DqnArray&lt;*&gt;"> <Type Name="DqnArray&lt;*&gt;">
<DisplayString>{{count={count}/{max}}}</DisplayString> <DisplayString>{{len={len}/{max}}}</DisplayString>
<Expand> <Expand>
<Item Name="[count]">count</Item> <Item Name="[len]">len</Item>
<Item Name="[max]">max</Item> <Item Name="[max]">max</Item>
<ArrayItems> <ArrayItems>
<Size>count</Size> <Size>len</Size>
<ValuePointer>data</ValuePointer> <ValuePointer>data</ValuePointer>
</ArrayItems> </ArrayItems>
</Expand> </Expand>
</Type> </Type>
<Type Name="DqnMemStack::Block"> <Type Name="DqnMemStack::Block">
<DisplayString>{{used={used}/{size} prevBlock={prevBlock}}}</DisplayString> <DisplayString>{{used={head-tail}/{size} prev_block={prev_block}}}</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>
</Type> </Type>
<Type Name="DqnSlice&lt;*&gt;"> <Type Name="DqnSlice&lt;*&gt;">
@ -29,6 +21,16 @@
<StringView>data,s</StringView> <StringView>data,s</StringView>
</Type> </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"> <Type Name="DqnString">
<DisplayString>{{len={len}/{max} {str,s}}}</DisplayString> <DisplayString>{{len={len}/{max} {str,s}}}</DisplayString>
<StringView>str,s</StringView> <StringView>str,s</StringView>