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
|
||||
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 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 WX treat warnings as errors
|
||||
REM wd4100 ignore: unused argument parameters
|
||||
REM wd4201 ignore: nonstandard extension used: nameless struct/union
|
||||
REM wd4189 ignore: local variable is initialised but not referenced
|
||||
|
||||
set CompileFlags=-EHa- -GR- -Oi -MT -Z7 -W4 -WX -wd4100 -wd4201 -wd4189 -FC -Od
|
||||
set CompileFlags=-EHsc -GR- -Oi -MT -Z7 -W4 -WX -wd4201 -FC -O2
|
||||
|
||||
REM Include directories
|
||||
set IncludeFlags=
|
||||
@ -44,7 +41,7 @@ set LinkLibraries=user32.lib gdi32.lib msimg32.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
|
||||
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%
|
||||
|
189
dqn.h
189
dqn.h
@ -42,6 +42,7 @@
|
||||
// #DqnWChar WChar Operations (IsDigit(), IsAlpha() etc)
|
||||
// #DqnWStr WStr Operations (WStr_Len() etc)
|
||||
// #DqnRnd Random Number Generator (ints and floats)
|
||||
// #Dqn_* Dqn_QuickSort
|
||||
|
||||
// #XPlatform (Win32 & Unix)
|
||||
// #DqnFile File I/O (Read, Write, Delete)
|
||||
@ -61,8 +62,14 @@
|
||||
// #DqnSprintf Cross-platform Sprintf Implementation (Public Domain lib stb_sprintf)
|
||||
|
||||
// TODO
|
||||
// - DqnMemStack
|
||||
// - Allow 0 size memblock stack initialisation/block-less stack for situations where you don't
|
||||
// care about specifying a size upfront
|
||||
//
|
||||
// - Win32
|
||||
// - Get rid of reliance on MAX_PATH
|
||||
//
|
||||
// - Make lib compile and run on Linux with GCC using -03
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Preprocessor Checks
|
||||
@ -972,6 +979,90 @@ DQN_FILE_SCOPE u32 DqnRnd_PCGNext (DqnRandPCGState *pcg);
|
||||
DQN_FILE_SCOPE f32 DqnRnd_PCGNextf(DqnRandPCGState *pcg);
|
||||
// return: A random integer N between [min, 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 */
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
@ -1899,9 +1990,10 @@ DqnMemStackInternal_AllocateBlock(u32 byteAlign, size_t size, const bool zeroCle
|
||||
|
||||
if (!result) return NULL;
|
||||
|
||||
result->memory = (u8 *)DQN_ALIGN_POW_N((u8 *)result + sizeof(*result), byteAlign);
|
||||
result->size = alignedSize;
|
||||
result->used = 0;
|
||||
result->memory = (u8 *)DQN_ALIGN_POW_N((u8 *)result + sizeof(*result), byteAlign);
|
||||
result->size = alignedSize;
|
||||
result->used = 0;
|
||||
result->prevBlock = NULL;
|
||||
return result;
|
||||
}
|
||||
|
||||
@ -1966,6 +2058,8 @@ DQN_FILE_SCOPE bool DqnMemStack_InitWithFixedMem(DqnMemStack *const stack, u8 *c
|
||||
const u32 DEFAULT_ALIGNMENT = 4;
|
||||
stack->tempRegionCount = 0;
|
||||
stack->byteAlign = (byteAlign == 0) ? DEFAULT_ALIGNMENT : byteAlign;
|
||||
|
||||
DQN_ASSERT(!stack->block->prevBlock);
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -1976,6 +2070,7 @@ DQN_FILE_SCOPE bool DqnMemStack_InitWithFixedSize(DqnMemStack *const stack, size
|
||||
if (result)
|
||||
{
|
||||
stack->flags |= DqnMemStackFlag_IsNotExpandable;
|
||||
DQN_ASSERT(!stack->block->prevBlock);
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -1996,6 +2091,7 @@ DQN_FILE_SCOPE bool DqnMemStack_Init(DqnMemStack *const stack, size_t size, cons
|
||||
stack->tempRegionCount = 0;
|
||||
stack->byteAlign = byteAlign;
|
||||
stack->flags = 0;
|
||||
DQN_ASSERT(!stack->block->prevBlock);
|
||||
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"))
|
||||
{
|
||||
stack->block->used -= sizeAligned;
|
||||
if (stack->block->used == 0 && stack->block->prevBlock)
|
||||
{
|
||||
return DQN_ASSERT(DqnMemStack_FreeLastBlock(stack));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@ -3927,6 +4027,65 @@ DQN_FILE_SCOPE i32 DqnRnd_PCGRange(DqnRandPCGState *pcg, i32 min, i32 max)
|
||||
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
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
@ -5639,11 +5798,24 @@ void DqnIni_PropertyValueSet(DqnIni *ini, int section, int property,
|
||||
#include <unistd.h> // unlink()
|
||||
#endif
|
||||
|
||||
#ifdef DQN_CPP_MODE
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// XPlatform > #DqnFile CPP Implementation
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
DqnFile::DqnFile (const bool raiiCleanup) { this->raiiCleanup = raiiCleanup; }
|
||||
DqnFile::~DqnFile() { if (this->raiiCleanup) this->Close(); }
|
||||
// NOTE(doyle): This is necessary since we supply a default constructor, some uninitialised values
|
||||
// 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_,
|
||||
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);
|
||||
}
|
||||
|
||||
void DqnFile::Close() { DqnFile_Close(this); }
|
||||
#endif
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// XPlatform > #DqnFileInternal Implementation
|
||||
@ -6167,7 +6339,7 @@ DQN_FILE_SCOPE bool DqnFile_GetFileSizeW(const wchar_t *const path, size_t *cons
|
||||
LARGE_INTEGER largeInt = {};
|
||||
largeInt.HighPart = attribData.nFileSizeHigh;
|
||||
largeInt.LowPart = attribData.nFileSizeLow;
|
||||
*size = largeInt.QuadPart;
|
||||
*size = (size_t)largeInt.QuadPart;
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -6308,8 +6480,7 @@ DQN_FILE_SCOPE f64 DqnTimer_NowInMs()
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("tv_nsec: %ld\n", timeSpec.tv_nsec);
|
||||
result = ((f64)timeSpec.tv_sec * 1000.0f) + ((f64)timeSpec.tv_nsec / 100000.0f);
|
||||
result = (f64)((timeSpec.tv_sec * 1000.0f) + (timeSpec.tv_nsec / 1000000.0f));
|
||||
}
|
||||
|
||||
#else
|
||||
|
@ -17,6 +17,18 @@
|
||||
|
||||
#include <limits.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)
|
||||
{
|
||||
f32 *hmmMatf = (f32 *)&hmmMat;
|
||||
@ -40,6 +52,7 @@ void HandmadeMathVerifyMat4(DqnMat4 dqnMat, hmm_mat4 hmmMat)
|
||||
|
||||
void HandmadeMathTest()
|
||||
{
|
||||
PrintHeader("DqnMath vs HandmadeMath Test");
|
||||
// Test Perspective/Projection matrix values
|
||||
if (1)
|
||||
{
|
||||
@ -114,6 +127,7 @@ void HandmadeMathTest()
|
||||
|
||||
void StringsTest()
|
||||
{
|
||||
PrintHeader("Strings Test");
|
||||
// Char Checks
|
||||
if (1)
|
||||
{
|
||||
@ -525,7 +539,7 @@ void StringsTest()
|
||||
|
||||
void OtherTest()
|
||||
{
|
||||
|
||||
PrintHeader("Other Test");
|
||||
if (1)
|
||||
{
|
||||
#if defined(DQN_UNIX_PLATFORM)
|
||||
@ -552,7 +566,7 @@ void OtherTest()
|
||||
|
||||
void RandomTest()
|
||||
{
|
||||
|
||||
PrintHeader("Random Number Generator Test");
|
||||
DqnRandPCGState pcg;
|
||||
DqnRnd_PCGInit(&pcg);
|
||||
for (i32 i = 0; i < 10; i++)
|
||||
@ -572,6 +586,7 @@ void RandomTest()
|
||||
|
||||
void MathTest()
|
||||
{
|
||||
PrintHeader("Math Test");
|
||||
if (1)
|
||||
{ // Lerp
|
||||
if (1)
|
||||
@ -604,6 +619,7 @@ void MathTest()
|
||||
|
||||
void VecTest()
|
||||
{
|
||||
PrintHeader("Math Vector Test");
|
||||
if (1)
|
||||
{ // V2
|
||||
|
||||
@ -964,6 +980,7 @@ void VecTest()
|
||||
|
||||
void ArrayTestMemAPIInternal(DqnArray<DqnV2> *array, DqnMemAPI memAPI)
|
||||
{
|
||||
PrintHeader("Array with Default Mem API Test");
|
||||
if (1)
|
||||
{
|
||||
DQN_ASSERT(DqnArray_Init(array, 1, memAPI));
|
||||
@ -1139,6 +1156,7 @@ void ArrayTestMemAPIInternal(DqnArray<DqnV2> *array, DqnMemAPI memAPI)
|
||||
|
||||
void ArrayTest()
|
||||
{
|
||||
PrintHeader("Array Test");
|
||||
DqnArray<DqnV2> array = {};
|
||||
ArrayTestMemAPIInternal(&array, DqnMemAPI_DefaultUseCalloc());
|
||||
printf("ArrayTest(): Completed successfully\n");
|
||||
@ -1146,6 +1164,7 @@ void ArrayTest()
|
||||
|
||||
void MemStackTest()
|
||||
{
|
||||
PrintHeader("MemStack Test");
|
||||
// Test over allocation, alignments, temp regions
|
||||
if (1)
|
||||
{
|
||||
@ -1250,6 +1269,7 @@ void MemStackTest()
|
||||
DQN_ASSERT(stack.block->size == allocSize);
|
||||
DQN_ASSERT(stack.block->used == sizeA);
|
||||
DQN_ASSERT(stack.byteAlign == ALIGNMENT);
|
||||
DQN_ASSERT(!stack.block->prevBlock);
|
||||
|
||||
// Free once more to release stack A memory
|
||||
DqnMemStack_FreeLastBlock(&stack);
|
||||
@ -1532,6 +1552,7 @@ void MemStackTest()
|
||||
#ifdef DQN_XPLATFORM_LAYER
|
||||
void FileTest()
|
||||
{
|
||||
PrintHeader("File Test");
|
||||
// File i/o
|
||||
if (1)
|
||||
{
|
||||
@ -1740,10 +1761,13 @@ const u32 QUEUE_SIZE = 256;
|
||||
FILE_SCOPE void JobQueueDebugCallbackIncrementCounter(DqnJobQueue *const queue,
|
||||
void *const userData)
|
||||
{
|
||||
(void)userData;
|
||||
DQN_ASSERT(queue->size == QUEUE_SIZE);
|
||||
{
|
||||
DqnLockGuard guard = globalJobQueueLock.LockGuard();
|
||||
globalDebugCounter++;
|
||||
|
||||
#if 0
|
||||
u32 number = globalDebugCounter;
|
||||
#if defined(DQN_WIN32_IMPLEMENTATION)
|
||||
printf("JobQueueDebugCallbackIncrementCounter(): Thread %d: Incrementing Number: %d\n",
|
||||
@ -1751,6 +1775,7 @@ FILE_SCOPE void JobQueueDebugCallbackIncrementCounter(DqnJobQueue *const queue,
|
||||
#elif defined(DQN_UNIX_IMPLEMENTATION)
|
||||
printf("JobQueueDebugCallbackIncrementCounter(): Thread unix: Incrementing Number: %d\n",
|
||||
number);
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
@ -1758,6 +1783,7 @@ FILE_SCOPE void JobQueueDebugCallbackIncrementCounter(DqnJobQueue *const queue,
|
||||
|
||||
FILE_SCOPE void JobQueueTest()
|
||||
{
|
||||
PrintHeader("Job Queue Multithreading Test");
|
||||
globalDebugCounter = 0;
|
||||
|
||||
DqnMemStack memStack = {};
|
||||
@ -1788,11 +1814,133 @@ FILE_SCOPE void JobQueueTest()
|
||||
|
||||
DqnJobQueue_BlockAndCompleteAllJobs(&jobQueue);
|
||||
|
||||
printf("\nJobQueueTest(): Final incremented value: %d\n", globalDebugCounter);
|
||||
printf("JobQueueTest(): Final incremented value: %d\n", globalDebugCounter);
|
||||
DQN_ASSERT(globalDebugCounter == WORK_ENTRIES);
|
||||
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)
|
||||
{
|
||||
StringsTest();
|
||||
@ -1802,6 +1950,7 @@ int main(void)
|
||||
VecTest();
|
||||
ArrayTest();
|
||||
MemStackTest();
|
||||
SortTest();
|
||||
|
||||
#ifdef DQN_XPLATFORM_LAYER
|
||||
FileTest();
|
||||
|
Loading…
Reference in New Issue
Block a user