List removal for arrays, template specialize sort
This commit is contained in:
parent
88bac561ec
commit
25d6308a5f
243
dqn.h
243
dqn.h
@ -474,6 +474,9 @@ struct DqnString
|
|||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
// #DqnArray Public API - CPP Dynamic Array with Templates
|
// #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>
|
template <typename T>
|
||||||
struct DqnArray
|
struct DqnArray
|
||||||
{
|
{
|
||||||
@ -497,17 +500,21 @@ struct DqnArray
|
|||||||
void Clear (const bool clearMemory = false);
|
void Clear (const bool clearMemory = false);
|
||||||
bool Remove (const i64 index);
|
bool Remove (const i64 index);
|
||||||
bool RemoveStable(const i64 index);
|
bool RemoveStable(const i64 index);
|
||||||
|
void RemoveStable(i64 *indexList, const i64 numIndexes);
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
bool DqnArray<T>::Init(const i64 size, const DqnMemAPI api = DqnMemAPI_HeapAllocator())
|
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);
|
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);
|
this->data = (T *)api.callback(info);
|
||||||
if (!this->data) return false;
|
if (!this->data) return false;
|
||||||
|
}
|
||||||
|
|
||||||
this->memAPI = api;
|
this->memAPI = api;
|
||||||
this->count = 0;
|
this->count = 0;
|
||||||
@ -578,7 +585,7 @@ template <typename T>
|
|||||||
T *DqnArray<T>::Push(const T *item, const i64 num)
|
T *DqnArray<T>::Push(const T *item, const i64 num)
|
||||||
{
|
{
|
||||||
i64 newSize = this->count + num;
|
i64 newSize = this->count + num;
|
||||||
if (newSize > this->max)
|
if (!this->data || newSize > this->max)
|
||||||
{
|
{
|
||||||
if (!this->Grow()) return nullptr;
|
if (!this->Grow()) return nullptr;
|
||||||
}
|
}
|
||||||
@ -670,6 +677,76 @@ bool DqnArray<T>::RemoveStable(const i64 index)
|
|||||||
return true;
|
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
|
// #DqnHash Public API
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
@ -897,7 +974,7 @@ typename DqnHashTable<T>::Entry *DqnHashTable<T>::Make(const char *const key, i3
|
|||||||
if (!this->entries[hashIndex])
|
if (!this->entries[hashIndex])
|
||||||
{
|
{
|
||||||
i64 index =
|
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;
|
i64 indexToEndAt = index;
|
||||||
if (index == -1) indexToEndAt = 0;
|
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.
|
// Unique entry, so remove this index from the used list as well.
|
||||||
i64 indexToRemove = Dqn_BinarySearch<i64>(this->usedEntries, this->usedEntriesIndex,
|
i64 indexToRemove = Dqn_BinarySearch<i64>(this->usedEntries, this->usedEntriesIndex,
|
||||||
hashIndex, true);
|
hashIndex, Dqn_BinarySearchBound_Lower);
|
||||||
|
|
||||||
for (i64 i = indexToRemove; i < this->usedEntriesIndex - 1; i++)
|
for (i64 i = indexToRemove; i < this->usedEntriesIndex - 1; i++)
|
||||||
this->usedEntries[i] = this->usedEntries[i + 1];
|
this->usedEntries[i] = this->usedEntries[i + 1];
|
||||||
@ -1517,7 +1594,7 @@ template <typename T>
|
|||||||
using Dqn_QuickSortLessThanCallback = bool (*)(const T *const , const T *const);
|
using Dqn_QuickSortLessThanCallback = bool (*)(const T *const , const T *const);
|
||||||
|
|
||||||
template <typename T>
|
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)
|
Dqn_QuickSortLessThanCallback<T> IsLessThan)
|
||||||
{
|
{
|
||||||
if (!array || size <= 1 || !IsLessThan) return;
|
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();
|
DqnRndPCG state; state.Init();
|
||||||
|
|
||||||
i32 lastIndex = size - 1;
|
auto lastIndex = size - 1;
|
||||||
i32 pivotIndex = state.Range(0, lastIndex);
|
auto pivotIndex = (i64)state.Range(0, (i32)lastIndex);
|
||||||
i32 partitionIndex = 0;
|
auto partitionIndex = 0;
|
||||||
i32 startIndex = 0;
|
auto startIndex = 0;
|
||||||
|
|
||||||
// Swap pivot with last index, so pivot is always at the end of the array.
|
// Swap pivot with last index, so pivot is always at the end of the array.
|
||||||
// This makes logic much simpler.
|
// 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, |7, 8, 2^, 3, 6*
|
||||||
// 4, 5, 2, |8, 7, ^3, 6*
|
// 4, 5, 2, |8, 7, ^3, 6*
|
||||||
// 4, 5, 2, 3, |7, 8, ^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]))
|
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);
|
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>
|
template <typename T>
|
||||||
using Dqn_BinarySearchLessThanCallback = bool (*)(const T&, const 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.
|
enum Dqn_BinarySearchBound
|
||||||
// -1 if there is no element lower than the find value (i.e. the 0th element is the find val).
|
{
|
||||||
|
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.
|
// 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>
|
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 Dqn_BinarySearchLessThanCallback<T> IsLessThan,
|
||||||
const bool lowerBound = false)
|
const Dqn_BinarySearchBound bound = Dqn_BinarySearchBound_Normal)
|
||||||
{
|
{
|
||||||
if (size == 0 || !array) return -1;
|
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)
|
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 if (IsLessThan(array[mid], find)) start = mid + 1;
|
||||||
else end = mid - 1;
|
else end = mid - 1;
|
||||||
mid = (i64)((start + end) * 0.5f);
|
mid = (i64)((start + end) * 0.5f);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (lowerBound)
|
if (bound == Dqn_BinarySearchBound_Lower)
|
||||||
{
|
{
|
||||||
if (find < array[mid]) return -1;
|
if (find < array[mid]) return -1;
|
||||||
return mid;
|
return mid;
|
||||||
}
|
}
|
||||||
|
else if (bound == Dqn_BinarySearchBound_Higher)
|
||||||
|
{
|
||||||
|
if (find > array[mid]) return -1;
|
||||||
|
return mid;
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
return -1;
|
return -1;
|
||||||
@ -1626,8 +1806,9 @@ DQN_FILE_SCOPE i64 Dqn_BinarySearch(T *const array, const i64 size, const T &fin
|
|||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
DQN_FILE_SCOPE i64 Dqn_BinarySearch(T *const array, const i64 size, const i64 &find,
|
DQN_FILE_SCOPE i64
|
||||||
const bool lowerBound = false)
|
Dqn_BinarySearch(T *const array, const i64 size, const i64 &find,
|
||||||
|
const Dqn_BinarySearchBound bound = Dqn_BinarySearchBound_Normal)
|
||||||
{
|
{
|
||||||
if (size == 0 || !array) return -1;
|
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)
|
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 if (array[mid] < find) start = mid + 1;
|
||||||
else end = mid - 1;
|
else end = mid - 1;
|
||||||
mid = (i64)((start + end) * 0.5f);
|
mid = (i64)((start + end) * 0.5f);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (lowerBound)
|
if (bound == Dqn_BinarySearchBound_Lower)
|
||||||
{
|
{
|
||||||
if (find < array[mid]) return -1;
|
if (find < array[mid]) return -1;
|
||||||
return mid;
|
return mid;
|
||||||
}
|
}
|
||||||
|
else if (bound == Dqn_BinarySearchBound_Higher)
|
||||||
|
{
|
||||||
|
if (find > array[mid]) return -1;
|
||||||
|
return mid;
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
return -1;
|
return -1;
|
||||||
|
@ -1068,6 +1068,8 @@ void DqnRect_Test()
|
|||||||
}
|
}
|
||||||
|
|
||||||
void DqnArray_TestInternal(const DqnMemAPI memAPI)
|
void DqnArray_TestInternal(const DqnMemAPI memAPI)
|
||||||
|
{
|
||||||
|
if (1)
|
||||||
{
|
{
|
||||||
DqnArray<DqnV2> array = {};
|
DqnArray<DqnV2> array = {};
|
||||||
if (1)
|
if (1)
|
||||||
@ -1246,10 +1248,149 @@ void DqnArray_TestInternal(const DqnMemAPI memAPI)
|
|||||||
|
|
||||||
LogSuccess("DqnArray(): Test stable removal");
|
LogSuccess("DqnArray(): Test stable removal");
|
||||||
}
|
}
|
||||||
|
|
||||||
DQN_ASSERT(array.Free());
|
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)
|
void DqnArray_TestRealDataInternal(DqnArray<char> *array)
|
||||||
{
|
{
|
||||||
#ifdef DQN_XPLATFORM_LAYER
|
#ifdef DQN_XPLATFORM_LAYER
|
||||||
@ -1999,7 +2140,7 @@ void DqnQuickSort_Test()
|
|||||||
u32 *stdArray = (u32 *)stack.Push(sizeInBytes);
|
u32 *stdArray = (u32 *)stack.Push(sizeInBytes);
|
||||||
DQN_ASSERT(dqnCPPArray && stdArray);
|
DQN_ASSERT(dqnCPPArray && stdArray);
|
||||||
|
|
||||||
f64 dqnCPPTimings[2] = {};
|
f64 dqnCPPTimings[5] = {};
|
||||||
f64 stdTimings[DQN_ARRAY_COUNT(dqnCPPTimings)] = {};
|
f64 stdTimings[DQN_ARRAY_COUNT(dqnCPPTimings)] = {};
|
||||||
|
|
||||||
f64 dqnCPPAverage = 0;
|
f64 dqnCPPAverage = 0;
|
||||||
@ -2017,12 +2158,9 @@ void DqnQuickSort_Test()
|
|||||||
// Time Dqn_QuickSort
|
// Time Dqn_QuickSort
|
||||||
{
|
{
|
||||||
f64 start = DqnTimer_NowInS();
|
f64 start = DqnTimer_NowInS();
|
||||||
Dqn_QuickSort<u32>(
|
Dqn_QuickSort(dqnCPPArray, numInts);
|
||||||
dqnCPPArray, numInts,
|
|
||||||
[](const u32 *const a, const u32 *const b) -> bool { return *a < *b; });
|
|
||||||
|
|
||||||
f64 duration = DqnTimer_NowInS() - start;
|
f64 duration = DqnTimer_NowInS() - start;
|
||||||
|
|
||||||
dqnCPPTimings[timingsIndex] = duration;
|
dqnCPPTimings[timingsIndex] = duration;
|
||||||
dqnCPPAverage += duration;
|
dqnCPPAverage += duration;
|
||||||
printf("Dqn_QuickSort: %f vs ", dqnCPPTimings[timingsIndex]);
|
printf("Dqn_QuickSort: %f vs ", dqnCPPTimings[timingsIndex]);
|
||||||
@ -2187,24 +2325,22 @@ void Dqn_BinarySearch_Test()
|
|||||||
if (1)
|
if (1)
|
||||||
{
|
{
|
||||||
i32 array[] = {1, 2, 3};
|
i32 array[] = {1, 2, 3};
|
||||||
|
i64 result = Dqn_BinarySearch(array, DQN_ARRAY_COUNT(array), 0, Dqn_BinarySearchBound_Lower);
|
||||||
const bool LOWER_BOUND = true;
|
|
||||||
i64 result = Dqn_BinarySearch(array, DQN_ARRAY_COUNT(array), 0, LOWER_BOUND);
|
|
||||||
DQN_ASSERT(result == -1);
|
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);
|
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);
|
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);
|
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);
|
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);
|
DQN_ASSERT(result == 2);
|
||||||
LogSuccess("Dqn_BinarySearch(): Lower bound with odd sized array");
|
LogSuccess("Dqn_BinarySearch(): Lower bound with odd sized array");
|
||||||
}
|
}
|
||||||
@ -2213,30 +2349,78 @@ void Dqn_BinarySearch_Test()
|
|||||||
{
|
{
|
||||||
i32 array[] = {1, 2, 3, 4};
|
i32 array[] = {1, 2, 3, 4};
|
||||||
|
|
||||||
const bool LOWER_BOUND = true;
|
i64 result = Dqn_BinarySearch(array, DQN_ARRAY_COUNT(array), 0, Dqn_BinarySearchBound_Lower);
|
||||||
i64 result = Dqn_BinarySearch(array, DQN_ARRAY_COUNT(array), 0, LOWER_BOUND);
|
|
||||||
DQN_ASSERT(result == -1);
|
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);
|
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);
|
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);
|
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);
|
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);
|
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);
|
DQN_ASSERT(result == 3);
|
||||||
|
|
||||||
LogSuccess("Dqn_BinarySearch(): Lower bound with even sized array");
|
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)
|
int main(void)
|
||||||
|
Loading…
Reference in New Issue
Block a user