Add quicksort generic to lib
This commit is contained in:
parent
825caefe4a
commit
cbf7b4d606
@ -17,7 +17,7 @@ REM Drop compilation files into build folder
|
|||||||
IF NOT EXIST bin mkdir bin
|
IF NOT EXIST bin mkdir bin
|
||||||
pushd bin
|
pushd bin
|
||||||
|
|
||||||
REM EHa- disable exception handling (we don't use)
|
REM EHa- disable exception handling (but we use for algorithms so /EHsc)
|
||||||
REM GR- disable c runtime type information (we don't use)
|
REM GR- disable c runtime type information (we don't use)
|
||||||
|
|
||||||
REM MD use dynamic runtime library
|
REM MD use dynamic runtime library
|
||||||
@ -30,11 +30,8 @@ REM Zi enables debug data, Z7 combines the debug files into one.
|
|||||||
|
|
||||||
REM W4 warning level 4
|
REM W4 warning level 4
|
||||||
REM WX treat warnings as errors
|
REM WX treat warnings as errors
|
||||||
REM wd4100 ignore: unused argument parameters
|
|
||||||
REM wd4201 ignore: nonstandard extension used: nameless struct/union
|
REM wd4201 ignore: nonstandard extension used: nameless struct/union
|
||||||
REM wd4189 ignore: local variable is initialised but not referenced
|
set CompileFlags=-EHsc -GR- -Oi -MT -Z7 -W4 -WX -wd4201 -FC -O2
|
||||||
|
|
||||||
set CompileFlags=-EHa- -GR- -Oi -MT -Z7 -W4 -WX -wd4100 -wd4201 -wd4189 -FC -Od
|
|
||||||
|
|
||||||
REM Include directories
|
REM Include directories
|
||||||
set IncludeFlags=
|
set IncludeFlags=
|
||||||
@ -44,7 +41,7 @@ set LinkLibraries=user32.lib gdi32.lib msimg32.lib
|
|||||||
|
|
||||||
REM incrmenetal:no, turn incremental builds off
|
REM incrmenetal:no, turn incremental builds off
|
||||||
REM opt:ref, try to remove functions from libs that are referenced at all
|
REM opt:ref, try to remove functions from libs that are referenced at all
|
||||||
set LinkFlags=-incremental:no -opt:ref
|
set LinkFlags=-incremental:no -opt:ref -machine:x64
|
||||||
|
|
||||||
cl %CompileFlags% %CompileEntryPoint% %IncludeFlags% /link %LinkLibraries% %LinkFlags% /nologo /OUT:"%ProjectName%.exe"
|
cl %CompileFlags% %CompileEntryPoint% %IncludeFlags% /link %LinkLibraries% %LinkFlags% /nologo /OUT:"%ProjectName%.exe"
|
||||||
REM cl /P /c %CompileFlags% %CompileEntryPoint%
|
REM cl /P /c %CompileFlags% %CompileEntryPoint%
|
||||||
|
183
dqn.h
183
dqn.h
@ -42,6 +42,7 @@
|
|||||||
// #DqnWChar WChar Operations (IsDigit(), IsAlpha() etc)
|
// #DqnWChar WChar Operations (IsDigit(), IsAlpha() etc)
|
||||||
// #DqnWStr WStr Operations (WStr_Len() etc)
|
// #DqnWStr WStr Operations (WStr_Len() etc)
|
||||||
// #DqnRnd Random Number Generator (ints and floats)
|
// #DqnRnd Random Number Generator (ints and floats)
|
||||||
|
// #Dqn_* Dqn_QuickSort
|
||||||
|
|
||||||
// #XPlatform (Win32 & Unix)
|
// #XPlatform (Win32 & Unix)
|
||||||
// #DqnFile File I/O (Read, Write, Delete)
|
// #DqnFile File I/O (Read, Write, Delete)
|
||||||
@ -61,8 +62,14 @@
|
|||||||
// #DqnSprintf Cross-platform Sprintf Implementation (Public Domain lib stb_sprintf)
|
// #DqnSprintf Cross-platform Sprintf Implementation (Public Domain lib stb_sprintf)
|
||||||
|
|
||||||
// TODO
|
// TODO
|
||||||
|
// - DqnMemStack
|
||||||
|
// - Allow 0 size memblock stack initialisation/block-less stack for situations where you don't
|
||||||
|
// care about specifying a size upfront
|
||||||
|
//
|
||||||
// - Win32
|
// - Win32
|
||||||
// - Get rid of reliance on MAX_PATH
|
// - Get rid of reliance on MAX_PATH
|
||||||
|
//
|
||||||
|
// - Make lib compile and run on Linux with GCC using -03
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
// Preprocessor Checks
|
// Preprocessor Checks
|
||||||
@ -972,6 +979,90 @@ DQN_FILE_SCOPE u32 DqnRnd_PCGNext (DqnRandPCGState *pcg);
|
|||||||
DQN_FILE_SCOPE f32 DqnRnd_PCGNextf(DqnRandPCGState *pcg);
|
DQN_FILE_SCOPE f32 DqnRnd_PCGNextf(DqnRandPCGState *pcg);
|
||||||
// return: A random integer N between [min, max]
|
// return: A random integer N between [min, max]
|
||||||
DQN_FILE_SCOPE i32 DqnRnd_PCGRange(DqnRandPCGState *pcg, i32 min, i32 max);
|
DQN_FILE_SCOPE i32 DqnRnd_PCGRange(DqnRandPCGState *pcg, i32 min, i32 max);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// #Dqn_* Public API
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
typedef bool Dqn_QuickSortLessThanCallback(const void *const val1, const void *const val2);
|
||||||
|
typedef void Dqn_QuickSortSwapCallback (void *const val1, void *const val2);
|
||||||
|
DQN_FILE_SCOPE void Dqn_QuickSortC(void *const array, const u32 itemSize, const u32 size,
|
||||||
|
Dqn_QuickSortLessThanCallback *const IsLessThan,
|
||||||
|
Dqn_QuickSortSwapCallback *const Swap);
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
DQN_FILE_SCOPE void Dqn_QuickSort(T *const array, const u32 size,
|
||||||
|
Dqn_QuickSortLessThanCallback *const IsLessThan)
|
||||||
|
{
|
||||||
|
if (!array || size == 0 || size == 1 || !IsLessThan) return;
|
||||||
|
|
||||||
|
// Insertion Sort, under 24->32 is an optimal amount
|
||||||
|
const u32 QUICK_SORT_THRESHOLD = 24;
|
||||||
|
if (size < QUICK_SORT_THRESHOLD)
|
||||||
|
{
|
||||||
|
u32 itemToInsertIndex = 1;
|
||||||
|
while (itemToInsertIndex < size)
|
||||||
|
{
|
||||||
|
for (u32 checkIndex = 0; checkIndex < itemToInsertIndex; checkIndex++)
|
||||||
|
{
|
||||||
|
if (!IsLessThan(&array[checkIndex], &array[itemToInsertIndex]))
|
||||||
|
{
|
||||||
|
T itemToInsert = array[itemToInsertIndex];
|
||||||
|
for (u32 i = itemToInsertIndex; i > checkIndex; i--)
|
||||||
|
array[i] = array[i - 1];
|
||||||
|
|
||||||
|
array[checkIndex] = itemToInsert;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
itemToInsertIndex++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
DqnRandPCGState state = {};
|
||||||
|
DqnRnd_PCGInit(&state);
|
||||||
|
|
||||||
|
u32 pivotIndex = DqnRnd_PCGRange(&state, 0, size - 1);
|
||||||
|
u32 partitionIndex = 0;
|
||||||
|
u32 startIndex = 0;
|
||||||
|
|
||||||
|
// Swap pivot with last index, so pivot is always at the end of the array.
|
||||||
|
// This makes logic much simpler.
|
||||||
|
{
|
||||||
|
u32 lastIndex = size - 1;
|
||||||
|
DQN_SWAP(T, array[lastIndex], array[pivotIndex]);
|
||||||
|
pivotIndex = lastIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 4^, 8, 7, 5, 2, 3, 6
|
||||||
|
if (IsLessThan(&array[startIndex], &array[pivotIndex])) partitionIndex++;
|
||||||
|
startIndex++;
|
||||||
|
|
||||||
|
// 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 (u32 checkIndex = startIndex; checkIndex < size; checkIndex++)
|
||||||
|
{
|
||||||
|
if (IsLessThan(&array[checkIndex], &array[pivotIndex]))
|
||||||
|
{
|
||||||
|
DQN_SWAP(T, array[partitionIndex], array[checkIndex]);
|
||||||
|
partitionIndex++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Move pivot to right of partition
|
||||||
|
// 4, 5, 2, 3, |6, 8, ^7*
|
||||||
|
DQN_SWAP(T, array[partitionIndex], array[pivotIndex]);
|
||||||
|
Dqn_QuickSort(array, partitionIndex, IsLessThan);
|
||||||
|
|
||||||
|
// Skip the value at partion index since that is guaranteed to be sorted.
|
||||||
|
// 4, 5, 2, 3, (x), 8, 7
|
||||||
|
u32 oneAfterPartitionIndex = partitionIndex + 1;
|
||||||
|
Dqn_QuickSort(array + oneAfterPartitionIndex, (size - oneAfterPartitionIndex), IsLessThan);
|
||||||
|
}
|
||||||
|
|
||||||
#endif /* DQN_H */
|
#endif /* DQN_H */
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
@ -1902,6 +1993,7 @@ DqnMemStackInternal_AllocateBlock(u32 byteAlign, size_t size, const bool zeroCle
|
|||||||
result->memory = (u8 *)DQN_ALIGN_POW_N((u8 *)result + sizeof(*result), byteAlign);
|
result->memory = (u8 *)DQN_ALIGN_POW_N((u8 *)result + sizeof(*result), byteAlign);
|
||||||
result->size = alignedSize;
|
result->size = alignedSize;
|
||||||
result->used = 0;
|
result->used = 0;
|
||||||
|
result->prevBlock = NULL;
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1966,6 +2058,8 @@ DQN_FILE_SCOPE bool DqnMemStack_InitWithFixedMem(DqnMemStack *const stack, u8 *c
|
|||||||
const u32 DEFAULT_ALIGNMENT = 4;
|
const u32 DEFAULT_ALIGNMENT = 4;
|
||||||
stack->tempRegionCount = 0;
|
stack->tempRegionCount = 0;
|
||||||
stack->byteAlign = (byteAlign == 0) ? DEFAULT_ALIGNMENT : byteAlign;
|
stack->byteAlign = (byteAlign == 0) ? DEFAULT_ALIGNMENT : byteAlign;
|
||||||
|
|
||||||
|
DQN_ASSERT(!stack->block->prevBlock);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1976,6 +2070,7 @@ DQN_FILE_SCOPE bool DqnMemStack_InitWithFixedSize(DqnMemStack *const stack, size
|
|||||||
if (result)
|
if (result)
|
||||||
{
|
{
|
||||||
stack->flags |= DqnMemStackFlag_IsNotExpandable;
|
stack->flags |= DqnMemStackFlag_IsNotExpandable;
|
||||||
|
DQN_ASSERT(!stack->block->prevBlock);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1996,6 +2091,7 @@ DQN_FILE_SCOPE bool DqnMemStack_Init(DqnMemStack *const stack, size_t size, cons
|
|||||||
stack->tempRegionCount = 0;
|
stack->tempRegionCount = 0;
|
||||||
stack->byteAlign = byteAlign;
|
stack->byteAlign = byteAlign;
|
||||||
stack->flags = 0;
|
stack->flags = 0;
|
||||||
|
DQN_ASSERT(!stack->block->prevBlock);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2067,6 +2163,10 @@ DQN_FILE_SCOPE bool DqnMemStack_Pop(DqnMemStack *const stack, void *ptr, size_t
|
|||||||
if (DQN_ASSERT_MSG(calcSize == sizeAligned, "'ptr' was not the last item allocated to memStack"))
|
if (DQN_ASSERT_MSG(calcSize == sizeAligned, "'ptr' was not the last item allocated to memStack"))
|
||||||
{
|
{
|
||||||
stack->block->used -= sizeAligned;
|
stack->block->used -= sizeAligned;
|
||||||
|
if (stack->block->used == 0 && stack->block->prevBlock)
|
||||||
|
{
|
||||||
|
return DQN_ASSERT(DqnMemStack_FreeLastBlock(stack));
|
||||||
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -3927,6 +4027,65 @@ DQN_FILE_SCOPE i32 DqnRnd_PCGRange(DqnRandPCGState *pcg, i32 min, i32 max)
|
|||||||
return min + value;
|
return min + value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// #Dqn_* Implementation
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
FILE_SCOPE void *DqnInternal_QuickSortGetArrayItemPtr(void *const array, const u32 index,
|
||||||
|
const u32 size)
|
||||||
|
{
|
||||||
|
u8 *byteArray = (u8 *)array;
|
||||||
|
void *result = (void *)(byteArray + (index * size));
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
DQN_FILE_SCOPE void Dqn_QuickSortC(void *const array, const u32 itemSize, const u32 size,
|
||||||
|
Dqn_QuickSortLessThanCallback *const IsLessThan,
|
||||||
|
Dqn_QuickSortSwapCallback *const Swap)
|
||||||
|
{
|
||||||
|
// NOTE: See <template> version for better implementation comments since here we need to use
|
||||||
|
// void * for generics in C making it harder in general to comprehend.
|
||||||
|
if (!array || size == 0 || size == 1) return;
|
||||||
|
|
||||||
|
DqnRandPCGState state = {};
|
||||||
|
DqnRnd_PCGInit(&state);
|
||||||
|
|
||||||
|
u32 pivotIndex = DqnRnd_PCGRange(&state, 0, size - 1);
|
||||||
|
u32 partitionIndex = 0;
|
||||||
|
u32 startIndex = 0;
|
||||||
|
|
||||||
|
{
|
||||||
|
void *lastItemPtr = DqnInternal_QuickSortGetArrayItemPtr(array, size - 1, itemSize);
|
||||||
|
void *pivotItemPtr = DqnInternal_QuickSortGetArrayItemPtr(array, pivotIndex, itemSize);
|
||||||
|
Swap(lastItemPtr, pivotItemPtr);
|
||||||
|
pivotIndex = size - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void *startItemPtr = DqnInternal_QuickSortGetArrayItemPtr(array, startIndex, itemSize);
|
||||||
|
void *pivotItemPtr = DqnInternal_QuickSortGetArrayItemPtr(array, pivotIndex, itemSize);
|
||||||
|
if (IsLessThan(startItemPtr, pivotItemPtr)) partitionIndex++;
|
||||||
|
startIndex++;
|
||||||
|
|
||||||
|
for (u32 checkIndex = startIndex; checkIndex < size; checkIndex++)
|
||||||
|
{
|
||||||
|
void *checkItemPtr = DqnInternal_QuickSortGetArrayItemPtr(array, checkIndex, itemSize);
|
||||||
|
if (IsLessThan(checkItemPtr, pivotItemPtr))
|
||||||
|
{
|
||||||
|
void *partitionItemPtr = DqnInternal_QuickSortGetArrayItemPtr(array, partitionIndex, itemSize);
|
||||||
|
Swap(partitionItemPtr, checkItemPtr);
|
||||||
|
partitionIndex++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void *partitionItemPtr = DqnInternal_QuickSortGetArrayItemPtr(array, partitionIndex, itemSize);
|
||||||
|
Swap(partitionItemPtr, pivotItemPtr);
|
||||||
|
|
||||||
|
Dqn_QuickSortC(array, itemSize, partitionIndex, IsLessThan, Swap);
|
||||||
|
|
||||||
|
u32 oneAfterPartitionIndex = partitionIndex + 1;
|
||||||
|
void *oneAfterPartionIndexPtr = DqnInternal_QuickSortGetArrayItemPtr(array, oneAfterPartitionIndex, itemSize);
|
||||||
|
Dqn_QuickSortC(oneAfterPartionIndexPtr, itemSize, (size - oneAfterPartitionIndex), IsLessThan, Swap);
|
||||||
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
// #External Code
|
// #External Code
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
@ -5639,11 +5798,24 @@ void DqnIni_PropertyValueSet(DqnIni *ini, int section, int property,
|
|||||||
#include <unistd.h> // unlink()
|
#include <unistd.h> // unlink()
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef DQN_CPP_MODE
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
// XPlatform > #DqnFile CPP Implementation
|
// XPlatform > #DqnFile CPP Implementation
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
DqnFile::DqnFile (const bool raiiCleanup) { this->raiiCleanup = raiiCleanup; }
|
// NOTE(doyle): This is necessary since we supply a default constructor, some uninitialised values
|
||||||
DqnFile::~DqnFile() { if (this->raiiCleanup) this->Close(); }
|
// were put in when using DqnFile file = {};
|
||||||
|
DqnFile::DqnFile(const bool raiiCleanup)
|
||||||
|
: permissionFlags(0)
|
||||||
|
, handle(0)
|
||||||
|
, size(0)
|
||||||
|
, raiiCleanup(raiiCleanup)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
DqnFile::~DqnFile()
|
||||||
|
{
|
||||||
|
if (this->raiiCleanup) this->Close();
|
||||||
|
}
|
||||||
|
|
||||||
bool DqnFile::Open(const char *const path, const u32 permissionFlags_,
|
bool DqnFile::Open(const char *const path, const u32 permissionFlags_,
|
||||||
const enum DqnFileAction action)
|
const enum DqnFileAction action)
|
||||||
@ -5666,8 +5838,8 @@ size_t DqnFile::Read(u8 *const buffer, const size_t numBytesToRead)
|
|||||||
{
|
{
|
||||||
return DqnFile_Read(this, buffer, numBytesToRead);
|
return DqnFile_Read(this, buffer, numBytesToRead);
|
||||||
}
|
}
|
||||||
|
|
||||||
void DqnFile::Close() { DqnFile_Close(this); }
|
void DqnFile::Close() { DqnFile_Close(this); }
|
||||||
|
#endif
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
// XPlatform > #DqnFileInternal Implementation
|
// XPlatform > #DqnFileInternal Implementation
|
||||||
@ -6167,7 +6339,7 @@ DQN_FILE_SCOPE bool DqnFile_GetFileSizeW(const wchar_t *const path, size_t *cons
|
|||||||
LARGE_INTEGER largeInt = {};
|
LARGE_INTEGER largeInt = {};
|
||||||
largeInt.HighPart = attribData.nFileSizeHigh;
|
largeInt.HighPart = attribData.nFileSizeHigh;
|
||||||
largeInt.LowPart = attribData.nFileSizeLow;
|
largeInt.LowPart = attribData.nFileSizeLow;
|
||||||
*size = largeInt.QuadPart;
|
*size = (size_t)largeInt.QuadPart;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -6308,8 +6480,7 @@ DQN_FILE_SCOPE f64 DqnTimer_NowInMs()
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
printf("tv_nsec: %ld\n", timeSpec.tv_nsec);
|
result = (f64)((timeSpec.tv_sec * 1000.0f) + (timeSpec.tv_nsec / 1000000.0f));
|
||||||
result = ((f64)timeSpec.tv_sec * 1000.0f) + ((f64)timeSpec.tv_nsec / 100000.0f);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#else
|
#else
|
||||||
|
@ -17,6 +17,18 @@
|
|||||||
|
|
||||||
#include <limits.h>
|
#include <limits.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|
||||||
|
FILE_SCOPE void PrintHeader(const char *const header)
|
||||||
|
{
|
||||||
|
DQN_ASSERT_HARD(header);
|
||||||
|
|
||||||
|
char buf[1024] = {};
|
||||||
|
DQN_ASSERT(Dqn_sprintf(buf, "// %s", header) < (i32)DQN_ARRAY_COUNT(buf));
|
||||||
|
printf("//////////////////////////////////////////////////////////////////\n");
|
||||||
|
printf("%s\n", buf);
|
||||||
|
printf("//////////////////////////////////////////////////////////////////\n");
|
||||||
|
}
|
||||||
|
|
||||||
void HandmadeMathVerifyMat4(DqnMat4 dqnMat, hmm_mat4 hmmMat)
|
void HandmadeMathVerifyMat4(DqnMat4 dqnMat, hmm_mat4 hmmMat)
|
||||||
{
|
{
|
||||||
f32 *hmmMatf = (f32 *)&hmmMat;
|
f32 *hmmMatf = (f32 *)&hmmMat;
|
||||||
@ -40,6 +52,7 @@ void HandmadeMathVerifyMat4(DqnMat4 dqnMat, hmm_mat4 hmmMat)
|
|||||||
|
|
||||||
void HandmadeMathTest()
|
void HandmadeMathTest()
|
||||||
{
|
{
|
||||||
|
PrintHeader("DqnMath vs HandmadeMath Test");
|
||||||
// Test Perspective/Projection matrix values
|
// Test Perspective/Projection matrix values
|
||||||
if (1)
|
if (1)
|
||||||
{
|
{
|
||||||
@ -114,6 +127,7 @@ void HandmadeMathTest()
|
|||||||
|
|
||||||
void StringsTest()
|
void StringsTest()
|
||||||
{
|
{
|
||||||
|
PrintHeader("Strings Test");
|
||||||
// Char Checks
|
// Char Checks
|
||||||
if (1)
|
if (1)
|
||||||
{
|
{
|
||||||
@ -525,7 +539,7 @@ void StringsTest()
|
|||||||
|
|
||||||
void OtherTest()
|
void OtherTest()
|
||||||
{
|
{
|
||||||
|
PrintHeader("Other Test");
|
||||||
if (1)
|
if (1)
|
||||||
{
|
{
|
||||||
#if defined(DQN_UNIX_PLATFORM)
|
#if defined(DQN_UNIX_PLATFORM)
|
||||||
@ -552,7 +566,7 @@ void OtherTest()
|
|||||||
|
|
||||||
void RandomTest()
|
void RandomTest()
|
||||||
{
|
{
|
||||||
|
PrintHeader("Random Number Generator Test");
|
||||||
DqnRandPCGState pcg;
|
DqnRandPCGState pcg;
|
||||||
DqnRnd_PCGInit(&pcg);
|
DqnRnd_PCGInit(&pcg);
|
||||||
for (i32 i = 0; i < 10; i++)
|
for (i32 i = 0; i < 10; i++)
|
||||||
@ -572,6 +586,7 @@ void RandomTest()
|
|||||||
|
|
||||||
void MathTest()
|
void MathTest()
|
||||||
{
|
{
|
||||||
|
PrintHeader("Math Test");
|
||||||
if (1)
|
if (1)
|
||||||
{ // Lerp
|
{ // Lerp
|
||||||
if (1)
|
if (1)
|
||||||
@ -604,6 +619,7 @@ void MathTest()
|
|||||||
|
|
||||||
void VecTest()
|
void VecTest()
|
||||||
{
|
{
|
||||||
|
PrintHeader("Math Vector Test");
|
||||||
if (1)
|
if (1)
|
||||||
{ // V2
|
{ // V2
|
||||||
|
|
||||||
@ -964,6 +980,7 @@ void VecTest()
|
|||||||
|
|
||||||
void ArrayTestMemAPIInternal(DqnArray<DqnV2> *array, DqnMemAPI memAPI)
|
void ArrayTestMemAPIInternal(DqnArray<DqnV2> *array, DqnMemAPI memAPI)
|
||||||
{
|
{
|
||||||
|
PrintHeader("Array with Default Mem API Test");
|
||||||
if (1)
|
if (1)
|
||||||
{
|
{
|
||||||
DQN_ASSERT(DqnArray_Init(array, 1, memAPI));
|
DQN_ASSERT(DqnArray_Init(array, 1, memAPI));
|
||||||
@ -1139,6 +1156,7 @@ void ArrayTestMemAPIInternal(DqnArray<DqnV2> *array, DqnMemAPI memAPI)
|
|||||||
|
|
||||||
void ArrayTest()
|
void ArrayTest()
|
||||||
{
|
{
|
||||||
|
PrintHeader("Array Test");
|
||||||
DqnArray<DqnV2> array = {};
|
DqnArray<DqnV2> array = {};
|
||||||
ArrayTestMemAPIInternal(&array, DqnMemAPI_DefaultUseCalloc());
|
ArrayTestMemAPIInternal(&array, DqnMemAPI_DefaultUseCalloc());
|
||||||
printf("ArrayTest(): Completed successfully\n");
|
printf("ArrayTest(): Completed successfully\n");
|
||||||
@ -1146,6 +1164,7 @@ void ArrayTest()
|
|||||||
|
|
||||||
void MemStackTest()
|
void MemStackTest()
|
||||||
{
|
{
|
||||||
|
PrintHeader("MemStack Test");
|
||||||
// Test over allocation, alignments, temp regions
|
// Test over allocation, alignments, temp regions
|
||||||
if (1)
|
if (1)
|
||||||
{
|
{
|
||||||
@ -1250,6 +1269,7 @@ void MemStackTest()
|
|||||||
DQN_ASSERT(stack.block->size == allocSize);
|
DQN_ASSERT(stack.block->size == allocSize);
|
||||||
DQN_ASSERT(stack.block->used == sizeA);
|
DQN_ASSERT(stack.block->used == sizeA);
|
||||||
DQN_ASSERT(stack.byteAlign == ALIGNMENT);
|
DQN_ASSERT(stack.byteAlign == ALIGNMENT);
|
||||||
|
DQN_ASSERT(!stack.block->prevBlock);
|
||||||
|
|
||||||
// Free once more to release stack A memory
|
// Free once more to release stack A memory
|
||||||
DqnMemStack_FreeLastBlock(&stack);
|
DqnMemStack_FreeLastBlock(&stack);
|
||||||
@ -1532,6 +1552,7 @@ void MemStackTest()
|
|||||||
#ifdef DQN_XPLATFORM_LAYER
|
#ifdef DQN_XPLATFORM_LAYER
|
||||||
void FileTest()
|
void FileTest()
|
||||||
{
|
{
|
||||||
|
PrintHeader("File Test");
|
||||||
// File i/o
|
// File i/o
|
||||||
if (1)
|
if (1)
|
||||||
{
|
{
|
||||||
@ -1740,10 +1761,13 @@ const u32 QUEUE_SIZE = 256;
|
|||||||
FILE_SCOPE void JobQueueDebugCallbackIncrementCounter(DqnJobQueue *const queue,
|
FILE_SCOPE void JobQueueDebugCallbackIncrementCounter(DqnJobQueue *const queue,
|
||||||
void *const userData)
|
void *const userData)
|
||||||
{
|
{
|
||||||
|
(void)userData;
|
||||||
DQN_ASSERT(queue->size == QUEUE_SIZE);
|
DQN_ASSERT(queue->size == QUEUE_SIZE);
|
||||||
{
|
{
|
||||||
DqnLockGuard guard = globalJobQueueLock.LockGuard();
|
DqnLockGuard guard = globalJobQueueLock.LockGuard();
|
||||||
globalDebugCounter++;
|
globalDebugCounter++;
|
||||||
|
|
||||||
|
#if 0
|
||||||
u32 number = globalDebugCounter;
|
u32 number = globalDebugCounter;
|
||||||
#if defined(DQN_WIN32_IMPLEMENTATION)
|
#if defined(DQN_WIN32_IMPLEMENTATION)
|
||||||
printf("JobQueueDebugCallbackIncrementCounter(): Thread %d: Incrementing Number: %d\n",
|
printf("JobQueueDebugCallbackIncrementCounter(): Thread %d: Incrementing Number: %d\n",
|
||||||
@ -1751,6 +1775,7 @@ FILE_SCOPE void JobQueueDebugCallbackIncrementCounter(DqnJobQueue *const queue,
|
|||||||
#elif defined(DQN_UNIX_IMPLEMENTATION)
|
#elif defined(DQN_UNIX_IMPLEMENTATION)
|
||||||
printf("JobQueueDebugCallbackIncrementCounter(): Thread unix: Incrementing Number: %d\n",
|
printf("JobQueueDebugCallbackIncrementCounter(): Thread unix: Incrementing Number: %d\n",
|
||||||
number);
|
number);
|
||||||
|
#endif
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1758,6 +1783,7 @@ FILE_SCOPE void JobQueueDebugCallbackIncrementCounter(DqnJobQueue *const queue,
|
|||||||
|
|
||||||
FILE_SCOPE void JobQueueTest()
|
FILE_SCOPE void JobQueueTest()
|
||||||
{
|
{
|
||||||
|
PrintHeader("Job Queue Multithreading Test");
|
||||||
globalDebugCounter = 0;
|
globalDebugCounter = 0;
|
||||||
|
|
||||||
DqnMemStack memStack = {};
|
DqnMemStack memStack = {};
|
||||||
@ -1788,11 +1814,133 @@ FILE_SCOPE void JobQueueTest()
|
|||||||
|
|
||||||
DqnJobQueue_BlockAndCompleteAllJobs(&jobQueue);
|
DqnJobQueue_BlockAndCompleteAllJobs(&jobQueue);
|
||||||
|
|
||||||
printf("\nJobQueueTest(): Final incremented value: %d\n", globalDebugCounter);
|
printf("JobQueueTest(): Final incremented value: %d\n", globalDebugCounter);
|
||||||
DQN_ASSERT(globalDebugCounter == WORK_ENTRIES);
|
DQN_ASSERT(globalDebugCounter == WORK_ENTRIES);
|
||||||
DqnLock_Delete(&globalJobQueueLock);
|
DqnLock_Delete(&globalJobQueueLock);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
FILE_SCOPE inline bool Dqn_QuickSortLessThanU32(const void *const val1, const void *const val2)
|
||||||
|
{
|
||||||
|
const u32 *const a = (u32 *)val1;
|
||||||
|
const u32 *const b = (u32 *)val2;
|
||||||
|
return (*a) < (*b);
|
||||||
|
}
|
||||||
|
|
||||||
|
FILE_SCOPE inline void Dqn_QuickSortSwapU32(void *const val1, void *const val2)
|
||||||
|
{
|
||||||
|
u32 *a = (u32 *)val1;
|
||||||
|
u32 *b = (u32 *)val2;
|
||||||
|
DQN_SWAP(u32, *a, *b);
|
||||||
|
}
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
void SortTest()
|
||||||
|
{
|
||||||
|
{
|
||||||
|
u32 array[] = {4, 8, 7, 5, 2, 3, 6};
|
||||||
|
Dqn_QuickSortC(array, sizeof(array[0]), DQN_ARRAY_COUNT(array), Dqn_QuickSortLessThanU32,
|
||||||
|
Dqn_QuickSortSwapU32);
|
||||||
|
|
||||||
|
for (u32 i = 0; i < DQN_ARRAY_COUNT(array) - 1; i++)
|
||||||
|
{
|
||||||
|
DQN_ASSERT(array[i] <= array[i + 1]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
PrintHeader("DqnSort vs std::Sort");
|
||||||
|
DqnRandPCGState state = {};
|
||||||
|
DqnRnd_PCGInit(&state);
|
||||||
|
if (1)
|
||||||
|
{
|
||||||
|
DqnMemStack stack = {};
|
||||||
|
DQN_ASSERT(stack.Init(DQN_KILOBYTE(1), false));
|
||||||
|
|
||||||
|
// Create array of ints
|
||||||
|
u32 numInts = 1000000;
|
||||||
|
u32 sizeInBytes = sizeof(u32) * numInts;
|
||||||
|
u32 *dqnCArray = (u32 *)stack.Push(sizeInBytes);
|
||||||
|
u32 *dqnCPPArray = (u32 *)stack.Push(sizeInBytes);
|
||||||
|
u32 *stdArray = (u32 *)stack.Push(sizeInBytes);
|
||||||
|
DQN_ASSERT(dqnCArray && dqnCPPArray && stdArray);
|
||||||
|
|
||||||
|
f64 dqnCTimings[10] = {};
|
||||||
|
f64 dqnCPPTimings[DQN_ARRAY_COUNT(dqnCTimings)] = {};
|
||||||
|
f64 stdTimings[DQN_ARRAY_COUNT(dqnCTimings)] = {};
|
||||||
|
|
||||||
|
f64 dqnCAverage = 0;
|
||||||
|
f64 dqnCPPAverage = 0;
|
||||||
|
f64 stdAverage = 0;
|
||||||
|
|
||||||
|
for (u32 timingsIndex = 0; timingsIndex < DQN_ARRAY_COUNT(dqnCTimings); timingsIndex++)
|
||||||
|
{
|
||||||
|
// Populate with random numbers
|
||||||
|
for (u32 i = 0; i < numInts; i++)
|
||||||
|
{
|
||||||
|
dqnCArray[i] = DqnRnd_PCGNext(&state);
|
||||||
|
dqnCPPArray[i] = dqnCArray[i];
|
||||||
|
stdArray[i] = dqnCPPArray[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Time Dqn_QuickSortC
|
||||||
|
{
|
||||||
|
f64 start = DqnTimer_NowInS();
|
||||||
|
Dqn_QuickSortC(dqnCArray, sizeof(dqnCArray[0]), numInts, Dqn_QuickSortLessThanU32,
|
||||||
|
Dqn_QuickSortSwapU32);
|
||||||
|
f64 duration = DqnTimer_NowInS() - start;
|
||||||
|
|
||||||
|
dqnCTimings[timingsIndex] = duration;
|
||||||
|
dqnCAverage += duration;
|
||||||
|
|
||||||
|
printf("[%02d]Dqn_QuickSortC: %f vs ", timingsIndex, dqnCTimings[timingsIndex]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Time Dqn_QuickSortC
|
||||||
|
{
|
||||||
|
f64 start = DqnTimer_NowInS();
|
||||||
|
Dqn_QuickSort(dqnCPPArray, numInts, Dqn_QuickSortLessThanU32);
|
||||||
|
f64 duration = DqnTimer_NowInS() - start;
|
||||||
|
|
||||||
|
dqnCPPTimings[timingsIndex] = duration;
|
||||||
|
dqnCPPAverage += duration;
|
||||||
|
printf("Dqn_QuickSort: %f vs ", dqnCPPTimings[timingsIndex]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Time std::sort
|
||||||
|
{
|
||||||
|
f64 start = DqnTimer_NowInS();
|
||||||
|
std::sort(stdArray, stdArray + numInts);
|
||||||
|
f64 duration = DqnTimer_NowInS() - start;
|
||||||
|
|
||||||
|
stdTimings[timingsIndex] = duration;
|
||||||
|
stdAverage += duration;
|
||||||
|
|
||||||
|
printf("std::sort: %f\n", stdTimings[timingsIndex]);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (u32 i = 0; i < numInts; i++)
|
||||||
|
{
|
||||||
|
DQN_ASSERT_MSG(dqnCArray[i] == stdArray[i], "DqnArray[%d]: %d, stdArray[%d]: %d", i,
|
||||||
|
dqnCArray[i], stdArray[i], i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Print averages
|
||||||
|
if (1)
|
||||||
|
{
|
||||||
|
dqnCAverage /= (f64)DQN_ARRAY_COUNT(dqnCTimings);
|
||||||
|
dqnCPPAverage /= (f64)DQN_ARRAY_COUNT(dqnCPPTimings);
|
||||||
|
stdAverage /= (f64)DQN_ARRAY_COUNT(stdTimings);
|
||||||
|
printf("\n- Average Timings\n");
|
||||||
|
printf(" Dqn_QuickSortC: %f vs Dqn_QuickSort: %f vs std::sort: %f\n\n", dqnCAverage,
|
||||||
|
dqnCPPAverage, stdAverage);
|
||||||
|
}
|
||||||
|
stack.Pop(stdArray, sizeInBytes);
|
||||||
|
stack.Pop(dqnCPPArray, sizeInBytes);
|
||||||
|
stack.Pop(dqnCArray, sizeInBytes);
|
||||||
|
stack.Free();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
int main(void)
|
int main(void)
|
||||||
{
|
{
|
||||||
StringsTest();
|
StringsTest();
|
||||||
@ -1802,6 +1950,7 @@ int main(void)
|
|||||||
VecTest();
|
VecTest();
|
||||||
ArrayTest();
|
ArrayTest();
|
||||||
MemStackTest();
|
MemStackTest();
|
||||||
|
SortTest();
|
||||||
|
|
||||||
#ifdef DQN_XPLATFORM_LAYER
|
#ifdef DQN_XPLATFORM_LAYER
|
||||||
FileTest();
|
FileTest();
|
||||||
|
Loading…
Reference in New Issue
Block a user