From a233bf0e4bd9792123d6eea96fc2b78798d911ce Mon Sep 17 00:00:00 2001 From: Anton Tarasenko Date: Thu, 8 Apr 2021 18:51:07 +0700 Subject: [PATCH] Add `AssociativeArray` ability to deallocate keys `AssociativeArray` by design does not manage keys, automatically deallocating them, like it can with stored values. This patch adds a parameter to `Empty()` method that allows it to deallocate all of the used keys when deallocation all of the values. As a side effect this patch also fixes a bug that broke `AssociativeArray` after using `Empty()` method. --- sources/Data/Collections/AssociativeArray.uc | 18 ++++++++++-- .../Tests/TEST_AssociativeArray.uc | 29 +++++++++++++++++-- 2 files changed, 42 insertions(+), 5 deletions(-) diff --git a/sources/Data/Collections/AssociativeArray.uc b/sources/Data/Collections/AssociativeArray.uc index f4ef8f0..1515d64 100644 --- a/sources/Data/Collections/AssociativeArray.uc +++ b/sources/Data/Collections/AssociativeArray.uc @@ -424,9 +424,14 @@ public final function AssociativeArray RemoveItem(AcediaObject key) * Completely clears caller `AssociativeArray` of all stored entries, * deallocating any stored managed values. * + * @param deallocateKeys Setting this to `true` will force this method to + * also deallocate all keys from the caller `AssociativeArray`. + * Since we do not record whether `AssociativeArray` manages keys like it + * does values - all keys will be deallocated, so use this parameter with + * caution. * @return Caller `AssociativeArray` to allow for method chaining. */ -public function Empty() +public function Empty(optional bool deallocateKeys) { local int i, j; local array nextEntries; @@ -439,9 +444,19 @@ public function Empty() if (nextEntries[j].value == none) continue; nextEntries[j].value.FreeSelf(nextEntries[j].valueLifeVersion); } + if (deallocateKeys) + { + for (j = 0; j < nextEntries.length; j += 1) + { + if (nextEntries[j].key != none) { + nextEntries[j].key.FreeSelf(nextEntries[j].keyLifeVersion); + } + } + } } hashTable.length = 0; storedElementCount = 0; + UpdateHashTableCapacity(); } /** @@ -458,7 +473,6 @@ public final function array GetKeys() local array nextEntry; for (i = 0; i < hashTable.length; i += 1) { - //hashTable[i] = CleanBucket(hashTable[i]); CleanBucket(hashTable[i]); nextEntry = hashTable[i].entries; for (j = 0; j < nextEntry.length; j += 1) { diff --git a/sources/Data/Collections/Tests/TEST_AssociativeArray.uc b/sources/Data/Collections/Tests/TEST_AssociativeArray.uc index 4a7710f..80a02e0 100644 --- a/sources/Data/Collections/Tests/TEST_AssociativeArray.uc +++ b/sources/Data/Collections/Tests/TEST_AssociativeArray.uc @@ -183,16 +183,39 @@ protected static function Test_CreateItem() protected static function Test_Empty() { + local AcediaObject key1, key2, key3; local AssociativeArray array; + key1 = __().text.FromString("key"); + key2 = __().box.int(13); + key3 = __().box.float(345.2); array = AssociativeArray(__().memory.Allocate(class'AssociativeArray')); + array.SetItem(key1, __().text.FromString("value")); + array.SetItem(key2, __().text.FromString("value #2"), true); + array.SetItem(key3, __().box.bool(true)); + Context("Testing `Empty()` method for `AssociativeArray`."); - array.SetItem(__().text.FromString("key"), __().text.FromString("value")); - array.SetItem(__().box.int(13), __().text.FromString("value #2")); - array.SetItem(__().box.float(345.2), __().box.bool(true)); Issue("`AssociativeArray` still contains elements after being emptied."); array.Empty(); TEST_ExpectTrue(array.GetKeys().length == 0); TEST_ExpectTrue(array.GetLength() == 0); + + Issue("`AssociativeArray` deallocated keys when not being told to do so."); + TEST_ExpectTrue(key1.IsAllocated()); + TEST_ExpectTrue(key2.IsAllocated()); + TEST_ExpectTrue(key3.IsAllocated()); + + Issue("`AssociativeArray` still contains elements after being emptied."); + array.SetItem(key1, __().text.FromString("value"), true); + array.SetItem(key2, __().text.FromString("value #2")); + array.SetItem(key3, __().box.bool(true), true); + array.Empty(true); + TEST_ExpectTrue(array.GetKeys().length == 0); + TEST_ExpectTrue(array.GetLength() == 0); + + Issue("`AssociativeArray` does not deallocate keys when told to do so."); + TEST_ExpectFalse(key1.IsAllocated()); + TEST_ExpectFalse(key2.IsAllocated()); + TEST_ExpectFalse(key3.IsAllocated()); } protected static function Test_Length()