List removal for arrays, template specialize sort

This commit is contained in:
Doyle Thai 2017-11-11 20:08:43 +11:00
parent 88bac561ec
commit 25d6308a5f
2 changed files with 589 additions and 204 deletions

243
dqn.h
View File

@ -474,6 +474,9 @@ struct DqnString
////////////////////////////////////////////////////////////////////////////////
// #DqnArray Public API - CPP Dynamic Array with Templates
////////////////////////////////////////////////////////////////////////////////
#define DQN_FOR_ARRAY(indexName, arrayPtr) \
for (auto indexName = 0; indexName < (arrayPtr)->count; indexName++)
template <typename T>
struct DqnArray
{
@ -497,17 +500,21 @@ struct DqnArray
void Clear (const bool clearMemory = false);
bool Remove (const i64 index);
bool RemoveStable(const i64 index);
void RemoveStable(i64 *indexList, const i64 numIndexes);
};
template <typename T>
bool DqnArray<T>::Init(const i64 size, const DqnMemAPI api = DqnMemAPI_HeapAllocator())
{
if (this->data) this->Free();
DQN_ASSERT_HARD(size >= 0);
if (size > 0)
{
i64 allocateSize = size * sizeof(T);
DqnMemAPI::Request info = DqnMemAPI::RequestAlloc(api, allocateSize);
DqnMemAPI::Request info = DqnMemAPI::RequestAlloc(api, allocateSize, /*zeroClear*/ false);
this->data = (T *)api.callback(info);
if (!this->data) return false;
}
this->memAPI = api;
this->count = 0;
@ -578,7 +585,7 @@ template <typename T>
T *DqnArray<T>::Push(const T *item, const i64 num)
{
i64 newSize = this->count + num;
if (newSize > this->max)
if (!this->data || newSize > this->max)
{
if (!this->Grow()) return nullptr;
}
@ -670,6 +677,76 @@ bool DqnArray<T>::RemoveStable(const i64 index)
return true;
}
template <typename T>
void DqnArray<T>::RemoveStable(i64 *indexList, const i64 numIndexes)
{
if (numIndexes == 0 || !indexList) return;
// NOTE: Sort the index list and ensure we only remove indexes up to the size of our array
Dqn_QuickSort<i64>(indexList, numIndexes);
i64 arrayHighestIndex = this->count - 1;
i64 realCount = numIndexes;
if (indexList[numIndexes - 1] > arrayHighestIndex)
{
i64 realNumIndexes = Dqn_BinarySearch<i64>(indexList, numIndexes, arrayHighestIndex,
Dqn_BinarySearchBound_Lower);
// NOTE: If -1, then there's no index in the indexlist that is within the range of our array
// i.e. no index we can remove without out of array bounds access
if (realNumIndexes == -1)
return;
if (indexList[realNumIndexes] == arrayHighestIndex)
{
realCount = realNumIndexes++;
}
else
{
realCount = realNumIndexes += 2;
}
realCount = DQN_MIN(numIndexes, realCount);
}
if (realCount == 1)
{
this->RemoveStable(indexList[0]);
}
else
{
i64 indexListIndex = 0;
i64 indexToCopyTo = indexList[indexListIndex++];
i64 indexToCopyFrom = indexToCopyTo + 1;
i64 deadIndex = indexList[indexListIndex++];
bool breakLoop = false;
for (;
indexToCopyFrom < this->count;
indexToCopyTo++, indexToCopyFrom++)
{
while (indexToCopyFrom == deadIndex)
{
deadIndex = indexList[indexListIndex++];
indexToCopyFrom++;
breakLoop |= (indexToCopyFrom >= this->count);
breakLoop |= (indexListIndex > realCount);
if (breakLoop) break;
}
if (breakLoop) break;
this->data[indexToCopyTo] = this->data[indexToCopyFrom];
}
for (; indexToCopyFrom < this->count; indexToCopyTo++, indexToCopyFrom++)
{
this->data[indexToCopyTo] = this->data[indexToCopyFrom];
}
this->count -= realCount;
DQN_ASSERT(this->count >= 0);
}
}
////////////////////////////////////////////////////////////////////////////////
// #DqnHash Public API
////////////////////////////////////////////////////////////////////////////////
@ -897,7 +974,7 @@ typename DqnHashTable<T>::Entry *DqnHashTable<T>::Make(const char *const key, i3
if (!this->entries[hashIndex])
{
i64 index =
Dqn_BinarySearch<i64>(this->usedEntries, this->usedEntriesIndex, hashIndex, true);
Dqn_BinarySearch<i64>(this->usedEntries, this->usedEntriesIndex, hashIndex, Dqn_BinarySearchBound_Lower);
i64 indexToEndAt = index;
if (index == -1) indexToEndAt = 0;
@ -951,7 +1028,7 @@ void DqnHashTable<T>::Remove(const char *const key, i32 keyLen)
{
// Unique entry, so remove this index from the used list as well.
i64 indexToRemove = Dqn_BinarySearch<i64>(this->usedEntries, this->usedEntriesIndex,
hashIndex, true);
hashIndex, Dqn_BinarySearchBound_Lower);
for (i64 i = indexToRemove; i < this->usedEntriesIndex - 1; i++)
this->usedEntries[i] = this->usedEntries[i + 1];
@ -1517,7 +1594,7 @@ template <typename T>
using Dqn_QuickSortLessThanCallback = bool (*)(const T *const , const T *const);
template <typename T>
DQN_FILE_SCOPE void Dqn_QuickSort(T *const array, const i32 size,
DQN_FILE_SCOPE void Dqn_QuickSort(T *const array, const i64 size,
Dqn_QuickSortLessThanCallback<T> IsLessThan)
{
if (!array || size <= 1 || !IsLessThan) return;
@ -1551,10 +1628,10 @@ DQN_FILE_SCOPE void Dqn_QuickSort(T *const array, const i32 size,
DqnRndPCG state; state.Init();
i32 lastIndex = size - 1;
i32 pivotIndex = state.Range(0, lastIndex);
i32 partitionIndex = 0;
i32 startIndex = 0;
auto lastIndex = size - 1;
auto pivotIndex = (i64)state.Range(0, (i32)lastIndex);
auto partitionIndex = 0;
auto startIndex = 0;
// Swap pivot with last index, so pivot is always at the end of the array.
// This makes logic much simpler.
@ -1569,7 +1646,7 @@ DQN_FILE_SCOPE void Dqn_QuickSort(T *const array, const i32 size,
// 4, 5, |7, 8, 2^, 3, 6*
// 4, 5, 2, |8, 7, ^3, 6*
// 4, 5, 2, 3, |7, 8, ^6*
for (i32 checkIndex = startIndex; checkIndex < lastIndex; checkIndex++)
for (auto checkIndex = startIndex; checkIndex < lastIndex; checkIndex++)
{
if (IsLessThan(&array[checkIndex], &array[pivotIndex]))
{
@ -1589,16 +1666,97 @@ DQN_FILE_SCOPE void Dqn_QuickSort(T *const array, const i32 size,
Dqn_QuickSort(array + oneAfterPartitionIndex, (size - oneAfterPartitionIndex), IsLessThan);
}
template <typename T>
DQN_FILE_SCOPE void Dqn_QuickSort(T *const array, const i64 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 itemToInsertIndex = 1;
while (itemToInsertIndex < size)
{
for (i32 checkIndex = 0; checkIndex < itemToInsertIndex; checkIndex++)
{
if (!(array[checkIndex] < array[itemToInsertIndex]))
{
T itemToInsert = array[itemToInsertIndex];
for (i32 i = itemToInsertIndex; i > checkIndex; i--)
array[i] = array[i - 1];
array[checkIndex] = itemToInsert;
break;
}
}
itemToInsertIndex++;
}
return;
}
#endif
DqnRndPCG state; state.Init();
auto lastIndex = size - 1;
auto pivotIndex = (i64)state.Range(0, (i32)lastIndex); // TODO(doyle): RNG 64bit
auto partitionIndex = 0;
auto startIndex = 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[lastIndex], array[pivotIndex]);
pivotIndex = lastIndex;
// 4^, 8, 7, 5, 2, 3, 6
if (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 (auto checkIndex = startIndex; checkIndex < lastIndex; checkIndex++)
{
if (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);
// Skip the value at partion index since that is guaranteed to be sorted.
// 4, 5, 2, 3, (x), 8, 7
i32 oneAfterPartitionIndex = partitionIndex + 1;
Dqn_QuickSort(array + oneAfterPartitionIndex, (size - oneAfterPartitionIndex));
}
template <typename T>
using Dqn_BinarySearchLessThanCallback = bool (*)(const T&, const T&);
// lowerBound: If true, the return value is the first element lower than the value to find.
// -1 if there is no element lower than the find value (i.e. the 0th element is the find val).
enum Dqn_BinarySearchBound
{
Dqn_BinarySearchBound_Normal, // Return the index of the first item that matches the find value
Dqn_BinarySearchBound_Lower, // Return the index of the first item lower than the find value
Dqn_BinarySearchBound_Higher, // Return the index of the first item higher than the find value
};
// bound: The 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 <typename T>
DQN_FILE_SCOPE i64 Dqn_BinarySearch(T *const array, const i64 size, const T &find,
DQN_FILE_SCOPE i64
Dqn_BinarySearch(T *const array, const i64 size, const T &find,
const Dqn_BinarySearchLessThanCallback<T> IsLessThan,
const bool lowerBound = false)
const Dqn_BinarySearchBound bound = Dqn_BinarySearchBound_Normal)
{
if (size == 0 || !array) return -1;
@ -1608,17 +1766,39 @@ DQN_FILE_SCOPE i64 Dqn_BinarySearch(T *const array, const i64 size, const T &fin
while (start <= end)
{
if (array[mid] == find) return (lowerBound) ? (mid - 1) : mid;
if (array[mid] == find)
{
if (bound == Dqn_BinarySearchBound_Lower)
{
// NOTE: We can always -1 because at worst case, 0 index will go to -1 which is
// correct behaviour.
return mid - 1;
}
else if (bound == Dqn_BinarySearchBound_Higher)
{
if ((mid + 1) >= size) return -1;
return mid + 1;
}
else
{
return mid;
}
}
else if (IsLessThan(array[mid], find)) start = mid + 1;
else end = mid - 1;
mid = (i64)((start + end) * 0.5f);
}
if (lowerBound)
if (bound == Dqn_BinarySearchBound_Lower)
{
if (find < array[mid]) return -1;
return mid;
}
else if (bound == Dqn_BinarySearchBound_Higher)
{
if (find > array[mid]) return -1;
return mid;
}
else
{
return -1;
@ -1626,8 +1806,9 @@ DQN_FILE_SCOPE i64 Dqn_BinarySearch(T *const array, const i64 size, const T &fin
}
template <typename T>
DQN_FILE_SCOPE i64 Dqn_BinarySearch(T *const array, const i64 size, const i64 &find,
const bool lowerBound = false)
DQN_FILE_SCOPE i64
Dqn_BinarySearch(T *const array, const i64 size, const i64 &find,
const Dqn_BinarySearchBound bound = Dqn_BinarySearchBound_Normal)
{
if (size == 0 || !array) return -1;
@ -1637,17 +1818,37 @@ DQN_FILE_SCOPE i64 Dqn_BinarySearch(T *const array, const i64 size, const i64 &f
while (start <= end)
{
if (array[mid] == find) return (lowerBound) ? (mid - 1) : mid;
if (array[mid] == find)
{
if (bound == Dqn_BinarySearchBound_Lower)
{
return mid - 1;
}
else if (bound == Dqn_BinarySearchBound_Higher)
{
if ((mid + 1) >= size) return -1;
return mid + 1;
}
else
{
return mid;
}
}
else if (array[mid] < find) start = mid + 1;
else end = mid - 1;
mid = (i64)((start + end) * 0.5f);
}
if (lowerBound)
if (bound == Dqn_BinarySearchBound_Lower)
{
if (find < array[mid]) return -1;
return mid;
}
else if (bound == Dqn_BinarySearchBound_Higher)
{
if (find > array[mid]) return -1;
return mid;
}
else
{
return -1;

View File

@ -1068,6 +1068,8 @@ void DqnRect_Test()
}
void DqnArray_TestInternal(const DqnMemAPI memAPI)
{
if (1)
{
DqnArray<DqnV2> array = {};
if (1)
@ -1246,10 +1248,149 @@ void DqnArray_TestInternal(const DqnMemAPI memAPI)
LogSuccess("DqnArray(): Test stable removal");
}
DQN_ASSERT(array.Free());
}
if (1)
{
// Test normal remove list scenario
if (1)
{
i64 indexesToFree[] = {3, 2, 1, 0};
i32 intList[] = {128, 32, 29, 31};
DqnArray<i32> array;
array.Init(DQN_ARRAY_COUNT(intList), memAPI);
array.Push(intList, DQN_ARRAY_COUNT(intList));
array.RemoveStable(indexesToFree, DQN_ARRAY_COUNT(indexesToFree));
DQN_ASSERT(array.count == 0);
array.Free();
}
// Test all indexes invalid
if (1)
{
i64 indexesToFree[] = {100, 200, 300, 400};
i32 intList[] = {128, 32, 29, 31};
DqnArray<i32> array;
array.Init(DQN_ARRAY_COUNT(intList), memAPI);
array.Push(intList, DQN_ARRAY_COUNT(intList));
array.RemoveStable(indexesToFree, DQN_ARRAY_COUNT(indexesToFree));
DQN_ASSERT(array.count == 4);
DQN_ASSERT(array.data[0] == 128);
DQN_ASSERT(array.data[1] == 32);
DQN_ASSERT(array.data[2] == 29);
DQN_ASSERT(array.data[3] == 31);
array.Free();
}
// Test remove singular index
if (1)
{
i64 indexesToFree[] = {1};
i32 intList[] = {128, 32, 29, 31};
DqnArray<i32> array;
array.Init(DQN_ARRAY_COUNT(intList), memAPI);
array.Push(intList, DQN_ARRAY_COUNT(intList));
array.RemoveStable(indexesToFree, DQN_ARRAY_COUNT(indexesToFree));
DQN_ASSERT(array.count == 3);
DQN_ASSERT(array.data[0] == 128);
DQN_ASSERT(array.data[1] == 29);
DQN_ASSERT(array.data[2] == 31);
array.Free();
}
// Test remove singular invalid index
if (1)
{
i64 indexesToFree[] = {100};
i32 intList[] = {128, 32, 29, 31};
DqnArray<i32> array;
array.Init(DQN_ARRAY_COUNT(intList), memAPI);
array.Push(intList, DQN_ARRAY_COUNT(intList));
array.RemoveStable(indexesToFree, DQN_ARRAY_COUNT(indexesToFree));
DQN_ASSERT(array.count == 4);
DQN_ASSERT(array.data[0] == 128);
DQN_ASSERT(array.data[1] == 32);
DQN_ASSERT(array.data[2] == 29);
DQN_ASSERT(array.data[3] == 31);
array.Free();
}
// Test remove second last index
if (1)
{
i64 indexesToFree[] = {2};
i32 intList[] = {128, 32, 29, 31};
DqnArray<i32> array;
array.Init(DQN_ARRAY_COUNT(intList), memAPI);
array.Push(intList, DQN_ARRAY_COUNT(intList));
array.RemoveStable(indexesToFree, DQN_ARRAY_COUNT(indexesToFree));
DQN_ASSERT(array.count == 3);
DQN_ASSERT(array.data[0] == 128);
DQN_ASSERT(array.data[1] == 32);
DQN_ASSERT(array.data[2] == 31);
array.Free();
}
// Test remove last 2 indexes
if (1)
{
i64 indexesToFree[] = {2, 3};
i32 intList[] = {128, 32, 29, 31};
DqnArray<i32> array;
array.Init(DQN_ARRAY_COUNT(intList), memAPI);
array.Push(intList, DQN_ARRAY_COUNT(intList));
array.RemoveStable(indexesToFree, DQN_ARRAY_COUNT(indexesToFree));
DQN_ASSERT(array.count == 2);
DQN_ASSERT(array.data[0] == 128);
DQN_ASSERT(array.data[1] == 32);
array.Free();
}
// Test invalid free index doesn't delete out of bounds
if (1)
{
i64 indexesToFree[] = {30, 1, 3};
i32 intList[] = {128, 32, 29, 31};
DqnArray<i32> array;
array.Init(DQN_ARRAY_COUNT(intList), memAPI);
array.Push(intList, DQN_ARRAY_COUNT(intList));
array.RemoveStable(indexesToFree, DQN_ARRAY_COUNT(indexesToFree));
DQN_ASSERT(array.count == 2);
DQN_ASSERT(array.data[0] == 128);
DQN_ASSERT(array.data[1] == 29);
array.Free();
}
// Test a free list including the first index
if (1)
{
i64 indexesToFree[] = {0, 1, 2};
i32 intList[] = {128, 32, 29, 31};
DqnArray<i32> array;
array.Init(DQN_ARRAY_COUNT(intList), memAPI);
array.Push(intList, DQN_ARRAY_COUNT(intList));
array.RemoveStable(indexesToFree, DQN_ARRAY_COUNT(indexesToFree));
DQN_ASSERT(array.count == 1);
DQN_ASSERT(array.data[0] == 31);
array.Free();
}
LogSuccess("DqnArray(): Test stable removal with list of indexes");
}
}
void DqnArray_TestRealDataInternal(DqnArray<char> *array)
{
#ifdef DQN_XPLATFORM_LAYER
@ -1999,7 +2140,7 @@ void DqnQuickSort_Test()
u32 *stdArray = (u32 *)stack.Push(sizeInBytes);
DQN_ASSERT(dqnCPPArray && stdArray);
f64 dqnCPPTimings[2] = {};
f64 dqnCPPTimings[5] = {};
f64 stdTimings[DQN_ARRAY_COUNT(dqnCPPTimings)] = {};
f64 dqnCPPAverage = 0;
@ -2017,12 +2158,9 @@ void DqnQuickSort_Test()
// Time Dqn_QuickSort
{
f64 start = DqnTimer_NowInS();
Dqn_QuickSort<u32>(
dqnCPPArray, numInts,
[](const u32 *const a, const u32 *const b) -> bool { return *a < *b; });
Dqn_QuickSort(dqnCPPArray, numInts);
f64 duration = DqnTimer_NowInS() - start;
dqnCPPTimings[timingsIndex] = duration;
dqnCPPAverage += duration;
printf("Dqn_QuickSort: %f vs ", dqnCPPTimings[timingsIndex]);
@ -2187,24 +2325,22 @@ void Dqn_BinarySearch_Test()
if (1)
{
i32 array[] = {1, 2, 3};
const bool LOWER_BOUND = true;
i64 result = Dqn_BinarySearch(array, DQN_ARRAY_COUNT(array), 0, LOWER_BOUND);
i64 result = Dqn_BinarySearch(array, DQN_ARRAY_COUNT(array), 0, Dqn_BinarySearchBound_Lower);
DQN_ASSERT(result == -1);
result = Dqn_BinarySearch(array, DQN_ARRAY_COUNT(array), 1, LOWER_BOUND);
result = Dqn_BinarySearch(array, DQN_ARRAY_COUNT(array), 1, Dqn_BinarySearchBound_Lower);
DQN_ASSERT(result == -1);
result = Dqn_BinarySearch(array, DQN_ARRAY_COUNT(array), 2, LOWER_BOUND);
result = Dqn_BinarySearch(array, DQN_ARRAY_COUNT(array), 2, Dqn_BinarySearchBound_Lower);
DQN_ASSERT(result == 0);
result = Dqn_BinarySearch(array, DQN_ARRAY_COUNT(array), 3, LOWER_BOUND);
result = Dqn_BinarySearch(array, DQN_ARRAY_COUNT(array), 3, Dqn_BinarySearchBound_Lower);
DQN_ASSERT(result == 1);
result = Dqn_BinarySearch(array, DQN_ARRAY_COUNT(array), 4, LOWER_BOUND);
result = Dqn_BinarySearch(array, DQN_ARRAY_COUNT(array), 4, Dqn_BinarySearchBound_Lower);
DQN_ASSERT(result == 2);
result = Dqn_BinarySearch(array, DQN_ARRAY_COUNT(array), 5, LOWER_BOUND);
result = Dqn_BinarySearch(array, DQN_ARRAY_COUNT(array), 5, Dqn_BinarySearchBound_Lower);
DQN_ASSERT(result == 2);
LogSuccess("Dqn_BinarySearch(): Lower bound with odd sized array");
}
@ -2213,30 +2349,78 @@ void Dqn_BinarySearch_Test()
{
i32 array[] = {1, 2, 3, 4};
const bool LOWER_BOUND = true;
i64 result = Dqn_BinarySearch(array, DQN_ARRAY_COUNT(array), 0, LOWER_BOUND);
i64 result = Dqn_BinarySearch(array, DQN_ARRAY_COUNT(array), 0, Dqn_BinarySearchBound_Lower);
DQN_ASSERT(result == -1);
result = Dqn_BinarySearch(array, DQN_ARRAY_COUNT(array), 1, LOWER_BOUND);
result = Dqn_BinarySearch(array, DQN_ARRAY_COUNT(array), 1, Dqn_BinarySearchBound_Lower);
DQN_ASSERT(result == -1);
result = Dqn_BinarySearch(array, DQN_ARRAY_COUNT(array), 2, LOWER_BOUND);
result = Dqn_BinarySearch(array, DQN_ARRAY_COUNT(array), 2, Dqn_BinarySearchBound_Lower);
DQN_ASSERT(result == 0);
result = Dqn_BinarySearch(array, DQN_ARRAY_COUNT(array), 3, LOWER_BOUND);
result = Dqn_BinarySearch(array, DQN_ARRAY_COUNT(array), 3, Dqn_BinarySearchBound_Lower);
DQN_ASSERT(result == 1);
result = Dqn_BinarySearch(array, DQN_ARRAY_COUNT(array), 4, LOWER_BOUND);
result = Dqn_BinarySearch(array, DQN_ARRAY_COUNT(array), 4, Dqn_BinarySearchBound_Lower);
DQN_ASSERT(result == 2);
result = Dqn_BinarySearch(array, DQN_ARRAY_COUNT(array), 5, LOWER_BOUND);
result = Dqn_BinarySearch(array, DQN_ARRAY_COUNT(array), 5, Dqn_BinarySearchBound_Lower);
DQN_ASSERT(result == 3);
result = Dqn_BinarySearch(array, DQN_ARRAY_COUNT(array), 6, LOWER_BOUND);
result = Dqn_BinarySearch(array, DQN_ARRAY_COUNT(array), 6, Dqn_BinarySearchBound_Lower);
DQN_ASSERT(result == 3);
LogSuccess("Dqn_BinarySearch(): Lower bound with even sized array");
}
if (1)
{
i32 array[] = {1, 2, 3};
i64 result = Dqn_BinarySearch(array, DQN_ARRAY_COUNT(array), 0, Dqn_BinarySearchBound_Higher);
DQN_ASSERT(result == 0);
result = Dqn_BinarySearch(array, DQN_ARRAY_COUNT(array), 1, Dqn_BinarySearchBound_Higher);
DQN_ASSERT(result == 1);
result = Dqn_BinarySearch(array, DQN_ARRAY_COUNT(array), 2, Dqn_BinarySearchBound_Higher);
DQN_ASSERT(result == 2);
result = Dqn_BinarySearch(array, DQN_ARRAY_COUNT(array), 3, Dqn_BinarySearchBound_Higher);
DQN_ASSERT(result == -1);
result = Dqn_BinarySearch(array, DQN_ARRAY_COUNT(array), 4, Dqn_BinarySearchBound_Higher);
DQN_ASSERT(result == -1);
result = Dqn_BinarySearch(array, DQN_ARRAY_COUNT(array), 5, Dqn_BinarySearchBound_Higher);
DQN_ASSERT(result == -1);
LogSuccess("Dqn_BinarySearch(): Higher bound with odd sized array");
}
if (1)
{
i32 array[] = {1, 2, 3, 4};
i64 result = Dqn_BinarySearch(array, DQN_ARRAY_COUNT(array), 0, Dqn_BinarySearchBound_Higher);
DQN_ASSERT(result == 0);
result = Dqn_BinarySearch(array, DQN_ARRAY_COUNT(array), 1, Dqn_BinarySearchBound_Higher);
DQN_ASSERT(result == 1);
result = Dqn_BinarySearch(array, DQN_ARRAY_COUNT(array), 2, Dqn_BinarySearchBound_Higher);
DQN_ASSERT(result == 2);
result = Dqn_BinarySearch(array, DQN_ARRAY_COUNT(array), 3, Dqn_BinarySearchBound_Higher);
DQN_ASSERT(result == 3);
result = Dqn_BinarySearch(array, DQN_ARRAY_COUNT(array), 4, Dqn_BinarySearchBound_Higher);
DQN_ASSERT(result == -1);
result = Dqn_BinarySearch(array, DQN_ARRAY_COUNT(array), 5, Dqn_BinarySearchBound_Higher);
DQN_ASSERT(result == -1);
result = Dqn_BinarySearch(array, DQN_ARRAY_COUNT(array), 6, Dqn_BinarySearchBound_Higher);
DQN_ASSERT(result == -1);
LogSuccess("Dqn_BinarySearch(): Higher bound with even sized array");
}
}
int main(void)