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