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…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user