From 2f681515f630eeef8906f7be5b4ecc3e46f2070a Mon Sep 17 00:00:00 2001 From: doyle Date: Wed, 15 Apr 2020 00:42:18 +1000 Subject: [PATCH] Remove old deprecated dqn lib --- Code/Deprecated/Dqn.natvis | 38 - Code/Deprecated/DqnFixedString.cpp | 77 - Code/Deprecated/DqnJson.cpp | 119 - Code/Deprecated/DqnMemStack.cpp | 520 -- Code/Deprecated/DqnOS.cpp | 50 - Code/Deprecated/DqnReflect.h | 919 -- Code/Deprecated/DqnUnitTest.cpp | 2024 ----- Code/Deprecated/DqnUnitTest.sln | 32 - Code/Deprecated/DqnVHashTable.cpp | 88 - Code/Deprecated/HandmadeMath.h | 2667 ------ Code/Deprecated/build.bat | 71 - Code/Deprecated/dqn.h | 8862 ------------------ Code/Deprecated/google-10000-english.txt | 10000 --------------------- Code/Deprecated/makefile | 3 - 14 files changed, 25470 deletions(-) delete mode 100644 Code/Deprecated/Dqn.natvis delete mode 100644 Code/Deprecated/DqnFixedString.cpp delete mode 100644 Code/Deprecated/DqnJson.cpp delete mode 100644 Code/Deprecated/DqnMemStack.cpp delete mode 100644 Code/Deprecated/DqnOS.cpp delete mode 100644 Code/Deprecated/DqnReflect.h delete mode 100644 Code/Deprecated/DqnUnitTest.cpp delete mode 100644 Code/Deprecated/DqnUnitTest.sln delete mode 100644 Code/Deprecated/DqnVHashTable.cpp delete mode 100644 Code/Deprecated/HandmadeMath.h delete mode 100644 Code/Deprecated/build.bat delete mode 100644 Code/Deprecated/dqn.h delete mode 100644 Code/Deprecated/google-10000-english.txt delete mode 100644 Code/Deprecated/makefile diff --git a/Code/Deprecated/Dqn.natvis b/Code/Deprecated/Dqn.natvis deleted file mode 100644 index d5a0801..0000000 --- a/Code/Deprecated/Dqn.natvis +++ /dev/null @@ -1,38 +0,0 @@ - - - - {{len={len}/{max}}} - - len - max - - len - data - - - - - - {{used={head-tail}/{size} prev_block={prev_block}}} - - - - {len={len} data={data,[len]}} - data,s - - - - {len={len} data={data,[len]}} - data,s - - - - {{len={len} {str,s}}} - str,s - - - - {{len={len}/{max} {str,s}}} - str,s - - diff --git a/Code/Deprecated/DqnFixedString.cpp b/Code/Deprecated/DqnFixedString.cpp deleted file mode 100644 index 2bb6371..0000000 --- a/Code/Deprecated/DqnFixedString.cpp +++ /dev/null @@ -1,77 +0,0 @@ -void DqnFixedString_Test() -{ - LOG_HEADER(); - { - DqnFixedString<512> str = DQN_BUFFER_STR_LIT("hello world"); - DQN_ASSERT(DqnStr_Cmp(str.str, "hello world") == 0); - - Log(Status::Ok, "Copy constructor DqnSlice"); - } - - { - DqnFixedString<512> zero = {}; - DqnFixedString<512> str = DQN_BUFFER_STR_LIT("hello world"); - str = zero; - DQN_ASSERT(str.len == 0 && str.str[0] == 0); - - DqnSlice helloSlice = DQN_BUFFER_STR_LIT("hello"); - str = helloSlice; - DQN_ASSERT(DqnStr_Cmp(str.str, "hello") == 0); - - Log(Status::Ok, "Copy constructor (DqnFixedString<>)"); - } - - { - DqnFixedString<512> str = DQN_BUFFER_STR_LIT("hello world"); - DQN_ASSERT(str.Sprintf("hello %s", "sailor")); - DQN_ASSERTM(DqnStr_Cmp(str.str, "hello sailor") == 0, "Result: %s", str.str); - - Log(Status::Ok, "Sprintf"); - } - - { - { - DqnFixedString<512> str = DQN_BUFFER_STR_LIT("hello world"); - 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); - } - - { - DqnFixedString<512> str = DQN_BUFFER_STR_LIT("hello world"); - 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); - } - - Log(Status::Ok, "Concatenation, operator +=, SprintfAppend"); - } - - { - DqnFixedString<512> str; - str = "hello big world"; - DQN_ASSERT(DqnStr_Cmp(str.str, "hello big world") == 0); - str = DqnFixedString<512>("goodbye", DQN_CHAR_COUNT("goodbye")); - DQN_ASSERT(DqnStr_Cmp(str.str, "goodbye") == 0); - - Log(Status::Ok, "Copy constructor (char const *str, int len)"); - } - - { - DqnFixedString<512> str = DQN_BUFFER_STR_LIT("hello world"); - 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); - - Log(Status::Ok, "Operator +"); - } - - { - DqnFixedString<512> str = "localhost"; - str.SprintfAppend(":%d", 16832); - str += "/json_rpc"; - DQN_ASSERT(str.len == 24 && DqnStr_Cmp("localhost:16832/json_rpc", str.str) == 0); - - Log(Status::Ok, "Copy constructor, sprintf, operator +="); - } -} diff --git a/Code/Deprecated/DqnJson.cpp b/Code/Deprecated/DqnJson.cpp deleted file mode 100644 index 65cb2eb..0000000 --- a/Code/Deprecated/DqnJson.cpp +++ /dev/null @@ -1,119 +0,0 @@ -void DqnJson_Test() -{ - LOG_HEADER(); - char const json[] = - R"FOO( - { - "result": { - "cumulative_difficulty": 282912831023, - "difficulty": 18293, - "name": "Block", - "array_of_objects": [{ - "hash": "83abdc3f", - "time": 102981029381, - }, { - "hash": "12acf73d", - "time": 123761239789, - }], - "time": 3498573485, - "embed_object": { - "proof": "axcbde", - "signature": "l9382kjabmznmx129aslzejs" - } - "bits": [1, 0, 1, 1, 0, 1, 0], - "hex": ["AF", "BE", "0C", "FF"], - "extra": [123], - "serialise": [], - }, - } - )FOO"; - - DqnJson result = DqnJson_Get(DqnSlice(json, DQN_ARRAY_COUNT(json)), DQN_BUFFER_STR_LIT("result")); - DqnJson cum_difficulty = DqnJson_Get(result, DQN_BUFFER_STR_LIT("cumulative_difficulty")); - DqnJson difficulty = DqnJson_Get(result, DQN_BUFFER_STR_LIT("difficulty")); - DqnJson name = DqnJson_Get(result, DQN_BUFFER_STR_LIT("name")); - DqnJson array_of_objects = DqnJson_Get(result, DQN_BUFFER_STR_LIT("array_of_objects")); - DqnJson time = DqnJson_Get(result, DQN_BUFFER_STR_LIT("time")); - DqnJson embed_object = DqnJson_Get(result, DQN_BUFFER_STR_LIT("embed_object")); - DqnJson bits = DqnJson_Get(result, DQN_BUFFER_STR_LIT("bits")); - DqnJson hex = DqnJson_Get(result, DQN_BUFFER_STR_LIT("hex")); - DqnJson extra = DqnJson_Get(result, DQN_BUFFER_STR_LIT("extra")); - DqnJson serialise = DqnJson_Get(result, DQN_BUFFER_STR_LIT("serialise")); - - DQN_ASSERT(DQN_BUFFER_STRCMP(cum_difficulty.value, DQN_BUFFER_STR_LIT("282912831023"), Dqn::IgnoreCase::No)); - DQN_ASSERT(DQN_BUFFER_STRCMP(difficulty.value, DQN_BUFFER_STR_LIT("18293"), Dqn::IgnoreCase::No)); - DQN_ASSERT(DQN_BUFFER_STRCMP(name.value, DQN_BUFFER_STR_LIT("\"Block\""), Dqn::IgnoreCase::No)); - - { - DQN_ASSERT(array_of_objects.IsArray() && array_of_objects.num_entries == 2); - isize count = 0; - while(DqnJson it = DqnJson_GetNextArrayItem(&array_of_objects)) - { - DqnJson hash = DqnJson_Get(it, DQN_BUFFER_STR_LIT("hash")); - DqnJson time2 = DqnJson_Get(it, DQN_BUFFER_STR_LIT("time")); - if (count == 0) - { - DQN_ASSERT(DQN_BUFFER_STRCMP(hash.value, DQN_BUFFER_STR_LIT("\"83abdc3f\""), Dqn::IgnoreCase::No)); - DQN_ASSERT(DQN_BUFFER_STRCMP(time2.value, DQN_BUFFER_STR_LIT("102981029381"), Dqn::IgnoreCase::No)); - } - else - { - DQN_ASSERT(DQN_BUFFER_STRCMP(hash.value, DQN_BUFFER_STR_LIT("\"12acf73d\""), Dqn::IgnoreCase::No)); - DQN_ASSERT(DQN_BUFFER_STRCMP(time2.value, DQN_BUFFER_STR_LIT("123761239789"), Dqn::IgnoreCase::No)); - } - ++count; - } - - } - - { - DqnJson proof = DqnJson_Get(embed_object, DQN_BUFFER_STR_LIT("proof")); - DqnJson signature = DqnJson_Get(embed_object, DQN_BUFFER_STR_LIT("signature")); - DQN_ASSERT(DQN_BUFFER_STRCMP(proof.value, DQN_BUFFER_STR_LIT("\"axcbde\""), Dqn::IgnoreCase::No)); - DQN_ASSERT(DQN_BUFFER_STRCMP(signature.value, DQN_BUFFER_STR_LIT("\"l9382kjabmznmx129aslzejs\""), Dqn::IgnoreCase::No)); - } - - DQN_ASSERT(DQN_BUFFER_STRCMP(time.value, DQN_BUFFER_STR_LIT("3498573485"), Dqn::IgnoreCase::No)); - - { - DQN_ASSERT(bits.IsArray() && bits.num_entries == 7); - DqnJson bits_array[7]; - isize bitsIndex = 0; - - while(DqnJson it = DqnJson_GetNextArrayItem(&bits)) - bits_array[bitsIndex++] = it; - - DQN_ASSERT(bitsIndex == DQN_ARRAY_COUNT(bits_array)); - DQN_ASSERT(DQN_BUFFER_STRCMP(bits_array[0].value, DQN_BUFFER_STR_LIT("1"), Dqn::IgnoreCase::No)); - DQN_ASSERT(DQN_BUFFER_STRCMP(bits_array[1].value, DQN_BUFFER_STR_LIT("0"), Dqn::IgnoreCase::No)); - DQN_ASSERT(DQN_BUFFER_STRCMP(bits_array[2].value, DQN_BUFFER_STR_LIT("1"), Dqn::IgnoreCase::No)); - DQN_ASSERT(DQN_BUFFER_STRCMP(bits_array[3].value, DQN_BUFFER_STR_LIT("1"), Dqn::IgnoreCase::No)); - DQN_ASSERT(DQN_BUFFER_STRCMP(bits_array[4].value, DQN_BUFFER_STR_LIT("0"), Dqn::IgnoreCase::No)); - DQN_ASSERT(DQN_BUFFER_STRCMP(bits_array[5].value, DQN_BUFFER_STR_LIT("1"), Dqn::IgnoreCase::No)); - DQN_ASSERT(DQN_BUFFER_STRCMP(bits_array[6].value, DQN_BUFFER_STR_LIT("0"), Dqn::IgnoreCase::No)); - } - - { - DQN_ASSERT(hex.IsArray() && hex.num_entries == 4); - DqnJson hex_array[4]; - isize hex_index = 0; - - while(DqnJson it = DqnJson_GetNextArrayItem(&hex)) - hex_array[hex_index++] = it; - - DQN_ASSERT(hex_index == DQN_ARRAY_COUNT(hex_array)); - DQN_ASSERT(DQN_BUFFER_STRCMP(hex_array[0].value, DQN_BUFFER_STR_LIT("\"AF\""), Dqn::IgnoreCase::No)); - DQN_ASSERT(DQN_BUFFER_STRCMP(hex_array[1].value, DQN_BUFFER_STR_LIT("\"BE\""), Dqn::IgnoreCase::No)); - DQN_ASSERT(DQN_BUFFER_STRCMP(hex_array[2].value, DQN_BUFFER_STR_LIT("\"0C\""), Dqn::IgnoreCase::No)); - DQN_ASSERT(DQN_BUFFER_STRCMP(hex_array[3].value, DQN_BUFFER_STR_LIT("\"FF\""), Dqn::IgnoreCase::No)); - } - - { - DQN_ASSERT(extra.IsArray() && extra.num_entries == 1); - while(DqnJson it = DqnJson_GetNextArrayItem(&extra)) - { - DQN_ASSERT(DQN_BUFFER_STRCMP(it.value, DQN_BUFFER_STR_LIT("123"), Dqn::IgnoreCase::No)); - } - } - Log(Status::Ok, "DqnJson sample structure parsed"); -} diff --git a/Code/Deprecated/DqnMemStack.cpp b/Code/Deprecated/DqnMemStack.cpp deleted file mode 100644 index 358d79d..0000000 --- a/Code/Deprecated/DqnMemStack.cpp +++ /dev/null @@ -1,520 +0,0 @@ -FILE_SCOPE void DqnMemStack_Test() -{ - LOG_HEADER(); - - // Check Alignment - if (1) - { - auto stack = DqnMemStack(DQN_MEGABYTE(1), Dqn::ZeroMem::Yes, 0, DqnMemTracker::Flag::Simple); - - i32 const ALIGN64 = 64; - i32 const ALIGN16 = 16; - i32 const ALIGN4 = 4; - DqnMemStack::PushType push_type = DqnMemStack::PushType::Head; - if (1) - { - u8 *result1 = (u8 *)stack.Push_(2, push_type, ALIGN4); - u8 *result2 = (u8 *)DQN_ALIGN_POW_N(result1, ALIGN4); - DQN_ASSERT(result1 == result2); - stack.Pop(result1); - DQN_ASSERT(stack.block->head == stack.block->memory); - } - - if (1) - { - u8 *result1 = (u8 *)stack.Push_(120, push_type, ALIGN16); - u8 *result2 = (u8 *)DQN_ALIGN_POW_N(result1, ALIGN16); - DQN_ASSERT(result1 == result2); - stack.Pop(result1); - DQN_ASSERT(stack.block->head == stack.block->memory); - } - - if (1) - { - u8 *result1 = (u8 *)stack.Push_(12, push_type, ALIGN64); - u8 *result2 = (u8 *)DQN_ALIGN_POW_N(result1, ALIGN64); - DQN_ASSERT(result1 == result2); - stack.Pop(result1); - DQN_ASSERT(stack.block->head == stack.block->memory); - } - - stack.Free(); - Log(Status::Ok, "Check allocated alignment to 4, 16, 64"); - } - - // Check Non-Expandable - if (1) - { - 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); - - stack.Free(); - Log(Status::Ok, "Check non-expandable flag prevents expansion."); - } - - // Check Expansion - if (1) - { - auto stack = DqnMemStack(DQN_MEGABYTE(1), Dqn::ZeroMem::Yes); - auto *old_block = stack.block; - DQN_ASSERT(old_block); - DQN_ASSERT(old_block->size == DQN_MEGABYTE(1)); - DQN_ASSERT(old_block->head == old_block->head); - DQN_ASSERT(old_block->tail == old_block->tail); - DQN_ASSERT(old_block->prev_block == nullptr); - - auto *result1 = stack.Push_(DQN_MEGABYTE(2)); - DQN_ASSERT(result1); - DQN_ASSERT(stack.block->prev_block == old_block); - DQN_ASSERT(stack.block != old_block); - - Log(Status::Ok, "Check memory stack allocates additional memory blocks."); - stack.Free(); - } - - // Temporary Regions - if (1) - { - // Check temporary regions - if (1) - { - auto stack = DqnMemStack(DQN_MEGABYTE(1), Dqn::ZeroMem::Yes, 0, DqnMemTracker::Flag::Simple); - - 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 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 != head_before); - DQN_ASSERT(stack.block->tail == tail_before); - 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 != block_to_return_to); - DQN_ASSERT(stack.mem_region_count == 1); - } - - DQN_ASSERT(stack.block == block_to_return_to); - DQN_ASSERT(stack.block->head == head_before); - DQN_ASSERT(stack.block->tail == tail_before); - - stack.Free(); - } - - // Check temporary regions keep state - if (1) - { - auto stack = DqnMemStack(DQN_MEGABYTE(1), Dqn::ZeroMem::Yes, 0, DqnMemTracker::Flag::Simple); - 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 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 != head_before); - DQN_ASSERT(stack.block->tail == tail_before); - 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 != block_to_return_to); - DQN_ASSERT(stack.mem_region_count == 1); - stack.MemRegionSave(&mem_guard1); - } - - 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(); - } - - // Check temporary regions with tail and head pushes - if (1) - { - auto stack = DqnMemStack(DQN_MEGABYTE(1), Dqn::ZeroMem::Yes, 0, DqnMemTracker::Flag::Simple); - - auto *pop1 = stack.Push_(222); - auto *pop2 = stack.Push_(333, DqnMemStack::PushType::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 mem_guard1 = stack.MemRegionScope(); - auto *result2 = stack.Push_(100); - auto *result3 = stack.Push_(100, DqnMemStack::PushType::Tail); - auto *result4 = stack.Push_(100); - auto *result5 = stack.Push_(100, DqnMemStack::PushType::Tail); - DQN_ASSERT(result2 && result3 && result4 && result5); - DQN_ASSERT(result3 > result5); - DQN_ASSERT(result2 < result4); - 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 == block_to_return_to->memory); - - // Force allocation of new block - auto *result6 = stack.Push_(DQN_MEGABYTE(5)); - DQN_ASSERT(result6); - DQN_ASSERT(stack.block != block_to_return_to); - DQN_ASSERT(stack.mem_region_count == 1); - } - - 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); - stack.Pop(pop2); - DQN_ASSERT(stack.block->head == stack.block->memory); - DQN_ASSERT(stack.block->tail == stack.block->memory + stack.block->size); - - stack.Free(); - } - Log(Status::Ok, "Temporary regions revert state and save state"); - } - - // Check Fixed Mem Init - if (1) - { - // Check success - if (1) - { - isize const buf_size = sizeof(DqnMemStack::Block) * 5; - char buf[buf_size] = {}; - auto stack = DqnMemStack(&buf, buf_size, Dqn::ZeroMem::No); - - DQN_ASSERT(stack.block); - DQN_ASSERT(stack.block->prev_block == false); - DQN_ASSERT(stack.mem_region_count == 0); - DQN_ASSERT(stack.flags == DqnMemStack::Flag::NonExpandable); - - auto *result1 = stack.Push_(32); - DQN_ASSERT(result1); - stack.Pop(result1); - - auto *result2 = stack.Push_(buf_size * 2); - DQN_ASSERT(result2 == nullptr); - DQN_ASSERT(stack.block); - DQN_ASSERT(stack.block->prev_block == false); - DQN_ASSERT(stack.mem_region_count == 0); - DQN_ASSERT(stack.flags == DqnMemStack::Flag::NonExpandable); - - stack.Free(); - } - - Log(Status::Ok, "Checked fixed mem initialisation"); - } - - // Check Freeing Blocks - if (1) - { - usize size = 32; - usize additional_size = DqnMemStack::MINIMUM_BLOCK_SIZE; - - auto stack = DqnMemStack(size, Dqn::ZeroMem::Yes, 0); - auto *block1 = stack.block; - - size += additional_size; - auto *result1 = stack.Push_(size); - auto *block2 = stack.block; - - size += additional_size; - auto *result2 = stack.Push_(size); - auto *block3 = stack.block; - - size += additional_size; - auto *result3 = stack.Push_(size); - auto *block4 = stack.block; - - size += additional_size; - auto *result4 = stack.Push_(size); - auto *block5 = stack.block; - - DQN_ASSERT(result1 && result2 && result3 && result4); - DQN_ASSERT(block1 && block2 && block3 && block4 && block5); - DQN_ASSERT(block5->prev_block == block4); - DQN_ASSERT(block4->prev_block == block3); - DQN_ASSERT(block3->prev_block == block2); - DQN_ASSERT(block2->prev_block == block1); - DQN_ASSERT(block1->prev_block == nullptr); - - 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.FreeBlock(block5)); - DQN_ASSERT(stack.block == block3); - DQN_ASSERT(block3->prev_block == block2); - DQN_ASSERT(block2->prev_block == block1); - DQN_ASSERT(block1->prev_block == nullptr); - - stack.Free(); - DQN_ASSERT(stack.block == nullptr); - Log(Status::Ok, "Check freeing arbitrary blocks and freeing"); - } - - // Check bounds guard places magic values - if (1) - { - auto stack = DqnMemStack(DQN_MEGABYTE(1), Dqn::ZeroMem::Yes, 0, DqnMemTracker::Flag::Simple); - char *result = static_cast(stack.Push_(64)); - - // TODO(doyle): check head and tail are adjacent to the bounds of the allocation - u32 *head = stack.tracker.PtrToHeadGuard(result); - u32 *tail = stack.tracker.PtrToTailGuard(result); - DQN_ASSERT(*head == DqnMemTracker::HEAD_GUARD_VALUE); - DQN_ASSERT(*tail == DqnMemTracker::TAIL_GUARD_VALUE); - - stack.Free(); - Log(Status::Ok, "Bounds guards are placed adjacent and have magic values."); - } - - if (1) - { - // Push_ to tail and head - if (1) - { - DqnMemStack stack = DqnMemStack(DQN_MEGABYTE(1), Dqn::ZeroMem::Yes, 0, DqnMemTracker::Flag::Simple); - - auto *result1 = stack.Push_(100); - auto *result2 = stack.Push_(100, DqnMemStack::PushType::Tail); - 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(head_before == stack.block->head) - DQN_ASSERT(tail_before != stack.block->tail) - - stack.Pop(result1); - DQN_ASSERT(stack.block->prev_block == false); - DQN_ASSERT(stack.block->head == stack.block->memory); - DQN_ASSERT(stack.block->tail == stack.block->memory + stack.block->size); - stack.Free(); - Log(Status::Ok, "Push_, pop to tail and head."); - } - - // Expansion with tail - if (1) - { - // Push_ too much to tail causes expansion - if (1) - { - DqnMemStack stack = DqnMemStack(DQN_MEGABYTE(1), Dqn::ZeroMem::Yes, 0, DqnMemTracker::Flag::Simple); - - auto *result1 = stack.Push_(100); - DQN_ASSERT(stack.block->prev_block == nullptr); - DQN_ASSERT(stack.block->head > stack.block->memory && stack.block->head < stack.block->tail); - DQN_ASSERT(stack.block->tail == stack.block->memory + stack.block->size); - auto *block_before = stack.block; - - auto *result2 = stack.Push_(DQN_MEGABYTE(1), DqnMemStack::PushType::Tail); - DQN_ASSERT(result2 && result1); - DQN_ASSERT(result2 != result1); - DQN_ASSERT(stack.block->prev_block == block_before); - DQN_ASSERT(stack.block != block_before); - - DQN_ASSERT(stack.block->head == stack.block->memory); - DQN_ASSERT(stack.block->tail < stack.block->memory + stack.block->size && - stack.block->tail >= stack.block->head); - - stack.Pop(result2); - DQN_ASSERT(block_before == stack.block); - - stack.Pop(result1); - DQN_ASSERT(block_before == stack.block); - - stack.Free(); - } - - // Push_ too much to tail fails to expand when non expandable - if (1) - { - DqnMemStack stack = DqnMemStack(DQN_MEGABYTE(1), Dqn::ZeroMem::Yes, DqnMemStack::Flag::NonExpandable); - - auto *result1 = stack.Push_(100); - DQN_ASSERT(stack.block->prev_block == nullptr); - DQN_ASSERT(stack.block->head != stack.block->memory); - DQN_ASSERT(stack.block->tail == stack.block->memory + stack.block->size); - auto *block_before = stack.block; - - auto *result2 = stack.Push_(DQN_MEGABYTE(1), DqnMemStack::PushType::Tail); - DQN_ASSERT(result2 == nullptr); - DQN_ASSERT(stack.block->prev_block == nullptr); - DQN_ASSERT(stack.block == block_before); - DQN_ASSERT(stack.block->head > stack.block->memory && stack.block->head < stack.block->tail); - DQN_ASSERT(stack.block->tail == stack.block->memory + stack.block->size); - - stack.Pop(result2); - DQN_ASSERT(block_before == stack.block); - - stack.Pop(result1); - DQN_ASSERT(block_before == stack.block); - - stack.Free(); - } - - Log(Status::Ok, "Non-Expanding and expanding stack with tail push."); - } - } - - // Check stack allocator mem api callbacks - if (1) - { -#if 0 - // Realloc in same block and allow it to grow in place. - if (1) - { - // Using push on head - if (1) - { - DqnMemStack stack = DqnMemStack(DQN_MEGABYTE(1), Dqn::ZeroMem::Yes, DqnMemStack::Flag::BoundsGuard); - auto *api = &stack.myHeadAPI; - - auto *block_before = stack.block; - auto *head_before = stack.block->head; - - isize buf_size = 16; - char *buf = (char *)stack.Push_(buf_size); - DqnMem_Set(buf, 'X', buf_size); - for (auto i = 0; i < buf_size; i++) DQN_ASSERT(buf[i] == 'X'); - - isize old_buf_size = buf_size; - buf_size = 32; - buf = (char *)api->Realloc(buf, old_buf_size, buf_size); - for (auto i = 0; i < old_buf_size; i++) DQN_ASSERT(buf[i] == 'X'); - DqnMem_Set(buf, '@', buf_size); - - DQN_ASSERT(block_before == stack.block); - DQN_ASSERT(head_before < stack.block->head); - stack.Pop(buf); - - DQN_ASSERT(block_before == stack.block); - 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::ZeroMem::Yes, DqnMemStack::Flag::BoundsGuard); - auto *api = &stack.myHeadAPI; - - auto *block_before = stack.block; - auto *tail_before = stack.block->tail; - - isize buf_size = 16; - char *buf = (char *)stack.Push_(buf_size, DqnMemStack::PushType::Tail); - DqnMem_Set(buf, 'X', buf_size); - for (auto i = 0; i < buf_size; i++) DQN_ASSERT(buf[i] == 'X'); - - isize old_buf_size = buf_size; - buf_size = 32; - buf = (char *)api->Realloc(buf, old_buf_size, buf_size); - for (auto i = 0; i < old_buf_size; i++) DQN_ASSERT(buf[i] == 'X'); - DqnMem_Set(buf, '@', buf_size); - - DQN_ASSERT(block_before == stack.block); - DQN_ASSERT(tail_before > stack.block->tail); - stack.Pop(buf); - - DQN_ASSERT(block_before == stack.block); - DQN_ASSERT(tail_before == stack.block->tail); - DQN_ASSERT(stack.block->head == stack.block->memory); - stack.Free(); - } - Log(Status::Ok, "Allocator MemAPI callback, realloc grow in place"); - } - - // Realloc in same block and insufficient size and expand - if (1) - { - // Using push on head - if (1) - { - auto stack = DqnMemStack(DQN_MEGABYTE(1), Dqn::ZeroMem::Yes, DqnMemStack::Flag::BoundsGuard); - auto *api = &stack.myHeadAPI; - - auto *block_before = stack.block; - auto *head_before = stack.block->head; - - isize buf_size = 16; - char *buf = (char *)stack.Push_(buf_size); - DqnMem_Set(buf, 'X', buf_size); - for (auto i = 0; i < buf_size; i++) DQN_ASSERT(buf[i] == 'X'); - - isize old_buf_size = buf_size; - buf_size = DQN_MEGABYTE(2); - buf = (char *)api->Realloc(buf, old_buf_size, buf_size); - for (auto i = 0; i < old_buf_size; i++) DQN_ASSERT(buf[i] == 'X'); - DqnMem_Set(buf, '@', buf_size); - - DQN_ASSERT(block_before == stack.block->prev_block); - stack.Pop(buf); - - DQN_ASSERT(block_before == stack.block); - 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::ZeroMem::Yes, DqnMemStack::Flag::BoundsGuard); - auto *api = &stack.myHeadAPI; - - auto *block_before = stack.block; - auto *tail_before = stack.block->tail; - - isize buf_size = 16; - char *buf = (char *)stack.Push_(buf_size, DqnMemStack::PushType::Tail); - DqnMem_Set(buf, 'X', buf_size); - for (auto i = 0; i < buf_size; i++) DQN_ASSERT(buf[i] == 'X'); - - isize old_buf_size = buf_size; - buf_size = DQN_MEGABYTE(2); - buf = (char *)api->Realloc(buf, old_buf_size, buf_size); - for (auto i = 0; i < old_buf_size; i++) - DQN_ASSERT(buf[i] == 'X'); - DqnMem_Set(buf, '@', buf_size); - - DQN_ASSERT(block_before != stack.block); - DQN_ASSERT(block_before == stack.block->prev_block); - stack.Pop(buf); - - DQN_ASSERT(block_before == stack.block); - DQN_ASSERT(tail_before == stack.block->tail); - - DQN_ASSERT(stack.block->head == stack.block->memory); - stack.Free(); - } - Log(Status::Ok, "Allocator MemAPI callback, realloc insufficient size so expand"); - } - - // TODO(doyle): Realloc to smaller size logic -#endif - } -} - diff --git a/Code/Deprecated/DqnOS.cpp b/Code/Deprecated/DqnOS.cpp deleted file mode 100644 index 0125232..0000000 --- a/Code/Deprecated/DqnOS.cpp +++ /dev/null @@ -1,50 +0,0 @@ -struct DqnProcess -{ -}; - -void DqnOS_Test() -{ - // pid_t pid = vfork(); - // if (pid == 0) - // { - // char const *argv[] = {"jim", "jams", NULL}; - // char const *envp[] = {"some", "environment", NULL}; - // chdir("/home/usr/loki/"); - // execve(cmd, argv, envp); - // perror("Could not execute"); - // } -#if defined(DQN__IS_WIN32) - // CreateProcessW(); - - WSAData wsaData; - int result = WSAStartup(MAKEWORD(2, 2), &wsaData); - if (result != 0) - { - fprintf(stderr, "WSAStartup failed: %d\n", result); - return; - } - - addrinfo hints = {}; - hints.ai_family = AF_UNSPEC; - hints.ai_socktype = SOCK_STREAM; - hints.ai_protocol = IPPROTO_TCP; - - addrinfo *foundAddr = nullptr; - result = getaddrinfo("127.0.0.1", "38151", &hints, &foundAddr); - if (result != 0) - { - fprintf(stderr, "getaddrinfo failed: %d\n", result); - WSACleanup(); - return; - } - - SOCKET connectSocket = socket(foundAddr->ai_family, foundAddr->ai_socktype, foundAddr->ai_protocol); - if (connectSocket == INVALID_SOCKET) - { - fprintf(stderr, "socket failed: %d\n", WSAGetLastError()); - freeaddrinfo(foundAddr); - WSACleanup(); - return; - } -#endif -} diff --git a/Code/Deprecated/DqnReflect.h b/Code/Deprecated/DqnReflect.h deleted file mode 100644 index 60ffd33..0000000 --- a/Code/Deprecated/DqnReflect.h +++ /dev/null @@ -1,919 +0,0 @@ -#ifndef DQN_REFLECT_H -#define DQN_REFLECT_H - -#define DQN_REFLECT -#define DQN_REFLECT_META(...) - -// -// HOW TO REFLECT ANNOTATED CODE -// Define in the preprocessor, DQN_REFLECT_IMPLEMENTATION and compile -// Dqn_Reflect.h to produce the metaprogram binary. Run the binary on the -// desired C++ source files which will generate a DqnReflect_Generated.cpp -// - -// -// DqnReflect.exe .[c|cpp|h] ... -// - -// -// HOW TO ANNOTATE CODE -// This header file should be included in all files containing information you -// wish to reflect, you may reflect C-like data structures, such as in the -// following example. -// - -// -// Your Source Code -// - -#if 0 -DQN_REFLECT enum struct OpenGLShader -{ - Invalid, - Rect DQN_REFLECT_META(VertexShaderFilePath = "Rect.vert", FragmentShaderFilePath = "Rect.frag"), - Text DQN_REFLECT_META(VertexShaderFilePath = "Text.vert", FragmentShaderFilePath = "Text.frag"), -}; -#endif - -// -// Generated code in DqnReflect_Generated.cpp -// - -#if 0 -#ifndef DQN_REFLECT_GENERATED_H -#define DQN_REFLECT_GENERATED_H - -// -// OpenGL.h -// - -#if !defined(DQN_REFLECT_DISABLE_OPENGL_H) -char const *DqnReflect_OpenGLShader_Strings[] = {"Invalid", "Bitmap", "Text" }; - -char const *DqnReflect_EnumString(OpenGLShader val) -{ - if (val == OpenGLShader::Invalid) return DqnReflect_OpenGLShader_Strings[0]; // "Invalid" - if (val == OpenGLShader::Rect) return DqnReflect_OpenGLShader_Strings[1]; // "Rect" - if (val == OpenGLShader::Bitmap) return DqnReflect_OpenGLShader_Strings[2]; // "Bitmap" - return nullptr; -} - -char const *DqnReflect_VertexFilePathMetadata(OpenGLShader val) -{ - if (val == OpenGLShader::Rect) return "Rect.vert"; - if (val == OpenGLShader::Bitmap) return "Bitmap.vert"; - return nullptr; -} - -char const *DqnReflect_FragmentFilePathMetadata(OpenGLShader val) -{ - if (val == OpenGLShader::Rect) return "Rect.frag"; - if (val == OpenGLShader::Bitmap) return "Bitmap.frag"; - return nullptr; -} - -#endif // DQN_REFLECT_DISABLE_OPENGL_H - -#endif // DQN_REFLECT_GENERATED_H -#endif - -#ifdef DQN_REFLECT_IMPLEMENTATION -#include -#include -#include -#include -#include -#include - -using usize = size_t; -using isize = ptrdiff_t; -using i64 = int64_t; -using i32 = int32_t; -using b32 = int32_t; -using u8 = uint8_t; - -template -struct Defer -{ - Proc proc; - Defer(Proc p) : proc(p) {} - ~Defer() { proc(); } -}; - -struct DeferHelper -{ - template - Defer operator+(Lambda lambda) { return Defer(lambda); } -}; - -#define STR_LITERAL(str) {str, CHAR_COUNT(str)} -struct StringLiteral -{ - StringLiteral() = default; - StringLiteral(char *string, int string_len) : str(string) , len(string_len) { } - char *str; - int len; -}; - -template -struct LinkedList -{ - T data; - LinkedList *next; -}; - -#define REFLECT_MAX(a, b) ((a) > (b)) ? (a) : (b) -#define ARRAY_COUNT(str) sizeof(str)/sizeof(str[0]) -#define CHAR_COUNT(str) (ARRAY_COUNT(str) - 1) -#define TOKEN_COMBINE(x, y) x ## y -#define TOKEN_COMBINE2(x, y) TOKEN_COMBINE(x, y) -#define DEFER auto const TOKEN_COMBINE(defer_lambda_, __COUNTER__) = DeferHelper() + [&]() - -#define KILOBYTE(val) (1024ULL * (val)) -#define MEGABYTE(val) (1024ULL * KILOBYTE(val)) - -// -// Memory Utilities -// - -struct MemArena -{ - void *memory; - usize size; - usize used; -}; - -struct MemArenaScopedRegion -{ - MemArenaScopedRegion (MemArena *arena_, usize used_) : arena(arena_), used(used_) {} - ~MemArenaScopedRegion() { arena->used = used; } - MemArena *arena; - usize used; -}; - -static MemArena global_main_arena; - -#define MEM_ARENA_ALLOC_ARRAY(arena, Type, num) static_cast(MemArena_Alloc(arena, sizeof(Type) * num)) -#define MEM_ARENA_ALLOC_STRUCT(arena, Type) static_cast(MemArena_Alloc(arena, sizeof(Type))) -MemArena MemArena_Init(void *memory, usize size) -{ - MemArena result = {}; - result.memory = memory; - result.size = size; - result.used = 0; - return result; -} - -MemArenaScopedRegion MemArena_MakeScopedRegion(MemArena *arena) -{ - return MemArenaScopedRegion(arena, arena->used); -} - -void *MemArena_Alloc(MemArena *arena, usize size) -{ - assert(arena->used + size <= arena->size); - void *result = static_cast(arena->memory) + arena->used; - arena->used += size; - return result; -} - -template void EraseStableFromCArray(T *array, isize len, isize max, isize index); -#define FIXED_ARRAY_TEMPLATE_DECL template -FIXED_ARRAY_TEMPLATE_DECL struct FixedArray -{ - FixedArray() = default; - T data[MAX_]; - isize len; - isize Max() const { return MAX_; } - T const &operator[] (isize i) const { assert(i >= 0 && i < len); return data[i]; } - T &operator[] (isize i) { assert(i >= 0 && i < len); return data[i]; } - T const *begin () const { return data; } - T const *end () const { return data + len; } - T *begin () { return data; } - T *end () { return data + len; } -}; -FIXED_ARRAY_TEMPLATE_DECL FixedArray FixedArray_Init (T const *item, int num) { FixedArray result = {}; FixedArray_Add(&result, item, num); return result; } -FIXED_ARRAY_TEMPLATE_DECL T *FixedArray_Add (FixedArray *a, T const *items, int num) { assert(a->len + num <= MAX_); T *result = static_cast(MemCopy(a->data + a->len, items, sizeof(T) * num)); a->len += num; return result; } -FIXED_ARRAY_TEMPLATE_DECL T *FixedArray_Add (FixedArray *a, T const item) { assert(a->len < MAX_); a->data[a->len++] = item; return &a->data[a->len - 1]; } -FIXED_ARRAY_TEMPLATE_DECL T *FixedArray_Make (FixedArray *a, int num) { assert(a->len + num <= MAX_); T *result = a->data + a->len; a->len += num; return result;} -FIXED_ARRAY_TEMPLATE_DECL void FixedArray_Clear (FixedArray *a) { a->len = 0; } -FIXED_ARRAY_TEMPLATE_DECL void FixedArray_EraseStable (FixedArray *a, isize index) { EraseStableFromCArray(a->data, a->len--, a.Max(), index); } -FIXED_ARRAY_TEMPLATE_DECL void FixedArray_EraseUnstable(FixedArray *a, isize index) { assert(index >= 0 && index < a->len); if (--a->len == 0) return; a->data[index] = a->data[a->len]; } - -// -// String Utilities -// - -b32 CharIsAlpha (char ch) { return (ch >= 'A' && ch <= 'Z') || (ch >= 'a' && ch <= 'z'); } -b32 CharIsDigit (char ch) { return (ch >= '0' && ch <= '9'); } -b32 CharIsAlphaNum (char ch) { return CharIsAlpha(ch) || CharIsDigit(ch); } -b32 CharIsWhitespace(char ch) { return (ch == ' ' || ch == '\t' || ch == '\n' || ch == '\r'); } - -char const *StrSkipToChar(char const *src, char ch) -{ - char const *result = src; - while (result && result[0] && result[0] != ch) ++result; - return result; -} - -char const *StrSkipToNextAlphaNum(char const *src) -{ - char const *result = src; - while (result && result[0] && !CharIsAlphaNum(result[0])) ++result; - return result; -} - -char const *StrSkipToNextDigit(char const *src) -{ - char const *result = src; - while (result && result[0] && !CharIsDigit(result[0])) ++result; - return result; -} - -char const *StrSkipToNextChar(char const *src) -{ - char const *result = src; - while (result && result[0] && !CharIsAlpha(result[0])) ++result; - return result; -} - -char const *StrSkipToNextWord(char const *src) -{ - char const *result = src; - while (result && result[0] && !CharIsWhitespace(result[0])) ++result; - while (result && result[0] && CharIsWhitespace(result[0])) ++result; - return result; -} - -char const *StrSkipToNextWhitespace(char const *src) -{ - char const *result = src; - while (result && result[0] && !CharIsWhitespace(result[0])) ++result; - return result; -} - -char const *StrSkipWhitespace(char const *src) -{ - char const *result = src; - while (result && result[0] && CharIsWhitespace(result[0])) ++result; - return result; -} - -char const *StrSkipToNextWordInplace(char const **src) { *src = StrSkipToNextWord(*src); return *src; } -char const *StrSkipWhitespaceInplace(char const **src) { *src = StrSkipWhitespace(*src); return *src; } - -char *StrFind(StringLiteral src, StringLiteral find) -{ - char *buf_ptr = src.str; - char *buf_end = buf_ptr + src.len; - char *result = nullptr; - - for (;*buf_ptr; ++buf_ptr) - { - int len_remaining = static_cast(buf_end - buf_ptr); - if (len_remaining < find.len) break; - - if (strncmp(buf_ptr, find.str, find.len) == 0) - { - result = buf_ptr; - break; - } - } - return result; -} - -b32 StrCmp(StringLiteral a, StringLiteral b) -{ - if (a.len != b.len) - return false; - b32 result = (memcmp(a.str, b.str, a.len) == 0); - return result; -} - -// -// CPP Tokenisers/Tokens -// - -#define CPP_TOKEN_TYPE_X_MACRO \ - X(EndOfStream, "End Of Stream") \ - X(LeftBrace, "{") \ - X(RightBrace, "}") \ - X(OpenParen, "(") \ - X(CloseParen, ")") \ - X(Comma, ",") \ - X(Colon, ":") \ - X(FwdSlash, "/") \ - X(Comment, "comment") \ - X(LessThan, "<") \ - X(GreaterThan, ">") \ - X(Equals, "=") \ - X(String, "\"") \ - X(SemiColon, ";") \ - X(Identifier, "Identifier") \ - X(Number, "[0-9]") \ - X(Hash, "#") - -#define X(decl, str) decl, -enum struct CPPTokenType -{ - CPP_TOKEN_TYPE_X_MACRO -}; -#undef X - -#define X(decl, str) str, -char const *CPPTokenType_Strings[] -{ - CPP_TOKEN_TYPE_X_MACRO -}; -#undef X - -struct CPPToken -{ - CPPTokenType type; - char *str; - int len; -}; - -struct CPPReflectMetadataEntry -{ - StringLiteral key; - StringLiteral value; -}; - -using CPPReflectMetadataArray = FixedArray; -struct CPPEnumValuesLinkedList -{ - StringLiteral value; - CPPReflectMetadataArray metadata_array; - CPPEnumValuesLinkedList *next; -}; - -struct CPPTokeniser -{ - CPPToken *tokens; - int tokens_index; - int tokens_len; - int tokens_max; - - int spaces_per_indent; - int indent_level; - FILE *output_file; -}; - -void CPPTokeniser_SprintfToFile(CPPTokeniser *tokeniser, char const *fmt, ...) -{ - int const num_spaces = tokeniser->spaces_per_indent * tokeniser->indent_level; - fprintf(tokeniser->output_file, "%*s", num_spaces, ""); - - va_list va; - va_start(va, fmt); - vfprintf(tokeniser->output_file, fmt, va); - va_end(va); -} - -void CPPTokeniser_SprintfToFileNoIndenting(CPPTokeniser *tokeniser, char const *fmt, ...) -{ - va_list va; - va_start(va, fmt); - vfprintf(tokeniser->output_file, fmt, va); - va_end(va); -} - -CPPToken CPPTokeniser_NextToken(CPPTokeniser *tokeniser) -{ - CPPToken result = tokeniser->tokens[tokeniser->tokens_index++]; - if (result.type == CPPTokenType::LeftBrace) tokeniser->indent_level++; - else if (result.type == CPPTokenType::RightBrace) tokeniser->indent_level--; - assert(tokeniser->indent_level >= 0); - return result; -} - -CPPToken CPPTokeniser_PeekToken(CPPTokeniser *tokeniser) -{ - CPPToken result = tokeniser->tokens[tokeniser->tokens_index]; - return result; -} - -void CPPTokeniser_RewindToken(CPPTokeniser *tokeniser) -{ - tokeniser->tokens[--tokeniser->tokens_index]; -} - -CPPToken CPPTokeniser_PrevToken(CPPTokeniser *tokeniser) -{ - CPPToken result = {}; - result.type = CPPTokenType::EndOfStream; - if (tokeniser->tokens_index > 0) - result = tokeniser->tokens[tokeniser->tokens_index - 1]; - return result; -} - -CPPToken *CPPTokeniser_MakeToken(CPPTokeniser *tokeniser) -{ - assert(tokeniser->tokens_len < tokeniser->tokens_max); - CPPToken *result = tokeniser->tokens + tokeniser->tokens_len++; - return result; -} - -// -// CPP Parsing Helpers -// - -b32 IsIdentifierToken(CPPToken token, StringLiteral expect_str) -{ - b32 result = (token.type == CPPTokenType::Identifier) && (StrCmp(StringLiteral(token.str, token.len), expect_str)); - return result; -} - -b32 ExpectToken(CPPToken token, CPPTokenType type) -{ - b32 result = token.type == type; - if (!result) - { - fprintf(stdout, "Expected token type: %s received: %.*s\n", CPPTokenType_Strings[(int)type], token.len, token.str); - fprintf(stdout, "Context: %.*s\n\n", (token.len > 100) ? 100 : token.len, token.str); - } - return result; -} - -// -// CPP Parsing Functions -// - -CPPReflectMetadataArray ParseCPPReflectMeta(CPPTokeniser *tokeniser) -{ - CPPReflectMetadataArray result = {}; - CPPToken token = CPPTokeniser_NextToken(tokeniser); - if (!ExpectToken(token, CPPTokenType::OpenParen)) - return result; - - for (token = CPPTokeniser_NextToken(tokeniser); - token.type != CPPTokenType::EndOfStream && token.type != CPPTokenType::CloseParen; - token = CPPTokeniser_NextToken(tokeniser)) - { - if (token.type == CPPTokenType::Identifier) - { - auto metadata_key = StringLiteral(token.str, token.len); - CPPToken peek_token = CPPTokeniser_PeekToken(tokeniser); - if (!ExpectToken(peek_token, CPPTokenType::Equals)) - continue; - - token = CPPTokeniser_NextToken(tokeniser); - peek_token = CPPTokeniser_PeekToken(tokeniser); - - if (peek_token.type == CPPTokenType::String || peek_token.type == CPPTokenType::Identifier) - { - token = CPPTokeniser_NextToken(tokeniser); - if (IsIdentifierToken(token, STR_LITERAL("nullptr"))) continue; - - CPPReflectMetadataEntry *entry = FixedArray_Make(&result, 1); - entry->key = metadata_key; - entry->value = StringLiteral(token.str, token.len); - } - } - } - - while (token.type != CPPTokenType::EndOfStream && token.type != CPPTokenType::Comma) - token = CPPTokeniser_NextToken(tokeniser); - - if (token.type == CPPTokenType::EndOfStream) - CPPTokeniser_RewindToken(tokeniser); - return result; -} - -void ParseCPPEnum(CPPTokeniser *tokeniser) -{ - CPPToken token = CPPTokeniser_NextToken(tokeniser); - b32 enum_is_struct_or_class = false; - - if (IsIdentifierToken(token, STR_LITERAL("class")) || - IsIdentifierToken(token, STR_LITERAL("struct"))) - { - enum_is_struct_or_class = true; - token = CPPTokeniser_NextToken(tokeniser); - } - - if (!ExpectToken(token, CPPTokenType::Identifier)) - return; - - CPPToken const enum_name = token; - token = CPPTokeniser_NextToken(tokeniser); - - if (!ExpectToken(token, CPPTokenType::LeftBrace)) - return; - - b32 has_metadata = false; - CPPEnumValuesLinkedList *start_enum_value_token = nullptr, *enum_value_token = nullptr; - MemArenaScopedRegion mem_region = MemArena_MakeScopedRegion(&global_main_arena); - for (token = CPPTokeniser_NextToken(tokeniser); - token.type != CPPTokenType::EndOfStream && token.type != CPPTokenType::SemiColon; - token = CPPTokeniser_NextToken(tokeniser)) - { - if (token.type == CPPTokenType::Identifier) - { - CPPToken enum_value = token; - token = CPPTokeniser_NextToken(tokeniser); - CPPReflectMetadataArray metadata_array = {}; - if (IsIdentifierToken(token, STR_LITERAL("DQN_REFLECT_META"))) - { - has_metadata = true; - metadata_array = ParseCPPReflectMeta(tokeniser); - } - - if (!start_enum_value_token) - { - start_enum_value_token = MEM_ARENA_ALLOC_STRUCT(&global_main_arena, CPPEnumValuesLinkedList); - enum_value_token = start_enum_value_token; - } - else - { - enum_value_token->next = MEM_ARENA_ALLOC_STRUCT(&global_main_arena, CPPEnumValuesLinkedList); - enum_value_token = enum_value_token->next; - } - - (*enum_value_token) = {}; - enum_value_token->metadata_array = metadata_array; - enum_value_token->value = StringLiteral(enum_value.str, enum_value.len); - } - } - - // - // Write Stringified Enum Array - // - { - CPPTokeniser_SprintfToFile(tokeniser, "char const *DqnReflect_%.*s_Strings[] = {", enum_name.len, enum_name.str); - tokeniser->indent_level++; - for (CPPEnumValuesLinkedList *link = start_enum_value_token; link; link = link->next) - { - StringLiteral enum_value = link->value; - CPPTokeniser_SprintfToFileNoIndenting(tokeniser, "\"%.*s\", ", enum_value.len, enum_value.str); - } - - tokeniser->indent_level--; - CPPTokeniser_SprintfToFile(tokeniser, "};\n\n"); - } - - // - // Write ReflectEnumString Function - // - { - CPPTokeniser_SprintfToFile(tokeniser, "char const *DqnReflect_EnumString(%.*s val)\n{\n", enum_name.len, enum_name.str); - tokeniser->indent_level++; - DEFER - { - CPPTokeniser_SprintfToFile(tokeniser, "return nullptr;\n"); - tokeniser->indent_level--; - CPPTokeniser_SprintfToFile(tokeniser, "}\n\n"); - }; - - struct SourceCode - { - StringLiteral decl; - StringLiteral enum_value; - }; - - LinkedList src_code = {}; - int longest_decl_len = 0; - { - LinkedList *curr_src_code = nullptr; - char const *fmt = (enum_is_struct_or_class) ? "if (val == %.*s::%.*s) " : "if (val == %.*s) "; - for (CPPEnumValuesLinkedList *link = start_enum_value_token; link; link = link->next) - { - if (!curr_src_code) curr_src_code = &src_code; - else - { - curr_src_code->next = static_cast *>( MemArena_Alloc(&global_main_arena, sizeof(*curr_src_code))); - curr_src_code = curr_src_code->next; - } - - StringLiteral enum_value = link->value; - int required_len = 0; - - if (enum_is_struct_or_class) required_len = snprintf(nullptr, 0, fmt, enum_name.len, enum_name.str, enum_value.len, enum_value.str) + 1; - else required_len = snprintf(nullptr, 0, fmt, enum_value.len, enum_value.str) + 1; - - longest_decl_len = REFLECT_MAX(longest_decl_len, required_len); - curr_src_code->data.decl.str = MEM_ARENA_ALLOC_ARRAY(&global_main_arena, char, required_len); - curr_src_code->data.decl.len = required_len; - curr_src_code->data.enum_value = enum_value; - - if (enum_is_struct_or_class) snprintf(curr_src_code->data.decl.str, curr_src_code->data.decl.len, fmt, enum_name.len, enum_name.str, enum_value.len, enum_value.str); - else snprintf(curr_src_code->data.decl.str, curr_src_code->data.decl.len, fmt, enum_value.len, enum_value.str); - } - curr_src_code->next = nullptr; - } - - int enum_index = 0; - for (LinkedList *src_code_ptr = &src_code; - src_code_ptr; - src_code_ptr = src_code_ptr->next, ++enum_index) - { - StringLiteral enum_value = src_code_ptr->data.enum_value; - int padding = longest_decl_len - src_code_ptr->data.decl.len; - CPPTokeniser_SprintfToFile(tokeniser, "%.*s%*s", src_code_ptr->data.decl.len, src_code_ptr->data.decl.str, padding, ""); - CPPTokeniser_SprintfToFileNoIndenting(tokeniser, - "return DqnReflect_%.*s_Strings[%d]; // \"%.*s\"\n", - enum_name.len, enum_name.str, - enum_index, - enum_value.len, enum_value.str); - } - } - - // - // Write User Annotated Metadata Getter Functions - // - if (has_metadata) - { - struct CPPDeclToValue - { - StringLiteral cpp_decl; - StringLiteral value; - }; - - struct MetadataEntry - { - StringLiteral key; - FixedArray cpp_decl_to_val; - }; - - FixedArray metadata_entries = {}; - for (CPPEnumValuesLinkedList *link = start_enum_value_token; - link; - link = link->next) - { - for (CPPReflectMetadataEntry const &reflect_entry : link->metadata_array) - { - MetadataEntry *metadata_entry_to_append_to = nullptr; - for (MetadataEntry &check_metadata_entry : metadata_entries) - { - if (StrCmp(check_metadata_entry.key, reflect_entry.key)) - { - metadata_entry_to_append_to = &check_metadata_entry; - break; - } - } - - if (!metadata_entry_to_append_to) - { - metadata_entry_to_append_to = FixedArray_Make(&metadata_entries, 1); - metadata_entry_to_append_to->key = reflect_entry.key; - } - - CPPDeclToValue decl_to_val = {}; - decl_to_val.cpp_decl = StringLiteral(link->value.str, link->value.len); - decl_to_val.value = reflect_entry.value; - FixedArray_Add(&metadata_entry_to_append_to->cpp_decl_to_val, decl_to_val); - } - } - - for (MetadataEntry const &metadata : metadata_entries) - { - CPPTokeniser_SprintfToFile(tokeniser, - "char const *DqnReflect_%.*sMetadata(%.*s val)\n{\n", - metadata.key.len, metadata.key.str, - enum_name.len, enum_name.str); - - tokeniser->indent_level++; - DEFER - { - CPPTokeniser_SprintfToFile(tokeniser, "return nullptr;\n"); - tokeniser->indent_level--; - CPPTokeniser_SprintfToFile(tokeniser, "}\n\n"); - }; - - int enum_index = 0; - for (CPPDeclToValue const &decl_to_val : metadata.cpp_decl_to_val) - { - StringLiteral const *cpp_decl = &decl_to_val.cpp_decl; - StringLiteral const *value = &decl_to_val.value; - - if (enum_is_struct_or_class) - { - CPPTokeniser_SprintfToFile(tokeniser, - "if (val == %.*s::%.*s) ", - enum_name.len, enum_name.str, - cpp_decl->len, cpp_decl->str); - } - else - { - CPPTokeniser_SprintfToFile(tokeniser, - "if (val == %.*s) ", - cpp_decl->len, cpp_decl->str); - } - CPPTokeniser_SprintfToFileNoIndenting(tokeniser, "return \"%.*s\";\n", value->len, value->str); - } - } - } -} - -int main(int argc, char *argv[]) -{ - if (argc < 1) - { - fprintf(stdout, "Usage: %s [, ...]", argv[0]); - return 0; - } - - usize main_arena_mem_size = MEGABYTE(2); - void *main_arena_mem = malloc(main_arena_mem_size); - global_main_arena = MemArena_Init(main_arena_mem, main_arena_mem_size); - FILE *output_file = fopen("DqnReflect_Generated.cpp", "w"); - - fprintf(output_file, - "#ifndef DQN_REFLECT_GENERATED_H\n" - "#define DQN_REFLECT_GENERATED_H\n\n" - "// This is an auto generated file using Dqn_Reflect\n" - "\n"); - - for (usize arg_index = 1; arg_index < argc; ++arg_index) - { - MemArenaScopedRegion mem_region = MemArena_MakeScopedRegion(&global_main_arena); - char *file_name = argv[arg_index]; - FILE *file = fopen(file_name, "rb"); - fseek(file, 0, SEEK_END); - usize file_size = ftell(file); - rewind(file); - - char *file_buf = (char *)MemArena_Alloc(&global_main_arena, file_size + 1); - file_buf[file_size] = 0; - - if (fread(file_buf, file_size, 1, file) != 1) - { - fprintf(stderr, "Failed to fread: %zu bytes into buffer from file: %s\n", file_size, file_name); - continue; - } - - int const file_name_len = (int)strlen(file_name); - int file_include_contents_hash_define_len = 0; - char *file_include_contents_hash_define = nullptr; - { - char *extracted_file_name_buf = static_cast(MemArena_Alloc(&global_main_arena, file_name_len)); - int extracted_file_name_len = 0; - - for (int i = file_name_len - 1; i >= 0; i--, extracted_file_name_len++) - { - char ch = file_name[i]; - if (ch == '.') - ch = '_'; - - if (ch >= 'a' && ch <= 'z') ch -= 'a' - 'A'; - - if (ch == '\\' || ch == '/') - break; - - extracted_file_name_buf[i] = ch; - } - - file_include_contents_hash_define = extracted_file_name_buf + file_name_len - extracted_file_name_len; - file_include_contents_hash_define_len = extracted_file_name_len; - } - - fprintf(output_file, - "//\n" - "// %s\n" - "//\n" - "\n" - "#if !defined(DQN_REFLECT_DISABLE_%.*s)\n", - file_name, - file_include_contents_hash_define_len, - file_include_contents_hash_define); - - CPPTokeniser tokeniser = {}; - tokeniser.spaces_per_indent = 4; - tokeniser.output_file = output_file; - tokeniser.tokens_max = 16384; - tokeniser.tokens = MEM_ARENA_ALLOC_ARRAY(&global_main_arena, CPPToken, tokeniser.tokens_max); - - StringLiteral const REFLECT_MARKER = STR_LITERAL("DQN_REFLECT"); - char *file_buf_end = file_buf + file_size; - StringLiteral buffer = StringLiteral(file_buf, file_size); - - for (char *ptr = StrFind(buffer, REFLECT_MARKER); - ptr; - ptr = StrFind(buffer, REFLECT_MARKER)) - { - ptr += REFLECT_MARKER.len; - for (; ptr;) - { - while (CharIsWhitespace(ptr[0])) ptr++; - if (!ptr[0]) break; - - CPPToken *token = CPPTokeniser_MakeToken(&tokeniser); - token->str = ptr++; - token->len = 1; - switch(token->str[0]) - { - case '{': { token->type = CPPTokenType::LeftBrace; } break; - case '}': { token->type = CPPTokenType::RightBrace; } break; - case '(': { token->type = CPPTokenType::OpenParen; } break; - case ')': { token->type = CPPTokenType::CloseParen; } break; - case ',': { token->type = CPPTokenType::Comma; } break; - case ';': { token->type = CPPTokenType::SemiColon; } break; - case '=': { token->type = CPPTokenType::Equals; } break; - case '<': { token->type = CPPTokenType::LessThan; } break; - case '>': { token->type = CPPTokenType::GreaterThan; } break; - case ':': { token->type = CPPTokenType::Colon; } break; - case '/': - { - token->type = CPPTokenType::FwdSlash; - if (ptr[0] == '/') - { - while (ptr[0] == ' ' || ptr[0] == '\t') ptr++; - token->str = ptr; - while (ptr[0] != '\n') ptr++; - token->type = CPPTokenType::Comment; - token->len = ptr - token->str; - } - } - break; - - default: - { - ptr--; - if (ptr[0] == '"') - { - token->type = CPPTokenType::String; - for (token->str = ++ptr;;) - { - while (ptr[0] != '"') ptr++; - token->len = ptr - token->str; - if (ptr[-1] != '\\') - { - ptr++; - break; - } - } - } - else - { - if (CharIsDigit(ptr[0])) - { - while (CharIsDigit(ptr[0]) || ptr[0] == 'x' || ptr[0] == 'b' || ptr[0] == 'e' || ptr[0] == '.' || ptr[0] == 'f') - ptr++; - - token->type = CPPTokenType::Number; - } - else - { - token->type = CPPTokenType::Identifier; - if (CharIsAlpha(ptr[0]) || ptr[0] == '_') - { - ptr++; - while (CharIsAlphaNum(ptr[0]) || ptr[0] == '_') ptr++; - } - } - - token->len = ptr - token->str; - } - - } - break; - } - - if (token->len == 0) - { - *token = {}; - tokeniser.tokens_len--; - } - else if (token->type == CPPTokenType::SemiColon) - { - break; - } - } - - buffer.str = ptr; - buffer.len = static_cast(file_buf_end - ptr); - } - - CPPToken *sentinel = CPPTokeniser_MakeToken(&tokeniser); - sentinel->type = CPPTokenType::EndOfStream; - - for (CPPToken token = CPPTokeniser_NextToken(&tokeniser); - token.type != CPPTokenType::EndOfStream; - token = CPPTokeniser_NextToken(&tokeniser)) - { -#if 0 - Token const *token = tokens + index; - fprintf(stdout, "%.*s", token->len, token->str); - if (index < (tokens_index - 1)) fprintf(stdout, " -> "); -#endif - if (token.type == CPPTokenType::Identifier) - { - if (StrCmp(StringLiteral(token.str, token.len), STR_LITERAL("enum"))) - ParseCPPEnum(&tokeniser); - } - } - - fprintf(output_file, "#endif // DQN_REFLECT_DISABLE_%.*s\n\n", - file_include_contents_hash_define_len, - file_include_contents_hash_define); - } - - fprintf(output_file, "#endif // DQN_REFLECT_GENERATED_H\n"); - fclose(output_file); - - return 0; -} - -#endif // DQN_REFLECT_IMPLEMENTATION -#endif // DQN_REFLECT_H diff --git a/Code/Deprecated/DqnUnitTest.cpp b/Code/Deprecated/DqnUnitTest.cpp deleted file mode 100644 index f2e8113..0000000 --- a/Code/Deprecated/DqnUnitTest.cpp +++ /dev/null @@ -1,2024 +0,0 @@ -#if defined(__linux__) - #define HANDMADE_MATH_NO_SSE -#endif - -#if defined(__GNUC__) - #pragma GCC diagnostic push - #pragma GCC diagnostic ignored "-Wfree-nonheap-object" -#endif - -#if defined(_WIN32) -#define WIN32_MEAN_AND_LEAN -#include -#include -#include -#endif - -#define DQN_PLATFORM_HEADER -#define DQN_PLATFORM_IMPLEMENTATION -#define DQN_IMPLEMENTATION -#include "dqn.h" - -#define HANDMADE_MATH_IMPLEMENTATION -#define HANDMADE_MATH_CPP_MODE -#include "tests/HandmadeMath.h" - -#include -#include - -// TODO(doyle): Replace DQN_ASSERT with a non-halting assert that can connect to -// some sort of testing framework to track successes and failures. - -#define LOG_HEADER() LogHeader(__func__) -FILE_SCOPE i32 global_indent; -FILE_SCOPE bool global_new_line; - -#define RED "\x1B[31m" -#define GRN "\x1B[32m" -#define YEL "\x1B[33m" -#define BLU "\x1B[34m" -#define MAG "\x1B[35m" -#define CYN "\x1B[36m" -#define WHT "\x1B[37m" -#define RESET "\x1B[0m" - -enum class Status -{ - None, - Ok, - Error -}; -void Log(Status status, char const *fmt, va_list va) -{ - DQN_ASSERT(global_indent >= 0); - LOCAL_PERSIST i32 line_len = 0; - - char buf[1024] = {}; - i32 buf_len = 0; - { - buf_len = Dqn_vsprintf(buf, fmt, va); - DQN_ASSERT(buf_len < (i32)DQN_ARRAY_COUNT(buf)); - line_len += buf_len; - } - - char indent_str[] = " "; - i32 indent_len = DQN_CHAR_COUNT(indent_str); - { - line_len += (indent_len * global_indent); - for (auto i = 0; i < global_indent; i++) - printf("%s", indent_str); - - printf("%s", &(buf[0])); - } - - if (status == Status::Ok || status == Status::Error) - { - char ok_status[] = "OK"; - char err_status[] = "ERROR"; - - char *statusStr; - i32 status_str_len; - if (status == Status::Ok) - { - statusStr = ok_status; - status_str_len = DQN_CHAR_COUNT(ok_status); - } - else - { - statusStr = err_status; - status_str_len = DQN_CHAR_COUNT(err_status); - } - line_len += status_str_len; - - i32 target_len = 90; - i32 remaining = target_len - line_len; - remaining = DQN_MAX(remaining, 0); - - for (auto i = 0; i < remaining; i++) - putchar('.'); - - if (status == Status::Ok) - { - printf(GRN "%s" RESET, statusStr); - } - else - { - printf(RED "%s" RESET, statusStr); - } - } - - if (global_new_line) - { - line_len = 0; - printf("\n"); - } -} - -void Log(Status status, char const *fmt, ...) -{ - va_list va; - va_start(va, fmt); - Log(status, fmt, va); - va_end(va); -} - -void Log(char const *fmt, ...) -{ - va_list va; - va_start(va, fmt); - Log(Status::None, fmt, va); - va_end(va); -} - -void LogHeader(char const *func_name) -{ - global_indent--; - Log("\n[%s]", func_name); - global_indent++; -} - -#include "DqnFixedString.cpp" -#include "DqnOS.cpp" -#include "DqnJson.cpp" -#include "DqnVHashTable.cpp" -#include "DqnMemStack.cpp" - -void HandmadeMathVerifyMat4(DqnMat4 dqn_mat, hmm_mat4 hmm_mat) -{ - f32 *hmm_matf = (f32 *)&hmm_mat; - f32 *dqn_matf = (f32 *)&dqn_mat; - - const u32 EXPECTED_SIZE = 16; - u32 totalSize = DQN_ARRAY_COUNT(dqn_mat.e) * DQN_ARRAY_COUNT(dqn_mat.e[0]); - DQN_ASSERT(totalSize == EXPECTED_SIZE); - DQN_ASSERT(totalSize == - (DQN_ARRAY_COUNT(hmm_mat.Elements) * DQN_ARRAY_COUNT(hmm_mat.Elements[0]))); - - for (u32 i = 0; i < EXPECTED_SIZE; i++) - { - const f32 EPSILON = 0.001f; - f32 diff = hmm_matf[i] - dqn_matf[i]; - diff = DQN_ABS(diff); - DQN_ASSERTM(diff < EPSILON, "hmm_matf[%d]: %f, dqn_matf[%d]: %f\n", i, hmm_matf[i], i, - dqn_matf[i]); - } -} - -void HandmadeMathTestInternal() -{ - LOG_HEADER(); - // Test Perspective/Projection matrix values -} - -void Dqn_Test() -{ - LOG_HEADER(); - - // const u64 LARGEST_NUM = (u64)-1; - const i64 SMALLEST_NUM = LLONG_MIN; - // StrToI64 - if (1) - { - const char *const a = "123"; - DQN_ASSERT(Dqn_StrToI64(a, DqnStr_Len(a)) == 123); - - const char *const b = "-123"; - DQN_ASSERT(Dqn_StrToI64(b, DqnStr_Len(b)) == -123); - DQN_ASSERT(Dqn_StrToI64(b, 1) == 0); - - const char *const c = "-0"; - DQN_ASSERT(Dqn_StrToI64(c, DqnStr_Len(c)) == 0); - - const char *const d = "+123"; - DQN_ASSERT(Dqn_StrToI64(d, DqnStr_Len(d)) == 123); - -// TODO(doyle): Unsigned conversion -#if 0 - char *e = "18446744073709551615"; - DQN_ASSERT((u64)(Dqn_StrToI64(e, DqnStr_Len(e))) == LARGEST_NUM); -#endif - - const char *const f = "-9223372036854775808"; - DQN_ASSERT(Dqn_StrToI64(f, DqnStr_Len(f)) == SMALLEST_NUM); - - Log("Dqn_StrToI64()"); - } - - // i64 to str - if (1) - { - char a[DQN_I64_MAX_STR_SIZE] = {}; - Dqn_I64ToStr(+100, a, DQN_ARRAY_COUNT(a)); - DQN_ASSERT(DqnStr_Cmp(a, "100") == 0); - - char b[DQN_I64_MAX_STR_SIZE] = {}; - Dqn_I64ToStr(-100, b, DQN_ARRAY_COUNT(b)); - DQN_ASSERT(DqnStr_Cmp(b, "-100") == 0); - - char c[DQN_I64_MAX_STR_SIZE] = {}; - Dqn_I64ToStr(0, c, DQN_ARRAY_COUNT(c)); - DQN_ASSERT(DqnStr_Cmp(c, "0") == 0); - -#if 0 - char d[DQN_I64_MAX_STR_SIZE] = {}; - Dqn_I64ToStr(LARGEST_NUM, d, DQN_ARRAY_COUNT(d)); - DQN_ASSERT(DqnStr_Cmp(d, "18446744073709551615") == 0); -#endif - - if (sizeof(size_t) == sizeof(u64)) - { - char e[DQN_I64_MAX_STR_SIZE] = {}; - Dqn_I64ToStr(SMALLEST_NUM, e, DQN_ARRAY_COUNT(e)); - DQN_ASSERTM(DqnStr_Cmp(e, "-9223372036854775808") == 0, "e: %s", e); - } - - Log("Dqn_I64ToStr()"); - } - - // StrToF32 - if (1) - { - const f32 EPSILON = 0.001f; - const char a[] = "-0.66248"; - f32 vA = Dqn_StrToF32(a, DQN_ARRAY_COUNT(a)); - DQN_ASSERT(DQN_ABS(vA) - DQN_ABS(-0.66248f) < EPSILON); - - const char b[] = "-0.632053"; - f32 vB = Dqn_StrToF32(b, DQN_ARRAY_COUNT(b)); - DQN_ASSERT(DQN_ABS(vB) - DQN_ABS(-0.632053f) < EPSILON); - - const char c[] = "-0.244271"; - f32 vC = Dqn_StrToF32(c, DQN_ARRAY_COUNT(c)); - DQN_ASSERT(DQN_ABS(vC) - DQN_ABS(-0.244271f) < EPSILON); - - const char d[] = "-0.511812"; - f32 vD = Dqn_StrToF32(d, DQN_ARRAY_COUNT(d)); - DQN_ASSERT(DQN_ABS(vD) - DQN_ABS(-0.511812f) < EPSILON); - - const char e[] = "-0.845392"; - f32 vE = Dqn_StrToF32(e, DQN_ARRAY_COUNT(e)); - DQN_ASSERT(DQN_ABS(vE) - DQN_ABS(-0.845392f) < EPSILON); - - const char f[] = "0.127809"; - f32 vF = Dqn_StrToF32(f, DQN_ARRAY_COUNT(f)); - DQN_ASSERT(DQN_ABS(vF) - DQN_ABS(-0.127809f) < EPSILON); - - const char g[] = "0.532"; - f32 vG = Dqn_StrToF32(g, DQN_ARRAY_COUNT(g)); - DQN_ASSERT(DQN_ABS(vG) - DQN_ABS(-0.532f) < EPSILON); - - const char h[] = "0.923"; - f32 vH = Dqn_StrToF32(h, DQN_ARRAY_COUNT(h)); - DQN_ASSERT(DQN_ABS(vH) - DQN_ABS(-0.923f) < EPSILON); - - const char i[] = "0.000"; - f32 vI = Dqn_StrToF32(i, DQN_ARRAY_COUNT(i)); - DQN_ASSERT(DQN_ABS(vI) - DQN_ABS(-0.000f) < EPSILON); - - const char j[] = "0.000283538"; - f32 vJ = Dqn_StrToF32(j, DQN_ARRAY_COUNT(j)); - DQN_ASSERT(DQN_ABS(vJ) - DQN_ABS(-0.000283538f) < EPSILON); - - const char k[] = "-1.25"; - f32 vK = Dqn_StrToF32(k, DQN_ARRAY_COUNT(k)); - DQN_ASSERT(DQN_ABS(vK) - DQN_ABS(-1.25f) < EPSILON); - - const char l[] = "0.286843"; - f32 vL = Dqn_StrToF32(l, DQN_ARRAY_COUNT(l)); - DQN_ASSERT(DQN_ABS(vL) - DQN_ABS(-0.286843f) < EPSILON); - - const char m[] = "-0.406"; - f32 vM = Dqn_StrToF32(m, DQN_ARRAY_COUNT(m)); - DQN_ASSERT(DQN_ABS(vM) - DQN_ABS(-0.406f) < EPSILON); - - const char n[] = "-0.892"; - f32 vN = Dqn_StrToF32(n, DQN_ARRAY_COUNT(n)); - DQN_ASSERT(DQN_ABS(vN) - DQN_ABS(-0.892f) < EPSILON); - - const char o[] = "0.201"; - f32 vO = Dqn_StrToF32(o, DQN_ARRAY_COUNT(o)); - DQN_ASSERT(DQN_ABS(vO) - DQN_ABS(-0.201f) < EPSILON); - - const char p[] = "1.25"; - f32 vP = Dqn_StrToF32(p, DQN_ARRAY_COUNT(p)); - DQN_ASSERT(DQN_ABS(vP) - DQN_ABS(1.25f) < EPSILON); - - const char q[] = "9.64635e-05"; - f32 vQ = Dqn_StrToF32(q, DQN_ARRAY_COUNT(q)); - DQN_ASSERT(DQN_ABS(vQ) - DQN_ABS(9.64635e-05) < EPSILON); - - const char r[] = "9.64635e+05"; - f32 vR = Dqn_StrToF32(r, DQN_ARRAY_COUNT(r)); - DQN_ASSERT(DQN_ABS(vR) - DQN_ABS(9.64635e+05) < EPSILON); - - Log("Dqn_StrToF32()"); - } - - // UCS <-> UTF8 Checks - if (1) - { - // Test ascii characters - if (1) - { - u32 codepoint = '@'; - u32 string[1] = {}; - - u32 bytes_used = Dqn_UCSToUTF8(&string[0], codepoint); - DQN_ASSERT(bytes_used == 1); - DQN_ASSERT(string[0] == '@'); - - bytes_used = Dqn_UTF8ToUCS(&string[0], codepoint); - DQN_ASSERT(string[0] >= 0 && string[0] < 0x80); - DQN_ASSERT(bytes_used == 1); - - Log("Dqn_UTF8ToUCS(): Test ascii characters"); - } - - // Test 2 byte characters - if (1) - { - u32 codepoint = 0x278; - u32 string[1] = {}; - - u32 bytes_used = Dqn_UCSToUTF8(&string[0], codepoint); - DQN_ASSERT(bytes_used == 2); - DQN_ASSERT(string[0] == 0xC9B8); - - bytes_used = Dqn_UTF8ToUCS(&string[0], string[0]); - DQN_ASSERT(string[0] == codepoint); - DQN_ASSERT(bytes_used == 2); - - Log("Dqn_UTF8ToUCS(): Test 2 byte characters"); - } - - // Test 3 byte characters - if (1) - { - u32 codepoint = 0x0A0A; - u32 string[1] = {}; - - u32 bytes_used = Dqn_UCSToUTF8(&string[0], codepoint); - DQN_ASSERT(bytes_used == 3); - DQN_ASSERT(string[0] == 0xE0A88A); - - bytes_used = Dqn_UTF8ToUCS(&string[0], string[0]); - DQN_ASSERT(string[0] == codepoint); - DQN_ASSERT(bytes_used == 3); - - Log("Dqn_UTF8ToUCS(): Test 3 byte characters"); - } - - // Test 4 byte characters - if (1) - { - u32 codepoint = 0x10912; - u32 string[1] = {}; - u32 bytes_used = Dqn_UCSToUTF8(&string[0], codepoint); - - DQN_ASSERT(bytes_used == 4); - DQN_ASSERT(string[0] == 0xF090A492); - - bytes_used = Dqn_UTF8ToUCS(&string[0], string[0]); - DQN_ASSERT(string[0] == codepoint); - DQN_ASSERT(bytes_used == 4); - - Log("Dqn_UTF8ToUCS(): Test 4 byte characters"); - } - - if (1) - { - u32 codepoint = 0x10912; - u32 bytes_used = Dqn_UCSToUTF8(NULL, codepoint); - DQN_ASSERT(bytes_used == 0); - - bytes_used = Dqn_UTF8ToUCS(NULL, codepoint); - DQN_ASSERT(bytes_used == 0); - - Log("Dqn_UTF8ToUCS(): Test return result on on NULL output param"); - } - } - -} - -void DqnStr_Test() -{ - // String Checks - if (1) - { - LOG_HEADER(); - - // strcmp - if (1) - { - const char *const a = "str_a"; - - // Check simple compares - if (1) - { - DQN_ASSERT(DqnStr_Cmp(a, "str_a") == +0); - DQN_ASSERT(DqnStr_Cmp(a, "str_b") == -1); - DQN_ASSERT(DqnStr_Cmp("str_b", a) == +1); - DQN_ASSERT(DqnStr_Cmp(a, "") == +1); - DQN_ASSERT(DqnStr_Cmp("", "") == 0); - - // NOTE: Check that the string has not been trashed. - DQN_ASSERT(DqnStr_Cmp(a, "str_a") == +0); - Log("DqnStr_Cmp(): Check simple compares"); - } - - // Check ops against null - if (1) - { - DQN_ASSERT(DqnStr_Cmp(NULL, NULL) != +0); - DQN_ASSERT(DqnStr_Cmp(a, NULL) != +0); - DQN_ASSERT(DqnStr_Cmp(NULL, a) != +0); - Log("DqnStr_Cmp(): Check ops against null"); - } - } - - // strlen - if (1) - { - const char *const a = "str_a"; - DQN_ASSERT(DqnStr_Len(a) == 5); - DQN_ASSERT(DqnStr_Len("") == 0); - DQN_ASSERT(DqnStr_Len(" a ") == 6); - DQN_ASSERT(DqnStr_Len("a\n") == 2); - - // NOTE: Check that the string has not been trashed. - DQN_ASSERT(DqnStr_Cmp(a, "str_a") == 0); - DQN_ASSERT(DqnStr_Len(NULL) == 0); - - Log("DqnStr_Len()"); - } - - // StrReverse - if (1) - { - // Basic reverse operations - if (1) - { - char a[] = "aba"; - DqnStr_Reverse(a, DqnStr_Len(a)); - DQN_ASSERT(DqnStr_Cmp(a, "aba") == 0); - - DqnStr_Reverse(a, 2); - DQN_ASSERT(DqnStr_Cmp(a, "baa") == 0); - - DqnStr_Reverse(a, DqnStr_Len(a)); - DQN_ASSERT(DqnStr_Cmp(a, "aab") == 0); - - DqnStr_Reverse(&a[1], 2); - DQN_ASSERT(DqnStr_Cmp(a, "aba") == 0); - - DqnStr_Reverse(a, 0); - DQN_ASSERT(DqnStr_Cmp(a, "aba") == 0); - Log("DqnStr_Reverse(): Basic reverse operations"); - } - - // Try reverse empty string - if (1) - { - char a[] = ""; - DqnStr_Reverse(a, DqnStr_Len(a)); - DQN_ASSERT(DqnStr_Cmp(a, "") == 0); - Log("DqnStr_Reverse(): Reverse empty string"); - } - - // Try reverse single char string - if (1) - { - char a[] = "a"; - DqnStr_Reverse(a, DqnStr_Len(a)); - DQN_ASSERT(DqnStr_Cmp(a, "a") == 0); - - DqnStr_Reverse(a, 0); - DQN_ASSERT(DqnStr_Cmp(a, "a") == 0); - Log("DqnStr_Reverse(): Reverse single char string"); - } - } - - if (1) - { - const char *const a = "Microsoft"; - const char *const b = "icro"; - i32 lenA = DqnStr_Len(a); - i32 lenB = DqnStr_Len(b); - DQN_ASSERT(DqnStr_HasSubstring(a, lenA, b, lenB) == true); - DQN_ASSERT(DqnStr_HasSubstring(a, lenA, "iro", DqnStr_Len("iro")) == false); - DQN_ASSERT(DqnStr_HasSubstring(b, lenB, a, lenA) == false); - DQN_ASSERT(DqnStr_HasSubstring("iro", DqnStr_Len("iro"), a, lenA) == false); - DQN_ASSERT(DqnStr_HasSubstring("", 0, "iro", 4) == false); - DQN_ASSERT(DqnStr_HasSubstring("", 0, "", 0) == false); - DQN_ASSERT(DqnStr_HasSubstring(NULL, 0, NULL, 0) == false); - Log("DqnStr_HasSubstring(): Check string with matching substring"); - } - - if (1) - { - const char *const a = "Micro"; - const char *const b = "irob"; - i32 lenA = DqnStr_Len(a); - i32 lenB = DqnStr_Len(b); - DQN_ASSERT(DqnStr_HasSubstring(a, lenA, b, lenB) == false); - DQN_ASSERT(DqnStr_HasSubstring(b, lenB, a, lenA) == false); - Log("DqnStr_HasSubstring(): Check string with non-matching substring"); - } - - } -} - -void DqnChar_Test() -{ - LOG_HEADER(); - - // Char Checks - if (1) - { - DQN_ASSERT(DqnChar_IsAlpha('a') == true); - DQN_ASSERT(DqnChar_IsAlpha('A') == true); - DQN_ASSERT(DqnChar_IsAlpha('0') == false); - DQN_ASSERT(DqnChar_IsAlpha('@') == false); - DQN_ASSERT(DqnChar_IsAlpha(' ') == false); - DQN_ASSERT(DqnChar_IsAlpha('\n') == false); - Log(Status::Ok, "IsAlpha"); - - DQN_ASSERT(DqnChar_IsDigit('1') == true); - DQN_ASSERT(DqnChar_IsDigit('n') == false); - DQN_ASSERT(DqnChar_IsDigit('N') == false); - DQN_ASSERT(DqnChar_IsDigit('*') == false); - DQN_ASSERT(DqnChar_IsDigit(' ') == false); - DQN_ASSERT(DqnChar_IsDigit('\n') == false); - Log(Status::Ok, "IsDigit"); - - DQN_ASSERT(DqnChar_IsAlphaNum('1') == true); - DQN_ASSERT(DqnChar_IsAlphaNum('a') == true); - DQN_ASSERT(DqnChar_IsAlphaNum('A') == true); - DQN_ASSERT(DqnChar_IsAlphaNum('*') == false); - DQN_ASSERT(DqnChar_IsAlphaNum(' ') == false); - DQN_ASSERT(DqnChar_IsAlphaNum('\n') == false); - Log(Status::Ok, "IsAlphaNum"); - - DQN_ASSERT(DqnChar_ToLower(L'A') == L'a'); - DQN_ASSERT(DqnChar_ToLower(L'a') == L'a'); - DQN_ASSERT(DqnChar_ToLower(L' ') == L' '); - Log(Status::Ok, "ToLower"); - - DQN_ASSERT(DqnChar_ToUpper(L'A') == L'A'); - DQN_ASSERT(DqnChar_ToUpper(L'a') == L'A'); - DQN_ASSERT(DqnChar_ToUpper(L' ') == L' '); - Log(Status::Ok, "ToUpper"); - - DQN_ASSERT(DqnChar_IsWhitespace(' ')); - DQN_ASSERT(DqnChar_IsWhitespace('\r')); - DQN_ASSERT(DqnChar_IsWhitespace('\n')); - DQN_ASSERT(DqnChar_IsWhitespace('\t')); - Log(Status::Ok, "IsWhiteSpace"); - } - - // Trim white space test - if (1) - { - if (1) - { - char a[] = ""; - i32 newLen = 0; - auto *result = DqnChar_TrimWhitespaceAround(a, DQN_CHAR_COUNT(a), &newLen); - - DQN_ASSERT(newLen == 0); - DQN_ASSERT(result == nullptr); - } - - if (1) - { - char a[] = "a"; - i32 newLen = 0; - auto *result = DqnChar_TrimWhitespaceAround(a, DQN_CHAR_COUNT(a), &newLen); - - DQN_ASSERT(newLen == 1); - DQN_ASSERT(result == a); - } - - if (1) - { - char a[] = " abc"; - i32 newLen = 0; - auto *result = DqnChar_TrimWhitespaceAround(a, DQN_CHAR_COUNT(a), &newLen); - - DQN_ASSERT(newLen == 3); - DQN_ASSERT(result == (a + 1)); - } - - if (1) - { - char a[] = "abc "; - i32 newLen = 0; - auto *result = DqnChar_TrimWhitespaceAround(a, DQN_CHAR_COUNT(a), &newLen); - - DQN_ASSERT(newLen == 3); - DQN_ASSERT(result == a); - } - - if (1) - { - char a[] = " abc "; - i32 newLen = 0; - auto *result = DqnChar_TrimWhitespaceAround(a, DQN_CHAR_COUNT(a), &newLen); - - DQN_ASSERT(newLen == 3); - DQN_ASSERT(result == a + 3); - } - - if (1) - { - char a[] = " "; - i32 newLen = 0; - auto *result = DqnChar_TrimWhitespaceAround(a, DQN_CHAR_COUNT(a), &newLen); - - DQN_ASSERT(newLen == 0); - DQN_ASSERT(result == nullptr); - } - - Log(Status::Ok, "TrimWhitespaceAround"); - } -} - -void DqnString_Test() -{ - LOG_HEADER(); - - // Try expanding string - if (1) - { - DqnString str = "hello world"; - DQN_DEFER { str.Free(); }; - str = "hello world2"; - str.Append(", hello again"); - str.Append(", and hello again"); - - DQN_ASSERT(str.str[str.len] == 0); - DQN_ASSERT(str.len <= str.max); - DQN_ASSERTM(DqnStr_Cmp("hello world2, hello again, and hello again", str.str) == 0, "str: %s", str.str); - - str.Free(); - Log(Status::Ok, "Check expand on append"); - } - - { - DqnString str = DQN_BUFFER_STR_LIT("hello world"); - DQN_DEFER { str.Free(); }; - DQN_ASSERT(DqnStr_Cmp(str.str, "hello world") == 0); - - Log(Status::Ok, "Copy constructor DqnSlice"); - } - - { - DqnString zero = {}; - DqnString str = DQN_BUFFER_STR_LIT("hello world"); - str.Free(); - str = zero; - - DqnBuffer helloSlice = DQN_BUFFER_STR_LIT("hello"); - str = helloSlice; - DQN_DEFER { str.Free(); }; - DQN_ASSERT(DqnStr_Cmp(str.str, "hello") == 0); - - Log(Status::Ok, "Copy constructor (DqnFixedString<>)"); - } - - { - DqnString str = DQN_BUFFER_STR_LIT("hello world"); - DQN_DEFER { str.Free(); }; - DQN_ASSERT(str.Sprintf("hello %s", "sailor")); - DQN_ASSERTM(DqnStr_Cmp(str.str, "hello sailor") == 0, "Result: %s", str.str); - - Log(Status::Ok, "Sprintf"); - } - - { - { - DqnString str = DQN_BUFFER_STR_LIT("hello world"); - 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); - } - - { - DqnString str = DQN_BUFFER_STR_LIT("hello world"); - 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); - } - - Log(Status::Ok, "Concatenation, operator +=, SprintfAppend"); - } - - { - DqnString str; - str = "hello big world"; - DQN_ASSERT(DqnStr_Cmp(str.str, "hello big world") == 0); - str.Free(); - - str = DqnString("goodbye", DQN_CHAR_COUNT("goodbye")); - DQN_ASSERT(DqnStr_Cmp(str.str, "goodbye") == 0); - Log(Status::Ok, "Copy constructor (char const *str, int len)"); - } - - { - DqnString str = DQN_BUFFER_STR_LIT("hello world"); - 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); - - Log(Status::Ok, "Operator +"); - } - - { - DqnString str = "localhost"; - 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); - - Log(Status::Ok, "Copy constructor, sprintf, operator +="); - } -} - -void DqnRnd_Test() -{ - LOG_HEADER(); - - auto pcg = DqnRndPCG(); - for (i32 i = 0; i < 1000000; i++) - { - i32 min = -100; - i32 max = 1000000000; - i32 result = pcg.Range(min, max); - DQN_ASSERT(result >= min && result <= max); - - f32 rand_f32 = pcg.Nextf(); - DQN_ASSERT(rand_f32 >= 0.0f && rand_f32 <= 1.0f); - } - Log(Status::Ok, "DqnRndPCG"); -} - -void DqnMath_Test() -{ - LOG_HEADER(); - - // Lerp - if (1) - { - if (1) - { - f32 start = 10; - f32 t = 0.5f; - f32 end = 20; - DQN_ASSERT(DqnMath_Lerp(start, t, end) == 15); - } - - if (1) - { - f32 start = 10; - f32 t = 2.0f; - f32 end = 20; - DQN_ASSERT(DqnMath_Lerp(start, t, end) == 30); - } - - Log(Status::Ok, "Lerp"); - } - - // Sqrtf - if (1) - { - DQN_ASSERT(DqnMath_Sqrtf(4.0f) == 2.0f); - Log(Status::Ok, "Sqrtf"); - } - - // Handmade Math Test - if (1) - { - if (1) - { - f32 aspect_ratio = 1; - DqnMat4 dqn_perspective = DqnMat4_Perspective(90, aspect_ratio, 100, 1000); - hmm_mat4 hmm_perspective = HMM_Perspective(90, aspect_ratio, 100, 1000); - HandmadeMathVerifyMat4(dqn_perspective, hmm_perspective); - - Log(Status::Ok, "HandmadeMathTest: Perspective"); - } - - // Test Mat4 translate * scale - if (1) - { - hmm_vec3 hmm_vec = HMM_Vec3i(1, 2, 3); - DqnV3 dqn_vec = DqnV3(1, 2, 3); - DqnMat4 dqn_translate = DqnMat4_Translate3f(dqn_vec.x, dqn_vec.y, dqn_vec.z); - hmm_mat4 hmm_translate = HMM_Translate(hmm_vec); - HandmadeMathVerifyMat4(dqn_translate, hmm_translate); - - hmm_vec3 hmm_axis = HMM_Vec3(0.5f, 0.2f, 0.7f); - DqnV3 dqn_axis = DqnV3(0.5f, 0.2f, 0.7f); - f32 rotation_in_degrees = 80.0f; - - DqnMat4 dqn_rotate = DqnMat4_Rotate(DQN_DEGREES_TO_RADIANS(rotation_in_degrees), dqn_axis.x, - dqn_axis.y, dqn_axis.z); - hmm_mat4 hmm_rotate = HMM_Rotate(rotation_in_degrees, hmm_axis); - HandmadeMathVerifyMat4(dqn_rotate, hmm_rotate); - - dqn_vec *= 2; - hmm_vec *= 2; - DqnMat4 dqn_scale = DqnMat4_Scale(dqn_vec.x, dqn_vec.y, dqn_vec.z); - hmm_mat4 hmm_scale = HMM_Scale(hmm_vec); - HandmadeMathVerifyMat4(dqn_scale, hmm_scale); - - DqnMat4 dqn_ts_matrix = DqnMat4_Mul(dqn_translate, dqn_scale); - hmm_mat4 hmm_ts_matrix = HMM_MultiplyMat4(hmm_translate, hmm_scale); - HandmadeMathVerifyMat4(dqn_ts_matrix, hmm_ts_matrix); - - // Test Mat4 * MulV4 - if (1) - { - DqnV4 dqn_v4 = DqnV4(1, 2, 3, 4); - hmm_vec4 hmm_v4 = HMM_Vec4(1, 2, 3, 4); - - DqnV4 dqn_result = DqnMat4_MulV4(dqn_ts_matrix, dqn_v4); - hmm_vec4 hmmResult = HMM_MultiplyMat4ByVec4(hmm_ts_matrix, hmm_v4); - - DQN_ASSERT(dqn_result.x == hmmResult.X); - DQN_ASSERT(dqn_result.y == hmmResult.Y); - DQN_ASSERT(dqn_result.z == hmmResult.Z); - DQN_ASSERT(dqn_result.w == hmmResult.W); - - Log(Status::Ok, "HandmadeMathTest: Mat4 * MulV4"); - } - } - } -} - -void DqnVX_Test() -{ - LOG_HEADER(); - - // V2 - if (1) - { - // Ctor - if (1) - { - // Ctor with floats - if (1) - { - DqnV2 vec = DqnV2(5.5f, 5.0f); - DQN_ASSERT(vec.x == 5.5f && vec.y == 5.0f); - DQN_ASSERT(vec.w == 5.5f && vec.h == 5.0f); - } - - // Ctor with 2 integers - if (1) - { - DqnV2 vec = DqnV2(3, 5); - DQN_ASSERT(vec.x == 3 && vec.y == 5.0f); - DQN_ASSERT(vec.w == 3 && vec.h == 5.0f); - } - Log(Status::Ok, "DqnV2: Ctor"); - } - - // V2 Arithmetic - if (1) - { - DqnV2 vec_a = DqnV2(5, 10); - DqnV2 vec_b = DqnV2(2, 3); - DQN_ASSERT(DqnV2_Equals(vec_a, vec_b) == false); - DQN_ASSERT(DqnV2_Equals(vec_a, DqnV2(5, 10)) == true); - DQN_ASSERT(DqnV2_Equals(vec_b, DqnV2(2, 3)) == true); - - DqnV2 result = DqnV2_Add(vec_a, DqnV2(5, 10)); - DQN_ASSERT(DqnV2_Equals(result, DqnV2(10, 20)) == true); - - result = DqnV2_Sub(result, DqnV2(5, 10)); - DQN_ASSERT(DqnV2_Equals(result, DqnV2(5, 10)) == true); - - result = DqnV2_Scalef(result, 5); - DQN_ASSERT(DqnV2_Equals(result, DqnV2(25, 50)) == true); - - result = DqnV2_Hadamard(result, DqnV2(10.0f, 0.5f)); - DQN_ASSERT(DqnV2_Equals(result, DqnV2(250, 25)) == true); - - f32 dot_result = DqnV2_Dot(DqnV2(5, 10), DqnV2(3, 4)); - DQN_ASSERT(dot_result == 55); - Log(Status::Ok, "DqnV2: Arithmetic"); - } - - // Test operator overloading - if (1) - { - DqnV2 vec_a = DqnV2(5, 10); - DqnV2 vec_b = DqnV2(2, 3); - DQN_ASSERT((vec_a == vec_b) == false); - DQN_ASSERT((vec_a == DqnV2(5, 10)) == true); - DQN_ASSERT((vec_b == DqnV2(2, 3)) == true); - - DqnV2 result = vec_a + DqnV2(5, 10); - DQN_ASSERT((result == DqnV2(10, 20)) == true); - - result -= DqnV2(5, 10); - DQN_ASSERT((result == DqnV2(5, 10)) == true); - - result *= 5; - DQN_ASSERT((result == DqnV2(25, 50)) == true); - - result = result * DqnV2(10.0f, 0.5f); - DQN_ASSERT((result == DqnV2(250, 25)) == true); - - result += DqnV2(1, 1); - DQN_ASSERT((result == DqnV2(251, 26)) == true); - - result = result - DqnV2(1, 1); - DQN_ASSERT((result == DqnV2(250, 25)) == true); - Log(Status::Ok, "DqnV2: Operator Overloading"); - } - - // V2 Properties - if (1) - { - const f32 EPSILON = 0.001f; - DqnV2 a = DqnV2(0, 0); - DqnV2 b = DqnV2(3, 4); - - f32 len_sq = DqnV2_LengthSquared(a, b); - DQN_ASSERT(len_sq == 25); - - f32 length = DqnV2_Length(a, b); - DQN_ASSERT(length == 5); - - DqnV2 normalised = DqnV2_Normalise(b); - f32 norm_x = b.x / 5.0f; - f32 norm_y = b.y / 5.0f; - f32 diff_norm_x = normalised.x - norm_x; - f32 diff_norm_y = normalised.y - norm_y; - DQN_ASSERTM(diff_norm_x < EPSILON, "normalised.x: %f, norm_x: %f\n", normalised.x, norm_x); - DQN_ASSERTM(diff_norm_y < EPSILON, "normalised.y: %f, norm_y: %f\n", normalised.y, norm_y); - - DqnV2 c = DqnV2(3.5f, 8.0f); - DQN_ASSERT(DqnV2_Overlaps(b, c) == true); - DQN_ASSERT(DqnV2_Overlaps(b, a) == false); - - DqnV2 d = DqnV2_Perpendicular(c); - DQN_ASSERT(DqnV2_Dot(c, d) == 0); - - Log(Status::Ok, "DqnV2: LengthSquared, Length, Normalize, Overlaps, Perp"); - } - - // ConstrainToRatio - if (1) - { - DqnV2 ratio = DqnV2(16, 9); - DqnV2 dim = DqnV2(2000, 1080); - DqnV2 result = DqnV2_ConstrainToRatio(dim, ratio); - DQN_ASSERT(result.w == 1920 && result.h == 1080); - Log(Status::Ok, "DqnV2: ConstrainToRatio"); - } - } - - // V3 - if (1) - { - // Ctor - if (1) - { - // Floats - if (1) - { - DqnV3 vec = DqnV3(5.5f, 5.0f, 5.875f); - DQN_ASSERT(vec.x == 5.5f && vec.y == 5.0f && vec.z == 5.875f); - DQN_ASSERT(vec.r == 5.5f && vec.g == 5.0f && vec.b == 5.875f); - } - - // Integers - if (1) - { - DqnV3 vec = DqnV3(3, 4, 5); - DQN_ASSERT(vec.x == 3 && vec.y == 4 && vec.z == 5); - DQN_ASSERT(vec.r == 3 && vec.g == 4 && vec.b == 5); - } - Log(Status::Ok, "DqnV3: Ctor"); - } - - if (1) - { - // Arithmetic - if (1) - { - DqnV3 vec_a = DqnV3(5, 10, 15); - DqnV3 vec_b = DqnV3(2, 3, 6); - DQN_ASSERT(DqnV3_Equals(vec_a, vec_b) == false); - DQN_ASSERT(DqnV3_Equals(vec_a, DqnV3(5, 10, 15)) == true); - DQN_ASSERT(DqnV3_Equals(vec_b, DqnV3(2, 3, 6)) == true); - - DqnV3 result = DqnV3_Add(vec_a, DqnV3(5, 10, 15)); - DQN_ASSERT(DqnV3_Equals(result, DqnV3(10, 20, 30)) == true); - - result = DqnV3_Sub(result, DqnV3(5, 10, 15)); - DQN_ASSERT(DqnV3_Equals(result, DqnV3(5, 10, 15)) == true); - - result = DqnV3_Scalef(result, 5); - DQN_ASSERT(DqnV3_Equals(result, DqnV3(25, 50, 75)) == true); - - result = DqnV3_Hadamard(result, DqnV3(10.0f, 0.5f, 10.0f)); - DQN_ASSERT(DqnV3_Equals(result, DqnV3(250, 25, 750)) == true); - - f32 dot_result = DqnV3_Dot(DqnV3(5, 10, 2), DqnV3(3, 4, 6)); - DQN_ASSERT(dot_result == 67); - - DqnV3 cross = DqnV3_Cross(vec_a, vec_b); - DQN_ASSERT(DqnV3_Equals(cross, DqnV3(15, 0, -5)) == true); - } - - // Operator overloading - if (1) - { - DqnV3 vec_a = DqnV3(5, 10, 15); - DqnV3 vec_b = DqnV3(2, 3, 6); - DQN_ASSERT((vec_a == vec_b) == false); - DQN_ASSERT((vec_a == DqnV3(5, 10, 15)) == true); - DQN_ASSERT((vec_b == DqnV3(2, 3, 6)) == true); - - DqnV3 result = vec_a + DqnV3(5, 10, 15); - DQN_ASSERT((result == DqnV3(10, 20, 30)) == true); - - result -= DqnV3(5, 10, 15); - DQN_ASSERT((result == DqnV3(5, 10, 15)) == true); - - result = result * 5; - DQN_ASSERT((result == DqnV3(25, 50, 75)) == true); - - result *= DqnV3(10.0f, 0.5f, 10.0f); - DQN_ASSERT((result == DqnV3(250, 25, 750)) == true); - - result = result - DqnV3(1, 1, 1); - DQN_ASSERT((result == DqnV3(249, 24, 749)) == true); - - result += DqnV3(1, 1, 1); - DQN_ASSERT((result == DqnV3(250, 25, 750)) == true); - } - Log(Status::Ok, "DqnV3: Arithmetic"); - } - } - - // V4 - if (1) - { - - // Ctor - if (1) - { - // Floats - if (1) - { - DqnV4 vec = DqnV4(5.5f, 5.0f, 5.875f, 5.928f); - DQN_ASSERT(vec.x == 5.5f && vec.y == 5.0f && vec.z == 5.875f && vec.w == 5.928f); - DQN_ASSERT(vec.r == 5.5f && vec.g == 5.0f && vec.b == 5.875f && vec.a == 5.928f); - } - - // Integers - if (1) - { - DqnV4 vec = DqnV4(3, 4, 5, 6); - DQN_ASSERT(vec.x == 3 && vec.y == 4 && vec.z == 5 && vec.w == 6); - DQN_ASSERT(vec.r == 3 && vec.g == 4 && vec.b == 5 && vec.a == 6); - } - Log(Status::Ok, "DqnV4: Ctor"); - } - // V4 Arithmetic - if (1) - { - // Arithmetic - { - DqnV4 vec_a = DqnV4(5, 10, 15, 20); - DqnV4 vec_b = DqnV4(2, 3, 6, 8); - DQN_ASSERT(DqnV4_Equals(vec_a, vec_b) == false); - DQN_ASSERT(DqnV4_Equals(vec_a, DqnV4(5, 10, 15, 20)) == true); - DQN_ASSERT(DqnV4_Equals(vec_b, DqnV4(2, 3, 6, 8)) == true); - - DqnV4 result = DqnV4_Add(vec_a, DqnV4(5, 10, 15, 20)); - DQN_ASSERT(DqnV4_Equals(result, DqnV4(10, 20, 30, 40)) == true); - - result = DqnV4_Sub(result, DqnV4(5, 10, 15, 20)); - DQN_ASSERT(DqnV4_Equals(result, DqnV4(5, 10, 15, 20)) == true); - - result = DqnV4_Scalef(result, 5); - DQN_ASSERT(DqnV4_Equals(result, DqnV4(25, 50, 75, 100)) == true); - - result = DqnV4_Hadamard(result, DqnV4(10.0f, 0.5f, 10.0f, 0.25f)); - DQN_ASSERT(DqnV4_Equals(result, DqnV4(250, 25, 750, 25)) == true); - - f32 dot_result = DqnV4_Dot(DqnV4(5, 10, 2, 8), DqnV4(3, 4, 6, 5)); - DQN_ASSERT(dot_result == 107); - } - - // Operator Overloading - if (1) - { - DqnV4 vec_a = DqnV4(5, 10, 15, 20); - DqnV4 vec_b = DqnV4(2, 3, 6, 8); - DQN_ASSERT((vec_a == vec_b) == false); - DQN_ASSERT((vec_a == DqnV4(5, 10, 15, 20)) == true); - DQN_ASSERT((vec_b == DqnV4(2, 3, 6, 8)) == true); - - DqnV4 result = vec_a + DqnV4(5, 10, 15, 20); - DQN_ASSERT((result == DqnV4(10, 20, 30, 40)) == true); - - result = result - DqnV4(5, 10, 15, 20); - DQN_ASSERT((result == DqnV4(5, 10, 15, 20)) == true); - - result = result * 5; - DQN_ASSERT((result == DqnV4(25, 50, 75, 100)) == true); - - result *= DqnV4(10.0f, 0.5f, 10.0f, 0.25f); - DQN_ASSERT((result == DqnV4(250, 25, 750, 25)) == true); - - result += DqnV4(1, 1, 1, 1); - DQN_ASSERT((result == DqnV4(251, 26, 751, 26)) == true); - - result -= DqnV4(1, 1, 1, 1); - DQN_ASSERT((result == DqnV4(250, 25, 750, 25)) == true); - } - Log(Status::Ok, "DqnV4: Arithmetic"); - } - } -} - -void DqnRect_Test() -{ - LOG_HEADER(); - // Rect - if (1) - { - // Test rect init functions - if (1) - { - DqnRect rect4f = DqnRect(1.1f, 2.2f, 3.3f, 4.4f); - DqnRect rect4i = DqnRect(1, 2, 3, 4); - - DQN_ASSERT(rect4i.min.x == 1 && rect4i.min.y == 2); - DQN_ASSERT(rect4i.max.x == 4 && rect4i.max.y == 6); - - const f32 EPSILON = 0.001f; - f32 diff_max_x = rect4f.max.x - 4.4f; - f32 diff_max_y = rect4f.max.y - 6.6f; - DQN_ASSERT(rect4f.min.x == 1.1f && rect4f.min.y == 2.2f); - DQN_ASSERT(DQN_ABS(diff_max_x) < EPSILON && DQN_ABS(diff_max_y) < EPSILON); - - DqnRect rect = DqnRect(-10, -10, 20, 20); - DQN_ASSERT(DqnV2_Equals(rect.min, DqnV2(-10, -10))); - DQN_ASSERT(DqnV2_Equals(rect.max, DqnV2(10, 10))); - Log(Status::Ok, "Ctor"); - } - - // Test rect get size function - if (1) - { - // Test float rect - if (1) - { - DqnRect rect = DqnRect(DqnV2(-10, -10), DqnV2(20, 20)); - - f32 width, height; - rect.GetSize(&width, &height); - DQN_ASSERT(width == 20); - DQN_ASSERT(height == 20); - - DqnV2 dim = rect.GetSize(); - DQN_ASSERT(DqnV2_Equals(dim, DqnV2(20, 20))); - Log(Status::Ok, "GetSize"); - } - } - - // Test rect get centre - DqnRect rect = DqnRect(DqnV2(-10, -10), DqnV2(20, 20)); - DqnV2 rect_centre = rect.GetCenter(); - DQN_ASSERT(DqnV2_Equals(rect_centre, DqnV2(0, 0))); - Log(Status::Ok, "GetCentre"); - - // Test clipping rect get centre - DqnRect clip_rect = DqnRect(DqnV2(-15, -15), DqnV2(10, 10) + DqnV2(15)); - DqnRect clip_result = rect.ClipRect(clip_rect); - DQN_ASSERT(clip_result.min.x == -10 && clip_result.min.y == -10); - DQN_ASSERT(clip_result.max.x == 10 && clip_result.max.y == 10); - Log(Status::Ok, "ClipRect"); - - // Test shifting rect - if (1) - { - DqnRect shifted_rect = rect.Move(DqnV2(10, 0)); - DQN_ASSERT(DqnV2_Equals(shifted_rect.min, DqnV2(0, -10))); - DQN_ASSERT(DqnV2_Equals(shifted_rect.max, DqnV2(20, 10))); - - // Ensure dimensions have remained the same - if (1) - { - f32 width, height; - shifted_rect.GetSize(&width, &height); - DQN_ASSERT(width == 20); - DQN_ASSERT(height == 20); - - DqnV2 dim = shifted_rect.GetSize(); - DQN_ASSERT(DqnV2_Equals(dim, DqnV2(20, 20))); - } - - // Test rect contains p - if (1) - { - DqnV2 inP = DqnV2(5, 5); - DqnV2 outP = DqnV2(100, 100); - DQN_ASSERT(shifted_rect.ContainsP(inP)); - DQN_ASSERT(!shifted_rect.ContainsP(outP)); - } - - Log(Status::Ok, "Move"); - } - } -} - -void DqnArray_TestRealDataInternal(DqnArray *array) -{ - (void)array; -#ifdef DQN_PLATFORM_HEADER - size_t buf_size = 0; - u8 *buf = DqnFile_ReadAll("tests/google-10000-english.txt", &buf_size); - DQN_ASSERT(buf); - - for (usize i = 0; i < buf_size; i++) - array->Push(buf[i]); - - DQN_ASSERT((size_t)array->len == buf_size); - for (auto i = 0; i < array->len; i++) - DQN_ASSERT(array->data[i] == buf[i]); - - array->Free(); - free(buf); - - Log(Status::Ok, "Testing real data"); -#endif -} - -void DqnArray_Test() -{ - LOG_HEADER(); - if (1) - { - if (1) - { - DqnArray array1 = {}; - array1.Reserve(3); - DQN_ASSERT(array1.len == 0); - DQN_ASSERT(array1.max == 3); - array1.Free(); - - array1.Reserve(0); - DQN_ASSERT(array1.len == 0); - DQN_ASSERT(array1.max == 0); - - array1.Push('c'); - DQN_ASSERT(array1.len == 1); - array1.Free(); - - Log(Status::Ok, "Testing faux-array constructors DqnArray_()"); - } - - if (1) - { - DqnArray array = {}; - array.Reserve(1); - DqnArray_TestRealDataInternal(&array); - } - - if (1) - { - auto stack = DqnMemStack(DQN_MEGABYTE(1), Dqn::ZeroMem::Yes, 0, DqnMemTracker::Flag::Simple); - DQN_DEFER { stack.Free(); }; -#if 0 - if (1) - { - auto memGuard0 = stack.TempRegionGuard(); - DqnArray array(&stack.myHeadAPI); - array.Reserve(1); - DqnArray_TestRealDataInternal(&array); - } - - // Test reallocing strategies for memory stacks - if (1) - { - auto memGuard0 = stack.TempRegionGuard(); - DqnArray array(&stack.myHeadAPI); - array.Reserve(128); - stack.Push(1024); - DqnArray_TestRealDataInternal(&array); - } -#endif - } - } -} - -#ifdef DQN_PLATFORM_HEADER -void DqnFile_Test() -{ - LOG_HEADER(); - // File i/o - if (1) - { - - // Test file open - if (1) - { - const char *const FILE_TO_OPEN = ".clang-format"; - u32 expectedSize = 0; -#if defined(DQN__IS_UNIX) - { - struct stat fileStat = {0}; - DQN_ASSERT(stat(FILE_TO_OPEN, &fileStat) == 0); - expectedSize = fileStat.st_size; - } - - if (1) - { - // NOTE: cpuinfo is generated when queried, so a normal 'stat' - // should give us zero, but we fall back to manual byte checking - // which should give us the proper size. - size_t size = 0; - DQN_ASSERT(DqnFile_Size("/proc/cpuinfo", &size)); - DQN_ASSERT(size > 0); - } - -#else - { - HANDLE handle = CreateFile(FILE_TO_OPEN, GENERIC_READ, 0, NULL, OPEN_EXISTING, - FILE_ATTRIBUTE_NORMAL, NULL); - if (handle == INVALID_HANDLE_VALUE) - { - DqnWin32_DisplayLastError("CreateFile() failed"); - } - DQN_ASSERT(handle != INVALID_HANDLE_VALUE); - - LARGE_INTEGER size; - DQN_ASSERT(GetFileSizeEx(handle, &size)); - - CloseHandle(handle); - expectedSize = size.LowPart; - } -#endif - - if (1) - { - size_t size = 0; - DQN_ASSERT(DqnFile_Size(FILE_TO_OPEN, &size)); - DQN_ASSERT(size == expectedSize); - } - - DqnFile file = {}; - DQN_ASSERT(file.Open( - ".clang-format", DqnFile::Flag::FileReadWrite, DqnFile::Action::OpenOnly)); - - DQN_ASSERTM(file.size == expectedSize, - "DqnFileOpen() failed: file.size: %d, expected:%d\n", file.size, - expectedSize); - - u8 *buffer = (u8 *)calloc(1, (size_t)file.size * sizeof(u8)); - DQN_ASSERT(file.Read(buffer, (u32)file.size) == file.size); - free(buffer); - - file.Close(); - DQN_ASSERT(!file.handle && file.size == 0 && file.flags == 0); - - Log(Status::Ok, "General test"); - } - - // Test invalid file - if (1) - { - DqnFile file = {}; - DQN_ASSERT(!file.Open( - "asdljasdnel;kajdf", DqnFile::Flag::FileReadWrite, DqnFile::Action::OpenOnly)); - DQN_ASSERT(file.size == 0); - DQN_ASSERT(file.flags == 0); - DQN_ASSERT(!file.handle); - Log(Status::Ok, "Invalid file test"); - } - } - - // Write Test - if (1) - { - const char *file_names[] = {"dqn_1", "dqn_2", "dqn_3", "dqn_4", "dqn_5"}; - const char *writeData[] = {"1234", "2468", "36912", "481216", "5101520"}; - DqnFile files[DQN_ARRAY_COUNT(file_names)] = {}; - - // Write data out to some files - for (u32 i = 0; i < DQN_ARRAY_COUNT(file_names); i++) - { - u32 permissions = DqnFile::Flag::FileReadWrite; - DqnFile *file = files + i; - if (!file->Open(file_names[i], permissions, DqnFile::Action::ClearIfExist)) - { - bool result = - file->Open(file_names[i], permissions, DqnFile::Action::CreateIfNotExist); - DQN_ASSERT(result); - } - - size_t bytesToWrite = DqnStr_Len(writeData[i]); - u8 *dataToWrite = (u8 *)(writeData[i]); - size_t bytesWritten = file->Write(dataToWrite, bytesToWrite); - DQN_ASSERT(bytesWritten == bytesToWrite); - file->Close(); - } - - auto memstack = DqnMemStack(DQN_MEGABYTE(1), Dqn::ZeroMem::Yes, DqnMemTracker::Flag::Simple); - // Read data back in - for (u32 i = 0; i < DQN_ARRAY_COUNT(file_names); i++) - { - // Manual read the file contents - { - u32 permissions = DqnFile::Flag::FileRead; - DqnFile *file = files + i; - bool result = file->Open(file_names[i], permissions, DqnFile::Action::OpenOnly); - DQN_ASSERT(result); - - u8 *buffer = (u8 *)memstack.Push_(file->size); - DQN_ASSERT(buffer); - - size_t bytesRead = file->Read(buffer, file->size); - DQN_ASSERT(bytesRead == file->size); - - // Verify the data is the same as we wrote out - DQN_ASSERT(DqnStr_Cmp((char *)buffer, (writeData[i]), (i32)bytesRead) == 0); - - // Delete when we're done with it - memstack.Pop(buffer); - file->Close(); - } - - // Read using the ReadEntireFile api which doesn't need a file handle as an argument - { - size_t reqSize = 0; - DQN_ASSERT(DqnFile_Size(file_names[i], &reqSize)); - - u8 *buffer = (u8 *)memstack.Push_(reqSize); - DQN_ASSERT(buffer); - - DQN_ASSERT(DqnFile_ReadAll(file_names[i], buffer, reqSize)); - - // Verify the data is the same as we wrote out - DQN_ASSERT(DqnStr_Cmp((char *)buffer, (writeData[i]), (i32)reqSize) == 0); - memstack.Pop(buffer); - } - - DQN_ASSERT(DqnFile_Delete(file_names[i])); - } - - // Then check delete actually worked, files should not exist. - for (u32 i = 0; i < DQN_ARRAY_COUNT(file_names); i++) - { - DqnFile dummy = {}; - u32 permissions = DqnFile::Flag::FileRead; - bool fileExists = dummy.Open(file_names[i], permissions, DqnFile::Action::OpenOnly); - DQN_ASSERT(!fileExists); - } - memstack.Free(); - - Log(Status::Ok, "Write file"); - } - - // Test directory listing - if (1) - { - i32 num_files; -#if defined(DQN___IS_UNIX) - char **file_list = DqnFile_ListDir(".", &num_files); -#else - char **file_list = DqnFile_ListDir("*", &num_files); -#endif - - Log("Test directory listing"); - global_indent++; - for (auto i = 0; i < num_files; i++) - Log("%02d: %s", i, file_list[i]); - - DqnFile_ListDirFree(file_list, num_files); - global_indent--; - Log(Status::Ok, "List directory files"); - } - -} - -void PlatformSleep(int milliseconds) -{ -#if defined(DQN__IS_UNIX) - usleep(milliseconds * 1000); -#else - Sleep(milliseconds); -#endif -} - -void DqnTimer_Test() -{ - LOG_HEADER(); - - if (1) - { - - int sleepTimeInMs = 250; - f64 start_in_ms = DqnTimer_NowInMs(); - PlatformSleep(sleepTimeInMs); - f64 end_in_ms = DqnTimer_NowInMs(); - - DQN_ASSERT((start_in_ms + sleepTimeInMs) <= end_in_ms); - Log("start: %f, end: %f", start_in_ms, end_in_ms); - - Log(Status::Ok, "Timer advanced in time over 1 second"); - global_indent++; - Log("Start: %f, End: %f", start_in_ms, end_in_ms); - global_indent--; - } -} - - -FILE_SCOPE u32 volatile global_debug_counter; -FILE_SCOPE DqnLock global_job_queue_lock; -const u32 QUEUE_SIZE = 256; -FILE_SCOPE void JobQueueDebugCallbackIncrementCounter(DqnJobQueue *const queue, void *const user_data) -{ - (void)user_data; - DQN_ASSERT(queue->size == QUEUE_SIZE); - { - auto guard = global_job_queue_lock.Guard(); - global_debug_counter++; - - // u32 number = global_debug_counter; -#if defined(DQN__IS_WIN32) - // Log("JobQueueDebugCallbackIncrementCounter(): Thread %d: Incrementing Number: %d", GetCurrentThreadId(), number); -#else - // Log("JobQueueDebugCallbackIncrementCounter(): Thread unix: Incrementing Number: %d", number); -#endif - } - -} - -FILE_SCOPE void DqnJobQueue_Test() -{ - LOG_HEADER(); - global_debug_counter = 0; - - auto memstack = DqnMemStack(DQN_MEGABYTE(1), Dqn::ZeroMem::Yes, 0, DqnMemTracker::Flag::Simple); - - u32 num_threads, num_cores; - DqnOS_GetThreadsAndCores(&num_cores, &num_threads); - DQN_ASSERT(num_threads > 0 && num_cores > 0); - - u32 total_threads = (num_cores - 1) * num_threads; - if (total_threads == 0) total_threads = 1; - - DqnJobQueue job_queue = {}; - DqnJob *job_list = (DqnJob *)memstack.Push_(sizeof(*job_queue.job_list) * QUEUE_SIZE); - DQN_ASSERT(DqnJobQueue_Init(&job_queue, job_list, QUEUE_SIZE, total_threads)); - - const u32 WORK_ENTRIES = 2048; - DQN_ASSERT(global_job_queue_lock.Init()); - for (u32 i = 0; i < WORK_ENTRIES; i++) - { - DqnJob job = {}; - job.callback = JobQueueDebugCallbackIncrementCounter; - while (!DqnJobQueue_AddJob(&job_queue, job)) - { - DqnJobQueue_TryExecuteNextJob(&job_queue); - } - } - - DqnJobQueue_BlockAndCompleteAllJobs(&job_queue); - DQN_ASSERT(global_debug_counter == WORK_ENTRIES); - global_job_queue_lock.Delete(); - - Log("Final incremented value: %d\n", global_debug_counter); -} - -#else -f64 DqnTimer_NowInMs() { return 0; } -f64 DqnTimer_NowInS() { return 0; } -#endif // DQN_PLATFORM_HEADER - -#include -void DqnQuickSort_Test() -{ - LOG_HEADER(); - auto state = DqnRndPCG(); - if (1) - { - auto stack = DqnMemStack(DQN_KILOBYTE(1), Dqn::ZeroMem::Yes, 0, DqnMemTracker::Flag::Simple); - - // Create array of ints - u32 num_ints = 1000000; - u32 size_in_bytes = sizeof(u32) * num_ints; - u32 *dqn_cpp_array = (u32 *)stack.Push_(size_in_bytes); - u32 *std_array = (u32 *)stack.Push_(size_in_bytes); - DQN_ASSERT(dqn_cpp_array && std_array); - - f64 dqn_cpp_timings[2] = {}; - f64 std_timings[DQN_ARRAY_COUNT(dqn_cpp_timings)] = {}; - - f64 dqn_cpp_avg = 0; - f64 std_avg = 0; - - Log("Timings"); global_indent++; - for (u32 timingsIndex = 0; timingsIndex < DQN_ARRAY_COUNT(dqn_cpp_timings); timingsIndex++) - { - // Populate with random numbers - for (u32 i = 0; i < num_ints; i++) - { - dqn_cpp_array[i] = state.Next(); - std_array[i] = dqn_cpp_array[i]; - } - - global_new_line = false; - Log("%02d: ", timingsIndex); - global_indent -= 2; - // Time Dqn_QuickSort - { - f64 start = DqnTimer_NowInS(); - DqnQuickSort(dqn_cpp_array, num_ints); - - f64 duration = DqnTimer_NowInS() - start; - dqn_cpp_timings[timingsIndex] = duration; - dqn_cpp_avg += duration; - Log("Dqn_QuickSort: %f vs ", dqn_cpp_timings[timingsIndex]); - } - - // Time std::sort - global_new_line = true; - { - f64 start = DqnTimer_NowInS(); - std::sort(std_array, std_array + num_ints); - f64 duration = DqnTimer_NowInS() - start; - - std_timings[timingsIndex] = duration; - std_avg += duration; - - Log("std::sort: %f", std_timings[timingsIndex]); - } - global_indent += 2; - - // Validate algorithm is correct - for (u32 i = 0; i < num_ints; i++) - { - DQN_ASSERTM(dqn_cpp_array[i] == std_array[i], "DqnArray[%d]: %d, std_array[%d]: %d", i, - dqn_cpp_array[i], std_array[i], i); - } - } - global_indent--; - - // Print averages - if (1) - { - dqn_cpp_avg /= (f64)DQN_ARRAY_COUNT(dqn_cpp_timings); - std_avg /= (f64)DQN_ARRAY_COUNT(std_timings); - Log("Average Timings"); - global_indent++; - Log("Dqn_QuickSort: %f vs std::sort: %f\n", dqn_cpp_avg, std_avg); - global_indent--; - } - stack.Free(); - Log(Status::Ok, "QuickSort"); - } -} - -void DqnBSearch_Test() -{ - LOG_HEADER(); - if (1) - { - u32 array[] = {1, 2, 3}; - i64 result = DqnBSearch(array, DQN_ARRAY_COUNT(array), 1); - DQN_ASSERT(result == 0); - - result = DqnBSearch(array, DQN_ARRAY_COUNT(array), 2); - DQN_ASSERT(result == 1); - - result = DqnBSearch(array, DQN_ARRAY_COUNT(array), 3); - DQN_ASSERT(result == 2); - - result = DqnBSearch(array, DQN_ARRAY_COUNT(array), 4); - DQN_ASSERT(result == -1); - Log(Status::Ok, "With odd sized array and custom compare"); - } - - if (1) - { - i64 array[] = {1, 2, 3, 4}; - i64 result = DqnBSearch(array, DQN_ARRAY_COUNT(array), 1); - DQN_ASSERT(result == 0); - - result = DqnBSearch(array, DQN_ARRAY_COUNT(array), 2); - DQN_ASSERT(result == 1); - - result = DqnBSearch(array, DQN_ARRAY_COUNT(array), 3); - DQN_ASSERT(result == 2); - - result = DqnBSearch(array, DQN_ARRAY_COUNT(array), 4); - DQN_ASSERT(result == 3); - - result = DqnBSearch(array, DQN_ARRAY_COUNT(array), 5); - DQN_ASSERT(result == -1); - Log(Status::Ok, "With even sized array"); - } - - if (1) - { - i64 array[] = {1, 2, 3}; - i64 result = DqnBSearch(array, DQN_ARRAY_COUNT(array), 0, DqnBSearchType::MinusOne); - DQN_ASSERT(result == -1); - - result = DqnBSearch(array, DQN_ARRAY_COUNT(array), 1, DqnBSearchType::MinusOne); - DQN_ASSERT(result == -1); - - result = DqnBSearch(array, DQN_ARRAY_COUNT(array), 2, DqnBSearchType::MinusOne); - DQN_ASSERT(result == 0); - - result = DqnBSearch(array, DQN_ARRAY_COUNT(array), 3, DqnBSearchType::MinusOne); - DQN_ASSERT(result == 1); - - result = DqnBSearch(array, DQN_ARRAY_COUNT(array), 4, DqnBSearchType::MinusOne); - DQN_ASSERT(result == 2); - - result = DqnBSearch(array, DQN_ARRAY_COUNT(array), 5, DqnBSearchType::MinusOne); - DQN_ASSERT(result == 2); - Log(Status::Ok, "Lower bound with odd sized array"); - } - - if (1) - { - i64 array[] = {1, 2, 3, 4}; - - i64 result = DqnBSearch(array, DQN_ARRAY_COUNT(array), 0, DqnBSearchType::MinusOne); - DQN_ASSERT(result == -1); - - result = DqnBSearch(array, DQN_ARRAY_COUNT(array), 1, DqnBSearchType::MinusOne); - DQN_ASSERT(result == -1); - - result = DqnBSearch(array, DQN_ARRAY_COUNT(array), 2, DqnBSearchType::MinusOne); - DQN_ASSERT(result == 0); - - result = DqnBSearch(array, DQN_ARRAY_COUNT(array), 3, DqnBSearchType::MinusOne); - DQN_ASSERT(result == 1); - - result = DqnBSearch(array, DQN_ARRAY_COUNT(array), 4, DqnBSearchType::MinusOne); - DQN_ASSERT(result == 2); - - result = DqnBSearch(array, DQN_ARRAY_COUNT(array), 5, DqnBSearchType::MinusOne); - DQN_ASSERT(result == 3); - - result = DqnBSearch(array, DQN_ARRAY_COUNT(array), 6, DqnBSearchType::MinusOne); - DQN_ASSERT(result == 3); - Log(Status::Ok, "Lower bound with even sized array"); - } - - if (1) - { - i64 array[] = {1, 2, 3}; - i64 result = DqnBSearch(array, DQN_ARRAY_COUNT(array), 0, DqnBSearchType::PlusOne); - DQN_ASSERT(result == 0); - - result = DqnBSearch(array, DQN_ARRAY_COUNT(array), 1, DqnBSearchType::PlusOne); - DQN_ASSERT(result == 1); - - result = DqnBSearch(array, DQN_ARRAY_COUNT(array), 2, DqnBSearchType::PlusOne); - DQN_ASSERT(result == 2); - - result = DqnBSearch(array, DQN_ARRAY_COUNT(array), 3, DqnBSearchType::PlusOne); - DQN_ASSERT(result == -1); - - result = DqnBSearch(array, DQN_ARRAY_COUNT(array), 4, DqnBSearchType::PlusOne); - DQN_ASSERT(result == -1); - - result = DqnBSearch(array, DQN_ARRAY_COUNT(array), 5, DqnBSearchType::PlusOne); - DQN_ASSERT(result == -1); - Log(Status::Ok, "Higher bound with odd sized array"); - } - - if (1) - { - i64 array[] = {1, 2, 3, 4}; - - i64 result = DqnBSearch(array, DQN_ARRAY_COUNT(array), 0, DqnBSearchType::PlusOne); - DQN_ASSERT(result == 0); - - result = DqnBSearch(array, DQN_ARRAY_COUNT(array), 1, DqnBSearchType::PlusOne); - DQN_ASSERT(result == 1); - - result = DqnBSearch(array, DQN_ARRAY_COUNT(array), 2, DqnBSearchType::PlusOne); - DQN_ASSERT(result == 2); - - result = DqnBSearch(array, DQN_ARRAY_COUNT(array), 3, DqnBSearchType::PlusOne); - DQN_ASSERT(result == 3); - - result = DqnBSearch(array, DQN_ARRAY_COUNT(array), 4, DqnBSearchType::PlusOne); - DQN_ASSERT(result == -1); - - result = DqnBSearch(array, DQN_ARRAY_COUNT(array), 5, DqnBSearchType::PlusOne); - DQN_ASSERT(result == -1); - - result = DqnBSearch(array, DQN_ARRAY_COUNT(array), 6, DqnBSearchType::PlusOne); - DQN_ASSERT(result == -1); - Log(Status::Ok, "Higher bound with even sized array"); - } -} - -void DqnMemSet_Test() -{ - LOG_HEADER(); - auto rnd = DqnRndPCG(); - - const int NUM_TIMINGS = 5; - f64 timings[2][NUM_TIMINGS] = {}; - f64 avg_timings[DQN_ARRAY_COUNT(timings)] = {}; - void *buffers[DQN_ARRAY_COUNT(timings)] = {}; - - const i32 NUM_ITERATIONS = DQN_ARRAY_COUNT(timings[0]); - Log("Timings"); - for (auto i = 0; i < NUM_ITERATIONS; i++) - { - i32 size = rnd.Range(DQN_MEGABYTE(16), DQN_MEGABYTE(32)); - u8 value = (u8)rnd.Range(0, 255); - - global_indent++; - global_new_line = false; - Log("%02d: ", i); - global_indent--; - global_indent--; - - i32 timingsIndex = 0; - // DqnMem_Set - { - buffers[timingsIndex] = malloc(size); DQN_ASSERT(buffers[timingsIndex]); - - f64 start = DqnTimer_NowInMs(); - DqnMem_Set(buffers[timingsIndex], value, size); - f64 duration = DqnTimer_NowInMs() - start; - - timings[timingsIndex++][i] = duration; - Log("DqnMem_Set: %5.3f vs ", duration); - } - - - // crt memset - { - buffers[timingsIndex] = malloc(size); DQN_ASSERT(buffers[timingsIndex]); - - f64 start = DqnTimer_NowInMs(); - memset(buffers[timingsIndex], value, size); - f64 duration = DqnTimer_NowInMs() - start; - - timings[timingsIndex++][i] = duration; - Log("memset: %5.3f\n", duration); - } - global_indent++; - global_new_line = true; - - for (auto test_index = 0; test_index < size; test_index++) - { - DQN_ASSERT(((u8 *)buffers[0])[test_index] == ((u8 *)buffers[1])[test_index]); - } - - for (usize bufferIndex = 0; bufferIndex < DQN_ARRAY_COUNT(buffers); bufferIndex++) - { - free(buffers[bufferIndex]); - } - } - - for (usize timingsIndex = 0; timingsIndex < DQN_ARRAY_COUNT(timings); timingsIndex++) - { - f64 total_time = 0; - for (auto iteration_index = 0; iteration_index < NUM_ITERATIONS; iteration_index++) - { - total_time += timings[timingsIndex][iteration_index]; - } - avg_timings[timingsIndex] = total_time / (f64)NUM_ITERATIONS; - } - - Log("Average Timings"); - global_indent++; - Log("DqnMem_Set: %f vs memset: %f\n", avg_timings[0], avg_timings[1]); - global_indent--; - - Log(Status::Ok, "MemSet"); -} - -struct RawBuf -{ - char *buffer; - int len; -}; - -DQN_CATALOG_LOAD_PROC(CatalogRawLoad, RawBuf) -{ - usize buf_size; - u8 *buf = DqnFile_ReadAll(file.str, &buf_size); - - if (!buf) - return false; - - data->buffer = reinterpret_cast(buf); - data->len = static_cast(buf_size); - return true; -} - -void DqnCatalog_Test() -{ - LOG_HEADER(); - - DqnCatalog catalog = {}; - catalog.PollAssets(); - - DqnCatalogPath path = "DqnCatalog_TrackFile"; - DqnFile_Delete(path.str); - - // Initially write the file and check the catalog is able to open it up - { - char const write_buf[] = "aaaa"; - DqnFile_WriteAll(path.str, reinterpret_cast(write_buf), DQN_CHAR_COUNT(write_buf)); - RawBuf *buf = catalog.GetIfUpdated(path); - DQN_ASSERT(DqnMem_Cmp(buf->buffer, write_buf, DQN_CHAR_COUNT(write_buf)) == 0); - Log(Status::Ok, "Catalog finds and loads on demand new file"); - } - - // Update the file and check that the GetIfUpdated returns a non-nullptr (because the entry is updated) - { - PlatformSleep(1000); - char const write_buf[] = "xxxx"; - DqnFile_WriteAll(path.str, reinterpret_cast(write_buf), DQN_CHAR_COUNT(write_buf)); - RawBuf *buf = catalog.GetIfUpdated(path); - DQN_ASSERT(DqnMem_Cmp(buf->buffer, write_buf, DQN_CHAR_COUNT(write_buf)) == 0); - Log(Status::Ok, "Catalog finds updated file after subsequent write"); - } - - // Update the file and get the catalog to poll the entries and check it has been updated - { - PlatformSleep(1000); - char const write_buf[] = "abcd"; - DqnFile_WriteAll(path.str, reinterpret_cast(write_buf), DQN_CHAR_COUNT(write_buf)); - catalog.PollAssets(); - - RawBuf *buf = catalog.GetIfUpdated(path); - DQN_ASSERT(DqnMem_Cmp(buf->buffer, write_buf, DQN_CHAR_COUNT(write_buf)) == 0); - Log(Status::Ok, "Catalog finds updated file using the poll asset interface"); - } - - // Update the file and get the catalog to poll the entries and check it has been updated - { - catalog.Erase(path.str); - RawBuf *buf = catalog.Get(path); - DQN_ASSERT(buf == nullptr); - Log(Status::Ok, "Catalog erase removes file from catalog"); - } - - DqnFile_Delete(path.str); -} - -int main(void) -{ - global_indent = 1; - global_new_line = true; - DqnString_Test(); - DqnMemStack_Test(); - DqnChar_Test(); - DqnRnd_Test(); - DqnMath_Test(); - DqnVX_Test(); - DqnRect_Test(); - DqnArray_Test(); - DqnQuickSort_Test(); - DqnBSearch_Test(); - DqnMemSet_Test(); - DqnFixedString_Test(); - DqnJson_Test(); - -#ifdef DQN_PLATFORM_HEADER - DqnVHashTable_Test(); - DqnOS_Test(); - DqnFile_Test(); - DqnCatalog_Test(); - DqnTimer_Test(); - DqnJobQueue_Test(); -#endif - - // Log("\nPress 'Enter' Key to Exit\n"); - // getchar(); - - return 0; -} - -#if defined(__GNUC__) - #pragma GCC diagnostic pop -#endif - diff --git a/Code/Deprecated/DqnUnitTest.sln b/Code/Deprecated/DqnUnitTest.sln deleted file mode 100644 index cadd90f..0000000 --- a/Code/Deprecated/DqnUnitTest.sln +++ /dev/null @@ -1,32 +0,0 @@ - -Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 15 -VisualStudioVersion = 15.0.27428.2037 -MinimumVisualStudioVersion = 10.0.40219.1 -Project("{911E67C6-3D85-4FCE-B560-20A9C3E3FF48}") = "DqnUnitTest", "bin\DqnUnitTest.exe", "{F1606403-E704-4C35-8354-8E33DE4F5CCF}" - ProjectSection(DebuggerProjectSystem) = preProject - PortSupplier = 00000000-0000-0000-0000-000000000000 - Executable = F:\dev\dqn\bin\DqnUnitTest.exe - RemoteMachine = THAI-XPS13 - StartingDirectory = F:\dev\dqn\ - Environment = Default - LaunchingEngine = 00000000-0000-0000-0000-000000000000 - UseLegacyDebugEngines = No - LaunchSQLEngine = No - AttachLaunchAction = No - EndProjectSection -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Release|x64 = Release|x64 - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {F1606403-E704-4C35-8354-8E33DE4F5CCF}.Release|x64.ActiveCfg = Release|x64 - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection - GlobalSection(ExtensibilityGlobals) = postSolution - SolutionGuid = {8DD71C86-534C-4A9C-A217-CBA13DE8DA5A} - EndGlobalSection -EndGlobal diff --git a/Code/Deprecated/DqnVHashTable.cpp b/Code/Deprecated/DqnVHashTable.cpp deleted file mode 100644 index 516a124..0000000 --- a/Code/Deprecated/DqnVHashTable.cpp +++ /dev/null @@ -1,88 +0,0 @@ -void DqnVHashTable_Test() -{ - LOG_HEADER(); - struct Block - { - int x; - }; - using Height = u32; - - { - Block block = {}; - - DqnVHashTable table = {}; - DQN_DEFER { table.Free(); }; - table.Set(12, block); - - Block *getResult = table.Get(12); - Block *operatorResult = table[12]; - DQN_ASSERT(operatorResult == getResult); - DQN_ASSERT(operatorResult != nullptr); - Log(Status::Ok, "Set and get element using key"); - - table.Erase(12); - getResult = table.Get(12); - operatorResult = table[12]; - - DQN_ASSERT(operatorResult == getResult); - DQN_ASSERT(operatorResult == nullptr); - Log(Status::Ok, "Erase element using key"); - } - - { - Block blocks[] = {{0}, {1}, {2}, {3}, {4}}; - DqnVHashTable table = {}; - DQN_DEFER { table.Free(); }; - - table.Set(1, blocks[0]); - table.Set(2, blocks[1]); - table.Set(3, blocks[2]); - table.Set(4, blocks[3]); - table.Set(5, blocks[4]); - - { - bool blockSeen[DQN_ARRAY_COUNT(blocks)] = {}; - isize blocksSeen = 0; - for (auto const &entry : table) - { - Block const *block = &entry.item; - DQN_ASSERT(blockSeen[block->x] == false); - blockSeen[block->x] = true; - blocksSeen++; - } - DQN_ASSERT(blocksSeen == DQN_ARRAY_COUNT(blockSeen)); - Log(Status::Ok, "Auto iterator using prefix operator++"); - } - - { - bool blockSeen[DQN_ARRAY_COUNT(blocks)] = {}; - isize blocksSeen = 0; - for (auto it = table.begin(); it != table.end();) - { - Block *block = &it.entry->item; - - DQN_ASSERT(blockSeen[block->x] == false); - blockSeen[block->x] = true; - blocksSeen++; - it = it + 1; - } - DQN_ASSERT(blocksSeen == DQN_ARRAY_COUNT(blockSeen)); - Log(Status::Ok, "Auto iterator using operator+"); - } - - { - bool blockSeen[DQN_ARRAY_COUNT(blocks)] = {}; - isize blocksSeen = 0; - for (auto it = table.begin(); it != table.end(); it++) - { - Block *block = &it.entry->item; - - DQN_ASSERT(blockSeen[block->x] == false); - blockSeen[block->x] = true; - blocksSeen++; - } - DQN_ASSERT(blocksSeen == DQN_ARRAY_COUNT(blockSeen)); - Log(Status::Ok, "Auto iterator using postfix operator++"); - } - } -} diff --git a/Code/Deprecated/HandmadeMath.h b/Code/Deprecated/HandmadeMath.h deleted file mode 100644 index 9617995..0000000 --- a/Code/Deprecated/HandmadeMath.h +++ /dev/null @@ -1,2667 +0,0 @@ -#ifdef __GNUC__ - #pragma GCC diagnostic push - #pragma GCC diagnostic ignored "-Wpsabi" -#endif -/* - HandmadeMath.h v1.1.2 - - This is a single header file with a bunch of useful functions for - basic game math operations. - - ========================================================================== - - You MUST - - #define HANDMADE_MATH_IMPLEMENTATION - - in EXACTLY one C or C++ file that includes this header, BEFORE the - include, like this: - - #define HANDMADE_MATH_IMPLEMENTATION - #include "HandmadeMath.h" - - All other files should just #include "HandmadeMath.h" without the #define. - - ========================================================================== - - For overloaded and operator overloaded versions of the base C functions, - you MUST - - #define HANDMADE_MATH_CPP_MODE - - in EXACTLY one C or C++ file that includes this header, BEFORE the - include, like this: - - #define HANDMADE_MATH_IMPLEMENTATION - #define HANDMADE_MATH_CPP_MODE - #include "HandmadeMath.h" - - All other files should just #include "HandmadeMath.h" without the #define. - - ========================================================================== - - To disable SSE intrinsics, you MUST - - #define HANDMADE_MATH_NO_SSE - - in EXACTLY one C or C++ file that includes this header, BEFORE the - include, like this: - - #define HANDMADE_MATH_IMPLEMENTATION - #define HANDMADE_MATH_CPP_MODE - #define HANDMADE_MATH_NO_SSE - #include "HandmadeMath.h" - - or - - #define HANDMADE_MATH_IMPLEMENTATION - #define HANDMADE_MATH_NO_SSE - #include "HandmadeMath.h" - - ========================================================================== - - To disable inlining functions, you MUST - - #define HANDMADE_MATH_NO_INLINE - - in EXACTLY one C or C++ file that includes this header, BEFORE the - include, like this: - - #define HANDMADE_MATH_IMPLEMENTATION - #define HANDMADE_MATH_CPP_MODE - #define HANDMADE_MATH_NO_INLINE - #include "HandmadeMath.h" - - All other files should just #include "HandmadeMath.h" without the #define. - - ========================================================================== - - To Disable the CRT, you MUST - - #define HMM_SINF MySinF - #define HMM_COSF MyCosF - #define HMM_TANF MyTanF - #define HMM_EXPF MyExpF - #define HMM_LOGF MyLogF - #define HMM_ACOSF MyACosF - #define HMM_ATANF MyATanF - #define HMM_ATAN2F MYATan2F - - Provide your own implementations of SinF, CosF, TanF, ACosF, ATanF, ATan2F, ExpF and LogF - in EXACTLY one C or C++ file that includes this header, BEFORE the - include, like this: - - #define HMM_SINF MySinF - #define HMM_COSF MyCosF - #define HMM_TANF MyTanF - #define HMM_EXPF MyExpF - #define HMM_LOGF MyLogF - #define HMM_ACOSF MyACosF - #define HMM_ATANF MyATanF - #define HMM_ATAN2F MyATan2F - #define HANDMADE_MATH_IMPLEMENTATION - #define HANDMADE_MATH_CPP_MODE - #include "HandmadeMath.h" - - If you do not define all five of these, HandmadeMath.h will use the - versions of these functions that are provided by the CRT. - - ========================================================================== - - Version History: - 0.2 (*) Updated documentation - (*) Better C compliance - (*) Prefix all handmade math functions - (*) Better operator overloading - 0.2a - (*) Prefixed Macros - 0.2b - (*) Disabled warning 4201 on MSVC as it is legal is C11 - (*) Removed the f at the end of HMM_PI to get 64bit precision - 0.3 - (*) Added +=, -=, *=, /= for hmm_vec2, hmm_vec3, hmm_vec4 - 0.4 - (*) SSE Optimized HMM_SqrtF - (*) SSE Optimized HMM_RSqrtF - (*) Removed CRT - 0.5 - (*) Added scalar multiplication and division for vectors - and matrices - (*) Added matrix subtraction and += for hmm_mat4 - (*) Reconciled all headers and implementations - (*) Tidied up, and filled in a few missing operators - 0.5.1 - (*) Ensured column-major order for matrices throughout - (*) Fixed HMM_Translate producing row-major matrices - 0.5.2 - (*) Fixed SSE code in HMM_SqrtF - (*) Fixed SSE code in HMM_RSqrtF - 0.6 - (*) Added Unit testing - (*) Made HMM_Power faster - (*) Fixed possible efficiency problem with HMM_Normalize - (*) RENAMED HMM_LengthSquareRoot to HMM_LengthSquared - (*) RENAMED HMM_RSqrtF to HMM_RSquareRootF - (*) RENAMED HMM_SqrtF to HMM_SquareRootF - (*) REMOVED Inner function (user should use Dot now) - (*) REMOVED HMM_FastInverseSquareRoot function declaration - 0.7 - (*) REMOVED HMM_LengthSquared in HANDMADE_MATH_IMPLEMENTATION (should use - HMM_LengthSquaredVec3, or HANDMADE_MATH_CPP_MODE for function overloaded version) - (*) REMOVED HMM_Length in HANDMADE_MATH_IMPLEMENTATION (should use HMM_LengthVec3, - HANDMADE_MATH_CPP_MODE for function overloaded version) - (*) REMOVED HMM_Normalize in HANDMADE_MATH_IMPLEMENTATION (should use HMM_NormalizeVec3, - or HANDMADE_MATH_CPP_MODE for function overloaded version) - (*) Added HMM_LengthSquaredVec2 - (*) Added HMM_LengthSquaredVec4 - (*) Addd HMM_LengthVec2 - (*) Added HMM_LengthVec4 - (*) Added HMM_NormalizeVec2 - (*) Added HMM_NormalizeVec4 - 1.0 - (*) Lots of testing! - 1.1 - (*) Quaternion support - (*) Added type hmm_quaternion - (*) Added HMM_Quaternion - (*) Added HMM_QuaternionV4 - (*) Added HMM_AddQuaternion - (*) Added HMM_SubtractQuaternion - (*) Added HMM_MultiplyQuaternion - (*) Added HMM_MultiplyQuaternionF - (*) Added HMM_DivideQuaternionF - (*) Added HMM_InverseQuaternion - (*) Added HMM_DotQuaternion - (*) Added HMM_NormalizeQuaternion - (*) Added HMM_Slerp - (*) Added HMM_QuaternionToMat4 - (*) Added HMM_QuaternionFromAxisAngle - 1.1.1 - (*) Resolved compiler warnings on gcc and g++ - 1.1.2 - (*) Fixed invalid HMMDEF's in the function definitions - 1.1.3 - (*) Fixed compile error in C mode - - LICENSE - - This software is in the public domain. Where that dedication is not - recognized, you are granted a perpetual, irrevocable license to copy, - distribute, and modify this file as you see fit. - - CREDITS - - Written by Zakary Strange (zak@handmade.network && @strangezak) - - Functionality: - Matt Mascarenhas (@miblo_) - Aleph - FieryDrake (@fierydrake) - Gingerbill (@TheGingerBill) - Ben Visness (@bvisness) - Trinton Bullard (@Peliex_Dev) - - Fixes: - Jeroen van Rijn (@J_vanRijn) - Kiljacken (@Kiljacken) - Insofaras (@insofaras) -*/ - -#ifndef HANDMADE_NO_SSE -#include -#endif - -#ifndef HANDMADE_MATH_H -#define HANDMADE_MATH_H - -#ifdef _MSC_VER -#pragma warning(disable:4201) -#endif - -#ifdef __clang__ -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wgnu-anonymous-struct" -#endif - -#ifdef __cplusplus -extern "C" -{ -#endif - -#ifdef HANDMADE_MATH_STATIC -#define HMMDEF static -#else -#define HMMDEF extern -#endif - -#ifdef HANDMADE_MATH_NO_INLINE -#define HINLINE -#elif _MSC_VER && !__INTEL_COMPILER -#define HINLINE __inline -#else -#define HINLINE inline -#endif - -#if !defined(HMM_SINF) || !defined(HMM_COSF) || !defined(HMM_TANF) || \ - !defined(HMM_EXPF) || !defined(HMM_LOGF) || !defined(HMM_ACOSF) || \ - !defined(HMM_ATANF)|| !defined(HMM_ATAN2F) -#include -#endif - -#ifndef HMM_SINF -#define HMM_SINF sinf -#endif - -#ifndef HMM_COSF -#define HMM_COSF cosf -#endif - -#ifndef HMM_TANF -#define HMM_TANF tanf -#endif - -#ifndef HMM_EXPF -#define HMM_EXPF expf -#endif - -#ifndef HMM_LOGF -#define HMM_LOGF logf -#endif - -#ifndef HMM_ACOSF -#define HMM_ACOSF acosf -#endif - -#ifndef HMM_ATANF -#define HMM_ATANF atanf -#endif - -#ifndef HMM_ATAN2F -#define HMM_ATAN2F atan2f -#endif - -#define HMM_PI32 3.14159265359f -#define HMM_PI 3.14159265358979323846 - -#define HMM_MIN(a, b) (a) > (b) ? (b) : (a) -#define HMM_MAX(a, b) (a) < (b) ? (b) : (a) -#define HMM_ABS(a) ((a) > 0 ? (a) : -(a)) -#define HMM_MOD(a, m) ((a) % (m)) >= 0 ? ((a) % (m)) : (((a) % (m)) + (m)) -#define HMM_SQUARE(x) ((x) * (x)) - -typedef union hmm_vec2 -{ - struct - { - float X, Y; - }; - - struct - { - float U, V; - }; - - struct - { - float Left, Right; - }; - - float Elements[2]; -} hmm_vec2; - -typedef union hmm_vec3 -{ - struct - { - float X, Y, Z; - }; - - struct - { - float U, V, W; - }; - - struct - { - float R, G, B; - }; - - struct - { - hmm_vec2 XY; - float Ignored0_; - }; - - struct - { - float Ignored1_; - hmm_vec2 YZ; - }; - - struct - { - hmm_vec2 UV; - float Ignored2_; - }; - - struct - { - float Ignored3_; - hmm_vec2 VW; - }; - - float Elements[3]; -} hmm_vec3; - -typedef union hmm_vec4 -{ - struct - { - union - { - hmm_vec3 XYZ; - struct - { - float X, Y, Z; - }; - }; - - float W; - }; - struct - { - union - { - hmm_vec3 RGB; - struct - { - float R, G, B; - }; - }; - - float A; - }; - - struct - { - hmm_vec2 XY; - float Ignored0_; - float Ignored1_; - }; - - struct - { - float Ignored2_; - hmm_vec2 YZ; - float Ignored3_; - }; - - struct - { - float Ignored4_; - float Ignored5_; - hmm_vec2 ZW; - }; - - float Elements[4]; -} hmm_vec4; - -typedef union hmm_mat4 -{ - float Elements[4][4]; -} hmm_mat4; - -typedef union hmm_quaternion -{ - struct - { - union - { - hmm_vec3 XYZ; - struct - { - float X, Y, Z; - }; - }; - - float W; - }; - - float Elements[4]; -} hmm_quaternion; - -typedef hmm_vec2 hmm_v2; -typedef hmm_vec3 hmm_v3; -typedef hmm_vec4 hmm_v4; -typedef hmm_mat4 hmm_m4; - -HMMDEF float HMM_SinF(float Angle); -HMMDEF float HMM_TanF(float Angle); -HMMDEF float HMM_ATanF(float Theta); -HMMDEF float HMM_ATan2F(float Theta, float Theta2); -HMMDEF float HMM_CosF(float Angle); -HMMDEF float HMM_ACosF(float Theta); -HMMDEF float HMM_ExpF(float Float); -HMMDEF float HMM_LogF(float Float); - -HMMDEF float HMM_ToRadians(float Degrees); -HMMDEF float HMM_SquareRootF(float Float); -HMMDEF float HMM_RSquareRootF(float Float); - -HMMDEF float HMM_LengthSquaredVec2(hmm_vec2 A); -HMMDEF float HMM_LengthSquaredVec3(hmm_vec3 A); -HMMDEF float HMM_LengthSquaredVec4(hmm_vec4 A); - -HMMDEF float HMM_LengthVec2(hmm_vec2 A); -HMMDEF float HMM_LengthVec3(hmm_vec3 A); -HMMDEF float HMM_LengthVec4(hmm_vec4 A); - -HMMDEF float HMM_Power(float Base, int Exponent); -HMMDEF float HMM_PowerF(float Base, float Exponent); -HMMDEF float HMM_Lerp(float A, float Time, float B); -HMMDEF float HMM_Clamp(float Min, float Value, float Max); - -HMMDEF hmm_vec2 HMM_NormalizeVec2(hmm_vec2 A); -HMMDEF hmm_vec3 HMM_NormalizeVec3(hmm_vec3 A); -HMMDEF hmm_vec4 HMM_NormalizeVec4(hmm_vec4 A); - -HMMDEF float HMM_DotVec2(hmm_vec2 VecOne, hmm_vec2 VecTwo); -HMMDEF float HMM_DotVec3(hmm_vec3 VecOne, hmm_vec3 VecTwo); -HMMDEF float HMM_DotVec4(hmm_vec4 VecOne, hmm_vec4 VecTwo); - -HMMDEF hmm_vec3 HMM_Cross(hmm_vec3 VecOne, hmm_vec3 VecTwo); - -HMMDEF hmm_vec2 HMM_Vec2(float X, float Y); -HMMDEF hmm_vec2 HMM_Vec2i(int X, int Y); -HMMDEF hmm_vec3 HMM_Vec3(float X, float Y, float Z); -HMMDEF hmm_vec3 HMM_Vec3i(int X, int Y, int Z); -HMMDEF hmm_vec4 HMM_Vec4(float X, float Y, float Z, float W); -HMMDEF hmm_vec4 HMM_Vec4i(int X, int Y, int Z, int W); -HMMDEF hmm_vec4 HMM_Vec4v(hmm_vec3 Vector, float W); - -HMMDEF hmm_vec2 HMM_AddVec2(hmm_vec2 Left, hmm_vec2 Right); -HMMDEF hmm_vec3 HMM_AddVec3(hmm_vec3 Left, hmm_vec3 Right); -HMMDEF hmm_vec4 HMM_AddVec4(hmm_vec4 Left, hmm_vec4 Right); - -HMMDEF hmm_vec2 HMM_SubtractVec2(hmm_vec2 Left, hmm_vec2 Right); -HMMDEF hmm_vec3 HMM_SubtractVec3(hmm_vec3 Left, hmm_vec3 Right); -HMMDEF hmm_vec4 HMM_SubtractVec4(hmm_vec4 Left, hmm_vec4 Right); - -HMMDEF hmm_vec2 HMM_MultiplyVec2(hmm_vec2 Left, hmm_vec2 Right); -HMMDEF hmm_vec2 HMM_MultiplyVec2f(hmm_vec2 Left, float Right); -HMMDEF hmm_vec3 HMM_MultiplyVec3(hmm_vec3 Left, hmm_vec3 Right); -HMMDEF hmm_vec3 HMM_MultiplyVec3f(hmm_vec3 Left, float Right); -HMMDEF hmm_vec4 HMM_MultiplyVec4(hmm_vec4 Left, hmm_vec4 Right); -HMMDEF hmm_vec4 HMM_MultiplyVec4f(hmm_vec4 Left, float Right); - -HMMDEF hmm_vec2 HMM_DivideVec2(hmm_vec2 Left, hmm_vec2 Right); -HMMDEF hmm_vec2 HMM_DivideVec2f(hmm_vec2 Left, float Right); -HMMDEF hmm_vec3 HMM_DivideVec3(hmm_vec3 Left, hmm_vec3 Right); -HMMDEF hmm_vec3 HMM_DivideVec3f(hmm_vec3 Left, float Right); -HMMDEF hmm_vec4 HMM_DivideVec4(hmm_vec4 Left, hmm_vec4 Right); -HMMDEF hmm_vec4 HMM_DivideVec4f(hmm_vec4 Left, float Right); - -HMMDEF hmm_mat4 HMM_Mat4(void); -HMMDEF hmm_mat4 HMM_Mat4d(float Diagonal); -HMMDEF hmm_mat4 HMM_AddMat4(hmm_mat4 Left, hmm_mat4 Right); -HMMDEF hmm_mat4 HMM_SubtractMat4(hmm_mat4 Left, hmm_mat4 Right); -HMMDEF hmm_mat4 HMM_MultiplyMat4(hmm_mat4 Left, hmm_mat4 Right); -HMMDEF hmm_mat4 HMM_MultiplyMat4f(hmm_mat4 Matrix, float Scalar); -HMMDEF hmm_vec4 HMM_MultiplyMat4ByVec4(hmm_mat4 Matrix, hmm_vec4 Vector); -HMMDEF hmm_mat4 HMM_DivideMat4f(hmm_mat4 Matrix, float Scalar); - -HMMDEF hmm_mat4 HMM_Transpose(hmm_mat4 Matrix); - -HMMDEF hmm_mat4 HMM_Orthographic(float Left, float Right, float Bottom, float Top, float Near, float Far); -HMMDEF hmm_mat4 HMM_Perspective(float FOV, float AspectRatio, float Near, float Far); - -HMMDEF hmm_mat4 HMM_Translate(hmm_vec3 Translation); -HMMDEF hmm_mat4 HMM_Rotate(float Angle, hmm_vec3 Axis); -HMMDEF hmm_mat4 HMM_Scale(hmm_vec3 Scale); - -HMMDEF hmm_mat4 HMM_LookAt(hmm_vec3 Eye, hmm_vec3 Center, hmm_vec3 Up); - -HMMDEF hmm_quaternion HMM_Quaternion(float X, float Y, float Z, float W); -HMMDEF hmm_quaternion HMM_QuaternionV4(hmm_vec4 Vector); -HMMDEF hmm_quaternion HMM_AddQuaternion(hmm_quaternion Left, hmm_quaternion Right); -HMMDEF hmm_quaternion HMM_SubtractQuaternion(hmm_quaternion Left, hmm_quaternion Right); -HMMDEF hmm_quaternion HMM_MultiplyQuaternion(hmm_quaternion Left, hmm_quaternion Right); -HMMDEF hmm_quaternion HMM_MultiplyQuaternionF(hmm_quaternion Left, float Multiplicative); -HMMDEF hmm_quaternion HMM_DivideQuaternionF(hmm_quaternion Left, float Dividend); -HMMDEF hmm_quaternion HMM_InverseQuaternion(hmm_quaternion Left); -HMMDEF float HMM_DotQuaternion(hmm_quaternion Left, hmm_quaternion Right); -HMMDEF hmm_quaternion HMM_NormalizeQuaternion(hmm_quaternion Left); -HMMDEF hmm_quaternion HMM_NLerp(hmm_quaternion Left, float Time, hmm_quaternion Right); -HMMDEF hmm_quaternion HMM_Slerp(hmm_quaternion Left, float Time, hmm_quaternion Right); -HMMDEF hmm_mat4 HMM_QuaternionToMat4(hmm_quaternion Left); -HMMDEF hmm_quaternion HMM_QuaternionFromAxisAngle(hmm_vec3 Axis, float AngleOfRotation); - -#ifdef __cplusplus -} -#endif - -#ifdef HANDMADE_MATH_CPP_MODE - -HMMDEF float HMM_Length(hmm_vec2 A); -HMMDEF float HMM_Length(hmm_vec3 A); -HMMDEF float HMM_Length(hmm_vec4 A); - -HMMDEF float HMM_LengthSquared(hmm_vec2 A); -HMMDEF float HMM_LengthSquared(hmm_vec3 A); -HMMDEF float HMM_LengthSquared(hmm_vec4 A); - -HMMDEF hmm_vec2 HMM_Normalize(hmm_vec2 A); -HMMDEF hmm_vec3 HMM_Normalize(hmm_vec3 A); -HMMDEF hmm_vec4 HMM_Normalize(hmm_vec4 A); -HMMDEF hmm_quaternion HMM_Normalize(hmm_quaternion A); - -HMMDEF float HMM_Dot(hmm_vec2 VecOne, hmm_vec2 VecTwo); -HMMDEF float HMM_Dot(hmm_vec3 VecOne, hmm_vec3 VecTwo); -HMMDEF float HMM_Dot(hmm_vec4 VecOne, hmm_vec4 VecTwo); -HMMDEF float HMM_Dot(hmm_quaternion QuatOne, hmm_quaternion QuatTwo); - -HMMDEF hmm_vec2 HMM_Add(hmm_vec2 Left, hmm_vec2 Right); -HMMDEF hmm_vec3 HMM_Add(hmm_vec3 Left, hmm_vec3 Right); -HMMDEF hmm_vec4 HMM_Add(hmm_vec4 Left, hmm_vec4 Right); -HMMDEF hmm_mat4 HMM_Add(hmm_mat4 Left, hmm_mat4 Right); -HMMDEF hmm_quaternion HMM_Add(hmm_quaternion Left, hmm_quaternion Right); - -HMMDEF hmm_vec2 HMM_Subtract(hmm_vec2 Left, hmm_vec2 Right); -HMMDEF hmm_vec3 HMM_Subtract(hmm_vec3 Left, hmm_vec3 Right); -HMMDEF hmm_vec4 HMM_Subtract(hmm_vec4 Left, hmm_vec4 Right); -HMMDEF hmm_mat4 HMM_Subtract(hmm_mat4 Left, hmm_mat4 Right); -HMMDEF hmm_quaternion HMM_Subtract(hmm_quaternion Left, hmm_quaternion Right); - -HMMDEF hmm_vec2 HMM_Multiply(hmm_vec2 Left, hmm_vec2 Right); -HMMDEF hmm_vec2 HMM_Multiply(hmm_vec2 Left, float Right); -HMMDEF hmm_vec3 HMM_Multiply(hmm_vec3 Left, hmm_vec3 Right); -HMMDEF hmm_vec3 HMM_Multiply(hmm_vec3 Left, float Right); -HMMDEF hmm_vec4 HMM_Multiply(hmm_vec4 Left, hmm_vec4 Right); -HMMDEF hmm_vec4 HMM_Multiply(hmm_vec4 Left, float Right); -HMMDEF hmm_mat4 HMM_Multiply(hmm_mat4 Left, hmm_mat4 Right); -HMMDEF hmm_mat4 HMM_Multiply(hmm_mat4 Left, float Right); -HMMDEF hmm_vec4 HMM_Multiply(hmm_mat4 Matrix, hmm_vec4 Vector); -HMMDEF hmm_quaternion HMM_Multiply(hmm_quaternion Left, hmm_quaternion Right); -HMMDEF hmm_quaternion HMM_Multiply(hmm_quaternion Left, float Right); - -HMMDEF hmm_vec2 HMM_Divide(hmm_vec2 Left, hmm_vec2 Right); -HMMDEF hmm_vec2 HMM_Divide(hmm_vec2 Left, float Right); -HMMDEF hmm_vec3 HMM_Divide(hmm_vec3 Left, hmm_vec3 Right); -HMMDEF hmm_vec3 HMM_Divide(hmm_vec3 Left, float Right); -HMMDEF hmm_vec4 HMM_Divide(hmm_vec4 Left, hmm_vec4 Right); -HMMDEF hmm_vec4 HMM_Divide(hmm_vec4 Left, float Right); -HMMDEF hmm_mat4 HMM_Divide(hmm_mat4 Left, float Right); -HMMDEF hmm_quaternion HMM_Divide(hmm_quaternion Left, hmm_quaternion Right); -HMMDEF hmm_quaternion HMM_Divide(hmm_quaternion Left, float Right); - -HMMDEF hmm_vec2 operator+(hmm_vec2 Left, hmm_vec2 Right); -HMMDEF hmm_vec3 operator+(hmm_vec3 Left, hmm_vec3 Right); -HMMDEF hmm_vec4 operator+(hmm_vec4 Left, hmm_vec4 Right); -HMMDEF hmm_mat4 operator+(hmm_mat4 Left, hmm_mat4 Right); -HMMDEF hmm_quaternion operator+(hmm_quaternion Left, hmm_quaternion Right); - -HMMDEF hmm_vec2 operator-(hmm_vec2 Left, hmm_vec2 Right); -HMMDEF hmm_vec3 operator-(hmm_vec3 Left, hmm_vec3 Right); -HMMDEF hmm_vec4 operator-(hmm_vec4 Left, hmm_vec4 Right); -HMMDEF hmm_mat4 operator-(hmm_mat4 Left, hmm_mat4 Right); -HMMDEF hmm_quaternion operator-(hmm_quaternion Left, hmm_quaternion Right); - -HMMDEF hmm_vec2 operator*(hmm_vec2 Left, hmm_vec2 Right); -HMMDEF hmm_vec3 operator*(hmm_vec3 Left, hmm_vec3 Right); -HMMDEF hmm_vec4 operator*(hmm_vec4 Left, hmm_vec4 Right); -HMMDEF hmm_mat4 operator*(hmm_mat4 Left, hmm_mat4 Right); -HMMDEF hmm_quaternion operator*(hmm_quaternion Left, hmm_quaternion Right); - -HMMDEF hmm_vec2 operator*(hmm_vec2 Left, float Right); -HMMDEF hmm_vec3 operator*(hmm_vec3 Left, float Right); -HMMDEF hmm_vec4 operator*(hmm_vec4 Left, float Right); -HMMDEF hmm_mat4 operator*(hmm_mat4 Left, float Right); -HMMDEF hmm_quaternion operator*(hmm_quaternion Left, float Right); - -HMMDEF hmm_vec2 operator*(float Left, hmm_vec2 Right); -HMMDEF hmm_vec3 operator*(float Left, hmm_vec3 Right); -HMMDEF hmm_vec4 operator*(float Left, hmm_vec4 Right); -HMMDEF hmm_mat4 operator*(float Left, hmm_mat4 Right); -HMMDEF hmm_quaternion operator*(float Left, hmm_quaternion Right); - -HMMDEF hmm_vec4 operator*(hmm_mat4 Matrix, hmm_vec4 Vector); - -HMMDEF hmm_vec2 operator/(hmm_vec2 Left, hmm_vec2 Right); -HMMDEF hmm_vec3 operator/(hmm_vec3 Left, hmm_vec3 Right); -HMMDEF hmm_vec4 operator/(hmm_vec4 Left, hmm_vec4 Right); - -HMMDEF hmm_vec2 operator/(hmm_vec2 Left, float Right); -HMMDEF hmm_vec3 operator/(hmm_vec3 Left, float Right); -HMMDEF hmm_vec4 operator/(hmm_vec4 Left, float Right); -HMMDEF hmm_mat4 operator/(hmm_mat4 Left, float Right); -HMMDEF hmm_quaternion operator/(hmm_quaternion Left, float Right); - -HMMDEF hmm_vec2 &operator+=(hmm_vec2 &Left, hmm_vec2 Right); -HMMDEF hmm_vec3 &operator+=(hmm_vec3 &Left, hmm_vec3 Right); -HMMDEF hmm_vec4 &operator+=(hmm_vec4 &Left, hmm_vec4 Right); -HMMDEF hmm_mat4 &operator+=(hmm_mat4 &Left, hmm_mat4 Right); -HMMDEF hmm_quaternion &operator+=(hmm_quaternion &Left, hmm_quaternion Right); - -HMMDEF hmm_vec2 &operator-=(hmm_vec2 &Left, hmm_vec2 Right); -HMMDEF hmm_vec3 &operator-=(hmm_vec3 &Left, hmm_vec3 Right); -HMMDEF hmm_vec4 &operator-=(hmm_vec4 &Left, hmm_vec4 Right); -HMMDEF hmm_mat4 &operator-=(hmm_mat4 &Left, hmm_mat4 Right); -HMMDEF hmm_quaternion &operator-=(hmm_quaternion &Left, hmm_quaternion Right); - -HMMDEF hmm_vec2 &operator*=(hmm_vec2 &Left, hmm_vec2 Right); -HMMDEF hmm_vec3 &operator*=(hmm_vec3 &Left, hmm_vec3 Right); -HMMDEF hmm_vec4 &operator*=(hmm_vec4 &Left, hmm_vec4 Right); - -HMMDEF hmm_vec2 &operator*=(hmm_vec2 &Left, float Right); -HMMDEF hmm_vec3 &operator*=(hmm_vec3 &Left, float Right); -HMMDEF hmm_vec4 &operator*=(hmm_vec4 &Left, float Right); -HMMDEF hmm_mat4 &operator*=(hmm_mat4 &Left, float Right); -HMMDEF hmm_quaternion &operator*=(hmm_quaternion &Left, float Right); - -HMMDEF hmm_vec2 &operator/=(hmm_vec2 &Left, hmm_vec2 Right); -HMMDEF hmm_vec3 &operator/=(hmm_vec3 &Left, hmm_vec3 Right); -HMMDEF hmm_vec4 &operator/=(hmm_vec4 &Left, hmm_vec4 Right); - -HMMDEF hmm_vec2 &operator/=(hmm_vec2 &Left, float Right); -HMMDEF hmm_vec3 &operator/=(hmm_vec3 &Left, float Right); -HMMDEF hmm_vec4 &operator/=(hmm_vec4 &Left, float Right); -HMMDEF hmm_mat4 &operator/=(hmm_mat4 &Left, float Right); -HMMDEF hmm_quaternion &operator/=(hmm_quaternion &Left, float Right); - -#endif /* HANDMADE_MATH_CPP */ - -#ifdef __clang__ -#pragma GCC diagnostic pop -#endif - -#endif /* HANDMADE_MATH_H */ - -#ifdef HANDMADE_MATH_IMPLEMENTATION - -HINLINE float -HMM_SinF(float Angle) -{ - float Result = 0.0f; - - Result = HMM_SINF(Angle); - return (Result); -} - -HINLINE float -HMM_CosF(float Angle) -{ - float Result = 0.0f; - - Result = HMM_COSF(Angle); - return (Result); -} - -HINLINE float -HMM_TanF(float Radians) -{ - float Result = 0.0f; - - Result = HMM_TANF(Radians); - return (Result); -} - -HINLINE float -HMM_ACosF(float Radians) -{ - float Result = 0.0f; - - Result = HMM_ACOSF(Radians); - return (Result); -} - -HINLINE float -HMM_ATanF(float Radians) -{ - float Result = 0.0f; - - Result = HMM_ATANF(Radians); - return (Result); -} - -HINLINE float -HMM_Atan2F(float Left, float Right) -{ - float Result = 0.0f; - - Result = HMM_ATAN2F(Left, Right); - return (Result); -} - -HINLINE float -HMM_ExpF(float Float) -{ - float Result = 0.0f; - - Result = HMM_EXPF(Float); - return (Result); -} - -HINLINE float -HMM_LogF(float Float) -{ - float Result = 0.0f; - - Result = HMM_LOGF(Float); - return (Result); -} - -HINLINE float -HMM_ToRadians(float Degrees) -{ - float Result = 0.0f; - - Result = Degrees * (HMM_PI32 / 180.0f); - return (Result); -} - -HINLINE float -HMM_SquareRootF(float Value) -{ - float Result = 0.0f; - -#ifdef HANDMADE_MATH_NO_SSE - Result = sqrtf(Value); -#else - __m128 In = _mm_set_ss(Value); - __m128 Out = _mm_sqrt_ss(In); - Result = _mm_cvtss_f32(Out); -#endif - - return(Result); -} - -HINLINE float -HMM_RSquareRootF(float Value) -{ - float Result = 0.0f; - -#ifdef HANDMADE_MATH_NO_SSE - Result = 1.0f/HMM_SquareRootF(Value); -#else - __m128 In = _mm_set_ss(Value); - __m128 Out = _mm_rsqrt_ss(In); - Result = _mm_cvtss_f32(Out); -#endif - - return(Result); -} - -HINLINE float -HMM_LengthSquaredVec2(hmm_vec2 A) -{ - float Result = 0.0f; - - Result = HMM_DotVec2(A, A); - - return(Result); -} - -HINLINE float -HMM_LengthSquaredVec3(hmm_vec3 A) -{ - float Result = 0.0f; - - Result = HMM_DotVec3(A, A); - - return (Result); -} - -HINLINE float -HMM_LengthSquaredVec4(hmm_vec4 A) -{ - float Result = 0.0f; - - Result = HMM_DotVec4(A, A); - - return(Result); -} - -HINLINE float -HMM_LengthVec2(hmm_vec2 A) -{ - float Result = 0.0f; - - Result = HMM_SquareRootF(HMM_LengthSquaredVec2(A)); - - return(Result); -} - -HINLINE float -HMM_LengthVec3(hmm_vec3 A) -{ - float Result = 0.0f; - - Result = HMM_SquareRootF(HMM_LengthSquaredVec3(A)); - - return (Result); -} - -HINLINE float -HMM_LengthVec4(hmm_vec4 A) -{ - float Result = 0.0f; - - Result = HMM_SquareRootF(HMM_LengthSquaredVec4(A)); - - return(Result); -} - -HINLINE float -HMM_Power(float Base, int Exponent) -{ - float Result = 1.0f; - float Mul = Exponent < 0 ? 1.f / Base : Base; - unsigned int X = Exponent < 0 ? -Exponent : Exponent; - while (X) - { - if (X & 1) - { - Result *= Mul; - } - - Mul *= Mul; - X >>= 1; - } - - return (Result); -} - -HINLINE float -HMM_PowerF(float Base, float Exponent) -{ - return HMM_EXPF(Exponent * HMM_LOGF(Base)); -} - -HINLINE float -HMM_Lerp(float A, float Time, float B) -{ - float Result = 0; - - Result = (1.0f - Time) * A + Time * B; - return (Result); -} - -HINLINE float -HMM_Clamp(float Min, float Value, float Max) -{ - float Result = Value; - - if(Result < Min) - { - Result = Min; - } - else if(Result > Max) - { - Result = Max; - } - - return (Result); -} - -HINLINE hmm_vec2 -HMM_NormalizeVec2(hmm_vec2 A) -{ - hmm_vec2 Result = {0}; - - float VectorLength = HMM_LengthVec2(A); - - Result.X = A.X * (1.0f / VectorLength); - Result.Y = A.Y * (1.0f / VectorLength); - - return (Result); -} - -HINLINE hmm_vec3 -HMM_NormalizeVec3(hmm_vec3 A) -{ - hmm_vec3 Result = {0}; - - float VectorLength = HMM_LengthVec3(A); - - Result.X = A.X * (1.0f / VectorLength); - Result.Y = A.Y * (1.0f / VectorLength); - Result.Z = A.Z * (1.0f / VectorLength); - - return (Result); -} - -HINLINE hmm_vec4 -HMM_NormalizeVec4(hmm_vec4 A) -{ - hmm_vec4 Result = {0}; - - float VectorLength = HMM_LengthVec4(A); - - Result.X = A.X * (1.0f / VectorLength); - Result.Y = A.Y * (1.0f / VectorLength); - Result.Z = A.Z * (1.0f / VectorLength); - Result.W = A.W * (1.0f / VectorLength); - - return (Result); -} - -HINLINE float -HMM_DotVec2(hmm_vec2 VecOne, hmm_vec2 VecTwo) -{ - float Result = 0.0f; - - Result = (VecOne.X * VecTwo.X) + (VecOne.Y * VecTwo.Y); - - return (Result); -} - -HINLINE float -HMM_DotVec3(hmm_vec3 VecOne, hmm_vec3 VecTwo) -{ - float Result = 0.0f; - - Result = (VecOne.X * VecTwo.X) + (VecOne.Y * VecTwo.Y) + (VecOne.Z * VecTwo.Z); - - return (Result); -} - -HINLINE float -HMM_DotVec4(hmm_vec4 VecOne, hmm_vec4 VecTwo) -{ - float Result = 0.0f; - - Result = (VecOne.X * VecTwo.X) + (VecOne.Y * VecTwo.Y) + (VecOne.Z * VecTwo.Z) + (VecOne.W * VecTwo.W); - - return (Result); -} - -HINLINE hmm_vec3 -HMM_Cross(hmm_vec3 VecOne, hmm_vec3 VecTwo) -{ - hmm_vec3 Result = {0}; - - Result.X = (VecOne.Y * VecTwo.Z) - (VecOne.Z * VecTwo.Y); - Result.Y = (VecOne.Z * VecTwo.X) - (VecOne.X * VecTwo.Z); - Result.Z = (VecOne.X * VecTwo.Y) - (VecOne.Y * VecTwo.X); - - return (Result); -} - -HINLINE hmm_vec2 -HMM_Vec2(float X, float Y) -{ - hmm_vec2 Result = {0}; - - Result.X = X; - Result.Y = Y; - - return (Result); -} - -HINLINE hmm_vec2 -HMM_Vec2i(int X, int Y) -{ - hmm_vec2 Result = {0}; - - Result.X = (float)X; - Result.Y = (float)Y; - - return (Result); -} - -HINLINE hmm_vec3 -HMM_Vec3(float X, float Y, float Z) -{ - hmm_vec3 Result = {0}; - - Result.X = X; - Result.Y = Y; - Result.Z = Z; - - return (Result); -} - -HINLINE hmm_vec3 -HMM_Vec3i(int X, int Y, int Z) -{ - hmm_vec3 Result = {0}; - - Result.X = (float)X; - Result.Y = (float)Y; - Result.Z = (float)Z; - - return (Result); -} - -HINLINE hmm_vec4 -HMM_Vec4(float X, float Y, float Z, float W) -{ - hmm_vec4 Result = {0}; - - Result.X = X; - Result.Y = Y; - Result.Z = Z; - Result.W = W; - - return (Result); -} - -HINLINE hmm_vec4 -HMM_Vec4i(int X, int Y, int Z, int W) -{ - hmm_vec4 Result = {0}; - - Result.X = (float)X; - Result.Y = (float)Y; - Result.Z = (float)Z; - Result.W = (float)W; - - return (Result); -} - -HINLINE hmm_vec4 -HMM_Vec4v(hmm_vec3 Vector, float W) -{ - hmm_vec4 Result = {0}; - - Result.XYZ = Vector; - Result.W = W; - - return (Result); -} - -HINLINE hmm_vec2 -HMM_AddVec2(hmm_vec2 Left, hmm_vec2 Right) -{ - hmm_vec2 Result = {0}; - - Result.X = Left.X + Right.X; - Result.Y = Left.Y + Right.Y; - - return (Result); -} - -HINLINE hmm_vec3 -HMM_AddVec3(hmm_vec3 Left, hmm_vec3 Right) -{ - hmm_vec3 Result = {0}; - - Result.X = Left.X + Right.X; - Result.Y = Left.Y + Right.Y; - Result.Z = Left.Z + Right.Z; - - return (Result); -} - -HINLINE hmm_vec4 -HMM_AddVec4(hmm_vec4 Left, hmm_vec4 Right) -{ - hmm_vec4 Result = {0}; - - Result.X = Left.X + Right.X; - Result.Y = Left.Y + Right.Y; - Result.Z = Left.Z + Right.Z; - Result.W = Left.W + Right.W; - - return (Result); -} - -HINLINE hmm_vec2 -HMM_SubtractVec2(hmm_vec2 Left, hmm_vec2 Right) -{ - hmm_vec2 Result = {0}; - - Result.X = Left.X - Right.X; - Result.Y = Left.Y - Right.Y; - - return (Result); -} - -HINLINE hmm_vec3 -HMM_SubtractVec3(hmm_vec3 Left, hmm_vec3 Right) -{ - hmm_vec3 Result = {0}; - - Result.X = Left.X - Right.X; - Result.Y = Left.Y - Right.Y; - Result.Z = Left.Z - Right.Z; - - return (Result); -} - -HINLINE hmm_vec4 -HMM_SubtractVec4(hmm_vec4 Left, hmm_vec4 Right) -{ - hmm_vec4 Result = {0}; - - Result.X = Left.X - Right.X; - Result.Y = Left.Y - Right.Y; - Result.Z = Left.Z - Right.Z; - Result.W = Left.W - Right.W; - - return (Result); -} - -HINLINE hmm_vec2 -HMM_MultiplyVec2(hmm_vec2 Left, hmm_vec2 Right) -{ - hmm_vec2 Result = {0}; - - Result.X = Left.X * Right.X; - Result.Y = Left.Y * Right.Y; - - return (Result); -} - -HINLINE hmm_vec2 -HMM_MultiplyVec2f(hmm_vec2 Left, float Right) -{ - hmm_vec2 Result = {0}; - - Result.X = Left.X * Right; - Result.Y = Left.Y * Right; - - return (Result); -} - -HINLINE hmm_vec3 -HMM_MultiplyVec3(hmm_vec3 Left, hmm_vec3 Right) -{ - hmm_vec3 Result = {0}; - - Result.X = Left.X * Right.X; - Result.Y = Left.Y * Right.Y; - Result.Z = Left.Z * Right.Z; - - return (Result); -} - -HINLINE hmm_vec3 -HMM_MultiplyVec3f(hmm_vec3 Left, float Right) -{ - hmm_vec3 Result = {0}; - - Result.X = Left.X * Right; - Result.Y = Left.Y * Right; - Result.Z = Left.Z * Right; - - return (Result); -} - -HINLINE hmm_vec4 -HMM_MultiplyVec4(hmm_vec4 Left, hmm_vec4 Right) -{ - hmm_vec4 Result = {0}; - - Result.X = Left.X * Right.X; - Result.Y = Left.Y * Right.Y; - Result.Z = Left.Z * Right.Z; - Result.W = Left.W * Right.W; - - return (Result); -} - -HINLINE hmm_vec4 -HMM_MultiplyVec4f(hmm_vec4 Left, float Right) -{ - hmm_vec4 Result = {0}; - - Result.X = Left.X * Right; - Result.Y = Left.Y * Right; - Result.Z = Left.Z * Right; - Result.W = Left.W * Right; - - return (Result); -} - -HINLINE hmm_vec2 -HMM_DivideVec2(hmm_vec2 Left, hmm_vec2 Right) -{ - hmm_vec2 Result = {0}; - - Result.X = Left.X / Right.X; - Result.Y = Left.Y / Right.Y; - - return (Result); -} - -HINLINE hmm_vec2 -HMM_DivideVec2f(hmm_vec2 Left, float Right) -{ - hmm_vec2 Result = {0}; - - Result.X = Left.X / Right; - Result.Y = Left.Y / Right; - - return (Result); -} - -HINLINE hmm_vec3 -HMM_DivideVec3(hmm_vec3 Left, hmm_vec3 Right) -{ - hmm_vec3 Result = {0}; - - Result.X = Left.X / Right.X; - Result.Y = Left.Y / Right.Y; - Result.Z = Left.Z / Right.Z; - - return (Result); -} - -HINLINE hmm_vec3 -HMM_DivideVec3f(hmm_vec3 Left, float Right) -{ - hmm_vec3 Result = {0}; - - Result.X = Left.X / Right; - Result.Y = Left.Y / Right; - Result.Z = Left.Z / Right; - - return (Result); -} - -HINLINE hmm_vec4 -HMM_DivideVec4(hmm_vec4 Left, hmm_vec4 Right) -{ - hmm_vec4 Result = {0}; - - Result.X = Left.X / Right.X; - Result.Y = Left.Y / Right.Y; - Result.Z = Left.Z / Right.Z; - Result.W = Left.W / Right.W; - - return (Result); -} - -HINLINE hmm_vec4 -HMM_DivideVec4f(hmm_vec4 Left, float Right) -{ - hmm_vec4 Result = {0}; - - Result.X = Left.X / Right; - Result.Y = Left.Y / Right; - Result.Z = Left.Z / Right; - Result.W = Left.W / Right; - - return (Result); -} - -HINLINE hmm_mat4 -HMM_Mat4(void) -{ - hmm_mat4 Result = {0}; - - return (Result); -} - -HINLINE hmm_mat4 -HMM_Mat4d(float Diagonal) -{ - hmm_mat4 Result = HMM_Mat4(); - - Result.Elements[0][0] = Diagonal; - Result.Elements[1][1] = Diagonal; - Result.Elements[2][2] = Diagonal; - Result.Elements[3][3] = Diagonal; - - return (Result); -} - -HINLINE hmm_mat4 -HMM_AddMat4(hmm_mat4 Left, hmm_mat4 Right) -{ - hmm_mat4 Result = HMM_Mat4(); - - int Columns; - for(Columns = 0; Columns < 4; ++Columns) - { - int Rows; - for(Rows = 0; Rows < 4; ++Rows) - { - Result.Elements[Columns][Rows] = Left.Elements[Columns][Rows] + Right.Elements[Columns][Rows]; - } - } - - return (Result); -} - -HINLINE hmm_mat4 -HMM_SubtractMat4(hmm_mat4 Left, hmm_mat4 Right) -{ - hmm_mat4 Result = HMM_Mat4(); - - int Columns; - for(Columns = 0; Columns < 4; ++Columns) - { - int Rows; - for(Rows = 0; Rows < 4; ++Rows) - { - Result.Elements[Columns][Rows] = Left.Elements[Columns][Rows] - Right.Elements[Columns][Rows]; - } - } - - return (Result); -} - -HINLINE hmm_mat4 -HMM_MultiplyMat4(hmm_mat4 Left, hmm_mat4 Right) -{ - hmm_mat4 Result = HMM_Mat4(); - - int Columns; - for(Columns = 0; Columns < 4; ++Columns) - { - int Rows; - for(Rows = 0; Rows < 4; ++Rows) - { - float Sum = 0; - int CurrentMatrice; - for(CurrentMatrice = 0; CurrentMatrice < 4; ++CurrentMatrice) - { - Sum += Left.Elements[CurrentMatrice][Rows] * Right.Elements[Columns][CurrentMatrice]; - } - - Result.Elements[Columns][Rows] = Sum; - } - } - - return (Result); -} - -HINLINE hmm_mat4 -HMM_MultiplyMat4f(hmm_mat4 Matrix, float Scalar) -{ - hmm_mat4 Result = HMM_Mat4(); - - int Columns; - for(Columns = 0; Columns < 4; ++Columns) - { - int Rows; - for(Rows = 0; Rows < 4; ++Rows) - { - Result.Elements[Columns][Rows] = Matrix.Elements[Columns][Rows] * Scalar; - } - } - - return (Result); -} - -HINLINE hmm_vec4 -HMM_MultiplyMat4ByVec4(hmm_mat4 Matrix, hmm_vec4 Vector) -{ - hmm_vec4 Result = {0}; - - int Columns, Rows; - for(Rows = 0; Rows < 4; ++Rows) - { - float Sum = 0; - for(Columns = 0; Columns < 4; ++Columns) - { - Sum += Matrix.Elements[Columns][Rows] * Vector.Elements[Columns]; - } - - Result.Elements[Rows] = Sum; - } - - return (Result); -} - -HINLINE hmm_mat4 -HMM_DivideMat4f(hmm_mat4 Matrix, float Scalar) -{ - hmm_mat4 Result = HMM_Mat4(); - - int Columns; - for(Columns = 0; Columns < 4; ++Columns) - { - int Rows; - for(Rows = 0; Rows < 4; ++Rows) - { - Result.Elements[Columns][Rows] = Matrix.Elements[Columns][Rows] / Scalar; - } - } - - return (Result); -} - -HINLINE hmm_mat4 -HMM_Transpose(hmm_mat4 Matrix) -{ - hmm_mat4 Result = HMM_Mat4(); - - int Columns; - for(Columns = 0; Columns < 4; ++Columns) - { - int Rows; - for(Rows = 0; Rows < 4; ++Rows) - { - Result.Elements[Rows][Columns] = Matrix.Elements[Columns][Rows]; - } - } - - return (Result); -} - -HINLINE hmm_mat4 -HMM_Orthographic(float Left, float Right, float Bottom, float Top, float Near, float Far) -{ - hmm_mat4 Result = HMM_Mat4d(1.0f); - - Result.Elements[0][0] = 2.0f / (Right - Left); - Result.Elements[1][1] = 2.0f / (Top - Bottom); - Result.Elements[2][2] = 2.0f / (Near - Far); - - Result.Elements[3][0] = (Left + Right) / (Left - Right); - Result.Elements[3][1] = (Bottom + Top) / (Bottom - Top); - Result.Elements[3][2] = (Far + Near) / (Near - Far); - - return (Result); -} - -HINLINE hmm_mat4 -HMM_Perspective(float FOV, float AspectRatio, float Near, float Far) -{ - hmm_mat4 Result = HMM_Mat4d(1.0f); - - float TanThetaOver2 = HMM_TanF(FOV * (HMM_PI32 / 360.0f)); - - Result.Elements[0][0] = 1.0f / TanThetaOver2; - Result.Elements[1][1] = AspectRatio / TanThetaOver2; - Result.Elements[2][3] = -1.0f; - Result.Elements[2][2] = (Near + Far) / (Near - Far); - Result.Elements[3][2] = (2.0f * Near * Far) / (Near - Far); - Result.Elements[3][3] = 0.0f; - - return (Result); -} - -HINLINE hmm_mat4 -HMM_Translate(hmm_vec3 Translation) -{ - hmm_mat4 Result = HMM_Mat4d(1.0f); - - Result.Elements[3][0] = Translation.X; - Result.Elements[3][1] = Translation.Y; - Result.Elements[3][2] = Translation.Z; - - return (Result); -} - -HINLINE hmm_mat4 -HMM_Rotate(float Angle, hmm_vec3 Axis) -{ - hmm_mat4 Result = HMM_Mat4d(1.0f); - - Axis = HMM_NormalizeVec3(Axis); - - float SinTheta = HMM_SinF(HMM_ToRadians(Angle)); - float CosTheta = HMM_CosF(HMM_ToRadians(Angle)); - float CosValue = 1.0f - CosTheta; - - Result.Elements[0][0] = (Axis.X * Axis.X * CosValue) + CosTheta; - Result.Elements[0][1] = (Axis.X * Axis.Y * CosValue) + (Axis.Z * SinTheta); - Result.Elements[0][2] = (Axis.X * Axis.Z * CosValue) - (Axis.Y * SinTheta); - - Result.Elements[1][0] = (Axis.Y * Axis.X * CosValue) - (Axis.Z * SinTheta); - Result.Elements[1][1] = (Axis.Y * Axis.Y * CosValue) + CosTheta; - Result.Elements[1][2] = (Axis.Y * Axis.Z * CosValue) + (Axis.X * SinTheta); - - Result.Elements[2][0] = (Axis.Z * Axis.X * CosValue) + (Axis.Y * SinTheta); - Result.Elements[2][1] = (Axis.Z * Axis.Y * CosValue) - (Axis.X * SinTheta); - Result.Elements[2][2] = (Axis.Z * Axis.Z * CosValue) + CosTheta; - - return (Result); -} - -HINLINE hmm_mat4 -HMM_Scale(hmm_vec3 Scale) -{ - hmm_mat4 Result = HMM_Mat4d(1.0f); - - Result.Elements[0][0] = Scale.X; - Result.Elements[1][1] = Scale.Y; - Result.Elements[2][2] = Scale.Z; - - return (Result); -} - -HINLINE hmm_mat4 -HMM_LookAt(hmm_vec3 Eye, hmm_vec3 Center, hmm_vec3 Up) -{ - hmm_mat4 Result = {0}; - - hmm_vec3 F = HMM_NormalizeVec3(HMM_SubtractVec3(Center, Eye)); - hmm_vec3 S = HMM_NormalizeVec3(HMM_Cross(F, Up)); - hmm_vec3 U = HMM_Cross(S, F); - - Result.Elements[0][0] = S.X; - Result.Elements[0][1] = U.X; - Result.Elements[0][2] = -F.X; - - Result.Elements[1][0] = S.Y; - Result.Elements[1][1] = U.Y; - Result.Elements[1][2] = -F.Y; - - Result.Elements[2][0] = S.Z; - Result.Elements[2][1] = U.Z; - Result.Elements[2][2] = -F.Z; - - Result.Elements[3][0] = -HMM_DotVec3(S, Eye); - Result.Elements[3][1] = -HMM_DotVec3(U, Eye); - Result.Elements[3][2] = HMM_DotVec3(F, Eye); - Result.Elements[3][3] = 1.0f; - - return (Result); -} - - -HINLINE hmm_quaternion -HMM_Quaternion(float X, float Y, float Z, float W) -{ - hmm_quaternion Result = {0}; - - Result.X = X; - Result.Y = Y; - Result.Z = Z; - Result.W = W; - - return(Result); -} - -HINLINE hmm_quaternion -HMM_QuaternionV4(hmm_vec4 Vector) -{ - hmm_quaternion Result = {0}; - - Result.X = Vector.X; - Result.Y = Vector.Y; - Result.Z = Vector.Z; - Result.W = Vector.W; - - return(Result); -} - -HINLINE hmm_quaternion -HMM_AddQuaternion(hmm_quaternion Left, hmm_quaternion Right) -{ - hmm_quaternion Result = {0}; - - Result.X = Left.X + Right.X; - Result.Y = Left.Y + Right.Y; - Result.Z = Left.Z + Right.Z; - Result.W = Left.W + Right.W; - - return(Result); -} - -HINLINE hmm_quaternion -HMM_SubtractQuaternion(hmm_quaternion Left, hmm_quaternion Right) -{ - hmm_quaternion Result = {0}; - - Result.X = Left.X - Right.X; - Result.Y = Left.Y - Right.Y; - Result.Z = Left.Z - Right.Z; - Result.W = Left.W - Right.W; - - return(Result); -} - -HINLINE hmm_quaternion -HMM_MultiplyQuaternion(hmm_quaternion Left, hmm_quaternion Right) -{ - hmm_quaternion Result = {0}; - - Result.X = (Left.X * Right.W) + (Left.Y * Right.Z) - (Left.Z * Right.Y) + (Left.W * Right.X); - Result.Y = (-Left.X * Right.Z) + (Left.Y * Right.W) + (Left.Z * Right.X) + (Left.W * Right.Y); - Result.Z = (Left.X * Right.Y) - (Left.Y * Right.X) + (Left.Z * Right.W) + (Left.W * Right.Z); - Result.W = (-Left.X * Right.X) - (Left.Y * Right.Y) - (Left.Z * Right.Z) + (Left.W * Right.W); - - return(Result); -} - -HINLINE hmm_quaternion -HMM_MultiplyQuaternionF(hmm_quaternion Left, float Multiplicative) -{ - hmm_quaternion Result = {0}; - - Result.X = Left.X * Multiplicative; - Result.Y = Left.Y * Multiplicative; - Result.Z = Left.Z * Multiplicative; - Result.W = Left.W * Multiplicative; - - return(Result); -} - -HINLINE hmm_quaternion -HMM_DivideQuaternionF(hmm_quaternion Left, float Dividend) -{ - hmm_quaternion Result = {0}; - - Result.X = Left.X / Dividend; - Result.Y = Left.Y / Dividend; - Result.Z = Left.Z / Dividend; - Result.W = Left.W / Dividend; - - return(Result); -} - -HINLINE hmm_quaternion -HMM_InverseQuaternion(hmm_quaternion Left) -{ - hmm_quaternion Conjugate = {0}; - hmm_quaternion Result = {0}; - float Norm = 0; - float NormSquared = 0; - - Conjugate.X = -Left.X; - Conjugate.Y = -Left.Y; - Conjugate.Z = -Left.Z; - Conjugate.W = Left.W; - - Norm = HMM_SquareRootF(HMM_DotQuaternion(Left, Left)); - NormSquared = Norm * Norm; - - Result.X = Conjugate.X / NormSquared; - Result.Y = Conjugate.Y / NormSquared; - Result.Z = Conjugate.Z / NormSquared; - Result.W = Conjugate.W / NormSquared; - - return(Result); -} - -HINLINE float -HMM_DotQuaternion(hmm_quaternion Left, hmm_quaternion Right) -{ - float Result = 0.0f; - - Result = (Left.X * Right.X) + (Left.Y * Right.Y) + (Left.Z * Right.Z) + (Left.W * Right.W); - - return(Result); -} - -HINLINE hmm_quaternion -HMM_NormalizeQuaternion(hmm_quaternion Left) -{ - hmm_quaternion Result = {0}; - - float Length = HMM_SquareRootF(HMM_DotQuaternion(Left, Left)); - Result = HMM_DivideQuaternionF(Left, Length); - - return(Result); -} - -HINLINE hmm_quaternion -HMM_NLerp(hmm_quaternion Left, float Time, hmm_quaternion Right) -{ - hmm_quaternion Result = {0}; - - Result.X = HMM_Lerp(Left.X, Time, Right.X); - Result.Y = HMM_Lerp(Left.Y, Time, Right.Y); - Result.Z = HMM_Lerp(Left.Z, Time, Right.Z); - Result.W = HMM_Lerp(Left.W, Time, Right.W); - - Result = HMM_NormalizeQuaternion(Result); - - return(Result); -} - -HINLINE hmm_quaternion -HMM_Slerp(hmm_quaternion Left, float Time, hmm_quaternion Right) -{ - hmm_quaternion Result = {0}; - hmm_quaternion QuaternionLeft = {0}; - hmm_quaternion QuaternionRight = {0}; - - float Cos_Theta = HMM_DotQuaternion(Left, Right); - float Angle = HMM_ACosF(Cos_Theta); - - float S1 = HMM_SinF((1.0f - Time) * Angle); - float S2 = HMM_SinF(Time * Angle); - float Is = 1.0f / HMM_SinF(Angle); - - QuaternionLeft = HMM_MultiplyQuaternionF(Left, S1); - QuaternionRight = HMM_MultiplyQuaternionF(Right, S2); - - Result = HMM_AddQuaternion(QuaternionLeft, QuaternionRight); - Result = HMM_MultiplyQuaternionF(Result, Is); - - return(Result); -} - -HINLINE hmm_mat4 -HMM_QuaternionToMat4(hmm_quaternion Left) -{ - hmm_mat4 Result = {0}; - Result = HMM_Mat4d(1); - - hmm_quaternion NormalizedQuaternion = HMM_NormalizeQuaternion(Left); - - float XX, YY, ZZ, - XY, XZ, YZ, - WX, WY, WZ; - - XX = NormalizedQuaternion.X * NormalizedQuaternion.X; - YY = NormalizedQuaternion.Y * NormalizedQuaternion.Y; - ZZ = NormalizedQuaternion.Z * NormalizedQuaternion.Z; - XY = NormalizedQuaternion.X * NormalizedQuaternion.Y; - XZ = NormalizedQuaternion.X * NormalizedQuaternion.Z; - YZ = NormalizedQuaternion.Y * NormalizedQuaternion.Z; - WX = NormalizedQuaternion.W * NormalizedQuaternion.X; - WY = NormalizedQuaternion.W * NormalizedQuaternion.Y; - WZ = NormalizedQuaternion.W * NormalizedQuaternion.Z; - - Result.Elements[0][0] = 1.0f - 2.0f * (YY + ZZ); - Result.Elements[0][1] = 2.0f * (XY + WZ); - Result.Elements[0][2] = 2.0f * (XZ - WY); - - Result.Elements[1][0] = 2.0f * (XY - WZ); - Result.Elements[1][1] = 1.0f - 2.0f * (XX + ZZ); - Result.Elements[1][2] = 2.0f * (YZ + WX); - - Result.Elements[2][0] = 2.0f * (XZ + WY); - Result.Elements[2][1] = 2.0f * (YZ - WX); - Result.Elements[2][2] = 1.0f - 2.0f * (XX + YY); - - return(Result); -} - -HINLINE hmm_quaternion -HMM_QuaternionFromAxisAngle(hmm_vec3 Axis, float AngleOfRotation) -{ - hmm_quaternion Result = {0}; - float AxisNorm = 0; - float SineOfRotation = 0; - hmm_vec3 RotatedVector = {0}; - - AxisNorm = HMM_SquareRootF(HMM_DotVec3(Axis, Axis)); - SineOfRotation = HMM_SinF(AngleOfRotation / 2.0f); - RotatedVector = HMM_MultiplyVec3f(Axis, SineOfRotation); - - Result.W = HMM_CosF(AngleOfRotation / 2.0f); - Result.XYZ = HMM_DivideVec3f(RotatedVector, AxisNorm); - - return(Result); -} - -#ifdef HANDMADE_MATH_CPP_MODE - -HINLINE float -HMM_Length(hmm_vec2 A) -{ - float Result = 0.0f; - - Result = HMM_LengthVec2(A); - - return(Result); -} - -HINLINE float -HMM_Length(hmm_vec3 A) -{ - float Result = 0.0f; - - Result = HMM_LengthVec3(A); - - return(Result); -} - -HINLINE float -HMM_Length(hmm_vec4 A) -{ - float Result = 0.0f; - - Result = HMM_LengthVec4(A); - - return(Result); -} - -HINLINE float -HMM_LengthSquared(hmm_vec2 A) -{ - float Result = 0.0f; - - Result = HMM_LengthSquaredVec2(A); - - return(Result); -} - -HINLINE float -HMM_LengthSquared(hmm_vec3 A) -{ - float Result = 0.0f; - - Result = HMM_LengthSquaredVec3(A); - - return(Result); -} - -HINLINE float -HMM_LengthSquared(hmm_vec4 A) -{ - float Result = 0.0f; - - Result = HMM_LengthSquaredVec4(A); - - return(Result); -} - -HINLINE hmm_vec2 -HMM_Normalize(hmm_vec2 A) -{ - hmm_vec2 Result = {0}; - - Result = HMM_NormalizeVec2(A); - - return(Result); -} - -HINLINE hmm_vec3 -HMM_Normalize(hmm_vec3 A) -{ - hmm_vec3 Result = {0}; - - Result = HMM_NormalizeVec3(A); - - return(Result); -} - -HINLINE hmm_vec4 -HMM_Normalize(hmm_vec4 A) -{ - hmm_vec4 Result = {0}; - - Result = HMM_NormalizeVec4(A); - - return(Result); -} - -HINLINE hmm_quaternion -HMM_Normalize(hmm_quaternion A) -{ - hmm_quaternion Result = {0}; - - Result = HMM_NormalizeQuaternion(A); - - return(Result); -} - -HINLINE float -HMM_Dot(hmm_vec2 VecOne, hmm_vec2 VecTwo) -{ - float Result = 0; - - Result = HMM_DotVec2(VecOne, VecTwo); - - return(Result); -} - -HINLINE float -HMM_Dot(hmm_vec3 VecOne, hmm_vec3 VecTwo) -{ - float Result = 0; - - Result = HMM_DotVec3(VecOne, VecTwo); - - return(Result); -} - -HINLINE float -HMM_Dot(hmm_vec4 VecOne, hmm_vec4 VecTwo) -{ - float Result = 0; - - Result = HMM_DotVec4(VecOne, VecTwo); - - return(Result); -} - -HINLINE float -HMM_Dot(hmm_quaternion QuatOne, hmm_quaternion QuatTwo) -{ - float Result = 0; - - Result = HMM_DotQuaternion(QuatOne, QuatTwo); - - return(Result); -} - -HINLINE hmm_vec2 -HMM_Add(hmm_vec2 Left, hmm_vec2 Right) -{ - hmm_vec2 Result = {0}; - - Result = HMM_AddVec2(Left, Right); - return (Result); -} - -HINLINE hmm_vec3 -HMM_Add(hmm_vec3 Left, hmm_vec3 Right) -{ - hmm_vec3 Result = {0}; - - Result = HMM_AddVec3(Left, Right); - return (Result); -} - -HINLINE hmm_vec4 -HMM_Add(hmm_vec4 Left, hmm_vec4 Right) -{ - hmm_vec4 Result = {0}; - - Result = HMM_AddVec4(Left, Right); - return (Result); -} - -HINLINE hmm_mat4 -HMM_Add(hmm_mat4 Left, hmm_mat4 Right) -{ - hmm_mat4 Result = {0}; - - Result = HMM_AddMat4(Left, Right); - return (Result); -} - -HINLINE hmm_quaternion -HMM_Add(hmm_quaternion Left, hmm_quaternion Right) -{ - hmm_quaternion Result = {0}; - - Result = HMM_AddQuaternion(Left, Right); - return(Result); -} - -HINLINE hmm_vec2 -HMM_Subtract(hmm_vec2 Left, hmm_vec2 Right) -{ - hmm_vec2 Result = {0}; - - Result = HMM_SubtractVec2(Left, Right); - return (Result); -} - -HINLINE hmm_vec3 -HMM_Subtract(hmm_vec3 Left, hmm_vec3 Right) -{ - hmm_vec3 Result = {0}; - - Result = HMM_SubtractVec3(Left, Right); - return (Result); -} - -HINLINE hmm_vec4 -HMM_Subtract(hmm_vec4 Left, hmm_vec4 Right) -{ - hmm_vec4 Result = {0}; - - Result = HMM_SubtractVec4(Left, Right); - return (Result); -} - -HINLINE hmm_mat4 -HMM_Subtract(hmm_mat4 Left, hmm_mat4 Right) -{ - hmm_mat4 Result = {0}; - - Result = HMM_SubtractMat4(Left, Right); - return (Result); -} - -HINLINE hmm_quaternion -HMM_Subtract(hmm_quaternion Left, hmm_quaternion Right) -{ - hmm_quaternion Result = {0}; - - Result = HMM_SubtractQuaternion(Left, Right); - return (Result); -} - -HINLINE hmm_vec2 -HMM_Multiply(hmm_vec2 Left, hmm_vec2 Right) -{ - hmm_vec2 Result = {0}; - - Result = HMM_MultiplyVec2(Left, Right); - return (Result); -} - -HINLINE hmm_vec2 -HMM_Multiply(hmm_vec2 Left, float Right) -{ - hmm_vec2 Result = {0}; - - Result = HMM_MultiplyVec2f(Left, Right); - return (Result); -} - -HINLINE hmm_vec3 -HMM_Multiply(hmm_vec3 Left, hmm_vec3 Right) -{ - hmm_vec3 Result = {0}; - - Result = HMM_MultiplyVec3(Left, Right); - return (Result); -} - -HINLINE hmm_vec3 -HMM_Multiply(hmm_vec3 Left, float Right) -{ - hmm_vec3 Result = {0}; - - Result = HMM_MultiplyVec3f(Left, Right); - return (Result); -} - -HINLINE hmm_vec4 -HMM_Multiply(hmm_vec4 Left, hmm_vec4 Right) -{ - hmm_vec4 Result = {0}; - - Result = HMM_MultiplyVec4(Left, Right); - return (Result); -} - -HINLINE hmm_vec4 -HMM_Multiply(hmm_vec4 Left, float Right) -{ - hmm_vec4 Result = {0}; - - Result = HMM_MultiplyVec4f(Left, Right); - return (Result); -} - -HINLINE hmm_mat4 -HMM_Multiply(hmm_mat4 Left, hmm_mat4 Right) -{ - hmm_mat4 Result = {0}; - - Result = HMM_MultiplyMat4(Left, Right); - return (Result); -} - -HINLINE hmm_mat4 -HMM_Multiply(hmm_mat4 Left, float Right) -{ - hmm_mat4 Result = {0}; - - Result = HMM_MultiplyMat4f(Left, Right); - return (Result); -} - -HINLINE hmm_vec4 -HMM_Multiply(hmm_mat4 Matrix, hmm_vec4 Vector) -{ - hmm_vec4 Result = {0}; - - Result = HMM_MultiplyMat4ByVec4(Matrix, Vector); - return (Result); -} - -HINLINE hmm_quaternion -HMM_Multiply(hmm_quaternion Left, hmm_quaternion Right) -{ - hmm_quaternion Result = {0}; - - Result = HMM_MultiplyQuaternion(Left, Right); - return (Result); -} - -HINLINE hmm_quaternion -HMM_Multiply(hmm_quaternion Left, float Right) -{ - hmm_quaternion Result = {0}; - - Result = HMM_MultiplyQuaternionF(Left, Right); - return (Result); -} - -HINLINE hmm_quaternion -HMM_Multiply(float Left, hmm_quaternion Right) -{ - hmm_quaternion Result = {0}; - - Result = HMM_MultiplyQuaternionF(Right, Left); - return (Result); -} - -HINLINE hmm_vec2 -HMM_Divide(hmm_vec2 Left, hmm_vec2 Right) -{ - hmm_vec2 Result = {0}; - - Result = HMM_DivideVec2(Left, Right); - return (Result); -} - -HINLINE hmm_vec2 -HMM_Divide(hmm_vec2 Left, float Right) -{ - hmm_vec2 Result = {0}; - - Result = HMM_DivideVec2f(Left, Right); - return (Result); -} - -HINLINE hmm_vec3 -HMM_Divide(hmm_vec3 Left, hmm_vec3 Right) -{ - hmm_vec3 Result = {0}; - - Result = HMM_DivideVec3(Left, Right); - return (Result); -} - -HINLINE hmm_vec3 -HMM_Divide(hmm_vec3 Left, float Right) -{ - hmm_vec3 Result = {0}; - - Result = HMM_DivideVec3f(Left, Right); - return (Result); -} - -HINLINE hmm_vec4 -HMM_Divide(hmm_vec4 Left, hmm_vec4 Right) -{ - hmm_vec4 Result = {0}; - - Result = HMM_DivideVec4(Left, Right); - return (Result); -} - -HINLINE hmm_vec4 -HMM_Divide(hmm_vec4 Left, float Right) -{ - hmm_vec4 Result = {0}; - - Result = HMM_DivideVec4f(Left, Right); - return (Result); -} - -HINLINE hmm_mat4 -HMM_Divide(hmm_mat4 Left, float Right) -{ - hmm_mat4 Result = {0}; - - Result = HMM_DivideMat4f(Left, Right); - return (Result); -} - -HINLINE hmm_quaternion -HMM_Divide(hmm_quaternion Left, float Right) -{ - hmm_quaternion Result = {0}; - - Result = HMM_DivideQuaternionF(Left, Right); - return (Result); -} - -HINLINE hmm_vec2 -operator+(hmm_vec2 Left, hmm_vec2 Right) -{ - hmm_vec2 Result = {0}; - - Result = HMM_Add(Left, Right); - return (Result); -} - -HINLINE hmm_vec3 -operator+(hmm_vec3 Left, hmm_vec3 Right) -{ - hmm_vec3 Result = {0}; - - Result = HMM_Add(Left, Right); - return (Result); -} - -HINLINE hmm_vec4 -operator+(hmm_vec4 Left, hmm_vec4 Right) -{ - hmm_vec4 Result = {0}; - - Result = HMM_Add(Left, Right); - return (Result); -} - -HINLINE hmm_mat4 -operator+(hmm_mat4 Left, hmm_mat4 Right) -{ - hmm_mat4 Result = {0}; - - Result = HMM_Add(Left, Right); - return (Result); -} - -HINLINE hmm_quaternion -operator+(hmm_quaternion Left, hmm_quaternion Right) -{ - hmm_quaternion Result = {0}; - - Result = HMM_Add(Left, Right); - return (Result); -} - -HINLINE hmm_vec2 -operator-(hmm_vec2 Left, hmm_vec2 Right) -{ - hmm_vec2 Result = {0}; - - Result = HMM_Subtract(Left, Right); - return (Result); -} - -HINLINE hmm_vec3 -operator-(hmm_vec3 Left, hmm_vec3 Right) -{ - hmm_vec3 Result = {0}; - - Result = HMM_Subtract(Left, Right); - return (Result); -} - -HINLINE hmm_vec4 -operator-(hmm_vec4 Left, hmm_vec4 Right) -{ - hmm_vec4 Result = {0}; - - Result = HMM_Subtract(Left, Right); - return (Result); -} - -HINLINE hmm_mat4 -operator-(hmm_mat4 Left, hmm_mat4 Right) -{ - hmm_mat4 Result = {0}; - - Result = HMM_Subtract(Left, Right); - return (Result); -} - -HINLINE hmm_quaternion -operator-(hmm_quaternion Left, hmm_quaternion Right) -{ - hmm_quaternion Result = {0}; - - Result = HMM_Subtract(Left, Right); - return (Result); -} - -HINLINE hmm_vec2 -operator*(hmm_vec2 Left, hmm_vec2 Right) -{ - hmm_vec2 Result = {0}; - - Result = HMM_Multiply(Left, Right); - return (Result); -} - -HINLINE hmm_vec3 -operator*(hmm_vec3 Left, hmm_vec3 Right) -{ - hmm_vec3 Result = {0}; - - Result = HMM_Multiply(Left, Right); - return (Result); -} - -HINLINE hmm_vec4 -operator*(hmm_vec4 Left, hmm_vec4 Right) -{ - hmm_vec4 Result = HMM_Multiply(Left, Right); - - return (Result); -} - -HINLINE hmm_vec2 -operator*(hmm_vec2 Left, float Right) -{ - hmm_vec2 Result = {0}; - - Result = HMM_Multiply(Left, Right); - return (Result); -} - -HINLINE hmm_vec3 -operator*(hmm_vec3 Left, float Right) -{ - hmm_vec3 Result = {0}; - - Result = HMM_Multiply(Left, Right); - return (Result); -} - -HINLINE hmm_vec4 -operator*(hmm_vec4 Left, float Right) -{ - hmm_vec4 Result = {0}; - - Result = HMM_Multiply(Left, Right); - return (Result); -} - -HINLINE hmm_mat4 -operator*(hmm_mat4 Left, float Right) -{ - hmm_mat4 Result = {0}; - - Result = HMM_Multiply(Left, Right); - return (Result); -} - -HINLINE hmm_vec2 -operator*(float Left, hmm_vec2 Right) -{ - hmm_vec2 Result = {0}; - - Result = HMM_Multiply(Right, Left); - return (Result); -} - -HINLINE hmm_vec3 -operator*(float Left, hmm_vec3 Right) -{ - hmm_vec3 Result = {0}; - - Result = HMM_Multiply(Right, Left); - return (Result); -} - -HINLINE hmm_vec4 -operator*(float Left, hmm_vec4 Right) -{ - hmm_vec4 Result = {0}; - - Result = HMM_Multiply(Right, Left); - return (Result); -} - -HINLINE hmm_mat4 -operator*(float Left, hmm_mat4 Right) -{ - hmm_mat4 Result = {0}; - - Result = HMM_Multiply(Right, Left); - return (Result); -} - -HINLINE hmm_mat4 -operator*(hmm_mat4 Left, hmm_mat4 Right) -{ - hmm_mat4 Result = {0}; - - Result = HMM_Multiply(Left, Right); - return (Result); -} - -HINLINE hmm_vec4 -operator*(hmm_mat4 Matrix, hmm_vec4 Vector) -{ - hmm_vec4 Result = {0}; - - Result = HMM_Multiply(Matrix, Vector); - return (Result); -} - -HINLINE hmm_quaternion -operator*(hmm_quaternion Left, hmm_quaternion Right) -{ - hmm_quaternion Result = {0}; - - Result = HMM_Multiply(Left, Right); - return (Result); -} - -HINLINE hmm_quaternion -operator*(hmm_quaternion Left, float Right) -{ - hmm_quaternion Result = {0}; - - Result = HMM_Multiply(Left, Right); - return (Result); -} - -HINLINE hmm_quaternion -operator*(float Left, hmm_quaternion Right) -{ - hmm_quaternion Result = {0}; - - Result = HMM_Multiply(Right, Left); - return (Result); -} - -HINLINE hmm_vec2 -operator/(hmm_vec2 Left, hmm_vec2 Right) -{ - hmm_vec2 Result = {0}; - - Result = HMM_Divide(Left, Right); - return (Result); -} - -HINLINE hmm_vec3 -operator/(hmm_vec3 Left, hmm_vec3 Right) -{ - hmm_vec3 Result = {0}; - - Result = HMM_Divide(Left, Right); - - return (Result); -} - -HINLINE hmm_vec4 -operator/(hmm_vec4 Left, hmm_vec4 Right) -{ - hmm_vec4 Result = {0}; - - Result = HMM_Divide(Left, Right); - return (Result); -} - -HINLINE hmm_vec2 -operator/(hmm_vec2 Left, float Right) -{ - hmm_vec2 Result = {0}; - - Result = HMM_Divide(Left, Right); - return (Result); -} - -HINLINE hmm_vec3 -operator/(hmm_vec3 Left, float Right) -{ - hmm_vec3 Result = {0}; - - Result = HMM_Divide(Left, Right); - return (Result); -} - -HINLINE hmm_vec4 -operator/(hmm_vec4 Left, float Right) -{ - hmm_vec4 Result = {0}; - - Result = HMM_Divide(Left, Right); - return (Result); -} - -HINLINE hmm_mat4 -operator/(hmm_mat4 Left, float Right) -{ - hmm_mat4 Result = {0}; - - Result = HMM_Divide(Left, Right); - return (Result); -} - -HINLINE hmm_quaternion -operator/(hmm_quaternion Left, float Right) -{ - hmm_quaternion Result = {0}; - - Result = HMM_Divide(Left, Right); - return (Result); -} - -HINLINE hmm_vec2 & -operator+=(hmm_vec2 &Left, hmm_vec2 Right) -{ - return (Left = Left + Right); -} - -HINLINE hmm_vec3 & -operator+=(hmm_vec3 &Left, hmm_vec3 Right) -{ - return (Left = Left + Right); -} - -HINLINE hmm_vec4 & -operator+=(hmm_vec4 &Left, hmm_vec4 Right) -{ - return (Left = Left + Right); -} - -HINLINE hmm_mat4 & -operator+=(hmm_mat4 &Left, hmm_mat4 Right) -{ - return (Left = Left + Right); -} - -HINLINE hmm_quaternion & -operator+=(hmm_quaternion &Left, hmm_quaternion Right) -{ - return (Left = Left + Right); -} - -HINLINE hmm_vec2 & -operator-=(hmm_vec2 &Left, hmm_vec2 Right) -{ - return (Left = Left - Right); -} - -HINLINE hmm_vec3 & -operator-=(hmm_vec3 &Left, hmm_vec3 Right) -{ - return (Left = Left - Right); -} - -HINLINE hmm_vec4 & -operator-=(hmm_vec4 &Left, hmm_vec4 Right) -{ - return (Left = Left - Right); -} - -HINLINE hmm_mat4 & -operator-=(hmm_mat4 &Left, hmm_mat4 Right) -{ - return (Left = Left - Right); -} - -HINLINE hmm_quaternion & -operator-=(hmm_quaternion &Left, hmm_quaternion Right) -{ - return (Left = Left - Right); -} - -HINLINE hmm_vec2 & -operator/=(hmm_vec2 &Left, hmm_vec2 Right) -{ - return (Left = Left / Right); -} - -HINLINE hmm_vec3 & -operator/=(hmm_vec3 &Left, hmm_vec3 Right) -{ - return (Left = Left / Right); -} - -HINLINE hmm_vec4 & -operator/=(hmm_vec4 &Left, hmm_vec4 Right) -{ - return (Left = Left / Right); -} - -HINLINE hmm_vec2 & -operator/=(hmm_vec2 &Left, float Right) -{ - return (Left = Left / Right); -} - -HINLINE hmm_vec3 & -operator/=(hmm_vec3 &Left, float Right) -{ - return (Left = Left / Right); -} - -HINLINE hmm_vec4 & -operator/=(hmm_vec4 &Left, float Right) -{ - return (Left = Left / Right); -} - -HINLINE hmm_mat4 & -operator/=(hmm_mat4 &Left, float Right) -{ - return (Left = Left / Right); -} - -HINLINE hmm_quaternion & -operator/=(hmm_quaternion &Left, float Right) -{ - return (Left = Left / Right); -} - -HINLINE hmm_vec2 & -operator*=(hmm_vec2 &Left, hmm_vec2 Right) -{ - return (Left = Left * Right); -} - -HINLINE hmm_vec3 & -operator*=(hmm_vec3 &Left, hmm_vec3 Right) -{ - return (Left = Left * Right); -} - -HINLINE hmm_vec4 & -operator*=(hmm_vec4 &Left, hmm_vec4 Right) -{ - return (Left = Left * Right); -} - -HINLINE hmm_vec2 & -operator*=(hmm_vec2 &Left, float Right) -{ - return (Left = Left * Right); -} - -HINLINE hmm_vec3 & -operator*=(hmm_vec3 &Left, float Right) -{ - return (Left = Left * Right); -} - -HINLINE hmm_vec4 & -operator*=(hmm_vec4 &Left, float Right) -{ - return (Left = Left * Right); -} - -HINLINE hmm_mat4 & -operator*=(hmm_mat4 &Left, float Right) -{ - return (Left = Left * Right); -} - -HINLINE hmm_quaternion & -operator*=(hmm_quaternion &Left, float Right) -{ - return (Left = Left * Right); -} - -#endif /* HANDMADE_MATH_CPP_MODE */ - -#endif /* HANDMADE_MATH_IMPLEMENTATION */ - -#ifdef __GNUC__ - #pragma GCC diagnostic pop -#endif diff --git a/Code/Deprecated/build.bat b/Code/Deprecated/build.bat deleted file mode 100644 index bbafb7f..0000000 --- a/Code/Deprecated/build.bat +++ /dev/null @@ -1,71 +0,0 @@ -@REM Build for Visual Studio compiler. Run your copy of vcvars32.bat or -@REM vcvarsall.bat to setup command-line compiler. - -@echo OFF -set ProjectName=DqnUnitTest -set CompileEntryPoint=..\DqnUnitTest.cpp - -REM Build tags file if you have ctags in path -where /q ctags -if %errorlevel%==0 ( -REM When parsing a C++ member function definition (e.g. "className::function"), -REM ctags cannot determine whether the scope specifier is a class name or -REM a namespace specifier and always lists it as a class name in the scope -REM portion of the extension fields. Also, if a C++ function is defined outside -REM of the class declaration (the usual case), the access specification (i.e. -REM public, protected, or private) and implementation information (e.g. virtual, -REM pure virtual) contained in the function declaration are not known when the -REM tag is generated for the function definition. -c++-kinds=+p fixes that - -REM The --fields=+iaS option: -REM a Access (or export) of class members -REM i Inheritance information -REM S Signature of routine (e.g. prototype or parameter list) -REM -REM The --extra=+q option: -REM By default, ctags only generates tags for separate identifiers found in -REM the source files. With --extras=+q option, then ctags will also generate -REM a second, class-qualified tag for each class member - ctags -R --c++-kinds=+p --fields=+iaS --extras=+q -) - -REM Check if build tool is on path -REM >nul, 2>nul will remove the output text from the where command -where cl.exe >nul 2>nul -if %errorlevel%==1 call msvc86.bat - -REM Drop compilation files into build folder -IF NOT EXIST bin mkdir bin -pushd bin - -REM EHa- disable exception handling (but we use for algorithms so /EHsc) -REM GR- disable c runtime type information (we don't use) - -REM MD use dynamic runtime library -REM MT use static runtime library, so build and link it into exe - -REM Oi enable intrinsics optimisation, let us use CPU intrinsics if there is one -REM instead of generating a call to external library (i.e. CRT). - -REM Zi enables debug data, Z7 combines the debug files into one. - -REM W4 warning level 4 -REM WX treat warnings as errors -REM wd4201 ignore: nonstandard extension used: nameless struct/union -set CompileFlags=-EHsc -GR- -Oi -MT -Z7 -W4 -WX -wd4201 -FC -Od -wd4127 /P - -REM Include directories -set IncludeFlags= - -REM Link libraries -set LinkLibraries=user32.lib ws2_32.lib - -REM incrmenetal:no, turn incremental builds off -REM opt:ref, try to remove functions from libs that are referenced at all -set LinkFlags=-incremental:no -opt:ref -machine:x64 - -cl %CompileFlags% %CompileEntryPoint% %IncludeFlags% /link %LinkLibraries% %LinkFlags% /nologo /OUT:"%ProjectName%.exe" -REM cl /P /c %CompileFlags% %CompileEntryPoint% - -popd - diff --git a/Code/Deprecated/dqn.h b/Code/Deprecated/dqn.h deleted file mode 100644 index cca5847..0000000 --- a/Code/Deprecated/dqn.h +++ /dev/null @@ -1,8862 +0,0 @@ -// Dqn.h Usage -// ================================================================================================= -/* - // Define this wherever you want access to DQN code that uses the platform. - #define DQN_PLATFORM_HEADER // Enable function prototypes for xplatform/platform code - #define DQN_IMPLEMENTATION // Enable the implementation - #define DQN_PLATFORM_IMPLEMENTATION // Enable platform specific implementation on Win32 you must link against user32.lib and kernel32.lib - #define DQN_MAKE_STATIC // Make all functions be static - #include "dqn.h" - */ - -// Conventions -// All data structures fields are exposed by default, with exceptions here and there. The rationale -// is I rarely go into libraries and start changing values around in fields unless I know the -// implementation OR we're required to fill out a struct for some function. - -// Just treat all struct fields to be internal and read-only unless explicitly stated otherwise. - -// Table Of Contents #TOC #TableOfContents -// ================================================================================================= -// You can search by # to jump straight to the section. -// The first match is the public API, the next matche(s) are the implementation - -// #Preprocessor Checks -// #Portable Code -// #Library Settings -// #Win32 Prototypes -// #DqnSprintf Cross-platform Sprintf Implementation (Public Domain lib stb_sprintf) -// #DqnDefer Macro helper/template to implement defer in C++ -// #DqnAssert Assertions and Logging -// #DqnAllocator Generic allocation API for Dqn Data Structures -// #DqnSlice A ptr and length into memory but doesn't imply ownership of memory -// #DqnBuffer Typedef to slices, but indicates ownership of the memory -// #DqnFixedString Fixed sized strings at compile time. -// #DqnMem Memory Allocation -// #DqnMemStack Memory Allocator, Push, Pop Style -// #DqnLogger -// #DqnArray Dynamic Array using Templates -// #DqnChar Char Operations (IsDigit(), IsAlpha() etc) -// #DqnStr Str Operations (Str_Len(), Str_Copy() etc) -// #DqnWChar WChar Operations (IsDigit(), IsAlpha() etc) -// #DqnWStr WStr Operations (Str_Len(), Str_Copy() etc) -// #DqnString String library -// #DqnRndPCG 32 bit Random Number Generator using PCG (ints and floats) -// #Dqn_* Random utility functions -// #DqnFixedPool Pool objects -// #DqnPool Pool objects -// #DqnHash Hashing using Murmur -// #DqnMath Simple Math Helpers (Lerp etc.) -// #DqnV2 2D Math Vectors -// #DqnV3 3D Math Vectors -// #DqnV4 4D Math Vectors -// #DqnMat4 4x4 Math Matrix -// #DqnRect Rectangles -// #DqnJson Zero Allocation Json Parser - -// #XPlatform (Win32 & Unix) -// #DqnVArray Array backed by virtual memory -// #DqnVHashTable Hash Table using templates backed by virtual memory -// #DqnFile File I/O (Read, Write, Delete) -// #DqnTimer High Resolution Timer -// #DqnLock Mutex Synchronisation -// #DqnJobQueue Multithreaded Job Queue -// #DqnAtomic Interlocks/Atomic Operations -// #DqnOS Common Platform API helpers - -// #Platform -// - #DqnWin32 Common Win32 API Helpers - -// TODO -// - Win32 -// - Get rid of reliance on MAX_PATH -// -// - Mbuildake lib compile and run on Linux with GCC using -03 -// - Make DqnV* operations be static to class for consistency? - -// #Preprocessor Checks -// ================================================================================================= -// This needs to be above the portable layer so that, if the user requests a platform -// implementation, platform specific implementations in the portable layer will get activated. -#if (defined(_WIN32) || defined(_WIN64)) - #define DQN_IS_WIN32 1 -#else - #define DQN_IS_UNIX 1 -#endif - -#if defined(DQN_PLATFORM_IMPLEMENTATION) - #define DQN__XPLATFORM_LAYER 1 -#endif - -// #Portable Code -// ================================================================================================= -#ifndef DQN_H -#define DQN_H - -#ifdef DQN_MAKE_STATIC - #define DQN_FILE_SCOPE static -#else - #define DQN_FILE_SCOPE -#endif - -#include // For standard types -#include // For standard types -#include // memmove -#include // va_list -#include // FLT_MAX -#define LOCAL_PERSIST static -#define FILE_SCOPE static - -using usize = size_t; -using isize = ptrdiff_t; - -using uint = unsigned int; -using u64 = uint64_t; -using u32 = uint32_t; -using u16 = uint16_t; -using u8 = uint8_t; - -using i64 = int64_t; -using i32 = int32_t; -using i16 = int16_t; -using i8 = int8_t; - -using b32 = i32; - -using f64 = double; -using f32 = float; - -#define DQN_F32_MIN -FLT_MAX -#define DQN_I64_MAX INT64_MAX -#define DQN_U64_MAX UINT64_MAX - -#define DQN_TERABYTE(val) (DQN_GIGABYTE(val) * 1024LL) - -#define DQN_TERABYTE(val) (DQN_GIGABYTE(val) * 1024LL) -#define DQN_GIGABYTE(val) (DQN_MEGABYTE(val) * 1024LL) -#define DQN_MEGABYTE(val) (DQN_KILOBYTE(val) * 1024LL) -#define DQN_KILOBYTE(val) ((val) * 1024LL) - -#define DQN_DAY_TO_S(val) ((DQN_HOUR_TO_S(val)) * 24) -#define DQN_HOUR_TO_S(val) ((DQN_MINUTE_TO_S(val)) * 60) -#define DQN_MINUTE_TO_S(val) ((val) * 60) - -#define DQN_ALIGN_POW_N(val, align) ((((usize)val) + ((usize)align-1)) & (~(usize)(align-1))) -#define DQN_ALIGN_POW_4(val) DQN_ALIGN_POW_N(val, 4) - -#define DQN_INVALID_CODE_PATH 0 -#define DQN_CHAR_COUNT(charArray) DQN_ARRAY_COUNT(charArray) - 1 -#define DQN_ARRAY_COUNT(array) (sizeof(array) / sizeof(array[0])) - -#define DQN_PI 3.14159265359f -#define DQN_SQUARED(x) ((x) * (x)) -#define DQN_ABS(x) (((x) < 0) ? (-(x)) : (x)) -#define DQN_DEGREES_TO_RADIANS(x) ((x * (DQN_PI / 180.0f))) -#define DQN_RADIANS_TO_DEGREES(x) ((x * (180.0f / DQN_PI))) - -#define DQN_CLAMP(value, min, max) DQN_MIN(DQN_MAX(value, min), max) -#define DQN_MAX(a, b) ((a) < (b) ? (b) : (a)) -#define DQN_MIN(a, b) ((a) < (b) ? (a) : (b)) -#define DQN_SWAP(type, a, b) do { type tmp = a; a = b; b = tmp; } while(0) - -// NOTE: Directives don't get replaced if there's a stringify or paste (# or ##) so TOKEN_COMBINE2 is needed -// to let directives get expanded (i.e. __COUNTER__), then we can combine. -#define DQN_TOKEN_COMBINE(x, y) x ## y -#define DQN_TOKEN_COMBINE2(x, y) DQN_TOKEN_COMBINE(x, y) - -// Produce a unique name with prefix and counter. i.e. where prefix is "data" then it gives "data1" -#define DQN_UNIQUE_NAME(prefix) DQN_TOKEN_COMBINE2(prefix, __COUNTER__) -#define DQN_FOR_EACH(i, lim) for (isize (i) = 0; (i) < (isize)(lim); ++(i)) - -// #Library Settings -// ================================================================================================= -namespace Dqn -{ -enum struct ZeroMem { No = 0, Yes = 1}; -enum struct IgnoreCase { No = 0, Yes = 1}; - -FILE_SCOPE const bool is_debug = true; -FILE_SCOPE const bool allow_allocation_tagging = true; -}; // namespace Dqn - - -// #Win32 Prototypes -// ================================================================================================= -#if defined(DQN_PLATFORM_HEADER) && defined(DQN_IS_WIN32) && !defined(_WINDOWS_) -using WORD = unsigned short; -using DWORD = unsigned long; -using BOOL = int; -using LONG = long; -using LONGLONG = long long; -using HANDLE = void *; -using HMODULE = HANDLE; -using HWND = HANDLE; -using UINT = unsigned int; -using ULONG = unsigned long; -using ULONGLONG = unsigned long long; -using DWORD64 = unsigned long long; -using BYTE = unsigned char; - -u32 const MB_OK = 0x00000000L; -HANDLE const INVALID_HANDLE_VALUE = ((HANDLE)(LONG *)-1); -u32 const MAX_PATH = 260; -u32 const INFINITE = 0xFFFFFFFF; -u32 const CP_UTF8 = 65001; -u32 const FORMAT_MESSAGE_IGNORE_INSERTS = 0x00000200; -u32 const FORMAT_MESSAGE_FROM_SYSTEM = 0x00001000; -u32 const MEM_COMMIT = 0x00001000; -u32 const MEM_RESERVE = 0x00002000; -u32 const PAGE_READWRITE = 0x04; -u32 const MEM_DECOMMIT = 0x4000; -u32 const MEM_RELEASE = 0x8000; -u32 const GENERIC_READ = 0x80000000L; -u32 const GENERIC_WRITE = 0x40000000L; -u32 const GENERIC_EXECUTE = 0x20000000L; -u32 const GENERIC_ALL = 0x10000000L; -u32 const CREATE_NEW = 1; -u32 const CREATE_ALWAYS = 2; -u32 const OPEN_EXISTING = 3; -u32 const OPEN_ALWAYS = 4; -u32 const TRUNCATE_EXISTING = 5; -u32 const FILE_ATTRIBUTE_NORMAL = 0x00000080; - -struct RECT -{ - LONG left; - LONG top; - LONG right; - LONG bottom; -}; - -union LARGE_INTEGER -{ - struct { DWORD LowPart; LONG HighPart; }; - struct { DWORD LowPart; LONG HighPart; } u; - LONGLONG QuadPart; -}; - -union ULARGE_INTEGER -{ - struct { DWORD LowPart; DWORD HighPart; }; - struct { DWORD LowPart; DWORD HighPart; } u; - ULONGLONG QuadPart; -}; - -struct SECURITY_ATTRIBUTES -{ - DWORD length; - void *securityDescriptor; - BOOL inheritHandle; -}; - -struct PROCESS_INFORMATION -{ - void *hProcess; - void *hThread; - DWORD dwProcessId; - DWORD dwThreadId; -}; - - -struct FILETIME -{ - DWORD dwLowDateTime; - DWORD dwHighDateTime; -}; - -struct WIN32_FILE_ATTRIBUTE_DATA -{ - DWORD dwFileAttributes; - FILETIME ftCreationTime; - FILETIME ftLastAccessTime; - FILETIME ftLastWriteTime; - DWORD nFileSizeHigh; - DWORD nFileSizeLow; -}; - -enum GET_FILEEX_INFO_LEVELS -{ - GetFileExInfoStandard, - GetFileExMaxInfoLevel -}; - -struct WIN32_FIND_DATAW -{ - DWORD dwFileAttributes; - FILETIME ftCreationTime; - FILETIME ftLastAccessTime; - FILETIME ftLastWriteTime; - DWORD nFileSizeHigh; - DWORD nFileSizeLow; - DWORD dwReserved0; - DWORD dwReserved1; - wchar_t cFileName[MAX_PATH]; - wchar_t cAlternateFileName[14]; -}; - -struct LIST_ENTRY { - struct LIST_ENTRY *Flink; - struct LIST_ENTRY *Blink; -}; - -struct RTL_CRITICAL_SECTION_DEBUG -{ - WORD Type; - WORD CreatorBackTraceIndex; - struct CRITICAL_SECTION *CriticalSection; - LIST_ENTRY ProcessLocksList; - DWORD EntryCount; - DWORD ContentionCount; - DWORD Flags; - WORD CreatorBackTraceIndexHigh; - WORD SpareWORD; -}; - -struct CRITICAL_SECTION -{ - RTL_CRITICAL_SECTION_DEBUG *DebugInfo; - LONG LockCount; - LONG RecursionCount; - HANDLE OwningThread; - HANDLE LockSemaphore; - ULONG *SpinCount; -}; - -struct OVERLAPPED { - ULONG *Internal; - ULONG *InternalHigh; - union { - struct { - DWORD Offset; - DWORD OffsetHigh; - }; - void *Pointer; - }; - HANDLE hEvent; -}; - -struct SYSTEM_INFO { - union - { - DWORD dwOemId; - struct - { - WORD wProcessorArchitecture; - WORD wReserved; - }; - }; - DWORD dwPageSize; - void *lpMinimumApplicationAddress; - void *lpMaximumApplicationAddress; - DWORD *dwActiveProcessorMask; - DWORD dwNumberOfProcessors; - DWORD dwProcessorType; - DWORD dwAllocationGranularity; - WORD wProcessorLevel; - WORD wProcessorRevision; -}; - -enum LOGICAL_PROCESSOR_RELATIONSHIP -{ - RelationProcessorCore, - RelationNumaNode, - RelationCache, - RelationProcessorPackage, - RelationGroup, - RelationAll = 0xffff -}; - -typedef unsigned long *KAFFINITY; -struct GROUP_AFFINITY { - KAFFINITY Mask; - WORD Group; - WORD Reserved[3]; -}; - -struct PROCESSOR_RELATIONSHIP -{ - BYTE Flags; - BYTE EfficiencyClass; - BYTE Reserved[20]; - WORD GroupCount; - GROUP_AFFINITY GroupMask[1]; -}; - -struct NUMA_NODE_RELATIONSHIP { - DWORD NodeNumber; - BYTE Reserved[20]; - GROUP_AFFINITY GroupMask; -}; - -enum PROCESSOR_CACHE_TYPE -{ - CacheUnified, - CacheInstruction, - CacheData, - CacheTrace -}; - -struct CACHE_RELATIONSHIP -{ - BYTE Level; - BYTE Associativity; - WORD LineSize; - DWORD CacheSize; - PROCESSOR_CACHE_TYPE Type; - BYTE Reserved[20]; - GROUP_AFFINITY GroupMask; -}; - -struct PROCESSOR_GROUP_INFO -{ - BYTE MaximumProcessorCount; - BYTE ActiveProcessorCount; - BYTE Reserved[38]; - KAFFINITY ActiveProcessorMask; -}; - -struct GROUP_RELATIONSHIP -{ - WORD MaximumGroupCount; - WORD ActiveGroupCount; - BYTE Reserved[20]; - PROCESSOR_GROUP_INFO GroupInfo[1]; -}; - -struct SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX -{ - LOGICAL_PROCESSOR_RELATIONSHIP Relationship; - DWORD Size; - union - { - PROCESSOR_RELATIONSHIP Processor; - NUMA_NODE_RELATIONSHIP NumaNode; - CACHE_RELATIONSHIP Cache; - GROUP_RELATIONSHIP Group; - }; -}; - -struct SYSTEMTIME -{ - WORD wYear; - WORD wMonth; - WORD wDayOfWeek; - WORD wDay; - WORD wHour; - WORD wMinute; - WORD wSecond; - WORD wMilliseconds; -}; - -struct FILETIME -{ - DWORD dwLowDateTime; - DWORD dwHighDateTime; -}; - -typedef DWORD (*LPTHREAD_START_ROUTINE)(void *lpThreadParameter); - -DWORD64 __rdtsc(); - -void DeleteCriticalSection (CRITICAL_SECTION *lpCriticalSection); -BOOL DeleteFileA (char const *lpFileName); // TODO(doyle): Wide versions only -BOOL DeleteFileW (wchar_t const *lpFileName); -BOOL CloseHandle (HANDLE hObject); -BOOL CopyFileA (char const *lpExistingFileName, char const *lpNewFileName, BOOL bFailIfExists); -BOOL CopyFileW (wchar_t const *lpExistingFileName, wchar_t const *lpNewFileName, BOOL bFailIfExists); -BOOL CloseHandle (HANDLE *hObject); -HANDLE CreateFileW (wchar_t const *lpFileName, DWORD dwDesiredAccess, DWORD dwShareMode, SECURITY_ATTRIBUTES *lpSecurityAttributes, - DWORD dwCreationDisposition, DWORD dwFlagsAndAttributes, HANDLE hTemplateFile); -HANDLE CreateSemaphoreA (SECURITY_ATTRIBUTES *lpSemaphoreAttributes, long lInitialCount, long lMaximumCount, char const *lpName); -HANDLE CreateThread (SECURITY_ATTRIBUTES *lpThreadAttributes, size_t dwStackSize, LPTHREAD_START_ROUTINE lpStartAddress, - void *lpParameter, DWORD dwCreationFlags, DWORD *lpThreadId); -void EnterCriticalSection (CRITICAL_SECTION *lpCriticalSection); -BOOL FindClose (HANDLE hFindFile); -HANDLE FindFirstFileW (wchar_t const *lpFileName, WIN32_FIND_DATAW *lpFindFileData); -BOOL FindNextFileW (HANDLE hFindFile, WIN32_FIND_DATAW *lpFindFileData); -DWORD FormatMessageA (DWORD dwFlags, void const *lpSource, DWORD dwMessageId, DWORD dwLanguageId, char *lpBuffer, DWORD nSize, va_list *Arguments); -BOOL GetClientRect (HWND hWnd, RECT *lpRect); -BOOL GetExitCodeProcess (HANDLE *hProcess, DWORD *lpExitCode); -BOOL GetFileSizeEx (HANDLE hFile, LARGE_INTEGER *lpFileSize); -BOOL GetFileAttributesExW (wchar_t const *lpFileName, GET_FILEEX_INFO_LEVELS fInfoLevelId, void *lpFileInformation); -DWORD GetLastError (void); -void GetLocalTime (SYSTEMTIME *lpSystemTime); -DWORD GetModuleFileNameA (HMODULE hModule, char *lpFilename, DWORD nSize); -void GetNativeSystemInfo (SYSTEM_INFO *lpSystemInfo); -BOOL GetLogicalProcessorInformationEx(LOGICAL_PROCESSOR_RELATIONSHIP RelationshipType, SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX *Buffer, DWORD *ReturnedLength); -BOOL InitializeCriticalSectionEx (CRITICAL_SECTION *lpCriticalSection, DWORD dwSpinCount, DWORD Flags); -long InterlockedAdd (long volatile *Addend, long Value); -long InterlockedCompareExchange (long volatile *Destination, long Exchange, long Comparand); -void LeaveCriticalSection (CRITICAL_SECTION *lpCriticalSection); -int MessageBoxA (HWND hWnd, char const *lpText, char const *lpCaption, UINT uType); -int MultiByteToWideChar (unsigned int CodePage, DWORD dwFlags, char const *lpMultiByteStr, int cbMultiByte, wchar_t *lpWideCharStr, int cchWideChar); -void OutputDebugStringA (char const *lpOutputString); -BOOL ReadFile (HANDLE hFile, void *lpBuffer, DWORD nNumberOfBytesToRead, DWORD *lpNumberOfBytesRead, OVERLAPPED *lpOverlapped); -BOOL ReleaseSemaphore (HANDLE hSemaphore, long lReleaseCount, long *lpPreviousCount); -BOOL QueryPerformanceFrequency (LARGE_INTEGER *lpFrequency); -BOOL QueryPerformanceCounter (LARGE_INTEGER *lpPerformanceCount); -DWORD WaitForSingleObject (HANDLE *hHandle, DWORD dwMilliseconds); -DWORD WaitForSingleObjectEx (HANDLE hHandle, DWORD dwMilliseconds, BOOL bAlertable); -int WideCharToMultiByte (unsigned int CodePage, DWORD dwFlags, wchar_t const *lpWideCharStr, int cchWideChar, - char *lpMultiByteStr, int cbMultiByte, char const *lpDefaultChar, BOOL *lpUsedDefaultChar); -void Sleep (DWORD dwMilliseconds); -BOOL WriteFile (HANDLE hFile, void *const lpBuffer, DWORD nNumberOfBytesToWrite, DWORD *lpNumberOfBytesWritten, OVERLAPPED *lpOverlapped); -void *VirtualAlloc (void *lpAddress, size_t dwSize, DWORD flAllocationType, DWORD flProtect); -BOOL VirtualFree (void *lpAddress, size_t dwSize, DWORD dwFreeType); -#endif // defined(DQN_PLATFORM_HEADER) && defined(DQN_IS_WIN32) && !defined(_WINDOWS_) -#ifndef STB_SPRINTF_H_INCLUDE -#define STB_SPRINTF_H_INCLUDE - -//////////////////////////////////////////////////////////////////////////////// -// #DqnSprintf Public API - Cross-platform Sprintf Implementation -//////////////////////////////////////////////////////////////////////////////// -// stb_sprintf - v1.05 - public domain snprintf() implementation -// originally by Jeff Roberts / RAD Game Tools, 2015/10/20 -// http://github.com/nothings/stb -// -// allowed types: sc uidBboXx p AaGgEef n -// lengths : h ll j z t I64 I32 I -// -// Contributors: -// Fabian "ryg" Giesen (reformatting) -// -// Contributors (bugfixes): -// github:d26435 -// github:trex78 -// Jari Komppa (SI suffixes) -// Rohit Nirmal -// Marcin Wojdyr -// Leonard Ritter -// -// LICENSE: -// -// See end of file for license information. - -/* -Single file sprintf replacement. -Originally written by Jeff Roberts at RAD Game Tools - 2015/10/20. -Hereby placed in public domain. -This is a full sprintf replacement that supports everything that -the C runtime sprintfs support, including float/double, 64-bit integers, -hex floats, field parameters (%*.*d stuff), length reads backs, etc. -Why would you need this if sprintf already exists? Well, first off, -it's *much* faster (see below). It's also much smaller than the CRT -versions code-space-wise. We've also added some simple improvements -that are super handy (commas in thousands, callbacks at buffer full, -for example). Finally, the format strings for MSVC and GCC differ -for 64-bit integers (among other small things), so this lets you use -the same format strings in cross platform code. -It uses the standard single file trick of being both the header file -and the source itself. If you just include it normally, you just get -the header file function definitions. To get the code, you include -it from a C or C++ file and define STB_SPRINTF_IMPLEMENTATION first. -It only uses va_args macros from the C runtime to do it's work. It -does cast doubles to S64s and shifts and divides U64s, which does -drag in CRT code on most platforms. -It compiles to roughly 8K with float support, and 4K without. -As a comparison, when using MSVC static libs, calling sprintf drags -in 16K. -API: -==== -int stbsp_sprintf( char * buf, char const * fmt, ... ) -int stbsp_snprintf( char * buf, int count, char const * fmt, ... ) - Convert an arg list into a buffer. stbsp_snprintf always returns - a zero-terminated string (unlike regular snprintf). -int stbsp_vsprintf( char * buf, char const * fmt, va_list va ) -int stbsp_vsnprintf( char * buf, int count, char const * fmt, va_list va ) - Convert a va_list arg list into a buffer. stbsp_vsnprintf always returns - a zero-terminated string (unlike regular snprintf). -int stbsp_vsprintfcb( STBSP_SPRINTFCB * callback, void * user, char * buf, char const * fmt, va_list va ) - typedef char * STBSP_SPRINTFCB( char const * buf, void * user, int len ); - Convert into a buffer, calling back every STB_SPRINTF_MIN chars. - Your callback can then copy the chars out, print them or whatever. - This function is actually the workhorse for everything else. - The buffer you pass in must hold at least STB_SPRINTF_MIN characters. - // you return the next buffer to use or 0 to stop converting -void stbsp_set_separators( char comma, char period ) - Set the comma and period characters to use. -FLOATS/DOUBLES: -=============== -This code uses a internal float->ascii conversion method that uses -doubles with error correction (double-doubles, for ~105 bits of -precision). This conversion is round-trip perfect - that is, an atof -of the values output here will give you the bit-exact double back. -One difference is that our insignificant digits will be different than -with MSVC or GCC (but they don't match each other either). We also -don't attempt to find the minimum length matching float (pre-MSVC15 -doesn't either). -If you don't need float or doubles at all, define STB_SPRINTF_NOFLOAT -and you'll save 4K of code space. -64-BIT INTS: -============ -This library also supports 64-bit integers and you can use MSVC style or -GCC style indicators (%I64d or %lld). It supports the C99 specifiers -for size_t and ptr_diff_t (%jd %zd) as well. -EXTRAS: -======= -Like some GCCs, for integers and floats, you can use a ' (single quote) -specifier and commas will be inserted on the thousands: "%'d" on 12345 -would print 12,345. -For integers and floats, you can use a "$" specifier and the number -will be converted to float and then divided to get kilo, mega, giga or -tera and then printed, so "%$d" 1000 is "1.0 k", "%$.2d" 2536000 is -"2.53 M", etc. For byte values, use two $:s, like "%$$d" to turn -2536000 to "2.42 Mi". If you prefer JEDEC suffixes to SI ones, use three -$:s: "%$$$d" -> "2.42 M". To remove the space between the number and the -suffix, add "_" specifier: "%_$d" -> "2.53M". -In addition to octal and hexadecimal conversions, you can print -integers in binary: "%b" for 256 would print 100. -PERFORMANCE vs MSVC 2008 32-/64-bit (GCC is even slower than MSVC): -=================================================================== -"%d" across all 32-bit ints (4.8x/4.0x faster than 32-/64-bit MSVC) -"%24d" across all 32-bit ints (4.5x/4.2x faster) -"%x" across all 32-bit ints (4.5x/3.8x faster) -"%08x" across all 32-bit ints (4.3x/3.8x faster) -"%f" across e-10 to e+10 floats (7.3x/6.0x faster) -"%e" across e-10 to e+10 floats (8.1x/6.0x faster) -"%g" across e-10 to e+10 floats (10.0x/7.1x faster) -"%f" for values near e-300 (7.9x/6.5x faster) -"%f" for values near e+300 (10.0x/9.1x faster) -"%e" for values near e-300 (10.1x/7.0x faster) -"%e" for values near e+300 (9.2x/6.0x faster) -"%.320f" for values near e-300 (12.6x/11.2x faster) -"%a" for random values (8.6x/4.3x faster) -"%I64d" for 64-bits with 32-bit values (4.8x/3.4x faster) -"%I64d" for 64-bits > 32-bit values (4.9x/5.5x faster) -"%s%s%s" for 64 char strings (7.1x/7.3x faster) -"...512 char string..." ( 35.0x/32.5x faster!) -*/ - -#if defined(__has_feature) - #if __has_feature(address_sanitizer) - #define STBI__ASAN __attribute__((no_sanitize("address"))) - #endif -#endif -#ifndef STBI__ASAN -#define STBI__ASAN -#endif - -#ifdef STB_SPRINTF_STATIC -#define STBSP__PUBLICDEC static -#define STBSP__PUBLICDEF static STBI__ASAN -#else -#ifdef __cplusplus -#define STBSP__PUBLICDEC extern "C" -#define STBSP__PUBLICDEF extern "C" STBI__ASAN -#else -#define STBSP__PUBLICDEC extern -#define STBSP__PUBLICDEF STBI__ASAN -#endif -#endif - -#include // for va_list() - -#ifndef STB_SPRINTF_MIN -#define STB_SPRINTF_MIN 512 // how many characters per callback -#endif -typedef char *STBSP_SPRINTFCB(char *buf, void *user, int len); - -#ifndef STB_SPRINTF_DECORATE -#define STB_SPRINTF_DECORATE(name) stbsp_##name // define this before including if you want to change the names -#endif - -// Convert a va_list arg list into a buffer. vsnprintf always returns a zero-terminated string (unlike regular snprintf). -// return: The number of characters copied into the buffer -STBSP__PUBLICDEF int STB_SPRINTF_DECORATE(vsprintf)(char *buf, char const *fmt, va_list va); -STBSP__PUBLICDEF int STB_SPRINTF_DECORATE(vsnprintf)(char *buf, int count, char const *fmt, va_list va); - -// Write format string to buffer. It always writes the whole string and appends a null. -// return: The number of characters copied into the buffer not including the null terminator. -STBSP__PUBLICDEF int STB_SPRINTF_DECORATE(sprintf)(char *buf, char const *fmt, ...); -STBSP__PUBLICDEF int STB_SPRINTF_DECORATE(snprintf)(char *buf, int count, char const *fmt, ...); - -// snprintf() always returns a zero-terminated string (unlike regular snprintf). -// Convert into a buffer, calling back every STB_SPRINTF_MIN chars. -// Your callback can then copy the chars out, print them or whatever. -// This function is actually the workhorse for everything else. -// The buffer you pass in must hold at least STB_SPRINTF_MIN characters. -// You return the next buffer to use or 0 to stop converting -STBSP__PUBLICDEF int STB_SPRINTF_DECORATE(vsprintfcb)(STBSP_SPRINTFCB *callback, void *user, char *buf, char const *fmt, va_list va); - -// Set the comma and period characters to use. -STBSP__PUBLICDEF void STB_SPRINTF_DECORATE(set_separators)(char comma, char period); -#endif // STB_SPRINTF_H_INCLUDE - -// #DqnDefer -// ================================================================================================= -template -struct DqnDefer_ -{ - DqnDefer_(Proc p) : proc(p) { } - ~DqnDefer_() { proc(); } - Proc proc; -}; - -struct DqnDeferHelper_ -{ - template - DqnDefer_ operator+(Proc proc) { return DqnDefer_(proc); }; -}; - -#define DQN_DEFER const auto DQN_UNIQUE_NAME(dqn_defer_lambda_) = DqnDeferHelper_() + [&]() - -// #DqnAssert API -// ================================================================================================= -// NOTE: "## __VA_ARGS__" is a GCC hack. Zero variadic arguments won't compile -// because there will be a trailing ',' at the end. Pasting it swallows it. MSVC -// implicitly swallows the trailing comma. - -// Always assert are enabled in release mode. -#define DQN_ALWAYS_ASSERT(expr) DQN_ASSERT_MSG(expr, "") -#define DQN_ALWAYS_ASSERTM(expr, msg, ...) DQN_ASSERT_MSG(expr, msg, ## __VA_ARGS__) - -// Generate a DqnLogger::Context structure -#define DQN_LOGGER_MAKE_CONTEXT_ \ - { \ - (char *)__FILE__, DQN_CHAR_COUNT(__FILE__), (char *)__func__, DQN_CHAR_COUNT(__func__), __LINE__ \ - } - -#define DQN_ASSERT(expr) DQN_ASSERT_MSG(expr, "asserted.") -#define DQN_ASSERT_MSG(expr, msg, ...) \ - do \ - { \ - if (!(expr)) \ - { \ - dqn_lib_context_.logger->Log(DqnLogger::Type::Error, DQN_LOGGER_MAKE_CONTEXT_, "[" #expr "] " msg, ##__VA_ARGS__); \ - (*((int *)0)) = 0; \ - } \ - } while (0) - -// Assert at compile time by making a type that is invalid depending on the expression result -#define DQN_COMPILE_ASSERT(expr) DQN_COMPILE_ASSERT_INTERNAL(expr, DQN_UNIQUE_NAME(DqnCompileAssertInternal_)) -#define DQN_COMPILE_ASSERT_INTERNAL(expr, name) typedef char name[((int)(expr)) * 2 - 1]; - -struct DqnLibContext -{ - struct DqnAllocator *xallocator; - struct DqnAllocator *allocator; - struct DqnLogger *logger; -}; -extern DqnLibContext dqn_lib_context_; - -DQN_COMPILE_ASSERT(sizeof(isize) == sizeof(usize)); - -// #DqnAllocator -// ================================================================================================= -// A generic structure for managing memory allocations for different Dqn data structures. -struct DqnAllocator -{ - enum struct Type - { - Default, // Malloc, realloc, free - XAllocator, // Malloc, realloc, free, crash on failure - VirtualMemory, // VirtualAlloc, VirtualFree, mmap, munmap - DqnMemStack, - }; - - Type type; - void *user_context; - - DqnAllocator() = default; - DqnAllocator(Type type_) { *this = {}; type = type_; } - DqnAllocator(struct DqnMemStack *mem_stack) { *this = {}; type = Type::DqnMemStack; user_context = mem_stack; } - - void *Malloc (size_t size, Dqn::ZeroMem zero = Dqn::ZeroMem::No); - void *Realloc(void *ptr, size_t new_size); - void Free (void *ptr, size_t old_size); -}; - -// #DqnSlice/#DqnBuffer -// ================================================================================================= -// NOTE: A slice and buffer is the same thing but, slices have the pre-existing concepts of being a -// a ptr and length into pre-existing allocated memory. So instead, I use buffer to indicate the -// data structure it self owns the memory it's holding. -template -struct DqnSlice -{ - union { T *data; T *str; }; - int len; - - inline int SizeInBytes() const { return len * sizeof(T); } - operator bool() const { bool result = (str != nullptr); return result; } - DqnSlice() = default; - DqnSlice(T *data_, int len_) : data(data_), len(len_) {} -}; - -template -using DqnBuffer = DqnSlice; - -#define DQN_BUFFER_STR_LIT(literal) DqnBuffer(literal, DQN_CHAR_COUNT(literal)) -#define DQN_BUFFER_STRCMP(a, b, ignore_case) ((a).len == (b).len && (DqnStr_Cmp((char *)((a).str), (char *)((b).str), (a).len, ignore_case) == 0)) -#define DQN_BUFFER_MEMCMP(a, b) ((a).len == (b).len && (DqnMem_Cmp((void *)((a).str), (void *)((b).str), (a).len) == 0)) - -#define DQN_SLICE_STRCMP(a, b, ignore_case) ((a).len == (b).len && (DqnStr_Cmp((char *)((a).str), (char *)((b).str), (a).len, ignore_case) == 0)) -#define DQN_SLICE_MEMCMP(a, b) ((a).len == (b).len && (DqnMem_Cmp((void *)((a).str), (void *)((b).str), (a).len) == 0)) - -template -DQN_FILE_SCOPE DqnBuffer DqnBuffer_Make(DqnAllocator *allocator, int num, Dqn::ZeroMem clear = Dqn::ZeroMem::Yes) -{ - DqnBuffer result = {}; - result.len = num; - result.data = static_cast(allocator->Malloc(num * sizeof(T), clear)); - return result; -} - -template -DQN_FILE_SCOPE DqnBuffer DqnBuffer_Copy(DqnAllocator *allocator, T const *data, int len) -{ - DqnBuffer result; - result.len = len; - result.data = static_cast(allocator->Malloc(len * sizeof(T), Dqn::ZeroMem::No)); - DqnMem_Copy(result.data, data, len * sizeof(T)); - return result; -} - -template -DQN_FILE_SCOPE DqnBuffer DqnBuffer_CopyAndNullTerminate(DqnAllocator *allocator, T const *data, int len) -{ - DqnBuffer result; - result.len = len; - result.data = static_cast(allocator->Malloc((len + 1) * sizeof(T), Dqn::ZeroMem::No)); - DqnMem_Copy(result.data, data, len * sizeof(T)); - result.data[len] = 0; - return result; -} - -// #DqnFixedString Public API - Fixed sized strings at compile time -// ================================================================================================= -template -struct DqnFixedString -{ - int len; - char str[MAX]; - - DqnFixedString(): len(0) { this->str[0] = 0; } - DqnFixedString(char const *fmt, ...) { va_list va; va_start(va, fmt); len = stbsp_vsnprintf(str, MAX, fmt, va); va_end(va); DQN_ASSERT(len < MAX); } - DqnFixedString(char const *fmt, va_list va) { len = stbsp_vsnprintf(str, MAX, fmt, va); DQN_ASSERT(len < MAX); } - DqnFixedString(DqnSlice const &other) { DqnMem_Copy(str, other.str, other.len); len = other.len; str[len] = 0; } - DqnFixedString(DqnSlice const &other) { DqnMem_Copy(str, other.str, other.len); len = other.len; str[len] = 0; } - DqnFixedString(DqnFixedString const &other) { if (this != &other) { DqnMem_Copy(str, other.str, other.len); len = other.len; str[len] = 0; } } - - DqnFixedString &operator+=(char const *other) { int other_len = Dqn_StrLen(other); DqnMem_Copy(str + len, other, other_len); len += other_len; str[len] = 0; DQN_ASSERT(len < MAX); return *this; } - DqnFixedString &operator+=(DqnSlice const &other) { DqnMem_Copy(str + len, other.str, other.len); len += other.len; str[len] = 0; DQN_ASSERT(len < MAX); return *this; } - DqnFixedString &operator+=(DqnSlice const &other) { DqnMem_Copy(str + len, other.str, other.len); len += other.len; str[len] = 0; DQN_ASSERT(len < MAX); return *this; } - DqnFixedString &operator+=(DqnFixedString const &other) { DqnMem_Copy(str + len, other.str, other.len); len += other.len; str[len] = 0; DQN_ASSERT(len < MAX); return *this; } - - DqnFixedString operator+ (char const *other) { auto result = *this; int other_len = Dqn_StrLen(other); DqnMem_Copy(str + len, other, other_len); len += other_len; str[len] = 0; DQN_ASSERT(len < MAX); return result; } - DqnFixedString operator+ (DqnSlice const &other) { auto result = *this; DqnMem_Copy(str + len, other.str, other.len); len += other.len; str[len] = 0; DQN_ASSERT(len < MAX); return result; } - DqnFixedString operator+ (DqnSlice const &other) { auto result = *this; DqnMem_Copy(str + len, other.str, other.len); len += other.len; str[len] = 0; DQN_ASSERT(len < MAX); return result; } - DqnFixedString operator+ (DqnFixedString const &other) { auto result = *this; DqnMem_Copy(str + len, other.str, other.len); len += other.len; str[len] = 0; DQN_ASSERT(len < MAX); return result; } - - // Xprintf functions always modifies buffer and null-terminates even with insufficient buffer size. - // Asserts on failure if DQN_ASSERT is defined. - // return: The number of characters copied to the buffer - int SprintfAppend (char const *fmt, ...) { va_list va; va_start(va, fmt); int extra = stbsp_sprintf (str + len, MAX, fmt, va); len += extra; DQN_ASSERT(len < MAX); va_end(va); return extra; } - int VSprintfAppend(char const *fmt, va_list va) { int extra = stbsp_vsnprintf(str + len, MAX, fmt, va); len += extra; DQN_ASSERT(len < MAX); return extra; } - void NullTerminate () { str[len] = 0; } // NOTE: If you modify the storage directly, this can be handy. - void Clear (Dqn::ZeroMem clear = Dqn::ZeroMem::No) { if (clear == Dqn::ZeroMem::Yes) DqnMem_Set(str, 0, MAX); *this = {}; } -}; - -using DqnFixedString16 = DqnFixedString<16>; -using DqnFixedString32 = DqnFixedString<32>; -using DqnFixedString64 = DqnFixedString<64>; -using DqnFixedString128 = DqnFixedString<128>; -using DqnFixedString256 = DqnFixedString<256>; -using DqnFixedString512 = DqnFixedString<512>; -using DqnFixedString1024 = DqnFixedString<1024>; -using DqnFixedString2048 = DqnFixedString<2048>; - -// #DqnMem -// ================================================================================================= -// TODO(doyle): Use platform allocation, fallback to malloc if platform not defined -DQN_FILE_SCOPE void *DqnMem_Alloc (usize size); -DQN_FILE_SCOPE void *DqnMem_XAlloc (usize size); -DQN_FILE_SCOPE void *DqnMem_XCalloc (usize size); -DQN_FILE_SCOPE void DqnMem_Clear (void *memory, u8 clear_val, usize size); -DQN_FILE_SCOPE void *DqnMem_Realloc (void *memory, usize new_size); -DQN_FILE_SCOPE void *DqnMem_XRealloc(void *memory, usize new_size); -DQN_FILE_SCOPE void DqnMem_Free (void *memory); -DQN_FILE_SCOPE void DqnMem_Copy (void *dest, void const *src, usize num_bytes_to_copy); -DQN_FILE_SCOPE void *DqnMem_Set (void *dest, u8 value, usize num_bytes_to_set); -DQN_FILE_SCOPE int DqnMem_Cmp (void const *src, void const *dest, usize num_bytes); - -// #DqnMemTracker -// ================================================================================================= -// Allocation Layout -// +--------------------+-------------------------------------------------------------------------+------------------------+-----------------+ -// | Ptr From Allocator | Offset To Src | Alignment | Alloc Type | Alloc Amount | B. Guard (Opt.) | Aligned Ptr For Client | B. Guard (Opt.) | -// +--------------------+-------------------------------------------------------------------------+------------------------+-----------------+ -// Ptr From Allocator: The pointer returned by the allocator, not aligned -// Offset To Src: Number of bytes to subtract from the "Aligned Ptr For Client" to return to the "Ptr From Allocator" -// Alignment: The pointer given to the client is aligned to this power of two boundary -// Alloc Type: If the allocation was allocated from the head or tail of the memory block (mainly for memstacks). -// Alloc Amount: The requested allocation amount by the client (so does not include metadata) -// B. Guard: Bounds Guard value. -// Aligned Ptr For Client: The allocated memory for the client. - -#pragma pack(push, 1) -struct DqnPtrHeader -{ - u8 offset_to_src_ptr; // Offset to subtract from the client ptr to receive the allocation ptr - u8 alignment; - u8 alloc_type; // TODO(doyle): alloc_type is a memstack specific thing - usize alloc_amount; -}; -#pragma pack(pop) - -struct DqnMemTracker -{ - enum Flag - { - None = 0, - TrackPtr = (1 << 0), - BoundsGuard = (1 << 1), - TagAllocation = (1 << 2), - Simple = (TrackPtr | BoundsGuard), - All = (TrackPtr | BoundsGuard | TagAllocation), - }; - - struct TaggedAllocation - { - DqnBuffer filename; - DqnBuffer function; - size_t line_num; - isize bytes_allocated; - TaggedAllocation *next; - }; - - static u32 const HEAD_GUARD_VALUE = 0xCAFEBABE; - static u32 const TAIL_GUARD_VALUE = 0xDEADBEEF; - - void **ptrs; // If track_ptr was set, ptrs is an array to all the pointers that get passed through SetupPtr, otherwise null - int ptrs_len; - int ptrs_max; - u32 bounds_guard_size; // If bounds_guard was set, sizeof(GUARD_VALUE) otherwise 0 - - u16 tagged_allocs_max; - TaggedAllocation **tagged_allocs; - u16 *tagged_allocs_used_list; - u16 tagged_allocs_used_index; - - void Init (Flag flag); - void Free (); - bool IsTrackingPtrs () const { return (ptrs != nullptr); } - bool IsGuardingBounds () const { return (bounds_guard_size > 0); } - bool IsTaggingAllocations() const { return (tagged_allocs_used_index > 0); } // TODO(doyle): Just store the flags instead of these unreasonable checks - -#define DQN_STRINGIFY(val) DQN_STRINGIFY2(val) -#define DQN_STRINGIFY2(val) #val -#define DQN_MEMTRACKER_TAG_ALLOC(tracker, size) (tracker)->Tag_(DQN_BUFFER_STR_LIT(__FILE__), DQN_BUFFER_STR_LIT(__func__), __LINE__, DQN_BUFFER_STR_LIT(__FILE__ DQN_STRINGIFY(__LINE__)), (isize)size) - void Tag_(DqnBuffer filename, DqnBuffer function, int line_num, DqnBuffer filename_line_num_data, isize bytes); - - // MemTracker setups up the ptr by adding a DqnPtrHeader to each given ptr. When the client - // requests an allocation, use GetAllocationSize() to get the adjusted size necessary for adding - // the tracking metadata, then pass in the allocated ptr into SetupPtr. - - // If MemTracker was init with - // - track_ptr: it also tracks each ptr passed in - // - bounds_guard: it also adds a 4 byte magic value on both sides of the ptr - // size: The original size requested, i.e. before GetAllocationSize adjusted it - void *SetupPtr (void *ptr, isize size, u8 alignment); - - void RemovePtr (void *ptr); - void RemovePtrRange (void *begin, void *end); - void CheckPtrs () const; - usize GetAllocationSize (usize size, u8 alignment = 1) const { return sizeof(DqnPtrHeader) + bounds_guard_size + (alignment - 1) + size + bounds_guard_size; } - - // ptr: The ptr given to the client when allocating. - u32 *PtrToHeadGuard (char *ptr) const { return reinterpret_cast(ptr - bounds_guard_size); } - u32 *PtrToTailGuard (char *ptr) const { return reinterpret_cast(ptr + PtrToHeader(ptr)->alloc_amount); } - DqnPtrHeader *PtrToHeader (char *ptr) const { return reinterpret_cast(ptr - bounds_guard_size - sizeof(DqnPtrHeader)); } -}; - -// #DqnMemStack -// ================================================================================================= -// DqnMemStack is a memory allocator in a stack like, push-pop style. It -// pre-allocates a block of memory at init and sub-allocates from this block to -// take advantage of memory locality. You can allocate and grow the stack from -// the bottom and/or allocate from the top and grow downwards until space is -// insufficient in the memory block. - -// When an allocation requires a larger amount of memory than available in the -// block then the MemStack will allocate a new block of sufficient size for you -// in Push(..). This DOES mean that occasionally there will be wasted space at -// the end of each block and is a tradeoff for memory locality against optimal -// space usage. - -// My convention with using a memory stack is, any function that takes a memory -// stack must revert all allocations from the the end of the stack in the scope -// it was used in. If the function takes an allocator, then it must always do -// some operation that allocates persistent data into the head of the allocator. - -// If a function requires an allocator purely for temporary purposes, then there -// always exists some non-user facing global allocator that is accessible which -// it can use. - -#define DQN_MEMSTACK_PUSH(stack, size) DQN_MEMSTACK_PUSH_ARRAY(stack, char, size) -#define DQN_MEMSTACK_PUSH_STRUCT(stack, Type) DQN_MEMSTACK_PUSH_ARRAY(stack, Type, 1) -#define DQN_MEMSTACK_PUSH_ARRAY(stack, Type, num) (Type *)(stack)->Push_(sizeof(Type) * (num)); DQN_MEMTRACKER_TAG_ALLOC(&(stack)->tracker, sizeof(Type) * num) - -#define DQN_MEMSTACK_PUSH_BACK(stack, size) DQN_MEMSTACK_PUSH_BACK_ARRAY(stack, char, size) -#define DQN_MEMSTACK_PUSH_BACK_STRUCT(stack, Type) DQN_MEMSTACK_PUSH_BACK_ARRAY(stack, Type, 1) -#define DQN_MEMSTACK_PUSH_BACK_ARRAY(stack, Type, num) (Type *)(stack)->Push_(sizeof(Type) * (num), DqnMemStack::PushType::Opposite); DQN_MEMTRACKER_TAG_ALLOC(&(stack)->tracker, sizeof(Type) * num) - -struct DqnMemStack -{ - static const i32 MINIMUM_BLOCK_SIZE = DQN_KILOBYTE(64); - - enum Flag - { - NonExpandable = (1 << 0), // Disallow additional memory blocks when full. - NonExpandableAssert = (1 << 1), // Assert when non-expandable is set and we run out of space - DefaultAllocateTail = (1 << 2), // Allocate to tail when push_type is unspecified, otherwise allocate to head - }; - - struct Info // Statistics of the memory stack. - { - isize total_used; - isize total_size; - isize wasted_size; - i32 num_blocks; - }; - - struct Block - { - char *memory; - isize size; - char *head; - char *tail; - Block *prev_block; - - Block() = default; - Block(void *memory_, isize size_) { *this = {}; memory = (char *)memory_; size = size_; head = memory; tail = memory + size; } - isize Usage() const { return size - (tail - head); } - }; - - DqnMemTracker tracker; // Metadata for managing ptr allocation - DqnAllocator *block_allocator; // Memory block allocator - Block *block; // Backing memory storage - u32 flags; - i32 mem_region_count; // The number of memory regions in use - - // Initialisation - // ============================================================================================= - DqnMemStack() = default; // Zero Is Initialisation, on first allocation LazyInit() is called. - DqnMemStack(void *mem, isize size, Dqn::ZeroMem clear, u32 flags_ = 0, DqnMemTracker::Flag flags = DqnMemTracker::Flag::Simple); // Use fixed memory from the given buffer. Assert after buffer is full. - - // Init and alloc additional memory blocks when full, but only if NonExpandable flag is not set. - DqnMemStack (isize size, Dqn::ZeroMem clear, u32 flags_ = 0, DqnMemTracker::Flag tracker_flags = DqnMemTracker::Simple, DqnAllocator *block_allocator_ = dqn_lib_context_.allocator) { LazyInit(size, clear, flags_, tracker_flags, block_allocator_); } - void LazyInit(isize size, Dqn::ZeroMem clear, u32 flags_ = 0, DqnMemTracker::Flag tracker_flags = DqnMemTracker::Simple, DqnAllocator *block_allocator_ = dqn_lib_context_.allocator); - - // Allocation - // ============================================================================================= - enum struct AllocMode - { - Head, // Set the default to allocating to the start of the memory block - Tail, // Set the default to allocating from the end of the memory block - }; - - enum struct PushType - { - Default, // Allocation defaults to the AllocMode set in SetAllocMode(), by default this is initialised to be from the start of the memory stack. - Opposite, // Opposite is always the opposite side of the current default allocation mode. - - // TODO(doyle): Head and Tail are possibly redundant modes now. When the - // client changes the default allocation mode outside of functions that - // take a memory stack as an allocator, it means if the function wants - // to use the "temporary" side of the memory stack, they need to be - // aware of what the opposite side of the memory stack is as to not - // trample over the memory that the client wants allocated memory from. - - // This is what the 2 new PushType options above facilitate. I can't - // immediately see a situation now where you want to actually specify - // the side and override the allocation mode which could make for - // unintuitive behaviour, but I'm going to sit on this for awhile and - // see how the actual real world use cases pan out. - - Head, // Ignores the AllocMode, always allocate from the start of the memory block - Tail, // Ignores the AllocMode, always allocate from the end of the memory block - }; - - // NOTE: Prefer the macro to enable allocation tagging if defined. - // Allocate memory from the MemStack. - // alignment: Must be a power of 2, ptr returned from allocator is address aligned to this value. - // return: Ptr to memory, nullptr if out of space and is disallowed to expand OR the stack is full and malloc fails - void *Push_ (usize size, PushType push_type = PushType::Default, u8 alignment = 4); - - // On Push, if push_type is PushType::Default, it will behave according to the AllocMode last set. - void SetAllocMode (AllocMode mode) { if (mode == AllocMode::Head) flags &= ~Flag::DefaultAllocateTail; else flags |= Flag::DefaultAllocateTail; } - - // TODO(doyle): Edge case where Pop fails. If you Push to the head and it - // fits in the existing block. Then push to the tail a size larger than the - // remaining space and generate a new block, then, if you try to Pop the ptr - // from the head, it will not find the right block to pop from and assert. - 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 () { tracker.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 - // ============================================================================================= - // Revert all allocations between the Begin() and End() regions. Scope version is RAII'ed. - struct MemRegion - { - DqnMemStack *stack; // Stack associated with this MemRegion - Block *starting_block; // The block to revert back to - char *starting_block_head; - char *starting_block_tail; - }; - - struct MemRegionScoped - { - MemRegionScoped(DqnMemStack *stack) { region = stack->MemRegionBegin(); } - ~MemRegionScoped() { if (region.stack) region.stack->MemRegionEnd(region); } - MemRegion region; - }; - - 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 MemRegionSave (MemRegion *region); - void MemRegionSave (MemRegionScoped *scope) { MemRegionSave(&scope->region); } -}; - -// #DqnLogger Public -// ================================================================================================= -struct DqnLogger -{ -#define LOG_TYPES \ - X(Warning, "WRN") \ - X(Error, "ERR") \ - X(Debug, "DBG") \ - X(Memory, "MEM") \ - X(Message, "MSG") - -#define X(type, prefix) type, - enum struct Type { LOG_TYPES }; -#undef X - -#define X(type, prefix) prefix, - static char const *TypePrefix(Type type) - { - LOCAL_PERSIST char const *type_string[] = {LOG_TYPES}; - return type_string[static_cast(type)]; - } -#undef X -#undef LOG_TYPES - - struct Context - { - char *filename; - int filename_len; - char *function; - int function_len; - int line_num; - }; - - #define DQN_LOGGER(logger, type, fmt, ...) (logger)->Log(type, DQN_LOGGER_MAKE_CONTEXT_, fmt, ## __VA_ARGS__) - #define DQN_LOGGER_E(logger, fmt, ...) (logger)->Log(DqnLogger::Type::Error, DQN_LOGGER_MAKE_CONTEXT_, fmt, ## __VA_ARGS__) - #define DQN_LOGGER_W(logger, fmt, ...) (logger)->Log(DqnLogger::Type::Warning, DQN_LOGGER_MAKE_CONTEXT_, fmt, ## __VA_ARGS__) - #define DQN_LOGGER_D(logger, fmt, ...) (logger)->Log(DqnLogger::Type::Debug, DQN_LOGGER_MAKE_CONTEXT_, fmt, ## __VA_ARGS__) - #define DQN_LOGGER_M(logger, fmt, ...) (logger)->Log(DqnLogger::Type::Message, DQN_LOGGER_MAKE_CONTEXT_, fmt, ## __VA_ARGS__) - - DqnMemStack allocator; - DqnFixedString1024 log_builder; - DqnBuffer log_buf; - int log_buf_index; - - // TODO(doyle): Switch to bit flags - b32 no_console; // Log to console if false. - b32 no_print_error; - b32 no_print_debug; - b32 no_print_warning; - - // Build up a log line that gets prepended to the next log. When Log() is called and is then reset. - // - void PrependToLog(char const *fmt, ...) { va_list va; va_start (va, fmt); log_builder.VSprintfAppend(fmt, va); va_end(va); } - - // return: A static string whose lifetime persists until the next log call. - char const *LogNoContext(Type type, char const *fmt, ...); - char const *Log (Type type, Context log_context, char const *fmt, ...); - char const *LogVA (Type type, Context log_context, char const *fmt, va_list va); -}; - -// #DqnArray -// ================================================================================================= -template -struct DqnArray -{ - DqnAllocator *allocator = dqn_lib_context_.allocator; - isize len; - isize max; - T *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 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, sizeof(*data) * max); } *this = {}; } - T *Front () { DQN_ASSERT_MSG(len > 0, "len: %zu", len); return data + 0; } - T *Back () { DQN_ASSERT_MSG(len > 0, "len: %zu", len); 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 *Add (T const &v) { if (len + 1 > max) Reserve(GrowCapacity_(len + 1)); data[len++] = v; return data + (len-1); } - T *Add (T const *v, isize v_len) { isize new_len = len + v_len; if (new_len > max) Reserve(GrowCapacity_(new_len)); T *result = data + len; for (isize i = 0; i < v_len; ++i) data[len++] = v[i]; return result; } - void Pop () { if (len > 0) len--; } - void Erase (isize index) { DQN_ASSERT_MSG(index >= 0 && index < len, "index: %zu, len: %zu", index, len); data[index] = data[--len]; } - void EraseStable(isize index); - T *Insert (isize index, T const *v) { return Insert(index, v, 1); } - T *Insert (isize index, T const &v) { return Insert(index, &v, 1); } - T *Insert (isize index, T const *v, isize len_items); - bool Contains (T const *v) const { T const *ptr = data; T const *end = data + len; while (ptr < end) if (*ptr++ == *v) return true; return false; } - - T &operator[] (isize i) const { DQN_ASSERT_MSG(i >= 0 && i < len, "i: %zu, len: %zu", i, len); return this->data[i]; } - T *begin () { return data; } - T *begin () const { return data; } - T *end () { return data + len; } - T *end () const { return data + len; } - -private: - isize GrowCapacity_(isize size) const { isize new_max = max ? (max * 2) : 8; return new_max > size ? new_max : size; } -}; - -template T *DqnArray::Insert(isize index, T const *v, isize len_items) -{ - index = DQN_MIN(DQN_MAX(index, 0), len); - isize const new_len = len + len_items; - - if (new_len >= max) - Reserve(GrowCapacity_(new_len)); - - T *src = data + index; - T *dest = src + len_items; - - if (src < dest) - memmove(dest, src, ((data + len) - src) * sizeof(T)); - - len = new_len; - for (isize i = 0; i < len_items; i++) - src[i] = v[i]; - - return src; -} - -template void DqnArray::EraseStable(isize index) -{ - DQN_ASSERT(index >= 0 && index < len); - isize const off = (data + index) - data; - memmove(data + off, data + off + 1, ((usize)len - (usize)off - 1) * sizeof(T)); - len--; -} - -template void DqnArray::Reserve(isize new_max) -{ - if (new_max <= max) return; - - if (data) - { - T *newData = (T *)allocator->Realloc(data, new_max * sizeof(T)); - data = newData; - max = new_max; - } - else - { - data = (T *)allocator->Malloc(new_max * sizeof(T)); - max = new_max; - } - - DQN_ASSERT(data); -} - -// #DqnChar -// ================================================================================================= -DQN_FILE_SCOPE char DqnChar_ToLower (char c); -DQN_FILE_SCOPE char DqnChar_ToUpper (char c); -DQN_FILE_SCOPE bool DqnChar_IsDigit (char c); -DQN_FILE_SCOPE bool DqnChar_IsAlpha (char c); -DQN_FILE_SCOPE bool DqnChar_IsAlphaNum (char c); -DQN_FILE_SCOPE bool DqnChar_IsEndOfLine (char c); -DQN_FILE_SCOPE bool DqnChar_IsWhitespace(char c); - -DQN_FILE_SCOPE char *DqnChar_TrimWhitespaceAround(char const *src, i32 src_len, i32 *new_len); -DQN_FILE_SCOPE char *DqnChar_SkipWhitespace (char const *ptr); - -// TODO(doyle): this is NOT UTF8 safe -// ch: Char to find -// len: The length of the string stored in ptr, (doesn't care if it includes null terminator) -// len_to_char: The length to the char from end of the ptr, i.e. (ptr + len) -// return: The ptr to the last char, null if it could not find. -DQN_FILE_SCOPE char *DqnChar_FindLastChar (char *ptr, char ch, i32 len, u32 *len_to_char); - -// #DqnStr -// ================================================================================================= -// num_bytes_to_cmp: If -1, cmp runs until \0 is encountered. -// return: 0 if equal. 0 < if a is before b, > 0 if a is after b -DQN_FILE_SCOPE i32 DqnStr_Cmp (char const *a, char const *b, i32 num_bytes_to_cmp = -1, Dqn::IgnoreCase ignore = Dqn::IgnoreCase::No); - -// str_len: Len of string, if -1, StrLen is used. -// return: Pointer in str to the last slash, if none then the original string. -DQN_FILE_SCOPE char *DqnStr_GetPtrToLastSlash (char const *str, i32 str_len = -1); - -// return: String length not including the nullptr terminator. 0 if invalid args. -DQN_FILE_SCOPE i32 DqnStr_Len (char const *a); -DQN_FILE_SCOPE i32 DqnStr_LenUTF8 (u32 const *a, i32 *len_in_bytes = nullptr); - -// return: String length starting from a, up to and not including the first delimiter character. -DQN_FILE_SCOPE i32 DqnStr_LenDelimitWith (char const *a, char delimiter); - -// return: The dest argument, nullptr if args invalid (i.e. nullptr pointers or numChars < 0) -DQN_FILE_SCOPE void DqnStr_Reverse (char *buf, isize buf_size); - -// return: Number of bytes in codepoint, 0 if *a becomes invalid or end of stream. -DQN_FILE_SCOPE i32 DqnStr_ReadUTF8Codepoint (u32 const *a, u32 *out_codepoint); - -// return: The offset into the src to first char of the found string. Returns -1 if not found -DQN_FILE_SCOPE i32 DqnStr_FindFirstOccurence (char const *src, i32 src_len, char const *find, i32 find_len, Dqn::IgnoreCase ignore = Dqn::IgnoreCase::No); -DQN_FILE_SCOPE bool DqnStr_EndsWith (char const *src, i32 src_len, char const *find, i32 find_len, Dqn::IgnoreCase ignore = Dqn::IgnoreCase::No); - -// return: Helper function that returns the pointer to the first occurence, nullptr if not found. -DQN_FILE_SCOPE char *DqnStr_GetFirstOccurence (char const *src, i32 src_len, char const *find, i32 find_len, Dqn::IgnoreCase ignore = Dqn::IgnoreCase::No); -DQN_FILE_SCOPE bool DqnStr_HasSubstring (char const *src, i32 src_len, char const *find, i32 find_len, Dqn::IgnoreCase ignore = Dqn::IgnoreCase::No); - -DQN_FILE_SCOPE DqnSlice DqnStr_RemoveLeadTrailChar (char const *str, i32 str_len, char lead_char, char trail_char); -DQN_FILE_SCOPE inline DqnSlice DqnStr_RemoveLeadTrailQuotes (DqnSlice slice); -DQN_FILE_SCOPE inline DqnSlice DqnStr_RemoveLeadTrailBraces (DqnSlice slice); -DQN_FILE_SCOPE inline DqnSlice DqnStr_RemoveLeadTrailQuotes (char const *str, i32 str_len); -DQN_FILE_SCOPE inline DqnSlice DqnStr_RemoveLeadTrailBraces (char const *str, i32 str_len); - -// #DqnWChar -// ================================================================================================= -// NOTE: See above for documentation -DQN_FILE_SCOPE bool DqnWChar_IsDigit (wchar_t c); -DQN_FILE_SCOPE wchar_t DqnWChar_ToLower (wchar_t c); - -DQN_FILE_SCOPE wchar_t *DqnWChar_SkipWhitespace (wchar_t *ptr); -DQN_FILE_SCOPE wchar_t *DqnWChar_FindLastChar (wchar_t *ptr, wchar_t ch, i32 len, u32 *len_to_char); -DQN_FILE_SCOPE i32 DqnWChar_GetNextLine (wchar_t *ptr, i32 *line_len); - -// #DqnWStr -// ================================================================================================= -DQN_FILE_SCOPE i32 DqnWStr_Cmp (wchar_t const *a, wchar_t const *b); -DQN_FILE_SCOPE i32 DqnWStr_FindFirstOccurence(wchar_t const *src, i32 src_len, wchar_t const *find, i32 find_len); -DQN_FILE_SCOPE bool DqnWStr_HasSubstring (wchar_t const *src, i32 src_len, wchar_t const *find, i32 find_len); -DQN_FILE_SCOPE i32 DqnWStr_Len (wchar_t const *a); -DQN_FILE_SCOPE i32 DqnWStr_LenDelimitWith (wchar_t const *a, wchar_t delimiter); -DQN_FILE_SCOPE void DqnWStr_Reverse (wchar_t *buf, i32 buf_size); - -// #DqnString -// ================================================================================================= -struct DqnString -{ - DqnAllocator *allocator = dqn_lib_context_.allocator; - int len = 0; - int max = 0; - char *str = nullptr; - - DqnString() = default; - DqnString(char *buf, int max_) : len(0), str(buf) { max = max_; NullTerminate(); } - DqnString(char const *str_) { Append(str_); } - DqnString(char const *str_, int len_) { Append(str_, len_); } - DqnString(DqnSlice const &other) { Append(other.data, other.len); } - DqnString(DqnSlice const &other) { Append(other.data, other.len); } - DqnString(DqnString const &other) { if (this == &other) return; *this = other; } // TODO(doyle): I can't decide on copy semantics - - DqnString &operator+=(char const *other) { Append(other); return *this; } - DqnString &operator+=(DqnSlice const &other) { Append(other.data, other.len); return *this; } - DqnString &operator+=(DqnSlice const &other) { Append(other.data, other.len); return *this; } - DqnString &operator+=(DqnString const &other) { Append(other.str, other.len); return *this; } - - DqnString operator+ (char const *other) { auto result = *this; result.Append(other); return result; } - DqnString operator+ (DqnSlice const &other) { auto result = *this; result.Append(other.data, other.len); return result; } - DqnString operator+ (DqnSlice const &other) { auto result = *this; result.Append(other.data, other.len); return result; } - DqnString operator+ (DqnString const &other) { auto result = *this; result.Append(other.str, other.len); return result; } - - // Xprintf functions always modifies buffer and null-terminates even with insufficient buffer size. - // return: The number of characters copied to the buffer - int Sprintf (char const *fmt, ...) { va_list va; va_start(va, fmt); int result = VSprintf (fmt, va); va_end(va); return result; } - int SprintfAppend (char const *fmt, ...) { va_list va; va_start(va, fmt); int result = VSprintfAppend(fmt, va); va_end(va); return result; } - - int VSprintf (char const *fmt, va_list va) { return VSprintfAtOffset(fmt, va, 0 /*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 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, sizeof(*str) * len); 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); - - void Append (char const *src, int len_ = -1); - int VSprintfAtOffset(char const *fmt, va_list va, int offset) { Reserve(len + stbsp_vsnprintf(nullptr, 0, fmt, va) + 1); int result = stbsp_vsnprintf(str + offset, max - len, fmt, va); len = (offset + result); return result; } - - static bool Cmp (DqnString const *a, DqnString const *b, Dqn::IgnoreCase ignore = Dqn::IgnoreCase::No) { return (a->len == b->len) && (DqnStr_Cmp(a->str, b->str, a->len, ignore) == 0); } - static bool Cmp (DqnString const *a, DqnSlice const b, Dqn::IgnoreCase ignore = Dqn::IgnoreCase::No) { return (a->len == b.len) && (DqnStr_Cmp(a->str, b.data, b.len, ignore) == 0); } - static bool Cmp (DqnString const *a, DqnSlice const b, Dqn::IgnoreCase ignore = Dqn::IgnoreCase::No) { return (a->len == b.len) && (DqnStr_Cmp(a->str, b.data, b.len, ignore) == 0); } - - // return: -1 if invalid, or if buf_size is 0 the required buffer length in wchar_t characters - i32 ToWChar(wchar_t *const buf, i32 const buf_size) const; - // return: String allocated using api. - wchar_t *ToWChar(DqnAllocator *allocator = dqn_lib_context_.allocator) const; - -}; - -// #DqnRnd -// ================================================================================================= -struct DqnRndPCG // PCG (Permuted Congruential Generator) -{ - u64 state[2]; - - DqnRndPCG(); - DqnRndPCG(u32 seed); - - u32 Next (); // return: A random number N between [0, 0xFFFFFFFF] - f32 Nextf(); // return: A random float N between [0.0, 1.0f] - i32 Range(i32 min, i32 max); // return: A random integer N between [min, max] -}; - -// #Dqn_* -// ================================================================================================= -// return: The number of splits in the array. If array is null this returns the required size of the array. -i32 Dqn_SplitString(char const *src, i32 src_len, char split_char, DqnSlice *array = nullptr, i32 size = 0); - -// Util function that uses Dqn_SplitString -// return: The number of splits, splitting by "split_char" would generate. -i32 Dqn_GetNumSplits(char const *src, i32 src_len, char split_char); - -// Skips whitespace then reads UTF8 rune upto first \r or \n and null terminates at that point. Advances input to the start of the next line. -// line_len: (Optional) Returns the length of the null terminated line returned -// return : The immediate null terminated line, nullptr if no more lines are to be read. -DQN_FILE_SCOPE char *Dqn_EatLine(char **input, int *line_len); -DQN_FILE_SCOPE wchar_t *Dqn_EatLine(wchar_t **input, int *line_len); - -DQN_FILE_SCOPE inline bool Dqn_BitIsSet (u32 bits, u32 flag); -DQN_FILE_SCOPE inline u32 Dqn_BitSet (u32 bits, u32 flag); -DQN_FILE_SCOPE inline u32 Dqn_BitUnset (u32 bits, u32 flag); -DQN_FILE_SCOPE inline u32 Dqn_BitToggle(u32 bits, u32 flag); - -template using DqnQuickSort_LessThanProc = bool (*) (T const &a, T const &b, void *user_context); -#define DQN_QUICK_SORT_LESS_THAN_PROC(name) template inline bool name(T const &a, T const &b, void *user_context) -DQN_QUICK_SORT_LESS_THAN_PROC(DqnQuickSort_DefaultLessThan) -{ - (void)user_context; - bool result = a < b; - return result; -} - -template IsLessThan = DqnQuickSort_DefaultLessThan> -DQN_FILE_SCOPE void DqnQuickSort(T *array, isize size, void *user_context) -{ - if (!array || size <= 1) return; - -#if 1 - // Insertion Sort, under 24->32 is an optimal amount - const i32 QUICK_SORT_THRESHOLD = 24; - if (size < QUICK_SORT_THRESHOLD) - { - i32 item_to_insert_index = 1; - while (item_to_insert_index < size) - { - for (i32 check_index = 0; check_index < item_to_insert_index; check_index++) - { - if (!IsLessThan(array[check_index], array[item_to_insert_index], user_context)) - { - T item_to_insert = array[item_to_insert_index]; - for (i32 i = item_to_insert_index; i > check_index; i--) - array[i] = array[i - 1]; - - array[check_index] = item_to_insert; - break; - } - } - item_to_insert_index++; - } - - return; - } -#endif - - auto state = DqnRndPCG(); - auto last_index = size - 1; - auto pivot_index = (i64)state.Range(0, (i32)last_index); - auto partition_index = 0; - auto start_index = 0; - - // Swap pivot with last index, so pivot is always at the end of the array. - // This makes logic much simpler. - DQN_SWAP(T, array[last_index], array[pivot_index]); - pivot_index = last_index; - - // 4^, 8, 7, 5, 2, 3, 6 - if (IsLessThan(array[start_index], array[pivot_index], user_context)) partition_index++; - start_index++; - - // 4, |8, 7, 5^, 2, 3, 6* - // 4, 5, |7, 8, 2^, 3, 6* - // 4, 5, 2, |8, 7, ^3, 6* - // 4, 5, 2, 3, |7, 8, ^6* - for (auto check_index = start_index; check_index < last_index; check_index++) - { - if (IsLessThan(array[check_index], array[pivot_index], user_context)) - { - DQN_SWAP(T, array[partition_index], array[check_index]); - partition_index++; - } - } - - // Move pivot to right of partition - // 4, 5, 2, 3, |6, 8, ^7* - DQN_SWAP(T, array[partition_index], array[pivot_index]); - DqnQuickSort(array, partition_index, user_context); - - // Skip the value at partion index since that is guaranteed to be sorted. - // 4, 5, 2, 3, (x), 8, 7 - i32 one_after_partition_index = partition_index + 1; - DqnQuickSort(array + one_after_partition_index, (size - one_after_partition_index), user_context); -} - -template -DQN_FILE_SCOPE void DqnQuickSort(T *array, isize size) -{ - if (!array || size <= 1) return; - -#if 1 - // Insertion Sort, under 24->32 is an optimal amount - const i32 QUICK_SORT_THRESHOLD = 24; - if (size < QUICK_SORT_THRESHOLD) - { - i32 item_to_insert_index = 1; - while (item_to_insert_index < size) - { - for (i32 check_index = 0; check_index < item_to_insert_index; check_index++) - { - if (!(array[check_index] < array[item_to_insert_index])) - { - T item_to_insert = array[item_to_insert_index]; - for (i32 i = item_to_insert_index; i > check_index; i--) - array[i] = array[i - 1]; - - array[check_index] = item_to_insert; - break; - } - } - item_to_insert_index++; - } - - return; - } -#endif - - auto state = DqnRndPCG(); - auto last_index = size - 1; - auto pivot_index = (i64)state.Range(0, (i32)last_index); - auto partition_index = 0; - auto start_index = 0; - - // Swap pivot with last index, so pivot is always at the end of the array. - // This makes logic much simpler. - DQN_SWAP(T, array[last_index], array[pivot_index]); - pivot_index = last_index; - - // 4^, 8, 7, 5, 2, 3, 6 - if (array[start_index] < array[pivot_index]) partition_index++; - start_index++; - - // 4, |8, 7, 5^, 2, 3, 6* - // 4, 5, |7, 8, 2^, 3, 6* - // 4, 5, 2, |8, 7, ^3, 6* - // 4, 5, 2, 3, |7, 8, ^6* - for (auto check_index = start_index; check_index < last_index; check_index++) - { - if (array[check_index] < array[pivot_index]) - { - DQN_SWAP(T, array[partition_index], array[check_index]); - partition_index++; - } - } - - // Move pivot to right of partition - // 4, 5, 2, 3, |6, 8, ^7* - DQN_SWAP(T, array[partition_index], array[pivot_index]); - DqnQuickSort(array, partition_index); - - // Skip the value at partion index since that is guaranteed to be sorted. - // 4, 5, 2, 3, (x), 8, 7 - i32 one_after_partition_index = partition_index + 1; - DqnQuickSort(array + one_after_partition_index, (size - one_after_partition_index)); -} - - -template using DqnBSearch_LessThanProc = bool (*)(const T&, const T&); -template using DqnBSearch_EqualsProc = bool (*)(const T&, const T&); -#define DQN_BSEARCH_LESS_THAN_PROC(name) template inline bool name(T const &a, T const &b) -#define DQN_BSEARCH_EQUALS_PROC(name) template inline bool name(T const &a, T const &b) -DQN_BSEARCH_LESS_THAN_PROC(DqnBSearch_DefaultLessThan) { return a < b; } -DQN_BSEARCH_EQUALS_PROC (DqnBSearch_DefaultEquals) { return a == b; } - -enum struct DqnBSearchType -{ - Match, // Return the index of the first item that matches the find value - MinusOne, // Return the index of the first item lower than the find value - PlusOne, // Return the index of the first item higher than the find value - - MatchOrMinusOne, // Return the index of the matching item if not found the first item lower - MatchOrPlusOne, // Return the index of the matching item if not found the first item higher -}; - -// type: The matching behaviour of the binary search, -// return: -1 if element not found, otherwise index of the element. -// For higher and lower bounds return -1 if there is no element higher/lower than the -// find value (i.e. -1 if the 0th element is the find val for lower bound). -template IsLessThan = DqnBSearch_DefaultLessThan, - DqnBSearch_EqualsProc Equals = DqnBSearch_DefaultEquals> -DQN_FILE_SCOPE i64 -DqnBSearch(T const *array, isize size, T const &find, DqnBSearchType type = DqnBSearchType::Match) -{ - if (size == 0 || !array) - { - return -1; - } - - isize start = 0; - isize end = size - 1; - isize mid = static_cast((start + end) * 0.5f); - - while (start <= end) - { - if (Equals(array[mid], find)) - { - if (type == DqnBSearchType::Match || - type == DqnBSearchType::MatchOrMinusOne || - type == DqnBSearchType::MatchOrPlusOne) - { - return mid; - } - else if (type == DqnBSearchType::MinusOne) - { - // NOTE: We can always -1 because at worst case, 0 index will go to -1 which is - // correct behaviour. - return mid - 1; - } - else - { - return ((mid + 1) >= size) ? -1 : mid + 1; - } - } - else if (IsLessThan(array[mid], find)) start = mid + 1; - else end = mid - 1; - mid = static_cast((start + end) * 0.5f); - } - - if (type == DqnBSearchType::Match) - { - return -1; - } - if (type == DqnBSearchType::MinusOne || type == DqnBSearchType::MatchOrMinusOne) - { - return (IsLessThan(find, array[mid])) ? -1 : mid; - } - else - { - return (IsLessThan(find, array[mid])) ? mid : -1; - } -} - -DQN_FILE_SCOPE inline i64 DqnBSearch(i64 const *array, i64 size, i64 find, DqnBSearchType type = DqnBSearchType::Match) { return DqnBSearch(array, size, find, type); } - -const size_t DQN_I32_MAX_STR_SIZE = 11; -const size_t DQN_I64_MAX_STR_SIZE = 21; -// Return the len of the derived string. If buf is nullptr and or buf_size is 0 the function returns the -// required string length for the integer -// TODO NOTE(doyle): Parsing stops when a non-digit is encountered, so numbers with ',' don't work atm. -DQN_FILE_SCOPE i32 Dqn_I64ToStr (i64 const value, char *buf, i32 buf_size); -DQN_FILE_SCOPE i64 Dqn_StrToI64 (char const *buf, i64 buf_size); -DQN_FILE_SCOPE inline i64 Dqn_StrToI64 (DqnSlice buf) { return Dqn_StrToI64(buf.data, buf.len); } -DQN_FILE_SCOPE inline i64 Dqn_StrToI64 (DqnSlice buf) { return Dqn_StrToI64(buf.data, buf.len); } - -// WARNING: Not robust, precision errors and whatnot but good enough! -DQN_FILE_SCOPE f32 Dqn_StrToF32 (char const *buf, i64 buf_size); - -// Both return the number of bytes read, return 0 if invalid codepoint or UTF8 -DQN_FILE_SCOPE u32 Dqn_UCSToUTF8(u32 *dest, u32 character); -DQN_FILE_SCOPE u32 Dqn_UTF8ToUCS(u32 *dest, u32 character); - -DQN_FILE_SCOPE i32 Dqn_WStrToI32(wchar_t const *buf, i32 buf_size); -DQN_FILE_SCOPE i32 Dqn_I32ToWStr(i32 value, wchar_t *buf, i32 buf_size); - -// #DqnPool -// ================================================================================================= -template -struct DqnFixedPool -{ - struct Entry : public T - { - u16 nextIndex; - }; - - const static isize SENTINEL_INDEX = SIZE; - - Entry pool[SIZE]; - i16 freeIndex; - i16 numFree; - - DqnFixedPool() : freeIndex(0) , numFree(SIZE) - { - DQN_FOR_EACH(i, SIZE - 1) - { - Entry *entry = pool + i; - entry->nextIndex = i + 1; - } - Entry *last = pool + (SIZE - 1); - last->nextIndex = SENTINEL_INDEX; - } - - T *GetNext() - { - if (freeIndex == SENTINEL_INDEX) return nullptr; - Entry *result = pool + freeIndex; - freeIndex = result->nextIndex; - numFree--; - return result; - } - - void Return(T *item) - { - auto *entry = reinterpret_cast(item); - entry->nextIndex = freeIndex; - freeIndex = entry - pool; - numFree++; - } -}; - -// #DqnPool -// ================================================================================================= -template -struct DqnPool -{ - struct Entry : public T - { - u16 nextIndex; - }; - - Entry *pool; - i16 freeIndex; - i16 numFree; - i32 size; - - void UseMemory(Entry *pool_, isize size) - { - pool = pool_; - freeIndex = 0; - numFree = size; - - DQN_FOR_EACH(i, size - 1) - { - Entry *entry = pool + i; - entry->nextIndex = i + 1; - } - Entry *last = pool + (size - 1); - last->nextIndex = size; - } - - T *GetNext() - { - if (freeIndex == size) return nullptr; - Entry *result = pool + freeIndex; - freeIndex = result->nextIndex; - numFree--; - return result; - } - - void Return(T *item) - { - auto *entry = reinterpret_cast(item); - entry->nextIndex = freeIndex; - freeIndex = entry - pool; - numFree++; - } -}; - -// #DqnHash -// ================================================================================================= -DQN_FILE_SCOPE u32 DqnHash_Murmur32Seed(void const *data, usize len, u32 seed); -DQN_FILE_SCOPE u64 DqnHash_Murmur64Seed(void const *data_, usize len, u64 seed); - -DQN_FILE_SCOPE inline u32 DqnHash_Murmur32(void const *data, usize len) -{ - return DqnHash_Murmur32Seed(data, len, 0x9747b28c); -} - -DQN_FILE_SCOPE inline u64 DqnHash_Murmur64(void const *data, usize len) -{ - return DqnHash_Murmur64Seed(data, len, 0x9747b28c); -} - -// #DqnMath -// ================================================================================================= -DQN_FILE_SCOPE f32 DqnMath_Lerp (f32 a, f32 t, f32 b); -DQN_FILE_SCOPE f32 DqnMath_Sqrtf (f32 a); -DQN_FILE_SCOPE f32 DqnMath_Clampf(f32 val, f32 min, f32 max); - -// #DqnV2 -// ================================================================================================= -union DqnV2i -{ - struct { i32 x, y; }; - struct { i32 w, h; }; - struct { i32 min, max; }; - i32 e[2]; - - DqnV2i() = default; - DqnV2i(i32 x_, i32 y_): x(x_), y(y_) {} - DqnV2i(f32 x_, f32 y_): x((i32)x_), y((i32)y_) {} - - bool operator==(DqnV2i const &b) const { return (this->x == b.x) && (this->y == b.y); } - bool operator!=(DqnV2i const &b) const { return !(*this == b); } - bool operator>=(DqnV2i const &b) const { return (this->x >= b.x) && (this->y >= b.y); } - bool operator<=(DqnV2i const &b) const { return (this->x <= b.x) && (this->y <= b.y); } - bool operator< (DqnV2i const &b) const { return (this->x < b.x) && (this->y < b.y); } - bool operator> (DqnV2i const &b) const { return (this->x > b.x) && (this->y > b.y); } -}; - -union DqnV2 -{ - struct { f32 x, y; }; - struct { f32 w, h; }; - struct { f32 min, max; }; - f32 e[2]; - - DqnV2() = default; - DqnV2(f32 xy) : x(xy), y(xy) {} - DqnV2(f32 x_, f32 y_): x(x_), y(y_) {} - DqnV2(i32 x_, i32 y_): x((f32)x_), y((f32)y_) {} - DqnV2(DqnV2i a) : x((f32)a.x), y((f32)a.y) {} - - bool operator==(DqnV2 const &b) const { return (this->x == b.x) && (this->y == b.y); } - bool operator!=(DqnV2 const &b) const { return !(*this == b); } - bool operator>=(DqnV2 const &b) const { return (this->x >= b.x) && (this->y >= b.y); } - bool operator<=(DqnV2 const &b) const { return (this->x <= b.x) && (this->y <= b.y); } - bool operator< (DqnV2 const &b) const { return (this->x < b.x) && (this->y < b.y); } - bool operator> (DqnV2 const &b) const { return (this->x > b.x) && (this->y > b.y); } -}; - -DQN_FILE_SCOPE DqnV2 DqnV2_Add (DqnV2 a, DqnV2 b); -DQN_FILE_SCOPE DqnV2 DqnV2_Sub (DqnV2 a, DqnV2 b); -DQN_FILE_SCOPE DqnV2 DqnV2_Scalei (DqnV2 a, i32 b); -DQN_FILE_SCOPE DqnV2 DqnV2_Scalef (DqnV2 a, f32 b); -DQN_FILE_SCOPE DqnV2 DqnV2_Hadamard(DqnV2 a, DqnV2 b); -DQN_FILE_SCOPE f32 DqnV2_Dot (DqnV2 a, DqnV2 b); -DQN_FILE_SCOPE bool DqnV2_Equals (DqnV2 a, DqnV2 b); - -DQN_FILE_SCOPE f32 DqnV2_LengthSquared(const DqnV2 a, const DqnV2 b); -DQN_FILE_SCOPE f32 DqnV2_Length (const DqnV2 a, const DqnV2 b); -DQN_FILE_SCOPE DqnV2 DqnV2_Normalise (const DqnV2 a); -DQN_FILE_SCOPE bool DqnV2_Overlaps ( DqnV2 a, DqnV2 b); -DQN_FILE_SCOPE DqnV2 DqnV2_Perpendicular(const DqnV2 a); - -DQN_FILE_SCOPE DqnV2 DqnV2_ResizeKeepAspectRatio(DqnV2 src_size, DqnV2 target_size); -DQN_FILE_SCOPE DqnV2 DqnV2_ConstrainToRatio (DqnV2 dim, DqnV2 ratio); // Resize the dimension to fit the aspect ratio provided. Downscale only. - -DQN_FILE_SCOPE inline DqnV2 operator- (DqnV2 a, DqnV2 b) { return DqnV2_Sub (a, b); } -DQN_FILE_SCOPE inline DqnV2 operator+ (DqnV2 a, DqnV2 b) { return DqnV2_Add (a, b); } -DQN_FILE_SCOPE inline DqnV2 operator* (DqnV2 a, DqnV2 b) { return DqnV2_Hadamard(a, b); } -DQN_FILE_SCOPE inline DqnV2 operator* (DqnV2 a, f32 b) { return DqnV2_Scalef (a, b); } -DQN_FILE_SCOPE inline DqnV2 operator* (DqnV2 a, i32 b) { return DqnV2_Scalei (a, b); } -DQN_FILE_SCOPE inline DqnV2 &operator*=(DqnV2 &a, DqnV2 b) { return (a = DqnV2_Hadamard(a, b)); } -DQN_FILE_SCOPE inline DqnV2 &operator*=(DqnV2 &a, f32 b) { return (a = DqnV2_Scalef (a, b)); } -DQN_FILE_SCOPE inline DqnV2 &operator*=(DqnV2 &a, i32 b) { return (a = DqnV2_Scalei (a, b)); } -DQN_FILE_SCOPE inline DqnV2 &operator-=(DqnV2 &a, DqnV2 b) { return (a = DqnV2_Sub (a, b)); } -DQN_FILE_SCOPE inline DqnV2 &operator+=(DqnV2 &a, DqnV2 b) { return (a = DqnV2_Add (a, b)); } - -// DqnV2i -DQN_FILE_SCOPE DqnV2i DqnV2i_Add (DqnV2i a, DqnV2i b); -DQN_FILE_SCOPE DqnV2i DqnV2i_Sub (DqnV2i a, DqnV2i b); -DQN_FILE_SCOPE DqnV2i DqnV2i_Scalei (DqnV2i a, i32 b); -DQN_FILE_SCOPE DqnV2i DqnV2i_Scalef (DqnV2i a, f32 b); -DQN_FILE_SCOPE DqnV2i DqnV2i_Hadamard(DqnV2i a, DqnV2i b); -DQN_FILE_SCOPE f32 DqnV2i_Dot (DqnV2i a, DqnV2i b); -DQN_FILE_SCOPE bool DqnV2i_Equals (DqnV2i a, DqnV2i b); - -DQN_FILE_SCOPE inline DqnV2i operator- (DqnV2i a, DqnV2i b) { return DqnV2i_Sub (a, b); } -DQN_FILE_SCOPE inline DqnV2i operator+ (DqnV2i a, DqnV2i b) { return DqnV2i_Add (a, b); } -DQN_FILE_SCOPE inline DqnV2i operator* (DqnV2i a, DqnV2i b) { return DqnV2i_Hadamard(a, b); } -DQN_FILE_SCOPE inline DqnV2i operator* (DqnV2i a, f32 b) { return DqnV2i_Scalef (a, b); } -DQN_FILE_SCOPE inline DqnV2i operator* (DqnV2i a, i32 b) { return DqnV2i_Scalei (a, b); } -DQN_FILE_SCOPE inline DqnV2i &operator*=(DqnV2i &a, DqnV2i b) { return (a = DqnV2i_Hadamard(a, b)); } -DQN_FILE_SCOPE inline DqnV2i &operator-=(DqnV2i &a, DqnV2i b) { return (a = DqnV2i_Sub (a, b)); } -DQN_FILE_SCOPE inline DqnV2i &operator+=(DqnV2i &a, DqnV2i b) { return (a = DqnV2i_Add (a, b)); } - -// #DqnV3 -// ================================================================================================= -union DqnV3 -{ - struct { f32 x, y, z; }; - struct { f32 r, g, b; }; - DqnV2 xy; - f32 e[3]; - - DqnV3() = default; - DqnV3(f32 xyz) : x(xyz), y(xyz), z(xyz) {} - DqnV3(f32 x_, f32 y_, f32 z_): x(x_), y(y_), z(z_) {} - DqnV3(i32 x_, i32 y_, i32 z_): x((f32)x_), y((f32)y_), z((f32)z_) {} -}; - -union DqnV3i -{ - struct { i32 x, y, z; }; - struct { i32 r, g, b; }; - i32 e[3]; - - DqnV3i() = default; - DqnV3i(i32 x_, i32 y_, i32 z_): x(x_), y(y_), z(z_) {} - DqnV3i(f32 x_, f32 y_, f32 z_): x((i32)x_), y((i32)y_), z((i32)z_) {} -}; - -// DqnV3 -DQN_FILE_SCOPE DqnV3 DqnV3_Add (DqnV3 a, DqnV3 b); -DQN_FILE_SCOPE DqnV3 DqnV3_Sub (DqnV3 a, DqnV3 b); -DQN_FILE_SCOPE DqnV3 DqnV3_Scalei (DqnV3 a, i32 b); -DQN_FILE_SCOPE DqnV3 DqnV3_Scalef (DqnV3 a, f32 b); -DQN_FILE_SCOPE DqnV3 DqnV3_Hadamard(DqnV3 a, DqnV3 b); -DQN_FILE_SCOPE f32 DqnV3_Dot (DqnV3 a, DqnV3 b); -DQN_FILE_SCOPE bool DqnV3_Equals (DqnV3 a, DqnV3 b); -DQN_FILE_SCOPE DqnV3 DqnV3_Cross (DqnV3 a, DqnV3 b); - -DQN_FILE_SCOPE DqnV3 DqnV3_Normalise (DqnV3 a); -DQN_FILE_SCOPE f32 DqnV3_Length (DqnV3 a, DqnV3 b); -DQN_FILE_SCOPE f32 DqnV3_LengthSquared(DqnV3 a, DqnV3 b); - -DQN_FILE_SCOPE inline DqnV3 operator- (DqnV3 a, DqnV3 b) { return DqnV3_Sub (a, b); } -DQN_FILE_SCOPE inline DqnV3 operator+ (DqnV3 a, DqnV3 b) { return DqnV3_Add (a, b); } -DQN_FILE_SCOPE inline DqnV3 operator+ (DqnV3 a, f32 b) { return DqnV3_Add (a, DqnV3(b)); } -DQN_FILE_SCOPE inline DqnV3 operator* (DqnV3 a, DqnV3 b) { return DqnV3_Hadamard(a, b); } -DQN_FILE_SCOPE inline DqnV3 operator* (DqnV3 a, f32 b) { return DqnV3_Scalef (a, b); } -DQN_FILE_SCOPE inline DqnV3 operator* (DqnV3 a, i32 b) { return DqnV3_Scalei (a, b); } -DQN_FILE_SCOPE inline DqnV3 operator/ (DqnV3 a, f32 b) { return DqnV3_Scalef (a, (1.0f/b)); } -DQN_FILE_SCOPE inline DqnV3 &operator*=(DqnV3 &a, DqnV3 b) { return (a = DqnV3_Hadamard(a, b)); } -DQN_FILE_SCOPE inline DqnV3 &operator*=(DqnV3 &a, f32 b) { return (a = DqnV3_Scalef (a, b)); } -DQN_FILE_SCOPE inline DqnV3 &operator*=(DqnV3 &a, i32 b) { return (a = DqnV3_Scalei (a, b)); } -DQN_FILE_SCOPE inline DqnV3 &operator-=(DqnV3 &a, DqnV3 b) { return (a = DqnV3_Sub (a, b)); } -DQN_FILE_SCOPE inline DqnV3 &operator+=(DqnV3 &a, DqnV3 b) { return (a = DqnV3_Add (a, b)); } -DQN_FILE_SCOPE inline bool operator==(DqnV3 a, DqnV3 b) { return DqnV3_Equals (a, b); } - -// #DqnV4 -// ================================================================================================= -union DqnV4 -{ - struct { f32 x, y, z, w; }; - DqnV3 xyz; - DqnV2 xy; - - struct { f32 r, g, b, a; }; - DqnV3 rgb; - - f32 e[4]; - DqnV2 v2[2]; - - DqnV4() = default; - DqnV4(f32 xyzw) : x(xyzw), y(xyzw), z(xyzw), w(xyzw) {} - DqnV4(f32 x_, f32 y_, f32 z_, f32 w_): x(x_), y(y_), z(z_), w(w_) {} - DqnV4(i32 x_, i32 y_, i32 z_, i32 w_): x((f32)x_), y((f32)y_), z((f32)z_), w((f32)w_) {} - DqnV4(DqnV3 a, f32 w_) : x(a.x), y(a.y), z(a.z), w(w_) {} - -}; - -DQN_FILE_SCOPE DqnV4 DqnV4_Add (DqnV4 a, DqnV4 b); -DQN_FILE_SCOPE DqnV4 DqnV4_Sub (DqnV4 a, DqnV4 b); -DQN_FILE_SCOPE DqnV4 DqnV4_Scalef (DqnV4 a, f32 b); -DQN_FILE_SCOPE DqnV4 DqnV4_Scalei (DqnV4 a, i32 b); -DQN_FILE_SCOPE DqnV4 DqnV4_Hadamard(DqnV4 a, DqnV4 b); -DQN_FILE_SCOPE f32 DqnV4_Dot (DqnV4 a, DqnV4 b); -DQN_FILE_SCOPE bool DqnV4_Equals (DqnV4 a, DqnV4 b); - -DQN_FILE_SCOPE inline DqnV4 operator- (DqnV4 a, DqnV4 b) { return DqnV4_Sub (a, b); } -DQN_FILE_SCOPE inline DqnV4 operator+ (DqnV4 a, DqnV4 b) { return DqnV4_Add (a, b); } -DQN_FILE_SCOPE inline DqnV4 operator+ (DqnV4 a, f32 b) { return DqnV4_Add (a, DqnV4(b)); } -DQN_FILE_SCOPE inline DqnV4 operator* (DqnV4 a, DqnV4 b) { return DqnV4_Hadamard(a, b); } -DQN_FILE_SCOPE inline DqnV4 operator* (DqnV4 a, f32 b) { return DqnV4_Scalef (a, b); } -DQN_FILE_SCOPE inline DqnV4 operator* (DqnV4 a, i32 b) { return DqnV4_Scalei (a, b); } -DQN_FILE_SCOPE inline DqnV4 &operator*=(DqnV4 &a, DqnV4 b) { return (a = DqnV4_Hadamard(a, b)); } -DQN_FILE_SCOPE inline DqnV4 &operator*=(DqnV4 &a, f32 b) { return (a = DqnV4_Scalef (a, b)); } -DQN_FILE_SCOPE inline DqnV4 &operator*=(DqnV4 &a, i32 b) { return (a = DqnV4_Scalei (a, b)); } -DQN_FILE_SCOPE inline DqnV4 &operator-=(DqnV4 &a, DqnV4 b) { return (a = DqnV4_Sub (a, b)); } -DQN_FILE_SCOPE inline DqnV4 &operator+=(DqnV4 &a, DqnV4 b) { return (a = DqnV4_Add (a, b)); } -DQN_FILE_SCOPE inline bool operator==(DqnV4 &a, DqnV4 b) { return DqnV4_Equals (a, b); } - -// #DqnMat4 -// ================================================================================================= -typedef union DqnMat4 -{ - // TODO(doyle): Row/column instead? More cache friendly since multiplication - // prefers rows. - DqnV4 col[4]; - f32 e[4][4]; // Column/row -} DqnMat4; - -DQN_FILE_SCOPE DqnMat4 DqnMat4_Identity (); - -DQN_FILE_SCOPE DqnMat4 DqnMat4_Orthographic(f32 left, f32 right, f32 bottom, f32 top, f32 znear, f32 zfar); -DQN_FILE_SCOPE DqnMat4 DqnMat4_Perspective (f32 fov_y_degrees, f32 aspect_ratio, f32 znear, f32 zfar); -DQN_FILE_SCOPE DqnMat4 DqnMat4_LookAt (DqnV3 eye, DqnV3 center, DqnV3 up); - -DQN_FILE_SCOPE DqnMat4 DqnMat4_Translate3f (f32 x, f32 y, f32 z); -DQN_FILE_SCOPE DqnMat4 DqnMat4_TranslateV3 (DqnV3 vec); -DQN_FILE_SCOPE DqnMat4 DqnMat4_Rotate (f32 radians, f32 x, f32 y, f32 z); -DQN_FILE_SCOPE DqnMat4 DqnMat4_Scale (f32 x, f32 y, f32 z); -DQN_FILE_SCOPE DqnMat4 DqnMat4_ScaleV3 (DqnV3 scale); -DQN_FILE_SCOPE DqnMat4 DqnMat4_Mul (DqnMat4 a, DqnMat4 b); -DQN_FILE_SCOPE DqnV4 DqnMat4_MulV4 (DqnMat4 a, DqnV4 b); - -// #DqnRect -// ================================================================================================= -struct DqnRect -{ - DqnV2 min; - DqnV2 max; - - DqnRect() = default; - DqnRect(DqnV2 origin, DqnV2 size) { this->min = origin; this->max = origin + size; } - DqnRect(f32 x, f32 y, f32 w, f32 h) { this->min = DqnV2(x, y); this->max = DqnV2(x + w, y + h); } - DqnRect(i32 x, i32 y, i32 w, i32 h) { this->min = DqnV2(x, y); this->max = DqnV2(x + w, y + h); } - - f32 GetWidth () const { return max.w - min.w; } - f32 GetHeight() const { return max.h - min.h; } - DqnV2 GetSize () const { return max - min; } - void GetSize (f32 *const width, f32 *const height) const; - DqnV2 GetCenter() const; - - DqnRect ClipRect (DqnRect const clip) const; - DqnRect Move (DqnV2 const shift) const; - bool ContainsP(DqnV2 const p) const; -}; - -struct DqnJson -{ - enum struct Type - { - Object, - ArrayOfObjects, - ArrayOfPrimitives, - }; - - Type type; - DqnSlice value; - i32 num_entries; - - operator bool () const { return (value.data != nullptr); } - bool IsArray() const { return (type == Type::ArrayOfObjects || type == Type::ArrayOfPrimitives); } - i64 ToI64() const { return Dqn_StrToI64(value.data, value.len); } -}; - -// Zero allocation json finder. Returns the data of the value. -// If array, it returns a slice from [..] not-inclusive, if object, it returns a slice from {..} not-inclusive -// If just name value pair, it returns the literal with quotes or just the value if it is a primitive with quotes. -DQN_FILE_SCOPE DqnJson DqnJson_Get (char const *buf, i32 buf_len, char const *find_property, i32 find_property_len); -DQN_FILE_SCOPE DqnJson DqnJson_Get (DqnSlice const buf, DqnSlice const find_property); -DQN_FILE_SCOPE DqnJson DqnJson_Get (DqnSlice const buf, DqnSlice const find_property); -DQN_FILE_SCOPE DqnJson DqnJson_Get (DqnSlice const buf, DqnSlice const find_property); -DQN_FILE_SCOPE DqnJson DqnJson_Get (DqnJson const input, DqnSlice const find_property); -DQN_FILE_SCOPE DqnJson DqnJson_Get (DqnJson const input, DqnSlice const find_property); - -// return: The array item. -DQN_FILE_SCOPE DqnJson DqnJson_GetNextArrayItem(DqnJson *iterator); - -#endif /* DQN_H */ - -// #XPlatform (Win32 & Unix) -// ================================================================================================= -// Functions in the Cross Platform are guaranteed to be supported in both Unix -// and Win32 - -// NOTE(doyle): DQN_PLATFORM_HEADER is enabled by the user to have the function prototypes be -// visible. DQN_PLATFORM_H is like a normal header guard that ensures singular declaration of -// functions. -#ifdef DQN_PLATFORM_HEADER - -#ifndef DQN_PLATFORM_H -#define DQN_PLATFORM_H - -#if defined(DQN_IS_UNIX) - #include - #include -#endif - -// XPlatform > #DqnOS -// ================================================================================================= -DQN_FILE_SCOPE void *DqnOS_VAlloc(isize size, void *base_addr = nullptr); -DQN_FILE_SCOPE void DqnOS_VFree (void *address, isize size); - -// Uses a single call to DqnMem_Calloc() and DqnMem_Free(). Not completely platform "independent" for Unix. -// num_cores: num_threads_per_core: Can be nullptr, the function will just skip it. -DQN_FILE_SCOPE void DqnOS_GetThreadsAndCores(u32 *const num_cores, u32 *const num_threads_per_core); - -// #XPlatform > #DqnVArray Array backed by virtual memory -// ================================================================================================= -template -struct DqnVArray -{ - isize len; // Read - isize max; // Read - T *data; // Read - - DqnVArray () = default; // Zero is initialisation - DqnVArray (isize size) { LazyInit(size); } - 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::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; } - T *Make (isize num = 1) { if (!data) LazyInit(1024); len += num; DQN_ASSERT(len <= max); return &data[len - num]; } - T *Add (T const &v) { data[len++] = v; return data + (len - 1); } - T *Add (T const *v, isize v_len = 1) { T *result = data + len; for (isize i = 0; i < v_len; ++i) data[len++] = v[i]; return result; } - void Pop () { if (len > 0) len--; } - void Erase (isize index) { if (!data) return; DQN_ASSERT(index >= 0 && index < len); data[index] = data[--len]; } - void EraseStable(isize index); - T *Insert (isize index, T const *v) { return Insert(index, v, 1); } - T *Insert (isize index, T const &v) { return Insert(index, &v, 1); } - T *Insert (isize index, T const *v, isize num_items); - bool Contains (T const *v) const { T const *ptr = data; T const *end = data + len; while (ptr < end) { if (*ptr++ == *v) return true; } return false; } - - T &operator[] (isize i) const { DQN_ASSERT(i < len && i > 0); return this->data[i]; } - T *begin () { return data; } - T *end () { return data + len; } -}; - -template T *DqnVArray::Insert(isize index, T const *v, isize num_items) -{ - if (!data) LazyInit(1024); - - index = DQN_CLAMP(index, 0, len); - isize const new_len = len + num_items; - DQN_ASSERT(new_len <= max); - - T *src = data + index; - T *dest = src + num_items; - - if (src < dest) - memmove(dest, src, ((data + len) - src) * sizeof(T)); - - len = new_len; - for (isize i = 0; i < num_items; i++) - src[i] = v[i]; - - return src; -} - -template void DqnVArray::EraseStable(isize index) -{ - if (!data) return; - DQN_ASSERT(index >= 0 && index < len); - isize const off = (data + index) - data; - memmove(data + off, data + off + 1, ((usize)len - (usize)off - 1) * sizeof(T)); - len--; -} - -// #XPlatform > #DqnVHashTable -// ================================================================================================= -template using DqnVHashTableHashingProc = isize(*)(isize count, Key const &data); -template using DqnVHashTableEqualsProc = bool (*)(Key const &a, Key const &b); - -const u64 DQN_VHASH_TABLE_DEFAULT_SEED = 0x9747B28CAB3F8A7B; -#define DQN_VHASH_TABLE_HASHING_PROC(name, Type) inline isize name(isize count, Type const &key) -#define DQN_VHASH_TABLE_EQUALS_PROC(name, Type) inline bool name(Type const &a, Type const &b) - -template DQN_VHASH_TABLE_HASHING_PROC(DqnVHashTableDefaultHash, T) { return DqnHash_Murmur64Seed(&key, sizeof(key), DQN_VHASH_TABLE_DEFAULT_SEED) % count; } -template DQN_VHASH_TABLE_EQUALS_PROC (DqnVHashTableDefaultEquals, T) { return (DqnMem_Cmp(&a, &b, sizeof(a)) == 0); } - -template <> DQN_VHASH_TABLE_HASHING_PROC(DqnVHashTableDefaultHash, DqnString) { return DqnHash_Murmur64Seed(&key.str, key.len, DQN_VHASH_TABLE_DEFAULT_SEED) % count; } -template <> DQN_VHASH_TABLE_EQUALS_PROC (DqnVHashTableDefaultEquals, DqnString) { return (a.len == b.len) && (DqnStr_Cmp(a.str, b.str, a.len) == 0); } -template <> DQN_VHASH_TABLE_HASHING_PROC(DqnVHashTableDefaultHash>, DqnBuffer) { return DqnHash_Murmur64Seed(&key.str, key.len, DQN_VHASH_TABLE_DEFAULT_SEED) % count; } -template <> DQN_VHASH_TABLE_EQUALS_PROC (DqnVHashTableDefaultEquals>, DqnBuffer) { return DQN_BUFFER_STRCMP(a, b, Dqn::IgnoreCase::No); } - -// TODO(doyle): Fix this so we don't have to manually declare the fixed string sizes for hashing and equals -#define DQN_VHASH_TABLE_DEFAULT_FIXED_STRING_PROCS(StringCapacity) \ - template <> \ - DQN_VHASH_TABLE_HASHING_PROC(DqnVHashTableDefaultHash>, \ - DqnFixedString) \ - { \ - return DqnHash_Murmur64Seed(key.str, key.len, DQN_VHASH_TABLE_DEFAULT_SEED) % count; \ - } \ - template <> \ - DQN_VHASH_TABLE_EQUALS_PROC(DqnVHashTableDefaultEquals>, \ - DqnFixedString) \ - { \ - return (a.len == b.len) && (DqnStr_Cmp(a.str, b.str, a.len, Dqn::IgnoreCase::No) == 0); \ - } - -DQN_VHASH_TABLE_DEFAULT_FIXED_STRING_PROCS(1024) -DQN_VHASH_TABLE_DEFAULT_FIXED_STRING_PROCS(512) -DQN_VHASH_TABLE_DEFAULT_FIXED_STRING_PROCS(256) -DQN_VHASH_TABLE_DEFAULT_FIXED_STRING_PROCS(128) -DQN_VHASH_TABLE_DEFAULT_FIXED_STRING_PROCS(64) -DQN_VHASH_TABLE_DEFAULT_FIXED_STRING_PROCS(32) -DQN_VHASH_TABLE_DEFAULT_FIXED_STRING_PROCS(16) -DQN_VHASH_TABLE_DEFAULT_FIXED_STRING_PROCS(8) - - -#define DQN_VHASH_TABLE_TEMPLATE \ - template Hash, \ - DqnVHashTableEqualsProc Equals> - -#define DQN_VHASH_TABLE_DECL DqnVHashTable - -template Hash = DqnVHashTableDefaultHash, - DqnVHashTableEqualsProc Equals = DqnVHashTableDefaultEquals> -struct DqnVHashTable -{ - struct Entry - { - union { Key key; Key first; }; - union { Item item; Item second; }; - }; - - struct Bucket - { - Entry entries[4]; - isize entry_index; - }; - - Bucket *buckets; - isize num_buckets; - isize *indexes_of_used_buckets; - isize num_used_entries; - isize num_used_buckets; - - DqnVHashTable () = default; - DqnVHashTable (isize size) { LazyInit(size); } - - void LazyInit (isize size = DQN_MAX(DQN_MEGABYTE(1)/sizeof(Bucket), 1024) ); - void Free () { if (buckets) DqnOS_VFree(buckets, sizeof(buckets) * num_buckets); *this = {}; } - - void Erase (Key const &key); // Delete the element matching key, does nothing if key not found. - Entry *GetEntry (Key const &key); // return: The (key, item) entry associated with the key, nullptr if key not in table yet. - Item *GetOrMake(Key const &key, bool *existed = nullptr); // return: Item if found, otherwise make an entry (key, item) and return the ptr to the uninitialised item - Item *Get (Key const &key) { Entry *entry = GetEntry(key); return (entry) ? &entry->item : nullptr; } - Item *Set (Key const &key, Item const &item) { Item *result = GetOrMake(key); *result = item; return result; } - - Item *operator[](Key const &key) { return Get(key); } - - struct Iterator - { - Entry *entry; - Iterator(DqnVHashTable *table_, isize num_used_buckets_ = 0, isize index_in_bucket_ = 0); - Bucket *GetCurrBucket() const { return (table->buckets + table->indexes_of_used_buckets[num_used_buckets]); } - Entry *GetCurrEntry() const { return GetCurrBucket()->entries + index_in_bucket; } - Item *GetCurrItem () const { return &(GetCurrEntry()->item); } - - bool operator!=(Iterator const &other) const { return !(num_used_buckets == other.num_used_buckets && index_in_bucket == other.index_in_bucket); } - 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; } // 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 - - private: - DqnVHashTable *table; - isize num_used_buckets; - isize index_in_bucket; - }; - - 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_, - isize num_used_buckets_, - isize index_in_bucket_) -: table(table_) -, num_used_buckets(num_used_buckets_) -, index_in_bucket(index_in_bucket_) -, entry(nullptr) -{ - bool sentinel_index = (num_used_buckets == table->num_buckets && - index_in_bucket == DQN_ARRAY_COUNT(table->buckets[0].entries)); - bool empty_table = (table->num_used_buckets == 0); - if (empty_table || sentinel_index) - { - if (empty_table) - { - this->num_used_buckets = table->num_buckets; - this->index_in_bucket = DQN_ARRAY_COUNT(table->buckets[0].entries); - } - } - else - { - entry = GetCurrEntry(); - } -} - -DQN_VHASH_TABLE_TEMPLATE typename DQN_VHASH_TABLE_DECL::Iterator &DQN_VHASH_TABLE_DECL::Iterator::operator++() -{ - if (++index_in_bucket >= GetCurrBucket()->entry_index) - { - index_in_bucket = 0; - num_used_buckets++; - } - - if (num_used_buckets < table->num_used_buckets) - entry = GetCurrEntry(); - else - *this = table->end(); - - return *this; -} - -DQN_VHASH_TABLE_TEMPLATE void DQN_VHASH_TABLE_DECL::LazyInit(isize size) -{ - *this = {}; - this->num_buckets = size; - this->buckets = static_cast(DqnOS_VAlloc(size * sizeof(*this->buckets))); - this->indexes_of_used_buckets = static_cast (DqnOS_VAlloc(size * sizeof(*this->indexes_of_used_buckets))); - DQN_ASSERT(this->buckets && this->indexes_of_used_buckets); -} - -DQN_VHASH_TABLE_TEMPLATE typename DQN_VHASH_TABLE_DECL::Entry * -DQN_VHASH_TABLE_DECL::GetEntry(Key const &key) -{ - if (!buckets) return nullptr; - - isize index = Hash(this->num_buckets, key); - Bucket *bucket = this->buckets + index; - - Entry *result = nullptr; - for (isize i = 0; i < bucket->entry_index && !result; i++) - { - Entry *entry = bucket->entries + i; - result = Equals(entry->key, key) ? entry : nullptr; - } - - return result; -} - -DQN_VHASH_TABLE_TEMPLATE Item *DQN_VHASH_TABLE_DECL::GetOrMake(Key const &key, bool *existed) -{ - if (!this->buckets) LazyInit(); - - isize index = Hash(this->num_buckets, key); - Bucket *bucket = this->buckets + index; - - Entry *entry = nullptr; - for (isize i = 0; i < bucket->entry_index && !entry; i++) - { - Entry *check = bucket->entries + i; - entry = Equals(check->key, key) ? check : nullptr; - } - - if (existed) - *existed = (entry != nullptr); - - if (!entry) - { - DQN_ALWAYS_ASSERTM(bucket->entry_index < DQN_ARRAY_COUNT(bucket->entries), - "More than %zu collisions in hash table, increase the size of the table or buckets", - DQN_ARRAY_COUNT(bucket->entries)); - - if (bucket->entry_index == 0) - this->indexes_of_used_buckets[this->num_used_buckets++] = index; - - entry = bucket->entries + bucket->entry_index++; - entry->key = key; - ++this->num_used_entries; - - // TODO(doyle): A maybe case. We're using virtual memory, so you should - // just initialise a larger size. It's essentially free ... maybe one - // day we care about resizing the table but at the cost of a lot more code - // complexity. - isize const threshold = static_cast(0.75f * this->num_buckets); - DQN_ALWAYS_ASSERTM(this->num_used_buckets < threshold, "%zu >= %zu", this->num_used_buckets, threshold); - } - - Item *result = &entry->item; - return result; -} - -DQN_VHASH_TABLE_TEMPLATE void DQN_VHASH_TABLE_DECL::Erase(Key const &key) -{ - if (!buckets) - return; - - isize index = Hash(this->num_buckets, key); - Bucket *bucket = this->buckets + index; - - DQN_FOR_EACH(i, bucket->entry_index) - { - Entry *check = bucket->entries + i; - if (!Equals(check->key, key)) - { - continue; - } - - for (isize j = i; j < (bucket->entry_index - 1); ++j) - bucket->entries[j] = bucket->entries[j + 1]; - - --this->num_used_entries; - if (--bucket->entry_index == 0) - { - DQN_FOR_EACH(bucketIndex, this->num_used_buckets) - { - if (this->indexes_of_used_buckets[bucketIndex] == index) - { - indexes_of_used_buckets[bucketIndex] = - indexes_of_used_buckets[--this->num_used_buckets]; - } - } - } - - DQN_ASSERT(this->num_used_entries >= 0); - DQN_ASSERT(this->num_used_buckets >= 0); - DQN_ASSERT(bucket->entry_index >= 0); - return; - } -} - -// XPlatform > #DqnFile -// ================================================================================================= -struct DqnFile -{ - enum Flag - { - FileRead = (1 << 0), - FileWrite = (1 << 1), - Execute = (1 << 2), - All = (1 << 3), - FileReadWrite = FileRead | FileWrite - }; - - enum struct Action - { - OpenOnly, // Only open file if it exists. Fails and returns false if file did not exist or could not open. - CreateIfNotExist, // Try and create file. Return true if it was able to create. If it already exists, this fails. - ClearIfExist, // Clear the file contents to zero if it exists. Fails and returns false if file does not exist. - ForceCreate, // Always create, even if it exists - }; - - u32 flags; - void *handle; - usize size; - int curr_write_offset; - - // API - // ============================================================================================== - // NOTE: W(ide) versions of functions only work on Win32, since Unix is already UTF-8 compatible. - - // Open a handle for file read and writing. Deleting files does not need a handle. Handles should be - // closed before deleting files otherwise the OS may not be able to delete the file. - // return: FALSE if invalid args or failed to get handle (i.e. insufficient permission) - bool Open(char const *path, u32 const flags_, Action const action); - bool Open(wchar_t const *path, u32 const flags_, Action const action); - - // 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); - - // 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. - usize Read (u8 *buf, usize const num_bytes_to_read); - - // File close invalidates the handle after it is called. - void Close(); -}; - -struct DqnFileInfo -{ - usize size; - u64 create_time_in_s; - u64 last_write_time_in_s; - u64 last_access_time_in_s; -}; - -// Read entire file into the given buffer. To determine required buf_size size, use GetFileSize. -// NOTE: You want size + 1 and add the null-terminator yourself if you want a null terminated buffer. -// bytes_read: Pass in to get how many bytes of the buf was used. Basically the return value of Read -// return: False if insufficient buf_size OR file access failure OR nullptr arguments. -DQN_FILE_SCOPE bool DqnFile_ReadAll(char const *path, u8 *buf, usize buf_size); -DQN_FILE_SCOPE bool DqnFile_ReadAll(wchar_t const *path, u8 *buf, usize buf_size); - -// Buffer is null-terminated and should be freed when done with. -// return: False if file access failure OR nullptr arguments. -DQN_FILE_SCOPE u8 *DqnFile_ReadAll(char const *path, usize *buf_size, DqnAllocator *allocator = dqn_lib_context_.allocator); -DQN_FILE_SCOPE u8 *DqnFile_ReadAll(wchar_t const *path, usize *buf_size, DqnAllocator *allocator = dqn_lib_context_.allocator); -DQN_FILE_SCOPE u8 *DqnFile_ReadAll(wchar_t const *path, usize *buf_size, DqnMemStack *stack); -DQN_FILE_SCOPE u8 *DqnFile_ReadAll(char const *path, usize *buf_size, DqnMemStack *stack); - -DQN_FILE_SCOPE bool DqnFile_WriteAll(char const *path, u8 const *buf, usize const buf_size); -DQN_FILE_SCOPE bool DqnFile_WriteAll(wchar_t const *path, u8 const *buf, usize const buf_size); - -// return: False if file access failure -DQN_FILE_SCOPE bool DqnFile_Size(char const *path, usize *size); -DQN_FILE_SCOPE bool DqnFile_Size(wchar_t const *path, usize *size); - -DQN_FILE_SCOPE bool DqnFile_MakeDir(char const *path); - -// info: (Optional) Pass in to fill with file attributes -// return: False if file access failure -DQN_FILE_SCOPE bool DqnFile_GetInfo(char const *path, DqnFileInfo *info); -DQN_FILE_SCOPE bool DqnFile_GetInfo(wchar_t const *path, DqnFileInfo *info); - -// NOTE: You can't delete a file unless the handle has been closed to it on Win32. -// return: False if file access failure -DQN_FILE_SCOPE bool DqnFile_Delete (char const *path); -DQN_FILE_SCOPE bool DqnFile_Delete (wchar_t const *path); -DQN_FILE_SCOPE bool DqnFile_Copy (char const *src, char const *dest); -DQN_FILE_SCOPE bool DqnFile_Copy (wchar_t const *src, wchar_t const *dest); - -// NOTE: Win32: Current directory is "*", Unix: "." -// num_files: Pass in a ref to a i32. The function fills it out with the number of entries. -// return: An array of strings of the files in the directory in UTF-8. The directory lisiting is -// allocated with malloc and must be freed using free() or the helper function ListDirFree() -DQN_FILE_SCOPE char **DqnFile_ListDir (char const *dir, i32 *num_files, DqnAllocator *allocator = dqn_lib_context_.allocator); -DQN_FILE_SCOPE void DqnFile_ListDirFree (char **file_list, i32 num_files, DqnAllocator *allocator = dqn_lib_context_.allocator); - -// XPlatform > #DqnCatalog -// ================================================================================================= -using DqnCatalogPath = DqnFixedString1024; -template using DqnCatalogLoadProc = bool (*)(DqnCatalogPath const &file, T *data); -#define DQN_CATALOG_LOAD_PROC(name, type) bool name(DqnCatalogPath const &file, type *data) - -#define DQN_CATALOG_TEMPLATE template LoadAsset> -#define DQN_CATALOG_DECL DqnCatalog - -#if 0 -struct RawBuf { char *buffer; int len; }; -DQN_CATALOG_LOAD_PROC(CatalogRawLoad, RawBuf) -{ - size_t buf_size; - uint8_t *buf = DqnFile_ReadAll(file.str, &buf_size); - if (!buf) return false; - data->buffer = reinterpret_cast(buf); - data->len = static_cast(buf_size); - return true; -} - -int main(int, char) -{ - DqnCatalog catalog = {}; - RawBuf *file = catalog.GetIfUpdated("path/to/file/"); - if (file) { (void)file; // do work on file } - else { // file not updated since last query } - - while (true) // Or event loop, poll the assets in the catalog - { - catalog.PollAssets(); - } - catalog.Free(); -} -#endif - -DQN_CATALOG_TEMPLATE struct DqnCatalog -{ - struct Entry - { - T data; - u64 last_write_time_in_s; - bool updated; - }; - - DqnVHashTable asset_table; - - // Adds the file to the catalog if it has not been added yet. - // return: Asset if an update has been detected and not consumed yet otherwise nullptr. Update is consumed after called. - T *GetIfUpdated(DqnCatalogPath const &file); - Entry *GetEntry (DqnCatalogPath const &file) { Entry *entry = asset_table.Get(file); return entry; } - T *Get (DqnCatalogPath const &file) { Entry *entry = asset_table.Get(file); return (entry) ? &entry->data : nullptr; } - void Erase (DqnCatalogPath const &file) { asset_table.Erase(file); }; - - // return: Iterate all loaded assets for updates, true if atleast 1 asset was updated. - bool PollAssets (); - void Free () { asset_table.Free(); } - - // NOTE: Unlikely you will need to use. Prefer GetIfUpdated. - // Manually invoke an update on the entry by querying its last write time on disk and updating accordingly. - bool QueryAndUpdateAsset(DqnCatalogPath const &file, Entry *entry); -}; - -DQN_CATALOG_TEMPLATE bool DQN_CATALOG_DECL::QueryAndUpdateAsset(DqnCatalogPath const &file, Entry *entry) -{ - DqnFileInfo info = {}; - if (!DqnFile_GetInfo(file.str, &info)) - { - DQN_LOGGER_W(dqn_lib_context_.logger, "Catalog could not get file info for: %s\n", file.str); - return false; - } - - if (entry->last_write_time_in_s == info.last_write_time_in_s) - return true; - - T newData = {}; - if (LoadAsset(file, &newData)) - { - entry->last_write_time_in_s = info.last_write_time_in_s; - entry->data = newData; - entry->updated = true; - } - else - { - DQN_LOGGER_W(dqn_lib_context_.logger, "Catalog could not load file: %s\n", file.str); - return false; - } - - return true; -} - -DQN_CATALOG_TEMPLATE T *DQN_CATALOG_DECL::GetIfUpdated(DqnCatalogPath const &file) -{ - Entry *entry = this->asset_table.GetOrMake(file); - if (QueryAndUpdateAsset(file, entry)) - { - if (entry->updated) entry->updated = false; - else entry = nullptr; - } - else - { - entry = nullptr; - } - - return &entry->data; -} - -DQN_CATALOG_TEMPLATE bool DQN_CATALOG_DECL::PollAssets() -{ - bool result = false; - for (auto it = this->asset_table.begin(); it != this->asset_table.end(); ++it) - { - DqnCatalogPath const *file = &it.entry->key; - Entry *entry = &it.entry->item; - result |= QueryAndUpdateAsset(*file, entry); - } - - return result; -} - - -// XPlatform > #DqnTimer -// ================================================================================================= -DQN_FILE_SCOPE f64 DqnTimer_NowInMs(); -DQN_FILE_SCOPE f64 DqnTimer_NowInS (); - -// XPlatform > #DqnLock -// ================================================================================================= -struct DqnLock -{ -#if defined(DQN_IS_WIN32) - CRITICAL_SECTION win32_handle; -#else - pthread_mutex_t unix_handle; -#endif - - // Win32 only, when trying to acquire a locked lock, it is the number of spins permitted - // spinlocking on the lock before being blocked. Set before init if you want a different value. - u32 win32_spin_count = 16000; - - bool Init (); - void Acquire(); - void Release(); - void Delete (); - - struct Guard_ - { - Guard_(DqnLock *lock_) : lock(lock_) { lock->Acquire(); } - ~Guard_() { lock->Release(); } - - private: - DqnLock *lock; - }; - - // Create a lock guard on the lock this is invoked on. - Guard_ Guard() { return Guard_(this); } -}; - -// XPlatform > #DqnJobQueue -// ================================================================================================= -// DqnJobQueue is a platform abstracted "lockless" multithreaded work queue. It will create threads -// and assign threads to complete the job via the job "callback" using the "user_data" supplied. - -// Usage -// 1. Prepare your callback function for threads to execute following the 'DqnJob_Callback' function -// signature. -// 2. Create a job queue with DqnJobQueue_InitWithMem() -// 3. Add jobs with DqnJobQueue_AddJob() and threads will be dispatched automatically. - -// When all jobs are sent you can also utilise the main executing thread to complete jobs whilst you -// wait for all jobs to complete using DqnJobQueue_TryExecuteNextJob() or spinlock on -// DqnJobQueue_AllJobsComplete(). Alternatively you can combine both for the main thread to help -// complete work and not move on until all tasks are complete. - -typedef void DqnJob_Callback(struct DqnJobQueue *const queue, void *const user_data); -struct DqnJob -{ - DqnJob_Callback *callback; - void *user_data; -}; - -struct DqnJobQueue -{ - // JobList Circular Array, is setup in Init() - DqnJob *job_list; - u32 size; - - // NOTE(doyle): Modified by main+worker threads - i32 volatile jobToExecuteIndex; - i32 volatile num_jobs_queued; - -#if defined(DQN_IS_WIN32) - void *semaphore; -#else - sem_t semaphore; -#endif - - // NOTE: Modified by main thread ONLY - i32 volatile jobInsertIndex; - - bool Init (DqnJob *const job_list_, const u32 job_list_size, const u32 num_threads); - bool AddJob (const DqnJob job); - - void BlockAndCompleteAllJobs(); - bool TryExecuteNextJob(); - bool AllJobsComplete (); -}; - -// TODO(doyle): Queue delete, thread delete - -// queue: Pass a pointer to a zero cleared DqnJobQueue struct -// job_list: Pass in a pointer to an array of DqnJob's -// job_list_size: The number of elements in the job_list array -// num_threads: The number of threads the queue should request from the OS for working on the queue -// return: FALSE if invalid args i.e. nullptr ptrs or job_list_size & num_threads == 0 -DQN_FILE_SCOPE bool DqnJobQueue_Init(DqnJobQueue *const queue, const DqnJob *const job_list, - const u32 job_list_size, const u32 num_threads); - -// return: FALSE if the job is not able to be added, this occurs if the queue is full. -DQN_FILE_SCOPE bool DqnJobQueue_AddJob(DqnJobQueue *const queue, const DqnJob job); - -// Helper function that combines TryExecuteNextJob() and AllJobsComplete(), i.e. -// complete all work before moving on. Does nothing if queue is nullptr. -DQN_FILE_SCOPE void DqnJobQueue_BlockAndCompleteAllJobs(DqnJobQueue *const queue); - -// return: TRUE if there was a job to execute (the calling thread executes it). FALSE if it could -// not get a job. It may return FALSE whilst there are still jobs, this means that another thread -// has taken the job before the calling thread could and should NOT be used to determine if there -// are any remaining jobs left. That can only be definitively known using -// DqnJobQueue_AllJobsComplete(). This is typically combined like so .. -// while (DqnJobQueue_TryExecuteNextJob(queue) || !DqnJobQueue_AllJobsComplete(queue)); -// Return FALSE also if queue is a nullptr pointer. -DQN_FILE_SCOPE bool DqnJobQueue_TryExecuteNextJob(DqnJobQueue *const queue); -DQN_FILE_SCOPE bool DqnJobQueue_AllJobsComplete (DqnJobQueue *const queue); - -// XPlatform > #DqnAtomic -// ================================================================================================= -// All atomic operations generate a full read/write barrier. This is implicitly enforced by the -// OS calls, not explicitly in my code. - -// swap_val: The value to put into "dest", IF at point of read, "dest" has the value of "compare_val" -// compare_val: The value to check in "dest" -// return: Return the original value that was in "dest" -DQN_FILE_SCOPE i32 DqnAtomic_CompareSwap32(i32 volatile *const dest, const i32 swap_val, const i32 compare_val); - -// Add "value" to src -// return: The new value at src -DQN_FILE_SCOPE i32 DqnAtomic_Add32(i32 volatile *const src, const i32 value); - -// #Platform Specific -// ================================================================================================= -// Functions here are only available for the #defined sections (i.e. all functions in -// DQN_IS_WIN32 only have a valid implementation in Win32. - -#if defined(DQN_IS_WIN32) -// Platform > #DqnWin32 -// ================================================================================================= -#define DQN__WIN32_ERROR_BOX(text, title) MessageBoxA(nullptr, text, title, MB_OK); - -// The function automatically null-terminates the output string. -// out: A pointer to the buffer to receive the characters. -// out_len: The length/capacity of the buffer "out". If 0, the function returns the required length including null terminator. -// return: -1 if invalid, or if out_len is 0 the required buffer length. -DQN_FILE_SCOPE i32 DqnWin32_UTF8ToWChar(const char *const in, wchar_t *const out, const i32 out_len); -DQN_FILE_SCOPE i32 DqnWin32_WCharToUTF8(const wchar_t *const in, char *const out, const i32 out_len); - -// "width" and "height" are optional and won't be used if not given by user. -// width & height: Pass in a pointer for function to fill out. -DQN_FILE_SCOPE void DqnWin32_GetClientDim (HWND const window, LONG *width, LONG *height); -DQN_FILE_SCOPE void DqnWin32_GetRectDim (RECT const rect, LONG *width, LONG *height); - -DQN_FILE_SCOPE char const *DqnWin32_GetLastError(); - -// TODO(doyle): #deprecate #delete Display Last Error is mostly useless. -// Displays error in the format : in a Win32 Dialog Box. -// err_prefix: The message before the Win32 error, can be nullptr -DQN_FILE_SCOPE void DqnWin32_DisplayLastError (const char *const err_prefix); - -// Asimilar to DqnWin32_DisplayLastError() a particular error can be specified in a Win32 Dialog Box. -DQN_FILE_SCOPE void DqnWin32_DisplayErrorCode (const DWORD error, const char *const err_prefix); - -// Output text to the debug console. For visual studio this is the output window and not the console. -// ...: Variable args alike printf, powered by stb_sprintf -DQN_FILE_SCOPE void DqnWin32_OutputDebugString(const char *const fmt_str, ...); - -DQN_FILE_SCOPE void DqnWin32_GetExeNameAndDirectory(DqnMemStack *allocator, DqnBuffer *exe_name, DqnBuffer *exe_directory); -DQN_FILE_SCOPE u64 DqnWin32_EpochTimeUTC (); -DQN_FILE_SCOPE u64 DqnWin32_EpochTimeLocal (); -#endif // DQN_IS_WIN32 -#endif // DQN_PLATFORM_H -#endif // DQN_PLATFORM_HEADER - - -#ifdef DQN_IMPLEMENTATION -// DQN_IMPLEMENTATION -// ================================================================================================= -#include // TODO(doyle): For trigonometry functions (for now) -#include // For calloc, malloc, free -#include // For printf - -DqnAllocator xallocator_; -DqnAllocator allocator_; -DqnLogger logger_; -DqnLibContext dqn_lib_context_ = {&xallocator_, &allocator_, &logger_}; - -// NOTE: STB_SPRINTF is included when DQN_IMPLEMENTATION defined -// #define STB_SPRINTF_IMPLEMENTATION - -// NOTE: DQN_INI_IMPLEMENTATION modified to be included when DQN_IMPLEMENTATION defined -// #define DQN_INI_IMPLEMENTATION -#define DQN_INI_STRLEN(s) DqnStr_Len(s) - -// #DqnMemory -// ================================================================================================= -// NOTE: All memory allocations in dqn.h go through these functions. So they can -// be rerouted fairly easily especially for platform specific mallocs. -DQN_FILE_SCOPE void *DqnMem_Alloc(usize size) -{ - void *result = malloc(size); - return result; -} - -DQN_FILE_SCOPE void *DqnMem_XAlloc(usize size) -{ - void *result = malloc(size); - DQN_ALWAYS_ASSERT(result); - return result; -} - - -DQN_FILE_SCOPE void *DqnMem_Calloc(usize size) -{ - void *result = calloc(1, size); - return result; -} - -DQN_FILE_SCOPE void *DqnMem_XCalloc(usize size) -{ - void *result = calloc(1, size); - DQN_ALWAYS_ASSERT(result); - return result; -} - -DQN_FILE_SCOPE void DqnMem_Clear(void *memory, u8 clear_val, usize size) -{ - if (memory) - { - DqnMem_Set(memory, clear_val, size); - } -} - -DQN_FILE_SCOPE void *DqnMem_Realloc(void *memory, usize new_size) -{ - void *result = realloc(memory, new_size); - return result; -} - -DQN_FILE_SCOPE void *DqnMem_XRealloc(void *memory, usize new_size) -{ - void *result = realloc(memory, new_size); - DQN_ALWAYS_ASSERT(result); - return result; -} - -DQN_FILE_SCOPE void DqnMem_Free(void *memory) -{ - if (memory) free(memory); -} - -DQN_FILE_SCOPE void DqnMem_Copy(void *dest, void const *src, usize num_bytes_to_copy) -{ - auto *to = (u8 *)dest; - auto *from = (u8 *)src; - for (usize i = 0; i < num_bytes_to_copy; i++) - to[i] = from[i]; -} - -DQN_FILE_SCOPE void *DqnMem_Set(void *dest, u8 value, usize num_bytes_to_set) -{ - auto volatile *ptr = (u8 *)dest; // NOTE: Volatile so memset is not optimised out. - for (usize i = 0; i < num_bytes_to_set; i++) - ptr[i] = value; - - return dest; -} - -DQN_FILE_SCOPE int DqnMem_Cmp(void const *src, void const *dest, usize num_bytes) -{ - auto const *src_ptr = static_cast(src); - auto const *dest_ptr = static_cast(dest); - - usize i; - for (i = 0; i < num_bytes; ++i) - { - if (src_ptr[i] != dest_ptr[i]) - break; - } - - i = DQN_MIN(i, (num_bytes - 1)); - return (src_ptr[i] - dest_ptr[i]); -} - -// #DqnMemTracker -// ================================================================================================= -DQN_FILE_SCOPE void *DqnAllocator::Malloc(size_t size, Dqn::ZeroMem zero) -{ - void *result = nullptr; - switch(this->type) - { - case Type::Default: (zero == Dqn::ZeroMem::Yes) ? result = DqnMem_Alloc(size) : result = DqnMem_Calloc(size); break; - case Type::XAllocator: - { - (zero == Dqn::ZeroMem::Yes) ? result = DqnMem_Alloc(size) : result = DqnMem_Calloc(size); - DQN_ASSERT(result); - } - break; - - case Type::VirtualMemory: - { - #if defined(DQN_PLATFORM_HEADER) - result = DqnOS_VAlloc(size); - #else - DQN_ASSERT_MSG(DQN_INVALID_CODE_PATH, - "Dqn library hasn't been built with the platform header. I don't know how " - "to allocate virtual memory!"); - #endif - } - break; - case Type::DqnMemStack: - { - auto *mem_stack = reinterpret_cast(user_context); - result = DQN_MEMSTACK_PUSH(mem_stack, size); - if (zero == Dqn::ZeroMem::Yes) DqnMem_Clear(result, 0, size); - } - break; - default: DQN_ASSERT_MSG(DQN_INVALID_CODE_PATH, "New context type not handled."); break; - } - return result; -} - -DQN_FILE_SCOPE void *DqnAllocator::Realloc(void *ptr, size_t new_size) -{ - void *result = nullptr; - switch(this->type) - { - case Type::Default: result = DqnMem_Realloc(ptr, new_size); break; - case Type::XAllocator: - { - result = DqnMem_Realloc(ptr, new_size); - DQN_ASSERT(result); - } - break; - case Type::VirtualMemory: DQN_ASSERT_MSG(DQN_INVALID_CODE_PATH, "Realloc is disallowed on virtual memory! Reserve a bigger range!"); break; - case Type::DqnMemStack: - { - auto *mem_stack = reinterpret_cast(user_context); - DqnPtrHeader *ptr_header = mem_stack->tracker.PtrToHeader(static_cast(ptr)); - result = DQN_MEMSTACK_PUSH(mem_stack, new_size); - DqnMem_Copy(result, ptr, ptr_header->alloc_amount); - DQN_LOGGER_W(dqn_lib_context_.logger, "Memory stack used realloc and ptr: %p with: %zu bytes has been lost", ptr, ptr_header->alloc_amount); - } - break; - default: DQN_ASSERT_MSG(DQN_INVALID_CODE_PATH, "New context type not handled."); break; - } - return result; -} - -DQN_FILE_SCOPE void DqnAllocator::Free(void *ptr, size_t old_size) -{ - (void)old_size; - switch(this->type) - { - case Type::XAllocator: - case Type::Default: DqnMem_Free(ptr); break; - case Type::VirtualMemory: - { - #if defined(DQN_PLATFORM_HEADER) - DqnOS_VFree(ptr, old_size); - #else - DQN_ASSERT_MSG(DQN_INVALID_CODE_PATH, - "Dqn library hasn't been built with the platform header. I don't know how to free virtual memory!"); - #endif - } - break; - case Type::DqnMemStack: /*do nothing*/ break; - default: DQN_ASSERT_MSG(DQN_INVALID_CODE_PATH, "New context type not handled."); break; - } -} - -// #DqnMemTracker -// ================================================================================================= -// TODO(doyle): We shouldn't be using the library context for allocations since this is per -// allocator or actually maybe yes? I think we want more granularity then that -void DqnMemTracker::Init(DqnMemTracker::Flag flag) -{ - *this = {}; - this->bounds_guard_size = (flag & DqnMemTracker::BoundsGuard) ? sizeof(HEAD_GUARD_VALUE) : 0; - - if (flag & DqnMemTracker::TrackPtr) - { - this->ptrs_max = 8192; - this->ptrs = (void **)dqn_lib_context_.allocator->Malloc(this->ptrs_max * sizeof(this->ptrs)); - } - - if (flag & DqnMemTracker::TagAllocation) - { - this->tagged_allocs_max = 4096; - this->tagged_allocs = (decltype(this->tagged_allocs))dqn_lib_context_.allocator->Malloc(this->tagged_allocs_max * sizeof(*this->tagged_allocs)); - this->tagged_allocs_used_list = (decltype(this->tagged_allocs_used_list))dqn_lib_context_.allocator->Malloc(this->tagged_allocs_max * sizeof(*this->tagged_allocs_used_list)); - } -} - -void DqnMemTracker::Free() -{ - if (this->IsTaggingAllocations()) - { - DQN_FOR_EACH(i, this->tagged_allocs_used_index) - { - u16 used_index = this->tagged_allocs_used_list[i]; - for (TaggedAllocation *tagged_alloc = this->tagged_allocs[used_index]; tagged_alloc;) - { - TaggedAllocation *tag_to_free = tagged_alloc; - tagged_alloc = tagged_alloc->next; - dqn_lib_context_.allocator->Free(tag_to_free->filename.str, tag_to_free->filename.len); - dqn_lib_context_.allocator->Free(tag_to_free->function.str, tag_to_free->function.len); - dqn_lib_context_.allocator->Free(tag_to_free, sizeof(tag_to_free)); - } - } - } - - if (this->IsTrackingPtrs()) - dqn_lib_context_.allocator->Free(this->ptrs, sizeof(*this->ptrs) * ptrs_max); -} - -void DqnMemTracker::Tag_(DqnBuffer filename, DqnBuffer function, int line_num, DqnBuffer filename_line_num_data, isize bytes) -{ - if (!Dqn::allow_allocation_tagging || !this->IsTaggingAllocations()) - return; - - u16 index = DqnHash_Murmur32(filename_line_num_data.data, filename_line_num_data.len) % this->tagged_allocs_max; - TaggedAllocation **entry = this->tagged_allocs + index; - for (; *entry && (*entry)->filename.len > 0; entry = &((*entry)->next)) - { - if (line_num == (*entry)->line_num && DQN_BUFFER_STRCMP(filename, (*entry)->filename, Dqn::IgnoreCase::Yes)) - break; - } - - if (!(*entry)) - *entry = (TaggedAllocation *)dqn_lib_context_.allocator->Malloc(sizeof(**entry), Dqn::ZeroMem::Yes); - - if ((*entry)->filename.len == 0) - { - this->tagged_allocs_used_list[this->tagged_allocs_used_index++] = index; - (*entry)->filename = DqnBuffer_CopyAndNullTerminate(dqn_lib_context_.allocator, filename.str, filename.len); - (*entry)->function = DqnBuffer_CopyAndNullTerminate(dqn_lib_context_.allocator, function.str, function.len); - (*entry)->line_num = line_num; - } - - (*entry)->bytes_allocated += bytes; - DQN_ALWAYS_ASSERT((*entry)->bytes_allocated >= 0); - - DqnLogger::Context context = {}; - context.filename = (*entry)->filename.str; - context.filename_len = (*entry)->filename.len; - context.function = (*entry)->function.str; - context.function_len = (*entry)->function.len; - context.line_num = line_num; - dqn_lib_context_.logger->Log(DqnLogger::Type::Memory, context, "Currently allocated: %zu bytes", (*entry)->bytes_allocated); -} - -void *DqnMemTracker::SetupPtr(void *ptr, isize size, u8 alignment) -{ - // Calculate the aligned ptr - auto *byte_ptr = static_cast(ptr); - auto *unaligned_result = static_cast(ptr) + sizeof(DqnPtrHeader) + this->bounds_guard_size; - auto *aligned_result = reinterpret_cast(DQN_ALIGN_POW_N(unaligned_result, alignment)); - isize const offset_to_ptr_header = aligned_result - unaligned_result; - DQN_ASSERT(offset_to_ptr_header >= 0 && offset_to_ptr_header <= (alignment - 1)); - - char *check_allignment = reinterpret_cast(DQN_ALIGN_POW_N(aligned_result, alignment)); - DQN_ASSERT_MSG(check_allignment == aligned_result, "Adding bounds guard should not destroy alignment! %p != %p", aligned_result, check_allignment); - // Instrument allocation with guards and tracker - { - auto *ptr_header = reinterpret_cast(byte_ptr + offset_to_ptr_header); - ptr_header->offset_to_src_ptr = static_cast(aligned_result - byte_ptr); - ptr_header->alignment = alignment; - ptr_header->alloc_amount = size; - } - - if (this->IsGuardingBounds()) - { - u32 *head_guard = reinterpret_cast(aligned_result - sizeof(DqnMemTracker::HEAD_GUARD_VALUE)); - u32 *tail_guard = reinterpret_cast(aligned_result + size); - *head_guard = DqnMemTracker::HEAD_GUARD_VALUE; - *tail_guard = DqnMemTracker::TAIL_GUARD_VALUE; - } - - if (this->IsTrackingPtrs()) - { - if (this->ptrs_len + 1 > this->ptrs_max) - { - this->ptrs_max *= 2; - this->ptrs = (void **)DqnMem_XRealloc(this->ptrs, sizeof(this->ptrs) * this->ptrs_max); - } - this->ptrs[this->ptrs_len++] = aligned_result; - this->CheckPtrs(); - } - - return aligned_result; -} - -void DqnMemTracker::RemovePtr(void *ptr) -{ - if (!this->IsTrackingPtrs()) - return; - - DQN_ASSERT(this->ptrs_len > 0); - - b32 found = false; - DQN_FOR_EACH(i, this->ptrs_len) - { - if (this->ptrs[i] == ptr) - { - this->ptrs[i] = this->ptrs[--this->ptrs_len]; - found = true; - break; - } - } - - DQN_ALWAYS_ASSERTM(found, "Ptr %p was not in the tracked pointers list", ptr); -} - -void DqnMemTracker::RemovePtrRange(void *start, void *end) -{ - if (!this->IsTrackingPtrs()) - return; - - if (start >= end) return; - DQN_FOR_EACH(i, this->ptrs_len) - { - void *ptr = this->ptrs[i]; - if (ptr >= start && ptr < end) - this->ptrs[i--] = this->ptrs[--this->ptrs_len]; - } -} - -void DqnMemTracker::CheckPtrs() const -{ - if (!this->IsGuardingBounds()) - return; - - DQN_FOR_EACH(i, this->ptrs_len) - { - char *ptr = static_cast(this->ptrs[i]); - u32 const *head_guard = this->PtrToHeadGuard(ptr); - u32 const *tail_guard = this->PtrToTailGuard(ptr); - - DQN_ASSERT_MSG(*head_guard == HEAD_GUARD_VALUE, - "Bounds guard has been destroyed at the head end of the allocation! Expected: " - "%x, received: %x", - HEAD_GUARD_VALUE, *head_guard); - - DQN_ASSERT_MSG(*tail_guard == TAIL_GUARD_VALUE, - "Bounds guard has been destroyed at the tail end of the allocation! Expected: " - "%x, received: %x", - TAIL_GUARD_VALUE, *tail_guard); - } -} - -// #DqnMemStack -// ================================================================================================= -DQN_FILE_SCOPE DqnMemStack::Block * -DqnMemStack__AllocateBlock(isize size, Dqn::ZeroMem zero, DqnAllocator *allocator) -{ - isize total_size = sizeof(DqnMemStack::Block) + size; - auto *result = static_cast(allocator->Malloc(total_size, zero)); - DQN_ALWAYS_ASSERTM(result, "Allocated memory block was null"); - - char *block_offset = reinterpret_cast(result) + sizeof(*result); - *result = DqnMemStack::Block(block_offset, size); - return result; -} - -DqnMemStack::DqnMemStack(void *mem, isize size, Dqn::ZeroMem clear, u32 flags_, DqnMemTracker::Flag flags) -{ - DQN_ALWAYS_ASSERTM(mem, "Supplied fixed memory buffer is nullptr, initialise with fixed memory failed"); - DQN_ALWAYS_ASSERTM(size > sizeof(DqnMemStack::Block), "[%zu < %zu] Buffer too small for block metadata", size, sizeof(DqnMemStack::Block)); - *this = {}; - - if (clear == Dqn::ZeroMem::Yes) - DqnMem_Set(mem, 0, size); - - char *block_offset = static_cast(mem) + sizeof(*this->block); - isize const block_size = size - sizeof(*this->block); - - this->block = static_cast(mem); - *this->block = Block(block_offset, block_size); - this->flags = (flags_ | Flag::NonExpandable); - this->tracker.Init(flags); -} - -void DqnMemStack::LazyInit(isize size, Dqn::ZeroMem clear, u32 flags_, DqnMemTracker::Flag tracker_flags, DqnAllocator *block_allocator_) -{ - DQN_ALWAYS_ASSERTM(size > 0, "%zu <= 0", size); - *this = {}; - this->block = DqnMemStack__AllocateBlock(size, clear, block_allocator_); - this->flags = flags_; - this->block_allocator = block_allocator_; - this->tracker.Init(tracker_flags); -} - -void *DqnMemStack::Push_(usize size, PushType push_type, u8 alignment) -{ - DQN_ASSERT(size >= 0 && (alignment % 2 == 0)); - DQN_ALWAYS_ASSERTM(alignment <= 128, "Alignment _not_ supported. Update metadata to use u16 for storing the offset!"); - - if (size == 0) - return nullptr; - - if (!this->block) - this->LazyInit(MINIMUM_BLOCK_SIZE, Dqn::ZeroMem::Yes); - - usize size_to_alloc = this->tracker.GetAllocationSize(size, alignment); - bool push_to_head = true; - if (push_type == PushType::Default || push_type == PushType::Opposite) - { - push_to_head = !(this->flags & Flag::DefaultAllocateTail); - if (push_type == PushType::Opposite) push_to_head = !push_to_head; - } - else - { - push_to_head = (push_type == PushType::Head); - } - - - // Allocate New Block If Full - // ============================================================================================= - bool need_new_block = true; - if (push_to_head) need_new_block = ((this->block->head + size_to_alloc) > this->block->tail); - else need_new_block = ((this->block->tail - size_to_alloc) < this->block->head); - - if (need_new_block) - { - if ((this->flags & Flag::NonExpandable) && this->block) - { - DQN_ASSERT_MSG(!(this->flags & Flag::NonExpandableAssert), "Allocator is non-expandable and has run out of memory"); - return nullptr; - } - - isize new_block_size = DQN_MAX(size_to_alloc, MINIMUM_BLOCK_SIZE); - Block *new_block = DqnMemStack__AllocateBlock(new_block_size, Dqn::ZeroMem::No, this->block_allocator); - new_block->prev_block = this->block; - this->block = new_block; - } - - // Calculate Ptr To Give Client - // ============================================================================================= - char *src_ptr = (push_to_head) ? (this->block->head) : (this->block->tail - size_to_alloc); - void *aligned_result = this->tracker.SetupPtr(src_ptr, size, alignment); - this->tracker.PtrToHeader((char *)aligned_result)->alloc_type = (push_to_head) ? 0 : 1; - - if (push_to_head) - { - this->block->head += size_to_alloc; - DQN_ASSERT(this->block->head <= this->block->tail); - } - else - { - this->block->tail -= size_to_alloc; - DQN_ASSERT(this->block->tail >= this->block->head); - } - - return aligned_result; -} - -void DqnMemStack::Pop(void *ptr, Dqn::ZeroMem clear) -{ - if (!ptr) return; - - char *byte_ptr = static_cast(ptr); - DqnPtrHeader *ptr_header = reinterpret_cast(byte_ptr - sizeof(*ptr_header) - this->tracker.bounds_guard_size); - - // Check instrumented data - this->tracker.CheckPtrs(); - this->tracker.RemovePtr(byte_ptr); - - isize full_alloc_size = this->tracker.GetAllocationSize(ptr_header->alloc_amount, ptr_header->alignment); - char *start = byte_ptr - ptr_header->offset_to_src_ptr; - char *end = start + full_alloc_size; - char const *block_end = this->block->memory + this->block->size; - - if (ptr_header->alloc_type == 0) - { - DQN_ASSERT_MSG(end == this->block->head, "Pointer to pop was not the last allocation! %p != %p", end, this->block->head); - this->block->head -= full_alloc_size; - DQN_ASSERT(this->block->head >= this->block->memory); - } - else - { - DQN_ASSERT_MSG(start == this->block->tail, "Pointer to pop was not the last allocation! %p != %p", start, this->block->tail); - this->block->tail += full_alloc_size; - DQN_ASSERT(this->block->tail <= block_end); - } - - 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->PopBlock(); - } -} - -bool DqnMemStack::FreeBlock(DqnMemStack::Block *mem_block) -{ - if (!mem_block || !this->block) - return false; - - DqnMemStack::Block **block_ptr = &this->block; - - while (*block_ptr && (*block_ptr) != mem_block) - block_ptr = &((*block_ptr)->prev_block); - - if (*block_ptr) - { - DqnMemStack::Block *block_to_free = *block_ptr; - (*block_ptr) = block_to_free->prev_block; - - this->tracker.RemovePtrRange(block_to_free->memory, block_to_free->memory + block_to_free->size); - isize real_size = block_to_free->size + sizeof(DqnMemStack::Block); - this->block_allocator->Free(block_to_free, real_size); - - // No more blocks, then last block has been freed - if (!this->block) DQN_ASSERT(this->mem_region_count == 0); - return true; - } - - return false; -} - -void DqnMemStack::ResetTail() -{ - char *start = this->block->tail; - char *end = this->block->memory + this->block->size; - this->tracker.RemovePtrRange(start, end); - this->block->tail = end; -} - -void DqnMemStack::ClearCurrBlock(Dqn::ZeroMem zero) -{ - if (this->block) - { - this->tracker.RemovePtrRange(this->block->memory, this->block->memory + this->block->size); - this->block->head = this->block->memory; - this->block->tail = this->block->memory + this->block->size; - if (zero == Dqn::ZeroMem::Yes) - { - DqnMem_Clear(this->block->memory, 0, this->block->size); - } - } -} - -DqnMemStack::Info DqnMemStack::GetInfo() const -{ - Info result = {}; - for (Block *block_ = this->block; block_; block_ = block_->prev_block) - { - char const *block_end = block_->memory + block_->size; - isize usage_from_head = block_->head - block_->memory; - isize usage_from_tail = block_end - block_->tail; - - result.total_used += usage_from_head + usage_from_tail; - result.total_size += block_->size; - result.wasted_size += (block_->size - usage_from_head - usage_from_tail); - result.num_blocks++; - } - - char const *block_end = this->block->memory + this->block->size; - isize usage_from_head = this->block->head - this->block->memory; - isize usage_from_tail = block_end - this->block->tail; - result.wasted_size -= (this->block->size - usage_from_head - usage_from_tail); // Don't include the curr block - - return result; -} - -DqnMemStack::MemRegion DqnMemStack::MemRegionBegin() -{ - 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->mem_region_count++; - return result; -} - -void DqnMemStack::MemRegionEnd(MemRegion region) -{ - DQN_ASSERT(region.stack == this); - - this->mem_region_count--; - DQN_ASSERT(this->mem_region_count >= 0); - - while (this->block != region.starting_block) - this->PopBlock(); - - if (this->block) - { - this->block->head = region.starting_block_head; - this->block->tail = region.starting_block_tail; - - char *start = this->block->head; - char *end = this->block->tail; - this->tracker.RemovePtrRange(start, end); - } -} - -void DqnMemStack::MemRegionSave(MemRegion *region) -{ - DQN_ASSERT(region->stack == this); - region->stack = nullptr; - this->mem_region_count--; - DQN_ASSERT(this->mem_region_count >= 0); -} - -// #DqnHash -// ================================================================================================= -// Taken from GingerBill single file library @ github.com/gingerbill/gb -u32 DqnHash_Murmur32Seed(void const *data, usize len, u32 seed) -{ - u32 const c1 = 0xcc9e2d51; u32 const c2 = 0x1b873593; u32 const r1 = 15; - u32 const r2 = 13; u32 const m = 5; u32 const n = 0xe6546b64; - - usize i, nblocks = len / 4; - u32 hash = seed, k1 = 0; - u32 const *blocks = (u32 const *)data; - u8 const *tail = (u8 const *)(data) + nblocks * 4; - - for (i = 0; i < nblocks; i++) { - u32 k = blocks[i]; - k *= c1; - k = (k << r1) | (k >> (32 - r1)); - k *= c2; - - hash ^= k; - hash = ((hash << r2) | (hash >> (32 - r2))) * m + n; - } - - switch (len & 3) { - case 3: k1 ^= tail[2] << 16; - case 2: k1 ^= tail[1] << 8; - case 1: k1 ^= tail[0]; - - k1 *= c1; - k1 = (k1 << r1) | (k1 >> (32 - r1)); - k1 *= c2; - hash ^= k1; - } - - hash ^= len; hash ^= (hash >> 16); - hash *= 0x85ebca6b; hash ^= (hash >> 13); - hash *= 0xc2b2ae35; hash ^= (hash >> 16); - - return hash; -} - -u64 DqnHash_Murmur64Seed(void const *data_, usize len, u64 seed) -{ - u64 const m = 0xc6a4a7935bd1e995ULL; - i32 const r = 47; - - u64 h = seed ^ (len * m); - - u64 const *data = (u64 const *)data_; - u8 const *data2 = (u8 const *)data_; - u64 const *end = data + (len / 8); - - while (data != end) { - u64 k = *data++; - k *= m; k ^= k >> r; k *= m; - h ^= k; h *= m; - } - - switch (len & 7) { - case 7: h ^= (u64)(data2[6]) << 48; - case 6: h ^= (u64)(data2[5]) << 40; - case 5: h ^= (u64)(data2[4]) << 32; - case 4: h ^= (u64)(data2[3]) << 24; - case 3: h ^= (u64)(data2[2]) << 16; - case 2: h ^= (u64)(data2[1]) << 8; - case 1: h ^= (u64)(data2[0]); - h *= m; - }; - - h ^= h >> r; h *= m; h ^= h >> r; - return h; -} - -// #DqnMath -// ================================================================================================= -DQN_FILE_SCOPE f32 DqnMath_Lerp(f32 a, f32 t, f32 b) -{ - /* - Linear blend between two values. We having a starting point "a", and - the distance to "b" is defined as (b - a). Then we can say - - a + t(b - a) - - As our linear blend fn. We start from "a" and choosing a t from 0->1 - will vary the value of (b - a) towards b. If we expand this, this - becomes - - a + (t * b) - (a * t) == (1 - t)a + t*b - */ - f32 result = a + (b - a) * t; - return result; -} - -DQN_FILE_SCOPE f32 DqnMath_Sqrtf(f32 a) -{ - f32 result = sqrtf(a); - return result; -} - -DQN_FILE_SCOPE f32 DqnMath_Clampf(f32 val, f32 min, f32 max) -{ - if (val < min) return min; - if (val > max) return max; - return val; -} - -// #DqnV2 -// ================================================================================================= -DQN_FILE_SCOPE DqnV2 DqnV2_Add(DqnV2 a, DqnV2 b) -{ - DqnV2 result = {}; - for (u32 i = 0; i < DQN_ARRAY_COUNT(a.e); i++) - result.e[i] = a.e[i] + b.e[i]; - - return result; -} - -DQN_FILE_SCOPE DqnV2 DqnV2_Sub(DqnV2 a, DqnV2 b) -{ - DqnV2 result = {}; - for (u32 i = 0; i < DQN_ARRAY_COUNT(a.e); i++) - result.e[i] = a.e[i] - b.e[i]; - - return result; -} - -DQN_FILE_SCOPE DqnV2 DqnV2_Scalei(DqnV2 a, i32 b) -{ - DqnV2 result = {}; - for (u32 i = 0; i < DQN_ARRAY_COUNT(a.e); i++) - result.e[i] = a.e[i] * b; - - return result; -} - -DQN_FILE_SCOPE DqnV2 DqnV2_Scalef(DqnV2 a, f32 b) -{ - DqnV2 result = {}; - for (u32 i = 0; i < DQN_ARRAY_COUNT(a.e); i++) - result.e[i] = a.e[i] * b; - - return result; -} - -DQN_FILE_SCOPE DqnV2 DqnV2_Hadamard(DqnV2 a, DqnV2 b) -{ - DqnV2 result = {}; - for (u32 i = 0; i < DQN_ARRAY_COUNT(a.e); i++) - result.e[i] = a.e[i] * b.e[i]; - - return result; -} - -DQN_FILE_SCOPE f32 DqnV2_Dot(DqnV2 a, DqnV2 b) -{ - /* - DOT PRODUCT - Two vectors with dot product equals |a||b|cos(theta) - |a| |d| - |b| . |e| = (ad + be + cf) - |c| |f| - */ - f32 result = 0; - for (u32 i = 0; i < DQN_ARRAY_COUNT(a.e); i++) - result += (a.e[i] * b.e[i]); - - return result; -} - -DQN_FILE_SCOPE bool DqnV2_Equals(DqnV2 a, DqnV2 b) -{ - bool result = true; - for (u32 i = 0; i < DQN_ARRAY_COUNT(a.e); i++) - if (a.e[i] != b.e[i]) result = false; - return result; -} - -DQN_FILE_SCOPE f32 DqnV2_LengthSquared(DqnV2 a, DqnV2 b) -{ - f32 x_ = b.x - a.x; - f32 y_ = b.y - a.y; - f32 result = (DQN_SQUARED(x_) + DQN_SQUARED(y_)); - return result; -} - -DQN_FILE_SCOPE f32 DqnV2_Length(DqnV2 a, DqnV2 b) -{ - f32 len_sq = DqnV2_LengthSquared(a, b); - if (len_sq == 0) return 0; - - f32 result = DqnMath_Sqrtf(len_sq); - return result; -} - -DQN_FILE_SCOPE DqnV2 DqnV2_Normalise(DqnV2 a) -{ - f32 magnitude = DqnV2_Length(DqnV2(0, 0), a); - if (magnitude == 0) return DqnV2(0.0f); - - DqnV2 result = a * (1.0f / magnitude); - return result; -} - -DQN_FILE_SCOPE bool DqnV2_Overlaps(DqnV2 a, DqnV2 b) -{ - bool result = false; - - f32 lenOfA = a.max - a.min; - f32 lenOfB = b.max - b.min; - - if (lenOfA > lenOfB) - { - DqnV2 tmp = a; - a = b; - b = tmp; - } - - if ((a.min >= b.min && a.min <= b.max) || (a.max >= b.min && a.max <= b.max)) - { - result = true; - } - - return result; -} - -DQN_FILE_SCOPE DqnV2 DqnV2_Perpendicular(DqnV2 a) -{ - DqnV2 result = DqnV2(a.y, -a.x); - return result; -} - -DQN_FILE_SCOPE DqnV2 DqnV2_ResizeKeepAspectRatio(DqnV2 src_size, DqnV2 target_size) -{ - f32 ratio_a = src_size.w / target_size.w; - f32 ratio_b = src_size.h / target_size.h; - f32 ratio = DQN_MIN(ratio_a, ratio_b); - DqnV2 result = DqnV2_Scalef(target_size, ratio); - return result; -} - -DQN_FILE_SCOPE DqnV2 DqnV2_ConstrainToRatio(DqnV2 dim, DqnV2 ratio) -{ - DqnV2 result = {0}; - f32 num_ratio_increments_to_width = (f32)(dim.w / ratio.w); - f32 num_ratio_increments_to_height = (f32)(dim.h / ratio.h); - - f32 least_increments_to_side = - DQN_MIN(num_ratio_increments_to_height, num_ratio_increments_to_width); - - result.w = (f32)(ratio.w * least_increments_to_side); - result.h = (f32)(ratio.h * least_increments_to_side); - return result; -} - -// #DqnV2i -// ================================================================================================= -DQN_FILE_SCOPE DqnV2i DqnV2i_Add(DqnV2i a, DqnV2i b) -{ - DqnV2i result = {}; - for (u32 i = 0; i < DQN_ARRAY_COUNT(a.e); i++) - result.e[i] = a.e[i] + b.e[i]; - - return result; -} - -DQN_FILE_SCOPE DqnV2i DqnV2i_Sub(DqnV2i a, DqnV2i b) -{ - DqnV2i result = {}; - for (u32 i = 0; i < DQN_ARRAY_COUNT(a.e); i++) - result.e[i] = a.e[i] - b.e[i]; - - return result; -} - -DQN_FILE_SCOPE DqnV2i DqnV2i_Scalef(DqnV2i a, f32 b) -{ - DqnV2i result = {}; - for (u32 i = 0; i < DQN_ARRAY_COUNT(a.e); i++) - result.e[i] = (i32)(a.e[i] * b); - - return result; -} - -DQN_FILE_SCOPE DqnV2i DqnV2i_Scalei(DqnV2i a, i32 b) -{ - DqnV2i result = {}; - for (u32 i = 0; i < DQN_ARRAY_COUNT(a.e); i++) - result.e[i] = a.e[i] * b; - - return result; -} - -DQN_FILE_SCOPE DqnV2i DqnV2i_Hadamard(DqnV2i a, DqnV2i b) -{ - DqnV2i result = {}; - for (u32 i = 0; i < DQN_ARRAY_COUNT(a.e); i++) - result.e[i] = a.e[i] * b.e[i]; - - return result; -} - -DQN_FILE_SCOPE f32 DqnV2i_Dot(DqnV2i a, DqnV2i b) -{ - /* - DOT PRODUCT - Two vectors with dot product equals |a||b|cos(theta) - |a| |d| - |b| . |e| = (ad + be + cf) - |c| |f| - */ - f32 result = 0; - for (u32 i = 0; i < DQN_ARRAY_COUNT(a.e); i++) - result += (a.e[i] * b.e[i]); - - return result; -} - -DQN_FILE_SCOPE bool DqnV2i_Equals(DqnV2i a, DqnV2i b) -{ - bool result = true; - for (u32 i = 0; i < DQN_ARRAY_COUNT(a.e); i++) - if (a.e[i] != b.e[i]) result = false; - return result; -} - -// #DqnV3 -// ================================================================================================= -DQN_FILE_SCOPE DqnV3 DqnV3_Add(DqnV3 a, DqnV3 b) -{ - DqnV3 result = {0}; - for (u32 i = 0; i < DQN_ARRAY_COUNT(a.e); i++) - result.e[i] = a.e[i] + b.e[i]; - - return result; -} - -DQN_FILE_SCOPE DqnV3 DqnV3_Sub(DqnV3 a, DqnV3 b) -{ - DqnV3 result = {0}; - for (u32 i = 0; i < DQN_ARRAY_COUNT(a.e); i++) - result.e[i] = a.e[i] - b.e[i]; - - return result; -} - -DQN_FILE_SCOPE DqnV3 DqnV3_Scalei(DqnV3 a, i32 b) -{ - DqnV3 result = {0}; - for (u32 i = 0; i < DQN_ARRAY_COUNT(a.e); i++) - result.e[i] = a.e[i] * b; - - return result; -} - -DQN_FILE_SCOPE DqnV3 DqnV3_Scalef(DqnV3 a, f32 b) -{ - DqnV3 result = {0}; - for (u32 i = 0; i < DQN_ARRAY_COUNT(a.e); i++) - result.e[i] = a.e[i] * b; - - return result; -} - -DQN_FILE_SCOPE DqnV3 DqnV3_Hadamard(DqnV3 a, DqnV3 b) -{ - DqnV3 result = {0}; - for (u32 i = 0; i < DQN_ARRAY_COUNT(a.e); i++) - result.e[i] = a.e[i] * b.e[i]; - - return result; -} - -DQN_FILE_SCOPE f32 DqnV3_Dot(DqnV3 a, DqnV3 b) -{ - /* - DOT PRODUCT - Two vectors with dot product equals |a||b|cos(theta) - |a| |d| - |b| . |e| = (ad + be + cf) - |c| |f| - */ - f32 result = 0; - for (u32 i = 0; i < DQN_ARRAY_COUNT(a.e); i++) - result += (a.e[i] * b.e[i]); - - return result; -} - -DQN_FILE_SCOPE bool DqnV3_Equals(DqnV3 a, DqnV3 b) -{ - bool result = true; - for (u32 i = 0; i < DQN_ARRAY_COUNT(a.e); i++) - if (a.e[i] != b.e[i]) result = false; - return result; -} - -DQN_FILE_SCOPE DqnV3 DqnV3_Cross(DqnV3 a, DqnV3 b) -{ - /* - CROSS PRODUCT - Generate a perpendicular vector to the 2 vectors - |a| |d| |bf - ce| - |b| x |e| = |cd - af| - |c| |f| |ae - be| - */ - DqnV3 result = {0}; - result.e[0] = (a.e[1] * b.e[2]) - (a.e[2] * b.e[1]); - result.e[1] = (a.e[2] * b.e[0]) - (a.e[0] * b.e[2]); - result.e[2] = (a.e[0] * b.e[1]) - (a.e[1] * b.e[0]); - return result; -} - -DQN_FILE_SCOPE DqnV3 DqnV3_Normalise(DqnV3 a) -{ - f32 length = DqnMath_Sqrtf(DQN_SQUARED(a.x) + DQN_SQUARED(a.y) + DQN_SQUARED(a.z)); - f32 inv_len = 1 / length; - DqnV3 result = a * inv_len; - - return result; -} - -DQN_FILE_SCOPE f32 DqnV3_LengthSquared(DqnV3 a, DqnV3 b) -{ - f32 x = b.x - a.x; - f32 y = b.y - a.y; - f32 z = b.z - a.z; - f32 result = (DQN_SQUARED(x) + DQN_SQUARED(y) + DQN_SQUARED(z)); - return result; -} - -DQN_FILE_SCOPE f32 DqnV3_Length(DqnV3 a, DqnV3 b) -{ - f32 len_sq = DqnV3_LengthSquared(a, b); - if (len_sq == 0) return 0; - - f32 result = DqnMath_Sqrtf(len_sq); - return result; -} - -// #DqnV4 -// ================================================================================================= -DQN_FILE_SCOPE DqnV4 DqnV4_Add(DqnV4 a, DqnV4 b) -{ - DqnV4 result = {0}; - for (u32 i = 0; i < DQN_ARRAY_COUNT(a.e); i++) - result.e[i] = a.e[i] + b.e[i]; - - return result; -} - -DQN_FILE_SCOPE DqnV4 DqnV4_Sub(DqnV4 a, DqnV4 b) -{ - DqnV4 result = {0}; - for (u32 i = 0; i < DQN_ARRAY_COUNT(a.e); i++) - result.e[i] = a.e[i] - b.e[i]; - - return result; -} - -DQN_FILE_SCOPE DqnV4 DqnV4_Scalei(DqnV4 a, i32 b) -{ - DqnV4 result = {0}; - for (u32 i = 0; i < DQN_ARRAY_COUNT(a.e); i++) - result.e[i] = a.e[i] * b; - - return result; -} - -DQN_FILE_SCOPE DqnV4 DqnV4_Scalef(DqnV4 a, f32 b) -{ - DqnV4 result = {0}; - for (u32 i = 0; i < DQN_ARRAY_COUNT(a.e); i++) - result.e[i] = a.e[i] * b; - - return result; -} - -DQN_FILE_SCOPE DqnV4 DqnV4_Hadamard(DqnV4 a, DqnV4 b) -{ - DqnV4 result = {0}; - for (u32 i = 0; i < DQN_ARRAY_COUNT(a.e); i++) - result.e[i] = a.e[i] * b.e[i]; - - return result; -} - -DQN_FILE_SCOPE f32 DqnV4_Dot(DqnV4 a, DqnV4 b) -{ - /* - DOT PRODUCT - Two vectors with dot product equals |a||b|cos(theta) - |a| |d| - |b| . |e| = (ad + be + cf) - |c| |f| - */ - f32 result = 0; - for (u32 i = 0; i < DQN_ARRAY_COUNT(a.e); i++) - result += (a.e[i] * b.e[i]); - - return result; -} - -DQN_FILE_SCOPE bool DqnV4_Equals(DqnV4 a, DqnV4 b) -{ - bool result = true; - for (u32 i = 0; i < DQN_ARRAY_COUNT(a.e); i++) - if (a.e[i] != b.e[i]) result = false; - return result; -} - -// #DqnMat4 Implementation -// ================================================================================================= -DQN_FILE_SCOPE DqnMat4 DqnMat4_Identity() -{ - DqnMat4 result = {0, 0, 0, 0}; - result.e[0][0] = 1; - result.e[1][1] = 1; - result.e[2][2] = 1; - result.e[3][3] = 1; - return result; -} - -DQN_FILE_SCOPE DqnMat4 DqnMat4_Orthographic(f32 left, f32 right, f32 bottom, f32 top, f32 znear, - f32 zfar) -{ - DqnMat4 result = DqnMat4_Identity(); - result.e[0][0] = +2.0f / (right - left); - result.e[1][1] = +2.0f / (top - bottom); - result.e[2][2] = -2.0f / (zfar - znear); - - result.e[3][0] = -(right + left) / (right - left); - result.e[3][1] = -(top + bottom) / (top - bottom); - result.e[3][2] = -(zfar + znear) / (zfar - znear); - - return result; -} - -DQN_FILE_SCOPE DqnMat4 DqnMat4_Perspective(f32 fov_y_degrees, f32 aspect_ratio, f32 znear, f32 zfar) -{ - f32 fov_y_radians = DQN_DEGREES_TO_RADIANS(fov_y_degrees); - f32 fov_y_radians_over_2 = fov_y_radians * 0.5f; - f32 tan_fov_y_radians_over_2 = tanf(fov_y_radians_over_2); - f32 znear_sub_zfar = znear - zfar; - - DqnMat4 result = DqnMat4_Identity(); - result.e[0][0] = 1.0f / (aspect_ratio * tan_fov_y_radians_over_2); - result.e[1][1] = 1.0f / tan_fov_y_radians_over_2; - result.e[2][2] = (znear + zfar) / znear_sub_zfar; - result.e[2][3] = -1.0f; - result.e[3][2] = (2.0f * znear * zfar) / znear_sub_zfar; - result.e[3][3] = 0.0f; - - return result; -} - -DQN_FILE_SCOPE DqnMat4 DqnMat4_LookAt(DqnV3 eye, DqnV3 center, DqnV3 up) -{ - DqnMat4 result = {0, 0, 0, 0}; - - DqnV3 f = DqnV3_Normalise(DqnV3_Sub(eye, center)); - DqnV3 s = DqnV3_Normalise(DqnV3_Cross(up, f)); - DqnV3 u = DqnV3_Cross(f, s); - - result.e[0][0] = s.x; - result.e[0][1] = u.x; - result.e[0][2] = -f.x; - - result.e[1][0] = s.y; - result.e[1][1] = u.y; - result.e[1][2] = -f.y; - - result.e[2][0] = s.z; - result.e[2][1] = u.z; - result.e[2][2] = -f.z; - - result.e[3][0] = -DqnV3_Dot(s, eye); - result.e[3][1] = -DqnV3_Dot(u, eye); - result.e[3][2] = DqnV3_Dot(f, eye); - result.e[3][3] = 1.0f; - return result; -} - -DQN_FILE_SCOPE DqnMat4 DqnMat4_Translate3f(f32 x, f32 y, f32 z) -{ - DqnMat4 result = DqnMat4_Identity(); - result.e[3][0] = x; - result.e[3][1] = y; - result.e[3][2] = z; - return result; -} - -DQN_FILE_SCOPE DqnMat4 DqnMat4_TranslateV3(DqnV3 vec) -{ - DqnMat4 result = DqnMat4_Identity(); - result.e[3][0] = vec.x; - result.e[3][1] = vec.y; - result.e[3][2] = vec.z; - return result; -} - -DQN_FILE_SCOPE DqnMat4 DqnMat4_Rotate(f32 radians, f32 x, f32 y, f32 z) -{ - DqnMat4 result = DqnMat4_Identity(); - f32 sin_val = sinf(radians); - f32 cos_val = cosf(radians); - f32 one_minux_cos_val = 1 - cos_val; - - DqnV3 axis = DqnV3_Normalise(DqnV3(x, y, z)); - - result.e[0][0] = (axis.x * axis.x * one_minux_cos_val) + cos_val; - result.e[0][1] = (axis.x * axis.y * one_minux_cos_val) + (axis.z * sin_val); - result.e[0][2] = (axis.x * axis.z * one_minux_cos_val) - (axis.y * sin_val); - - result.e[1][0] = (axis.y * axis.x * one_minux_cos_val) - (axis.z * sin_val); - result.e[1][1] = (axis.y * axis.y * one_minux_cos_val) + cos_val; - result.e[1][2] = (axis.y * axis.z * one_minux_cos_val) + (axis.x * sin_val); - - result.e[2][0] = (axis.z * axis.x * one_minux_cos_val) + (axis.y * sin_val); - result.e[2][1] = (axis.z * axis.y * one_minux_cos_val) - (axis.x * sin_val); - result.e[2][2] = (axis.z * axis.z * one_minux_cos_val) + cos_val; - - return result; -} - -DQN_FILE_SCOPE DqnMat4 DqnMat4_Scale(f32 x, f32 y, f32 z) -{ - DqnMat4 result = {0, 0, 0, 0}; - result.e[0][0] = x; - result.e[1][1] = y; - result.e[2][2] = z; - result.e[3][3] = 1; - return result; -} - -DQN_FILE_SCOPE DqnMat4 DqnMat4_ScaleV3(DqnV3 scale) -{ - DqnMat4 result = {0, 0, 0, 0}; - result.e[0][0] = scale.x; - result.e[1][1] = scale.y; - result.e[2][2] = scale.z; - result.e[3][3] = 1; - return result; -} - -DQN_FILE_SCOPE DqnMat4 DqnMat4_Mul(DqnMat4 a, DqnMat4 b) -{ - DqnMat4 result = {0}; - for (u32 j = 0; j < 4; j++) { - for (u32 i = 0; i < 4; i++) - { - result.e[j][i] = a.e[0][i] * b.e[j][0] - + a.e[1][i] * b.e[j][1] - + a.e[2][i] * b.e[j][2] - + a.e[3][i] * b.e[j][3]; - } - } - - return result; -} - -DQN_FILE_SCOPE DqnV4 DqnMat4_MulV4(DqnMat4 a, DqnV4 b) -{ - DqnV4 result = {0}; - result.x = (a.e[0][0] * b.x) + (a.e[1][0] * b.y) + (a.e[2][0] * b.z) + (a.e[3][0] * b.w); - result.y = (a.e[0][1] * b.x) + (a.e[1][1] * b.y) + (a.e[2][1] * b.z) + (a.e[3][1] * b.w); - result.z = (a.e[0][2] * b.x) + (a.e[1][2] * b.y) + (a.e[2][2] * b.z) + (a.e[3][2] * b.w); - result.w = (a.e[0][3] * b.x) + (a.e[1][3] * b.y) + (a.e[2][3] * b.z) + (a.e[3][3] * b.w); - - return result; -} - -// #DqnRect Implementation -// ================================================================================================= -void DqnRect::GetSize(f32 *width, f32 *height) const -{ - DQN_ASSERT(this->min <= this->max); - if (width) *width = this->max.x - this->min.x; - if (height) *height = this->max.y - this->min.y; -} - -DqnV2 DqnRect::GetCenter() const -{ - DQN_ASSERT(this->min <= this->max); - f32 sumX = this->min.x + this->max.x; - f32 sumY = this->min.y + this->max.y; - DqnV2 result = DqnV2(sumX, sumY) * 0.5f; - return result; -} - -DqnRect DqnRect::ClipRect(DqnRect clip) const -{ - DQN_ASSERT(this->min <= this->max); - DQN_ASSERT(clip.min <= clip.max); - DqnRect result = *this; - - if (clip.min.x > this->min.x && clip.min.x < this->max.x) - { - if (clip.min.y > this->min.y && clip.min.y < this->max.y) - { - result.min = clip.min; - } - else if (clip.max.y > this->min.y) - { - result.min.x = clip.min.x; - } - } - - if (clip.max.x > this->min.x && clip.max.x < this->max.x) - { - if (clip.max.y > this->min.y && clip.max.y < this->max.y) - { - result.max = clip.max; - } - else if (clip.min.y < this->max.y) - { - result.max.x = clip.max.x; - } - } - - return result; -} - -DqnRect DqnRect::Move(DqnV2 shift) const -{ - DQN_ASSERT(this->min <= this->max); - - DqnRect result; - result.min = this->min + shift; - result.max = this->max + shift; - return result; -} - -bool DqnRect::ContainsP(DqnV2 p) const -{ - DQN_ASSERT(this->min <= this->max); - - bool outside_of_rect_x = false; - if (p.x < this->min.x || p.x > this->max.w) - outside_of_rect_x = true; - - bool outside_of_rect_y = false; - if (p.y < this->min.y || p.y > this->max.h) - outside_of_rect_y = true; - - if (outside_of_rect_x || outside_of_rect_y) return false; - - return true; -} - -// #DqnChar Implementation -// ================================================================================================= -DQN_FILE_SCOPE char DqnChar_ToLower(char c) -{ - if (c >= 'A' && c <= 'Z') - { - i32 shift_offset = 'a' - 'A'; - return (c + (char)shift_offset); - } - return c; -} - -DQN_FILE_SCOPE char DqnChar_ToUpper(char c) -{ - if (c >= 'a' && c <= 'z') - { - i32 shift_offset = 'a' - 'A'; - return (c - (char)shift_offset); - } - return c; -} - -DQN_FILE_SCOPE bool DqnChar_IsEndOfLine(char c) -{ - bool result = (c == '\n'); - return result; -} - -DQN_FILE_SCOPE bool DqnChar_IsWhitespace(char c) -{ - bool result = (c == ' ' || c == '\r' || c == '\n' || c == '\t'); - return result; -} - -DQN_FILE_SCOPE char *DqnChar_TrimWhitespaceAround(char const *src, i32 src_len, i32 *new_len) -{ - if (!src) return nullptr; - if (src_len < 0) return (char *)src; - - char const *start = src; - char const *end = start + (src_len - 1); - while(start[0] && DqnChar_IsWhitespace(start[0])) - { - start++; - } - - i32 chars_skipped = (i32)(start - src); - i32 updated_len = src_len - chars_skipped; - if (updated_len <= 0) - { - if (new_len) *new_len = 0; - return nullptr; - } - - while(end[0] && DqnChar_IsWhitespace(end[0])) - { - end--; - } - - chars_skipped = (i32)((src + src_len - 1) - end); - updated_len = updated_len - chars_skipped; - - if (new_len) *new_len = updated_len; - return (char *)start; -} - -DQN_FILE_SCOPE bool DqnChar_IsDigit(char c) -{ - if (c >= '0' && c <= '9') return true; - return false; -} - -DQN_FILE_SCOPE bool DqnChar_IsAlpha(char c) -{ - if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')) return true; - return false; -} - -DQN_FILE_SCOPE bool DqnChar_IsAlphaNum(char c) -{ - if (DqnChar_IsAlpha(c) || DqnChar_IsDigit(c)) return true; - return false; -} - -DQN_FILE_SCOPE char *DqnChar_SkipWhitespace(char const *ptr) -{ - while (ptr && (*ptr == ' ' || *ptr == '\r' || *ptr == '\n' || *ptr == '\t')) ptr++; - return (char *)ptr; -} - -DQN_FILE_SCOPE char *DqnChar_FindLastChar(char *ptr, char ch, i32 len, u32 *len_to_char) -{ - for (i32 i = len - 1; i >= 0; i--) - { - if (ptr[i] == ch) - { - if (len_to_char) *len_to_char = (u32)len - i; - return &ptr[i]; - } - } - - return nullptr; -} - -DQN_FILE_SCOPE char *Dqn_EatLine(char **input, int *line_len) -{ - *input = DqnChar_SkipWhitespace(*input); - char *result = *input; - - for (int rune_len = -1;; rune_len = -1) - { - u32 rune = 0; - for (; rune_len != 0 && rune_len != 1; *input += rune_len) - rune_len = DqnStr_ReadUTF8Codepoint(reinterpret_cast(*input), &rune); - - if (rune_len == 1) - { - if (rune == '\r' || rune == '\n') - { - char *ptr_to_rune = (*input - rune_len); - *ptr_to_rune = 0; - if (line_len) *line_len = static_cast(ptr_to_rune - result); - return result; - } - } - else if (rune_len == 0) - { - if (line_len) *line_len = static_cast(*input - result); - *input = nullptr; - return result; - } - } -} - -DQN_FILE_SCOPE wchar_t *Dqn_EatLine(wchar_t **input, int *line_len) -{ - *input = DqnWChar_SkipWhitespace(*input); - wchar_t *result = *input; - - for (;; (*input)++) - { - if (!(*input)) - { - if (line_len) *line_len = static_cast(*input - result); - return result; - } - - wchar_t ch = (*input)[0]; - if (ch == '\r' || ch == '\n') - { - (*input)[0] = 0; - if (line_len) *line_len = static_cast(*input - result); - (*input)++; - return result; - } - } -} - -// #DqnStr Implementation -// ================================================================================================= -DQN_FILE_SCOPE i32 DqnStr_Cmp(char const *a, char const *b, i32 num_bytes_to_cmp, Dqn::IgnoreCase ignore) -{ - if (!a || !b) return -1; - if (!a) return -b[0]; - if (!b) return -a[0]; - if (num_bytes_to_cmp == 0) return 0; - - i32 bytes_cmped = 0; - i32 result = 0; - if (ignore == Dqn::IgnoreCase::Yes) - { - while (a[0] && (DqnChar_ToLower(a[0]) == DqnChar_ToLower(b[0]))) - { - a++; b++; - if (++bytes_cmped == num_bytes_to_cmp) return 0; - } - result = DqnChar_ToLower(a[0]) - DqnChar_ToLower(b[0]); - } - else - { - while (a[0] && (a[0] == b[0])) - { - a++; b++; - if (++bytes_cmped == num_bytes_to_cmp) return 0; - } - result = a[0] - b[0]; - } - - return result; -} - -DQN_FILE_SCOPE char *DqnStr_GetPtrToLastSlash(char const *str, i32 str_len) -{ - char const *result = str; - if (str_len == -1) str_len = DqnStr_Len(str); - - for (auto i = str_len - 1; i >= 0; i--) - { - if (result[i] == '\\' || result[i] == '/') - { - result = result + i + 1; - break; - } - } - return (char *)result; -} - -DQN_FILE_SCOPE i32 DqnStr_Len(char const *a) -{ - i32 result = 0; - while (a && a[result]) result++; - return result; -} - -DQN_FILE_SCOPE i32 DqnStr_LenUTF8(u32 const *a, i32 *len_in_bytes) -{ - i32 utf8_len = 0; - i32 utf8_len_in_bytes = 0; - u8 *byte_ptr = (u8 *)a; - while (true) - { - u32 codepoint = 0; - i32 num_bytes_in_codepoint = DqnStr_ReadUTF8Codepoint((u32 *)byte_ptr, &codepoint); - - if (num_bytes_in_codepoint == 0) break; - utf8_len++; - byte_ptr += num_bytes_in_codepoint; - utf8_len_in_bytes += num_bytes_in_codepoint; - } - - if (len_in_bytes) *len_in_bytes = utf8_len_in_bytes; - return utf8_len; -} - -DQN_FILE_SCOPE i32 DqnStr_LenDelimitWith(char const *a, char delimiter) -{ - i32 result = 0; - while (a && a[result] && a[result] != delimiter) result++; - return result; -} - -DQN_FILE_SCOPE i32 DqnStr_ReadUTF8Codepoint(u32 const *a, u32 *out_codepoint) -{ - u8 *byte = (u8 *)a; - if (a && byte[0]) - { - i32 num_bytes_in_char = 0; - u32 actual_char = 0; - - if (byte[0] <= 128) - { - actual_char = byte[0]; - num_bytes_in_char = 1; - } - else if ((byte[0] & 0xE0) == 0xC0) - { - // Header 110xxxxx 10xxxxxx - actual_char = ((u32)(byte[0] & 0x3F) << 6) - | ((u32)(byte[1] & 0x1F) << 0); - num_bytes_in_char = 2; - } - else if ((byte[0] & 0xF0) == 0xE0) - { - // Header 1110xxxx 10xxxxxx 10xxxxxx - actual_char = ((u32)(byte[0] & 0x0F) << 12) - | ((u32)(byte[1] & 0x3F) << 6 ) - | ((u32)(byte[2] & 0x3F) << 0 ); - num_bytes_in_char = 3; - } - else if ((byte[0] & 0xF8) == 0xF0) - { - // Header 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx - actual_char = ((u32)(byte[0] & 0x07) << 18) - | ((u32)(byte[1] & 0x3F) << 12) - | ((u32)(byte[2] & 0x3F) << 6 ) - | ((u32)(byte[3] & 0x3F) << 0 ); - num_bytes_in_char = 4; - } - else - { - // NOTE: Malformed utf8 stream - } - - if (out_codepoint) *out_codepoint = actual_char; - return num_bytes_in_char; - } - - return 0; -} - -DQN_FILE_SCOPE void DqnStr_Reverse(char *buf, isize buf_size) -{ - if (!buf) return; - isize mid = buf_size / 2; - - for (isize i = 0; i < mid; i++) - { - char tmp = buf[i]; - buf[i] = buf[(buf_size - 1) - i]; - buf[(buf_size - 1) - i] = tmp; - } -} - -DQN_FILE_SCOPE bool DqnStr_EndsWith(char const *src, i32 src_len, char const *find, i32 find_len, - Dqn::IgnoreCase ignore) -{ - if (!src || !find || find_len < 0 || src_len < 0) return false; - - if (src_len < find_len) - return false; - - char const *src_end = src + (src_len); - char const *check_src_from = src_end - find_len; - - bool result = (DqnStr_Cmp(check_src_from, find, find_len, ignore) == 0); - return result; -} - -DQN_FILE_SCOPE i32 DqnStr_FindFirstOccurence(char const *src, i32 src_len, - char const *find, i32 find_len, Dqn::IgnoreCase ignore) -{ - if (!src || !find) return -1; - if (src_len == 0 || find_len == 0) return -1; - if (src_len < find_len) return -1; - - for (i32 index_in_src = 0; index_in_src < src_len; index_in_src++) - { - // NOTE: As we scan through, if the src string we index into becomes - // shorter than the substring we're checking then the substring is not - // contained in the src string. - i32 remaining_len_in_src = src_len - index_in_src; - if (remaining_len_in_src < find_len) break; - - const char *src_substr = src + index_in_src; - if (DqnStr_Cmp(src_substr, find, find_len, ignore) == 0) - { - return index_in_src; - } - } - - // NOTE(doyle): We have early exit, if we reach here, then the substring was - // not found. - return -1; -} - -DQN_FILE_SCOPE char *DqnStr_GetFirstOccurence(char const *src, i32 src_len, char const *find, - i32 find_len, Dqn::IgnoreCase ignore) -{ - i32 offset = DqnStr_FindFirstOccurence(src, src_len, find, find_len, ignore); - if (offset == -1) return nullptr; - - char *result = (char *)(src + offset); - return result; -} - -DQN_FILE_SCOPE bool DqnStr_HasSubstring(char const *src, i32 src_len, - char const *find, i32 find_len, Dqn::IgnoreCase ignore) -{ - if (DqnStr_FindFirstOccurence(src, src_len, find, find_len, ignore) == -1) - return false; - - return true; -} - -DQN_FILE_SCOPE i32 Dqn_I64ToStr(i64 value, char *buf, i32 buf_size) -{ - bool valid_buf = true; - if (!buf || buf_size == 0) valid_buf = false; - - if (value == 0) - { - if (valid_buf) - { - buf[0] = '0'; - buf[1] = 0; - } - - return 1; - } - - i32 char_index = 0; - bool negative = false; - if (value < 0) negative = true; - - if (negative) - { - if (valid_buf) buf[char_index] = '-'; - char_index++; - } - - bool last_digit_decremented = false; - i64 val = DQN_ABS(value); - if (val < 0) - { - // TODO(doyle): This will occur if we are checking the smallest number - // possible in i64 since the range of negative numbers is one more than - // it is for positives, so ABS will fail. - last_digit_decremented = true; - val = DQN_ABS(val - 1); - DQN_ASSERT(val >= 0); - } - - if (valid_buf) - { - if (last_digit_decremented) - { - i64 rem = (val % 10) + 1; - buf[char_index++] = (u8)rem + '0'; - val /= 10; - } - - while (val != 0 && char_index < buf_size) - { - i64 rem = val % 10; - buf[char_index++] = (u8)rem + '0'; - val /= 10; - } - - // NOTE(doyle): If string is negative, we only want to reverse starting - // from the second character, so we don't put the negative sign at the - // end - if (negative) - { - DqnStr_Reverse(buf + 1, char_index - 1); - } - else - { - DqnStr_Reverse(buf, char_index); - } - } - else - { - while (val != 0) - { - val /= 10; - char_index++; - } - } - - buf[char_index] = 0; - return char_index; -} - -DQN_FILE_SCOPE i64 Dqn_StrToI64(char const *buf, i64 buf_size) -{ - if (!buf || buf_size == 0) return 0; - - i64 index = 0; - while (buf[index] == ' ') - { - index++; - } - - bool is_minus = false; - if (buf[index] == '-' || buf[index] == '+') - { - if (buf[index] == '-') is_minus = true; - index++; - } - else if (!DqnChar_IsDigit(buf[index])) - { - return 0; - } - - i64 result = 0; - for (auto i = index; i < buf_size; i++) - { - if (DqnChar_IsDigit(buf[i])) - { - result *= 10; - result += (buf[i] - '0'); - } - else - { - break; - } - } - - if (is_minus) result *= -1; - - return result; -} - -DQN_FILE_SCOPE f32 Dqn_StrToF32(char const *buf, i64 buf_size) -{ - if (!buf || buf_size == 0) return 0; - - i64 index = 0; - bool is_minus = false; - if (buf[index] == '-') - { - index++; - is_minus = true; - } - - bool is_past_decimal = false; - i64 num_digits_after_decimal = 0; - i64 raw_num = 0; - - f32 digit_shift_val = 1.0f; - f32 digit_shift_multiplier = 0.1f; - for (auto i = index; i < buf_size; i++) - { - char ch = buf[i]; - if (ch == '.') - { - is_past_decimal = true; - continue; - } - // Handle scientific notation - else if (ch == 'e') - { - bool digit_shift_is_positive = true; - if (i < buf_size) - { - if (buf[i + 1] == '-') digit_shift_is_positive = false; - DQN_ASSERT(buf[i + 1] == '-' || buf[i + 1] == '+'); - i += 2; - } - - i32 exponent_pow = 0; - bool scientific_notation = false; - while (i < buf_size) - { - scientific_notation = true; - char exponent_char = buf[i]; - if (DqnChar_IsDigit(exponent_char)) - { - exponent_pow *= 10; - exponent_pow += (buf[i] - '0'); - } - else - { - i = buf_size; - } - - i++; - } - - // NOTE(doyle): If exponent not specified but this branch occurred, - // the float string has a malformed scientific notation in the - // string, i.e. "e" followed by no number. - DQN_ASSERT(scientific_notation); - - if (digit_shift_is_positive) - { - num_digits_after_decimal -= exponent_pow; - } - else - { - num_digits_after_decimal += exponent_pow; - } - } - else if (DqnChar_IsDigit(ch)) - { - num_digits_after_decimal += (i32)is_past_decimal; - raw_num *= 10; - raw_num += (ch - '0'); - } - else - { - break; - } - } - - for (isize i = 0; i < num_digits_after_decimal; i++) - digit_shift_val *= digit_shift_multiplier; - - f32 result = (f32)raw_num; - if (num_digits_after_decimal > 0) result *= digit_shift_val; - if (is_minus) result *= -1; - - return result; -} - -/* - Encoding - The following byte sequences are used to represent a character. The sequence - to be used depends on the UCS code number of the character: - - The extra 1's are the headers used to identify the string as a UTF-8 string. - UCS [0x00000000, 0x0000007F] -> UTF-8 0xxxxxxx - UCS [0x00000080, 0x000007FF] -> UTF-8 110xxxxx 10xxxxxx - UCS [0x00000800, 0x0000FFFF] -> UTF-8 1110xxxx 10xxxxxx 10xxxxxx - UCS [0x00010000, 0x001FFFFF] -> UTF-8 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx - UCS [0x00200000, 0x03FFFFFF] -> N/A 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx - UCS [0x04000000, 0x7FFFFFFF] -> N/A 1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx - - The xxx bit positions are filled with the bits of the character code number - in binary representation. Only the shortest possible multibyte sequence - which can represent the code number of the character can be used. - - The UCS code values 0xd800–0xdfff (UTF-16 surrogates) as well as 0xfffe and - 0xffff (UCS noncharacters) should not appear in conforming UTF-8 streams. -*/ -DQN_FILE_SCOPE u32 Dqn_UCSToUTF8(u32 *dest, u32 character) -{ - if (!dest) return 0; - - u8 *byte_ptr = (u8 *)dest; - - // Character is within ASCII range, so it's an ascii character - // UTF Bit Arrangement: 0xxxxxxx - // Character : 0xxxxxxx - if (character >= 0 && character < 0x80) - { - byte_ptr[0] = (u8)character; - return 1; - } - - // UTF Header Bits : 11000000 00xxxxxx - // UTF Bit Arrangement: 000xxxxx 00xxxxxx - // Character : 00000xxx xxxxxxxx - if (character < 0x800) - { - // Add the 2nd byte, 6 bits, OR the 0xC0 (11000000) header bits - byte_ptr[1] = (u8)((character >> 6) | 0xC0); - - // Add the 1st byte, 6 bits, plus the 0x80 (10000000) header bits - byte_ptr[0] = (u8)((character & 0x3F) | 0x80); - - return 2; - } - - // UTF Header Bits : 11100000 10000000 10000000 - // UTF Bit Arrangement : 0000xxxx 00xxxxxx 00xxxxxx - // Character : 00000000 xxxxxxxx xxxxxxxx - if (character < 0x10000) - { - // Add the 3rd byte, 4 bits, OR the 0xE0 (11100000) header bits - byte_ptr[2] = (u8)((character >> 12) | 0xE0); - - // Add the 2nd byte, 6 bits, OR the 0x80 (10000000) header bits - byte_ptr[1] = (u8)((character >> 6) | 0x80); - - // Add the 1st byte, 6 bits, plus the 0x80 (10000000) header bits - byte_ptr[0] = (u8)((character & 0x3F) | 0x80); - - return 3; - } - - // UTF Header Bits : 11110000 10000000 10000000 10000000 - // UTF Bit Arrangement : 00000xxx 00xxxxxx 00xxxxxx 00xxxxxx - // Character : 00000000 00000xxx xxxxxxxx xxxxxxxx - if (character < 0x110000) - { - // Add the 4th byte, 3 bits, OR the 0xF0 (11110000) header bits - byte_ptr[3] = (u8)((character >> 18) | 0xF0); - - // Add the 3rd byte, 6 bits, OR the 0x80 (10000000) header bits - byte_ptr[2] = (u8)(((character >> 12) & 0x3F) | 0x80); - - // Add the 2nd byte, 6 bits, plus the 0x80 (10000000) header bits - byte_ptr[1] = (u8)(((character >> 6) & 0x3F) | 0x80); - - // Add the 2nd byte, 6 bits, plus the 0x80 (10000000) header bits - byte_ptr[0] = (u8)((character & 0x3F) | 0x80); - - return 4; - } - - return 0; -} - -DQN_FILE_SCOPE u32 Dqn_UTF8ToUCS(u32 *dest, u32 character) -{ - if (!dest) return 0; - - const u32 HEADER_BITS_4_BYTES = 0xF0808080u; - const u32 HEADER_BITS_3_BYTES = 0xE08080u; - const u32 HEADER_BITS_2_BYTES = 0xC000u; - const u32 HEADER_BITS_1_BYTE = 0x80u; - - // UTF Header Bits : 11110000 10000000 10000000 10000000 - // UTF Bit Arrangement : 00000xxx 00xxxxxx 00xxxxxx 00xxxxxx - // UCS : 00000000 00000xxx xxxxxxxx xxxxxxxx - if ((character & HEADER_BITS_4_BYTES) == HEADER_BITS_4_BYTES) - { - u32 utf_without_header = HEADER_BITS_4_BYTES ^ character; - - u32 first_byte = utf_without_header & 0x3F; - u32 second_byte = (utf_without_header >> 8) & 0x3F; - u32 third_byte = (utf_without_header >> 16) & 0x3F; - u32 fourth_byte = utf_without_header >> 24; - - u32 result = - (fourth_byte << 18 | third_byte << 12 | second_byte << 6 | first_byte); - *dest = result; - - return 4; - } - - // UTF Header Bits : 11100000 10000000 10000000 - // UTF Bit Arrangement : 0000xxxx 00xxxxxx 00xxxxxx - // UCS : 00000000 xxxxxxxx xxxxxxxx - if ((character & HEADER_BITS_3_BYTES) == HEADER_BITS_3_BYTES) - { - u32 utf_without_header = HEADER_BITS_3_BYTES ^ character; - - u32 first_byte = utf_without_header & 0x3F; - u32 second_byte = (utf_without_header >> 8) & 0x3F; - u32 third_byte = utf_without_header >> 16; - - u32 result = (third_byte << 12 | second_byte << 6 | first_byte); - *dest = result; - - return 3; - } - - // UTF Header Bits : 11000000 00xxxxxx - // UTF Bit Arrangement: 000xxxxx 00xxxxxx - // UCS : 00000xxx xxxxxxxx - if ((character & HEADER_BITS_2_BYTES) == HEADER_BITS_2_BYTES) - { - u32 utf_without_header = HEADER_BITS_2_BYTES ^ character; - - u32 first_byte = utf_without_header & 0x3F; - u32 second_byte = utf_without_header >> 8; - - u32 result = (second_byte << 6 | first_byte); - *dest = result; - - return 2; - } - - // Character is within ASCII range, so it's an ascii character - // UTF Bit Arrangement: 0xxxxxxx - // UCS : 0xxxxxxx - if ((character & HEADER_BITS_1_BYTE) == 0) - { - u32 first_byte = (character & 0x3F); - *dest = first_byte; - - return 1; - } - - return 0; -} - -DQN_FILE_SCOPE DqnSlice DqnStr_RemoveLeadTrailChar(char const *str, i32 str_len, char lead_char, char trail_char) -{ - str = DqnChar_TrimWhitespaceAround(str, str_len, &str_len); - - if (str[0] == lead_char) - { - str++; - str_len--; - } - - if (str[str_len - 1] == trail_char) - { - str_len--; - } - - str = DqnChar_TrimWhitespaceAround(str, str_len, &str_len); - DqnSlice result = {(char *)str, str_len}; - return result; -} - -DQN_FILE_SCOPE inline DqnSlice DqnStr_RemoveLeadTrailBraces(char const *str, i32 str_len) -{ - DqnSlice result = DqnStr_RemoveLeadTrailChar(str, str_len, '{', '}'); - return result; -} - -DQN_FILE_SCOPE inline DqnSlice DqnStr_RemoveLeadTrailQuotes(char const *str, i32 str_len) -{ - DqnSlice result = DqnStr_RemoveLeadTrailChar(str, str_len, '"', '"'); - return result; -} - -DQN_FILE_SCOPE inline DqnSlice DqnStr_RemoveLeadTrailBraces(DqnSlice slice) -{ - DqnSlice result = DqnStr_RemoveLeadTrailBraces(slice.data, slice.len); - return result; -} - -DQN_FILE_SCOPE inline DqnSlice DqnStr_RemoveLeadTrailQuotes(DqnSlice slice) -{ - DqnSlice result = DqnStr_RemoveLeadTrailQuotes(slice.data, slice.len); - return result; -} - -// #DqnWChar -// ================================================================================================= -DQN_FILE_SCOPE bool DqnWChar_IsDigit(wchar_t c) -{ - if (c >= L'0' && c <= L'9') return true; - return false; -} - -DQN_FILE_SCOPE wchar_t DqnWChar_ToLower(wchar_t c) -{ - if (c >= L'A' && c <= L'Z') - { - i32 shift_offset = L'a' - L'A'; - return (c + (wchar_t)shift_offset); - } - - return c; -} - -DQN_FILE_SCOPE wchar_t *DqnWChar_SkipWhitespace(wchar_t *ptr) -{ - while (ptr && (*ptr == ' ' || *ptr == '\r' || *ptr == '\n')) ptr++; - return ptr; -} - -DQN_FILE_SCOPE wchar_t *DqnWChar_FindLastChar(wchar_t *ptr, wchar_t ch, i32 len, u32 *len_to_char) -{ - for (i32 i = len - 1; i >= 0; i--) - { - if (ptr[i] == ch) - { - if (len_to_char) *len_to_char = (u32)len - i; - return &ptr[i]; - } - } - - return nullptr; -} - -DQN_FILE_SCOPE i32 DqnWChar_GetNextLine(wchar_t *ptr, i32 *line_len) -{ - i32 len = 0; - ptr = DqnWChar_SkipWhitespace(ptr); - - // Advance pointer to first new line - while (ptr && *ptr != 0 && *ptr != '\r' && *ptr != '\n') - { - ptr++; - len++; - } - - if (!ptr || *ptr == 0) return -1; - - // Destroy all new lines - i32 extra_chars = 0; - while (ptr && (*ptr == '\r' || *ptr == '\n' || *ptr == ' ')) - { - *ptr = 0; - ptr++; - extra_chars++; - } - - if (line_len) *line_len = len; - return len + extra_chars; -} - -// #DqnWStr -// ================================================================================================= -DQN_FILE_SCOPE i32 DqnWStr_Cmp(wchar_t const *a, wchar_t const *b) -{ - if (!a && !b) return -1; - if (!a) return -1; - if (!b) return -1; - - const wchar_t *a_ptr = a; - const wchar_t *b_ptr = b; - - while ((*a_ptr) == (*b_ptr)) - { - if (!(*a_ptr)) return 0; - a_ptr++; - b_ptr++; - } - - return (((*a_ptr) < (*b_ptr)) ? -1 : 1); -} - -DQN_FILE_SCOPE i32 DqnWStr_FindFirstOccurence(wchar_t const *src, i32 src_len, - wchar_t const *find, i32 find_len) -{ - if (!src || !find) return -1; - if (src_len == 0 || find_len == 0) return -1; - if (src_len < find_len) return -1; - - for (i32 index_in_src = 0; index_in_src < src_len; index_in_src++) - { - // NOTE: As we scan through, if the src string we index into becomes - // shorter than the substring we're checking then the substring is not - // contained in the src string. - i32 remaining_len_in_src = src_len - index_in_src; - if (remaining_len_in_src < find_len) break; - - const wchar_t *src_substr = &src[index_in_src]; - i32 index = 0; - for (;;) - { - if (DqnWChar_ToLower(src_substr[index]) == - DqnWChar_ToLower(find[index])) - { - index++; - if (index >= find_len || !find[index]) - { - return index_in_src; - } - } - else - { - break; - } - } - } - - // NOTE(doyle): We have early exit, if we reach here, then the substring was - // not found. - return -1; -} - -DQN_FILE_SCOPE bool DqnWStr_HasSubstring(wchar_t const *src, i32 src_len, - wchar_t const *find, i32 find_len) -{ - if (DqnWStr_FindFirstOccurence(src, src_len, find, find_len) == -1) - return false; - - return true; -} - -DQN_FILE_SCOPE i32 DqnWStr_Len(wchar_t const *a) -{ - i32 result = 0; - while (a && a[result]) result++; - return result; -} - -DQN_FILE_SCOPE i32 DqnWStr_LenDelimitWith(wchar_t const *a, wchar_t delimiter) -{ - i32 result = 0; - while (a && a[result] && a[result] != delimiter) result++; - return result; -} - -DQN_FILE_SCOPE void DqnWStr_Reverse(wchar_t *buf, i32 buf_size) -{ - if (!buf) return; - i32 mid = buf_size / 2; - - for (i32 i = 0; i < mid; i++) - { - wchar_t tmp = buf[i]; - buf[i] = buf[(buf_size - 1) - i]; - buf[(buf_size - 1) - i] = tmp; - } -} - -DQN_FILE_SCOPE i32 Dqn_WStrToI32(wchar_t const *buf, i32 buf_size) -{ - if (!buf || buf_size == 0) return 0; - - i32 index = 0; - bool is_minus = false; - if (buf[index] == L'-' || buf[index] == L'+') - { - if (buf[index] == L'-') is_minus = true; - index++; - } - else if (!DqnWChar_IsDigit(buf[index])) - { - return 0; - } - - i32 result = 0; - for (i32 i = index; i < buf_size; i++) - { - if (DqnWChar_IsDigit(buf[i])) - { - result *= 10; - result += (buf[i] - L'0'); - } - else - { - break; - } - } - - if (is_minus) result *= -1; - - return result; -} - -DQN_FILE_SCOPE i32 Dqn_I32ToWstr(i32 value, wchar_t *buf, i32 buf_size) -{ - if (!buf || buf_size == 0) return 0; - - if (value == 0) - { - buf[0] = L'0'; - return 0; - } - - // NOTE(doyle): Max 32bit integer (+-)2147483647 - i32 char_index = 0; - bool negative = false; - if (value < 0) negative = true; - - if (negative) buf[char_index++] = L'-'; - - i32 val = DQN_ABS(value); - while (val != 0 && char_index < buf_size) - { - i32 rem = val % 10; - buf[char_index++] = (u8)rem + '0'; - val /= 10; - } - - // NOTE(doyle): If string is negative, we only want to reverse starting - // from the second character, so we don't put the negative sign at the end - if (negative) - { - DqnWStr_Reverse(buf + 1, char_index - 1); - } - else - { - DqnWStr_Reverse(buf, char_index); - } - - return char_index; -} - -// #DqnRnd -// ================================================================================================= -// Public Domain library with thanks to Mattias Gustavsson -// https://github.com/mattiasgustavsson/libs/blob/master/docs/rnd.md - -// Convert a randomized u32 value to a float value x in the range 0.0f <= x -// < 1.0f. Contributed by Jonatan Hedborg - -// NOTE: This is to abide to strict aliasing rules. -union DqnRnd__U32F32 -{ - u32 unsigned32; - f32 float32; -}; - -FILE_SCOPE f32 DqnRnd__F32NormalizedFromU32(u32 value) -{ - u32 exponent = 127; - u32 mantissa = value >> 9; - - union DqnRnd__U32F32 uf; - uf.unsigned32 = (exponent << 23 | mantissa); - return uf.float32 - 1.0f; -} - -FILE_SCOPE u64 DqnRnd__Murmur3Avalanche64(u64 h) -{ - h ^= h >> 33; - h *= 0xff51afd7ed558ccd; - h ^= h >> 33; - h *= 0xc4ceb9fe1a85ec53; - h ^= h >> 33; - return h; -} - -#if defined(DQN_IS_UNIX) - #include // __rdtsc -#endif - -FILE_SCOPE u32 DqnRnd__MakeSeed() -{ -#if defined(DQN_PLATFORM_IMPLEMENTATION) && (defined(DQN_IS_WIN32) || defined(DQN_IS_UNIX)) - i64 num_clock_cycles = __rdtsc(); - return (u32)num_clock_cycles; -#else - DQN_ASSERT(DQN_INVALID_CODE_PATH); - return 0; -#endif -} - -DqnRndPCG::DqnRndPCG() -{ - u32 seed = DqnRnd__MakeSeed(); - *this = DqnRndPCG(seed); -} - -DqnRndPCG::DqnRndPCG(u32 seed) -{ - u64 value = (((u64)seed) << 1ULL) | 1ULL; - value = DqnRnd__Murmur3Avalanche64(value); - this->state[0] = 0U; - this->state[1] = (value << 1ULL) | 1ULL; - this->Next(); - this->state[0] += DqnRnd__Murmur3Avalanche64(value); - this->Next(); -} - -u32 DqnRndPCG::Next() -{ - u64 oldstate = this->state[0]; - this->state[0] = oldstate * 0x5851f42d4c957f2dULL + this->state[1]; - u32 xorshifted = (u32)(((oldstate >> 18ULL) ^ oldstate) >> 27ULL); - u32 rot = (u32)(oldstate >> 59ULL); - return (xorshifted >> rot) | (xorshifted << ((-(i32)rot) & 31)); -} - -f32 DqnRndPCG::Nextf() -{ - f32 result = DqnRnd__F32NormalizedFromU32(this->Next()); - return result; -} - -i32 DqnRndPCG::Range(i32 min, i32 max) -{ - i32 const range = (max - min) + 1; - if (range <= 0) return min; - - i32 const value = (i32)(this->Nextf() * range); - i32 result = min + value; - return result; -} - - -// #Dqn_* -// ================================================================================================= -DQN_FILE_SCOPE inline bool Dqn_BitIsSet(u32 bits, u32 flag) -{ - bool result = ((bits & flag) == flag); - return result; -} - -DQN_FILE_SCOPE inline u32 Dqn_BitSet(u32 bits, u32 flag) -{ - u32 result = (bits | flag); - return result; -} - -DQN_FILE_SCOPE inline u32 Dqn_BitUnset(u32 bits, u32 flag) -{ - u32 result = (bits & ~flag); - return result; -} - -DQN_FILE_SCOPE inline u32 Dqn_BitToggle(u32 bits, u32 flag) -{ - u32 result = (bits ^ flag); - return result; -} - -// #DqnString Impleemntation -// ================================================================================================= -void DqnString::Reserve(int new_max) -{ - if (new_max >= this->max) - { - char *new_ptr = (this->str) ? static_cast(allocator->Realloc(this->str, new_max * sizeof(this->str[0]))) - : static_cast(allocator->Malloc(new_max * sizeof(this->str[0]))); - - DQN_ALWAYS_ASSERT(new_ptr); - this->str = new_ptr; - this->max = new_max; - } -} - -void DqnString::Append(char const *src, int len_) -{ - if (len_ == -1) - len_ = DqnStr_Len(src); - - Reserve(this->len + len_); - DqnMem_Copy(this->str + this->len, src, len_); - this->len += len_; - this->str[this->len] = 0; -} - -// #DqnLogger Implementation -// ================================================================================================= -char const *DqnLogger::LogNoContext(Type type, char const *fmt, ...) -{ - Context empty_context = {}; - va_list va; - va_start(va, fmt); - char const *result = this->LogVA(type, empty_context, fmt, va); - va_end(va); - return result; -} - -char const *DqnLogger::Log(Type type, Context log_context, char const *fmt, ...) -{ - va_list va; - va_start(va, fmt); - char const *result = this->LogVA(type, log_context, fmt, va); - va_end(va); - return result; -} - -char const *DqnLogger::LogVA(Type type, Context log_context, char const *fmt, va_list va) -{ - if (!this->allocator.block) - { - this->allocator.LazyInit(DqnMemStack::MINIMUM_BLOCK_SIZE, Dqn::ZeroMem::No, 0, DqnMemTracker::None); - } - - if (this->log_buf.len == 0) - { - this->log_buf_index = 0; - this->log_buf.len = 2048; - this->log_buf.data = (char *)this->allocator.Push_(sizeof(*this->log_buf.data) * this->log_buf.len); - } - - bool const have_context = (log_context.filename_len > 0); - char const *filename = nullptr; - for (isize i = (log_context.filename_len - 1); i >= 0; i--) - { - if (log_context.filename[i] == '\\') - { - filename = log_context.filename + (i + 1); - break; - } - } - - if (!filename) filename = log_context.filename; - - // Determine len - int required_len = 0; -#if defined(DQN_PLATFORM_HEADER) && defined(DQN_IS_WIN32) - SYSTEMTIME sys_time = {}; - GetLocalTime(&sys_time); - required_len += stbsp_snprintf(nullptr, 0, "%02d-%02d-%02d %02d:%02d:%02d ", sys_time.wYear % 100, sys_time.wMonth, sys_time.wDay, sys_time.wHour, sys_time.wMinute, sys_time.wSecond); -#endif - - if (have_context) - { - required_len += stbsp_snprintf(nullptr, 0, "%s %05d %s %s: ", filename, log_context.line_num, TypePrefix(type), log_context.function); - } - - required_len += stbsp_snprintf(nullptr, 0, "%s", this->log_builder.str); - required_len += stbsp_vsnprintf(nullptr, 0, fmt, va); - required_len += 2; // newline + null byte - - // Build string - this->allocator.SetAllocMode(DqnMemStack::AllocMode::Tail); - char *result = (char *)this->allocator.Push_(sizeof(char) * required_len); - this->allocator.SetAllocMode(DqnMemStack::AllocMode::Head); - DQN_DEFER { this->allocator.Pop(result); }; - - char *result_ptr = result; - - if (have_context) - { -#if defined(DQN_PLATFORM_HEADER) && defined(DQN_IS_WIN32) - result_ptr += stbsp_sprintf(result_ptr, "%02d-%02d-%02d %02d:%02d:%02d ", sys_time.wYear % 100, sys_time.wMonth, sys_time.wDay, sys_time.wHour, sys_time.wMinute, sys_time.wSecond); -#endif - result_ptr += stbsp_sprintf(result_ptr, "%s %05d %s %s: ", filename, log_context.line_num, TypePrefix(type), log_context.function); - } - - DqnMem_Copy(result_ptr, this->log_builder.str, this->log_builder.len); - result_ptr += this->log_builder.len; - result_ptr += stbsp_vsprintf(result_ptr, fmt, va); - *result_ptr++ = '\n'; - *result_ptr++ = 0; - - this->log_builder.Clear(); - - int buf_len_remaining = this->log_buf.len - this->log_buf_index; - if (required_len >= buf_len_remaining) // Bad case, the log line was greater than the buf we allocated - { - // TODO(doyle): Handle the bad case - } - else - { - // TODO(doyle): Write to disk - this->log_buf_index += (required_len - 1); // make index point at the null byte of the string - DqnMem_Copy(this->log_buf.str, result, required_len); - } - - if (this->no_console) return result; - if (this->no_print_error && type == Type::Error) return result; - if (this->no_print_debug && type == Type::Debug) return result; - if (this->no_print_warning && type == Type::Warning) return result; - - fprintf(stderr, "%s", result); - return result; -} - -// #Dqn -// ================================================================================================= -i32 Dqn_GetNumSplits(char const *src, i32 src_len, char split_char) -{ - auto result = Dqn_SplitString(src, src_len, split_char, nullptr, 0); - return result; -} - -i32 Dqn_SplitString(char const *src, i32 src_len, char split_char, DqnSlice *array, i32 size) -{ - // TODO(doyle): Const correctness - i32 slice_len = 0; - i32 array_index = 0; - for (auto i = 0; i < src_len; i++) - { - char *c = (char *)(src + i); - if (*c == split_char) - { - DqnSlice slice = {c - slice_len, slice_len}; - if (array) - { - if (array_index < size) - { - array[array_index] = slice; - } - } - array_index++; - slice_len = 0; - } - else - { - slice_len++; - } - } - - DqnSlice last_slice = {(char *)src + src_len - slice_len, slice_len}; - if (last_slice.len > 0 && array_index > 0) - { - if (array) - { - if (array_index < size) - { - array[array_index] = last_slice; - } - } - - array_index++; - } - - return array_index; -} - -// TODO(doyle): This should maybe be a tokenizer ... -DQN_FILE_SCOPE DqnJson DqnJson_Get(char const *buf, i32 buf_len, char const *find_property, i32 find_property_len) -{ - DqnJson result = {}; - if (!buf || buf_len == 0 || !find_property || find_property_len == 0) return result; - - char const *tmp = DqnChar_SkipWhitespace(buf); - buf_len = static_cast((buf + buf_len) - tmp); - buf = tmp; - - bool const find_structure_in_global_scope = (find_property_len == 1 && (find_property[0] == '{' || find_property[0] == '[')); - - if ((buf[0] == '{' || buf[1] == '[') && !find_structure_in_global_scope) - { - buf++; - buf_len--; - } - -TryNext: - char const *locate = nullptr; - for (i32 index_in_buf = 0; index_in_buf < buf_len; ++index_in_buf) - { - i32 remaining_len_in_src = buf_len - index_in_buf; - if (remaining_len_in_src < find_property_len) break; - - char const *buf_substr = buf + index_in_buf; - if (!find_structure_in_global_scope) - { - if (buf_substr[0] == '{' || buf_substr[0] == '[') - { - int bracket_count = 0; - int brace_count = 0; - int *search_char_count = nullptr; - if (buf_substr[0] == '[') - { - bracket_count++; - search_char_count = &bracket_count; - } - else - { - brace_count++; - search_char_count = &brace_count; - } - - for (++index_in_buf; (*search_char_count) != 0; ++index_in_buf) - { - buf_substr = buf + index_in_buf; - if (!buf_substr[0]) - return result; - - if (buf_substr[0] == '{') ++brace_count; - else if (buf_substr[0] == '}') --brace_count; - else if (buf_substr[0] == '[') ++bracket_count; - else if (buf_substr[0] == ']') --bracket_count; - else continue; - } - } - } - - if (DqnStr_Cmp(buf_substr, find_property, find_property_len, Dqn::IgnoreCase::No) == 0) - { - locate = buf + index_in_buf; - break; - } - } - if (!locate) return result; - - // NOTE: if find property is '{' we are looking for an object in array or the global scope etc - // which doesn't have a specific property name - char const *start_of_val = locate; - char const *buf_ptr = start_of_val; - if (!find_structure_in_global_scope) - { - // NOTE: When true, the find_property already includes the quotation marks, so don't need to check. - if (!(find_property[0] == '"' && find_property[find_property_len - 1] == '"')) - { - if (locate[-1] != '"' || locate[find_property_len] != '"') - { - buf_len -= static_cast(((locate - buf) + find_property_len)); - buf = locate + find_property_len; - goto TryNext; - } - } - - if (!(locate[find_property_len + 1] && locate[find_property_len + 1] == ':')) - { - return result; - } - - start_of_val = locate + find_property_len + 2; - start_of_val = DqnChar_SkipWhitespace(start_of_val); - buf_ptr = start_of_val; - } - - i32 brace_count = 0, bracket_count = 0; - if (buf_ptr[0] == '[' || buf_ptr[0] == '{') - { - start_of_val++; - - i32 *search_char_count = nullptr; - if (*buf_ptr++ == '[') - { - bracket_count++; - search_char_count = &bracket_count; - - while(buf_ptr[0] != '{' && buf_ptr[0] != '[' && buf_ptr[0] != '"' && !DqnChar_IsAlphaNum(buf_ptr[0]) && !buf_ptr[0]) - buf_ptr++; - - if (!buf_ptr[0]) - return result; - - const b32 array_of_primitives = (DqnChar_IsAlphaNum(buf_ptr[0]) || buf_ptr[0] == '"'); - result.type = (array_of_primitives) ? DqnJson::Type::ArrayOfPrimitives : DqnJson::Type::ArrayOfObjects; - } - else - { - brace_count++; - result.type = DqnJson::Type::Object; - search_char_count = &brace_count; - } - - if (result.type == DqnJson::Type::ArrayOfPrimitives) - { - for (result.num_entries = 1;;) - { - while(buf_ptr[0] && (buf_ptr[0] != ',' && buf_ptr[0] != ']')) - buf_ptr++; - - if (buf_ptr[0] == ',') - { - result.num_entries++; - buf_ptr++; - continue; - } - - if (!buf_ptr[0]) - return result; - - if (buf_ptr[0] == ']') - break; - } - } - else - { - for (; (*search_char_count) != 0; ++buf_ptr) - { - if (!buf_ptr[0]) - return result; - - if (buf_ptr[0] == '{') ++brace_count; - else if (buf_ptr[0] == '}') --brace_count; - else if (buf_ptr[0] == '[') ++bracket_count; - else if (buf_ptr[0] == ']') --bracket_count; - else continue; - - if (result.type == DqnJson::Type::ArrayOfObjects) - { - if (brace_count == 0 && bracket_count == 1) - { - result.num_entries++; - } - } - else - { - if (brace_count == 1 && bracket_count == 0) - { - result.num_entries++; - } - } - } - // Don't include the open and closing braces/brackets. - buf_ptr--; - } - - } - else if (buf_ptr[0] == '"' || DqnChar_IsAlphaNum(buf_ptr[0]) || buf_ptr[0] == '-') - { - while(buf_ptr[0] && (buf_ptr[0] != '\n' && buf_ptr[0] != ',' && buf_ptr[0] != '}')) - buf_ptr++; - - if (!buf_ptr[0]) - return result; - - result.num_entries = 1; - } - else - { - return result; - } - - result.value.data = (char *)start_of_val; - result.value.len = static_cast(buf_ptr - result.value.data); - result.value.data = DqnChar_TrimWhitespaceAround(result.value.data, result.value.len, &result.value.len); - return result; -} - -DQN_FILE_SCOPE DqnJson DqnJson_Get(DqnSlice const buf, DqnSlice const find_property) -{ - DqnJson result = DqnJson_Get(buf.data, buf.len, find_property.data, find_property.len); - return result; -} - -DQN_FILE_SCOPE DqnJson DqnJson_Get(DqnSlice const buf, DqnSlice const find_property) -{ - DqnJson result = DqnJson_Get(buf.data, buf.len, find_property.data, find_property.len); - return result; -} - -DQN_FILE_SCOPE DqnJson DqnJson_Get(DqnSlice const buf, DqnSlice const find_property) -{ - DqnJson result = DqnJson_Get(buf.data, buf.len, find_property.data, find_property.len); - return result; -} - -DQN_FILE_SCOPE DqnJson DqnJson_Get(DqnJson const input, DqnSlice const find_property) -{ - DqnJson result = DqnJson_Get(input.value.data, input.value.len, find_property.data, find_property.len); - return result; -} - -DQN_FILE_SCOPE DqnJson DqnJson_Get(DqnJson const input, DqnSlice const find_property) -{ - DqnJson result = DqnJson_Get(input.value.data, input.value.len, find_property.data, find_property.len); - return result; -} - -DQN_FILE_SCOPE DqnJson DqnJson_GetNextArrayItem(DqnJson *iterator) -{ - DqnJson result = {}; - if (!iterator->IsArray() || iterator->num_entries <= 0) - return result; - - if (iterator->type == DqnJson::Type::ArrayOfObjects) - { - if (result = DqnJson_Get(iterator->value, DQN_BUFFER_STR_LIT("{"))) - { - char const *end = iterator->value.data + iterator->value.len; - iterator->value.data = result.value.data + result.value.len; - --iterator->num_entries; - - while (iterator->value.data[0] && *iterator->value.data++ != '}') - ; - - iterator->value.data = DqnChar_SkipWhitespace(iterator->value.data); - if (iterator->value.data[0] && iterator->value.data[0] == ',') - iterator->value.data++; - - iterator->value.data = DqnChar_SkipWhitespace(iterator->value.data); - iterator->value.len = (iterator->value.data) ? static_cast(end - iterator->value.data) : 0; - } - } - else - { - char const *end = iterator->value.data + iterator->value.len; - result.value.data = iterator->value.data; - --iterator->num_entries; - - if (iterator->num_entries == 0) - { - while (iterator->value.data[0] && iterator->value.data[0] != ']') - ++iterator->value.data; - } - else - { - while (iterator->value.data[0] && iterator->value.data[0] != ',') - ++iterator->value.data; - } - - - result.value.len = static_cast(iterator->value.data - result.value.data); - iterator->value.data = DqnChar_SkipWhitespace(++iterator->value.data); - iterator->value.len = (iterator->value.data) ? static_cast(end - iterator->value.data) : 0; - } - - return result; -} - -#ifdef __GNUC__ - #pragma GCC diagnostic push - #pragma GCC diagnostic ignored "-Wstrict-aliasing" -#endif -// #DqnSprintf - STB_Sprintf -// ================================================================================================= -#include // for va_arg() - -#define stbsp__uint32 unsigned int -#define stbsp__int32 signed int - -#ifdef _MSC_VER -#define stbsp__uint64 unsigned __int64 -#define stbsp__int64 signed __int64 -#else -#define stbsp__uint64 unsigned long long -#define stbsp__int64 signed long long -#endif -#define stbsp__uint16 unsigned short - -#ifndef stbsp__uintptr -#if defined(__ppc64__) || defined(__aarch64__) || defined(_M_X64) || defined(__x86_64__) || defined(__x86_64) -#define stbsp__uintptr stbsp__uint64 -#else -#define stbsp__uintptr stbsp__uint32 -#endif -#endif - -#ifndef STB_SPRINTF_MSVC_MODE // used for MSVC2013 and earlier (MSVC2015 matches GCC) -#if defined(_MSC_VER) && (_MSC_VER < 1900) -#define STB_SPRINTF_MSVC_MODE -#endif -#endif - -#ifdef STB_SPRINTF_NOUNALIGNED // define this before inclusion to force stbsp_sprintf to always use aligned accesses -#define STBSP__UNALIGNED(code) -#else -#define STBSP__UNALIGNED(code) code -#endif - -#ifndef STB_SPRINTF_NOFLOAT -// internal float utility functions -static stbsp__int32 stbsp__real_to_str(char const **start, stbsp__uint32 *len, char *out, stbsp__int32 *decimal_pos, double value, stbsp__uint32 frac_digits); -static stbsp__int32 stbsp__real_to_parts(stbsp__int64 *bits, stbsp__int32 *expo, double value); -#define STBSP__SPECIAL 0x7000 -#endif - -static char stbsp__period = '.'; -static char stbsp__comma = ','; -static char stbsp__digitpair[201] = - "0001020304050607080910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576" - "7778798081828384858687888990919293949596979899"; - -STBSP__PUBLICDEF void STB_SPRINTF_DECORATE(set_separators)(char pcomma, char pperiod) -{ - stbsp__period = pperiod; - stbsp__comma = pcomma; -} - -#define STBSP__LEFTJUST 1 -#define STBSP__LEADINGPLUS 2 -#define STBSP__LEADINGSPACE 4 -#define STBSP__LEADING_0X 8 -#define STBSP__LEADINGZERO 16 -#define STBSP__INTMAX 32 -#define STBSP__TRIPLET_COMMA 64 -#define STBSP__NEGATIVE 128 -#define STBSP__METRIC_SUFFIX 256 -#define STBSP__HALFWIDTH 512 -#define STBSP__METRIC_NOSPACE 1024 -#define STBSP__METRIC_1024 2048 -#define STBSP__METRIC_JEDEC 4096 - -static void stbsp__lead_sign(stbsp__uint32 fl, char *sign) -{ - sign[0] = 0; - if (fl & STBSP__NEGATIVE) { - sign[0] = 1; - sign[1] = '-'; - } else if (fl & STBSP__LEADINGSPACE) { - sign[0] = 1; - sign[1] = ' '; - } else if (fl & STBSP__LEADINGPLUS) { - sign[0] = 1; - sign[1] = '+'; - } -} - -STBSP__PUBLICDEF int STB_SPRINTF_DECORATE(vsprintfcb)(STBSP_SPRINTFCB *callback, void *user, char *buf, char const *fmt, va_list va) -{ - static char hex[] = "0123456789abcdefxp"; - static char hexu[] = "0123456789ABCDEFXP"; - char *bf; - char const *f; - int tlen = 0; - - bf = buf; - f = fmt; - for (;;) { - stbsp__int32 fw, pr, tz; - stbsp__uint32 fl; - - // macros for the callback buffer stuff - #define stbsp__chk_cb_bufL(bytes) \ - { \ - int len = (int)(bf - buf); \ - if ((len + (bytes)) >= STB_SPRINTF_MIN) { \ - tlen += len; \ - if (0 == (bf = buf = callback(buf, user, len))) \ - goto done; \ - } \ - } - #define stbsp__chk_cb_buf(bytes) \ - { \ - if (callback) { \ - stbsp__chk_cb_bufL(bytes); \ - } \ - } - #define stbsp__flush_cb() \ - { \ - stbsp__chk_cb_bufL(STB_SPRINTF_MIN - 1); \ - } // flush if there is even one byte in the buffer - #define stbsp__cb_buf_clamp(cl, v) \ - cl = v; \ - if (callback) { \ - int lg = STB_SPRINTF_MIN - (int)(bf - buf); \ - if (cl > lg) \ - cl = lg; \ - } - - // fast copy everything up to the next % (or end of string) - for (;;) { - while (((stbsp__uintptr)f) & 3) { - schk1: - if (f[0] == '%') - goto scandd; - schk2: - if (f[0] == 0) - goto endfmt; - stbsp__chk_cb_buf(1); - *bf++ = f[0]; - ++f; - } - for (;;) { - // Check if the next 4 bytes contain %(0x25) or end of string. - // Using the 'hasless' trick: - // https://graphics.stanford.edu/~seander/bithacks.html#HasLessInWord - stbsp__uint32 v, c; - v = *(stbsp__uint32 *)f; - c = (~v) & 0x80808080; - if (((v ^ 0x25252525) - 0x01010101) & c) - goto schk1; - if ((v - 0x01010101) & c) - goto schk2; - if (callback) - if ((STB_SPRINTF_MIN - (int)(bf - buf)) < 4) - goto schk1; - *(stbsp__uint32 *)bf = v; - bf += 4; - f += 4; - } - } - scandd: - - ++f; - - // ok, we have a percent, read the modifiers first - fw = 0; - pr = -1; - fl = 0; - tz = 0; - - // flags - for (;;) { - switch (f[0]) { - // if we have left justify - case '-': - fl |= STBSP__LEFTJUST; - ++f; - continue; - // if we have leading plus - case '+': - fl |= STBSP__LEADINGPLUS; - ++f; - continue; - // if we have leading space - case ' ': - fl |= STBSP__LEADINGSPACE; - ++f; - continue; - // if we have leading 0x - case '#': - fl |= STBSP__LEADING_0X; - ++f; - continue; - // if we have thousand commas - case '\'': - fl |= STBSP__TRIPLET_COMMA; - ++f; - continue; - // if we have kilo marker (none->kilo->kibi->jedec) - case '$': - if (fl & STBSP__METRIC_SUFFIX) { - if (fl & STBSP__METRIC_1024) { - fl |= STBSP__METRIC_JEDEC; - } else { - fl |= STBSP__METRIC_1024; - } - } else { - fl |= STBSP__METRIC_SUFFIX; - } - ++f; - continue; - // if we don't want space between metric suffix and number - case '_': - fl |= STBSP__METRIC_NOSPACE; - ++f; - continue; - // if we have leading zero - case '0': - fl |= STBSP__LEADINGZERO; - ++f; - goto flags_done; - default: goto flags_done; - } - } - flags_done: - - // get the field width - if (f[0] == '*') { - fw = va_arg(va, stbsp__uint32); - ++f; - } else { - while ((f[0] >= '0') && (f[0] <= '9')) { - fw = fw * 10 + f[0] - '0'; - f++; - } - } - // get the precision - if (f[0] == '.') { - ++f; - if (f[0] == '*') { - pr = va_arg(va, stbsp__uint32); - ++f; - } else { - pr = 0; - while ((f[0] >= '0') && (f[0] <= '9')) { - pr = pr * 10 + f[0] - '0'; - f++; - } - } - } - - // handle integer size overrides - switch (f[0]) { - // are we halfwidth? - case 'h': - fl |= STBSP__HALFWIDTH; - ++f; - break; - // are we 64-bit (unix style) - case 'l': - ++f; - if (f[0] == 'l') { - fl |= STBSP__INTMAX; - ++f; - } - break; - // are we 64-bit on intmax? (c99) - case 'j': - fl |= STBSP__INTMAX; - ++f; - break; - // are we 64-bit on size_t or ptrdiff_t? (c99) - case 'z': - case 't': - fl |= ((sizeof(char *) == 8) ? STBSP__INTMAX : 0); - ++f; - break; - // are we 64-bit (msft style) - case 'I': - if ((f[1] == '6') && (f[2] == '4')) { - fl |= STBSP__INTMAX; - f += 3; - } else if ((f[1] == '3') && (f[2] == '2')) { - f += 3; - } else { - fl |= ((sizeof(void *) == 8) ? STBSP__INTMAX : 0); - ++f; - } - break; - default: break; - } - - // handle each replacement - switch (f[0]) { - #define STBSP__NUMSZ 512 // big enough for e308 (with commas) or e-307 - char num[STBSP__NUMSZ]; - char lead[8]; - char tail[8]; - char *s; - char const *h; - stbsp__uint32 l, n, cs; - stbsp__uint64 n64; -#ifndef STB_SPRINTF_NOFLOAT - double fv; -#endif - stbsp__int32 dp; - char const *sn; - - case 's': - // get the string - s = va_arg(va, char *); - if (s == 0) - s = (char *)"null"; - // get the length - sn = s; - for (;;) { - if ((((stbsp__uintptr)sn) & 3) == 0) - break; - lchk: - if (sn[0] == 0) - goto ld; - ++sn; - } - n = 0xffffffff; - if (pr >= 0) { - n = (stbsp__uint32)(sn - s); - if (n >= (stbsp__uint32)pr) - goto ld; - n = ((stbsp__uint32)(pr - n)) >> 2; - } - while (n) { - stbsp__uint32 v = *(stbsp__uint32 *)sn; - if ((v - 0x01010101) & (~v) & 0x80808080UL) - goto lchk; - sn += 4; - --n; - } - goto lchk; - ld: - - l = (stbsp__uint32)(sn - s); - // clamp to precision - if (l > (stbsp__uint32)pr) - l = pr; - lead[0] = 0; - tail[0] = 0; - pr = 0; - dp = 0; - cs = 0; - // copy the string in - goto scopy; - - case 'c': // char - // get the character - s = num + STBSP__NUMSZ - 1; - *s = (char)va_arg(va, int); - l = 1; - lead[0] = 0; - tail[0] = 0; - pr = 0; - dp = 0; - cs = 0; - goto scopy; - - case 'n': // weird write-bytes specifier - { - int *d = va_arg(va, int *); - *d = tlen + (int)(bf - buf); - } break; - -#ifdef STB_SPRINTF_NOFLOAT - case 'A': // float - case 'a': // hex float - case 'G': // float - case 'g': // float - case 'E': // float - case 'e': // float - case 'f': // float - va_arg(va, double); // eat it - s = (char *)"No float"; - l = 8; - lead[0] = 0; - tail[0] = 0; - pr = 0; - dp = 0; - cs = 0; - goto scopy; -#else - case 'A': // hex float - case 'a': // hex float - h = (f[0] == 'A') ? hexu : hex; - fv = va_arg(va, double); - if (pr == -1) - pr = 6; // default is 6 - // read the double into a string - if (stbsp__real_to_parts((stbsp__int64 *)&n64, &dp, fv)) - fl |= STBSP__NEGATIVE; - - s = num + 64; - - stbsp__lead_sign(fl, lead); - - if (dp == -1023) - dp = (n64) ? -1022 : 0; - else - n64 |= (((stbsp__uint64)1) << 52); - n64 <<= (64 - 56); - if (pr < 15) - n64 += ((((stbsp__uint64)8) << 56) >> (pr * 4)); -// add leading chars - -#ifdef STB_SPRINTF_MSVC_MODE - *s++ = '0'; - *s++ = 'x'; -#else - lead[1 + lead[0]] = '0'; - lead[2 + lead[0]] = 'x'; - lead[0] += 2; -#endif - *s++ = h[(n64 >> 60) & 15]; - n64 <<= 4; - if (pr) - *s++ = stbsp__period; - sn = s; - - // print the bits - n = pr; - if (n > 13) - n = 13; - if (pr > (stbsp__int32)n) - tz = pr - n; - pr = 0; - while (n--) { - *s++ = h[(n64 >> 60) & 15]; - n64 <<= 4; - } - - // print the expo - tail[1] = h[17]; - if (dp < 0) { - tail[2] = '-'; - dp = -dp; - } else - tail[2] = '+'; - n = (dp >= 1000) ? 6 : ((dp >= 100) ? 5 : ((dp >= 10) ? 4 : 3)); - tail[0] = (char)n; - for (;;) { - tail[n] = '0' + dp % 10; - if (n <= 3) - break; - --n; - dp /= 10; - } - - dp = (int)(s - sn); - l = (int)(s - (num + 64)); - s = num + 64; - cs = 1 + (3 << 24); - goto scopy; - - case 'G': // float - case 'g': // float - h = (f[0] == 'G') ? hexu : hex; - fv = va_arg(va, double); - if (pr == -1) - pr = 6; - else if (pr == 0) - pr = 1; // default is 6 - // read the double into a string - if (stbsp__real_to_str(&sn, &l, num, &dp, fv, (pr - 1) | 0x80000000)) - fl |= STBSP__NEGATIVE; - - // clamp the precision and delete extra zeros after clamp - n = pr; - if (l > (stbsp__uint32)pr) - l = pr; - while ((l > 1) && (pr) && (sn[l - 1] == '0')) { - --pr; - --l; - } - - // should we use %e - if ((dp <= -4) || (dp > (stbsp__int32)n)) { - if (pr > (stbsp__int32)l) - pr = l - 1; - else if (pr) - --pr; // when using %e, there is one digit before the decimal - goto doexpfromg; - } - // this is the insane action to get the pr to match %g sematics for %f - if (dp > 0) { - pr = (dp < (stbsp__int32)l) ? l - dp : 0; - } else { - pr = -dp + ((pr > (stbsp__int32)l) ? l : pr); - } - goto dofloatfromg; - - case 'E': // float - case 'e': // float - h = (f[0] == 'E') ? hexu : hex; - fv = va_arg(va, double); - if (pr == -1) - pr = 6; // default is 6 - // read the double into a string - if (stbsp__real_to_str(&sn, &l, num, &dp, fv, pr | 0x80000000)) - fl |= STBSP__NEGATIVE; - doexpfromg: - tail[0] = 0; - stbsp__lead_sign(fl, lead); - if (dp == STBSP__SPECIAL) { - s = (char *)sn; - cs = 0; - pr = 0; - goto scopy; - } - s = num + 64; - // handle leading chars - *s++ = sn[0]; - - if (pr) - *s++ = stbsp__period; - - // handle after decimal - if ((l - 1) > (stbsp__uint32)pr) - l = pr + 1; - for (n = 1; n < l; n++) - *s++ = sn[n]; - // trailing zeros - tz = pr - (l - 1); - pr = 0; - // dump expo - tail[1] = h[0xe]; - dp -= 1; - if (dp < 0) { - tail[2] = '-'; - dp = -dp; - } else - tail[2] = '+'; -#ifdef STB_SPRINTF_MSVC_MODE - n = 5; -#else - n = (dp >= 100) ? 5 : 4; -#endif - tail[0] = (char)n; - for (;;) { - tail[n] = '0' + dp % 10; - if (n <= 3) - break; - --n; - dp /= 10; - } - cs = 1 + (3 << 24); // how many tens - goto flt_lead; - - case 'f': // float - fv = va_arg(va, double); - doafloat: - // do kilos - if (fl & STBSP__METRIC_SUFFIX) { - double divisor; - divisor = 1000.0f; - if (fl & STBSP__METRIC_1024) - divisor = 1024.0; - while (fl < 0x4000000) { - if ((fv < divisor) && (fv > -divisor)) - break; - fv /= divisor; - fl += 0x1000000; - } - } - if (pr == -1) - pr = 6; // default is 6 - // read the double into a string - if (stbsp__real_to_str(&sn, &l, num, &dp, fv, pr)) - fl |= STBSP__NEGATIVE; - dofloatfromg: - tail[0] = 0; - stbsp__lead_sign(fl, lead); - if (dp == STBSP__SPECIAL) { - s = (char *)sn; - cs = 0; - pr = 0; - goto scopy; - } - s = num + 64; - - // handle the three decimal varieties - if (dp <= 0) { - stbsp__int32 i; - // handle 0.000*000xxxx - *s++ = '0'; - if (pr) - *s++ = stbsp__period; - n = -dp; - if ((stbsp__int32)n > pr) - n = pr; - i = n; - while (i) { - if ((((stbsp__uintptr)s) & 3) == 0) - break; - *s++ = '0'; - --i; - } - while (i >= 4) { - *(stbsp__uint32 *)s = 0x30303030; - s += 4; - i -= 4; - } - while (i) { - *s++ = '0'; - --i; - } - if ((stbsp__int32)(l + n) > pr) - l = pr - n; - i = l; - while (i) { - *s++ = *sn++; - --i; - } - tz = pr - (n + l); - cs = 1 + (3 << 24); // how many tens did we write (for commas below) - } else { - cs = (fl & STBSP__TRIPLET_COMMA) ? ((600 - (stbsp__uint32)dp) % 3) : 0; - if ((stbsp__uint32)dp >= l) { - // handle xxxx000*000.0 - n = 0; - for (;;) { - if ((fl & STBSP__TRIPLET_COMMA) && (++cs == 4)) { - cs = 0; - *s++ = stbsp__comma; - } else { - *s++ = sn[n]; - ++n; - if (n >= l) - break; - } - } - if (n < (stbsp__uint32)dp) { - n = dp - n; - if ((fl & STBSP__TRIPLET_COMMA) == 0) { - while (n) { - if ((((stbsp__uintptr)s) & 3) == 0) - break; - *s++ = '0'; - --n; - } - while (n >= 4) { - *(stbsp__uint32 *)s = 0x30303030; - s += 4; - n -= 4; - } - } - while (n) { - if ((fl & STBSP__TRIPLET_COMMA) && (++cs == 4)) { - cs = 0; - *s++ = stbsp__comma; - } else { - *s++ = '0'; - --n; - } - } - } - cs = (int)(s - (num + 64)) + (3 << 24); // cs is how many tens - if (pr) { - *s++ = stbsp__period; - tz = pr; - } - } else { - // handle xxxxx.xxxx000*000 - n = 0; - for (;;) { - if ((fl & STBSP__TRIPLET_COMMA) && (++cs == 4)) { - cs = 0; - *s++ = stbsp__comma; - } else { - *s++ = sn[n]; - ++n; - if (n >= (stbsp__uint32)dp) - break; - } - } - cs = (int)(s - (num + 64)) + (3 << 24); // cs is how many tens - if (pr) - *s++ = stbsp__period; - if ((l - dp) > (stbsp__uint32)pr) - l = pr + dp; - while (n < l) { - *s++ = sn[n]; - ++n; - } - tz = pr - (l - dp); - } - } - pr = 0; - - // handle k,m,g,t - if (fl & STBSP__METRIC_SUFFIX) { - char idx; - idx = 1; - if (fl & STBSP__METRIC_NOSPACE) - idx = 0; - tail[0] = idx; - tail[1] = ' '; - { - if (fl >> 24) { // SI kilo is 'k', JEDEC and SI kibits are 'K'. - if (fl & STBSP__METRIC_1024) - tail[idx + 1] = "_KMGT"[fl >> 24]; - else - tail[idx + 1] = "_kMGT"[fl >> 24]; - idx++; - // If printing kibits and not in jedec, add the 'i'. - if (fl & STBSP__METRIC_1024 && !(fl & STBSP__METRIC_JEDEC)) { - tail[idx + 1] = 'i'; - idx++; - } - tail[0] = idx; - } - } - }; - - flt_lead: - // get the length that we copied - l = (stbsp__uint32)(s - (num + 64)); - s = num + 64; - goto scopy; -#endif - - case 'B': // upper binary - case 'b': // lower binary - h = (f[0] == 'B') ? hexu : hex; - lead[0] = 0; - if (fl & STBSP__LEADING_0X) { - lead[0] = 2; - lead[1] = '0'; - lead[2] = h[0xb]; - } - l = (8 << 4) | (1 << 8); - goto radixnum; - - case 'o': // octal - h = hexu; - lead[0] = 0; - if (fl & STBSP__LEADING_0X) { - lead[0] = 1; - lead[1] = '0'; - } - l = (3 << 4) | (3 << 8); - goto radixnum; - - case 'p': // pointer - fl |= (sizeof(void *) == 8) ? STBSP__INTMAX : 0; - pr = sizeof(void *) * 2; - fl &= ~STBSP__LEADINGZERO; // 'p' only prints the pointer with zeros - // fall through - to X - - case 'X': // upper hex - case 'x': // lower hex - h = (f[0] == 'X') ? hexu : hex; - l = (4 << 4) | (4 << 8); - lead[0] = 0; - if (fl & STBSP__LEADING_0X) { - lead[0] = 2; - lead[1] = '0'; - lead[2] = h[16]; - } - radixnum: - // get the number - if (fl & STBSP__INTMAX) - n64 = va_arg(va, stbsp__uint64); - else - n64 = va_arg(va, stbsp__uint32); - - s = num + STBSP__NUMSZ; - dp = 0; - // clear tail, and clear leading if value is zero - tail[0] = 0; - if (n64 == 0) { - lead[0] = 0; - if (pr == 0) { - l = 0; - cs = (((l >> 4) & 15)) << 24; - goto scopy; - } - } - // convert to string - for (;;) { - *--s = h[n64 & ((1 << (l >> 8)) - 1)]; - n64 >>= (l >> 8); - if (!((n64) || ((stbsp__int32)((num + STBSP__NUMSZ) - s) < pr))) - break; - if (fl & STBSP__TRIPLET_COMMA) { - ++l; - if ((l & 15) == ((l >> 4) & 15)) { - l &= ~15; - *--s = stbsp__comma; - } - } - }; - // get the tens and the comma pos - cs = (stbsp__uint32)((num + STBSP__NUMSZ) - s) + ((((l >> 4) & 15)) << 24); - // get the length that we copied - l = (stbsp__uint32)((num + STBSP__NUMSZ) - s); - // copy it - goto scopy; - - case 'u': // unsigned - case 'i': - case 'd': // integer - // get the integer and abs it - if (fl & STBSP__INTMAX) { - stbsp__int64 i64 = va_arg(va, stbsp__int64); - n64 = (stbsp__uint64)i64; - if ((f[0] != 'u') && (i64 < 0)) { - n64 = (stbsp__uint64)-i64; - fl |= STBSP__NEGATIVE; - } - } else { - stbsp__int32 i = va_arg(va, stbsp__int32); - n64 = (stbsp__uint32)i; - if ((f[0] != 'u') && (i < 0)) { - n64 = (stbsp__uint32)-i; - fl |= STBSP__NEGATIVE; - } - } - -#ifndef STB_SPRINTF_NOFLOAT - if (fl & STBSP__METRIC_SUFFIX) { - if (n64 < 1024) - pr = 0; - else if (pr == -1) - pr = 1; - fv = (double)(stbsp__int64)n64; - goto doafloat; - } -#endif - - // convert to string - s = num + STBSP__NUMSZ; - l = 0; - - for (;;) { - // do in 32-bit chunks (avoid lots of 64-bit divides even with constant denominators) - char *o = s - 8; - if (n64 >= 100000000) { - n = (stbsp__uint32)(n64 % 100000000); - n64 /= 100000000; - } else { - n = (stbsp__uint32)n64; - n64 = 0; - } - if ((fl & STBSP__TRIPLET_COMMA) == 0) { - do { - s -= 2; - *(stbsp__uint16 *)s = *(stbsp__uint16 *)&stbsp__digitpair[(n % 100) * 2]; - n /= 100; - } while (n); - } - while (n) { - if ((fl & STBSP__TRIPLET_COMMA) && (l++ == 3)) { - l = 0; - *--s = stbsp__comma; - --o; - } else { - *--s = (char)(n % 10) + '0'; - n /= 10; - } - } - if (n64 == 0) { - if ((s[0] == '0') && (s != (num + STBSP__NUMSZ))) - ++s; - break; - } - while (s != o) - if ((fl & STBSP__TRIPLET_COMMA) && (l++ == 3)) { - l = 0; - *--s = stbsp__comma; - --o; - } else { - *--s = '0'; - } - } - - tail[0] = 0; - stbsp__lead_sign(fl, lead); - - // get the length that we copied - l = (stbsp__uint32)((num + STBSP__NUMSZ) - s); - if (l == 0) { - *--s = '0'; - l = 1; - } - cs = l + (3 << 24); - if (pr < 0) - pr = 0; - - scopy: - // get fw=leading/trailing space, pr=leading zeros - if (pr < (stbsp__int32)l) - pr = l; - n = pr + lead[0] + tail[0] + tz; - if (fw < (stbsp__int32)n) - fw = n; - fw -= n; - pr -= l; - - // handle right justify and leading zeros - if ((fl & STBSP__LEFTJUST) == 0) { - if (fl & STBSP__LEADINGZERO) // if leading zeros, everything is in pr - { - pr = (fw > pr) ? fw : pr; - fw = 0; - } else { - fl &= ~STBSP__TRIPLET_COMMA; // if no leading zeros, then no commas - } - } - - // copy the spaces and/or zeros - if (fw + pr) { - stbsp__int32 i; - stbsp__uint32 c; - - // copy leading spaces (or when doing %8.4d stuff) - if ((fl & STBSP__LEFTJUST) == 0) - while (fw > 0) { - stbsp__cb_buf_clamp(i, fw); - fw -= i; - while (i) { - if ((((stbsp__uintptr)bf) & 3) == 0) - break; - *bf++ = ' '; - --i; - } - while (i >= 4) { - *(stbsp__uint32 *)bf = 0x20202020; - bf += 4; - i -= 4; - } - while (i) { - *bf++ = ' '; - --i; - } - stbsp__chk_cb_buf(1); - } - - // copy leader - sn = lead + 1; - while (lead[0]) { - stbsp__cb_buf_clamp(i, lead[0]); - lead[0] -= (char)i; - while (i) { - *bf++ = *sn++; - --i; - } - stbsp__chk_cb_buf(1); - } - - // copy leading zeros - c = cs >> 24; - cs &= 0xffffff; - cs = (fl & STBSP__TRIPLET_COMMA) ? ((stbsp__uint32)(c - ((pr + cs) % (c + 1)))) : 0; - while (pr > 0) { - stbsp__cb_buf_clamp(i, pr); - pr -= i; - if ((fl & STBSP__TRIPLET_COMMA) == 0) { - while (i) { - if ((((stbsp__uintptr)bf) & 3) == 0) - break; - *bf++ = '0'; - --i; - } - while (i >= 4) { - *(stbsp__uint32 *)bf = 0x30303030; - bf += 4; - i -= 4; - } - } - while (i) { - if ((fl & STBSP__TRIPLET_COMMA) && (cs++ == c)) { - cs = 0; - *bf++ = stbsp__comma; - } else - *bf++ = '0'; - --i; - } - stbsp__chk_cb_buf(1); - } - } - - // copy leader if there is still one - sn = lead + 1; - while (lead[0]) { - stbsp__int32 i; - stbsp__cb_buf_clamp(i, lead[0]); - lead[0] -= (char)i; - while (i) { - *bf++ = *sn++; - --i; - } - stbsp__chk_cb_buf(1); - } - - // copy the string - n = l; - while (n) { - stbsp__int32 i; - stbsp__cb_buf_clamp(i, n); - n -= i; - STBSP__UNALIGNED(while (i >= 4) { - *(stbsp__uint32 *)bf = *(stbsp__uint32 *)s; - bf += 4; - s += 4; - i -= 4; - }) - while (i) { - *bf++ = *s++; - --i; - } - stbsp__chk_cb_buf(1); - } - - // copy trailing zeros - while (tz) { - stbsp__int32 i; - stbsp__cb_buf_clamp(i, tz); - tz -= i; - while (i) { - if ((((stbsp__uintptr)bf) & 3) == 0) - break; - *bf++ = '0'; - --i; - } - while (i >= 4) { - *(stbsp__uint32 *)bf = 0x30303030; - bf += 4; - i -= 4; - } - while (i) { - *bf++ = '0'; - --i; - } - stbsp__chk_cb_buf(1); - } - - // copy tail if there is one - sn = tail + 1; - while (tail[0]) { - stbsp__int32 i; - stbsp__cb_buf_clamp(i, tail[0]); - tail[0] -= (char)i; - while (i) { - *bf++ = *sn++; - --i; - } - stbsp__chk_cb_buf(1); - } - - // handle the left justify - if (fl & STBSP__LEFTJUST) - if (fw > 0) { - while (fw) { - stbsp__int32 i; - stbsp__cb_buf_clamp(i, fw); - fw -= i; - while (i) { - if ((((stbsp__uintptr)bf) & 3) == 0) - break; - *bf++ = ' '; - --i; - } - while (i >= 4) { - *(stbsp__uint32 *)bf = 0x20202020; - bf += 4; - i -= 4; - } - while (i--) - *bf++ = ' '; - stbsp__chk_cb_buf(1); - } - } - break; - - default: // unknown, just copy code - s = num + STBSP__NUMSZ - 1; - *s = f[0]; - l = 1; - fw = fl = 0; - lead[0] = 0; - tail[0] = 0; - pr = 0; - dp = 0; - cs = 0; - goto scopy; - } - ++f; - } -endfmt: - - if (!callback) - *bf = 0; - else - stbsp__flush_cb(); - -done: - return tlen + (int)(bf - buf); -} - -// cleanup -#undef STBSP__LEFTJUST -#undef STBSP__LEADINGPLUS -#undef STBSP__LEADINGSPACE -#undef STBSP__LEADING_0X -#undef STBSP__LEADINGZERO -#undef STBSP__INTMAX -#undef STBSP__TRIPLET_COMMA -#undef STBSP__NEGATIVE -#undef STBSP__METRIC_SUFFIX -#undef STBSP__NUMSZ -#undef stbsp__chk_cb_bufL -#undef stbsp__chk_cb_buf -#undef stbsp__flush_cb -#undef stbsp__cb_buf_clamp - -// ============================================================================ -// wrapper functions - -STBSP__PUBLICDEF int STB_SPRINTF_DECORATE(sprintf)(char *buf, char const *fmt, ...) -{ - int result; - va_list va; - va_start(va, fmt); - result = STB_SPRINTF_DECORATE(vsprintfcb)(0, 0, buf, fmt, va); - va_end(va); - return result; -} - -typedef struct stbsp__context { - char *buf; - int count; - char tmp[STB_SPRINTF_MIN]; -} stbsp__context; - -static char *stbsp__clamp_callback(char *buf, void *user, int len) -{ - stbsp__context *c = (stbsp__context *)user; - - if (len > c->count) - len = c->count; - - if (len) { - if (buf != c->buf) { - char *s, *d, *se; - d = c->buf; - s = buf; - se = buf + len; - do { - *d++ = *s++; - } while (s < se); - } - c->buf += len; - c->count -= len; - } - - if (c->count <= 0) - return 0; - return (c->count >= STB_SPRINTF_MIN) ? c->buf : c->tmp; // go direct into buffer if you can -} - -static char * stbsp__count_clamp_callback( char * buf, void * user, int len ) -{ - (void)buf; - stbsp__context * c = (stbsp__context*)user; - c->count += len; - return c->tmp; // go direct into buffer if you can -} - -STBSP__PUBLICDEF int STB_SPRINTF_DECORATE( vsnprintf )( char * buf, int count, char const * fmt, va_list va ) -{ - stbsp__context c; - int l; - - if ( (count == 0) && !buf ) - { - c.count = 0; - - STB_SPRINTF_DECORATE( vsprintfcb )( stbsp__count_clamp_callback, &c, c.tmp, fmt, va ); - l = c.count; - } - else - { - if ( count == 0 ) - return 0; - - c.buf = buf; - c.count = count; - - STB_SPRINTF_DECORATE( vsprintfcb )( stbsp__clamp_callback, &c, stbsp__clamp_callback(0,&c,0), fmt, va ); - - // zero-terminate - l = (int)( c.buf - buf ); - if ( l >= count ) // should never be greater, only equal (or less) than count - l = count - 1; - buf[l] = 0; - } - - return l; -} - -STBSP__PUBLICDEF int STB_SPRINTF_DECORATE(snprintf)(char *buf, int count, char const *fmt, ...) -{ - int result; - va_list va; - va_start(va, fmt); - - result = STB_SPRINTF_DECORATE(vsnprintf)(buf, count, fmt, va); - va_end(va); - - return result; -} - -STBSP__PUBLICDEF int STB_SPRINTF_DECORATE(vsprintf)(char *buf, char const *fmt, va_list va) -{ - return STB_SPRINTF_DECORATE(vsprintfcb)(0, 0, buf, fmt, va); -} - -// ======================================================================= -// low level float utility functions - -#ifndef STB_SPRINTF_NOFLOAT - -// copies d to bits w/ strict aliasing (this compiles to nothing on /Ox) -#define STBSP__COPYFP(dest, src) \ - { \ - int cn; \ - for (cn = 0; cn < 8; cn++) \ - ((char *)&dest)[cn] = ((char *)&src)[cn]; \ - } - -// get float info -static stbsp__int32 stbsp__real_to_parts(stbsp__int64 *bits, stbsp__int32 *expo, double value) -{ - double d; - stbsp__int64 b = 0; - - // load value and round at the frac_digits - d = value; - - STBSP__COPYFP(b, d); - - *bits = b & ((((stbsp__uint64)1) << 52) - 1); - *expo = (stbsp__int32)(((b >> 52) & 2047) - 1023); - - return (stbsp__int32)(b >> 63); -} - -static double const stbsp__bot[23] = { - 1e+000, 1e+001, 1e+002, 1e+003, 1e+004, 1e+005, 1e+006, 1e+007, 1e+008, 1e+009, 1e+010, 1e+011, - 1e+012, 1e+013, 1e+014, 1e+015, 1e+016, 1e+017, 1e+018, 1e+019, 1e+020, 1e+021, 1e+022 -}; -static double const stbsp__negbot[22] = { - 1e-001, 1e-002, 1e-003, 1e-004, 1e-005, 1e-006, 1e-007, 1e-008, 1e-009, 1e-010, 1e-011, - 1e-012, 1e-013, 1e-014, 1e-015, 1e-016, 1e-017, 1e-018, 1e-019, 1e-020, 1e-021, 1e-022 -}; -static double const stbsp__negboterr[22] = { - -5.551115123125783e-018, -2.0816681711721684e-019, -2.0816681711721686e-020, -4.7921736023859299e-021, -8.1803053914031305e-022, 4.5251888174113741e-023, - 4.5251888174113739e-024, -2.0922560830128471e-025, -6.2281591457779853e-026, -3.6432197315497743e-027, 6.0503030718060191e-028, 2.0113352370744385e-029, - -3.0373745563400371e-030, 1.1806906454401013e-032, -7.7705399876661076e-032, 2.0902213275965398e-033, -7.1542424054621921e-034, -7.1542424054621926e-035, - 2.4754073164739869e-036, 5.4846728545790429e-037, 9.2462547772103625e-038, -4.8596774326570872e-039 -}; -static double const stbsp__top[13] = { - 1e+023, 1e+046, 1e+069, 1e+092, 1e+115, 1e+138, 1e+161, 1e+184, 1e+207, 1e+230, 1e+253, 1e+276, 1e+299 -}; -static double const stbsp__negtop[13] = { - 1e-023, 1e-046, 1e-069, 1e-092, 1e-115, 1e-138, 1e-161, 1e-184, 1e-207, 1e-230, 1e-253, 1e-276, 1e-299 -}; -static double const stbsp__toperr[13] = { - 8388608, - 6.8601809640529717e+028, - -7.253143638152921e+052, - -4.3377296974619174e+075, - -1.5559416129466825e+098, - -3.2841562489204913e+121, - -3.7745893248228135e+144, - -1.7356668416969134e+167, - -3.8893577551088374e+190, - -9.9566444326005119e+213, - 6.3641293062232429e+236, - -5.2069140800249813e+259, - -5.2504760255204387e+282 -}; -static double const stbsp__negtoperr[13] = { - 3.9565301985100693e-040, -2.299904345391321e-063, 3.6506201437945798e-086, 1.1875228833981544e-109, - -5.0644902316928607e-132, -6.7156837247865426e-155, -2.812077463003139e-178, -5.7778912386589953e-201, - 7.4997100559334532e-224, -4.6439668915134491e-247, -6.3691100762962136e-270, -9.436808465446358e-293, - 8.0970921678014997e-317 -}; - -#if defined(_MSC_VER) && (_MSC_VER <= 1200) -static stbsp__uint64 const stbsp__powten[20] = { - 1, - 10, - 100, - 1000, - 10000, - 100000, - 1000000, - 10000000, - 100000000, - 1000000000, - 10000000000, - 100000000000, - 1000000000000, - 10000000000000, - 100000000000000, - 1000000000000000, - 10000000000000000, - 100000000000000000, - 1000000000000000000, - 10000000000000000000U -}; -#define stbsp__tento19th ((stbsp__uint64)1000000000000000000) -#else -static stbsp__uint64 const stbsp__powten[20] = { - 1, - 10, - 100, - 1000, - 10000, - 100000, - 1000000, - 10000000, - 100000000, - 1000000000, - 10000000000ULL, - 100000000000ULL, - 1000000000000ULL, - 10000000000000ULL, - 100000000000000ULL, - 1000000000000000ULL, - 10000000000000000ULL, - 100000000000000000ULL, - 1000000000000000000ULL, - 10000000000000000000ULL -}; -#define stbsp__tento19th (1000000000000000000ULL) -#endif - -#define stbsp__ddmulthi(oh, ol, xh, yh) \ - { \ - double ahi = 0, alo, bhi = 0, blo; \ - stbsp__int64 bt; \ - oh = xh * yh; \ - STBSP__COPYFP(bt, xh); \ - bt &= ((~(stbsp__uint64)0) << 27); \ - STBSP__COPYFP(ahi, bt); \ - alo = xh - ahi; \ - STBSP__COPYFP(bt, yh); \ - bt &= ((~(stbsp__uint64)0) << 27); \ - STBSP__COPYFP(bhi, bt); \ - blo = yh - bhi; \ - ol = ((ahi * bhi - oh) + ahi * blo + alo * bhi) + alo * blo; \ - } - -#define stbsp__ddtoS64(ob, xh, xl) \ - { \ - double ahi = 0, alo, vh, t; \ - ob = (stbsp__int64)ph; \ - vh = (double)ob; \ - ahi = (xh - vh); \ - t = (ahi - xh); \ - alo = (xh - (ahi - t)) - (vh + t); \ - ob += (stbsp__int64)(ahi + alo + xl); \ - } - -#define stbsp__ddrenorm(oh, ol) \ - { \ - double s; \ - s = oh + ol; \ - ol = ol - (s - oh); \ - oh = s; \ - } - -#define stbsp__ddmultlo(oh, ol, xh, xl, yh, yl) ol = ol + (xh * yl + xl * yh); - -#define stbsp__ddmultlos(oh, ol, xh, yl) ol = ol + (xh * yl); - -static void stbsp__raise_to_power10(double *ohi, double *olo, double d, stbsp__int32 power) // power can be -323 to +350 -{ - double ph, pl; - if ((power >= 0) && (power <= 22)) { - stbsp__ddmulthi(ph, pl, d, stbsp__bot[power]); - } else { - stbsp__int32 e, et, eb; - double p2h, p2l; - - e = power; - if (power < 0) - e = -e; - et = (e * 0x2c9) >> 14; /* %23 */ - if (et > 13) - et = 13; - eb = e - (et * 23); - - ph = d; - pl = 0.0; - if (power < 0) { - if (eb) { - --eb; - stbsp__ddmulthi(ph, pl, d, stbsp__negbot[eb]); - stbsp__ddmultlos(ph, pl, d, stbsp__negboterr[eb]); - } - if (et) { - stbsp__ddrenorm(ph, pl); - --et; - stbsp__ddmulthi(p2h, p2l, ph, stbsp__negtop[et]); - stbsp__ddmultlo(p2h, p2l, ph, pl, stbsp__negtop[et], stbsp__negtoperr[et]); - ph = p2h; - pl = p2l; - } - } else { - if (eb) { - e = eb; - if (eb > 22) - eb = 22; - e -= eb; - stbsp__ddmulthi(ph, pl, d, stbsp__bot[eb]); - if (e) { - stbsp__ddrenorm(ph, pl); - stbsp__ddmulthi(p2h, p2l, ph, stbsp__bot[e]); - stbsp__ddmultlos(p2h, p2l, stbsp__bot[e], pl); - ph = p2h; - pl = p2l; - } - } - if (et) { - stbsp__ddrenorm(ph, pl); - --et; - stbsp__ddmulthi(p2h, p2l, ph, stbsp__top[et]); - stbsp__ddmultlo(p2h, p2l, ph, pl, stbsp__top[et], stbsp__toperr[et]); - ph = p2h; - pl = p2l; - } - } - } - stbsp__ddrenorm(ph, pl); - *ohi = ph; - *olo = pl; -} - -// given a float value, returns the significant bits in bits, and the position of the -// decimal point in decimal_pos. +/-INF and NAN are specified by special values -// returned in the decimal_pos parameter. -// frac_digits is absolute normally, but if you want from first significant digits (got %g and %e), or in 0x80000000 -static stbsp__int32 stbsp__real_to_str(char const **start, stbsp__uint32 *len, char *out, stbsp__int32 *decimal_pos, double value, stbsp__uint32 frac_digits) -{ - double d; - stbsp__int64 bits = 0; - stbsp__int32 expo, e, ng, tens; - - d = value; - STBSP__COPYFP(bits, d); - expo = (stbsp__int32)((bits >> 52) & 2047); - ng = (stbsp__int32)(bits >> 63); - if (ng) - d = -d; - - if (expo == 2047) // is nan or inf? - { - *start = (bits & ((((stbsp__uint64)1) << 52) - 1)) ? "NaN" : "Inf"; - *decimal_pos = STBSP__SPECIAL; - *len = 3; - return ng; - } - - if (expo == 0) // is zero or denormal - { - if ((bits << 1) == 0) // do zero - { - *decimal_pos = 1; - *start = out; - out[0] = '0'; - *len = 1; - return ng; - } - // find the right expo for denormals - { - stbsp__int64 v = ((stbsp__uint64)1) << 51; - while ((bits & v) == 0) { - --expo; - v >>= 1; - } - } - } - - // find the decimal exponent as well as the decimal bits of the value - { - double ph, pl; - - // log10 estimate - very specifically tweaked to hit or undershoot by no more than 1 of log10 of all expos 1..2046 - tens = expo - 1023; - tens = (tens < 0) ? ((tens * 617) / 2048) : (((tens * 1233) / 4096) + 1); - - // move the significant bits into position and stick them into an int - stbsp__raise_to_power10(&ph, &pl, d, 18 - tens); - - // get full as much precision from double-double as possible - stbsp__ddtoS64(bits, ph, pl); - - // check if we undershot - if (((stbsp__uint64)bits) >= stbsp__tento19th) - ++tens; - } - - // now do the rounding in integer land - frac_digits = (frac_digits & 0x80000000) ? ((frac_digits & 0x7ffffff) + 1) : (tens + frac_digits); - if ((frac_digits < 24)) { - stbsp__uint32 dg = 1; - if ((stbsp__uint64)bits >= stbsp__powten[9]) - dg = 10; - while ((stbsp__uint64)bits >= stbsp__powten[dg]) { - ++dg; - if (dg == 20) - goto noround; - } - if (frac_digits < dg) { - stbsp__uint64 r; - // add 0.5 at the right position and round - e = dg - frac_digits; - if ((stbsp__uint32)e >= 24) - goto noround; - r = stbsp__powten[e]; - bits = bits + (r / 2); - if ((stbsp__uint64)bits >= stbsp__powten[dg]) - ++tens; - bits /= r; - } - noround:; - } - - // kill long trailing runs of zeros - if (bits) { - stbsp__uint32 n; - for (;;) { - if (bits <= 0xffffffff) - break; - if (bits % 1000) - goto donez; - bits /= 1000; - } - n = (stbsp__uint32)bits; - while ((n % 1000) == 0) - n /= 1000; - bits = n; - donez:; - } - - // convert to string - out += 64; - e = 0; - for (;;) { - stbsp__uint32 n; - char *o = out - 8; - // do the conversion in chunks of U32s (avoid most 64-bit divides, worth it, constant denomiators be damned) - if (bits >= 100000000) { - n = (stbsp__uint32)(bits % 100000000); - bits /= 100000000; - } else { - n = (stbsp__uint32)bits; - bits = 0; - } - while (n) { - out -= 2; - *(stbsp__uint16 *)out = *(stbsp__uint16 *)&stbsp__digitpair[(n % 100) * 2]; - n /= 100; - e += 2; - } - if (bits == 0) { - if ((e) && (out[0] == '0')) { - ++out; - --e; - } - break; - } - while (out != o) { - *--out = '0'; - ++e; - } - } - - *decimal_pos = tens; - *start = out; - *len = e; - return ng; -} - -#undef stbsp__ddmulthi -#undef stbsp__ddrenorm -#undef stbsp__ddmultlo -#undef stbsp__ddmultlos -#undef STBSP__SPECIAL -#undef STBSP__COPYFP - -#endif // STB_SPRINTF_NOFLOAT - -// clean up -#undef stbsp__uint16 -#undef stbsp__uint32 -#undef stbsp__int32 -#undef stbsp__uint64 -#undef stbsp__int64 -#undef STBSP__UNALIGNED -#ifdef __GNUC__ - #pragma GCC diagnostic pop -#endif -#endif // DQN_IMPLEMENTATION - -#if defined(DQN__XPLATFORM_LAYER) -// #XPlatform (Win32 & Unix) -// ================================================================================================= -// Functions in the Cross Platform are guaranteed to be supported in both Unix -// and Win32 - -#ifdef DQN_IS_UNIX - #include // Basic File I/O // TODO(doyle): Syscall versions - - #include // readdir()/opendir()/closedir() - #include // file size query - #include // high resolution timer - #include // timespec - #include // unlink() -#endif - -#define DQN_FILE__LIST_DIR(name) DQN_FILE_SCOPE char **name(char const *dir, i32 *num_files, DqnAllocator *allocator) - -// XPlatform > #DqnFile -// ================================================================================================= -#ifdef DQN_IS_WIN32 - -FILE_SCOPE bool -DqnFile__Win32Open(wchar_t const *path, DqnFile *file, u32 flags, DqnFile::Action action) -{ - if (!file || !path) return false; - - u32 const WIN32_GENERIC_READ = 0x80000000L; - u32 const WIN32_GENERIC_WRITE = 0x40000000L; - u32 const WIN32_GENERIC_EXECUTE = 0x20000000L; - u32 const WIN32_GENERIC_ALL = 0x10000000L; - - u32 const WIN32_CREATE_NEW = 1; - u32 const WIN32_CREATE_ALWAYS = 2; - u32 const WIN32_OPEN_EXISTING = 3; - u32 const WIN32_OPEN_ALWAYS = 4; - u32 const WIN32_TRUNCATE_EXISTING = 5; - - u32 const WIN32_FILE_ATTRIBUTE_NORMAL = 0x00000080; - - DWORD win32_flag = 0; - if (flags & DqnFile::Flag::All) - { - win32_flag = WIN32_GENERIC_ALL; - } - else - { - if (flags & DqnFile::Flag::FileRead) win32_flag |= WIN32_GENERIC_READ; - if (flags & DqnFile::Flag::FileWrite) win32_flag |= WIN32_GENERIC_WRITE; - if (flags & DqnFile::Flag::Execute) win32_flag |= WIN32_GENERIC_EXECUTE; - } - - DWORD win32_action = 0; - switch (action) - { - // Allow fall through - default: DQN_ASSERT(DQN_INVALID_CODE_PATH); - case DqnFile::Action::OpenOnly: win32_action = WIN32_OPEN_EXISTING; break; - case DqnFile::Action::ClearIfExist: win32_action = WIN32_TRUNCATE_EXISTING; break; - case DqnFile::Action::CreateIfNotExist: win32_action = WIN32_CREATE_NEW; break; - case DqnFile::Action::ForceCreate: win32_action = WIN32_CREATE_ALWAYS; break; - } - - HANDLE handle = CreateFileW(path, win32_flag, 0, nullptr, win32_action, - WIN32_FILE_ATTRIBUTE_NORMAL, nullptr); - - if (handle == INVALID_HANDLE_VALUE) - { - return false; - } - - LARGE_INTEGER size; - if (GetFileSizeEx(handle, &size) == 0) - { - file->Close(); - DqnWin32_DisplayLastError("GetFileSizeEx() failed"); - return false; - } - - file->handle = handle; - file->size = (usize)size.QuadPart; - file->flags = flags; - return true; -} - -DQN_FILE__LIST_DIR(DqnFile__PlatformListDir) -{ - if (!dir) return nullptr; - - i32 curr_num_files = 0; - wchar_t wide_dir[MAX_PATH] = {0}; - DqnWin32_UTF8ToWChar(dir, wide_dir, DQN_ARRAY_COUNT(wide_dir)); - - // Enumerate number of files first - { - WIN32_FIND_DATAW find_data = {0}; - HANDLE find_handle = FindFirstFileW(wide_dir, &find_data); - if (find_handle == INVALID_HANDLE_VALUE) - { - DQN__WIN32_ERROR_BOX("FindFirstFile() failed.", nullptr); - return nullptr; - } - - DQN_DEFER { FindClose(find_handle); }; - bool stay_in_loop = true; - while (stay_in_loop) - { - BOOL result = FindNextFileW(find_handle, &find_data); - if (result == 0) - { - DWORD error = GetLastError(); - - u32 const WIN32_ERROR_NO_MORE_FILES = 18L; - if (error != WIN32_ERROR_NO_MORE_FILES) - { - DqnWin32_DisplayErrorCode(error, "FindNextFileW() failed"); - } - - stay_in_loop = false; - } - else - { - curr_num_files++; - } - } - } - - if (curr_num_files == 0) - { - *num_files = 0; - return nullptr; - } - - { - WIN32_FIND_DATAW init_find = {}; - HANDLE find_handle = FindFirstFileW(wide_dir, &init_find); - if (find_handle == INVALID_HANDLE_VALUE) - { - DQN__WIN32_ERROR_BOX("FindFirstFile() failed.", nullptr); - *num_files = 0; - return nullptr; - } - - DQN_DEFER { FindClose(find_handle); }; - char **list = (char **)allocator->Malloc(sizeof(*list) * (curr_num_files), Dqn::ZeroMem::Yes); - - if (!list) - { - DQN_LOGGER_E(dqn_lib_context_.logger, "Memory allocation failed, required: %$_d", sizeof(*list) * curr_num_files); - *num_files = 0; - return nullptr; - } - - DQN_FOR_EACH(i, curr_num_files) - { - // TODO(doyle): Max path is bad. - size_t bytes_required = sizeof(**list) * MAX_PATH; - list[i] = (char *)allocator->Malloc(bytes_required, Dqn::ZeroMem::Yes); - if (!list[i]) - { - DQN_FOR_EACH(j, i) - allocator->Free(list[j], bytes_required); - - DQN_LOGGER_E(dqn_lib_context_.logger, "Memory allocation failed, required: %$_d", sizeof(**list) * MAX_PATH); - *num_files = 0; - return nullptr; - } - } - - i32 list_index = 0; - WIN32_FIND_DATAW find_data = {0}; - while (FindNextFileW(find_handle, &find_data) != 0) - { - DqnWin32_WCharToUTF8(find_data.cFileName, list[list_index++], MAX_PATH); - } - - *num_files = curr_num_files; - - return list; - } -} -#endif // DQN_IS_WIN32 - -#ifdef DQN_IS_UNIX -FILE_SCOPE bool DqnFile__UnixGetFileSize(char const *path, usize *size) -{ - struct stat file_stat = {}; - stat(path, &file_stat); - if (size) *size = file_stat.st_size; - - if (file_stat.st_size != 0) - return true; - - // NOTE: Can occur in some instances where files are generated on demand, i.e. /proc/cpuinfo. - // 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); }; - while (fgetc(file) != EOF) - { - (*size)++; - } - } - - return true; -} - -FILE_SCOPE bool -DqnFile__UnixOpen(char const *path, DqnFile *file, u32 flags, DqnFile::Action action) -{ - char operation = 0; - bool update_flag = false; - - if (flags & DqnFile::Flag::FileWrite) - { - update_flag = true; - switch (action) - { - default: DQN_ASSERT(DQN_INVALID_CODE_PATH); - case DqnFile::Action::OpenOnly: - { - operation = 'r'; - } - break; - - case DqnFile::Action::CreateIfNotExist: - case DqnFile::Action::ClearIfExist: - case DqnFile::Action::ForceCreate: - { - operation = 'w'; - } - break; - } - } - else if ((flags & DqnFile::Flag::FileRead) || - (flags & DqnFile::Flag::Execute)) - { - if (flags & DqnFile::Flag::Execute) - { - // TODO(doyle): Logging, UNIX doesn't have execute param for file - // handles. Execution goes through system() - } - operation = 'r'; - } - DQN_ASSERT(operation != 0); - - // TODO(doyle): What about not reading as a binary file and appending to end of file. - u32 mode_index = 0; - char mode[4] = {}; - mode[mode_index++] = operation; - - if (update_flag) mode[mode_index++] = '+'; - - mode[mode_index++] = 'b'; - DQN_ASSERT(mode_index <= DQN_ARRAY_COUNT(mode) - 1); - - // TODO(doyle): Use open syscall - // TODO(doyle): Query errno - if (!DqnFile__UnixGetFileSize(path, &file->size)) - { - return false; - } - - file->handle = fopen(path, mode); - file->flags = flags; - return true; -} - -DQN_FILE__LIST_DIR(DqnFile__PlatformListDir) -{ - if (!dir) return nullptr; - - // Enumerate num files - i32 curr_num_files = 0; - { - DIR *const dir_handle = opendir(dir); - if (!dir_handle) return nullptr; - DQN_DEFER { closedir(dir_handle); }; - - struct dirent *dir_file = readdir(dir_handle); - while (dir_file) - { - curr_num_files++; - dir_file = readdir(dir_handle); - } - } - - if (curr_num_files == 0) - { - *num_files = 0; - return nullptr; - } - - // Create file list - { - DIR *const dir_handle = opendir(dir); - if (!dir_handle) return nullptr; - DQN_DEFER { closedir(dir_handle); }; - - char **list = (char **)allocator->Calloc(1, sizeof(*list) * curr_num_files); - if (!list) - { - DQN_LOGE("Memory allocation failed, required: %$_d", sizeof(*list) * curr_num_files); - *num_files = 0; - return nullptr; - } - - struct dirent *dir_file = readdir(dir_handle); - for (auto i = 0; i < curr_num_files; i++) - { - list[i] = (char *)allocator->Calloc(1, sizeof(**list) * DQN_ARRAY_COUNT(dir_file->d_name)); - if (!list[i]) - { - for (auto j = 0; j < i; j++) api->Free(list[j]); - - DQN_LOGE("Memory allocation failed, required: %$_d", sizeof(**list) * DQN_ARRAY_COUNT(dir_file->d_name)); - *num_files = 0; - return nullptr; - } - } - - u32 list_index = 0; - *num_files = curr_num_files; - while (dir_file) - { - DqnMem_Copy(list[list_index++], dir_file->d_name, DQN_ARRAY_COUNT(dir_file->d_name)); - dir_file = readdir(dir_handle); - } - - return list; - } -} -#endif // DQN_IS_UNIX - -bool DqnFile::Open(char const *path, u32 flags_, Action action) -{ - if (!path) return false; - -#if defined(DQN_IS_WIN32) - // TODO(doyle): MAX PATH is baad - wchar_t wide_path[MAX_PATH] = {}; - DqnWin32_UTF8ToWChar(path, wide_path, DQN_ARRAY_COUNT(wide_path)); - return DqnFile__Win32Open(wide_path, this, flags_, action); -#else - return DqnFile__UnixOpen(path, this, flags_, action); -#endif -} - -bool DqnFile::Open(wchar_t const *path, u32 flags_, Action action) -{ - if (!path) return false; - -#if defined(DQN_IS_WIN32) - return DqnFile__Win32Open(path, this, flags_, action); - -#else - DQN_ASSERT(DQN_INVALID_CODE_PATH); - return false; -#endif -} - -usize DqnFile::Write(u8 const *buf, usize num_bytes_to_write) -{ - // TODO(doyle): Implement when it's needed - 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); - - num_bytes_written = (usize)bytes_written; - // TODO(doyle): Better logging system - if (result == 0) - { - DQN__WIN32_ERROR_BOX("ReadFile() failed.", nullptr); - } - -#else - const usize ITEMS_TO_WRITE = 1; - if (fwrite(buf, num_bytes_to_write, ITEMS_TO_WRITE, (FILE *)this->handle) == ITEMS_TO_WRITE) - { - num_bytes_written = ITEMS_TO_WRITE * num_bytes_to_write; - } -#endif - - return num_bytes_written; -} - -usize DqnFile::Read(u8 *buf, usize num_bytes_to_read) -{ - usize num_bytes_read = 0; - if (buf && this->handle) - { -#if defined(DQN_IS_WIN32) - DWORD bytes_to_read = (DWORD)num_bytes_to_read; - DWORD bytes_read = 0; - HANDLE win32_handle = this->handle; - - BOOL result = ReadFile(win32_handle, (void *)buf, bytes_to_read, &bytes_read, nullptr); - - num_bytes_read = (usize)bytes_read; - // TODO(doyle): 0 also means it is completing async, but still valid - if (result == 0) - { - DQN__WIN32_ERROR_BOX("ReadFile() failed.", nullptr); - } - -#else - // TODO(doyle): Syscall version - const usize ITEMS_TO_READ = 1; - if (fread(buf, num_bytes_to_read, ITEMS_TO_READ, (FILE *)this->handle) == ITEMS_TO_READ) - { - rewind((FILE *)this->handle); - num_bytes_read = ITEMS_TO_READ * num_bytes_to_read; - } - else - { - // TODO(doyle): Logging, failed read - } -#endif - } - return num_bytes_read; -} - -u8 *DqnFile_ReadAll(wchar_t const *path, usize *buf_size, DqnAllocator *allocator) -{ - // TODO(doyle): Logging - usize required_size = 0; - if (!DqnFile_Size(path, &required_size) || required_size == 0) - return nullptr; - - auto *buf = (u8 *)allocator->Malloc(required_size); - if (DqnFile_ReadAll(path, buf, required_size)) - { - *buf_size = required_size; - return buf; - } - - allocator->Free(buf, required_size); - return nullptr; -} - -DQN_FILE_SCOPE u8 *DqnFile_ReadAll(char const *path, usize *buf_size, DqnAllocator *allocator) -{ - // TODO(doyle): Logging - usize required_size = 0; - if (!DqnFile_Size(path, &required_size) || required_size == 0) - return nullptr; - - auto *buf = (u8 *)allocator->Malloc(required_size); - if (DqnFile_ReadAll(path, buf, required_size)) - { - *buf_size = required_size; - return buf; - } - - allocator->Free(buf, required_size); - return nullptr; -} - -DQN_FILE_SCOPE u8 *DqnFile_ReadAll(wchar_t const *path, usize *buf_size, DqnMemStack *stack) -{ - u8 *result = nullptr; - DqnFile file = {}; - if (!file.Open(path, DqnFile::Flag::FileRead, DqnFile::Action::OpenOnly)) - { - DQN_LOGGER_E(dqn_lib_context_.logger, "Could not open file: %s", path); - return result; - } - DQN_DEFER { file.Close(); }; - - result = DQN_MEMSTACK_PUSH_ARRAY(stack, u8, file.size); - usize bytes_read = file.Read(result, file.size); - if (bytes_read == file.size) - { - *buf_size = file.size; - } - else - { - DQN_LOGGER_E(dqn_lib_context_.logger, "bytes_read != file.size", bytes_read, file.size); - } - - return result; -} - -DQN_FILE_SCOPE u8 *DqnFile_ReadAll(char const *path, usize *buf_size, DqnMemStack *stack) -{ - u8 *result = nullptr; - DqnFile file = {}; - if (!file.Open(path, DqnFile::Flag::FileRead, DqnFile::Action::OpenOnly)) - { - DQN_LOGGER_E(dqn_lib_context_.logger, "Could not open file: %s", path); - return result; - } - DQN_DEFER { file.Close(); }; - - result = DQN_MEMSTACK_PUSH_ARRAY(stack, u8, file.size); - usize bytes_read = file.Read(result, file.size); - if (bytes_read == file.size) - { - *buf_size = file.size; - } - else - { - DQN_LOGGER_E(dqn_lib_context_.logger, "bytes_read != file.size", bytes_read, file.size); - } - - return result; -} - -DQN_FILE_SCOPE bool DqnFile_WriteAll(char const *path, u8 const *buf, usize const buf_size) -{ - DqnFile file = {}; - if (!file.Open(path, DqnFile::Flag::FileReadWrite, DqnFile::Action::ForceCreate)) - { - DQN_LOGGER_E(dqn_lib_context_.logger, "Could not open file at: %s", path); - return false; - } - - DQN_DEFER { file.Close(); }; - usize bytes_written = file.Write(buf, buf_size); - if (bytes_written != buf_size) - { - DQN_LOGGER_E(dqn_lib_context_.logger, "Bytes written did not match the buffer size, %zu != %zu", bytes_written, buf_size); - return false; - } - - return true; -} - -DQN_FILE_SCOPE bool DqnFile_WriteAll(wchar_t const *path, u8 const *buf, usize const buf_size) -{ - DqnFile file = {}; - if (!file.Open(path, DqnFile::Flag::FileReadWrite, DqnFile::Action::ForceCreate)) - { - DQN_LOGGER_E(dqn_lib_context_.logger, "Could not open file at: %s", path); - return false; - } - - DQN_DEFER { file.Close(); }; - usize bytes_written = file.Write(buf, buf_size); - if (bytes_written != buf_size) - { - DQN_LOGGER_E(dqn_lib_context_.logger, "Bytes written did not match the buffer size, %zu != %zu", bytes_written, buf_size); - return false; - } - - return true; -} - -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(); }; - - // TODO(doyle): Logging - if (file.size > buf_size || !result) - { - DQN_LOGGER_E(dqn_lib_context_.logger, "Insufficient buffer size given: %zu, required: %zu\n", buf_size, file.size); - return false; - } - - usize bytes_read = file.Read(buf, file.size); - DQN_ASSERT(bytes_read == file.size); - return result; -} - -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(); }; - - if (!result || file.size > buf_size) - { - return false; - } - - usize bytes_read = file.Read(buf, file.size); - DQN_ASSERT_MSG(bytes_read == file.size, "%zu != %zu", bytes_read, file.size); - return result; -} - -void DqnFile::Close() -{ - if (this->handle) - { -#if defined(DQN_IS_WIN32) - CloseHandle(this->handle); -#else - fclose((FILE *)this->handle); -#endif - this->handle = nullptr; - } - - this->size = 0; - this->flags = 0; -} - -#if defined(DQN_IS_WIN32) - DQN_COMPILE_ASSERT(sizeof(DWORD) == sizeof(u32)); -#endif - -bool DqnFile_Size(wchar_t const *path, usize *size) -{ - DqnFileInfo info = {}; - if (DqnFile_GetInfo(path, &info)) - { - if (size) *size = info.size; - return true; - } - - return false; -} - -bool DqnFile_Size(char const *path, usize *size) -{ - // TODO(doyle): Logging -#if defined(DQN_IS_WIN32) - // TODO(doyle): MAX PATH is baad - wchar_t wide_path[MAX_PATH] = {0}; - DqnWin32_UTF8ToWChar(path, wide_path, DQN_ARRAY_COUNT(wide_path)); - return DqnFile_Size(wide_path, size); - -#else - // TODO(doyle): Error logging - bool result = DqnFile__UnixGetFileSize(path, size); - return result; -#endif -} - -bool DqnFile_MakeDir(char const *path) -{ -#if defined(DQN_IS_WIN32) - // TODO(doyle): Handle error and this is super incomplete. Cannot create - // directories recursively - CreateDirectoryA(path, nullptr /*lpSecurityAttributes*/); - return true; -#else - return false; -#endif -} - -bool DqnFile_GetInfo(wchar_t const *path, DqnFileInfo *info) -{ -#if defined(DQN_IS_WIN32) - auto FileTimeToSeconds = [](FILETIME const *time) -> i64 { - ULARGE_INTEGER time_large_int = {}; - time_large_int.LowPart = time->dwLowDateTime; - time_large_int.HighPart = time->dwHighDateTime; - - u64 result = (time_large_int.QuadPart / 10000000ULL) - 11644473600ULL; - return result; - }; - - WIN32_FILE_ATTRIBUTE_DATA attrib_data = {}; - if (GetFileAttributesExW(path, GetFileExInfoStandard, &attrib_data)) - { - if (info) - { - info->create_time_in_s = FileTimeToSeconds(&attrib_data.ftCreationTime); - info->last_access_time_in_s = FileTimeToSeconds(&attrib_data.ftLastAccessTime); - info->last_write_time_in_s = FileTimeToSeconds(&attrib_data.ftLastWriteTime); - - // TODO(doyle): What if usize is < Quad.part? - LARGE_INTEGER large_int = {}; - large_int.HighPart = attrib_data.nFileSizeHigh; - large_int.LowPart = attrib_data.nFileSizeLow; - info->size = (usize)large_int.QuadPart; - } - - return true; - } - -#else - // NOTE: Wide char not supported on unix - DQN_ASSERT(DQN_INVALID_CODE_PATH); - -#endif - - return false; -} - -bool DqnFile_GetInfo(char const *path, DqnFileInfo *info) -{ -#if defined(DQN_IS_WIN32) - // TODO(doyle): MAX PATH is baad - wchar_t wide_path[MAX_PATH] = {}; - DqnWin32_UTF8ToWChar(path, wide_path, DQN_ARRAY_COUNT(wide_path)); - return DqnFile_GetInfo(wide_path, info); - -#else - struct stat file_stat = {}; - if (stat(path, &file_stat)) - { - return false; - } - - if (info) - { - info->size = file_stat.st_size; - info->create_time_in_s = 0; - info->last_write_time_in_s = file_stat.st_mtime; - info->last_access_time_in_s = file_stat.st_atime; - } - - return true; -#endif -} - - -bool DqnFile_Delete(char const *path) -{ -#if defined(DQN_IS_WIN32) - bool result = DeleteFileA(path); -#else - bool result = (unlink(path) == 0); -#endif - return result; -} - -bool DqnFile_Delete(wchar_t const *path) -{ -#if defined(DQN_IS_WIN32) - bool result = DeleteFileW(path); - return result; -#else - DQN_ASSERT(DQN_INVALID_CODE_PATH); - return false; -#endif -} - -bool DqnFile_Copy(char const *src, char const *dest) -{ - // TODO(doyle): Logging -#if defined(DQN_IS_WIN32) - BOOL result = (CopyFileA(src, dest, /*FailIfExist*/false) != 0); - if (result == 0) - DqnWin32_DisplayLastError("CopyFile failed: "); - - return (result != 0); - -#else - DQN_ASSERT(DQN_INVALID_CODE_PATH); - return false; -#endif -} - -bool DqnFile_Copy(wchar_t const *src, wchar_t const *dest) -{ - // TODO(doyle): Logging -#if defined(DQN_IS_WIN32) - BOOL result = (CopyFileW(src, dest, /*FailIfExist*/false) != 0); - if (result == 0) - DqnWin32_DisplayLastError("CopyFile failed: "); - - return result; -#else - DQN_ASSERT(DQN_INVALID_CODE_PATH); - return false; - -#endif -} - -char **DqnFile_ListDir(char const *dir, i32 *num_files, DqnAllocator *allocator) -{ - char **result = DqnFile__PlatformListDir(dir, num_files, allocator); - return result; -} - -void DqnFile_ListDirFree(char **file_list, i32 num_files, DqnAllocator *allocator) -{ - if (file_list) - { - for (isize i = 0; i < num_files; i++) - { - // TODO(doyle): Free needs size? Thanks to munmap on linux - if (file_list[i]) allocator->Free(file_list[i], DqnStr_Len(file_list[i])); - file_list[i] = nullptr; - } - - allocator->Free(file_list, num_files * sizeof(file_list)); - } -} - -// XPlatform > #DqnTimer -// ================================================================================================= -#if defined (DQN_IS_WIN32) -FILE_SCOPE f64 DqnTimerInternal_Win32QueryPerfCounterTimeInMs() -{ - LOCAL_PERSIST LARGE_INTEGER query_perf_freq = {0}; - if (query_perf_freq.QuadPart == 0) - { - QueryPerformanceFrequency(&query_perf_freq); - DQN_ASSERT(query_perf_freq.QuadPart != 0); - } - - LARGE_INTEGER qpc_result; - QueryPerformanceCounter(&qpc_result); - - // Convert to microseconds first then divide by ticks per second then to milliseconds - qpc_result.QuadPart *= 1000000; - f64 timestamp = qpc_result.QuadPart / (f64)query_perf_freq.QuadPart; - timestamp /= 1000.0f; - return timestamp; -} -#endif - -DQN_FILE_SCOPE f64 DqnTimer_NowInMs() -{ - f64 result = 0; -#if defined(DQN_IS_WIN32) - result = DQN_MAX(DqnTimerInternal_Win32QueryPerfCounterTimeInMs(), 0); - -#else - struct timespec time_spec = {0}; - if (clock_gettime(CLOCK_MONOTONIC, &time_spec)) - { - // TODO(doyle): Failed logging - DQN_ASSERT(DQN_INVALID_CODE_PATH); - } - else - { - result = (f64)((time_spec.tv_sec * 1000.0f) + (time_spec.tv_nsec / 1000000.0f)); - } - -#endif - return result; -}; - -DQN_FILE_SCOPE f64 DqnTimer_NowInS() { return DqnTimer_NowInMs() / 1000.0f; } - -// XPlatform > #DqnLock -// ================================================================================================= -bool DqnLock::Init() -{ -#if defined(DQN_IS_WIN32) - if (InitializeCriticalSectionEx(&this->win32_handle, this->win32_spin_count, 0)) - { - return true; - } - -#else - // NOTE: Static initialise, pre-empt a lock so that it gets initialised as per documentation - this->unix_handle = PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP; - this->Acquire(); - this->Release(); - return true; -#endif - - return false; -} - -void DqnLock::Acquire() -{ -#if defined(DQN_IS_WIN32) - EnterCriticalSection(&this->win32_handle); -#else - // TODO(doyle): Better error handling - i32 error = pthread_mutex_lock(&this->unix_handle); - DQN_ASSERT(error == 0); -#endif -} - -void DqnLock::Release() -{ -#if defined(DQN_IS_WIN32) - LeaveCriticalSection(&this->win32_handle); -#else - // TODO(doyle): better error handling - i32 error = pthread_mutex_unlock(&this->unix_handle); - DQN_ASSERT(error == 0); -#endif -} - -void DqnLock::Delete() -{ -#if defined(DQN_IS_WIN32) - DeleteCriticalSection(&this->win32_handle); -#else - i32 error = pthread_mutex_destroy(&this->unix_handle); - DQN_ASSERT(error == 0); -#endif -} - -// XPlatform > #DqnJobQueue -// ================================================================================================= -typedef void *DqnThreadCallbackInternal(void *thread_param); -usize DQN_JOB_QUEUE_INTERNAL_THREAD_DEFAULT_STACK_SIZE = 0; - -FILE_SCOPE u32 DqnJobQueueInternal_ThreadCreate(usize stackSize, - DqnThreadCallbackInternal *thread_callback, - void *thread_param, u32 num_threads) -{ - u32 num_threads_created = 0; - -#if defined(DQN_IS_WIN32) - DQN_ASSERT(stackSize == 0 || !thread_callback); - for (u32 i = 0; i < num_threads; i++) - { - HANDLE handle = CreateThread(nullptr, stackSize, (LPTHREAD_START_ROUTINE)thread_callback, - thread_param, 0, nullptr); - CloseHandle(handle); - num_threads_created++; - } - -#else - // TODO(doyle): Better error handling - pthread_attr_t attribute = {}; - DQN_ASSERT(pthread_attr_init(&attribute) == 0); - - // Allows us to use pthread_join() which lets us wait till a thread finishes execution - DQN_ASSERT(pthread_attr_setdetachstate(&attribute, PTHREAD_CREATE_JOINABLE) == 0); - - // TODO(doyle): Persist thread handles - for (u32 i = 0; i < num_threads; i++) - { - pthread_t thread = {}; - pthread_create(&thread, &attribute, thread_callback, thread_param); - num_threads_created++; - } - - DQN_ASSERT(pthread_attr_destroy(&attribute) == 0); -#endif - - DQN_ASSERT(num_threads_created == num_threads); - return num_threads_created; -} - - -FILE_SCOPE void *DqnJobQueueInternal_ThreadCallback(void *thread_param) -{ - DqnJobQueue *queue = (DqnJobQueue *)thread_param; - for (;;) - { - if (!DqnJobQueue_TryExecuteNextJob(queue)) - { -#if defined(DQN_IS_WIN32) - WaitForSingleObjectEx(queue->semaphore, INFINITE, false); -#else - sem_wait(&queue->semaphore); -#endif - } - } -} - -FILE_SCOPE bool DqnJobQueueInternal_CreateSemaphore(DqnJobQueue *queue, u32 init_signal_count, u32 max_signal_count) -{ - if (!queue) return false; - -#if defined(DQN_IS_WIN32) - queue->semaphore = (void *)CreateSemaphoreA(nullptr, init_signal_count, max_signal_count, nullptr); - DQN_ASSERT(queue->semaphore); - -#else - // TODO(doyle): Use max count for unix - // TODO(doyle): Error handling - const u32 UNIX_DONT_SHARE_BETWEEN_PROCESSES = 0; - i32 error = sem_init(&queue->semaphore, UNIX_DONT_SHARE_BETWEEN_PROCESSES, 0); - DQN_ASSERT(error == 0); - - for (u32 i = 0; i < init_signal_count; i++) - DQN_ASSERT(sem_post(&queue->semaphore) == 0); -#endif - - return true; -} - -FILE_SCOPE bool DqnJobQueueInternal_ReleaseSemaphore(DqnJobQueue *queue) -{ - DQN_ASSERT(queue); - -#if defined(DQN_IS_WIN32) - DQN_ASSERT(queue->semaphore); - ReleaseSemaphore(queue->semaphore, 1, nullptr); - -#else - // TODO(doyle): Error handling - DQN_ASSERT(sem_post(&queue->semaphore) == 0); -#endif - - return true; -} - -DQN_FILE_SCOPE bool DqnJobQueue_Init(DqnJobQueue *queue, DqnJob *job_list, u32 job_list_size, u32 num_threads) -{ - if (!queue || !job_list || job_list_size == 0 || num_threads == 0) return false; - queue->job_list = job_list; - queue->size = job_list_size; - - DQN_ASSERT(DqnJobQueueInternal_CreateSemaphore(queue, 0, num_threads)); - - // Create threads - u32 num_threads_created = DqnJobQueueInternal_ThreadCreate( - DQN_JOB_QUEUE_INTERNAL_THREAD_DEFAULT_STACK_SIZE, DqnJobQueueInternal_ThreadCallback, - (void *)queue, num_threads); - DQN_ASSERT(num_threads == num_threads_created); - - return true; -} - -DQN_FILE_SCOPE bool DqnJobQueue_AddJob(DqnJobQueue *queue, const DqnJob job) -{ - i32 newJobInsertIndex = (queue->jobInsertIndex + 1) % queue->size; - if (newJobInsertIndex == queue->jobToExecuteIndex) return false; - - queue->job_list[queue->jobInsertIndex] = job; - - DqnAtomic_Add32(&queue->num_jobs_queued, 1); - DQN_ASSERT(DqnJobQueueInternal_ReleaseSemaphore(queue)); - - queue->jobInsertIndex = newJobInsertIndex; - return true; -} - -DQN_FILE_SCOPE void DqnJobQueue_BlockAndCompleteAllJobs(DqnJobQueue *queue) -{ - while (DqnJobQueue_TryExecuteNextJob(queue) || !DqnJobQueue_AllJobsComplete(queue)) - ; -} - -DQN_FILE_SCOPE bool DqnJobQueue_TryExecuteNextJob(DqnJobQueue *queue) -{ - if (!queue) return false; - - i32 originalJobToExecute = queue->jobToExecuteIndex; - if (originalJobToExecute != queue->jobInsertIndex) - { - i32 newJobIndexForNextThread = (originalJobToExecute + 1) % queue->size; - i32 index = DqnAtomic_CompareSwap32(&queue->jobToExecuteIndex, newJobIndexForNextThread, - originalJobToExecute); - - // NOTE: If we weren't successful at the interlock, another thread has - // taken the work and we can't know if there's more work or not. So - // irrespective of that result, return true to let the thread check - // again for more work. - if (index == originalJobToExecute) - { - DqnJob job = queue->job_list[index]; - job.callback(queue, job.user_data); - DqnAtomic_Add32(&queue->num_jobs_queued, -1); - } - - return true; - } - - return false; -} - -DQN_FILE_SCOPE bool DqnJobQueue_AllJobsComplete(DqnJobQueue *queue) -{ - if (!queue) return false; - - bool result = (queue->num_jobs_queued == 0); - return result; -} - -bool DqnJobQueue::Init(DqnJob *job_list_, u32 job_list_size, u32 num_threads) -{ - bool result = DqnJobQueue_Init(this, job_list_, job_list_size, num_threads); - return result; -} - -bool DqnJobQueue::AddJob (const DqnJob job) { return DqnJobQueue_AddJob(this, job); } -void DqnJobQueue::BlockAndCompleteAllJobs() { DqnJobQueue_BlockAndCompleteAllJobs(this); } -bool DqnJobQueue::TryExecuteNextJob() { return DqnJobQueue_TryExecuteNextJob(this); } -bool DqnJobQueue::AllJobsComplete () { return DqnJobQueue_AllJobsComplete(this); } - -// XPlatform > #DqnAtomic -// ================================================================================================= - -#if defined(DQN_IS_WIN32) - DQN_COMPILE_ASSERT(sizeof(LONG) == sizeof(i32)); -#endif - -DQN_FILE_SCOPE i32 DqnAtomic_CompareSwap32(i32 volatile *dest, i32 swap_val, i32 compare_val) -{ - i32 result = 0; -#if defined(DQN_IS_WIN32) - result = (i32)InterlockedCompareExchange((LONG volatile *)dest, (LONG)swap_val, (LONG)compare_val); - -#else - result = __sync_val_compare_and_swap(dest, compare_val, swap_val); -#endif - return result; -} - -DQN_FILE_SCOPE i32 DqnAtomic_Add32(i32 volatile *src, i32 value) -{ - i32 result = 0; -#if defined(DQN_IS_WIN32) - result = (i32)InterlockedAdd((LONG volatile *)src, value); - -#else - result = __sync_add_and_fetch(src, value); -#endif - - return result; -} - -// XPlatform > #DqnOS -// ================================================================================================= -#if defined(DQN_IS_UNIX) -#include -#endif - -void *DqnOS_VAlloc(isize size, void *base_addr) -{ - void *result = nullptr; -#if defined (DQN_IS_WIN32) - result = VirtualAlloc(base_addr, size, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE); - DQN_ASSERT_MSG(result, "VirtualAlloc failed: %s\n", DqnWin32_GetLastError()); -#else - result = mmap( - base_addr, size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1 /*fd*/, 0 /*offset into fd*/); - DQN_ASSERT(result != MAP_FAILED); -#endif - - return result; -} - -void DqnOS_VFree(void *address, isize size) -{ -#if defined (DQN_IS_WIN32) - BOOL result = VirtualFree(address, 0 /*size*/, MEM_RELEASE); - (void)size; - DQN_ASSERT(result); -#else - int result = munmap(address, size); - DQN_ASSERT(result != 0); -#endif -} - -#define DQN_OS_GET_THREADS_AND_CORES(name) \ - DQN_FILE_SCOPE void name(u32 *const num_cores, u32 *const num_threads_per_core) - -#if defined(DQN_IS_UNIX) -DQN_OS_GET_THREADS_AND_CORES(DqnOS_GetThreadsAndCores) -{ - if (!num_threads_per_core && !num_cores) return; - - // TODO(doyle): Not exactly standard - - usize fileSize = 0; - if (u8 *read_buffer = DqnFile_ReadAll("/proc/cpuinfo", &fileSize)) - { - char const *src_ptr = reinterpret_cast(read_buffer); - usize src_len = fileSize; - -#define DQN_ADVANCE_CHAR_PTR_AND_LEN_INTERNAL(ptr, len, offset) \ - ptr += offset; \ - len -= offset - - if (num_threads_per_core) - { - *num_threads_per_core = 0; - // Find the offset to the processor field and move to it - DqnBuffer processor = DQN_BUFFER_STR_LIT("processor"); - i32 processorOffset = DqnStr_FindFirstOccurence(src_ptr, src_len, processor.data, processor.len); - - DQN_ASSERT(processorOffset != -1); - DQN_ADVANCE_CHAR_PTR_AND_LEN_INTERNAL(src_ptr, src_len, processorOffset); - - // Find the offset to the colon delimiter and advance to 1 after it - i32 colon_offset = DqnStr_FindFirstOccurence(src_ptr, src_len, ":", 1) + 1; - DQN_ASSERT(colon_offset != -1); - DQN_ADVANCE_CHAR_PTR_AND_LEN_INTERNAL(src_ptr, src_len, colon_offset); - - // Read num processors, i.e. logical cores/hyper threads - *num_threads_per_core = Dqn_StrToI64(src_ptr, src_len); - if (*num_threads_per_core == 0) *num_threads_per_core = 1; - } - - if (num_cores) - { - *num_cores = 0; - // Find the offset to the cpu cores field and move to it - DqnBuffer cpuCores = DQN_BUFFER_STR_LIT("cpu cores"); - i32 cpu_cores_offset = DqnStr_FindFirstOccurence(src_ptr, src_len, cpuCores.data, cpuCores.len); - DQN_ASSERT(cpu_cores_offset != -1); - - DQN_ADVANCE_CHAR_PTR_AND_LEN_INTERNAL(src_ptr, src_len, cpu_cores_offset); - - // Find the offset to the colon delimiter and advance to 1 after it - i32 colon_offset = DqnStr_FindFirstOccurence(src_ptr, src_len, ":", 1) + 1; - DQN_ASSERT(colon_offset != -1); - DQN_ADVANCE_CHAR_PTR_AND_LEN_INTERNAL(src_ptr, src_len, colon_offset); - - // Read num cores value, i.e. physical cores - *num_cores = Dqn_StrToI64(src_ptr, src_len); - } - DQN_DEFAULT_HEAP_ALLOCATOR->Free(read_buffer); - } - else - { - // TODO(doyle): Out of mem - DQN_ASSERT(DQN_INVALID_CODE_PATH); - } -} -#endif // DQN_IS_UNIX - -#if defined(DQN_IS_WIN32) -DQN_OS_GET_THREADS_AND_CORES(DqnOS_GetThreadsAndCores) -{ - if (num_threads_per_core) - { - SYSTEM_INFO system_info; - GetNativeSystemInfo(&system_info); - *num_threads_per_core = system_info.dwNumberOfProcessors; - } - - if (num_cores) - { - *num_cores = 0; - DWORD required_size = 0; - u8 insufficient_buf = {0}; - GetLogicalProcessorInformationEx( - RelationProcessorCore, - (SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX *)insufficient_buf, - &required_size); - - auto *raw_proc_info_array = (u8 *)DqnMem_Calloc(required_size); - if (!raw_proc_info_array) - { - DQN_LOGGER_E(dqn_lib_context_.logger, "Could not allocate memory for array required: %$d\n"); - return; - } - - if (GetLogicalProcessorInformationEx( - RelationProcessorCore, - (SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX *)raw_proc_info_array, - &required_size)) - { - SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX *logical_proc_info = - (SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX *)raw_proc_info_array; - DWORD bytes_read = 0; - - do - { - // NOTE: High efficiency value has greater performance and less efficiency. - PROCESSOR_RELATIONSHIP *procInfo = &logical_proc_info->Processor; - // u32 efficiency = procInfo->EfficiencyClass; - (*num_cores)++; - DQN_ASSERT(logical_proc_info->Relationship == RelationProcessorCore); - DQN_ASSERT(procInfo->GroupCount == 1); - - bytes_read += logical_proc_info->Size; - logical_proc_info = - (SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX *)((u8 *)logical_proc_info + - logical_proc_info->Size); - } while (bytes_read < required_size); - } - else - { - DqnWin32_DisplayLastError("GetLogicalProcessorInformationEx() failed"); - } - - DqnMem_Free(raw_proc_info_array); - } -} -#endif // DQN_IS_WIN32 - -#ifdef DQN_IS_WIN32 -// #DqnWin32 -// ================================================================================================= -DQN_FILE_SCOPE i32 DqnWin32_UTF8ToWChar(char const *in, wchar_t *out, i32 out_len) -{ - i32 result = MultiByteToWideChar(CP_UTF8, 0, in, -1, out, out_len); - - if (result == 0xFFFD || 0) - { - DQN__WIN32_ERROR_BOX("WideCharToMultiByte() failed.", nullptr); - return -1; - } - - return result; -} - -DQN_FILE_SCOPE i32 DqnWin32_WCharToUTF8(wchar_t const *in, char *out, i32 out_len) -{ - i32 result = - WideCharToMultiByte(CP_UTF8, 0, in, -1, out, out_len, nullptr, nullptr); - - if (result == 0xFFFD || 0) - { - DQN__WIN32_ERROR_BOX("WideCharToMultiByte() failed.", nullptr); - return -1; - } - - return result; -} - -DQN_FILE_SCOPE void DqnWin32_GetClientDim(HWND window, LONG *width, LONG *height) -{ - RECT rect; - GetClientRect(window, &rect); - if (width) *width = rect.right - rect.left; - if (height) *height = rect.bottom - rect.top; -} - -DQN_FILE_SCOPE void DqnWin32_GetRectDim(RECT const rect, LONG *width, LONG *height) -{ - if (width) *width = rect.right - rect.left; - if (height) *height = rect.bottom - rect.top; -} - -DQN_FILE_SCOPE char const *DqnWin32_GetLastError() -{ - LOCAL_PERSIST char err_msg[2048]; - err_msg[0] = 0; - - DWORD error = GetLastError(); - FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, - nullptr, error, 0, err_msg, DQN_ARRAY_COUNT(err_msg), nullptr); - - return err_msg; -} - -DQN_FILE_SCOPE void DqnWin32_DisplayLastError(char const *err_prefix) -{ - if (err_prefix) - { - char formatted_err[2048] = {0}; - stbsp_sprintf(formatted_err, "%s: %s", err_prefix, DqnWin32_GetLastError()); - DQN__WIN32_ERROR_BOX(formatted_err, nullptr); - } - else - { - DQN__WIN32_ERROR_BOX(DqnWin32_GetLastError(), nullptr); - } -} - -const i32 DQN__WIN32_INTERNAL_ERROR_MSG_SIZE = 2048; -DQN_FILE_SCOPE void DqnWin32_DisplayErrorCode(DWORD error, char const *err_prefix) -{ - char err_msg[DQN__WIN32_INTERNAL_ERROR_MSG_SIZE] = {0}; - FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, - nullptr, error, 0, err_msg, DQN_ARRAY_COUNT(err_msg), nullptr); - - char formatted_err[2048] = {0}; - stbsp_sprintf(formatted_err, "%s: %s", err_prefix, err_msg); - DQN__WIN32_ERROR_BOX(formatted_err, nullptr); -} - -DQN_FILE_SCOPE void DqnWin32_OutputDebugString(char const *fmt_str, ...) -{ - char str[DQN__WIN32_INTERNAL_ERROR_MSG_SIZE] = {0}; - - va_list va; - va_start(va, fmt_str); - { - i32 num_copied = stbsp_vsprintf(str, fmt_str, va); - DQN_ASSERT(num_copied < DQN_ARRAY_COUNT(str)); - } - va_end(va); - - OutputDebugStringA(str); -} - -DQN_FILE_SCOPE void DqnWin32_GetExeNameAndDirectory(DqnMemStack *mem_stack, DqnBuffer *exe_name, DqnBuffer *exe_directory) -{ - if (!exe_name && !exe_directory) return; - - int exe_buf_len = 512; - wchar_t *exe_buf = nullptr; - int exe_len = exe_buf_len; - while(exe_buf_len == exe_len) - { - if (exe_buf) - exe_buf_len += 128; - - exe_buf = DQN_MEMSTACK_PUSH_BACK_ARRAY(mem_stack, wchar_t, exe_buf_len); - DQN_DEFER { mem_stack->Pop(exe_buf); }; - exe_len = GetModuleFileNameW(nullptr, exe_buf, exe_buf_len); - } - - DqnAllocator allocator(mem_stack); - - i32 last_slash_index = 0; - for (i32 i = (exe_len - 1); i >= 0; --i) - { - if (exe_buf[i] == '\\') - { - last_slash_index = i; - break; - } - } - - if (exe_name) - { - wchar_t *start_of_exe_name = exe_buf + last_slash_index + 1; - wchar_t *end = exe_buf + exe_len; - *exe_name = DqnBuffer_CopyAndNullTerminate(&allocator, start_of_exe_name, static_cast(end - start_of_exe_name)); - } - - if (exe_directory) - *exe_directory = DqnBuffer_CopyAndNullTerminate(&allocator, exe_buf, last_slash_index); -} - -FILE_SCOPE inline u64 DqnWin32__FileTimeToEpoch(FILETIME file_time) -{ - ULARGE_INTEGER file_time_ularge = {}; - file_time_ularge.LowPart = file_time.dwLowDateTime; - file_time_ularge.HighPart = file_time.dwHighDateTime; - - u64 result = (file_time_ularge.QuadPart - 116444736000000000LL) / 10000000ULL; - return result; -} - -DQN_FILE_SCOPE u64 DqnWin32_EpochTimeUTC() -{ - FILETIME file_time; - GetSystemTimeAsFileTime(&file_time); - u64 result = DqnWin32__FileTimeToEpoch(file_time); - return result; -} - -DQN_FILE_SCOPE u64 DqnWin32_EpochTimeLocal() -{ - SYSTEMTIME sys_time; - GetLocalTime(&sys_time); - - FILETIME file_time; - bool converted = SystemTimeToFileTime(&sys_time, &file_time); - (void)converted; DQN_ASSERT(converted); - - u64 result = DqnWin32__FileTimeToEpoch(file_time); - return result; -} - -#endif // DQN_IS_WIN32 -#endif // DQN__XPLATFORM_LAYER diff --git a/Code/Deprecated/google-10000-english.txt b/Code/Deprecated/google-10000-english.txt deleted file mode 100644 index 3164d7b..0000000 --- a/Code/Deprecated/google-10000-english.txt +++ /dev/null @@ -1,10000 +0,0 @@ -the -of -and -to -a -in -for -is -on -that -by -this -with -i -you -it -not -or -be -are -from -at -as -your -all -have -new -more -an -was -we -will -home -can -us -about -if -page -my -has -search -free -but -our -one -other -do -no -information -time -they -site -he -up -may -what -which -their -news -out -use -any -there -see -only -so -his -when -contact -here -business -who -web -also -now -help -get -pm -view -online -c -e -first -am -been -would -how -were -me -s -services -some -these -click -its -like -service -x -than -find -price -date -back -top -people -had -list -name -just -over -state -year -day -into -email -two -health -n -world -re -next -used -go -b -work -last -most -products -music -buy -data -make -them -should -product -system -post -her -city -t -add -policy -number -such -please -available -copyright -support -message -after -best -software -then -jan -good -video -well -d -where -info -rights -public -books -high -school -through -m -each -links -she -review -years -order -very -privacy -book -items -company -r -read -group -sex -need -many -user -said -de -does -set -under -general -research -university -january -mail -full -map -reviews -program -life -know -games -way -days -management -p -part -could -great -united -hotel -real -f -item -international -center -ebay -must -store -travel -comments -made -development -report -off -member -details -line -terms -before -hotels -did -send -right -type -because -local -those -using -results -office -education -national -car -design -take -posted -internet -address -community -within -states -area -want -phone -dvd -shipping -reserved -subject -between -forum -family -l -long -based -w -code -show -o -even -black -check -special -prices -website -index -being -women -much -sign -file -link -open -today -technology -south -case -project -same -pages -uk -version -section -own -found -sports -house -related -security -both -g -county -american -photo -game -members -power -while -care -network -down -computer -systems -three -total -place -end -following -download -h -him -without -per -access -think -north -resources -current -posts -big -media -law -control -water -history -pictures -size -art -personal -since -including -guide -shop -directory -board -location -change -white -text -small -rating -rate -government -children -during -usa -return -students -v -shopping -account -times -sites -level -digital -profile -previous -form -events -love -old -john -main -call -hours -image -department -title -description -non -k -y -insurance -another -why -shall -property -class -cd -still -money -quality -every -listing -content -country -private -little -visit -save -tools -low -reply -customer -december -compare -movies -include -college -value -article -york -man -card -jobs -provide -j -food -source -author -different -press -u -learn -sale -around -print -course -job -canada -process -teen -room -stock -training -too -credit -point -join -science -men -categories -advanced -west -sales -look -english -left -team -estate -box -conditions -select -windows -photos -gay -thread -week -category -note -live -large -gallery -table -register -however -june -october -november -market -library -really -action -start -series -model -features -air -industry -plan -human -provided -tv -yes -required -second -hot -accessories -cost -movie -forums -march -la -september -better -say -questions -july -yahoo -going -medical -test -friend -come -dec -server -pc -study -application -cart -staff -articles -san -feedback -again -play -looking -issues -april -never -users -complete -street -topic -comment -financial -things -working -against -standard -tax -person -below -mobile -less -got -blog -party -payment -equipment -login -student -let -programs -offers -legal -above -recent -park -stores -side -act -problem -red -give -memory -performance -social -q -august -quote -language -story -sell -options -experience -rates -create -key -body -young -america -important -field -few -east -paper -single -ii -age -activities -club -example -girls -additional -password -z -latest -something -road -gift -question -changes -night -ca -hard -texas -oct -pay -four -poker -status -browse -issue -range -building -seller -court -february -always -result -audio -light -write -war -nov -offer -blue -groups -al -easy -given -files -event -release -analysis -request -fax -china -making -picture -needs -possible -might -professional -yet -month -major -star -areas -future -space -committee -hand -sun -cards -problems -london -washington -meeting -rss -become -interest -id -child -keep -enter -california -porn -share -similar -garden -schools -million -added -reference -companies -listed -baby -learning -energy -run -delivery -net -popular -term -film -stories -put -computers -journal -reports -co -try -welcome -central -images -president -notice -god -original -head -radio -until -cell -color -self -council -away -includes -track -australia -discussion -archive -once -others -entertainment -agreement -format -least -society -months -log -safety -friends -sure -faq -trade -edition -cars -messages -marketing -tell -further -updated -association -able -having -provides -david -fun -already -green -studies -close -common -drive -specific -several -gold -feb -living -sep -collection -called -short -arts -lot -ask -display -limited -powered -solutions -means -director -daily -beach -past -natural -whether -due -et -electronics -five -upon -period -planning -database -says -official -weather -mar -land -average -done -technical -window -france -pro -region -island -record -direct -microsoft -conference -environment -records -st -district -calendar -costs -style -url -front -statement -update -parts -aug -ever -downloads -early -miles -sound -resource -present -applications -either -ago -document -word -works -material -bill -apr -written -talk -federal -hosting -rules -final -adult -tickets -thing -centre -requirements -via -cheap -nude -kids -finance -true -minutes -else -mark -third -rock -gifts -europe -reading -topics -bad -individual -tips -plus -auto -cover -usually -edit -together -videos -percent -fast -function -fact -unit -getting -global -tech -meet -far -economic -en -player -projects -lyrics -often -subscribe -submit -germany -amount -watch -included -feel -though -bank -risk -thanks -everything -deals -various -words -linux -jul -production -commercial -james -weight -town -heart -advertising -received -choose -treatment -newsletter -archives -points -knowledge -magazine -error -camera -jun -girl -currently -construction -toys -registered -clear -golf -receive -domain -methods -chapter -makes -protection -policies -loan -wide -beauty -manager -india -position -taken -sort -listings -models -michael -known -half -cases -step -engineering -florida -simple -quick -none -wireless -license -paul -friday -lake -whole -annual -published -later -basic -sony -shows -corporate -google -church -method -purchase -customers -active -response -practice -hardware -figure -materials -fire -holiday -chat -enough -designed -along -among -death -writing -speed -html -countries -loss -face -brand -discount -higher -effects -created -remember -standards -oil -bit -yellow -political -increase -advertise -kingdom -base -near -environmental -thought -stuff -french -storage -oh -japan -doing -loans -shoes -entry -stay -nature -orders -availability -africa -summary -turn -mean -growth -notes -agency -king -monday -european -activity -copy -although -drug -pics -western -income -force -cash -employment -overall -bay -river -commission -ad -package -contents -seen -players -engine -port -album -regional -stop -supplies -started -administration -bar -institute -views -plans -double -dog -build -screen -exchange -types -soon -sponsored -lines -electronic -continue -across -benefits -needed -season -apply -someone -held -ny -anything -printer -condition -effective -believe -organization -effect -asked -eur -mind -sunday -selection -casino -pdf -lost -tour -menu -volume -cross -anyone -mortgage -hope -silver -corporation -wish -inside -solution -mature -role -rather -weeks -addition -came -supply -nothing -certain -usr -executive -running -lower -necessary -union -jewelry -according -dc -clothing -mon -com -particular -fine -names -robert -homepage -hour -gas -skills -six -bush -islands -advice -career -military -rental -decision -leave -british -teens -pre -huge -sat -woman -facilities -zip -bid -kind -sellers -middle -move -cable -opportunities -taking -values -division -coming -tuesday -object -lesbian -appropriate -machine -logo -length -actually -nice -score -statistics -client -ok -returns -capital -follow -sample -investment -sent -shown -saturday -christmas -england -culture -band -flash -ms -lead -george -choice -went -starting -registration -fri -thursday -courses -consumer -hi -airport -foreign -artist -outside -furniture -levels -channel -letter -mode -phones -ideas -wednesday -structure -fund -summer -allow -degree -contract -button -releases -wed -homes -super -male -matter -custom -virginia -almost -took -located -multiple -asian -distribution -editor -inn -industrial -cause -potential -song -cnet -ltd -los -hp -focus -late -fall -featured -idea -rooms -female -responsible -inc -communications -win -associated -thomas -primary -cancer -numbers -reason -tool -browser -spring -foundation -answer -voice -eg -friendly -schedule -documents -communication -purpose -feature -bed -comes -police -everyone -independent -ip -approach -cameras -brown -physical -operating -hill -maps -medicine -deal -hold -ratings -chicago -forms -glass -happy -tue -smith -wanted -developed -thank -safe -unique -survey -prior -telephone -sport -ready -feed -animal -sources -mexico -population -pa -regular -secure -navigation -operations -therefore -ass -simply -evidence -station -christian -round -paypal -favorite -understand -option -master -valley -recently -probably -thu -rentals -sea -built -publications -blood -cut -worldwide -improve -connection -publisher -hall -larger -anti -networks -earth -parents -nokia -impact -transfer -introduction -kitchen -strong -tel -carolina -wedding -properties -hospital -ground -overview -ship -accommodation -owners -disease -tx -excellent -paid -italy -perfect -hair -opportunity -kit -classic -basis -command -cities -william -express -anal -award -distance -tree -peter -assessment -ensure -thus -wall -ie -involved -el -extra -especially -interface -pussy -partners -budget -rated -guides -success -maximum -ma -operation -existing -quite -selected -boy -amazon -patients -restaurants -beautiful -warning -wine -locations -horse -vote -forward -flowers -stars -significant -lists -technologies -owner -retail -animals -useful -directly -manufacturer -ways -est -son -providing -rule -mac -housing -takes -iii -gmt -bring -catalog -searches -max -trying -mother -authority -considered -told -xml -traffic -programme -joined -input -strategy -feet -agent -valid -bin -modern -senior -ireland -sexy -teaching -door -grand -testing -trial -charge -units -instead -canadian -cool -normal -wrote -enterprise -ships -entire -educational -md -leading -metal -positive -fl -fitness -chinese -opinion -mb -asia -football -abstract -uses -output -funds -mr -greater -likely -develop -employees -artists -alternative -processing -responsibility -resolution -java -guest -seems -publication -pass -relations -trust -van -contains -session -multi -photography -republic -fees -components -vacation -century -academic -assistance -completed -skin -graphics -indian -prev -ads -mary -il -expected -ring -grade -dating -pacific -mountain -organizations -pop -filter -mailing -vehicle -longer -consider -int -northern -behind -panel -floor -german -buying -match -proposed -default -require -iraq -boys -outdoor -deep -morning -otherwise -allows -rest -protein -plant -reported -hit -transportation -mm -pool -mini -politics -partner -disclaimer -authors -boards -faculty -parties -fish -membership -mission -eye -string -sense -modified -pack -released -stage -internal -goods -recommended -born -unless -richard -detailed -japanese -race -approved -background -target -except -character -usb -maintenance -ability -maybe -functions -ed -moving -brands -places -php -pretty -trademarks -phentermine -spain -southern -yourself -etc -winter -rape -battery -youth -pressure -submitted -boston -incest -debt -keywords -medium -television -interested -core -break -purposes -throughout -sets -dance -wood -msn -itself -defined -papers -playing -awards -fee -studio -reader -virtual -device -established -answers -rent -las -remote -dark -programming -external -apple -le -regarding -instructions -min -offered -theory -enjoy -remove -aid -surface -minimum -visual -host -variety -teachers -isbn -martin -manual -block -subjects -agents -increased -repair -fair -civil -steel -understanding -songs -fixed -wrong -beginning -hands -associates -finally -az -updates -desktop -classes -paris -ohio -gets -sector -capacity -requires -jersey -un -fat -fully -father -electric -saw -instruments -quotes -officer -driver -businesses -dead -respect -unknown -specified -restaurant -mike -trip -pst -worth -mi -procedures -poor -teacher -xxx -eyes -relationship -workers -farm -fucking -georgia -peace -traditional -campus -tom -showing -creative -coast -benefit -progress -funding -devices -lord -grant -sub -agree -fiction -hear -sometimes -watches -careers -beyond -goes -families -led -museum -themselves -fan -transport -interesting -blogs -wife -evaluation -accepted -former -implementation -ten -hits -zone -complex -th -cat -galleries -references -die -presented -jack -flat -flow -agencies -literature -respective -parent -spanish -michigan -columbia -setting -dr -scale -stand -economy -highest -helpful -monthly -critical -frame -musical -definition -secretary -angeles -networking -path -australian -employee -chief -gives -kb -bottom -magazines -packages -detail -francisco -laws -changed -pet -heard -begin -individuals -colorado -royal -clean -switch -russian -largest -african -guy -titles -relevant -guidelines -justice -connect -bible -dev -cup -basket -applied -weekly -vol -installation -described -demand -pp -suite -vegas -na -square -chris -attention -advance -skip -diet -army -auction -gear -lee -os -difference -allowed -correct -charles -nation -selling -lots -piece -sheet -firm -seven -older -illinois -regulations -elements -species -jump -cells -module -resort -facility -random -pricing -dvds -certificate -minister -motion -looks -fashion -directions -visitors -documentation -monitor -trading -forest -calls -whose -coverage -couple -giving -chance -vision -ball -ending -clients -actions -listen -discuss -accept -automotive -naked -goal -successful -sold -wind -communities -clinical -situation -sciences -markets -lowest -highly -publishing -appear -emergency -developing -lives -currency -leather -determine -milf -temperature -palm -announcements -patient -actual -historical -stone -bob -commerce -ringtones -perhaps -persons -difficult -scientific -satellite -fit -tests -village -accounts -amateur -ex -met -pain -xbox -particularly -factors -coffee -www -settings -cum -buyer -cultural -steve -easily -oral -ford -poster -edge -functional -root -au -fi -closed -holidays -ice -pink -zealand -balance -monitoring -graduate -replies -shot -nc -architecture -initial -label -thinking -scott -llc -sec -recommend -canon -hardcore -league -waste -minute -bus -provider -optional -dictionary -cold -accounting -manufacturing -sections -chair -fishing -effort -phase -fields -bag -fantasy -po -letters -motor -va -professor -context -install -shirt -apparel -generally -continued -foot -mass -crime -count -breast -techniques -ibm -rd -johnson -sc -quickly -dollars -websites -religion -claim -driving -permission -surgery -patch -heat -wild -measures -generation -kansas -miss -chemical -doctor -task -reduce -brought -himself -nor -component -enable -exercise -bug -santa -mid -guarantee -leader -diamond -israel -se -processes -soft -servers -alone -meetings -seconds -jones -arizona -keyword -interests -flight -congress -fuel -username -walk -fuck -produced -italian -paperback -classifieds -wait -supported -pocket -saint -rose -freedom -argument -competition -creating -jim -drugs -joint -premium -providers -fresh -characters -attorney -upgrade -di -factor -growing -thousands -km -stream -apartments -pick -hearing -eastern -auctions -therapy -entries -dates -generated -signed -upper -administrative -serious -prime -samsung -limit -began -louis -steps -errors -shops -bondage -del -efforts -informed -ga -ac -thoughts -creek -ft -worked -quantity -urban -practices -sorted -reporting -essential -myself -tours -platform -load -affiliate -labor -immediately -admin -nursing -defense -machines -designated -tags -heavy -covered -recovery -joe -guys -integrated -configuration -cock -merchant -comprehensive -expert -universal -protect -drop -solid -cds -presentation -languages -became -orange -compliance -vehicles -prevent -theme -rich -im -campaign -marine -improvement -vs -guitar -finding -pennsylvania -examples -ipod -saying -spirit -ar -claims -porno -challenge -motorola -acceptance -strategies -mo -seem -affairs -touch -intended -towards -sa -goals -hire -election -suggest -branch -charges -serve -affiliates -reasons -magic -mount -smart -talking -gave -ones -latin -multimedia -xp -tits -avoid -certified -manage -corner -rank -computing -oregon -element -birth -virus -abuse -interactive -requests -separate -quarter -procedure -leadership -tables -define -racing -religious -facts -breakfast -kong -column -plants -faith -chain -developer -identify -avenue -missing -died -approximately -domestic -sitemap -recommendations -moved -houston -reach -comparison -mental -viewed -moment -extended -sequence -inch -attack -sorry -centers -opening -damage -lab -reserve -recipes -cvs -gamma -plastic -produce -snow -placed -truth -counter -failure -follows -eu -weekend -dollar -camp -ontario -automatically -des -minnesota -films -bridge -native -fill -williams -movement -printing -baseball -owned -approval -draft -chart -played -contacts -cc -jesus -readers -clubs -lcd -wa -jackson -equal -adventure -matching -offering -shirts -profit -leaders -posters -institutions -assistant -variable -ave -dj -advertisement -expect -parking -headlines -yesterday -compared -determined -wholesale -workshop -russia -gone -codes -kinds -extension -seattle -statements -golden -completely -teams -fort -cm -wi -lighting -senate -forces -funny -brother -gene -turned -portable -tried -electrical -applicable -disc -returned -pattern -ct -hentai -boat -named -theatre -laser -earlier -manufacturers -sponsor -classical -icon -warranty -dedicated -indiana -direction -harry -basketball -objects -ends -delete -evening -assembly -nuclear -taxes -mouse -signal -criminal -issued -brain -sexual -wisconsin -powerful -dream -obtained -false -da -cast -flower -felt -personnel -passed -supplied -identified -falls -pic -soul -aids -opinions -promote -stated -stats -hawaii -professionals -appears -carry -flag -decided -nj -covers -hr -em -advantage -hello -designs -maintain -tourism -priority -newsletters -adults -clips -savings -iv -graphic -atom -payments -rw -estimated -binding -brief -ended -winning -eight -anonymous -iron -straight -script -served -wants -miscellaneous -prepared -void -dining -alert -integration -atlanta -dakota -tag -interview -mix -framework -disk -installed -queen -vhs -credits -clearly -fix -handle -sweet -desk -criteria -pubmed -dave -massachusetts -diego -hong -vice -associate -ne -truck -behavior -enlarge -ray -frequently -revenue -measure -changing -votes -du -duty -looked -discussions -bear -gain -festival -laboratory -ocean -flights -experts -signs -lack -depth -iowa -whatever -logged -laptop -vintage -train -exactly -dry -explore -maryland -spa -concept -nearly -eligible -checkout -reality -forgot -handling -origin -knew -gaming -feeds -billion -destination -scotland -faster -intelligence -dallas -bought -con -ups -nations -route -followed -specifications -broken -tripadvisor -frank -alaska -zoom -blow -battle -residential -anime -speak -decisions -industries -protocol -query -clip -partnership -editorial -nt -expression -es -equity -provisions -speech -wire -principles -suggestions -rural -shared -sounds -replacement -tape -strategic -judge -spam -economics -acid -bytes -cent -forced -compatible -fight -apartment -height -null -zero -speaker -filed -gb -netherlands -obtain -bc -consulting -recreation -offices -designer -remain -managed -pr -failed -marriage -roll -korea -banks -fr -participants -secret -bath -aa -kelly -leads -negative -austin -favorites -toronto -theater -springs -missouri -andrew -var -perform -healthy -translation -estimates -font -assets -injury -mt -joseph -ministry -drivers -lawyer -figures -married -protected -proposal -sharing -philadelphia -portal -waiting -birthday -beta -fail -gratis -banking -officials -brian -toward -won -slightly -assist -conduct -contained -lingerie -shemale -legislation -calling -parameters -jazz -serving -bags -profiles -miami -comics -matters -houses -doc -postal -relationships -tennessee -wear -controls -breaking -combined -ultimate -wales -representative -frequency -introduced -minor -finish -departments -residents -noted -displayed -mom -reduced -physics -rare -spent -performed -extreme -samples -davis -daniel -bars -reviewed -row -oz -forecast -removed -helps -singles -administrator -cycle -amounts -contain -accuracy -dual -rise -usd -sleep -mg -bird -pharmacy -brazil -creation -static -scene -hunter -addresses -lady -crystal -famous -writer -chairman -violence -fans -oklahoma -speakers -drink -academy -dynamic -gender -eat -permanent -agriculture -dell -cleaning -constitutes -portfolio -practical -delivered -collectibles -infrastructure -exclusive -seat -concerns -colour -vendor -originally -intel -utilities -philosophy -regulation -officers -reduction -aim -bids -referred -supports -nutrition -recording -regions -junior -toll -les -cape -ann -rings -meaning -tip -secondary -wonderful -mine -ladies -henry -ticket -announced -guess -agreed -prevention -whom -ski -soccer -math -import -posting -presence -instant -mentioned -automatic -healthcare -viewing -maintained -ch -increasing -majority -connected -christ -dan -dogs -sd -directors -aspects -austria -ahead -moon -participation -scheme -utility -preview -fly -manner -matrix -containing -combination -devel -amendment -despite -strength -guaranteed -turkey -libraries -proper -distributed -degrees -singapore -enterprises -delta -fear -seeking -inches -phoenix -rs -convention -shares -principal -daughter -standing -voyeur -comfort -colors -wars -cisco -ordering -kept -alpha -appeal -cruise -bonus -certification -previously -hey -bookmark -buildings -specials -beat -disney -household -batteries -adobe -smoking -bbc -becomes -drives -arms -alabama -tea -improved -trees -avg -achieve -positions -dress -subscription -dealer -contemporary -sky -utah -nearby -rom -carried -happen -exposure -panasonic -hide -permalink -signature -gambling -refer -miller -provision -outdoors -clothes -caused -luxury -babes -frames -viagra -certainly -indeed -newspaper -toy -circuit -layer -printed -slow -removal -easier -src -liability -trademark -hip -printers -faqs -nine -adding -kentucky -mostly -eric -spot -taylor -trackback -prints -spend -factory -interior -revised -grow -americans -optical -promotion -relative -amazing -clock -dot -hiv -identity -suites -conversion -feeling -hidden -reasonable -victoria -serial -relief -revision -broadband -influence -ratio -pda -importance -rain -onto -dsl -planet -webmaster -copies -recipe -zum -permit -seeing -proof -dna -diff -tennis -bass -prescription -bedroom -empty -instance -hole -pets -ride -licensed -orlando -specifically -tim -bureau -maine -sql -represent -conservation -pair -ideal -specs -recorded -don -pieces -finished -parks -dinner -lawyers -sydney -stress -cream -ss -runs -trends -yeah -discover -sexo -ap -patterns -boxes -louisiana -hills -javascript -fourth -nm -advisor -mn -marketplace -nd -evil -aware -wilson -shape -evolution -irish -certificates -objectives -stations -suggested -gps -op -remains -acc -greatest -firms -concerned -euro -operator -structures -generic -encyclopedia -usage -cap -ink -charts -continuing -mixed -census -interracial -peak -tn -competitive -exist -wheel -transit -dick -suppliers -salt -compact -poetry -lights -tracking -angel -bell -keeping -preparation -attempt -receiving -matches -accordance -width -noise -engines -forget -array -discussed -accurate -stephen -elizabeth -climate -reservations -pin -playstation -alcohol -greek -instruction -managing -annotation -sister -raw -differences -walking -explain -smaller -newest -establish -gnu -happened -expressed -jeff -extent -sharp -lesbians -ben -lane -paragraph -kill -mathematics -aol -compensation -ce -export -managers -aircraft -modules -sweden -conflict -conducted -versions -employer -occur -percentage -knows -mississippi -describe -concern -backup -requested -citizens -connecticut -heritage -personals -immediate -holding -trouble -spread -coach -kevin -agricultural -expand -supporting -audience -assigned -jordan -collections -ages -participate -plug -specialist -cook -affect -virgin -experienced -investigation -raised -hat -institution -directed -dealers -searching -sporting -helping -perl -affected -lib -bike -totally -plate -expenses -indicate -blonde -ab -proceedings -favourite -transmission -anderson -utc -characteristics -der -lose -organic -seek -experiences -albums -cheats -extremely -verzeichnis -contracts -guests -hosted -diseases -concerning -developers -equivalent -chemistry -tony -neighborhood -nevada -kits -thailand -variables -agenda -anyway -continues -tracks -advisory -cam -curriculum -logic -template -prince -circle -soil -grants -anywhere -psychology -responses -atlantic -wet -circumstances -edward -investor -identification -ram -leaving -wildlife -appliances -matt -elementary -cooking -speaking -sponsors -fox -unlimited -respond -sizes -plain -exit -entered -iran -arm -keys -launch -wave -checking -costa -belgium -printable -holy -acts -guidance -mesh -trail -enforcement -symbol -crafts -highway -buddy -hardcover -observed -dean -setup -poll -booking -glossary -fiscal -celebrity -styles -denver -unix -filled -bond -channels -ericsson -appendix -notify -blues -chocolate -pub -portion -scope -hampshire -supplier -cables -cotton -bluetooth -controlled -requirement -authorities -biology -dental -killed -border -ancient -debate -representatives -starts -pregnancy -causes -arkansas -biography -leisure -attractions -learned -transactions -notebook -explorer -historic -attached -opened -tm -husband -disabled -authorized -crazy -upcoming -britain -concert -retirement -scores -financing -efficiency -sp -comedy -adopted -efficient -weblog -linear -commitment -specialty -bears -jean -hop -carrier -edited -constant -visa -mouth -jewish -meter -linked -portland -interviews -concepts -nh -gun -reflect -pure -deliver -wonder -hell -lessons -fruit -begins -qualified -reform -lens -alerts -treated -discovery -draw -mysql -classified -relating -assume -confidence -alliance -fm -confirm -warm -neither -lewis -howard -offline -leaves -engineer -lifestyle -consistent -replace -clearance -connections -inventory -converter -suck -organisation -babe -checks -reached -becoming -blowjob -safari -objective -indicated -sugar -crew -legs -sam -stick -securities -allen -pdt -relation -enabled -genre -slide -montana -volunteer -tested -rear -democratic -enhance -switzerland -exact -bound -parameter -adapter -processor -node -formal -dimensions -contribute -lock -hockey -storm -micro -colleges -laptops -mile -showed -challenges -editors -mens -threads -bowl -supreme -brothers -recognition -presents -ref -tank -submission -dolls -estimate -encourage -navy -kid -regulatory -inspection -consumers -cancel -limits -territory -transaction -manchester -weapons -paint -delay -pilot -outlet -contributions -continuous -db -czech -resulting -cambridge -initiative -novel -pan -execution -disability -increases -ultra -winner -idaho -contractor -ph -episode -examination -potter -dish -plays -bulletin -ia -pt -indicates -modify -oxford -adam -truly -epinions -painting -committed -extensive -affordable -universe -candidate -databases -patent -slot -psp -outstanding -ha -eating -perspective -planned -watching -lodge -messenger -mirror -tournament -consideration -ds -discounts -sterling -sessions -kernel -boobs -stocks -buyers -journals -gray -catalogue -ea -jennifer -antonio -charged -broad -taiwan -und -chosen -demo -greece -lg -swiss -sarah -clark -labour -hate -terminal -publishers -nights -behalf -caribbean -liquid -rice -nebraska -loop -salary -reservation -foods -gourmet -guard -properly -orleans -saving -nfl -remaining -empire -resume -twenty -newly -raise -prepare -avatar -gary -depending -illegal -expansion -vary -hundreds -rome -arab -lincoln -helped -premier -tomorrow -purchased -milk -decide -consent -drama -visiting -performing -downtown -keyboard -contest -collected -nw -bands -boot -suitable -ff -absolutely -millions -lunch -dildo -audit -push -chamber -guinea -findings -muscle -featuring -iso -implement -clicking -scheduled -polls -typical -tower -yours -sum -misc -calculator -significantly -chicken -temporary -attend -shower -alan -sending -jason -tonight -dear -sufficient -holdem -shell -province -catholic -oak -vat -awareness -vancouver -governor -beer -seemed -contribution -measurement -swimming -spyware -formula -constitution -packaging -solar -jose -catch -jane -pakistan -ps -reliable -consultation -northwest -sir -doubt -earn -finder -unable -periods -classroom -tasks -democracy -attacks -kim -wallpaper -merchandise -const -resistance -doors -symptoms -resorts -biggest -memorial -visitor -twin -forth -insert -baltimore -gateway -ky -dont -alumni -drawing -candidates -charlotte -ordered -biological -fighting -transition -happens -preferences -spy -romance -instrument -bruce -split -themes -powers -heaven -br -bits -pregnant -twice -classification -focused -egypt -physician -hollywood -bargain -wikipedia -cellular -norway -vermont -asking -blocks -normally -lo -spiritual -hunting -diabetes -suit -ml -shift -chip -res -sit -bodies -photographs -cutting -wow -simon -writers -marks -flexible -loved -favourites -mapping -numerous -relatively -birds -satisfaction -represents -char -indexed -pittsburgh -superior -preferred -saved -paying -cartoon -shots -intellectual -moore -granted -choices -carbon -spending -comfortable -magnetic -interaction -listening -effectively -registry -crisis -outlook -massive -denmark -employed -bright -treat -header -cs -poverty -formed -piano -echo -que -grid -sheets -patrick -experimental -puerto -revolution -consolidation -displays -plasma -allowing -earnings -voip -mystery -landscape -dependent -mechanical -journey -delaware -bidding -consultants -risks -banner -applicant -charter -fig -barbara -cooperation -counties -acquisition -ports -implemented -sf -directories -recognized -dreams -blogger -notification -kg -licensing -stands -teach -occurred -textbooks -rapid -pull -hairy -diversity -cleveland -ut -reverse -deposit -seminar -investments -latina -nasa -wheels -sexcam -specify -accessibility -dutch -sensitive -templates -formats -tab -depends -boots -holds -router -concrete -si -editing -poland -folder -womens -css -completion -upload -pulse -universities -technique -contractors -milfhunter -voting -courts -notices -subscriptions -calculate -mc -detroit -alexander -broadcast -converted -metro -toshiba -anniversary -improvements -strip -specification -pearl -accident -nick -accessible -accessory -resident -plot -qty -possibly -airline -typically -representation -regard -pump -exists -arrangements -smooth -conferences -uniprotkb -beastiality -strike -consumption -birmingham -flashing -lp -narrow -afternoon -threat -surveys -sitting -putting -consultant -controller -ownership -committees -penis -legislative -researchers -vietnam -trailer -anne -castle -gardens -missed -malaysia -unsubscribe -antique -labels -willing -bio -molecular -upskirt -acting -heads -stored -exam -logos -residence -attorneys -milfs -antiques -density -hundred -ryan -operators -strange -sustainable -philippines -statistical -beds -breasts -mention -innovation -pcs -employers -grey -parallel -honda -amended -operate -bills -bold -bathroom -stable -opera -definitions -von -doctors -lesson -cinema -asset -ag -scan -elections -drinking -blowjobs -reaction -blank -enhanced -entitled -severe -generate -stainless -newspapers -hospitals -vi -deluxe -humor -aged -monitors -exception -lived -duration -bulk -successfully -indonesia -pursuant -sci -fabric -edt -visits -primarily -tight -domains -capabilities -pmid -contrast -recommendation -flying -recruitment -sin -berlin -cute -organized -ba -para -siemens -adoption -improving -cr -expensive -meant -capture -pounds -buffalo -organisations -plane -pg -explained -seed -programmes -desire -expertise -mechanism -camping -ee -jewellery -meets -welfare -peer -caught -eventually -marked -driven -measured -medline -bottle -agreements -considering -innovative -marshall -massage -rubber -conclusion -closing -tampa -thousand -meat -legend -grace -susan -ing -ks -adams -python -monster -alex -bang -villa -bone -columns -disorders -bugs -collaboration -hamilton -detection -ftp -cookies -inner -formation -tutorial -med -engineers -entity -cruises -gate -holder -proposals -moderator -sw -tutorials -settlement -portugal -lawrence -roman -duties -valuable -erotic -tone -collectables -ethics -forever -dragon -busy -captain -fantastic -imagine -brings -heating -leg -neck -hd -wing -governments -purchasing -scripts -abc -stereo -appointed -taste -dealing -commit -tiny -operational -rail -airlines -liberal -livecam -jay -trips -gap -sides -tube -turns -corresponding -descriptions -cache -belt -jacket -determination -animation -oracle -er -matthew -lease -productions -aviation -hobbies -proud -excess -disaster -console -commands -jr -telecommunications -instructor -giant -achieved -injuries -shipped -bestiality -seats -approaches -biz -alarm -voltage -anthony -nintendo -usual -loading -stamps -appeared -franklin -angle -rob -vinyl -highlights -mining -designers -melbourne -ongoing -worst -imaging -betting -scientists -liberty -wyoming -blackjack -argentina -era -convert -possibility -analyst -commissioner -dangerous -garage -exciting -reliability -thongs -gcc -unfortunately -respectively -volunteers -attachment -ringtone -finland -morgan -derived -pleasure -honor -asp -oriented -eagle -desktops -pants -columbus -nurse -prayer -appointment -workshops -hurricane -quiet -luck -postage -producer -represented -mortgages -dial -responsibilities -cheese -comic -carefully -jet -productivity -investors -crown -par -underground -diagnosis -maker -crack -principle -picks -vacations -gang -semester -calculated -cumshot -fetish -applies -casinos -appearance -smoke -apache -filters -incorporated -nv -craft -cake -notebooks -apart -fellow -blind -lounge -mad -algorithm -semi -coins -andy -gross -strongly -cafe -valentine -hilton -ken -proteins -horror -su -exp -familiar -capable -douglas -debian -till -involving -pen -investing -christopher -admission -epson -shoe -elected -carrying -victory -sand -madison -terrorism -joy -editions -cpu -mainly -ethnic -ran -parliament -actor -finds -seal -situations -fifth -allocated -citizen -vertical -corrections -structural -municipal -describes -prize -sr -occurs -jon -absolute -disabilities -consists -anytime -substance -prohibited -addressed -lies -pipe -soldiers -nr -guardian -lecture -simulation -layout -initiatives -ill -concentration -classics -lbs -lay -interpretation -horses -lol -dirty -deck -wayne -donate -taught -bankruptcy -mp -worker -optimization -alive -temple -substances -prove -discovered -wings -breaks -genetic -restrictions -participating -waters -promise -thin -exhibition -prefer -ridge -cabinet -modem -harris -mph -bringing -sick -dose -evaluate -tiffany -tropical -collect -bet -composition -toyota -streets -nationwide -vector -definitely -shaved -turning -buffer -purple -existence -commentary -larry -limousines -developments -def -immigration -destinations -lets -mutual -pipeline -necessarily -syntax -li -attribute -prison -skill -chairs -nl -everyday -apparently -surrounding -mountains -moves -popularity -inquiry -ethernet -checked -exhibit -throw -trend -sierra -visible -cats -desert -postposted -ya -oldest -rhode -nba -busty -coordinator -obviously -mercury -steven -handbook -greg -navigate -worse -summit -victims -epa -spaces -fundamental -burning -escape -coupons -somewhat -receiver -substantial -tr -progressive -cialis -bb -boats -glance -scottish -championship -arcade -richmond -sacramento -impossible -ron -russell -tells -obvious -fiber -depression -graph -covering -platinum -judgment -bedrooms -talks -filing -foster -modeling -passing -awarded -testimonials -trials -tissue -nz -memorabilia -clinton -masters -bonds -cartridge -alberta -explanation -folk -org -commons -cincinnati -subsection -fraud -electricity -permitted -spectrum -arrival -okay -pottery -emphasis -roger -aspect -workplace -awesome -mexican -confirmed -counts -priced -wallpapers -hist -crash -lift -desired -inter -closer -assumes -heights -shadow -riding -infection -firefox -lisa -expense -grove -eligibility -venture -clinic -korean -healing -princess -mall -entering -packet -spray -studios -involvement -dad -buttons -placement -observations -vbulletin -funded -thompson -winners -extend -roads -subsequent -pat -dublin -rolling -fell -motorcycle -yard -disclosure -establishment -memories -nelson -te -arrived -creates -faces -tourist -cocks -av -mayor -murder -sean -adequate -senator -yield -presentations -grades -cartoons -pour -digest -reg -lodging -tion -dust -hence -wiki -entirely -replaced -radar -rescue -undergraduate -losses -combat -reducing -stopped -occupation -lakes -butt -donations -associations -citysearch -closely -radiation -diary -seriously -kings -shooting -kent -adds -nsw -ear -flags -pci -baker -launched -elsewhere -pollution -conservative -guestbook -shock -effectiveness -walls -abroad -ebony -tie -ward -drawn -arthur -ian -visited -roof -walker -demonstrate -atmosphere -suggests -kiss -beast -ra -operated -experiment -targets -overseas -purchases -dodge -counsel -federation -pizza -invited -yards -assignment -chemicals -gordon -mod -farmers -rc -queries -bmw -rush -ukraine -absence -nearest -cluster -vendors -mpeg -whereas -yoga -serves -woods -surprise -lamp -rico -partial -shoppers -phil -everybody -couples -nashville -ranking -jokes -cst -http -ceo -simpson -twiki -sublime -counseling -palace -acceptable -satisfied -glad -wins -measurements -verify -globe -trusted -copper -milwaukee -rack -medication -warehouse -shareware -ec -rep -dicke -kerry -receipt -supposed -ordinary -nobody -ghost -violation -configure -stability -mit -applying -southwest -boss -pride -institutional -expectations -independence -knowing -reporter -metabolism -keith -champion -cloudy -linda -ross -personally -chile -anna -plenty -solo -sentence -throat -ignore -maria -uniform -excellence -wealth -tall -rm -somewhere -vacuum -dancing -attributes -recognize -brass -writes -plaza -pdas -outcomes -survival -quest -publish -sri -screening -toe -thumbnail -trans -jonathan -whenever -nova -lifetime -api -pioneer -booty -forgotten -acrobat -plates -acres -venue -athletic -thermal -essays -behaviour -vital -telling -fairly -coastal -config -cf -charity -intelligent -edinburgh -vt -excel -modes -obligation -campbell -wake -stupid -harbor -hungary -traveler -urw -segment -realize -regardless -lan -enemy -puzzle -rising -aluminum -wells -wishlist -opens -insight -sms -shit -restricted -republican -secrets -lucky -latter -merchants -thick -trailers -repeat -syndrome -philips -attendance -penalty -drum -glasses -enables -nec -iraqi -builder -vista -jessica -chips -terry -flood -foto -ease -arguments -amsterdam -orgy -arena -adventures -pupils -stewart -announcement -tabs -outcome -xx -appreciate -expanded -casual -grown -polish -lovely -extras -gm -centres -jerry -clause -smile -lands -ri -troops -indoor -bulgaria -armed -broker -charger -regularly -believed -pine -cooling -tend -gulf -rt -rick -trucks -cp -mechanisms -divorce -laura -shopper -tokyo -partly -nikon -customize -tradition -candy -pills -tiger -donald -folks -sensor -exposed -telecom -hunt -angels -deputy -indicators -sealed -thai -emissions -physicians -loaded -fred -complaint -scenes -experiments -balls -afghanistan -dd -boost -spanking -scholarship -governance -mill -founded -supplements -chronic -icons -tranny -moral -den -catering -aud -finger -keeps -pound -locate -camcorder -pl -trained -burn -implementing -roses -labs -ourselves -bread -tobacco -wooden -motors -tough -roberts -incident -gonna -dynamics -lie -crm -rf -conversation -decrease -cumshots -chest -pension -billy -revenues -emerging -worship -bukkake -capability -ak -fe -craig -herself -producing -churches -precision -damages -reserves -contributed -solve -shorts -reproduction -minority -td -diverse -amp -ingredients -sb -ah -johnny -sole -franchise -recorder -complaints -facing -sm -nancy -promotions -tones -passion -rehabilitation -maintaining -sight -laid -clay -defence -patches -weak -refund -usc -towns -environments -trembl -divided -blvd -reception -amd -wise -emails -cyprus -wv -odds -correctly -insider -seminars -consequences -makers -hearts -geography -appearing -integrity -worry -ns -discrimination -eve -carter -legacy -marc -pleased -danger -vitamin -widely -processed -phrase -genuine -raising -implications -functionality -paradise -hybrid -reads -roles -intermediate -emotional -sons -leaf -pad -glory -platforms -ja -bigger -billing -diesel -versus -combine -overnight -geographic -exceed -bs -rod -saudi -fault -cuba -hrs -preliminary -districts -introduce -silk -promotional -kate -chevrolet -babies -bi -karen -compiled -romantic -revealed -specialists -generator -albert -examine -jimmy -graham -suspension -bristol -margaret -compaq -sad -correction -wolf -slowly -authentication -communicate -rugby -supplement -showtimes -cal -portions -infant -promoting -sectors -samuel -fluid -grounds -fits -kick -regards -meal -ta -hurt -machinery -bandwidth -unlike -equation -baskets -probability -pot -dimension -wright -img -barry -proven -schedules -admissions -cached -warren -slip -studied -reviewer -involves -quarterly -rpm -profits -devil -grass -comply -marie -florist -illustrated -cherry -continental -alternate -deutsch -achievement -limitations -kenya -webcam -cuts -funeral -nutten -earrings -enjoyed -automated -chapters -pee -charlie -quebec -nipples -passenger -convenient -dennis -mars -francis -tvs -sized -manga -noticed -socket -silent -literary -egg -mhz -signals -caps -orientation -pill -theft -childhood -swing -symbols -lat -meta -humans -analog -facial -choosing -talent -dated -flexibility -seeker -wisdom -shoot -boundary -mint -packard -offset -payday -philip -elite -gi -spin -holders -believes -swedish -poems -deadline -jurisdiction -robot -displaying -witness -collins -equipped -stages -encouraged -sur -winds -powder -broadway -acquired -assess -wash -cartridges -stones -entrance -gnome -roots -declaration -losing -attempts -gadgets -noble -glasgow -automation -impacts -rev -gospel -advantages -shore -loves -induced -ll -knight -preparing -loose -aims -recipient -linking -extensions -appeals -cl -earned -illness -islamic -athletics -southeast -ieee -ho -alternatives -pending -parker -determining -lebanon -corp -personalized -kennedy -gt -sh -conditioning -teenage -soap -ae -triple -cooper -nyc -vincent -jam -secured -unusual -answered -partnerships -destruction -slots -increasingly -migration -disorder -routine -toolbar -basically -rocks -conventional -titans -applicants -wearing -axis -sought -genes -mounted -habitat -firewall -median -guns -scanner -herein -occupational -animated -horny -judicial -rio -hs -adjustment -hero -integer -treatments -bachelor -attitude -camcorders -engaged -falling -basics -montreal -carpet -rv -struct -lenses -binary -genetics -attended -difficulty -punk -collective -coalition -pi -dropped -enrollment -duke -walter -ai -pace -besides -wage -producers -ot -collector -arc -hosts -interfaces -advertisers -moments -atlas -strings -dawn -representing -observation -feels -torture -carl -deleted -coat -mitchell -mrs -rica -restoration -convenience -returning -ralph -opposition -container -yr -defendant -warner -confirmation -app -embedded -inkjet -supervisor -wizard -corps -actors -liver -peripherals -liable -brochure -morris -bestsellers -petition -eminem -recall -antenna -picked -assumed -departure -minneapolis -belief -killing -bikini -memphis -shoulder -decor -lookup -texts -harvard -brokers -roy -ion -diameter -ottawa -doll -ic -podcast -tit -seasons -peru -interactions -refine -bidder -singer -evans -herald -literacy -fails -aging -nike -intervention -pissing -fed -plugin -attraction -diving -invite -modification -alice -latinas -suppose -customized -reed -involve -moderate -terror -younger -thirty -mice -opposite -understood -rapidly -dealtime -ban -temp -intro -mercedes -zus -assurance -fisting -clerk -happening -vast -mills -outline -amendments -tramadol -holland -receives -jeans -metropolitan -compilation -verification -fonts -ent -odd -wrap -refers -mood -favor -veterans -quiz -mx -sigma -gr -attractive -xhtml -occasion -recordings -jefferson -victim -demands -sleeping -careful -ext -beam -gardening -obligations -arrive -orchestra -sunset -tracked -moreover -minimal -polyphonic -lottery -tops -framed -aside -outsourcing -licence -adjustable -allocation -michelle -essay -discipline -amy -ts -demonstrated -dialogue -identifying -alphabetical -camps -declared -dispatched -aaron -handheld -trace -disposal -shut -florists -packs -ge -installing -switches -romania -voluntary -ncaa -thou -consult -phd -greatly -blogging -mask -cycling -midnight -ng -commonly -pe -photographer -inform -turkish -coal -cry -messaging -pentium -quantum -murray -intent -tt -zoo -largely -pleasant -announce -constructed -additions -requiring -spoke -aka -arrow -engagement -sampling -rough -weird -tee -refinance -lion -inspired -holes -weddings -blade -suddenly -oxygen -cookie -meals -canyon -goto -meters -merely -calendars -arrangement -conclusions -passes -bibliography -pointer -compatibility -stretch -durham -furthermore -permits -cooperative -muslim -xl -neil -sleeve -netscape -cleaner -cricket -beef -feeding -stroke -township -rankings -measuring -cad -hats -robin -robinson -jacksonville -strap -headquarters -sharon -crowd -tcp -transfers -surf -olympic -transformation -remained -attachments -dv -dir -entities -customs -administrators -personality -rainbow -hook -roulette -decline -gloves -israeli -medicare -cord -skiing -cloud -facilitate -subscriber -valve -val -hewlett -explains -proceed -flickr -feelings -knife -jamaica -priorities -shelf -bookstore -timing -liked -parenting -adopt -denied -fotos -incredible -britney -freeware -fucked -donation -outer -crop -deaths -rivers -commonwealth -pharmaceutical -manhattan -tales -katrina -workforce -islam -nodes -tu -fy -thumbs -seeds -cited -lite -ghz -hub -targeted -organizational -skype -realized -twelve -founder -decade -gamecube -rr -dispute -portuguese -tired -titten -adverse -everywhere -excerpt -eng -steam -discharge -ef -drinks -ace -voices -acute -halloween -climbing -stood -sing -tons -perfume -carol -honest -albany -hazardous -restore -stack -methodology -somebody -sue -ep -housewares -reputation -resistant -democrats -recycling -hang -gbp -curve -creator -amber -qualifications -museums -coding -slideshow -tracker -variation -passage -transferred -trunk -hiking -lb -damn -pierre -jelsoft -headset -photograph -oakland -colombia -waves -camel -distributor -lamps -underlying -hood -wrestling -suicide -archived -photoshop -jp -chi -bt -arabia -gathering -projection -juice -chase -mathematical -logical -sauce -fame -extract -specialized -diagnostic -panama -indianapolis -af -payable -corporations -courtesy -criticism -automobile -confidential -rfc -statutory -accommodations -athens -northeast -downloaded -judges -sl -seo -retired -isp -remarks -detected -decades -paintings -walked -arising -nissan -bracelet -ins -eggs -juvenile -injection -yorkshire -populations -protective -afraid -acoustic -railway -cassette -initially -indicator -pointed -hb -jpg -causing -mistake -norton -locked -eliminate -tc -fusion -mineral -sunglasses -ruby -steering -beads -fortune -preference -canvas -threshold -parish -claimed -screens -cemetery -planner -croatia -flows -stadium -venezuela -exploration -mins -fewer -sequences -coupon -nurses -ssl -stem -proxy -gangbang -astronomy -lanka -opt -edwards -drew -contests -flu -translate -announces -mlb -costume -tagged -berkeley -voted -killer -bikes -gates -adjusted -rap -tune -bishop -pulled -corn -gp -shaped -compression -seasonal -establishing -farmer -counters -puts -constitutional -grew -perfectly -tin -slave -instantly -cultures -norfolk -coaching -examined -trek -encoding -litigation -submissions -oem -heroes -painted -lycos -ir -zdnet -broadcasting -horizontal -artwork -cosmetic -resulted -portrait -terrorist -informational -ethical -carriers -ecommerce -mobility -floral -builders -ties -struggle -schemes -suffering -neutral -fisher -rat -spears -prospective -dildos -bedding -ultimately -joining -heading -equally -artificial -bearing -spectacular -coordination -connector -brad -combo -seniors -worlds -guilty -affiliated -activation -naturally -haven -tablet -jury -dos -tail -subscribers -charm -lawn -violent -mitsubishi -underwear -basin -soup -potentially -ranch -constraints -crossing -inclusive -dimensional -cottage -drunk -considerable -crimes -resolved -mozilla -byte -toner -nose -latex -branches -anymore -oclc -delhi -holdings -alien -locator -selecting -processors -pantyhose -plc -broke -nepal -zimbabwe -difficulties -juan -complexity -msg -constantly -browsing -resolve -barcelona -presidential -documentary -cod -territories -melissa -moscow -thesis -thru -jews -nylon -palestinian -discs -rocky -bargains -frequent -trim -nigeria -ceiling -pixels -ensuring -hispanic -cv -cb -legislature -hospitality -gen -anybody -procurement -diamonds -espn -fleet -untitled -bunch -totals -marriott -singing -theoretical -afford -exercises -starring -referral -nhl -surveillance -optimal -quit -distinct -protocols -lung -highlight -substitute -inclusion -hopefully -brilliant -turner -sucking -cents -reuters -ti -fc -gel -todd -spoken -omega -evaluated -stayed -civic -assignments -fw -manuals -doug -sees -termination -watched -saver -thereof -grill -households -gs -redeem -rogers -grain -aaa -authentic -regime -wanna -wishes -bull -montgomery -architectural -louisville -depend -differ -macintosh -movements -ranging -monica -repairs -breath -amenities -virtually -cole -mart -candle -hanging -colored -authorization -tale -verified -lynn -formerly -projector -bp -situated -comparative -std -seeks -herbal -loving -strictly -routing -docs -stanley -psychological -surprised -retailer -vitamins -elegant -gains -renewal -vid -genealogy -opposed -deemed -scoring -expenditure -panties -brooklyn -liverpool -sisters -critics -connectivity -spots -oo -algorithms -hacker -madrid -similarly -margin -coin -bbw -solely -fake -salon -collaborative -norman -fda -excluding -turbo -headed -voters -cure -madonna -commander -arch -ni -murphy -thinks -thats -suggestion -hdtv -soldier -phillips -asin -aimed -justin -bomb -harm -interval -mirrors -spotlight -tricks -reset -brush -investigate -thy -expansys -panels -repeated -assault -connecting -spare -logistics -deer -kodak -tongue -bowling -tri -danish -pal -monkey -proportion -filename -skirt -florence -invest -honey -um -analyses -drawings -significance -scenario -ye -fs -lovers -atomic -approx -symposium -arabic -gauge -essentials -junction -protecting -nn -faced -mat -rachel -solving -transmitted -weekends -screenshots -produces -oven -ted -intensive -chains -kingston -sixth -engage -deviant -noon -switching -quoted -adapters -correspondence -farms -imports -supervision -cheat -bronze -expenditures -sandy -separation -testimony -suspect -celebrities -macro -sender -mandatory -boundaries -crucial -syndication -gym -celebration -kde -adjacent -filtering -tuition -spouse -exotic -viewer -signup -threats -luxembourg -puzzles -reaching -vb -damaged -cams -receptor -piss -laugh -joel -surgical -destroy -citation -pitch -autos -yo -premises -perry -proved -offensive -imperial -dozen -benjamin -deployment -teeth -cloth -studying -colleagues -stamp -lotus -salmon -olympus -separated -proc -cargo -tan -directive -fx -salem -mate -dl -starter -upgrades -likes -butter -pepper -weapon -luggage -burden -chef -tapes -zones -races -isle -stylish -slim -maple -luke -grocery -offshore -governing -retailers -depot -kenneth -comp -alt -pie -blend -harrison -ls -julie -occasionally -cbs -attending -emission -pete -spec -finest -realty -janet -bow -penn -recruiting -apparent -instructional -phpbb -autumn -traveling -probe -midi -permissions -biotechnology -toilet -ranked -jackets -routes -packed -excited -outreach -helen -mounting -recover -tied -lopez -balanced -prescribed -catherine -timely -talked -upskirts -debug -delayed -chuck -reproduced -hon -dale -explicit -calculation -villas -ebook -consolidated -boob -exclude -peeing -occasions -brooks -equations -newton -oils -sept -exceptional -anxiety -bingo -whilst -spatial -respondents -unto -lt -ceramic -prompt -precious -minds -annually -considerations -scanners -atm -xanax -eq -pays -cox -fingers -sunny -ebooks -delivers -je -queensland -necklace -musicians -leeds -composite -unavailable -cedar -arranged -lang -theaters -advocacy -raleigh -stud -fold -essentially -designing -threaded -uv -qualify -fingering -blair -hopes -assessments -cms -mason -diagram -burns -pumps -slut -ejaculation -footwear -sg -vic -beijing -peoples -victor -mario -pos -attach -licenses -utils -removing -advised -brunswick -spider -phys -ranges -pairs -sensitivity -trails -preservation -hudson -isolated -calgary -interim -assisted -divine -streaming -approve -chose -compound -intensity -technological -syndicate -abortion -dialog -venues -blast -wellness -calcium -newport -antivirus -addressing -pole -discounted -indians -shield -harvest -membrane -prague -previews -bangladesh -constitute -locally -concluded -pickup -desperate -mothers -nascar -iceland -demonstration -governmental -manufactured -candles -graduation -mega -bend -sailing -variations -moms -sacred -addiction -morocco -chrome -tommy -springfield -refused -brake -exterior -greeting -ecology -oliver -congo -glen -botswana -nav -delays -synthesis -olive -undefined -unemployment -cyber -verizon -scored -enhancement -newcastle -clone -dicks -velocity -lambda -relay -composed -tears -performances -oasis -baseline -cab -angry -fa -societies -silicon -brazilian -identical -petroleum -compete -ist -norwegian -lover -belong -honolulu -beatles -lips -escort -retention -exchanges -pond -rolls -thomson -barnes -soundtrack -wondering -malta -daddy -lc -ferry -rabbit -profession -seating -dam -cnn -separately -physiology -lil -collecting -das -exports -omaha -tire -participant -scholarships -recreational -dominican -chad -electron -loads -friendship -heather -passport -motel -unions -treasury -warrant -sys -solaris -frozen -occupied -josh -royalty -scales -rally -observer -sunshine -strain -drag -ceremony -somehow -arrested -expanding -provincial -investigations -icq -ripe -yamaha -rely -medications -hebrew -gained -rochester -dying -laundry -stuck -solomon -placing -stops -homework -adjust -assessed -advertiser -enabling -encryption -filling -downloadable -sophisticated -imposed -silence -scsi -focuses -soviet -possession -cu -laboratories -treaty -vocal -trainer -organ -stronger -volumes -advances -vegetables -lemon -toxic -dns -thumbnails -darkness -pty -ws -nuts -nail -bizrate -vienna -implied -span -stanford -sox -stockings -joke -respondent -packing -statute -rejected -satisfy -destroyed -shelter -chapel -gamespot -manufacture -layers -wordpress -guided -vulnerability -accountability -celebrate -accredited -appliance -compressed -bahamas -powell -mixture -zoophilia -bench -univ -tub -rider -scheduling -radius -perspectives -mortality -logging -hampton -christians -borders -therapeutic -pads -butts -inns -bobby -impressive -sheep -accordingly -architect -railroad -lectures -challenging -wines -nursery -harder -cups -ash -microwave -cheapest -accidents -travesti -relocation -stuart -contributors -salvador -ali -salad -np -monroe -tender -violations -foam -temperatures -paste -clouds -competitions -discretion -tft -tanzania -preserve -jvc -poem -vibrator -unsigned -staying -cosmetics -easter -theories -repository -praise -jeremy -venice -jo -concentrations -vibrators -estonia -christianity -veteran -streams -landing -signing -executed -katie -negotiations -realistic -dt -cgi -showcase -integral -asks -relax -namibia -generating -christina -congressional -synopsis -hardly -prairie -reunion -composer -bean -sword -absent -photographic -sells -ecuador -hoping -accessed -spirits -modifications -coral -pixel -float -colin -bias -imported -paths -bubble -por -acquire -contrary -millennium -tribune -vessel -acids -focusing -viruses -cheaper -admitted -dairy -admit -mem -fancy -equality -samoa -gc -achieving -tap -stickers -fisheries -exceptions -reactions -leasing -lauren -beliefs -ci -macromedia -companion -squad -analyze -ashley -scroll -relate -divisions -swim -wages -additionally -suffer -forests -fellowship -nano -invalid -concerts -martial -males -victorian -retain -colours -execute -tunnel -genres -cambodia -patents -copyrights -yn -chaos -lithuania -mastercard -wheat -chronicles -obtaining -beaver -updating -distribute -readings -decorative -kijiji -confused -compiler -enlargement -eagles -bases -vii -accused -bee -campaigns -unity -loud -conjunction -bride -rats -defines -airports -instances -indigenous -begun -cfr -brunette -packets -anchor -socks -validation -parade -corruption -stat -trigger -incentives -cholesterol -gathered -essex -slovenia -notified -differential -beaches -folders -dramatic -surfaces -terrible -routers -cruz -pendant -dresses -baptist -scientist -starsmerchant -hiring -clocks -arthritis -bios -females -wallace -nevertheless -reflects -taxation -fever -pmc -cuisine -surely -practitioners -transcript -myspace -theorem -inflation -thee -nb -ruth -pray -stylus -compounds -pope -drums -contracting -topless -arnold -structured -reasonably -jeep -chicks -bare -hung -cattle -mba -radical -graduates -rover -recommends -controlling -treasure -reload -distributors -flame -levitra -tanks -assuming -monetary -elderly -pit -arlington -mono -particles -floating -extraordinary -tile -indicating -bolivia -spell -hottest -stevens -coordinate -kuwait -exclusively -emily -alleged -limitation -widescreen -compile -squirting -webster -struck -rx -illustration -plymouth -warnings -construct -apps -inquiries -bridal -annex -mag -gsm -inspiration -tribal -curious -affecting -freight -rebate -meetup -eclipse -sudan -ddr -downloading -rec -shuttle -aggregate -stunning -cycles -affects -forecasts -detect -sluts -actively -ciao -ampland -knee -prep -pb -complicated -chem -fastest -butler -shopzilla -injured -decorating -payroll -cookbook -expressions -ton -courier -uploaded -shakespeare -hints -collapse -americas -connectors -twinks -unlikely -oe -gif -pros -conflicts -techno -beverage -tribute -wired -elvis -immune -latvia -travelers -forestry -barriers -cant -jd -rarely -gpl -infected -offerings -martha -genesis -barrier -argue -incorrect -trains -metals -bicycle -furnishings -letting -arise -guatemala -celtic -thereby -irc -jamie -particle -perception -minerals -advise -humidity -bottles -boxing -wy -dm -bangkok -renaissance -pathology -sara -bra -ordinance -hughes -photographers -bitch -infections -jeffrey -chess -operates -brisbane -configured -survive -oscar -festivals -menus -joan -possibilities -duck -reveal -canal -amino -phi -contributing -herbs -clinics -mls -cow -manitoba -analytical -missions -watson -lying -costumes -strict -dive -saddam -circulation -drill -offense -threesome -bryan -cet -protest -handjob -assumption -jerusalem -hobby -tries -transexuales -invention -nickname -fiji -technician -inline -executives -enquiries -washing -audi -staffing -cognitive -exploring -trick -enquiry -closure -raid -ppc -timber -volt -intense -div -playlist -registrar -showers -supporters -ruling -steady -dirt -statutes -withdrawal -myers -drops -predicted -wider -saskatchewan -jc -cancellation -plugins -enrolled -sensors -screw -ministers -publicly -hourly -blame -geneva -freebsd -veterinary -acer -prostores -reseller -dist -handed -suffered -intake -informal -relevance -incentive -butterfly -tucson -mechanics -heavily -swingers -fifty -headers -mistakes -numerical -ons -geek -uncle -defining -xnxx -counting -reflection -sink -accompanied -assure -invitation -devoted -princeton -jacob -sodium -randy -spirituality -hormone -meanwhile -proprietary -timothy -childrens -brick -grip -naval -thumbzilla -medieval -porcelain -avi -bridges -pichunter -captured -watt -thehun -decent -casting -dayton -translated -shortly -cameron -columnists -pins -carlos -reno -donna -andreas -warrior -diploma -cabin -innocent -bdsm -scanning -ide -consensus -polo -valium -copying -rpg -delivering -cordless -patricia -horn -eddie -uganda -fired -journalism -pd -prot -trivia -adidas -perth -frog -grammar -intention -syria -disagree -klein -harvey -tires -logs -undertaken -tgp -hazard -retro -leo -livesex -statewide -semiconductor -gregory -episodes -boolean -circular -anger -diy -mainland -illustrations -suits -chances -interact -snap -happiness -arg -substantially -bizarre -glenn -ur -auckland -olympics -fruits -identifier -geo -worldsex -ribbon -calculations -doe -jpeg -conducting -startup -suzuki -trinidad -ati -kissing -wal -handy -swap -exempt -crops -reduces -accomplished -calculators -geometry -impression -abs -slovakia -flip -guild -correlation -gorgeous -capitol -sim -dishes -rna -barbados -chrysler -nervous -refuse -extends -fragrance -mcdonald -replica -plumbing -brussels -tribe -neighbors -trades -superb -buzz -transparent -nuke -rid -trinity -charleston -handled -legends -boom -calm -champions -floors -selections -projectors -inappropriate -exhaust -comparing -shanghai -speaks -burton -vocational -davidson -copied -scotia -farming -gibson -pharmacies -fork -troy -ln -roller -introducing -batch -organize -appreciated -alter -nicole -latino -ghana -edges -uc -mixing -handles -skilled -fitted -albuquerque -harmony -distinguished -asthma -projected -assumptions -shareholders -twins -developmental -rip -zope -regulated -triangle -amend -anticipated -oriental -reward -windsor -zambia -completing -gmbh -buf -ld -hydrogen -webshots -sprint -comparable -chick -advocate -sims -confusion -copyrighted -tray -inputs -warranties -genome -escorts -documented -thong -medal -paperbacks -coaches -vessels -harbour -walks -sucks -sol -keyboards -sage -knives -eco -vulnerable -arrange -artistic -bat -honors -booth -indie -reflected -unified -bones -breed -detector -ignored -polar -fallen -precise -sussex -respiratory -notifications -msgid -transexual -mainstream -invoice -evaluating -lip -subcommittee -sap -gather -suse -maternity -backed -alfred -colonial -mf -carey -motels -forming -embassy -cave -journalists -danny -rebecca -slight -proceeds -indirect -amongst -wool -foundations -msgstr -arrest -volleyball -mw -adipex -horizon -nu -deeply -toolbox -ict -marina -liabilities -prizes -bosnia -browsers -decreased -patio -dp -tolerance -surfing -creativity -lloyd -describing -optics -pursue -lightning -overcome -eyed -ou -quotations -grab -inspector -attract -brighton -beans -bookmarks -ellis -disable -snake -succeed -leonard -lending -oops -reminder -nipple -xi -searched -behavioral -riverside -bathrooms -plains -sku -ht -raymond -insights -abilities -initiated -sullivan -za -midwest -karaoke -trap -lonely -fool -ve -nonprofit -lancaster -suspended -hereby -observe -julia -containers -attitudes -karl -berry -collar -simultaneously -racial -integrate -bermuda -amanda -sociology -mobiles -screenshot -exhibitions -kelkoo -confident -retrieved -exhibits -officially -consortium -dies -terrace -bacteria -pts -replied -seafood -novels -rh -rrp -recipients -playboy -ought -delicious -traditions -fg -jail -safely -finite -kidney -periodically -fixes -sends -durable -mazda -allied -throws -moisture -hungarian -roster -referring -symantec -spencer -wichita -nasdaq -uruguay -ooo -hz -transform -timer -tablets -tuning -gotten -educators -tyler -futures -vegetable -verse -highs -humanities -independently -wanting -custody -scratch -launches -ipaq -alignment -masturbating -henderson -bk -britannica -comm -ellen -competitors -nhs -rocket -aye -bullet -towers -racks -lace -nasty -visibility -latitude -consciousness -ste -tumor -ugly -deposits -beverly -mistress -encounter -trustees -watts -duncan -reprints -hart -bernard -resolutions -ment -accessing -forty -tubes -attempted -col -midlands -priest -floyd -ronald -analysts -queue -dx -sk -trance -locale -nicholas -biol -yu -bundle -hammer -invasion -witnesses -runner -rows -administered -notion -sq -skins -mailed -oc -fujitsu -spelling -arctic -exams -rewards -beneath -strengthen -defend -aj -frederick -medicaid -treo -infrared -seventh -gods -une -welsh -belly -aggressive -tex -advertisements -quarters -stolen -cia -sublimedirectory -soonest -haiti -disturbed -determines -sculpture -poly -ears -dod -wp -fist -naturals -neo -motivation -lenders -pharmacology -fitting -fixtures -bloggers -mere -agrees -passengers -quantities -petersburg -consistently -powerpoint -cons -surplus -elder -sonic -obituaries -cheers -dig -taxi -punishment -appreciation -subsequently -om -belarus -nat -zoning -gravity -providence -thumb -restriction -incorporate -backgrounds -treasurer -guitars -essence -flooring -lightweight -ethiopia -tp -mighty -athletes -humanity -transcription -jm -holmes -complications -scholars -dpi -scripting -gis -remembered -galaxy -chester -snapshot -caring -loc -worn -synthetic -shaw -vp -segments -testament -expo -dominant -twist -specifics -itunes -stomach -partially -buried -cn -newbie -minimize -darwin -ranks -wilderness -debut -generations -tournaments -bradley -deny -anatomy -bali -judy -sponsorship -headphones -fraction -trio -proceeding -cube -defects -volkswagen -uncertainty -breakdown -milton -marker -reconstruction -subsidiary -strengths -clarity -rugs -sandra -adelaide -encouraging -furnished -monaco -settled -folding -emirates -terrorists -airfare -comparisons -beneficial -distributions -vaccine -belize -crap -fate -viewpicture -promised -volvo -penny -robust -bookings -threatened -minolta -republicans -discusses -gui -porter -gras -jungle -ver -rn -responded -rim -abstracts -zen -ivory -alpine -dis -prediction -pharmaceuticals -andale -fabulous -remix -alias -thesaurus -individually -battlefield -literally -newer -kay -ecological -spice -oval -implies -cg -soma -ser -cooler -appraisal -consisting -maritime -periodic -submitting -overhead -ascii -prospect -shipment -breeding -citations -geographical -donor -mozambique -tension -href -benz -trash -shapes -wifi -tier -fwd -earl -manor -envelope -diane -homeland -disclaimers -championships -excluded -andrea -breeds -rapids -disco -sheffield -bailey -aus -endif -finishing -emotions -wellington -incoming -prospects -lexmark -cleaners -bulgarian -hwy -eternal -cashiers -guam -cite -aboriginal -remarkable -rotation -nam -preventing -productive -boulevard -eugene -ix -gdp -pig -metric -compliant -minus -penalties -bennett -imagination -hotmail -refurbished -joshua -armenia -varied -grande -closest -activated -actress -mess -conferencing -assign -armstrong -politicians -trackbacks -lit -accommodate -tigers -aurora -una -slides -milan -premiere -lender -villages -shade -chorus -christine -rhythm -digit -argued -dietary -symphony -clarke -sudden -accepting -precipitation -marilyn -lions -findlaw -ada -pools -tb -lyric -claire -isolation -speeds -sustained -matched -approximate -rope -carroll -rational -programmer -fighters -chambers -dump -greetings -inherited -warming -incomplete -vocals -chronicle -fountain -chubby -grave -legitimate -biographies -burner -yrs -foo -investigator -gba -plaintiff -finnish -gentle -bm -prisoners -deeper -muslims -hose -mediterranean -nightlife -footage -howto -worthy -reveals -architects -saints -entrepreneur -carries -sig -freelance -duo -excessive -devon -screensaver -helena -saves -regarded -valuation -unexpected -cigarette -fog -characteristic -marion -lobby -egyptian -tunisia -metallica -outlined -consequently -headline -treating -punch -appointments -str -gotta -cowboy -narrative -bahrain -enormous -karma -consist -betty -queens -academics -pubs -quantitative -shemales -lucas -screensavers -subdivision -tribes -vip -defeat -clicks -distinction -honduras -naughty -hazards -insured -harper -livestock -mardi -exemption -tenant -sustainability -cabinets -tattoo -shake -algebra -shadows -holly -formatting -silly -nutritional -yea -mercy -hartford -freely -marcus -sunrise -wrapping -mild -fur -nicaragua -weblogs -timeline -tar -belongs -rj -readily -affiliation -soc -fence -nudist -infinite -diana -ensures -relatives -lindsay -clan -legally -shame -satisfactory -revolutionary -bracelets -sync -civilian -telephony -mesa -fatal -remedy -realtors -breathing -briefly -thickness -adjustments -graphical -genius -discussing -aerospace -fighter -meaningful -flesh -retreat -adapted -barely -wherever -estates -rug -democrat -borough -maintains -failing -shortcuts -ka -retained -voyeurweb -pamela -andrews -marble -extending -jesse -specifies -hull -logitech -surrey -briefing -belkin -dem -accreditation -wav -blackberry -highland -meditation -modular -microphone -macedonia -combining -brandon -instrumental -giants -organizing -shed -balloon -moderators -winston -memo -ham -solved -tide -kazakhstan -hawaiian -standings -partition -invisible -gratuit -consoles -funk -fbi -qatar -magnet -translations -porsche -cayman -jaguar -reel -sheer -commodity -posing -wang -kilometers -rp -bind -thanksgiving -rand -hopkins -urgent -guarantees -infants -gothic -cylinder -witch -buck -indication -eh -congratulations -tba -cohen -sie -usgs -puppy -kathy -acre -graphs -surround -cigarettes -revenge -expires -enemies -lows -controllers -aqua -chen -emma -consultancy -finances -accepts -enjoying -conventions -eva -patrol -smell -pest -hc -italiano -coordinates -rca -fp -carnival -roughly -sticker -promises -responding -reef -physically -divide -stakeholders -hydrocodone -gst -consecutive -cornell -satin -bon -deserve -attempting -mailto -promo -jj -representations -chan -worried -tunes -garbage -competing -combines -mas -beth -bradford -len -phrases -kai -peninsula -chelsea -boring -reynolds -dom -jill -accurately -speeches -reaches -schema -considers -sofa -catalogs -ministries -vacancies -quizzes -parliamentary -obj -prefix -lucia -savannah -barrel -typing -nerve -dans -planets -deficit -boulder -pointing -renew -coupled -viii -myanmar -metadata -harold -circuits -floppy -texture -handbags -jar -ev -somerset -incurred -acknowledge -thoroughly -antigua -nottingham -thunder -tent -caution -identifies -questionnaire -qualification -locks -modelling -namely -miniature -dept -hack -dare -euros -interstate -pirates -aerial -hawk -consequence -rebel -systematic -perceived -origins -hired -makeup -textile -lamb -madagascar -nathan -tobago -presenting -cos -troubleshooting -uzbekistan -indexes -pac -rl -erp -centuries -gl -magnitude -ui -richardson -hindu -dh -fragrances -vocabulary -licking -earthquake -vpn -fundraising -fcc -markers -weights -albania -geological -assessing -lasting -wicked -eds -introduces -kills -roommate -webcams -pushed -webmasters -ro -df -computational -acdbentity -participated -junk -handhelds -wax -lucy -answering -hans -impressed -slope -reggae -failures -poet -conspiracy -surname -theology -nails -evident -whats -rides -rehab -epic -saturn -organizer -nut -allergy -sake -twisted -combinations -preceding -merit -enzyme -cumulative -zshops -planes -edmonton -tackle -disks -condo -pokemon -amplifier -ambien -arbitrary -prominent -retrieve -lexington -vernon -sans -worldcat -titanium -irs -fairy -builds -contacted -shaft -lean -bye -cdt -recorders -occasional -leslie -casio -deutsche -ana -postings -innovations -kitty -postcards -dude -drain -monte -fires -algeria -blessed -luis -reviewing -cardiff -cornwall -favors -potato -panic -explicitly -sticks -leone -transsexual -ez -citizenship -excuse -reforms -basement -onion -strand -pf -sandwich -uw -lawsuit -alto -informative -girlfriend -bloomberg -cheque -hierarchy -influenced -banners -reject -eau -abandoned -bd -circles -italic -beats -merry -mil -scuba -gore -complement -cult -dash -passive -mauritius -valued -cage -checklist -bangbus -requesting -courage -verde -lauderdale -scenarios -gazette -hitachi -divx -extraction -batman -elevation -hearings -coleman -hugh -lap -utilization -beverages -calibration -jake -eval -efficiently -anaheim -ping -textbook -dried -entertaining -prerequisite -luther -frontier -settle -stopping -refugees -knights -hypothesis -palmer -medicines -flux -derby -sao -peaceful -altered -pontiac -regression -doctrine -scenic -trainers -muze -enhancements -renewable -intersection -passwords -sewing -consistency -collectors -conclude -recognised -munich -oman -celebs -gmc -propose -hh -azerbaijan -lighter -rage -adsl -uh -prix -astrology -advisors -pavilion -tactics -trusts -occurring -supplemental -travelling -talented -annie -pillow -induction -derek -precisely -shorter -harley -spreading -provinces -relying -finals -paraguay -steal -parcel -refined -fd -bo -fifteen -widespread -incidence -fears -predict -boutique -acrylic -rolled -tuner -avon -incidents -peterson -rays -asn -shannon -toddler -enhancing -flavor -alike -walt -homeless -horrible -hungry -metallic -acne -blocked -interference -warriors -palestine -listprice -libs -undo -cadillac -atmospheric -malawi -wm -pk -sagem -knowledgestorm -dana -halo -ppm -curtis -parental -referenced -strikes -lesser -publicity -marathon -ant -proposition -gays -pressing -gasoline -apt -dressed -scout -belfast -exec -dealt -niagara -inf -eos -warcraft -charms -catalyst -trader -bucks -allowance -vcr -denial -uri -designation -thrown -prepaid -raises -gem -duplicate -electro -criterion -badge -wrist -civilization -analyzed -vietnamese -heath -tremendous -ballot -lexus -varying -remedies -validity -trustee -maui -handjobs -weighted -angola -squirt -performs -plastics -realm -corrected -jenny -helmet -salaries -postcard -elephant -yemen -encountered -tsunami -scholar -nickel -internationally -surrounded -psi -buses -expedia -geology -pct -wb -creatures -coating -commented -wallet -cleared -smilies -vids -accomplish -boating -drainage -shakira -corners -broader -vegetarian -rouge -yeast -yale -newfoundland -sn -qld -pas -clearing -investigated -dk -ambassador -coated -intend -stephanie -contacting -vegetation -doom -findarticles -louise -kenny -specially -owen -routines -hitting -yukon -beings -bite -issn -aquatic -reliance -habits -striking -myth -infectious -podcasts -singh -gig -gilbert -sas -ferrari -continuity -brook -fu -outputs -phenomenon -ensemble -insulin -assured -biblical -weed -conscious -accent -mysimon -eleven -wives -ambient -utilize -mileage -oecd -prostate -adaptor -auburn -unlock -hyundai -pledge -vampire -angela -relates -nitrogen -xerox -dice -merger -softball -referrals -quad -dock -differently -firewire -mods -nextel -framing -organised -musician -blocking -rwanda -sorts -integrating -vsnet -limiting -dispatch -revisions -papua -restored -hint -armor -riders -chargers -remark -dozens -varies -msie -reasoning -wn -liz -rendered -picking -charitable -guards -annotated -ccd -sv -convinced -openings -buys -burlington -replacing -researcher -watershed -councils -occupations -acknowledged -nudity -kruger -pockets -granny -pork -zu -equilibrium -viral -inquire -pipes -characterized -laden -aruba -cottages -realtor -merge -privilege -edgar -develops -qualifying -chassis -dubai -estimation -barn -pushing -llp -fleece -pediatric -boc -fare -dg -asus -pierce -allan -dressing -techrepublic -sperm -vg -bald -filme -craps -fuji -frost -leon -institutes -mold -dame -fo -sally -yacht -tracy -prefers -drilling -brochures -herb -tmp -alot -ate -breach -whale -traveller -appropriations -suspected -tomatoes -benchmark -beginners -instructors -highlighted -bedford -stationery -idle -mustang -unauthorized -clusters -antibody -competent -momentum -fin -wiring -io -pastor -mud -calvin -uni -shark -contributor -demonstrates -phases -grateful -emerald -gradually -laughing -grows -cliff -desirable -tract -ul -ballet -ol -journalist -abraham -js -bumper -afterwards -webpage -religions -garlic -hostels -shine -senegal -explosion -pn -banned -wendy -briefs -signatures -diffs -cove -mumbai -ozone -disciplines -casa -mu -daughters -conversations -radios -tariff -nvidia -opponent -pasta -simplified -muscles -serum -wrapped -swift -motherboard -runtime -inbox -focal -bibliographic -vagina -eden -distant -incl -champagne -ala -decimal -hq -deviation -superintendent -propecia -dip -nbc -samba -hostel -housewives -employ -mongolia -penguin -magical -influences -inspections -irrigation -miracle -manually -reprint -reid -wt -hydraulic -centered -robertson -flex -yearly -penetration -wound -belle -rosa -conviction -hash -omissions -writings -hamburg -lazy -mv -mpg -retrieval -qualities -cindy -lolita -fathers -carb -charging -cas -marvel -lined -cio -dow -prototype -importantly -rb -petite -apparatus -upc -terrain -dui -pens -explaining -yen -strips -gossip -rangers -nomination -empirical -mh -rotary -worm -dependence -discrete -beginner -boxed -lid -sexuality -polyester -cubic -deaf -commitments -suggesting -sapphire -kinase -skirts -mats -remainder -crawford -labeled -privileges -televisions -specializing -marking -commodities -pvc -serbia -sheriff -griffin -declined -guyana -spies -blah -mime -neighbor -motorcycles -elect -highways -thinkpad -concentrate -intimate -reproductive -preston -deadly -cunt -feof -bunny -chevy -molecules -rounds -longest -refrigerator -tions -intervals -sentences -dentists -usda -exclusion -workstation -holocaust -keen -flyer -peas -dosage -receivers -urls -customise -disposition -variance -navigator -investigators -cameroon -baking -marijuana -adaptive -computed -needle -baths -enb -gg -cathedral -brakes -og -nirvana -ko -fairfield -owns -til -invision -sticky -destiny -generous -madness -emacs -climb -blowing -fascinating -landscapes -heated -lafayette -jackie -wto -computation -hay -cardiovascular -ww -sparc -cardiac -salvation -dover -adrian -predictions -accompanying -vatican -brutal -learners -gd -selective -arbitration -configuring -token -editorials -zinc -sacrifice -seekers -guru -isa -removable -convergence -yields -gibraltar -levy -suited -numeric -anthropology -skating -kinda -aberdeen -emperor -grad -malpractice -dylan -bras -belts -blacks -educated -rebates -reporters -burke -proudly -pix -necessity -rendering -mic -inserted -pulling -basename -kyle -obesity -curves -suburban -touring -clara -vertex -bw -hepatitis -nationally -tomato -andorra -waterproof -expired -mj -travels -flush -waiver -pale -specialties -hayes -humanitarian -invitations -functioning -delight -survivor -garcia -cingular -economies -alexandria -bacterial -moses -counted -undertake -declare -continuously -johns -valves -gaps -impaired -achievements -donors -tear -jewel -teddy -lf -convertible -ata -teaches -ventures -nil -bufing -stranger -tragedy -julian -nest -pam -dryer -painful -velvet -tribunal -ruled -nato -pensions -prayers -funky -secretariat -nowhere -cop -paragraphs -gale -joins -adolescent -nominations -wesley -dim -lately -cancelled -scary -mattress -mpegs -brunei -likewise -banana -introductory -slovak -cakes -stan -reservoir -occurrence -idol -bloody -mixer -remind -wc -worcester -sbjct -demographic -charming -mai -tooth -disciplinary -annoying -respected -stays -disclose -affair -drove -washer -upset -restrict -springer -beside -mines -portraits -rebound -logan -mentor -interpreted -evaluations -fought -baghdad -elimination -metres -hypothetical -immigrants -complimentary -helicopter -pencil -freeze -hk -performer -abu -titled -commissions -sphere -powerseller -moss -ratios -concord -graduated -endorsed -ty -surprising -walnut -lance -ladder -italia -unnecessary -dramatically -liberia -sherman -cork -maximize -cj -hansen -senators -workout -mali -yugoslavia -bleeding -characterization -colon -likelihood -lanes -purse -fundamentals -contamination -mtv -endangered -compromise -masturbation -optimize -stating -dome -caroline -leu -expiration -namespace -align -peripheral -bless -engaging -negotiation -crest -opponents -triumph -nominated -confidentiality -electoral -changelog -welding -orgasm -deferred -alternatively -heel -alloy -condos -plots -polished -yang -gently -greensboro -tulsa -locking -casey -controversial -draws -fridge -blanket -bloom -qc -simpsons -lou -elliott -recovered -fraser -justify -upgrading -blades -pgp -loops -surge -frontpage -trauma -aw -tahoe -advert -possess -demanding -defensive -sip -flashers -subaru -forbidden -tf -vanilla -programmers -pj -monitored -installations -deutschland -picnic -souls -arrivals -spank -cw -practitioner -motivated -wr -dumb -smithsonian -hollow -vault -securely -examining -fioricet -groove -revelation -rg -pursuit -delegation -wires -bl -dictionaries -mails -backing -greenhouse -sleeps -vc -blake -transparency -dee -travis -wx -endless -figured -orbit -currencies -niger -bacon -survivors -positioning -heater -colony -cannon -circus -promoted -forbes -mae -moldova -mel -descending -paxil -spine -trout -enclosed -feat -temporarily -ntsc -cooked -thriller -transmit -apnic -fatty -gerald -pressed -frequencies -scanned -reflections -hunger -mariah -sic -municipality -usps -joyce -detective -surgeon -cement -experiencing -fireplace -endorsement -bg -planners -disputes -textiles -missile -intranet -closes -seq -psychiatry -persistent -deborah -conf -marco -assists -summaries -glow -gabriel -auditor -wma -aquarium -violin -prophet -cir -bracket -looksmart -isaac -oxide -oaks -magnificent -erik -colleague -naples -promptly -modems -adaptation -hu -harmful -paintball -prozac -sexually -enclosure -acm -dividend -newark -kw -paso -glucose -phantom -norm -playback -supervisors -westminster -turtle -ips -distances -absorption -treasures -dsc -warned -neural -ware -fossil -mia -hometown -badly -transcripts -apollo -wan -disappointed -persian -continually -communist -collectible -handmade -greene -entrepreneurs -robots -grenada -creations -jade -scoop -acquisitions -foul -keno -gtk -earning -mailman -sanyo -nested -biodiversity -excitement -somalia -movers -verbal -blink -presently -seas -carlo -workflow -mysterious -novelty -bryant -tiles -voyuer -librarian -subsidiaries -switched -stockholm -tamil -garmin -ru -pose -fuzzy -indonesian -grams -therapist -richards -mrna -budgets -toolkit -promising -relaxation -goat -render -carmen -ira -sen -thereafter -hardwood -erotica -temporal -sail -forge -commissioners -dense -dts -brave -forwarding -qt -awful -nightmare -airplane -reductions -southampton -istanbul -impose -organisms -sega -telescope -viewers -asbestos -portsmouth -cdna -meyer -enters -pod -savage -advancement -wu -harassment -willow -resumes -bolt -gage -throwing -existed -whore -generators -lu -wagon -barbie -dat -favour -soa -knock -urge -smtp -generates -potatoes -thorough -replication -inexpensive -kurt -receptors -peers -roland -optimum -neon -interventions -quilt -huntington -creature -ours -mounts -syracuse -internship -lone -refresh -aluminium -snowboard -beastality -webcast -michel -evanescence -subtle -coordinated -notre -shipments -maldives -stripes -firmware -antarctica -cope -shepherd -lm -canberra -cradle -chancellor -mambo -lime -kirk -flour -controversy -legendary -bool -sympathy -choir -avoiding -beautifully -blond -expects -cho -jumping -fabrics -antibodies -polymer -hygiene -wit -poultry -virtue -burst -examinations -surgeons -bouquet -immunology -promotes -mandate -wiley -departmental -bbs -spas -ind -corpus -johnston -terminology -gentleman -fibre -reproduce -convicted -shades -jets -indices -roommates -adware -qui -intl -threatening -spokesman -zoloft -activists -frankfurt -prisoner -daisy -halifax -encourages -ultram -cursor -assembled -earliest -donated -stuffed -restructuring -insects -terminals -crude -morrison -maiden -simulations -cz -sufficiently -examines -viking -myrtle -bored -cleanup -yarn -knit -conditional -mug -crossword -bother -budapest -conceptual -knitting -attacked -hl -bhutan -liechtenstein -mating -compute -redhead -arrives -translator -automobiles -tractor -allah -continent -ob -unwrap -fares -longitude -resist -challenged -telecharger -hoped -pike -safer -insertion -instrumentation -ids -hugo -wagner -constraint -groundwater -touched -strengthening -cologne -gzip -wishing -ranger -smallest -insulation -newman -marsh -ricky -ctrl -scared -theta -infringement -bent -laos -subjective -monsters -asylum -lightbox -robbie -stake -cocktail -outlets -swaziland -varieties -arbor -mediawiki -configurations -poison diff --git a/Code/Deprecated/makefile b/Code/Deprecated/makefile deleted file mode 100644 index 5fa4116..0000000 --- a/Code/Deprecated/makefile +++ /dev/null @@ -1,3 +0,0 @@ -all: DqnUnitTest.cpp - mkdir -p bin - g++ -std=c++14 -o bin/DqnUnitTest DqnUnitTest.cpp -lm -Wall -pthread -ggdb