diff --git a/DqnUnitTest.cpp b/DqnUnitTest.cpp index b7d4811..c01abf1 100644 --- a/DqnUnitTest.cpp +++ b/DqnUnitTest.cpp @@ -136,6 +136,7 @@ void LogHeader(char const *funcName) } #include "DqnFixedString.cpp" +#include "DqnOS.cpp" void HandmadeMathVerifyMat4(DqnMat4 dqnMat, hmm_mat4 hmmMat) { @@ -1267,15 +1268,15 @@ void DqnArray_TestInternal(DqnMemAPI *const memAPI) array.Push(va); DqnV2 vb = DqnV2(1, 2); - array.Insert(vb, -1); + array.Insert(-1, vb); DQN_ASSERT(DqnV2_Equals(array.data[0], vb)); DqnV2 vc = DqnV2(2, 1); - array.Insert(vc, array.count); + array.Insert(array.count, vc); DQN_ASSERT(DqnV2_Equals(array.data[array.count-1], vc)); DqnV2 vd = DqnV2(8, 9); - array.Insert(vd, 1); + array.Insert(1, vd); DQN_ASSERT(DqnV2_Equals(array.data[0], vb)); DQN_ASSERT(DqnV2_Equals(array.data[1], vd)); @@ -1297,7 +1298,7 @@ void DqnArray_TestInternal(DqnMemAPI *const memAPI) array.Push(tmp); array.Push(tmp); - array.Insert(va, DQN_ARRAY_COUNT(va), 1); + array.Insert(1, va, DQN_ARRAY_COUNT(va)); DQN_ASSERT(DqnV2_Equals(array.data[0], tmp)); DQN_ASSERT(DqnV2_Equals(array.data[1], va[0])); DQN_ASSERT(DqnV2_Equals(array.data[2], va[1])); @@ -1327,7 +1328,6 @@ void DqnArray_TestInternal(DqnMemAPI *const memAPI) DqnV2 d = DqnV2(7, 8); DQN_ASSERT(array.Reserve(16)); - DQN_ASSERT(array.Remove(0) == false); DQN_ASSERT(array.max >= 16); DQN_ASSERT(array.count == 0); @@ -1342,20 +1342,20 @@ void DqnArray_TestInternal(DqnMemAPI *const memAPI) DQN_ASSERT(array.max >= 16); DQN_ASSERT(array.count == 4); - DQN_ASSERT(array.Remove(0)); + array.Erase(0); DQN_ASSERT(DqnV2_Equals(array.data[0], d)); DQN_ASSERT(DqnV2_Equals(array.data[1], b)); DQN_ASSERT(DqnV2_Equals(array.data[2], c)); DQN_ASSERT(array.max >= 16); DQN_ASSERT(array.count == 3); - DQN_ASSERT(array.Remove(2)); + array.Erase(2); DQN_ASSERT(DqnV2_Equals(array.data[0], d)); DQN_ASSERT(DqnV2_Equals(array.data[1], b)); DQN_ASSERT(array.max >= 16); DQN_ASSERT(array.count == 2); - DQN_ASSERT(array.Remove(100) == false); + // array.Erase(100); DQN_ASSERT(DqnV2_Equals(array.data[0], d)); DQN_ASSERT(DqnV2_Equals(array.data[1], b)); DQN_ASSERT(array.max >= 16); @@ -1385,20 +1385,20 @@ void DqnArray_TestInternal(DqnMemAPI *const memAPI) DQN_ASSERT(array.max >= 16); DQN_ASSERT(array.count == 4); - array.RemoveStable(0); + array.EraseStable(0); DQN_ASSERT(DqnV2_Equals(array.data[0], b)); DQN_ASSERT(DqnV2_Equals(array.data[1], c)); DQN_ASSERT(DqnV2_Equals(array.data[2], d)); DQN_ASSERT(array.max >= 16); DQN_ASSERT(array.count == 3); - array.RemoveStable(1); + array.EraseStable(1); DQN_ASSERT(DqnV2_Equals(array.data[0], b)); DQN_ASSERT(DqnV2_Equals(array.data[1], d)); DQN_ASSERT(array.max >= 16); DQN_ASSERT(array.count == 2); - array.RemoveStable(1); + array.EraseStable(1); DQN_ASSERT(DqnV2_Equals(array.data[0], b)); DQN_ASSERT(array.max >= 16); DQN_ASSERT(array.count == 1); @@ -1408,6 +1408,8 @@ void DqnArray_TestInternal(DqnMemAPI *const memAPI) array.Free(); } + // TODO(doyle): Stable erase list API +#if 0 if (1) { // Test normal remove list scenario @@ -1420,7 +1422,7 @@ void DqnArray_TestInternal(DqnMemAPI *const memAPI) array.Reserve(DQN_ARRAY_COUNT(intList)); array.Push(intList, DQN_ARRAY_COUNT(intList)); - array.RemoveStable(indexesToFree, DQN_ARRAY_COUNT(indexesToFree)); + array.EraseStable(indexesToFree, DQN_ARRAY_COUNT(indexesToFree)); DQN_ASSERT(array.count == 0); array.Free(); } @@ -1434,7 +1436,7 @@ void DqnArray_TestInternal(DqnMemAPI *const memAPI) DqnArray array(memAPI); array.Reserve(DQN_ARRAY_COUNT(intList)); array.Push(intList, DQN_ARRAY_COUNT(intList)); - array.RemoveStable(indexesToFree, DQN_ARRAY_COUNT(indexesToFree)); + array.EraseStable(indexesToFree, DQN_ARRAY_COUNT(indexesToFree)); DQN_ASSERT(array.count == 4); DQN_ASSERT(array.data[0] == 128); DQN_ASSERT(array.data[1] == 32); @@ -1452,7 +1454,7 @@ void DqnArray_TestInternal(DqnMemAPI *const memAPI) DqnArray array(memAPI); array.Reserve(DQN_ARRAY_COUNT(intList)); array.Push(intList, DQN_ARRAY_COUNT(intList)); - array.RemoveStable(indexesToFree, DQN_ARRAY_COUNT(indexesToFree)); + array.EraseStable(indexesToFree, DQN_ARRAY_COUNT(indexesToFree)); DQN_ASSERT(array.count == 3); DQN_ASSERT(array.data[0] == 128); DQN_ASSERT(array.data[1] == 29); @@ -1469,7 +1471,7 @@ void DqnArray_TestInternal(DqnMemAPI *const memAPI) DqnArray array(memAPI); array.Reserve(DQN_ARRAY_COUNT(intList)); array.Push(intList, DQN_ARRAY_COUNT(intList)); - array.RemoveStable(indexesToFree, DQN_ARRAY_COUNT(indexesToFree)); + array.EraseStable(indexesToFree, DQN_ARRAY_COUNT(indexesToFree)); DQN_ASSERT(array.count == 4); DQN_ASSERT(array.data[0] == 128); DQN_ASSERT(array.data[1] == 32); @@ -1487,7 +1489,7 @@ void DqnArray_TestInternal(DqnMemAPI *const memAPI) DqnArray array(memAPI); array.Reserve(DQN_ARRAY_COUNT(intList)); array.Push(intList, DQN_ARRAY_COUNT(intList)); - array.RemoveStable(indexesToFree, DQN_ARRAY_COUNT(indexesToFree)); + array.EraseStable(indexesToFree, DQN_ARRAY_COUNT(indexesToFree)); DQN_ASSERT(array.count == 3); DQN_ASSERT(array.data[0] == 128); DQN_ASSERT(array.data[1] == 32); @@ -1504,7 +1506,7 @@ void DqnArray_TestInternal(DqnMemAPI *const memAPI) DqnArray array(memAPI); array.Reserve(DQN_ARRAY_COUNT(intList)); array.Push(intList, DQN_ARRAY_COUNT(intList)); - array.RemoveStable(indexesToFree, DQN_ARRAY_COUNT(indexesToFree)); + array.EraseStable(indexesToFree, DQN_ARRAY_COUNT(indexesToFree)); DQN_ASSERT(array.count == 2); DQN_ASSERT(array.data[0] == 128); DQN_ASSERT(array.data[1] == 32); @@ -1520,7 +1522,7 @@ void DqnArray_TestInternal(DqnMemAPI *const memAPI) DqnArray array(memAPI); array.Reserve(DQN_ARRAY_COUNT(intList)); array.Push(intList, DQN_ARRAY_COUNT(intList)); - array.RemoveStable(indexesToFree, DQN_ARRAY_COUNT(indexesToFree)); + array.EraseStable(indexesToFree, DQN_ARRAY_COUNT(indexesToFree)); DQN_ASSERT(array.count == 2); DQN_ASSERT(array.data[0] == 128); @@ -1537,7 +1539,7 @@ void DqnArray_TestInternal(DqnMemAPI *const memAPI) DqnArray array(memAPI); array.Reserve(DQN_ARRAY_COUNT(intList)); array.Push(intList, DQN_ARRAY_COUNT(intList)); - array.RemoveStable(indexesToFree, DQN_ARRAY_COUNT(indexesToFree)); + array.EraseStable(indexesToFree, DQN_ARRAY_COUNT(indexesToFree)); DQN_ASSERT(array.count == 1); DQN_ASSERT(array.data[0] == 31); @@ -1545,6 +1547,7 @@ void DqnArray_TestInternal(DqnMemAPI *const memAPI) } Log(Status::Ok, "Test stable removal with list of indexes"); } +#endif } void DqnArray_TestRealDataInternal(DqnArray *array) @@ -2895,6 +2898,7 @@ int main(void) DqnFixedString_Test(); #ifdef DQN_PLATFORM_HEADER + DqnOS_Test(); DqnFile_Test(); DqnTimer_Test(); DqnJobQueue_Test(); diff --git a/dqn.h b/dqn.h index 745e676..ee6b6bc 100644 --- a/dqn.h +++ b/dqn.h @@ -1130,7 +1130,95 @@ public: FILE_SCOPE DqnMemAPI DQN_DEFAULT_HEAP_ALLOCATOR_ = DqnMemAPI::HeapAllocator(); FILE_SCOPE DqnMemAPI *DQN_DEFAULT_HEAP_ALLOCATOR = &DQN_DEFAULT_HEAP_ALLOCATOR_; +template +struct DqnArray +{ + DqnMemAPI *memAPI = DQN_DEFAULT_HEAP_ALLOCATOR; + isize count; + isize max; + T *data; + DqnArray () = default; + DqnArray (DqnMemAPI *memAPI_) { *this = {}; this->memAPI = memAPI_; } + ~DqnArray () { if (this->data && this->memAPI) this->memAPI->Free(data); } + + void UseMemory (T *data_, isize max_, isize count_ = 0) { this->memAPI = nullptr; this->data = data_; this->max = max_; this->count = count_; } + void Clear (Dqn::ZeroClear clear = Dqn::ZeroClear::Yes) { if (data) { count = 0; if (clear == Dqn::ZeroClear::Yes) DqnMem_Clear(data, 0, sizeof(T) * max); } } + void Free () { if (data) { memAPI->Free(data); } *this = {}; } + T *Front () { DQN_ASSERT(count > 0); return data + 0; } + T *Back () { DQN_ASSERT(count > 0); return data + (count - 1); } + bool Resize (isize newCount) { if (newCount > max) Reserve(GrowCapacity_(newCount)); count = newCount; } + bool Resize (isize newCount, T const *v) { if (newCount > max) Reserve(GrowCapacity_(newCount)); if (newCount > count) for (isize n = count; n < newCount; n++) data[n] = *v; count = newCount; } + bool Reserve (isize newMax); + T *Push (T const &v) { return Insert(count, &v, 1); } + T *Push (T const *v, isize numItems = 1) { return Insert(count, v, numItems); } + void Pop () { if (count > 0) count--; } + void Erase (isize index) { DQN_ASSERT(index >= 0 && index < count); data[index] = data[--count]; } + void EraseStable(isize index); + T *Insert (isize index, T const *v) { return Insert(index, v, 1); } + T *Insert (isize index, T const &v) { return Insert(index, &v, 1); } + T *Insert (isize index, T const *v, isize numItems); + bool Contains (T const *v) const { T const *ptr = data; T const *end = data + count; while (ptr < end) if (*ptr++ == *v) return true; return false; } + + T &operator[] (isize i) const { DQN_ASSERT(i < count && i > 0); return this->data[i]; } + T *begin () { return data; } + T *end () { return data + count; } + +private: + isize GrowCapacity_(isize size) const { isize newMax = max ? (max * 2) : 8; return newMax > size ? newMax : size; } +}; + +template T *DqnArray::Insert(isize index, T const *v, isize numItems) +{ + index = DQN_MIN(DQN_MAX(index, 0), count); + isize const off = (data + index) - data; + isize const newCount = count + numItems; + + if (newCount >= max && !Reserve(GrowCapacity_(newCount))) + { + return nullptr; + } + + count = newCount; + T *start = data + off; + if (off < count) + memmove(start + numItems, start, ((usize)count - (usize)off) * sizeof(T)); + + for (isize i = 0; i < numItems; i++) + data[off + i] = v[i]; + + return data + off; +} + +template void DqnArray::EraseStable(isize index) +{ + DQN_ASSERT(index >= 0 && index < count); + isize const off = (data + index) - data; + memmove(data + off, data + off + 1, ((usize)count - (usize)off - 1) * sizeof(T)); + count--; +} + +template bool DqnArray::Reserve(isize newMax) +{ + if (newMax <= max) return true; + + if (data) + { + T *newData = (T *)memAPI->Realloc(data, max * sizeof(T), newMax * sizeof(T)); + if (newData) + { + data = newData; + max = newMax; + } + return newData; + } + + data = (T *)memAPI->Alloc(newMax * sizeof(T)); + max = newMax; + return data; +} + +#if 0 // #DqnArray API // ================================================================================================= template @@ -1161,10 +1249,10 @@ struct DqnArray T *Get (isize index); void Clear (Dqn::ZeroClear clear = Dqn::ZeroClear::No); bool Remove (isize index); - bool RemoveStable(isize index); + bool EraseStable(isize index); // indexList: Array of indexes to remove. This list gets sorted. - void RemoveStable(isize *indexList, isize numIndexes); + void EraseStable(isize *indexList, isize numIndexes); // C++ Iterator // ============================================================================================= @@ -1188,6 +1276,7 @@ struct DqnSmartArray : public DqnArray { ~DqnSmartArray() { if (this->data && this->memAPI) this->memAPI->Free(this->data); } }; +#endif // #DqnAllocatorMetadata // ================================================================================================= @@ -1387,6 +1476,7 @@ inline void DqnMemStack_TempRegionKeepChanges(DqnMemSt // Implementation taken from Milton, developed by Serge at // https://github.com/serge-rgb/milton#license +#if 0 template void DqnArray::Free() { @@ -1455,7 +1545,7 @@ bool DqnArray::Grow(isize multiplier) template inline bool DqnArray__TryMakeEnoughSpace(DqnArray *array, isize numNewItems) { - i32 numToReserve = numNewItems; + isize numToReserve = numNewItems; if ((array->count + numNewItems) >= array->max) { numToReserve = array->count + numNewItems; @@ -1593,7 +1683,7 @@ bool DqnArray::Remove(isize index) } template -bool DqnArray::RemoveStable(isize index) +bool DqnArray::EraseStable(isize index) { if (index >= this->count || index < 0) return false; @@ -1620,7 +1710,7 @@ bool DqnArray::RemoveStable(isize index) } template -void DqnArray::RemoveStable(isize *indexList, isize numIndexes) +void DqnArray::EraseStable(isize *indexList, isize numIndexes) { if (numIndexes == 0 || !indexList) return; @@ -1651,7 +1741,7 @@ void DqnArray::RemoveStable(isize *indexList, isize numIndexes) if (realCount == 1) { - this->RemoveStable(indexList[0]); + this->EraseStable(indexList[0]); } else { @@ -1688,6 +1778,7 @@ void DqnArray::RemoveStable(isize *indexList, isize numIndexes) DQN_ASSERT(this->count >= 0); } } +#endif // #DqnHash API // ================================================================================================= @@ -3560,7 +3651,7 @@ void DqnAllocatorMetadata::RemoveAllocation(u8 *ptr) } DQN_ASSERT(deleteIndex != -1); - this->allocations.RemoveStable(deleteIndex); + this->allocations.EraseStable(deleteIndex); } void DqnAllocatorMetadata::CheckAllocations() const @@ -3867,7 +3958,7 @@ FILE_SCOPE void DqnMemStackInternal_KillMetadataPtrsExistingIn(DqnAllocatorMetad u8 *ptr = metadata->allocations.data[index]; if (ptr >= start && ptr < end) { - metadata->allocations.RemoveStable(index); + metadata->allocations.EraseStable(index); index--; } }