From 6998fb84de5a81414b9fe6b7a87d7cfe20b31b61 Mon Sep 17 00:00:00 2001 From: Doyle T Date: Mon, 28 May 2018 23:07:29 +1000 Subject: [PATCH] Simplify DqnArray usage (zero is init), add multi-insert --- dqn.h | 168 ++++++++++++++++++---------------------------- dqn_unit_test.cpp | 129 +++++++++++++++++++++++++---------- 2 files changed, 160 insertions(+), 137 deletions(-) diff --git a/dqn.h b/dqn.h index 665b850..5544f78 100644 --- a/dqn.h +++ b/dqn.h @@ -929,7 +929,6 @@ DQN_FILE_SCOPE void *DqnMem_Realloc(void *memory, const usize newSize); DQN_FILE_SCOPE void DqnMem_Free (void *memory); DQN_FILE_SCOPE void DqnMem_Copy (void *const dest, void const *const src, i64 const numBytesToCopy); DQN_FILE_SCOPE void *DqnMem_Set (void *const dest, u8 const value, i64 const numBytesToSet); -DQN_FILE_SCOPE void *DqnMem_Set64 (void *const dest, u8 const value, i64 const numBytesToSet); // #DqnMemAPI API // ================================================================================================= @@ -1019,25 +1018,25 @@ FILE_SCOPE DqnMemAPI *DQN_DEFAULT_HEAP_ALLOCATOR = &DQN_DEFAULT_HEAP_ALLOCATOR_; template struct DqnArray { - DqnMemAPI *memAPI; - isize count; - isize max; - T *data; + DqnMemAPI *memAPI; // R/Write: The allocation scheme used, if null, it gets set to DQN_DEFAULT_HEAP_ALLOCATOR + isize count; // Read: The number of item in the array + isize max; // Read: Maximum size of array + T *data; // Read: Item storage + + DqnArray() = default; // Zero Is Initialisation + DqnArray(DqnMemAPI *memAPI_) { *this = {}; this->memAPI = memAPI_; } // API // ============================================================================================= - void Init (T *const data_, isize max_, isize count_ = 0); - void Init (DqnMemAPI *const memAPI_ = DQN_DEFAULT_HEAP_ALLOCATOR); - void Init (DqnMemStack *const stack); - bool InitSize (isize size_, DqnMemAPI *const memAPI_ = DQN_DEFAULT_HEAP_ALLOCATOR); - bool InitSize (isize size_, DqnMemStack *const stack); + void UseMemory (T *data_, isize max_, isize count_ = 0) { this->memAPI = nullptr; this->data = data_; this->max = max_; this->count = count_; } void Free (); - bool Resize (isize newMax); // If (newMax < count), it will destroy the left over elements. + bool Reserve (isize newMax); // If (newMax <= count) true is returned. False is returned only if out of memory. bool Grow (isize multiplier = 2); - T *Make (); // Get a ptr to the next free element in the array, increment count. - T *Push (T const *item, isize num); - T *Push (T const item); + T *Make (isize num = 1); // Increment array count by num and return a ptr to the start of an array of num elements. + T *Push (T const *item, isize num); // return: Last element pushed (this->data + this->count - 1), or null if out of memory. + T *Push (T const item); // return: Last element pushed (this->data + this->count - 1), or null if out of memory. + T *Insert (T const *item, isize numItems, isize index); T *Insert (T const item, isize index); void Pop (); T *Peek (); @@ -1267,44 +1266,6 @@ inline void DqnMemStack_TempRegionEnd (DqnMemSt inline DqnMemStack::TempRegionGuard_ DqnMemStack_TempRegionGuard (DqnMemStack *me) { return me->TempRegionGuard(); } inline void DqnMemStack_TempRegionKeepChanges(DqnMemStack *me, DqnMemStack::TempRegion region) { me->TempRegionKeepChanges(region); } -template -void DqnArray::Init(DqnMemAPI *const memAPI_) -{ - memAPI = memAPI_; - count = max = 0; - data = nullptr; -} - -template -void DqnArray::Init(T *data_, isize max_, isize count_) -{ - DQN_ASSERT(data_); - memAPI = nullptr; - count = count_; - max = max_; - data = data_; -} - -template -void DqnArray::Init(DqnMemStack *const stack) -{ - this->Init(stack->myHeadAPI); -} - -template -bool DqnArray::InitSize(isize size_, DqnMemAPI *const memAPI_) -{ - this->Init(memAPI_); - bool result = this->Resize(size_); - return result; -} - -template -bool DqnArray::InitSize(isize size_, DqnMemStack *const stack) -{ - bool result = this->InitSize(size_, &stack->myHeadAPI); - return result; -} // Implementation taken from Milton, developed by Serge at // https://github.com/serge-rgb/milton#license @@ -1318,40 +1279,28 @@ void DqnArray::Free() auto sizeToFree = this->max * sizeof(T); this->memAPI->Free(this->data, sizeToFree); } - - this->data = nullptr; - this->count = 0; - this->max = 0; } + + auto *memAPI_ = this->memAPI; + *this = {}; + this->memAPI = memAPI_; } template -bool DqnArray::Resize(isize newMax) +bool DqnArray::Reserve(isize newMax) { - if (!this->memAPI) + if (newMax <= this->count) { - DQN_LOGE("DqnArray has no memory api assigned. Resize to %d items failed.", newMax); - return false; - } - - if (newMax == 0) - { - DQN_LOGD( - "DqnArray tried to resize to 0 items. Not allowed? TODO(doyle): Maybe just free the " - "array then?"); return true; } - - if (newMax < this->count) + if (!this->memAPI) { - DQN_LOGE( - "DqnArray has %d items but requested a resize to: %d and will destroy the remaining " - "items in the array!", this->count, newMax); + this->memAPI = DQN_DEFAULT_HEAP_ALLOCATOR; } - auto oldSize = this->max * sizeof(T); - auto newSize = newMax * sizeof(T); + usize oldSize = this->max * sizeof(T); + usize newSize = newMax * sizeof(T); T *result = nullptr; if (this->data) @@ -1381,22 +1330,29 @@ bool DqnArray::Grow(isize multiplier) { isize newMax = this->max * multiplier; newMax = (newMax < 8) ? 8 : newMax; - bool result = this->Resize(newMax); + bool result = this->Reserve(newMax); return result; } template -T *DqnArray::Make() +inline bool DqnArray__TryMakeEnoughSpace(DqnArray *array, isize numNewItems) { - bool accessible = true; - if (!this->data || this->count >= this->max) + bool result = true; + if (!array->data || (array->count + numNewItems) >= array->max) { - accessible = this->Grow(); + result = array->Grow(); } - if (accessible) + return result; +} + +template +T *DqnArray::Make(isize num) +{ + if (DqnArray__TryMakeEnoughSpace(this, num)) { - T *result = this->data[this->count++]; + T *result = &this->data[this->count]; + this->count += num; return result; } @@ -1406,13 +1362,10 @@ T *DqnArray::Make() template T *DqnArray::Push(T const *item, isize num) { - if (!this->data || (this->count + num) > this->max) + if (!DqnArray__TryMakeEnoughSpace(this, num)) { - if (!this->Grow()) - { - DQN_LOGE("DqnArray could not push %d item(s) onto array because growing failed.", num); - return nullptr; - } + DQN_LOGE("DqnArray could not push %d item(s) onto array because growing failed.", num); + return nullptr; } for (auto i = 0; i < num; i++) @@ -1431,35 +1384,43 @@ T *DqnArray::Push(T const item) } template -T *DqnArray::Insert(T const item, isize index) +T *DqnArray::Insert(T const *item, isize numItems, isize index) { - index = DQN_MAX(index, 0); + if (!DqnArray__TryMakeEnoughSpace(this, numItems)) + { + DQN_LOGE("DqnArray could not push %d item(s) onto array because growing failed.", numItems); + return nullptr; + } + + index = DQN_MIN(DQN_MAX(0, index), this->count); if (index >= this->count) { - T *result = this->Push(item); + T *result = this->Push(item, numItems); return result; } - if (!this->data || (this->count + 1) > this->max) + isize numItemsToShift = this->count - index; + for (isize i = 0; i < numItemsToShift; i++) { - if (!this->Grow()) - { - DQN_LOGE("DqnArray could not insert at index %d because growing failed.", index); - return nullptr; - } + isize backwardsIndex = this->count + numItems - 1 - i; + this->data[backwardsIndex] = this->data[this->count - 1 - i]; } - this->count++; - for (auto i = this->count - 1; (i - 1) >= index; i--) - this->data[i] = this->data[i - 1]; - - this->data[index] = item; - T *result = this->data + index; + this->count += numItems; + DqnMem_Copy(this->data + index, item, sizeof(*item) * numItems); + T *result = this->data + index; DQN_ASSERT(this->count <= this->max); return result; } +template +T *DqnArray::Insert(T const item, isize index) +{ + T *result = this->Insert(&item, 1, index); + return result; +} + template void DqnArray::Pop() { @@ -3832,7 +3793,8 @@ void DqnAllocatorMetadata::Init(bool boundsGuard) { this->boundsGuardSize = sizeof(HEAD_GUARD_VALUE); LOCAL_PERSIST DqnMemAPI heap = DqnMemAPI::HeapAllocator(); - DQN_ASSERT(this->allocations.InitSize(128, &heap)); + this->allocations.memAPI = &heap; + DQN_ASSERT(this->allocations.Reserve(128)); } else { diff --git a/dqn_unit_test.cpp b/dqn_unit_test.cpp index 9be7a87..8901894 100644 --- a/dqn_unit_test.cpp +++ b/dqn_unit_test.cpp @@ -1240,14 +1240,14 @@ void DqnArray_TestInternal(DqnMemAPI *const memAPI) { if (1) { - DqnArray array = {}; + DqnArray array(memAPI); if (1) { - DQN_ASSERT(array.InitSize(1, memAPI)); + DQN_ASSERT(array.Reserve(1)); DQN_ASSERT(array.max >= 1); DQN_ASSERT(array.count == 0); - // Test basic insert + // Test basic push if (1) { DqnV2 va = DqnV2_(5, 10); @@ -1258,7 +1258,7 @@ void DqnArray_TestInternal(DqnMemAPI *const memAPI) DQN_ASSERT(array.max >= 1); DQN_ASSERT(array.count == 1); - Log(Status::Ok, "Test basic insert"); + Log(Status::Ok, "Test basic push"); } // Test array resizing and freeing @@ -1320,12 +1320,63 @@ void DqnArray_TestInternal(DqnMemAPI *const memAPI) Log(Status::Ok, "Test resizing and free"); } + array.Free(); + + // Test insert + if (1) + { + DqnV2 va = DqnV2_(5, 10); + array.Push(va); + array.Push(va); + array.Push(va); + + DqnV2 vb = DqnV2_(1, 2); + array.Insert(vb, -1); + DQN_ASSERT(DqnV2_Equals(array.data[0], vb)); + + DqnV2 vc = DqnV2_(2, 1); + array.Insert(vc, array.count); + DQN_ASSERT(DqnV2_Equals(array.data[array.count-1], vc)); + + DqnV2 vd = DqnV2_(8, 9); + array.Insert(vd, 1); + + DQN_ASSERT(DqnV2_Equals(array.data[0], vb)); + DQN_ASSERT(DqnV2_Equals(array.data[1], vd)); + DQN_ASSERT(DqnV2_Equals(array.data[2], va)); + DQN_ASSERT(DqnV2_Equals(array.data[3], va)); + DQN_ASSERT(DqnV2_Equals(array.data[4], va)); + DQN_ASSERT(DqnV2_Equals(array.data[5], vc)); + + Log(Status::Ok, "Test insert"); + } + array.Free(); + + // Test multi-insert + if (1) + { + DqnV2 va[] = {DqnV2_(5, 10), DqnV2_(6, 10), DqnV2_(7, 10)}; + DqnV2 tmp = DqnV2_(1, 1); + array.Push(tmp); + array.Push(tmp); + array.Push(tmp); + + array.Insert(va, DQN_ARRAY_COUNT(va), 1); + 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])); + DQN_ASSERT(DqnV2_Equals(array.data[3], va[2])); + DQN_ASSERT(DqnV2_Equals(array.data[4], tmp)); + DQN_ASSERT(DqnV2_Equals(array.data[5], tmp)); + + Log(Status::Ok, "Test insert"); + } + array.Free(); } - array.Free(); if (1) { - DQN_ASSERT(array.InitSize(1, memAPI)); + DQN_ASSERT(array.Reserve(1)); DQN_ASSERT(array.max >= 1); DQN_ASSERT(array.count == 0); Log(Status::Ok, "Empty array"); @@ -1339,7 +1390,7 @@ void DqnArray_TestInternal(DqnMemAPI *const memAPI) DqnV2 c = DqnV2_(5, 6); DqnV2 d = DqnV2_(7, 8); - DQN_ASSERT(array.InitSize(16, memAPI)); + DQN_ASSERT(array.Reserve(16)); DQN_ASSERT(array.Remove(0) == false); DQN_ASSERT(array.max >= 16); DQN_ASSERT(array.count == 0); @@ -1380,6 +1431,7 @@ void DqnArray_TestInternal(DqnMemAPI *const memAPI) Log(Status::Ok, "Test removal"); } array.Free(); + array.memAPI = memAPI; if (1) { @@ -1388,7 +1440,7 @@ void DqnArray_TestInternal(DqnMemAPI *const memAPI) DqnV2 c = DqnV2_(5, 6); DqnV2 d = DqnV2_(7, 8); - DQN_ASSERT(array.InitSize(16, memAPI)); + DQN_ASSERT(array.Reserve(16)); DQN_ASSERT(array.Push(a)); DQN_ASSERT(array.Push(b)); @@ -1428,8 +1480,9 @@ void DqnArray_TestInternal(DqnMemAPI *const memAPI) i64 indexesToFree[] = {3, 2, 1, 0}; i32 intList[] = {128, 32, 29, 31}; - DqnArray array; - array.InitSize(DQN_ARRAY_COUNT(intList), memAPI); + DqnArray array(memAPI); + array.Reserve(DQN_ARRAY_COUNT(intList)); + array.Push(intList, DQN_ARRAY_COUNT(intList)); array.RemoveStable(indexesToFree, DQN_ARRAY_COUNT(indexesToFree)); DQN_ASSERT(array.count == 0); @@ -1442,8 +1495,8 @@ void DqnArray_TestInternal(DqnMemAPI *const memAPI) i64 indexesToFree[] = {100, 200, 300, 400}; i32 intList[] = {128, 32, 29, 31}; - DqnArray array; - array.InitSize(DQN_ARRAY_COUNT(intList), memAPI); + DqnArray array(memAPI); + array.Reserve(DQN_ARRAY_COUNT(intList)); array.Push(intList, DQN_ARRAY_COUNT(intList)); array.RemoveStable(indexesToFree, DQN_ARRAY_COUNT(indexesToFree)); DQN_ASSERT(array.count == 4); @@ -1460,8 +1513,8 @@ void DqnArray_TestInternal(DqnMemAPI *const memAPI) i64 indexesToFree[] = {1}; i32 intList[] = {128, 32, 29, 31}; - DqnArray array; - array.InitSize(DQN_ARRAY_COUNT(intList), memAPI); + DqnArray array(memAPI); + array.Reserve(DQN_ARRAY_COUNT(intList)); array.Push(intList, DQN_ARRAY_COUNT(intList)); array.RemoveStable(indexesToFree, DQN_ARRAY_COUNT(indexesToFree)); DQN_ASSERT(array.count == 3); @@ -1477,8 +1530,8 @@ void DqnArray_TestInternal(DqnMemAPI *const memAPI) i64 indexesToFree[] = {100}; i32 intList[] = {128, 32, 29, 31}; - DqnArray array; - array.InitSize(DQN_ARRAY_COUNT(intList), memAPI); + DqnArray array(memAPI); + array.Reserve(DQN_ARRAY_COUNT(intList)); array.Push(intList, DQN_ARRAY_COUNT(intList)); array.RemoveStable(indexesToFree, DQN_ARRAY_COUNT(indexesToFree)); DQN_ASSERT(array.count == 4); @@ -1495,8 +1548,8 @@ void DqnArray_TestInternal(DqnMemAPI *const memAPI) i64 indexesToFree[] = {2}; i32 intList[] = {128, 32, 29, 31}; - DqnArray array; - array.InitSize(DQN_ARRAY_COUNT(intList), memAPI); + DqnArray array(memAPI); + array.Reserve(DQN_ARRAY_COUNT(intList)); array.Push(intList, DQN_ARRAY_COUNT(intList)); array.RemoveStable(indexesToFree, DQN_ARRAY_COUNT(indexesToFree)); DQN_ASSERT(array.count == 3); @@ -1512,8 +1565,8 @@ void DqnArray_TestInternal(DqnMemAPI *const memAPI) i64 indexesToFree[] = {2, 3}; i32 intList[] = {128, 32, 29, 31}; - DqnArray array; - array.InitSize(DQN_ARRAY_COUNT(intList), memAPI); + DqnArray array(memAPI); + array.Reserve(DQN_ARRAY_COUNT(intList)); array.Push(intList, DQN_ARRAY_COUNT(intList)); array.RemoveStable(indexesToFree, DQN_ARRAY_COUNT(indexesToFree)); DQN_ASSERT(array.count == 2); @@ -1528,8 +1581,8 @@ void DqnArray_TestInternal(DqnMemAPI *const memAPI) i64 indexesToFree[] = {30, 1, 3}; i32 intList[] = {128, 32, 29, 31}; - DqnArray array; - array.InitSize(DQN_ARRAY_COUNT(intList), memAPI); + DqnArray array(memAPI); + array.Reserve(DQN_ARRAY_COUNT(intList)); array.Push(intList, DQN_ARRAY_COUNT(intList)); array.RemoveStable(indexesToFree, DQN_ARRAY_COUNT(indexesToFree)); @@ -1545,8 +1598,8 @@ void DqnArray_TestInternal(DqnMemAPI *const memAPI) i64 indexesToFree[] = {0, 1, 2}; i32 intList[] = {128, 32, 29, 31}; - DqnArray array; - array.InitSize(DQN_ARRAY_COUNT(intList), memAPI); + DqnArray array(memAPI); + array.Reserve(DQN_ARRAY_COUNT(intList)); array.Push(intList, DQN_ARRAY_COUNT(intList)); array.RemoveStable(indexesToFree, DQN_ARRAY_COUNT(indexesToFree)); @@ -1554,8 +1607,6 @@ void DqnArray_TestInternal(DqnMemAPI *const memAPI) DQN_ASSERT(array.data[0] == 31); array.Free(); } - - Log(Status::Ok, "Test stable removal with list of indexes"); } } @@ -1594,13 +1645,13 @@ void DqnArray_Test() { if (1) { - DqnArray array1; - array1.InitSize(3); + DqnArray array1 = {}; + array1.Reserve(3); DQN_ASSERT(array1.count == 0); DQN_ASSERT(array1.max == 3); array1.Free(); - array1.InitSize(0); + array1.Reserve(0); DQN_ASSERT(array1.count == 0); DQN_ASSERT(array1.max == 0); @@ -1614,7 +1665,7 @@ void DqnArray_Test() if (1) { DqnArray array = {}; - DQN_ASSERT(array.InitSize(1)); + DQN_ASSERT(array.Reserve(1)); DqnArray_TestRealDataInternal(&array); } @@ -1625,8 +1676,8 @@ void DqnArray_Test() if (1) { auto memGuard0 = stack.TempRegionGuard(); - DqnArray array = {}; - DQN_ASSERT(array.InitSize(1, &stack.myHeadAPI)); + DqnArray array(&stack.myHeadAPI); + DQN_ASSERT(array.Reserve(1)); DqnArray_TestRealDataInternal(&array); } @@ -1634,8 +1685,8 @@ void DqnArray_Test() if (1) { auto memGuard0 = stack.TempRegionGuard(); - DqnArray array = {}; - DQN_ASSERT(array.InitSize(128, &stack.myHeadAPI)); + DqnArray array(&stack.myHeadAPI); + DQN_ASSERT(array.Reserve(128)); stack.Push(1024); DqnArray_TestRealDataInternal(&array); } @@ -2878,6 +2929,16 @@ int main(void) DqnJobQueue_Test(); #endif + struct Item + { + f32 a, b, c, d; + }; + + Item storage[20] = {}; + DqnArray array = {}; + array.UseMemory(storage, DQN_ARRAY_COUNT(storage)); + + // Log("\nPress 'Enter' Key to Exit\n"); // getchar();