diff --git a/sources/Aliases/AliasSource.uc b/sources/Aliases/AliasSource.uc
index 5a1e8a5..39f6aad 100644
--- a/sources/Aliases/AliasSource.uc
+++ b/sources/Aliases/AliasSource.uc
@@ -23,7 +23,7 @@
* along with Acedia. If not, see .
*/
class AliasSource extends Singleton
- dependson(AssociativeArray)
+ dependson(HashTable)
config(AcediaAliases);
// (Sub-)class of `Aliases` objects that this `AliasSource` uses to store
@@ -50,7 +50,7 @@ var private config array record;
// It contains same records as `record` array + aliases from
// `loadedAliasObjects` objects when there are no duplicate aliases.
// Otherwise only stores first loaded alias.
-var private AssociativeArray aliasHash;
+var private HashTable aliasHash;
var private LoggerAPI.Definition errIncorrectAliasPair, warnDuplicateAlias;
@@ -63,7 +63,7 @@ protected function OnCreated()
}
// Load and hash
loadedAliasObjects = aliasesClass.static.LoadAllObjects();
- aliasHash = _.collections.EmptyAssociativeArray();
+ aliasHash = _.collections.EmptyHashTable();
HashValidAliasesFromRecord();
HashValidAliasesFromPerObjectConfig();
}
@@ -125,8 +125,8 @@ private final function HashValidAliasesFromPerObjectConfig()
// in a case-insensitive way.
private final function InsertAlias(BaseText alias, BaseText value)
{
- local Text aliasLowerCaseCopy;
- local AssociativeArray.Entry hashEntry;
+ local Text aliasLowerCaseCopy;
+ local HashTable.Entry hashEntry;
if (alias == none) return;
if (value == none) return;
aliasLowerCaseCopy = alias.LowerCopy();
@@ -136,7 +136,8 @@ private final function InsertAlias(BaseText alias, BaseText value)
}
_.memory.Free(hashEntry.key);
_.memory.Free(hashEntry.value);
- aliasHash.SetItem(aliasLowerCaseCopy, value.Copy(), true);
+ aliasHash.SetItem(aliasLowerCaseCopy, value);
+ aliasLowerCaseCopy.FreeSelf();
}
/**
@@ -191,7 +192,7 @@ public function Text Resolve(BaseText alias, optional bool copyOnFailure)
result = Text(aliasHash.GetItem(lowerCaseAlias));
lowerCaseAlias.FreeSelf();
if (result != none) {
- return result.Copy();
+ return result;
}
if (copyOnFailure) {
return alias.Copy();
@@ -254,6 +255,8 @@ public final function bool AddAlias(
record[record.length] = newPair;
}
aliasHash.SetItem(lowerCaseAlias, aliasValue);
+ _.memory.Free(lowerCaseAlias);
+ _.memory.Free(aliasValue);
AliasService(class'AliasService'.static.Require()).PendingSaveSource(self);
return true;
}
@@ -275,10 +278,10 @@ public final function bool AddAlias(
*/
public final function RemoveAlias(BaseText aliasToRemove)
{
- local int i;
- local bool isMatchingRecord;
- local bool removedAliasFromRecord;
- local AssociativeArray.Entry hashEntry;
+ local int i;
+ local bool isMatchingRecord;
+ local bool removedAliasFromRecord;
+ local HashTable.Entry hashEntry;
if (aliasToRemove == none) {
return;
}
diff --git a/sources/Avarice/AvariceLink.uc b/sources/Avarice/AvariceLink.uc
index 23f7c57..4098a6e 100644
--- a/sources/Avarice/AvariceLink.uc
+++ b/sources/Avarice/AvariceLink.uc
@@ -68,7 +68,7 @@ var private SimpleSignal onDeathSignal;
// We want to have a separate signal for each message "service", since most
// users of `AvariceLink` would only care about one particular service.
// To achieve that we use this array as a "service name" <-> "signal" map.
-var private AssociativeArray serviceSignalMap;
+var private HashTable serviceSignalMap;
var private const int TSERVICE_PREFIX, TTYPE_PREFIX;
var private const int TPARAMS_PREFIX, TMESSAGE_SUFFIX;
@@ -80,7 +80,7 @@ protected function Constructor()
onConnectedSignal = SimpleSignal(_.memory.Allocate(class'SimpleSignal'));
onDisconnectedSignal = SimpleSignal(_.memory.Allocate(class'SimpleSignal'));
onDeathSignal = SimpleSignal(_.memory.Allocate(class'SimpleSignal'));
- serviceSignalMap = _.collections.EmptyAssociativeArray();
+ serviceSignalMap = _.collections.EmptyHashTable();
}
protected function Finalizer()
@@ -219,6 +219,7 @@ private final function Avarice_OnMessage_Signal GetServiceSignal(
result = Avarice_OnMessage_Signal(
_.memory.Allocate(class'Avarice_OnMessage_Signal'));
serviceSignalMap.SetItem(service, result);
+ _.memory.Free(result);
}
else {
service.FreeSelf();
diff --git a/sources/Avarice/AvariceMessage.uc b/sources/Avarice/AvariceMessage.uc
index 2655819..3d823d4 100644
--- a/sources/Avarice/AvariceMessage.uc
+++ b/sources/Avarice/AvariceMessage.uc
@@ -35,7 +35,7 @@ var public Text type;
// Value of the "p" field
var public AcediaObject parameters;
-var private AssociativeArray messageTemplate;
+var private HashTable messageTemplate;
var private const int TS, TT, TP;
@@ -44,7 +44,7 @@ public static function StaticConstructor()
if (StaticConstructorGuard()) return;
super.StaticConstructor();
- default.messageTemplate = __().collections.EmptyAssociativeArray();
+ default.messageTemplate = __().collections.EmptyHashTable();
ResetTemplate(default.messageTemplate);
}
@@ -58,7 +58,7 @@ protected function Finalizer()
parameters = none;
}
-private static final function ResetTemplate(AssociativeArray template)
+private static final function ResetTemplate(HashTable template)
{
if (template == none) {
return;
@@ -70,8 +70,8 @@ private static final function ResetTemplate(AssociativeArray template)
public final function MutableText ToText()
{
- local MutableText result;
- local AssociativeArray template;
+ local MutableText result;
+ local HashTable template;
if (type == none) return none;
if (service == none) return none;
diff --git a/sources/Avarice/AvariceTcpStream.uc b/sources/Avarice/AvariceTcpStream.uc
index b2bf80a..623c287 100644
--- a/sources/Avarice/AvariceTcpStream.uc
+++ b/sources/Avarice/AvariceTcpStream.uc
@@ -335,19 +335,19 @@ private final function AvariceMessage MessageFromText(BaseText message)
{
local Parser parser;
local AvariceMessage result;
- local AssociativeArray parsedMessage;
+ local HashTable parsedMessage;
local AcediaObject item;
if (message == none) {
return none;
}
parser = _.text.Parse(message);
- parsedMessage = _.json.ParseObjectWith(parser);
+ parsedMessage = _.json.ParseHashTableWith(parser);
parser.FreeSelf();
if (parsedMessage == none) {
return none;
}
result = AvariceMessage(_.memory.Allocate(class'AvariceMessage'));
- item = parsedMessage.TakeItem(keyS, true);
+ item = parsedMessage.TakeItem(keyS);
if (item == none || item.class != class'Text')
{
_.memory.Free(item);
@@ -356,7 +356,7 @@ private final function AvariceMessage MessageFromText(BaseText message)
return none;
}
result.service = Text(item);
- item = parsedMessage.TakeItem(keyT, true);
+ item = parsedMessage.TakeItem(keyT);
if (item == none || item.class != class'Text')
{
_.memory.Free(item);
@@ -365,7 +365,7 @@ private final function AvariceMessage MessageFromText(BaseText message)
return none;
}
result.type = Text(item);
- result.parameters = parsedMessage.TakeItem(keyP, true);
+ result.parameters = parsedMessage.TakeItem(keyP);
_.memory.Free(parsedMessage);
return result;
}
diff --git a/sources/BaseRealm/Iter.uc b/sources/BaseRealm/Iter.uc
index 425b7c2..ef21bdb 100644
--- a/sources/BaseRealm/Iter.uc
+++ b/sources/BaseRealm/Iter.uc
@@ -25,14 +25,9 @@ class Iter extends AcediaObject
* Makes iterator pick next item.
* Use `HasFinished()` to check whether you have iterated all of them.
*
- * @param skipNone @deprecated
- * Set this to `true` if you want to skip all stored
- * values that are equal to `none`. By default does not skip them.
- * Since order of iterating through items is not guaranteed, at each
- * `Next()` call an arbitrary set of items can be skipped.
* @return Reference to caller `Iterator` to allow for method chaining.
*/
-public function Iter Next(optional bool skipNone);
+public function Iter Next();
/**
* Returns current value pointed to by an iterator.
diff --git a/sources/Commands/BuiltInCommands/ACommandTest.uc b/sources/Commands/BuiltInCommands/ACommandTest.uc
index 299472a..7e29f87 100644
--- a/sources/Commands/BuiltInCommands/ACommandTest.uc
+++ b/sources/Commands/BuiltInCommands/ACommandTest.uc
@@ -28,8 +28,8 @@ protected function BuildData(CommandDataBuilder builder)
protected function Executed(Command.CallData result, EPlayer callerPlayer)
{
- local Parser parser;
- local AssociativeArray root;
+ local Parser parser;
+ local HashTable root;
/*local int i;
local WeaponLocker lol;
local array aaa;
@@ -63,7 +63,7 @@ protected function Executed(Command.CallData result, EPlayer callerPlayer)
}
}*/
parser = _.text.ParseString("{\"innerObject\":{\"my_bool\":true,\"array\":[\"Engine.Actor\",false,null,{\"something \\\"here\\\"\":\"yes\",\"maybe\":0.003},56.6],\"one more\":{\"nope\":324532,\"whatever\":false,\"o rly?\":\"ya rly\"},\"my_int\":-9823452},\"some_var\":-7.32,\"another_var\":\"aye!\"}");
- root = _.json.ParseObjectWith(parser);
+ root = _.json.ParseHashTableWith(parser);
callerPlayer.BorrowConsole().WriteLine(_.json.PrettyPrint(root));
}
diff --git a/sources/Data/Collections/ArrayList.uc b/sources/Data/Collections/ArrayList.uc
index 5c42634..9b8943d 100644
--- a/sources/Data/Collections/ArrayList.uc
+++ b/sources/Data/Collections/ArrayList.uc
@@ -95,7 +95,7 @@ protected final function ArrayList FreeItem(int index)
return self;
}
-public function Empty(optional bool deprecated)
+public function Empty()
{
SetLength(0);
}
@@ -1103,54 +1103,6 @@ public final function MutableText GetMutableText(int index)
return result;
}
-/**
- * Returns `AssociativeArray` item at `index`. If index is invalid or
- * stores a non-`AssociativeArray` value, returns `none`.
- *
- * Referred value must be stored as `AssociativeArray`
- * (or one of it's sub-classes) for this method to work.
- *
- * @param index Index of an `AssociativeArray` item that `ArrayList`
- * has to return.
- * @return `AssociativeArray` value at `index` in the caller `ArrayList`.
- * `none` if passed `index` is invalid or non-`AssociativeArray` value
- * is stored there.
- */
-public final function AssociativeArray GetAssociativeArray(int index)
-{
- local AssociativeArray result;
-
- result = AssociativeArray(BorrowItem(index));
- if (result != none) {
- result.NewRef();
- }
- return result;
-}
-
-/**
- * Returns `DynamicArray` item at `index`. If index is invalid or
- * stores a non-`DynamicArray` value, returns `none`.
- *
- * Referred value must be stored as `Text` (or one of it's sub-classes,
- * such as `MutableText`) for this method to work.
- *
- * @param index Index of a `DynamicArray` item that caller `ArrayList`
- * has to return.
- * @return `DynamicArray` value at `index` in the caller `ArrayList`.
- * `none` if passed `index` is invalid or non-`ArrayList` value
- * is stored there.
- */
-public final function DynamicArray GetDynamicArray(int index)
-{
- local DynamicArray result;
-
- result = DynamicArray(BorrowItem(index));
- if (result != none) {
- result.NewRef();
- }
- return result;
-}
-
/**
* Returns `ArrayList` item at `index`. If index is invalid or
* stores a non-`ArrayList` value, returns `none`.
diff --git a/sources/Data/Collections/ArrayListIterator.uc b/sources/Data/Collections/ArrayListIterator.uc
index 80cb1e0..233b9e0 100644
--- a/sources/Data/Collections/ArrayListIterator.uc
+++ b/sources/Data/Collections/ArrayListIterator.uc
@@ -47,7 +47,7 @@ public function Iter LeaveOnlyNotNone()
return self;
}
-public function Iter Next(optional bool deprecated)
+public function Iter Next()
{
local int collectionLength;
diff --git a/sources/Data/Collections/AssociativeArray.uc b/sources/Data/Collections/AssociativeArray.uc
deleted file mode 100644
index 5e6867a..0000000
--- a/sources/Data/Collections/AssociativeArray.uc
+++ /dev/null
@@ -1,1015 +0,0 @@
-/**
- * This class implements an associative array for storing arbitrary types
- * of data that provides a quick (near constant) access to *values* by
- * associated *keys*.
- * Since UnrealScript lacks any sort of templating, `AssociativeArray`
- * stores generic `AcediaObject` keys and values. `Text` can be used instead of
- * typical `string` keys and primitive values can be added in their boxed form
- * (either as actual `Box` or as it's reference counterpart).
- * Copyright 2020 - 2021 Anton Tarasenko
- *------------------------------------------------------------------------------
- * This file is part of Acedia.
- *
- * Acedia is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, version 3 of the License, or
- * (at your option) any later version.
- *
- * Acedia is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Acedia. If not, see .
- */
-class AssociativeArray extends Collection;
-
-// Defines key <-> value (with managed status) mapping.
-// Stores lifetime information to ensure that values were not reallocated
-// after being added to the collection.
-struct Entry
-{
- var public AcediaObject key;
- var protected int keyLifeVersion;
- var public AcediaObject value;
- var protected int valueLifeVersion;
- var public bool managed;
-};
-// Bucket of entries. Used to store entries with the same index in hash table.
-struct Bucket
-{
- var array entries;
-};
-var private array hashTable;
-// Amount of elements currently stored in this `AssociativeArray`.
-// If one of the keys was deallocated outside of `AssociativeArray`,
-// this value may overestimate actual amount of elements.
-var private int storedElementCount;
-// Lower limit on hash table capacity, can be changed by the user.
-var private int minimalCapacity;
-
-// hard lower and upper limits on hash table size, constant.
-var private const int MINIMUM_SIZE;
-var private const int MAXIMUM_SIZE;
-// Minimum and maximum allowed density of elements
-// (`storedElementCount / hashTable.length`).
-// If density falls outside this range, - we have to resize hash table to
-// get into (MINIMUM_DENSITY; MAXIMUM_DENSITY) bounds, as long as it does not
-// violate hard size restrictions.
-// Actual size changes in multipliers of 2, so
-// `MINIMUM_DENSITY * 2 < MAXIMUM_DENSITY` must hold or we will constantly
-// oscillate outside of (MINIMUM_DENSITY; MAXIMUM_DENSITY) bounds.
-var private const float MINIMUM_DENSITY;
-var private const float MAXIMUM_DENSITY;
-
-/**
- * Auxiliary struct, necessary to implement iterator for `AssociativeArray`.
- * Can be used for manual iteration, but should be avoided in favor of
- * `Iterator`.
- */
-struct Index
-{
- var protected int bucketIndex;
- var protected int entryIndex;
-};
-
-protected function Constructor()
-{
- UpdateHashTableSize();
-}
-
-protected function Finalizer()
-{
- Empty();
-}
-
-// Auxiliary method that is needed as a replacement for `%` module
-// operator, since it is an operation on `float`s in UnrealScript and does not
-// have appropriate value range to work with hashes.
-// Assumes non-negative input.
-private function int Remainder(int number, int divisor)
-{
- local int quotient;
- quotient = number / divisor;
- return (number - quotient * divisor);
-}
-
-// Calculates appropriate bucket index for the given key.
-// Assumes that given key is not `none` and is allocated.
-private final function int GetBucketIndex(AcediaObject key)
-{
- local int bucketIndex;
- bucketIndex = key.GetHashCode();
- if (bucketIndex < 0) {
- // Minimum `int` value is greater than maximum one in absolute value,
- // so shift it up to avoid overflow.
- bucketIndex = -1 * (bucketIndex + 1);
- }
- bucketIndex = Remainder(bucketIndex, hashTable.length);
- return bucketIndex;
-}
-
-// Accessing value in `AssociativeArray` requires:
-// 1. Two level lookup of both bucket and entry (inside that bucket)
-// indices;
-// 2. Lifetime checks to ensure no-one reallocated keys/values we
-// are using;
-// 3. Appropriate clean up o keys/values that were already deallocated.
-//
-// We spread the cost of the cleaning by pairing it with every bucket
-// access.
-// We only clean one (accessed) bucket per `FindEntryIndices()` and,
-// given that there isn't many hash collisions, this operation should not be
-// noticeably expensive.
-//
-// As a result returns bucket's and entry's indices in `bucketIndex` and
-// `entryIndex` out variables.
-// `bucketIndex` is guaranteed to be found for non-`none` keys,
-// `entryIndex` is valid iff method returns `true`, otherwise it's equal to
-// the index at which new property can get inserted.
-private final function bool FindEntryIndices(
- AcediaObject key,
- out int bucketIndex,
- out int entryIndex)
-{
- local int i;
- local array bucketEntries;
- if (key == none) return false;
- if (!key.IsAllocated()) return false;
-
- bucketIndex = GetBucketIndex(key);
- CleanBucket(hashTable[bucketIndex]);
- // Check if bucket actually has given key.
- bucketEntries = hashTable[bucketIndex].entries;
- for (i = 0; i < bucketEntries.length; i += 1)
- {
- if (key.IsEqual(bucketEntries[i].key))
- {
- entryIndex = i;
- return true;
- }
- }
- entryIndex = bucketEntries.length;
- return false;
-}
-
-// Cleans given bucket from entries with deallocated/reallocated
-// keys or values.
-private final function CleanBucket(out Bucket bucketToClean)
-{
- local int i;
- local Entry nextEntry;
- local array bucketEntries;
- bucketEntries = bucketToClean.entries;
- i = 0;
- while (i < bucketEntries.length)
- {
- nextEntry = bucketEntries[i];
- // If value was already reallocated - set it to `none`.
- if ( nextEntry.value != none
- && nextEntry.value.GetLifeVersion() != nextEntry.valueLifeVersion)
- {
- bucketEntries[i].value = none;
- }
- // If key was reallocated - it's value becomes essentially
- // inaccessible, so we deallocate it.
- // All keys, recorded in hash table, guaranteed to be `!= none`.
- if (nextEntry.key.GetLifeVersion() != nextEntry.keyLifeVersion)
- {
- if (bucketEntries[i].value != none && bucketEntries[i].managed) {
- bucketEntries[i].value.FreeSelf(nextEntry.valueLifeVersion);
- }
- bucketEntries.Remove(i, 1);
- // We'll update the count, but won't trigger hash table size update
- // to avoid making value's indices lookup more expensive, since
- // this method is used in `FindEntryIndices()`.
- storedElementCount = Max(0, storedElementCount - 1);
- continue;
- }
- i += 1;
- }
- bucketToClean.entries = bucketEntries;
-}
-
-// Checks if we need to change our current hash table size
-// and does so if needed
-private final function UpdateHashTableSize()
-{
- local int oldSize, newSize;
- oldSize = hashTable.length;
- // Calculate new size (and whether it is needed) based on amount of
- // stored properties and current size
- newSize = oldSize;
- if (storedElementCount < newSize * MINIMUM_DENSITY) {
- newSize /= 2;
- }
- else if (storedElementCount > newSize * MAXIMUM_DENSITY) {
- newSize *= 2;
- }
- // `table_density = items_amount / table_size`, so to store at least
- // `items_amount = minimalCapacity` without making table too dense we need
- // `table_size = minimalCapacity / MAXIMUM_DENSITY`.
- newSize = Max(newSize, Ceil(minimalCapacity / MAXIMUM_DENSITY));
- // But everything must fall into the set hard limits
- newSize = Clamp(newSize, MINIMUM_SIZE, MAXIMUM_SIZE);
- // Only resize if difference is huge enough or table does not exists yet
- if (newSize != oldSize) {
- ResizeHashTable(newSize);
- }
-}
-
-// Changes size of the hash table, does not check any limits,
-// does not check if `newSize` is a valid size (`newSize > 0`).
-private final function ResizeHashTable(int newSize)
-{
- local int i, j;
- local int newBucketIndex, newEntryIndex;
- local array bucketEntries;
- local array oldHashTable;
- oldHashTable = hashTable;
- // Clean current hash table
- hashTable.length = 0;
- hashTable.length = newSize;
- for (i = 0; i < oldHashTable.length; i += 1)
- {
- CleanBucket(oldHashTable[i]);
- bucketEntries = oldHashTable[i].entries;
- for (j = 0; j < bucketEntries.length; j += 1)
- {
- newBucketIndex = GetBucketIndex(bucketEntries[j].key);
- newEntryIndex = hashTable[newBucketIndex].entries.length;
- hashTable[newBucketIndex].entries[newEntryIndex] = bucketEntries[j];
- }
- }
-}
-
-/**
- * Returns minimal capacity of the caller associative array.
- *
- * See `SetMinimalCapacity()` for details.
- *
- * @return Minimal capacity of the caller associative array. Default is zero.
- */
-public final function int GetMinimalCapacity()
-{
- return minimalCapacity;
-}
-
-/**
- * Returns minimal capacity of the caller associative array.
- *
- * This associative array works like a hash table and needs to allocate
- * sufficiently large dynamic array as a storage for its items.
- * If you keep adding new items that storage will eventually become too small
- * for hash table to work efficiently and we will have to reallocate and
- * re-fill it. If you want to add a huge enough amount of items, this process
- * can be repeated several times.
- * This is not ideal, since it means doing a lot of iteration, each
- * increasing infinite loop counter (game will crash if it gets high enough).
- * Setting minimal capacity to the (higher) amount of items you expect to
- * store in the caller array can remove the need for reallocating the storage.
- *
- * @param newMinimalCapacity New minimal capacity of this associative array.
- * It's recommended to set it to the max amount of items you expect to
- * store in this associative array
- * (you will be still allowed to store more).
- */
-public final function SetMinimalCapacity(int newMinimalCapacity)
-{
- minimalCapacity = newMinimalCapacity;
- UpdateHashTableSize();
-}
-
-/**
- * Checks if caller `AssociativeArray` has value recorded with a given `key`.
- *
- * @return `true` if caller `AssociativeArray` has value recorded with
- * a given `key` and `false` otherwise.
- */
-public final function bool HasKey(AcediaObject key)
-{
- local int bucketIndex, entryIndex;
- return FindEntryIndices(key, bucketIndex, entryIndex);
-}
-
-/**
- * Checks if caller `AssociativeArray`'s value recorded with a given `key`
- * is managed.
- *
- * Managed values will be automatically deallocated once they are removed
- * (or overwritten) from the caller `AssociativeArray`.
- *
- * @return `true` if value recorded with a given `key` is managed
- * and `false` otherwise;
- * if value is missing (`none` or there is not entry for the `key`),
- * returns `false`.
- */
-public final function bool IsManaged(AcediaObject key)
-{
- local int bucketIndex, entryIndex;
- if (FindEntryIndices(key, bucketIndex, entryIndex)) {
- return hashTable[bucketIndex].entries[entryIndex].managed;
- }
- return false;
-}
-
-/**
- * Returns value recorded by a given key `key` in the caller
- * `AssociativeArray`.
- *
- * Can return `none` if either stored values is `none` or there's no value
- * recorded with a `key`. To check whether there is a record, corresponding to
- * the `key` use `HasKey()` method.
- *
- * @param key Key for which to return value.
- * @return Value, stored with given key `key`. If there is no value with
- * such a key method will return `none`.
- */
-public final function AcediaObject GetItem(AcediaObject key)
-{
- local int bucketIndex, entryIndex;
- if (FindEntryIndices(key, bucketIndex, entryIndex)) {
- return hashTable[bucketIndex].entries[entryIndex].value;
- }
- return none;
-}
-
-/**
- * Returns entry corresponding to a given key `key` in the caller
- * `AssociativeArray`.
- *
- * @param key Key for which to return entry.
- * @return Entry (key/value pair + indicator of whether values was managed
- * by `AssociativeArray`) with the given key `key`.
- */
-public final function Entry GetEntry(AcediaObject key)
-{
- local Entry emptyEntry;
- local int bucketIndex, entryIndex;
- if (!FindEntryIndices(key, bucketIndex, entryIndex)) {
- return emptyEntry;
- }
- return hashTable[bucketIndex].entries[entryIndex];
-}
-
-/**
- * Returns entry corresponding to a given key `key` in the caller
- * `AssociativeArray`, removing it from the caller `AssociativeArray`.
- *
- * Returned value is no longer managed by the `AssociativeArray` (if it was)
- * and must be deallocated once you do not need them anymore.
- *
- * @param key Key for which to return entry.
- * @return Entry (key/value pair + indicator of whether values was managed
- * by `AssociativeArray`) with the given key `key`.
- */
-public final function Entry TakeEntry(AcediaObject key)
-{
- local Entry entryToTake;
- local int bucketIndex, entryIndex;
- if (!FindEntryIndices(key, bucketIndex, entryIndex)) {
- return entryToTake;
- }
- entryToTake = hashTable[bucketIndex].entries[entryIndex];
- hashTable[bucketIndex].entries.Remove(entryIndex, 1);
- storedElementCount = Max(0, storedElementCount - 1);
- UpdateHashTableSize();
- return entryToTake;
-}
-
-/**
- * Returns value recorded with a given key `key` in the caller
- * `AssociativeArray`, removing it from the collection.
- *
- * Returned value is no longer managed by the `AssociativeArray` (if it was)
- * and must be deallocated once you do not need it anymore.
- *
- * @param key Key for which to return value.
- * @param freeKey Setting this to `true` will also free the key item was
- * stored with. Passed argument `key` will not be deallocated, unless it is
- * the exact same object as item's key inside caller collection.
- * @return Value, stored with given key `key`. If there is no value with
- * such a key method will return `none`.
- */
-public final function AcediaObject TakeItem(
- AcediaObject key,
- optional bool freeKey)
-{
- local Entry entry;
- entry = TakeEntry(key);
- if (freeKey) {
- _.memory.Free(entry.key);
- }
- return entry.value;
-}
-
-/**
- * Records new `value` under the key `key` into the caller `AssociativeArray`.
- *
- * If this will override already existing managed record - old value will
- * be automatically deallocated (unless they are the same object as a new one).
- * If you wish to avoid this behavior - retrieve them with either of
- * `TakeItem()` or `TakeEntry()` methods first.
- *
- * @param key Key by which new value will be referred to.
- * @param value Value to store in the caller `AssociativeArray`.
- * @return Caller `AssociativeArray` to allow for method chaining.
- */
-public final function AssociativeArray SetItem(
- AcediaObject key,
- AcediaObject value,
- optional bool managed)
-{
- local Entry oldEntry, newEntry;
- local int bucketIndex, entryIndex;
- if (key == none) {
- return self;
- }
- if (FindEntryIndices(key, bucketIndex, entryIndex)) {
- oldEntry = hashTable[bucketIndex].entries[entryIndex];
- }
- else {
- storedElementCount += 1;
- }
- newEntry.key = key;
- newEntry.keyLifeVersion = key.GetLifeVersion();
- newEntry.managed = managed;
- newEntry.value = value;
- if (value != none) {
- newEntry.valueLifeVersion = value.GetLifeVersion();
- }
- if ( oldEntry.managed && oldEntry.value != none
- && newEntry.value != oldEntry.value)
- {
- oldEntry.value.FreeSelf(oldEntry.valueLifeVersion);
- }
- hashTable[bucketIndex].entries[entryIndex] = newEntry;
- return self;
-}
-
-/**
- * Creates a new instance of class `valueClass` and records it's value with
- * key `key` in the caller `AssociativeArray`. Value is recorded as managed.
- *
- * @param key Key by which new value will be referred to.
- * @param valueClass Class of object to create. Will only be created if
- * passed `key` is valid.
- * @return Caller `AssociativeArray` to allow for method chaining.
- */
-public final function AssociativeArray CreateItem(
- AcediaObject key,
- class valueClass)
-{
- if (key == none) return self;
- if (valueClass == none) return self;
-
- return SetItem(key, AcediaObject(_.memory.Allocate(valueClass)), true);
-}
-
-/**
- * Removes a value recorded with a given key `key`.
- * Does nothing if entry with a given key does not exist.
- *
- * Removed values are deallocated if they are managed. If you wish to avoid
- * that, use `TakeItem()` or `TakeEntry()` methods.
- *
- * @param key Key for which to remove value.
- * @param deallocateKey Should key be also deallocated?
- * @return Caller `AssociativeArray` to allow for method chaining.
- */
-public final function AssociativeArray RemoveItem(
- AcediaObject key,
- optional bool deallocateKey)
-{
- local Entry entryToRemove;
- local int bucketIndex, entryIndex;
- if (key == none) return self;
-
- if (!FindEntryIndices(key, bucketIndex, entryIndex)) {
- return self;
- }
- entryToRemove = hashTable[bucketIndex].entries[entryIndex];
- hashTable[bucketIndex].entries.Remove(entryIndex, 1);
- storedElementCount = Max(0, storedElementCount - 1);
- UpdateHashTableSize();
- if (entryToRemove.managed && entryToRemove.value != none) {
- entryToRemove.value.FreeSelf(entryToRemove.valueLifeVersion);
- }
- if (deallocateKey && entryToRemove.key != none) {
- entryToRemove.key.FreeSelf(entryToRemove.keyLifeVersion);
- }
- return self;
-}
-
-public function Empty(optional bool deallocateKeys)
-{
- local int i, j;
- local Collection subCollection;
- local array nextEntries;
- for (i = 0; i < hashTable.length; i += 1)
- {
- nextEntries = hashTable[i].entries;
- for (j = 0; j < nextEntries.length; j += 1)
- {
- if (!nextEntries[j].managed) continue;
- 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) {
- continue;
- }
- if ( nextEntries[j].key.GetLifeVersion()
- != nextEntries[j].keyLifeVersion) {
- continue;
- }
- subCollection = Collection(nextEntries[j].value);
- if (subCollection != none) {
- subCollection.Empty(true);
- }
- if (nextEntries[j].key != none) {
- nextEntries[j].key.FreeSelf(nextEntries[j].keyLifeVersion);
- }
- }
- }
- }
- hashTable.length = 0;
- storedElementCount = 0;
- UpdateHashTableSize();
-}
-
-/**
- * Returns key of all properties inside caller `AssociativeArray`.
- *
- * Collecting all keys from the `AssociativeArray` is O().
- *
- * See also `CopyTextKeys()` methods.
- *
- * @return Array of all the caller `AssociativeArray`'s keys.
- * This method does not return copies of keys, but actual keys instead -
- * deallocating them will remove their item from
- * the caller `AssociativeArray`.
- */
-public final function array GetKeys()
-{
- local int i, j;
- local array result;
- local array nextEntry;
- for (i = 0; i < hashTable.length; i += 1)
- {
- CleanBucket(hashTable[i]);
- nextEntry = hashTable[i].entries;
- for (j = 0; j < nextEntry.length; j += 1) {
- result[result.length] = nextEntry[j].key;
- }
- }
- return result;
-}
-
-/**
- * Returns copies of `Text` key of all properties inside caller
- * `AssociativeArray`. Keys that have a different class (even if they are
- * a child class for `Text`) are not returned.
- *
- * This method exists to provide alternative to `GetKeys()` method that would
- * return copies of keys instead of actually used references: we cannot make
- * a copy of an arbitrary `AcediaObject`, but we can of `Text`.
- * Which is also a most common type for the keys.
- *
- * Collecting all keys from the `AssociativeArray` is O().
- *
- * @return Array of all the caller `AssociativeArray`'s keys that have exactly
- * `Text` class.
- */
-public final function array CopyTextKeys()
-{
- local int i, j;
- local Text nextKeyAsText;
- local array result;
- local array nextEntry;
- for (i = 0; i < hashTable.length; i += 1)
- {
- CleanBucket(hashTable[i]);
- nextEntry = hashTable[i].entries;
- for (j = 0; j < nextEntry.length; j += 1)
- {
- nextKeyAsText = Text(nextEntry[j].key);
- if (nextKeyAsText != none && nextKeyAsText.class == class'Text')
- {
- result[result.length] = nextKeyAsText.Copy();
- }
- }
- }
- return result;
-}
-
-/**
- * Returns amount of elements in the caller `AssociativeArray`.
- *
- * Note that this value might overestimate real amount of values inside
- * `AssociativeArray` in case some of the keys used for storage were
- * deallocated by code outside of `AssociativeArray`.
- * Such values might be eventually found and removed, but
- * `AssociativeArray` does not provide any guarantees on when it's done.
- */
-public final function int GetLength()
-{
- return storedElementCount;
-}
-
-/**
- * Auxiliary method for iterator that increments given `Index` structure.
- *
- * @param previousIndex Index to increment.
- * @return `true` if incremented index is pointing at a valid item,
- * `false` if collection has ended.
- */
-public final function bool IncrementIndex(out Index previousIndex)
-{
- previousIndex.entryIndex += 1;
- // Go forward through buckets until we find non-empty one
- while (previousIndex.bucketIndex < hashTable.length)
- {
- CleanBucket(hashTable[previousIndex.bucketIndex]);
- if ( previousIndex.entryIndex
- < hashTable[previousIndex.bucketIndex].entries.length)
- {
- return true;
- }
- previousIndex.entryIndex = 0;
- previousIndex.bucketIndex += 1;
- }
- return false;
-}
-
-/**
- * Auxiliary method for iterator that returns value corresponding to
- * a given `Index` structure.
- *
- * @param index Index of item to return.
- * @return `Entry` corresponding to a given index. If index is invalid
- * (not pointing at any value for caller `AssociativeArray`) returns
- * `Entry` with key and value set to `none`.
- * Note that `none` can be returned because that is simply the value
- * being stored.
- */
-public final function Entry GetEntryByIndex(Index index)
-{
- local Entry emptyEntry;
- if (index.bucketIndex < 0) return emptyEntry;
- if (index.bucketIndex >= hashTable.length) return emptyEntry;
- if ( index.entryIndex < 0
- || index.entryIndex >= hashTable[index.bucketIndex].entries.length) {
- return emptyEntry;
- }
- return hashTable[index.bucketIndex].entries[index.entryIndex];
-}
-
-protected function AcediaObject GetByText(BaseText key)
-{
- return GetItem(key);
-}
-
-/**
- * Returns `bool` item at key `key`. If key is invalid or
- * stores a non-`bool` value, returns `defaultValue`.
- *
- * Referred value must be stored as `BoolBox` or `BoolRef`
- * (or one of their sub-classes) for this method to work.
- *
- * @param key Key of a `bool` item that `AssociativeArray`
- * has to return.
- * @param defaultValue Value to return if there is either no item recorded
- * at `key` or it has a wrong type.
- * @return `bool` value at `key` in the caller `AssociativeArray`.
- * `defaultValue` if passed `key` is invalid or non-`bool` value
- * is stored with it.
- */
-public final function bool GetBool(AcediaObject key, optional bool defaultValue)
-{
- local AcediaObject result;
- local BoolBox asBox;
- local BoolRef asRef;
- result = GetItem(key);
- if (result == none) {
- return defaultValue;
- }
- asBox = BoolBox(result);
- if (asBox != none) {
- return asBox.Get();
- }
- asRef = BoolRef(result);
- if (asRef != none) {
- return asRef.Get();
- }
- return defaultValue;
-}
-
-/**
- * Changes `AssociativeArray`'s value at key `key` to `value` that will be
- * recorded as either `BoolBox` or `BoolRef`, depending of `asRef`
- * optional parameter.
- *
- * Inserted value will always be recorded as a managed value, i.e. it will be
- * automatically deallocated when overwritten, removed or
- * caller `AssociativeArray` is deallocated.
- *
- * @param key Key, at which to change the value. If `DynamicArray` is
- * not long enough to hold it, it will be automatically expanded.
- * If passed key is negative - method will do nothing.
- * @param value Value to be set at a given key.
- * @param asRef Given `bool` value will be recorded as immutable `BoolBox`
- * by default (`asRef == false`). Setting this parameter to `true` will
- * make this method record it as a mutable `BoolRef`.
- * @return Reference to the caller `AssociativeArray` to allow for
- * method chaining.
- */
-public final function AssociativeArray SetBool(
- AcediaObject key,
- bool value,
- optional bool asRef)
-{
- if (asRef) {
- SetItem(key, _.ref.bool(value), true);
- }
- else {
- SetItem(key, _.box.bool(value), true);
- }
- return self;
-}
-
-/**
- * Returns `byte` item at key `key`. If key is invalid or
- * stores a non-`byte` value, returns `defaultValue`.
- *
- * Referred value must be stored as `ByteBox` or `ByteBox`
- * (or one of their sub-classes) for this method to work.
- *
- * @param key Key of a `byte` item that `AssociativeArray`
- * has to return.
- * @param defaultValue Value to return if there is either no item recorded
- * at `key` or it has a wrong type.
- * @return `byte` value at `key` in the caller `AssociativeArray`.
- * `defaultValue` if passed `key` is invalid or non-`byte` value
- * is stored with it.
- */
-public final function byte GetByte(AcediaObject key, optional byte defaultValue)
-{
- local AcediaObject result;
- local ByteBox asBox;
- local ByteRef asRef;
- result = GetItem(key);
- if (result == none) {
- return defaultValue;
- }
- asBox = ByteBox(result);
- if (asBox != none) {
- return asBox.Get();
- }
- asRef = ByteRef(result);
- if (asRef != none) {
- return asRef.Get();
- }
- return defaultValue;
-}
-
-/**
- * Changes `AssociativeArray`'s value at key `key` to `value` that will be
- * recorded as either `ByteBox` or `ByteBox`, depending of `asRef`
- * optional parameter.
- *
- * Inserted value will always be recorded as a managed value, i.e. it will be
- * automatically deallocated when overwritten, removed or
- * caller `AssociativeArray` is deallocated.
- *
- * @param key Key, at which to change the value. If `DynamicArray` is
- * not long enough to hold it, it will be automatically expanded.
- * If passed key is negative - method will do nothing.
- * @param value Value to be set at a given key.
- * @param asRef Given `byte` value will be recorded as immutable `ByteBox`
- * by default (`asRef == false`). Setting this parameter to `true` will
- * make this method record it as a mutable `ByteBox`.
- * @return Reference to the caller `AssociativeArray` to allow for
- * method chaining.
- */
-public final function AssociativeArray SetByte(
- AcediaObject key,
- byte value,
- optional bool asRef)
-{
- if (asRef) {
- SetItem(key, _.ref.byte(value), true);
- }
- else {
- SetItem(key, _.box.byte(value), true);
- }
- return self;
-}
-
-/**
- * Returns `int` item at key `key`. If key is invalid or
- * stores a non-`int` value, returns `defaultValue`.
- *
- * Referred value must be stored as `IntBox` or `IntRef`
- * (or one of their sub-classes) for this method to work.
- *
- * @param key Key of a `int` item that `AssociativeArray`
- * has to return.
- * @param defaultValue Value to return if there is either no item recorded
- * at `key` or it has a wrong type.
- * @return `int` value at `key` in the caller `AssociativeArray`.
- * `defaultValue` if passed `key` is invalid or non-`int` value
- * is stored with it.
- */
-public final function int GetInt(AcediaObject key, optional int defaultValue)
-{
- local AcediaObject result;
- local IntBox asBox;
- local IntRef asRef;
- result = GetItem(key);
- if (result == none) {
- return defaultValue;
- }
- asBox = IntBox(result);
- if (asBox != none) {
- return asBox.Get();
- }
- asRef = IntRef(result);
- if (asRef != none) {
- return asRef.Get();
- }
- return defaultValue;
-}
-
-/**
- * Changes `AssociativeArray`'s value at key `key` to `value` that will be
- * recorded as either `IntBox` or `IntRef`, depending of `asRef`
- * optional parameter.
- *
- * Inserted value will always be recorded as a managed value, i.e. it will be
- * automatically deallocated when overwritten, removed or
- * caller `AssociativeArray` is deallocated.
- *
- * @param key Key, at which to change the value. If `DynamicArray` is
- * not long enough to hold it, it will be automatically expanded.
- * If passed key is negative - method will do nothing.
- * @param value Value to be set at a given key.
- * @param asRef Given `int` value will be recorded as immutable `IntBox`
- * by default (`asRef == false`). Setting this parameter to `true` will
- * make this method record it as a mutable `IntRef`.
- * @return Reference to the caller `AssociativeArray` to allow for
- * method chaining.
- */
-public final function AssociativeArray SetInt(
- AcediaObject key,
- int value,
- optional bool asRef)
-{
- if (asRef) {
- SetItem(key, _.ref.int(value), true);
- }
- else {
- SetItem(key, _.box.int(value), true);
- }
- return self;
-}
-
-/**
- * Returns `float` item at key `key`. If key is invalid or
- * stores a non-`float` value, returns `defaultValue`.
- *
- * Referred value must be stored as `FloatBox` or `FloatRef`
- * (or one of their sub-classes) for this method to work.
- *
- * @param key Key of a `float` item that `AssociativeArray`
- * has to return.
- * @param defaultValue Value to return if there is either no item recorded
- * at `key` or it has a wrong type.
- * @return `float` value at `key` in the caller `AssociativeArray`.
- * `defaultValue` if passed `key` is invalid or non-`float` value
- * is stored with it.
- */
-public final function float GetFloat(
- AcediaObject key,
- optional float defaultValue)
-{
- local AcediaObject result;
- local FloatBox asBox;
- local FloatRef asRef;
- result = GetItem(key);
- if (result == none) {
- return defaultValue;
- }
- asBox = FloatBox(result);
- if (asBox != none) {
- return asBox.Get();
- }
- asRef = FloatRef(result);
- if (asRef != none) {
- return asRef.Get();
- }
- return defaultValue;
-}
-
-/**
- * Changes `AssociativeArray`'s value at key `key` to `value` that will be
- * recorded as either `FloatBox` or `FloatRef`, depending of `asRef`
- * optional parameter.
- *
- * Inserted value will always be recorded as a managed value, i.e. it will be
- * automatically deallocated when overwritten, removed or
- * caller `AssociativeArray` is deallocated.
- *
- * @param key Key, at which to change the value. If `DynamicArray` is
- * not long enough to hold it, it will be automatically expanded.
- * If passed key is negative - method will do nothing.
- * @param value Value to be set at a given key.
- * @param asRef Given `float` value will be recorded as immutable `FloatBox`
- * by default (`asRef == false`). Setting this parameter to `true` will
- * make this method record it as a mutable `FloatRef`.
- * @return Reference to the caller `AssociativeArray` to allow for
- * method chaining.
- */
-public final function AssociativeArray SetFloat(
- AcediaObject key,
- float value,
- optional bool asRef)
-{
- if (asRef) {
- SetItem(key, _.ref.float(value), true);
- }
- else {
- SetItem(key, _.box.float(value), true);
- }
- return self;
-}
-
-/**
- * Returns `Text` item stored at key `key`. If key is invalid or
- * stores a non-`Text` value, returns `none`.
- *
- * Referred value must be stored as `Text` (or one of it's sub-classes,
- * such as `MutableText`) for this method to work.
- *
- * @param key Key of a `Text` item that `AssociativeArray`
- * has to return.
- * @return `Text` value recorded with `key` in the caller `AssociativeArray`.
- * `none` if passed `key` is invalid or non-`Text` value
- * is stored with it.
- */
-public final function Text GetText(AcediaObject key)
-{
- return Text(GetItem(key));
-}
-
-/**
- * Returns `AssociativeArray` item stored at key `key`. If key is invalid or
- * stores a non-`AssociativeArray` value, returns `none`.
- *
- * Referred value must be stored as `AssociativeArray`
- * (or one of it's sub-classes) for this method to work.
- *
- * @param key Key of an `AssociativeArray` item that caller `AssociativeArray`
- * has to return.
- * @return `AssociativeArray` value recorded with `key` in the caller
- * `AssociativeArray`. `none` if passed `key` is invalid or
- * non-`AssociativeArray` value is stored with it.
- */
-public final function AssociativeArray GetAssociativeArray(AcediaObject key)
-{
- return AssociativeArray(GetItem(key));
-}
-
-/**
- * Returns `DynamicArray` item stored at key `key`. If key is invalid or
- * stores a non-`DynamicArray` value, returns `none`.
- *
- * Referred value must be stored as `DynamicArray`
- * (or one of it's sub-classes) for this method to work.
- *
- * @param key Key of a `DynamicArray` item that caller `AssociativeArray`
- * has to return.
- * @return `AssociativeArray` value recorded with `key` in the caller
- * `AssociativeArray`. `none` if passed `key` is invalid or
- * non-`AssociativeArray` value is stored with it.
- */
-public final function DynamicArray GetDynamicArray(AcediaObject key)
-{
- return DynamicArray(GetItem(key));
-}
-
-defaultproperties
-{
- iteratorClass = class'AssociativeArrayIterator'
- minimalCapacity = 0
- MINIMUM_SIZE = 50
- MAXIMUM_SIZE = 20000
- // `MINIMUM_DENSITY * 2 < MAXIMUM_DENSITY` must hold for `AssociativeArray`
- // to work properly
- MINIMUM_DENSITY = 0.25
- MAXIMUM_DENSITY = 0.75
-}
\ No newline at end of file
diff --git a/sources/Data/Collections/AssociativeArrayIterator.uc b/sources/Data/Collections/AssociativeArrayIterator.uc
deleted file mode 100644
index 9e7ac77..0000000
--- a/sources/Data/Collections/AssociativeArrayIterator.uc
+++ /dev/null
@@ -1,83 +0,0 @@
-/**
- * Iterator for iterating over `AssociativeArray`'s items.
- * Copyright 2020 Anton Tarasenko
- *------------------------------------------------------------------------------
- * This file is part of Acedia.
- *
- * Acedia is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, version 3 of the License, or
- * (at your option) any later version.
- *
- * Acedia is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Acedia. If not, see .
- */
-class AssociativeArrayIterator extends CollectionIterator
- dependson(AssociativeArray);
-
-var private bool hasNotFinished;
-var private AssociativeArray relevantCollection;
-var private AssociativeArray.Index currentIndex;
-
-protected function Finalizer()
-{
- relevantCollection = none;
-}
-
-public function bool Initialize(Collection relevantArray)
-{
- local AssociativeArray.Index emptyIndex;
- currentIndex = emptyIndex;
- relevantCollection = AssociativeArray(relevantArray);
- if (relevantCollection == none) {
- return false;
- }
- hasNotFinished = (relevantCollection.GetLength() > 0);
- if (GetKey() == none) {
- relevantCollection.IncrementIndex(currentIndex);
- }
- return true;
-}
-
-public function Iter Next(optional bool skipNone)
-{
- local int collectionLength;
- if (!skipNone)
- {
- hasNotFinished = relevantCollection.IncrementIndex(currentIndex);
- return self;
- }
- collectionLength = relevantCollection.GetLength();
- while (hasNotFinished)
- {
- hasNotFinished = relevantCollection.IncrementIndex(currentIndex);
- if (relevantCollection.GetEntryByIndex(currentIndex).value != none) {
- return self;
- }
- }
- return self;
-}
-
-public function AcediaObject Get()
-{
- return relevantCollection.GetEntryByIndex(currentIndex).value;
-}
-
-public function AcediaObject GetKey()
-{
- return relevantCollection.GetEntryByIndex(currentIndex).key;
-}
-
-public function bool HasFinished()
-{
- return !hasNotFinished;
-}
-
-defaultproperties
-{
-}
\ No newline at end of file
diff --git a/sources/Data/Collections/Collection.uc b/sources/Data/Collections/Collection.uc
index 8df12be..f5a98a0 100644
--- a/sources/Data/Collections/Collection.uc
+++ b/sources/Data/Collections/Collection.uc
@@ -29,11 +29,11 @@ var protected class iteratorClass;
*
* This method must return an item that `key` refers to with it's
* textual content (not as an object itself).
- * For example, `DynamicArray` parses it into unsigned number, while
- * `AssociativeArray` uses it as a key directly.
+ * For example, `ArrayList` parses it into unsigned number, while
+ * `HashTable` uses it as a key directly.
*
* There is no requirement that all stored values must be reachable by
- * this method (i.e. `AssociativeArray` only lets you access values with
+ * this method (i.e. `HashTable` only lets you access values with
* `Text` keys).
*/
protected function AcediaObject GetByText(BaseText key);
@@ -64,28 +64,18 @@ public final function CollectionIterator Iterate()
/**
* Completely clears caller `Collections` 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 `Collection`, if it uses them.
- * If this parameter is set to `true`, then `Empty()` call will also be
- * made recursively for all stored `Collection`, also causing them to
- * deallocate their keys.
- * For Acedia keys are only used by `AssociativeArray`.
- * Since we do not record whether `Collection` manages keys like it
- * does values - all keys will be deallocated, so use this parameter with
- * caution.
*/
-public function Empty(optional bool deallocateKeys) {}
+public function Empty() {}
/**
* Returns stored `AcediaObject` from the caller storage
* (or from it's sub-storages) via given `JSONPointer` path.
*
* Acedia provides two collections:
- * 1. `DynamicArray` is treated as a JSON array in the context of
+ * 1. `ArrayList` is treated as a JSON array in the context of
* JSON pointers and passed variable names are treated as a `Text`
* representation of it's integer indices;
- * 2. `AssociativeArray` is treated as a JSON object in the context of
+ * 2. `HashTable` is treated as a JSON object in the context of
* JSON pointers and passed variable names are treated as it's
* `Text` keys (to refer to an element with an empty key, use "/",
* since "" is treated as a JSON pointer and refers to
@@ -95,8 +85,7 @@ public function Empty(optional bool deallocateKeys) {}
* appropriately defining `GetByText()` protected method.
*
* There is no requirement that all stored values must be reachable by
- * this method (i.e. `AssociativeArray` only lets you access values with
- * `Text` keys).
+ * this method (i.e. `HashTable` only lets you access values with `Text` keys).
*
* @param jsonPointer Path, given by a JSON pointer.
* @return An item `jsonPointerAsText` is referring to (according to the above
@@ -106,16 +95,23 @@ public final function AcediaObject GetItemByJSON(JSONPointer jsonPointer)
{
local int segmentIndex;
local Text nextSegment;
- local AcediaObject result;
- local Collection nextCollection;
+ local AcediaObject result, nextObject;
+ local Collection prevCollection, nextCollection;
if (jsonPointer == none) return none;
if (jsonPointer.GetLength() < 1) return self;
nextCollection = self;
+ nextCollection.NewRef();
while (segmentIndex < jsonPointer.GetLength() - 1)
{
nextSegment = jsonPointer.GetComponent(segmentIndex);
- nextCollection = Collection(nextCollection.GetByText(nextSegment));
+ prevCollection = nextCollection;
+ nextObject = nextCollection.GetByText(nextSegment);
+ nextCollection = Collection(nextObject);
+ _.memory.Free(prevCollection);
+ if (nextCollection == none) {
+ _.memory.Free(nextObject);
+ }
_.memory.Free(nextSegment);
if (nextCollection == none) {
break;
@@ -147,10 +143,10 @@ public final function AcediaObject GetItemByJSON(JSONPointer jsonPointer)
* collection itself).
*
* Acedia provides two collections:
- * 1. `DynamicArray` is treated as a JSON array in the context of
+ * 1. `ArrayList` is treated as a JSON array in the context of
* JSON pointers and passed variable names are treated as a `Text`
* representation of it's integer indices;
- * 2. `AssociativeArray` is treated as a JSON object in the context of
+ * 2. `HashTable` is treated as a JSON object in the context of
* JSON pointers and passed variable names are treated as it's
* `Text` keys (to refer to an element with an empty key, use "/",
* since "" is treated as a JSON pointer and refers to
@@ -160,7 +156,7 @@ public final function AcediaObject GetItemByJSON(JSONPointer jsonPointer)
* appropriately defining `GetByText()` protected method.
*
* There is no requirement that all stored values must be reachable by
- * this method (i.e. `AssociativeArray` only lets you access values with
+ * this method (i.e. `HashTable` only lets you access values with
* `Text` keys).
*
* @param jsonPointer Path, given by a JSON pointer.
@@ -200,22 +196,26 @@ public final function bool GetBoolBy(
BaseText jsonPointerAsText,
optional bool defaultValue)
{
- local AcediaObject result;
+ local bool result;
+ local AcediaObject resultObject;
local BoolBox asBox;
local BoolRef asRef;
- result = GetItemBy(jsonPointerAsText);
- if (result == none) {
+
+ resultObject = GetItemBy(jsonPointerAsText);
+ if (resultObject == none) {
return defaultValue;
}
- asBox = BoolBox(result);
+ result = defaultValue;
+ asBox = BoolBox(resultObject);
if (asBox != none) {
- return asBox.Get();
+ result = asBox.Get();
}
- asRef = BoolRef(result);
+ asRef = BoolRef(resultObject);
if (asRef != none) {
- return asRef.Get();
+ result = asRef.Get();
}
- return defaultValue;
+ _.memory.Free(resultObject);
+ return result;
}
/**
@@ -238,22 +238,26 @@ public final function byte GetByteBy(
BaseText jsonPointerAsText,
optional byte defaultValue)
{
- local AcediaObject result;
+ local byte result;
+ local AcediaObject resultObject;
local ByteBox asBox;
local ByteRef asRef;
- result = GetItemBy(jsonPointerAsText);
- if (result == none) {
+
+ resultObject = GetItemBy(jsonPointerAsText);
+ if (resultObject == none) {
return defaultValue;
}
- asBox = ByteBox(result);
+ result = defaultValue;
+ asBox = ByteBox(resultObject);
if (asBox != none) {
- return asBox.Get();
+ result = asBox.Get();
}
- asRef = ByteRef(result);
+ asRef = ByteRef(resultObject);
if (asRef != none) {
- return asRef.Get();
+ result = asRef.Get();
}
- return defaultValue;
+ _.memory.Free(resultObject);
+ return result;
}
/**
@@ -276,22 +280,26 @@ public final function int GetIntBy(
BaseText jsonPointerAsText,
optional int defaultValue)
{
- local AcediaObject result;
+ local int result;
+ local AcediaObject resultObject;
local IntBox asBox;
local IntRef asRef;
- result = GetItemBy(jsonPointerAsText);
- if (result == none) {
+
+ resultObject = GetItemBy(jsonPointerAsText);
+ if (resultObject == none) {
return defaultValue;
}
- asBox = IntBox(result);
+ result = defaultValue;
+ asBox = IntBox(resultObject);
if (asBox != none) {
- return asBox.Get();
+ result = asBox.Get();
}
- asRef = IntRef(result);
+ asRef = IntRef(resultObject);
if (asRef != none) {
- return asRef.Get();
+ result = asRef.Get();
}
- return defaultValue;
+ _.memory.Free(resultObject);
+ return result;
}
/**
@@ -314,22 +322,26 @@ public final function float GetFloatBy(
BaseText jsonPointerAsText,
optional float defaultValue)
{
- local AcediaObject result;
+ local float result;
+ local AcediaObject resultObject;
local FloatBox asBox;
local FloatRef asRef;
- result = GetItemBy(jsonPointerAsText);
- if (result == none) {
+
+ resultObject = GetItemBy(jsonPointerAsText);
+ if (resultObject == none) {
return defaultValue;
}
- asBox = FloatBox(result);
+ result = defaultValue;
+ asBox = FloatBox(resultObject);
if (asBox != none) {
- return asBox.Get();
+ result = asBox.Get();
}
- asRef = FloatRef(result);
+ asRef = FloatRef(resultObject);
if (asRef != none) {
- return asRef.Get();
+ result = asRef.Get();
}
- return defaultValue;
+ _.memory.Free(resultObject);
+ return result;
}
/**
@@ -352,22 +364,26 @@ public final function Vector GetVectorBy(
BaseText jsonPointerAsText,
optional Vector defaultValue)
{
- local AcediaObject result;
+ local Vector result;
+ local AcediaObject resultObject;
local VectorBox asBox;
local VectorRef asRef;
- result = GetItemBy(jsonPointerAsText);
- if (result == none) {
+
+ resultObject = GetItemBy(jsonPointerAsText);
+ if (resultObject == none) {
return defaultValue;
}
- asBox = VectorBox(result);
+ result = defaultValue;
+ asBox = VectorBox(resultObject);
if (asBox != none) {
- return asBox.Get();
+ result = asBox.Get();
}
- asRef = VectorRef(result);
+ asRef = VectorRef(resultObject);
if (asRef != none) {
- return asRef.Get();
+ result = asRef.Get();
}
- return defaultValue;
+ _.memory.Free(resultObject);
+ return result;
}
/**
@@ -392,14 +408,16 @@ public final function string GetStringBy(
{
local AcediaObject result;
local Basetext asText;
+
result = GetItemBy(jsonPointerAsText);
if (result == none) {
return defaultValue;
}
asText = BaseText(result);
if (asText != none) {
- return asText.ToString();
+ return _.text.ToString(asText);
}
+ _.memory.Free(result);
return defaultValue;
}
@@ -425,14 +443,16 @@ public final function string GetFormattedStringBy(
{
local AcediaObject result;
local Basetext asText;
+
result = GetItemBy(jsonPointerAsText);
if (result == none) {
return defaultValue;
}
asText = BaseText(result);
if (asText != none) {
- return asText.ToFormattedString();
+ return _.text.ToFormattedString(asText);
}
+ _.memory.Free(result);
return defaultValue;
}
@@ -451,46 +471,16 @@ public final function string GetFormattedStringBy(
*/
public final function Text GetTextBy(BaseText jsonPointerAsText)
{
- return Text(GetItemBy(jsonPointerAsText));
-}
-
-/**
- * Returns an `AssociativeArray` value stored (in the caller `Collection` or
- * one of it's sub-collections) pointed by
- * [JSON pointer](https://tools.ietf.org/html/rfc6901).
- * See `GetItemBy()` for more information.
- *
- * Referred value must be stored as `AssociativeArray`
- * (or one of it's sub-classes) for this method to work.
- *
- * @param jsonPointerAsText Description of a path to the
- * `AssociativeArray` value.
- * @return `AssociativeArray` value, stored at `jsonPointerAsText` or
- * `none` if it is missing or has a different type.
- */
-public final function AssociativeArray GetAssociativeArrayBy(
- BaseText jsonPointerAsText)
-{
- return AssociativeArray(GetItemBy(jsonPointerAsText));
-}
+ local Text asText;
+ local AcediaObject result;
-/**
- * Returns an `DynamicArray` value stored (in the caller `Collection` or
- * one of it's sub-collections) pointed by
- * [JSON pointer](https://tools.ietf.org/html/rfc6901).
- * See `GetItemBy()` for more information.
- *
- * Referred value must be stored as `DynamicArray`
- * (or one of it's sub-classes) for this method to work.
- *
- * @param jsonPointerAsText Description of a path to the
- * `DynamicArray` value.
- * @return `DynamicArray` value, stored at `jsonPointerAsText` or
- * `none` if it is missing or has a different type.
- */
-public final function DynamicArray GetDynamicArrayBy(BaseText jsonPointerAsText)
-{
- return DynamicArray(GetItemBy(jsonPointerAsText));
+ result = GetItemBy(jsonPointerAsText);
+ asText = Text(result);
+ if (asText != none) {
+ return asText;
+ }
+ _.memory.Free(result);
+ return none;
}
/**
@@ -509,7 +499,16 @@ public final function DynamicArray GetDynamicArrayBy(BaseText jsonPointerAsText)
public final function HashTable GetHashTableBy(
BaseText jsonPointerAsText)
{
- return HashTable(GetItemBy(jsonPointerAsText));
+ local HashTable asHashTable;
+ local AcediaObject result;
+
+ result = GetItemBy(jsonPointerAsText);
+ asHashTable = HashTable(result);
+ if (asHashTable != none) {
+ return asHashTable;
+ }
+ _.memory.Free(result);
+ return none;
}
/**
@@ -527,7 +526,16 @@ public final function HashTable GetHashTableBy(
*/
public final function ArrayList GetArrayListBy(BaseText jsonPointerAsText)
{
- return ArrayList(GetItemBy(jsonPointerAsText));
+ local ArrayList asArrayList;
+ local AcediaObject result;
+
+ result = GetItemBy(jsonPointerAsText);
+ asArrayList = ArrayList(result);
+ if (asArrayList != none) {
+ return asArrayList;
+ }
+ _.memory.Free(result);
+ return none;
}
/**
@@ -549,22 +557,26 @@ public final function bool GetBoolByJSON(
JSONPointer jsonPointer,
optional bool defaultValue)
{
- local AcediaObject result;
+ local bool result;
+ local AcediaObject resultObject;
local BoolBox asBox;
local BoolRef asRef;
- result = GetItemByJSON(jsonPointer);
- if (result == none) {
+
+ resultObject = GetItemByJSON(jsonPointer);
+ if (resultObject == none) {
return defaultValue;
}
- asBox = BoolBox(result);
+ result = defaultValue;
+ asBox = BoolBox(resultObject);
if (asBox != none) {
- return asBox.Get();
+ result = asBox.Get();
}
- asRef = BoolRef(result);
+ asRef = BoolRef(resultObject);
if (asRef != none) {
- return asRef.Get();
+ result = asRef.Get();
}
- return defaultValue;
+ _.memory.Free(resultObject);
+ return result;
}
/**
@@ -586,22 +598,26 @@ public final function byte GetByteByJSON(
JSONPointer jsonPointer,
optional byte defaultValue)
{
- local AcediaObject result;
+ local byte result;
+ local AcediaObject resultObject;
local ByteBox asBox;
local ByteRef asRef;
- result = GetItemByJSON(jsonPointer);
- if (result == none) {
+
+ resultObject = GetItemByJSON(jsonPointer);
+ if (resultObject == none) {
return defaultValue;
}
- asBox = ByteBox(result);
+ result = defaultValue;
+ asBox = ByteBox(resultObject);
if (asBox != none) {
- return asBox.Get();
+ result = asBox.Get();
}
- asRef = ByteRef(result);
+ asRef = ByteRef(resultObject);
if (asRef != none) {
- return asRef.Get();
+ result = asRef.Get();
}
- return defaultValue;
+ _.memory.Free(resultObject);
+ return result;
}
/**
@@ -623,22 +639,26 @@ public final function int GetIntByJSON(
JSONPointer jsonPointer,
optional int defaultValue)
{
- local AcediaObject result;
+ local int result;
+ local AcediaObject resultObject;
local IntBox asBox;
local IntRef asRef;
- result = GetItemByJSON(jsonPointer);
- if (result == none) {
+
+ resultObject = GetItemByJSON(jsonPointer);
+ if (resultObject == none) {
return defaultValue;
}
- asBox = IntBox(result);
+ result = defaultValue;
+ asBox = IntBox(resultObject);
if (asBox != none) {
- return asBox.Get();
+ result = asBox.Get();
}
- asRef = IntRef(result);
+ asRef = IntRef(resultObject);
if (asRef != none) {
- return asRef.Get();
+ result = asRef.Get();
}
- return defaultValue;
+ _.memory.Free(resultObject);
+ return result;
}
/**
@@ -660,22 +680,26 @@ public final function float GetFloatByJSON(
JSONPointer jsonPointer,
optional float defaultValue)
{
- local AcediaObject result;
+ local float result;
+ local AcediaObject resultObject;
local FloatBox asBox;
local FloatRef asRef;
- result = GetItemByJSON(jsonPointer);
- if (result == none) {
+
+ resultObject = GetItemByJSON(jsonPointer);
+ if (resultObject == none) {
return defaultValue;
}
- asBox = FloatBox(result);
+ result = defaultValue;
+ asBox = FloatBox(resultObject);
if (asBox != none) {
- return asBox.Get();
+ result = asBox.Get();
}
- asRef = FloatRef(result);
+ asRef = FloatRef(resultObject);
if (asRef != none) {
- return asRef.Get();
+ result = asRef.Get();
}
- return defaultValue;
+ _.memory.Free(resultObject);
+ return result;
}
/**
@@ -697,22 +721,26 @@ public final function Vector GetVectorByJSON(
JSONPointer jsonPointer,
optional Vector defaultValue)
{
- local AcediaObject result;
+ local Vector result;
+ local AcediaObject resultObject;
local VectorBox asBox;
local VectorRef asRef;
- result = GetItemByJSON(jsonPointer);
- if (result == none) {
+
+ resultObject = GetItemByJSON(jsonPointer);
+ if (resultObject == none) {
return defaultValue;
}
- asBox = VectorBox(result);
+ result = defaultValue;
+ asBox = VectorBox(resultObject);
if (asBox != none) {
- return asBox.Get();
+ result = asBox.Get();
}
- asRef = VectorRef(result);
+ asRef = VectorRef(resultObject);
if (asRef != none) {
- return asRef.Get();
+ result = asRef.Get();
}
- return defaultValue;
+ _.memory.Free(resultObject);
+ return result;
}
/**
@@ -736,14 +764,16 @@ public final function string GetStringByJSON(
{
local AcediaObject result;
local BaseText asText;
+
result = GetItemByJSON(jsonPointer);
if (result == none) {
return defaultValue;
}
asText = BaseText(result);
if (asText != none) {
- return asText.ToString();
+ return _.text.ToString(asText);
}
+ _.memory.Free(result);
return defaultValue;
}
@@ -768,14 +798,16 @@ public final function string GetFormattedStringByJSON(
{
local AcediaObject result;
local BaseText asText;
+
result = GetItemByJSON(jsonPointer);
if (result == none) {
return defaultValue;
}
asText = BaseText(result);
if (asText != none) {
- return asText.ToFormattedString();
+ return _.text.ToFormattedString(asText);
}
+ _.memory.Free(result);
return defaultValue;
}
@@ -793,43 +825,16 @@ public final function string GetFormattedStringByJSON(
*/
public final function Text GetTextByJSON(JSONPointer jsonPointer)
{
- return Text(GetItemByJSON(jsonPointer));
-}
-
-/**
- * Returns an `AssociativeArray` value stored (in the caller `Collection` or
- * one of it's sub-collections) pointed by JSON pointer.
- * See `GetItemByJSON()` for more information.
- *
- * Referred value must be stored as `AssociativeArray`
- * (or one of it's sub-classes) for this method to work.
- *
- * @param jsonPointer JSON path to the `AssociativeArray` value.
- * @return `AssociativeArray` value, stored at `jsonPointerAsText` or
- * `none` if it is missing or has a different type.
- */
-public final function AssociativeArray GetAssociativeArrayByJSON(
- JSONPointer jsonPointer)
-{
- return AssociativeArray(GetItemByJSON(jsonPointer));
-}
+ local AcediaObject result;
+ local Text asText;
-/**
- * Returns an `DynamicArray` value stored (in the caller `Collection` or
- * one of it's sub-collections) pointed by JSON pointer.
- * See `GetItemByJSON()` for more information.
- *
- * Referred value must be stored as `DynamicArray`
- * (or one of it's sub-classes) for this method to work.
- *
- * @param jsonPointer JSON path to the `DynamicArray` value.
- * @return `DynamicArray` value, stored at `jsonPointerAsText` or
- * `none` if it is missing or has a different type.
- */
-public final function DynamicArray GetDynamicArrayByJSON(
- JSONPointer jsonPointer)
-{
- return DynamicArray(GetItemByJSON(jsonPointer));
+ result = GetItemByJSON(jsonPointer);
+ asText = Text(result);
+ if (asText != none) {
+ return asText;
+ }
+ _.memory.Free(result);
+ return none;
}
/**
@@ -847,7 +852,16 @@ public final function DynamicArray GetDynamicArrayByJSON(
public final function HashTable GetHashTableByJSON(
JSONPointer jsonPointer)
{
- return HashTable(GetItemByJSON(jsonPointer));
+ local AcediaObject result;
+ local HashTable asHashTable;
+
+ result = GetItemByJSON(jsonPointer);
+ asHashTable = HashTable(result);
+ if (asHashTable != none) {
+ return asHashTable;
+ }
+ _.memory.Free(result);
+ return none;
}
/**
@@ -865,7 +879,16 @@ public final function HashTable GetHashTableByJSON(
public final function ArrayList GetArrayListByJSON(
JSONPointer jsonPointer)
{
- return ArrayList(GetItemByJSON(jsonPointer));
+ local AcediaObject result;
+ local ArrayList asArrayList;
+
+ result = GetItemByJSON(jsonPointer);
+ asArrayList = ArrayList(result);
+ if (asArrayList != none) {
+ return asArrayList;
+ }
+ _.memory.Free(result);
+ return none;
}
defaultproperties
diff --git a/sources/Data/Collections/CollectionsAPI.uc b/sources/Data/Collections/CollectionsAPI.uc
index 8aa141e..87b0877 100644
--- a/sources/Data/Collections/CollectionsAPI.uc
+++ b/sources/Data/Collections/CollectionsAPI.uc
@@ -91,80 +91,6 @@ public final function HashTable EmptyHashTable()
return HashTable(_.memory.Allocate(class'HashTable'));
}
-/**
- * Creates a new `DynamicArray`, optionally filling it with objects from
- * a given native array.
- *
- * @param objectArray Objects to place inside created `DynamicArray`;
- * if empty (by default) - new, empty `DynamicArray` will be returned.
- * Objects will be added in the same order as in `objectArray`.
- * @param managed Flag that indicates whether objects from
- * `objectArray` argument should be added as managed.
- * By default `false` - they would not be managed.
- * @return New `DynamicArray`, optionally filled with contents of
- * `objectArray`. Guaranteed to be not `none` and to not contain any items
- * outside of `objectArray`.
- */
-public final function DynamicArray NewDynamicArray(
- array objectArray,
- optional bool managed)
-{
- local int i;
- local DynamicArray result;
- result = DynamicArray(_.memory.Allocate(class'DynamicArray'));
- for (i = 0; i < objectArray.length; i += 1) {
- result.AddItem(objectArray[i], managed);
- }
- return result;
-}
-
-/**
- * Creates a new empty `DynamicArray`.
- *
- * @return New empty instance of `DynamicArray`.
- */
-public final function DynamicArray EmptyDynamicArray()
-{
- return DynamicArray(_.memory.Allocate(class'DynamicArray'));
-}
-
-/**
- * Creates a new `AssociativeArray`, optionally filling it with entries
- * (key/value pairs) from a given native array.
- *
- * @param entriesArray Entries (key/value pairs) to place inside created
- * `AssociativeArray`; if empty (by default) - new,
- * empty `AssociativeArray` will be returned.
- * @param managed Flag that indicates whether values from
- * `entriesArray` argument should be added as managed.
- * By default `false` - they would not be managed.
- * @return New `AssociativeArray`, optionally filled with contents of
- * `entriesArray`. Guaranteed to be not `none` and to not contain any items
- * outside of `entriesArray`.
- */
-public final function AssociativeArray NewAssociativeArray(
- array entriesArray,
- optional bool managed)
-{
- local int i;
- local AssociativeArray result;
- result = AssociativeArray(_.memory.Allocate(class'AssociativeArray'));
- for (i = 0; i < entriesArray.length; i += 1) {
- result.SetItem(entriesArray[i].key, entriesArray[i].value, managed);
- }
- return result;
-}
-
-/**
- * Creates a new empty `AssociativeArray`.
- *
- * @return New empty instance of `AssociativeArray`.
- */
-public final function AssociativeArray EmptyAssociativeArray()
-{
- return AssociativeArray(_.memory.Allocate(class'AssociativeArray'));
-}
-
defaultproperties
{
}
\ No newline at end of file
diff --git a/sources/Data/Collections/DynamicArray.uc b/sources/Data/Collections/DynamicArray.uc
deleted file mode 100644
index 0a723e5..0000000
--- a/sources/Data/Collections/DynamicArray.uc
+++ /dev/null
@@ -1,817 +0,0 @@
-/**
- * Dynamic array object for storing arbitrary types of data. Generic
- * storage is achieved by using `AcediaObject` as the stored type. Native
- * variable types such as `int`, `bool`, etc. can be stored by boxing them into
- * `AcediaObject`s.
- * Appropriate classes and APIs for their construction are provided for
- * main primitive types and can be extended to any custom `struct`.
- * Copyright 2020 - 2021 Anton Tarasenko
- *------------------------------------------------------------------------------
- * This file is part of Acedia.
- *
- * Acedia is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, version 3 of the License, or
- * (at your option) any later version.
- *
- * Acedia is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Acedia. If not, see .
- */
-class DynamicArray extends Collection;
-
-// Actual storage of all our data.
-var private array storedObjects;
-// `managedFlags[i] > 0` iff `contents[i]` is a managed object.
-// Invariant `managedFlags.length == contents.length` should be enforced by
-// all methods.
-var private array managedFlags;
-// Recorded `lifeVersions` of all stored objects.
-// Invariant `lifeVersions.length == contents.length` should be enforced by
-// all methods.
-var private array lifeVersions;
-
-// Free array data
-protected function Finalizer()
-{
- Empty();
-}
-
-// Method, used to compare array values at different indices.
-// Does not check boundary conditions, so make sure passed indices are valid.
-private function bool AreEqual(AcediaObject object1, AcediaObject object2)
-{
- if (object1 == none && object2 == none) return true;
- if (object1 == none || object2 == none) return false;
-
- return object1.IsEqual(object2);
-}
-
-/**
- * Returns current length of dynamic `DynamicArray`.
- * Cannot fail.
- *
- * @return Returns length of the caller `DynamicArray`.
- * Guaranteed to be non-negative.
- */
-public final function int GetLength()
-{
- return storedObjects.length;
-}
-
-/**
- * Changes length of the caller `DynamicArray`.
- * If `DynamicArray` size is increased as a result - added items will be
- * filled with `none`s.
- * If `DynamicArray` size is decreased - erased managed items will be
- * automatically deallocated.
- *
- * @param newLength New length of an `DynamicArray`.
- * If negative value is passes - method will do nothing.
- * @return Reference to the caller `DynamicArray` to allow for method chaining.
- */
-public final function DynamicArray SetLength(int newLength)
-{
- local int i;
- if (newLength < 0) {
- return self;
- }
- for (i = newLength; i < storedObjects.length; i += 1) {
- FreeManagedItem(i);
- }
- storedObjects.length = newLength;
- managedFlags.length = newLength;
- lifeVersions.length = newLength;
- return self;
-}
-
-/**
- * Deallocates an item at a given index `index`, if it's managed.
- * Does not check `DynamicArray` bounds for `index`, so you must ensure that
- * `index` is valid.
- *
- * @param index Index of the managed item to deallocate.
- * @return Reference to the caller `DynamicArray` to allow for method chaining.
- */
-protected final function DynamicArray FreeManagedItem(int index)
-{
- if (storedObjects[index] == none) return self;
- if (!storedObjects[index].IsAllocated()) return self;
- if (managedFlags[index] <= 0) return self;
- if (lifeVersions[index] != storedObjects[index].GetLifeVersion()) {
- return self;
- }
- if ( storedObjects[index] != none && managedFlags[index] > 0
- && lifeVersions[index] == storedObjects[index].GetLifeVersion())
- {
- storedObjects[index].FreeSelf();
- storedObjects[index] = none;
- }
- return self;
-}
-
-public function Empty(optional bool deallocateKeys)
-{
- local int i;
- local Collection subCollection;
- if (deallocateKeys)
- {
- for (i = 0; i < storedObjects.length; i += 1)
- {
- subCollection = Collection(GetItem(i));
- if (subCollection != none) {
- subCollection.Empty(true);
- }
- }
- }
- SetLength(0);
-}
-
-/**
- * Adds `amountOfNewItems` empty (`none`) items at the end of
- * the `DynamicArray`.
- * To insert items at an arbitrary array index, use `Insert()`.
- *
- * @param amountOfNewItems Amount of items to add at the end.
- * If non-positive value is passed, - method does nothing.
- * @return Reference to the caller `DynamicArray` to allow for method chaining.
- */
-public final function DynamicArray Add(int amountOfNewItems)
-{
- if (amountOfNewItems > 0) {
- SetLength(storedObjects.length + amountOfNewItems);
- }
- return self;
-}
-
-/**
- * Inserts `count` empty (`none`) items into the `DynamicArray`
- * at specified position.
- * The indices of the following items are increased by `count` in order
- * to make room for the new items.
- *
- * To add items at the end of an `DynamicArray`, consider using `Add()`,
- * which is equivalent to `array.Insert(array.GetLength(), ...)`.
- *
- * @param index Index, where first inserted item will be located.
- * Must belong to `[0; self.GetLength()]` inclusive interval,
- * otherwise method does nothing.
- * @param count Amount of new items to insert.
- * Must be positive, otherwise method does nothing.
- * @return Reference to the caller `DynamicArray` to allow for method chaining.
- */
-public final function DynamicArray Insert(int index, int count)
-{
- local int i;
- local int swapIndex;
- local int amountToShift;
-
- if (count <= 0) return self;
- if (index < 0 || index > storedObjects.length) return self;
-
- amountToShift = storedObjects.length - index;
- Add(count);
- if (amountToShift == 0) {
- return self;
- }
- for (i = 0; i < amountToShift; i += 1)
- {
- swapIndex = storedObjects.length - i - 1;
- Swap(swapIndex, swapIndex - count);
- }
- return self;
-}
-
-/**
- * Swaps two `DynamicArray` items, along with information about their
- * managed status.
- *
- * @param index1 Index of item to swap.
- * @param index2 Index of item to swap.
- */
-protected final function Swap(int index1, int index2)
-{
- local AcediaObject temporaryItem;
- local int temporaryNumber;
- // Swap object
- temporaryItem = storedObjects[index1];
- storedObjects[index1] = storedObjects[index2];
- storedObjects[index2] = temporaryItem;
- // Swap life versions
- temporaryNumber = lifeVersions[index1];
- lifeVersions[index1] = lifeVersions[index2];
- lifeVersions[index2] = temporaryNumber;
- // Swap managed flags
- temporaryNumber = managedFlags[index1];
- managedFlags[index1] = managedFlags[index2];
- managedFlags[index2] = temporaryNumber;
-}
-
-/**
- * Removes number items from the `DynamicArray`, starting at `index`.
- * All items before position and from `index + count` on are not changed,
- * but the item indices change, - they shift to close the gap,
- * created by removed items.
- *
- * @param index Remove items starting from this index.
- * Must belong to `[0; self.GetLength() - 1]` inclusive interval,
- * otherwise method does nothing.
- * @param count Removes at most this much items.
- * Must be positive, otherwise method does nothing.
- * Specifying more items than can be removed simply removes
- * all items, starting from `index`.
- * @return Reference to the caller `DynamicArray` to allow for method chaining.
- */
-public final function DynamicArray Remove(int index, int count)
-{
- local int i;
- if (count <= 0) return self;
- if (index < 0 || index > storedObjects.length) return self;
-
- count = Min(count, storedObjects.length - index);
- for (i = 0; i < count; i += 1) {
- FreeManagedItem(index + i);
- }
- storedObjects.Remove(index, count);
- managedFlags.Remove(index, count);
- lifeVersions.Remove(index, count);
- return self;
-}
-
-/**
- * Removes item at a given index, shifting all the items that come after
- * one place backwards.
- *
- * @param index Remove items starting from this index.
- * Must belong to `[0; self.GetLength() - 1]` inclusive interval,
- * otherwise method does nothing.
- * @return Reference to the caller `DynamicArray` to allow for method chaining.
- */
-public final function DynamicArray RemoveIndex(int index)
-{
- Remove(index, 1);
- return self;
-}
-
-/**
- * Checks if caller `DynamicArray`'s value at index `index` is managed.
- *
- * Managed values will be automatically deallocated once they are removed
- * (or overwritten) from the caller `DynamicArray`.
- *
- * @return `true` if value, recorded in caller `DynamicArray` at index `index`
- * is managed and `false` otherwise.
- * If `index` is invalid (outside of `DynamicArray` bounds)
- * also returns `false`.
- */
-public final function bool IsManaged(int index)
-{
- if (index < 0) return false;
- if (index >= storedObjects.length) return false;
- if (storedObjects[index] == none) return false;
- if (!storedObjects[index].IsAllocated()) return false;
- if (storedObjects[index].GetLifeVersion() != lifeVersions[index]) {
- return false;
- }
-
- return (managedFlags[index] > 0);
-}
-
-/**
- * Returns item at `index` and replaces it with `none` inside `DynamicArray`.
- * If index is invalid, returns `none`.
- *
- * If returned value was managed, it won't be deallocated
- * and will stop being managed.
- *
- * @param index Index of an item that `DynamicArray` has to return.
- * @return Either value at `index` in the caller `DynamicArray` or `none` if
- * passed `index` is invalid.
- */
-public final function AcediaObject TakeItem(int index)
-{
- local AcediaObject result;
- if (index < 0) return none;
- if (index >= storedObjects.length) return none;
- if (storedObjects[index] == none) return none;
- if (!storedObjects[index].IsAllocated()) return none;
- if (storedObjects[index].GetLifeVersion() != lifeVersions[index]) {
- return none;
- }
-
- result = storedObjects[index];
- storedObjects[index] = none;
- managedFlags[index] = 0;
- lifeVersions[index] = 0;
- return result;
-}
-
-/**
- * Returns item at `index`. If index is invalid, returns `none`.
- *
- * @param index Index of an item that `DynamicArray` has to return.
- * @return Either value at `index` in the caller `DynamicArray` or `none` if
- * passed `index` is invalid.
- */
-public final function AcediaObject GetItem(int index)
-{
- if (index < 0) return none;
- if (index >= storedObjects.length) return none;
- if (storedObjects[index] == none) return none;
- if (!storedObjects[index].IsAllocated()) return none;
- if (storedObjects[index].GetLifeVersion() != lifeVersions[index]) {
- return none;
- }
-
- return storedObjects[index];
-}
-
-/**
- * Changes `DynamicArray`'s value at `index` to `item`.
- *
- * @param index Index, at which to change the value. If `DynamicArray` is
- * not long enough to hold it, it will be automatically expanded.
- * If passed index is negative - method will do nothing.
- * @param item Value to be set at a given index.
- * @param managed Whether `item` should be managed by `DynamicArray`.
- * By default (`false`) all items are not managed.
- * @return Reference to the caller `DynamicArray` to allow for method chaining.
- */
-public final function DynamicArray SetItem(
- int index,
- AcediaObject item,
- optional bool managed)
-{
- if (index < 0) {
- return self;
- }
- if (index >= storedObjects.length) {
- SetLength(index + 1);
- }
- else if (item != storedObjects[index]) {
- FreeManagedItem(index);
- }
- storedObjects[index] = item;
- managedFlags[index] = 0;
- if (managed) {
- managedFlags[index] = 1;
- }
- if (item != none) {
- lifeVersions[index] = item.GetLifeVersion();
- }
- return self;
-}
-
-/**
- * Creates a new instance of class `valueClass` and records it's value at index
- * `index` in the caller `DynamicArray`. Value is recorded as managed.
- *
- * @param index Index, at which to change the value. If `DynamicArray`
- * is not long enough to hold it, it will be automatically expanded.
- * If passed index is negative - method will do nothing.
- * @param valueClass Class of object to create. Will only be created if
- * passed `index` is valid.
- * @return Caller `DynamicArray` to allow for method chaining.
- */
-public final function DynamicArray CreateItem(
- int index,
- class valueClass)
-{
- if (index < 0) return self;
- if (valueClass == none) return self;
-
- return SetItem(index, AcediaObject(_.memory.Allocate(valueClass)), true);
-}
-
-/**
- * Adds given `item` at the end of the `DynamicArray`, expanding it by
- * one item.
- * Cannot fail.
- *
- * @param item Item to be added at the end of the `DynamicArray`.
- * @param managed Whether `item` should be managed by `DynamicArray`.
- * By default (`false`) all items are not managed.
- * @return Reference to the caller `DynamicArray` to allow for method chaining.
- */
-public final function DynamicArray AddItem(
- AcediaObject item,
- optional bool managed)
-{
- return SetItem(storedObjects.length, item, managed);
-}
-
-/**
- * Inserts given `item` at index `index` of the `DynamicArray`,
- * shifting all the items starting from `index` one position to the right.
- * Cannot fail.
- *
- * @param index Index at which to insert new item. Must belong to
- * inclusive range `[0; self.GetLength()]`, otherwise method does nothing.
- * @param item Item to insert.
- * @param managed Whether `item` should be managed by `DynamicArray`.
- * By default (`false`) all items are not managed.
- * @return Reference to the caller `DynamicArray` to allow for method chaining.
- */
-public final function DynamicArray InsertItem(
- int index,
- AcediaObject item,
- optional bool managed)
-{
- if (index < 0) return self;
- if (index > storedObjects.length) return self;
-
- Insert(index, 1);
- SetItem(index, item, managed);
- return self;
-}
-
-/**
- * Returns all occurrences of `item` in the caller `DynamicArray`
- * (optionally only first one).
- *
- * @param item Item that needs to be removed from a `DynamicArray`.
- * @param onlyFirstItem Set to `true` to only remove first occurrence.
- * By default `false`, which means all occurrences will be removed.
- * @return Reference to the caller `DynamicArray` to allow for method chaining.
- */
-public final function DynamicArray RemoveItem(
- AcediaObject item,
- optional bool onlyFirstItem)
-{
- local int i;
- while (i < storedObjects.length)
- {
- if (AreEqual(storedObjects[i], item))
- {
- Remove(i, 1);
- if (onlyFirstItem) {
- return self;
- }
- }
- else {
- i += 1;
- }
- }
- return self;
-}
-
-/**
- * Finds first occurrence of `item` in caller `DynamicArray` and returns
- * it's index.
- *
- * @param item Item to find in `DynamicArray`.
- * @return Index of first occurrence of `item` in caller `DynamicArray`.
- * `-1` if `item` is not found.
- */
-public final function int Find(AcediaObject item)
-{
- local int i;
- for (i = 0; i < storedObjects.length; i += 1)
- {
- if (AreEqual(storedObjects[i], item)) {
- return i;
- }
- }
- return -1;
-}
-
-protected function AcediaObject GetByText(BaseText key)
-{
- local int index, consumed;
- local Parser parser;
- parser = _.text.Parse(key);
- parser.MUnsignedInteger(index,,, consumed);
- if (!parser.Ok())
- {
- parser.FreeSelf();
- return none;
- }
- parser.FreeSelf();
- return GetItem(index);
-}
-
-/**
- * Returns `bool` item at `index`. If index is invalid or
- * stores a non-`bool` value, returns `defaultValue`.
- *
- * Referred value must be stored as `BoolBox` or `BoolRef`
- * (or one of their sub-classes) for this method to work.
- *
- * @param index Index of a `bool` item that `DynamicArray`
- * has to return.
- * @param defaultValue Value to return if there is either no item recorded
- * at `index` or it has a wrong type.
- * @return `bool` value at `index` in the caller `DynamicArray`.
- * `defaultValue` if passed `index` is invalid or non-`bool` value
- * is stored there.
- */
-public final function bool GetBool(int index, optional bool defaultValue)
-{
- local AcediaObject result;
- local BoolBox asBox;
- local BoolRef asRef;
- result = GetItem(index);
- if (result == none) {
- return defaultValue;
- }
- asBox = BoolBox(result);
- if (asBox != none) {
- return asBox.Get();
- }
- asRef = BoolRef(result);
- if (asRef != none) {
- return asRef.Get();
- }
- return defaultValue;
-}
-
-/**
- * Changes `DynamicArray`'s value at `index` to `value` that will be recorded
- * as either `BoolBox` or `BoolRef`, depending of `asRef` optional parameter.
- *
- * Inserted value will always be recorded as a managed value, i.e. it will be
- * automatically deallocated when overwritten, removed or caller `DynamicArray`
- * is deallocated.
- *
- * @param index Index, at which to change the value. If `DynamicArray` is
- * not long enough to hold it, it will be automatically expanded.
- * If passed index is negative - method will do nothing.
- * @param value Value to be set at a given index.
- * @param asRef Given `bool` value will be recorded as immutable `BoolBox`
- * by default (`asRef == false`). Setting this parameter to `true` will
- * make this method record it as a mutable `BoolRef`.
- * @return Reference to the caller `DynamicArray` to allow for method chaining.
- */
-public final function DynamicArray SetBool(
- int index,
- bool value,
- optional bool asRef)
-{
- if (asRef) {
- SetItem(index, _.ref.bool(value), true);
- }
- else {
- SetItem(index, _.box.bool(value), true);
- }
- return self;
-}
-
-/**
- * Returns `byte` item at `index`. If index is invalid or
- * stores a non-`byte` value, returns `defaultValue`.
- *
- * Referred value must be stored as `ByteBox` or `ByteRef`
- * (or one of their sub-classes) for this method to work.
- *
- * @param index Index of a `byte` item that `DynamicArray`
- * has to return.
- * @param defaultValue Value to return if there is either no item recorded
- * at `index` or it has a wrong type.
- * @return `byte` value at `index` in the caller `DynamicArray`.
- * `defaultValue` if passed `index` is invalid or non-`byte` value
- * is stored there.
- */
-public final function byte GetByte(int index, optional byte defaultValue)
-{
- local AcediaObject result;
- local ByteBox asBox;
- local ByteRef asRef;
- result = GetItem(index);
- if (result == none) {
- return defaultValue;
- }
- asBox = ByteBox(result);
- if (asBox != none) {
- return asBox.Get();
- }
- asRef = ByteRef(result);
- if (asRef != none) {
- return asRef.Get();
- }
- return defaultValue;
-}
-
-/**
- * Changes `DynamicArray`'s value at `index` to `value` that will be recorded
- * as either `ByteBox` or `ByteRef`, depending of `asRef` optional parameter.
- *
- * Inserted value will always be recorded as a managed value, i.e. it will be
- * automatically deallocated when overwritten, removed or caller `DynamicArray`
- * is deallocated.
- *
- * @param index Index, at which to change the value. If `DynamicArray` is
- * not long enough to hold it, it will be automatically expanded.
- * If passed index is negative - method will do nothing.
- * @param value Value to be set at a given index.
- * @param asRef Given `byte` value will be recorded as immutable `ByteBox`
- * by default (`asRef == false`). Setting this parameter to `true` will
- * make this method record it as a mutable `ByteRef`.
- * @return Reference to the caller `DynamicArray` to allow for method chaining.
- */
-public final function DynamicArray SetByte(
- int index,
- byte value,
- optional bool asRef)
-{
- if (asRef) {
- SetItem(index, _.ref.byte(value), true);
- }
- else {
- SetItem(index, _.box.byte(value), true);
- }
- return self;
-}
-
-/**
- * Returns `int` item at `index`. If index is invalid or
- * stores a non-`int` value, returns `defaultValue`.
- *
- * Referred value must be stored as `IntBox` or `IntRef`
- * (or one of their sub-classes) for this method to work.
- *
- * @param index Index of a `int` item that `DynamicArray`
- * has to return.
- * @param defaultValue Value to return if there is either no item recorded
- * at `index` or it has a wrong type.
- * @return `int` value at `index` in the caller `DynamicArray`.
- * `defaultValue` if passed `index` is invalid or non-`int` value
- * is stored there.
- */
-public final function int GetInt(int index, optional int defaultValue)
-{
- local AcediaObject result;
- local IntBox asBox;
- local IntRef asRef;
- result = GetItem(index);
- if (result == none) {
- return defaultValue;
- }
- asBox = IntBox(result);
- if (asBox != none) {
- return asBox.Get();
- }
- asRef = IntRef(result);
- if (asRef != none) {
- return asRef.Get();
- }
- return defaultValue;
-}
-
-/**
- * Changes `DynamicArray`'s value at `index` to `value` that will be recorded
- * as either `IntBox` or `IntRef`, depending of `asRef` optional parameter.
- *
- * Inserted value will always be recorded as a managed value, i.e. it will be
- * automatically deallocated when overwritten, removed or caller `DynamicArray`
- * is deallocated.
- *
- * @param index Index, at which to change the value. If `DynamicArray` is
- * not long enough to hold it, it will be automatically expanded.
- * If passed index is negative - method will do nothing.
- * @param value Value to be set at a given index.
- * @param asRef Given `int` value will be recorded as immutable `IntBox`
- * by default (`asRef == false`). Setting this parameter to `true` will
- * make this method record it as a mutable `IntRef`.
- * @return Reference to the caller `DynamicArray` to allow for method chaining.
- */
-public final function DynamicArray SetInt(
- int index,
- int value,
- optional bool asRef)
-{
- if (asRef) {
- SetItem(index, _.ref.int(value), true);
- }
- else {
- SetItem(index, _.box.int(value), true);
- }
- return self;
-}
-
-/**
- * Returns `float` item at `index`. If index is invalid or
- * stores a non-`int` value, returns `defaultValue`.
- *
- * Referred value must be stored as `FloatBox` or `FloatRef`
- * (or one of their sub-classes) for this method to work.
- *
- * @param index Index of a `float` item that `DynamicArray`
- * has to return.
- * @param defaultValue Value to return if there is either no item recorded
- * at `index` or it has a wrong type.
- * @return `float` value at `index` in the caller `DynamicArray`.
- * `defaultValue` if passed `index` is invalid or non-`float` value
- * is stored there.
- */
-public final function float GetFloat(int index, optional float defaultValue)
-{
- local AcediaObject result;
- local FloatBox asBox;
- local FloatRef asRef;
- result = GetItem(index);
- if (result == none) {
- return defaultValue;
- }
- asBox = FloatBox(result);
- if (asBox != none) {
- return asBox.Get();
- }
- asRef = FloatRef(result);
- if (asRef != none) {
- return asRef.Get();
- }
- return defaultValue;
-}
-
-/**
- * Changes `DynamicArray`'s value at `index` to `value` that will be recorded
- * as either `FloatBox` or `FloatRef`, depending of `asRef` optional parameter.
- *
- * Inserted value will always be recorded as a managed value, i.e. it will be
- * automatically deallocated when overwritten, removed or caller `DynamicArray`
- * is deallocated.
- *
- * @param index Index, at which to change the value. If `DynamicArray` is
- * not long enough to hold it, it will be automatically expanded.
- * If passed index is negative - method will do nothing.
- * @param value Value to be set at a given index.
- * @param asRef Given `float` value will be recorded as immutable `FloatBox`
- * by default (`asRef == false`). Setting this parameter to `true` will
- * make this method record it as a mutable `FloatRef`.
- * @return Reference to the caller `DynamicArray` to allow for method chaining.
- */
-public final function DynamicArray SetFloat(
- int index,
- float value,
- optional bool asRef)
-{
- if (asRef) {
- SetItem(index, _.ref.float(value), true);
- }
- else {
- SetItem(index, _.box.float(value), true);
- }
- return self;
-}
-
-/**
- * Returns `Text` item at `index`. If index is invalid or
- * stores a non-`Text` value, returns `none`.
- *
- * Referred value must be stored as `Text` (or one of it's sub-classes,
- * such as `MutableText`) for this method to work.
- *
- * @param index Index of a `Text` item that `DynamicArray` has to return.
- * @return `Text` value at `index` in the caller `DynamicArray`.
- * `none` if passed `index` is invalid or non-`Text` value
- * is stored there.
- */
-public final function Text GetText(int index)
-{
- return Text(GetItem(index));
-}
-
-/**
- * Returns `AssociativeArray` item at `index`. If index is invalid or
- * stores a non-`AssociativeArray` value, returns `none`.
- *
- * Referred value must be stored as `AssociativeArray`
- * (or one of it's sub-classes) for this method to work.
- *
- * @param index Index of an `AssociativeArray` item that `DynamicArray`
- * has to return.
- * @return `AssociativeArray` value at `index` in the caller `DynamicArray`.
- * `none` if passed `index` is invalid or non-`AssociativeArray` value
- * is stored there.
- */
-public final function AssociativeArray GetAssociativeArray(int index)
-{
- return AssociativeArray(GetItem(index));
-}
-
-/**
- * Returns `DynamicArray` item at `index`. If index is invalid or
- * stores a non-`DynamicArray` value, returns `none`.
- *
- * Referred value must be stored as `Text` (or one of it's sub-classes,
- * such as `MutableText`) for this method to work.
- *
- * @param index Index of a `DynamicArray` item that caller `DynamicArray`
- * has to return.
- * @return `DynamicArray` value at `index` in the caller `DynamicArray`.
- * `none` if passed `index` is invalid or non-`DynamicArray` value
- * is stored there.
- */
-public final function DynamicArray GetDynamicArray(int index)
-{
- return DynamicArray(GetItem(index));
-}
-
-defaultproperties
-{
- iteratorClass = class'DynamicArrayIterator'
-}
\ No newline at end of file
diff --git a/sources/Data/Collections/DynamicArrayIterator.uc b/sources/Data/Collections/DynamicArrayIterator.uc
deleted file mode 100644
index b6c48d4..0000000
--- a/sources/Data/Collections/DynamicArrayIterator.uc
+++ /dev/null
@@ -1,80 +0,0 @@
-/**
- * Iterator for iterating over `DynamicArray`'s items.
- * Copyright 2020 Anton Tarasenko
- *------------------------------------------------------------------------------
- * This file is part of Acedia.
- *
- * Acedia is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, version 3 of the License, or
- * (at your option) any later version.
- *
- * Acedia is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Acedia. If not, see .
- */
-class DynamicArrayIterator extends CollectionIterator;
-
-var private DynamicArray relevantCollection;
-var private int currentIndex;
-
-protected function Finalizer()
-{
- relevantCollection = none;
-}
-
-public function bool Initialize(Collection relevantArray)
-{
- currentIndex = 0;
- relevantCollection = DynamicArray(relevantArray);
- if (relevantCollection == none) {
- return false;
- }
- return true;
-}
-
-public function Iter Next(optional bool skipNone)
-{
- local int collectionLength;
- if (!skipNone)
- {
- currentIndex += 1;
- return self;
- }
- collectionLength = relevantCollection.GetLength();
- while (currentIndex < collectionLength)
- {
- currentIndex += 1;
- if (relevantCollection.GetItem(currentIndex) != none) {
- return self;
- }
- }
- return self;
-}
-
-public function AcediaObject Get()
-{
- return relevantCollection.GetItem(currentIndex);
-}
-
-/**
- * Note that for `DynamicArrayIterator` this method produces a new `IntBox`
- * object each time and requires manual deallocation.
- */
-public function AcediaObject GetKey()
-{
- return _.box.int(currentIndex);
-}
-
-public function bool HasFinished()
-{
- return currentIndex >= relevantCollection.GetLength();
-}
-
-defaultproperties
-{
-}
\ No newline at end of file
diff --git a/sources/Data/Collections/HashTable.uc b/sources/Data/Collections/HashTable.uc
index 1e56de1..2435a88 100644
--- a/sources/Data/Collections/HashTable.uc
+++ b/sources/Data/Collections/HashTable.uc
@@ -453,7 +453,7 @@ public final function HashTable RemoveItem(AcediaObject key)
return self;
}
-public function Empty(optional bool deprecated)
+public function Empty()
{
local int i, j;
local array nextEntries;
@@ -1155,54 +1155,6 @@ public final function Text GetText(AcediaObject key)
return result;
}
-/**
- * Returns `AssociativeArray` item stored at key `key`. If key is invalid or
- * stores a non-`AssociativeArray` value, returns `none`.
- *
- * Referred value must be stored as `AssociativeArray`
- * (or one of it's sub-classes) for this method to work.
- *
- * @param key Key of an `AssociativeArray` item that caller `HashTable`
- * has to return.
- * @return `AssociativeArray` value recorded with `key` in the caller
- * `HashTable`. `none` if passed `key` is invalid or
- * non-`AssociativeArray` value is stored with it.
- */
-public final function AssociativeArray GetAssociativeArray(AcediaObject key)
-{
- local AssociativeArray result;
-
- result = AssociativeArray(BorrowItem(key));
- if (result != none) {
- result.NewRef();
- }
- return result;
-}
-
-/**
- * Returns `DynamicArray` item stored at key `key`. If key is invalid or
- * stores a non-`DynamicArray` value, returns `none`.
- *
- * Referred value must be stored as `DynamicArray`
- * (or one of it's sub-classes) for this method to work.
- *
- * @param key Key of a `DynamicArray` item that caller `HashTable`
- * has to return.
- * @return `DynamicArray` value recorded with `key` in the caller
- * `HashTable`. `none` if passed `key` is invalid or
- * non-`DynamicArray` value is stored with it.
- */
-public final function DynamicArray GetDynamicArray(AcediaObject key)
-{
- local DynamicArray result;
-
- result = DynamicArray(BorrowItem(key));
- if (result != none) {
- result.NewRef();
- }
- return result;
-}
-
/**
* Returns `HashTable` item stored at key `key`. If key is invalid or
* stores a non-`HashTable` value, returns `none`.
diff --git a/sources/Data/Collections/HashTableIterator.uc b/sources/Data/Collections/HashTableIterator.uc
index 0a578ce..4463a44 100644
--- a/sources/Data/Collections/HashTableIterator.uc
+++ b/sources/Data/Collections/HashTableIterator.uc
@@ -57,7 +57,7 @@ public function Iter LeaveOnlyNotNone()
return self;
}
-public function Iter Next(optional bool deprecated)
+public function Iter Next()
{
local int collectionLength;
diff --git a/sources/Data/Collections/Tests/TEST_AssociativeArray.uc b/sources/Data/Collections/Tests/TEST_AssociativeArray.uc
deleted file mode 100644
index bbc9ec0..0000000
--- a/sources/Data/Collections/Tests/TEST_AssociativeArray.uc
+++ /dev/null
@@ -1,488 +0,0 @@
-/**
- * Set of tests for `AssociativeArray` class.
- * Copyright 2020 Anton Tarasenko
- *------------------------------------------------------------------------------
- * This file is part of Acedia.
- *
- * Acedia is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, version 3 of the License, or
- * (at your option) any later version.
- *
- * Acedia is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Acedia. If not, see .
- */
-class TEST_AssociativeArray extends TestCase
- abstract;
-
-protected static function TESTS()
-{
- Test_GetSet();
- Test_HasKey();
- Test_GetKeys();
- Test_CopyTextKeys();
- Test_Remove();
- Test_CreateItem();
- Test_Empty();
- Test_Length();
- Test_Managed();
- Test_DeallocationHandling();
- Test_Take();
- Test_LargeArray();
-}
-
-protected static function Test_GetSet()
-{
- local Text textObject;
- local AssociativeArray array;
- array = AssociativeArray(__().memory.Allocate(class'AssociativeArray'));
-
- Context("Testing getters and setters for items of `AssociativeArray`.");
- Issue("`SetItem()` does not correctly set new items.");
- textObject = __().text.FromString("value");
- array.SetItem(__().text.FromString("key"), textObject);
- array.SetItem(__().box.int(13), __().text.FromString("value #2"));
- array.SetItem(__().box.float(345.2), __().box.bool(true));
- TEST_ExpectTrue( Text(array.GetItem(__().box.int(13))).ToString()
- == "value #2");
- TEST_ExpectTrue(array.GetItem(__().text.FromString("key")) == textObject);
- TEST_ExpectTrue(BoolBox(array.GetItem(__().box.float(345.2))).Get());
-
- Issue("`SetItem()` does not correctly overwrite new items.");
- array.SetItem(__().text.FromString("key"), __().text.FromString("value"));
- array.SetItem(__().box.int(13), __().box.int(11));
- TEST_ExpectFalse(array.GetItem(__().text.FromString("key")) == textObject);
- TEST_ExpectTrue( Text(array.GetItem(__().text.FromString("key")))
- .ToString() == "value");
- TEST_ExpectTrue( IntBox(array.GetItem(__().box.int(13))).Get()
- == 11);
-
- Issue("`GetItem()` does not return `none` for non-existing keys.");
- TEST_ExpectNone(array.GetItem(__().box.int(12)));
- TEST_ExpectNone(array.GetItem(__().box.byte(67)));
- TEST_ExpectNone(array.GetItem(__().box.float(43.1234)));
- TEST_ExpectNone(array.GetItem(__().text.FromString("Some random stuff")));
-}
-
-protected static function Test_HasKey()
-{
- local AssociativeArray array;
- array = AssociativeArray(__().memory.Allocate(class'AssociativeArray'));
- Context("Testing `HasKey()` 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("`HasKey()` reports that added keys do not exist in"
- @ "`AssociativeArray`.");
- TEST_ExpectTrue(array.HasKey(__().text.FromString("key")));
- TEST_ExpectTrue(array.HasKey(__().box.int(13)));
- TEST_ExpectTrue(array.HasKey(__().box.float(345.2)));
-
- Issue("`HasKey()` reports that `AssociativeArray` contains keys that"
- @ "were never added.");
- TEST_ExpectFalse(array.HasKey(none));
- TEST_ExpectFalse(array.HasKey(__().box.float(13)));
- TEST_ExpectFalse(array.HasKey(__().box.byte(139)));
-}
-
-protected static function Test_GetKeys()
-{
- local int i;
- local AcediaObject key1, key2, key3;
- local array keys;
- local AssociativeArray array;
- array = AssociativeArray(__().memory.Allocate(class'AssociativeArray'));
- Context("Testing `GetKeys()` method for `AssociativeArray`.");
- key1 = __().text.FromString("key");
- key2 = __().box.int(13);
- key3 = __().box.float(345.2);
- array.SetItem(key1, __().text.FromString("value"));
- array.SetItem(key2, __().text.FromString("value #2"));
- array.SetItem(key3, __().box.bool(true));
- keys = array.GetKeys();
- Issue("`GetKeys()` returns array with wrong amount of elements.");
- TEST_ExpectTrue(keys.length == 3);
-
- Issue("`GetKeys()` returns array with duplicate keys.");
- TEST_ExpectTrue(keys[0] != keys[1]);
- TEST_ExpectTrue(keys[0] != keys[2]);
- TEST_ExpectTrue(keys[1] != keys[2]);
-
- Issue("`GetKeys()` returns array with incorrect keys.");
- for (i = 0; i < 3; i += 1) {
- TEST_ExpectTrue(keys[i] == key1 || keys[i] == key2 || keys[i] == key3);
- }
-
- keys = array.RemoveItem(key1).GetKeys();
- Issue("`GetKeys()` returns array with incorrect keys after removing"
- @ "an element.");
- TEST_ExpectTrue(keys.length == 2);
- TEST_ExpectTrue(keys[0] != keys[1]);
- for (i = 0; i < 2; i += 1) {
- TEST_ExpectTrue(keys[i] == key2 || keys[i] == key3);
- }
-}
-
-protected static function Test_CopyTextKeys()
-{
- local array allKeys;
- local array keys;
- local AssociativeArray array;
- array = AssociativeArray(__().memory.Allocate(class'AssociativeArray'));
- Context("Testing `CopyTextKeys()` method for `AssociativeArray`.");
- array.SetItem(__().text.FromString("key"), __().text.FromString("value"));
- array.SetItem(__().box.int(13), __().text.FromString("value #2"));
- array.SetItem(__().box.float(-925.274), __().text.FromString("value #2"));
- array.SetItem(__().text.FromString("second key"), __().box.bool(true));
-
- Issue("`CopyTextKeys()` does not return correct set of keys.");
- keys = array.CopyTextKeys();
- TEST_ExpectTrue(keys.length == 2);
- TEST_ExpectTrue(
- (keys[0].ToString() == "key"
- && keys[1].ToString() == "second key")
- || (keys[0].ToString() == "second key"
- && keys[1].ToString() == "key"));
-
- Issue("Deallocating keys returned by `CopyTextKeys()` affects their"
- @ "source collection.");
- allKeys = array.GetKeys();
- TEST_ExpectTrue(allKeys.length == 4);
- TEST_ExpectNotNone(array.GetItem(__().text.FromString("key")));
- TEST_ExpectNotNone(array.GetItem(__().text.FromString("second key")));
- TEST_ExpectTrue(
- array.GetText(__().text.FromString("key")).ToString() == "value");
-}
-
-protected static function Test_Remove()
-{
- Context("Testing removing elements from `AssociativeArray`.");
- SubTest_RemoveWithoutKeys();
- SubTest_RemoveWithKeys();
-}
-
-protected static function SubTest_RemoveWithoutKeys()
-{
- local AcediaObject key1, key2, key3;
- local array keys;
- local AssociativeArray array;
- array = AssociativeArray(__().memory.Allocate(class'AssociativeArray'));
- key1 = __().text.FromString("some key");
- key2 = __().box.int(25);
- key3 = __().box.float(0.07);
- array.SetItem(key1, __().text.FromString("value"));
- array.SetItem(key2, __().text.FromString("value #2"));
- array.SetItem(key3, __().box.bool(true));
- Issue("Elements are not properly removed from `AssociativeArray`.");
- array.RemoveItem(key1)
- .RemoveItem(__().box.int(25))
- .RemoveItem(__().box.float(0.06));
- keys = array.GetKeys();
- TEST_ExpectTrue(array.GetLength() == 1);
- TEST_ExpectTrue(keys.length == 1);
- TEST_ExpectTrue(keys[0] == key3);
-
- Issue("Keys are deallocated upon removing elements from `AssociativeArray`"
- @ "when they should not.");
- TEST_ExpectTrue(key1.IsAllocated());
- TEST_ExpectTrue(key2.IsAllocated());
-}
-
-protected static function SubTest_RemoveWithKeys()
-{
- local AcediaObject key1, key2, key3;
- local array keys;
- local AssociativeArray array;
- array = AssociativeArray(__().memory.Allocate(class'AssociativeArray'));
- key1 = __().text.FromString("some key");
- key2 = __().box.int(25);
- key3 = __().box.float(0.07);
- array.SetItem(key1, __().text.FromString("value"));
- array.SetItem(key2, __().text.FromString("value #2"));
- array.SetItem(key3, __().box.bool(true));
- Issue("Elements are not properly removed from `AssociativeArray`.");
- array.RemoveItem(key1, true)
- .RemoveItem(__().box.int(25), true)
- .RemoveItem(__().box.float(0.06), true);
- keys = array.GetKeys();
- TEST_ExpectTrue(array.GetLength() == 1);
- TEST_ExpectTrue(keys.length == 1);
- TEST_ExpectTrue(keys[0] == key3);
-
- Issue("Keys are not deallocated upon removing elements from"
- @ "`AssociativeArray` when they should.");
- TEST_ExpectFalse(key1.IsAllocated());
- TEST_ExpectFalse(key2.IsAllocated());
-}
-
-protected static function Test_CreateItem()
-{
- local AssociativeArray array;
- array = AssociativeArray(__().memory.Allocate(class'AssociativeArray'));
- Context("Testing creating brand new items for `AssociativeArray`.");
- Issue("`CreateItem()` incorrectly adds new values to the"
- @ "`AssociativeArray`.");
- array.CreateItem(__().text.FromString("key"), class'Text');
- array.CreateItem(__().box.float(17.895), class'IntRef');
- array.CreateItem(__().text.FromString("key #2"), class'BoolBox');
- TEST_ExpectTrue(Text(array.GetItem(__().text.FromString("key")))
- .ToString() == "");
- TEST_ExpectTrue( IntRef(array.GetItem(__().box.float(17.895))).Get()
- == 0);
- TEST_ExpectFalse(BoolBox(array.GetItem(__().text.FromString("key #2")))
- .Get());
-
- Issue("`CreateItem()` incorrectly overrides existing values in the"
- @ "`AssociativeArray`.");
- array.SetItem(__().box.int(13), __().ref.int(7));
- array.CreateItem(__().box.int(13), class'StringRef');
- TEST_ExpectTrue( StringRef(array.GetItem(__().box.int(13))).Get()
- == "");
-
- class'MockItem'.default.objectCount = 0;
- Issue("`CreateItem()` creates new object even if it cannot be recorded with"
- @ "a given key.");
- array.CreateItem(none, class'MockItem');
- TEST_ExpectTrue(class'MockItem'.default.objectCount == 0);
-}
-
-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`.");
- 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()
-{
- local AssociativeArray array;
- array = AssociativeArray(__().memory.Allocate(class'AssociativeArray'));
- Context("Testing computing length of `AssociativeArray`.");
- Issue("Length is not zero for newly created `AssociativeArray`.");
- TEST_ExpectTrue(array.GetLength() == 0);
-
- Issue("Length is incorrectly computed after adding elements to"
- @ "`AssociativeArray`.");
- array.SetItem(__().text.FromString("key"), __().text.FromString("value"));
- array.SetItem(__().box.int(4563), __().text.FromString("value #2"));
- array.SetItem(__().box.float(3425.243), __().box.byte(23));
- TEST_ExpectTrue(array.GetLength() == 3);
-
- Issue("Length is incorrectly computed after removing elements from"
- @ "`AssociativeArray`.");
- array.RemoveItem(__().box.int(4563));
- TEST_ExpectTrue(array.GetLength() == 2);
-}
-
-protected static function MockItem NewMockItem()
-{
- return MockItem(__().memory.Allocate(class'MockItem'));
-}
-
-protected static function Test_Managed()
-{
- local AssociativeArray array;
- class'MockItem'.default.objectCount = 0;
- array = AssociativeArray(__().memory.Allocate(class'AssociativeArray'));
- array.SetItem(__().box.int(0), NewMockItem());
- array.SetItem(__().box.int(1), NewMockItem());
- array.SetItem(__().box.int(2), NewMockItem());
- array.SetItem(__().box.int(3), NewMockItem(), true);
- array.SetItem(__().box.int(4), NewMockItem(), true);
- array.SetItem(__().box.int(5), NewMockItem(), true);
- array.CreateItem(__().box.int(6), class'MockItem');
- array.CreateItem(__().box.int(7), class'MockItem');
- array.CreateItem(__().box.int(8), class'MockItem');
- Context("Testing how `AssociativeArray` deallocates managed objects.");
- Issue("`RemoveItem()` incorrectly deallocates managed items.");
- array.RemoveItem(__().box.int(0));
- array.RemoveItem(__().box.int(3));
- array.RemoveItem(__().box.int(6));
- TEST_ExpectTrue(class'MockItem'.default.objectCount == 7);
-
- Issue("Rewriting values with `SetItem()` incorrectly handles"
- @ "managed items.");
- array.SetItem(__().box.int(1), __().ref.int(28347));
- array.SetItem(__().box.int(4), __().ref.float(13.4));
- array.SetItem(__().box.int(7), __().ref.byte(94));
- TEST_ExpectTrue(class'MockItem'.default.objectCount == 5);
-
- Issue("Rewriting values with `CreateItem()` incorrectly handles"
- @ "managed items.");
- array.CreateItem(__().box.int(2), class'IntRef');
- array.CreateItem(__().box.int(5), class'StringRef');
- array.CreateItem(__().box.int(8), class'IntArrayBox');
- TEST_ExpectTrue(class'MockItem'.default.objectCount == 3);
-}
-
-protected static function Test_DeallocationHandling()
-{
- Context("Testing how `AssociativeArray` deals with external deallocation of"
- @ "keys and managed objects.");
- SubTest_DeallocationHandlingKeys();
- SubTest_DeallocationHandlingManagedObjects();
-}
-
-protected static function SubTest_DeallocationHandlingKeys()
-{
- local IntBox key1;
- local BoolBox key2;
- local Text key3;
- local AssociativeArray array;
- local array keys;
- key1 = __().box.int(3881);
- key2 = __().box.bool(true);
- key3 = __().text.FromString("Text key, bay bee");
- array = AssociativeArray(__().memory.Allocate(class'AssociativeArray'));
- class'MockItem'.default.objectCount = 0;
- array.SetItem(key1, NewMockItem());
- array.SetItem(key2, __().box.float(32.31), true);
- array.SetItem(key3, NewMockItem(), true);
-
- Issue("Deallocating keys does not remove them from `AssociativeArray`.");
- key1.FreeSelf();
- key3.FreeSelf();
- keys = array.GetKeys();
- TEST_ExpectTrue(keys.length == 1);
- TEST_ExpectTrue(keys[0] == key2);
-
- Issue("`AssociativeArray` does not deallocate managed objects, even though"
- @ "their keys were deallocated");
- TEST_ExpectTrue(class'MockItem'.default.objectCount < 2);
- TEST_ExpectNone(array.GetItem(__().box.int(3881)));
-
- Issue("`AssociativeArray` deallocates unmanaged objects, when"
- @ "their keys were deallocated");
- TEST_ExpectTrue(class'MockItem'.default.objectCount > 0);
-}
-
-protected static function SubTest_DeallocationHandlingManagedObjects()
-{
- local MockItem exampleItem;
- local AssociativeArray array;
- class'MockItem'.default.objectCount = 0;
- exampleItem = NewMockItem();
- array = AssociativeArray(__().memory.Allocate(class'AssociativeArray'));
- array.SetItem(__().box.int(-34), exampleItem, true);
- array.SetItem(__().box.int(-7), exampleItem, true);
- array.SetItem(__().box.int(23), NewMockItem());
- array.SetItem(__().box.int(242), NewMockItem(), true);
- array.CreateItem(__().box.int(24532), class'MockItem');
- Issue("`AssociativeArray` does not return `none` even though stored object"
- @ "was already deallocated.");
- array.GetItem(__().box.int(23)).FreeSelf();
- TEST_ExpectTrue(class'MockItem'.default.objectCount == 3);
- TEST_ExpectTrue(array.GetItem(__().box.int(23)) == none);
-
- Issue("Managed items are not deallocated when they are duplicated inside"
- @ "`AssociativeArray`, but they should.");
- array.RemoveItem(__().box.int(-7));
- // At this point we got rid of all the managed objects that were generated
- // in `array` + deallocated `exampleObject`.
- TEST_ExpectTrue(class'MockItem'.default.objectCount == 2);
- TEST_ExpectTrue(array.GetItem(__().box.int(-34)) == none);
-}
-
-protected static function Test_Take()
-{
- local AssociativeArray.Entry entry;
- local AssociativeArray array;
- class'MockItem'.default.objectCount = 0;
- array = AssociativeArray(__().memory.Allocate(class'AssociativeArray'));
- array.SetItem(__().box.int(0), NewMockItem());
- array.SetItem(__().box.int(1), NewMockItem());
- array.SetItem(__().box.int(2), NewMockItem());
- array.SetItem(__().box.int(3), NewMockItem(), true);
- array.SetItem(__().box.int(4), NewMockItem(), true);
- array.SetItem(__().box.int(5), NewMockItem(), true);
- array.CreateItem(__().box.int(6), class'MockItem');
- array.CreateItem(__().box.int(7), class'MockItem');
- array.CreateItem(__().box.int(8), class'MockItem');
- Context("Testing `TakeItem()` method of `AssociativeArray`.");
- Issue("`TakeItem()` returns incorrect value.");
- TEST_ExpectTrue(array.TakeItem(__().box.int(0)).class == class'MockItem');
- TEST_ExpectTrue(array.TakeItem(__().box.int(3)).class == class'MockItem');
- TEST_ExpectTrue(array.TakeItem(__().box.int(6)).class == class'MockItem');
-
- Issue("`TakeEntry()` returns incorrect value.");
- entry = array.TakeEntry(__().box.int(4));
- TEST_ExpectTrue(entry.key.class == class'IntBox');
- TEST_ExpectTrue(entry.value.class == class'MockItem');
- entry = array.TakeEntry(__().box.int(7));
- TEST_ExpectTrue(entry.key.class == class'IntBox');
- TEST_ExpectTrue(entry.value.class == class'MockItem');
-
- Issue("Objects returned by `Take()` and `takeEntry()` are still managed by"
- @ "`AssociativeArray`.");
- array.Empty();
- TEST_ExpectTrue(class'MockItem'.default.objectCount == 7);
-}
-
-protected static function Test_LargeArray()
-{
- local int i;
- local AcediaObject nextKey;
- local AssociativeArray array;
- Context("Testing storing large amount of elements in `AssociativeArray`.");
- Issue("`AssociativeArray` cannot handle large amount of elements.");
- array = AssociativeArray(__().memory.Allocate(class'AssociativeArray'));
- for (i = 0; i < 2500; i += 1) {
- if (i % 2 == 0) {
- nextKey = __().text.FromString("var" @ i);
- }
- else {
- nextKey = __().box.int(i * 56 - 435632);
- }
- array.SetItem(nextKey, __().ref.int(i));
- }
- for (i = 0; i < 2500; i += 1) {
- if (i % 2 == 0) {
- nextKey = __().text.FromString("var" @ i);
- }
- else {
- nextKey = __().box.int(i * 56 - 435632);
- }
- TEST_ExpectTrue(IntRef(array.GetItem(nextKey)).Get() == i);
- }
-}
-
-defaultproperties
-{
- caseGroup = "Collections"
- caseName = "AssociativeArray"
-}
\ No newline at end of file
diff --git a/sources/Data/Collections/Tests/TEST_DynamicArray.uc b/sources/Data/Collections/Tests/TEST_DynamicArray.uc
deleted file mode 100644
index f2b96fa..0000000
--- a/sources/Data/Collections/Tests/TEST_DynamicArray.uc
+++ /dev/null
@@ -1,322 +0,0 @@
-/**
- * Set of tests for `DynamicArray` class.
- * Copyright 2020 Anton Tarasenko
- *------------------------------------------------------------------------------
- * This file is part of Acedia.
- *
- * Acedia is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, version 3 of the License, or
- * (at your option) any later version.
- *
- * Acedia is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Acedia. If not, see .
- */
-class TEST_DynamicArray extends TestCase
- abstract;
-
-protected static function TESTS()
-{
- Test_GetSet();
- Test_CreateItem();
- Test_Length();
- Test_Empty();
- Test_AddInsert();
- Test_Remove();
- Test_Find();
- Test_Managed();
- Test_DeallocationHandling();
- Test_Take();
-}
-
-protected static function Test_GetSet()
-{
- local DynamicArray array;
- array = DynamicArray(__().memory.Allocate(class'DynamicArray'));
- Context("Testing getters and setters for items of `DynamicArray`.");
- Issue("Setters do not correctly expand `DynamicArray`.");
- array.SetItem(0, __().box.int(-9)).SetItem(2, __().text.FromString("text"));
- TEST_ExpectTrue(array.GetLength() == 3);
- TEST_ExpectTrue(IntBox(array.GetItem(0)).Get() == -9);
- TEST_ExpectNone(array.GetItem(1));
- TEST_ExpectTrue(Text(array.GetItem(2)).ToString() == "text");
-
- Issue("Setters do not correctly overwrite items of `DynamicArray`.");
- array.SetItem(1, __().box.float(34.76));
- array.SetItem(2, none);
- TEST_ExpectTrue(array.GetLength() == 3);
- TEST_ExpectTrue(IntBox(array.GetItem(0)).Get() == -9);
- TEST_ExpectTrue(FloatBox(array.GetItem(1)).Get() == 34.76);
- TEST_ExpectNone(array.GetItem(2));
-}
-
-protected static function Test_CreateItem()
-{
- local DynamicArray array;
- array = DynamicArray(__().memory.Allocate(class'DynamicArray'));
- Context("Testing creating brand new items for `DynamicArray`.");
- Issue("`CreateItem()` incorrectly adds new values to the"
- @ "`DynamicArray`.");
- array.CreateItem(1, class'Text');
- array.CreateItem(3, class'IntRef');
- array.CreateItem(4, class'BoolBox');
- TEST_ExpectNone(array.GetItem(0));
- TEST_ExpectNone(array.GetItem(2));
- TEST_ExpectTrue(Text(array.GetItem(1)).ToString() == "");
- TEST_ExpectTrue(IntRef(array.GetItem(3)).Get() == 0);
- TEST_ExpectFalse(BoolBox(array.GetItem(4)).Get());
-
- Issue("`CreateItem()` incorrectly overrides existing values in the"
- @ "`DynamicArray`.");
- array.SetItem(5, __().ref.int(7));
- array.CreateItem(5, class'StringRef');
- TEST_ExpectTrue(StringRef(array.GetItem(5)).Get() == "");
-
- class'MockItem'.default.objectCount = 0;
- Issue("`CreateItem()` creates new object even if it cannot be recorded at"
- @ "a given index.");
- array.CreateItem(-1, class'MockItem');
- TEST_ExpectTrue(class'MockItem'.default.objectCount == 0);
-}
-
-protected static function Test_Length()
-{
- local DynamicArray array;
- array = DynamicArray(__().memory.Allocate(class'DynamicArray'));
- Context("Testing length getter and setter for `DynamicArray`.");
- Issue("Length of just created `DynamicArray` is not zero.");
- TEST_ExpectTrue(array.GetLength() == 0);
-
- Issue("`SetLength()` incorrectly changes length of the `DynamicArray`.");
- array.SetLength(200).SetItem(198, __().box.int(25));
- TEST_ExpectTrue(array.GetLength() == 200);
- TEST_ExpectTrue(IntBox(array.GetItem(198)).Get() == 25);
- array.SetLength(0);
- TEST_ExpectTrue(array.GetLength() == 0);
-
- Issue("Shrinking size of `DynamicArray` does not remove recorded items.");
- array.SetLength(1000);
- TEST_ExpectNone(array.GetItem(198));
-}
-
-protected static function Test_Empty()
-{
- local DynamicArray array;
- array = DynamicArray(__().memory.Allocate(class'DynamicArray'));
- Context("Testing emptying `DynamicArray`.");
- array.AddItem(__().box.int(1)).AddItem(__().box.int(3))
- .AddItem(__().box.int(1)).AddItem(__().box.int(3));
- Issue("`Empty()` does not produce an empty array.");
- array.Empty();
- TEST_ExpectTrue(array.GetLength() == 0);
-}
-
-protected static function Test_AddInsert()
-{
- local DynamicArray array;
- array = DynamicArray(__().memory.Allocate(class'DynamicArray'));
- Context("Testing adding new items to `DynamicArray`.");
- Issue("`Add()`/`AddItem()` incorrectly add new items to"
- @ "the `DynamicArray`.");
- array.AddItem(__().box.int(3)).Add(3).AddItem(__().box.byte(7)).Add(1);
- TEST_ExpectTrue(array.GetLength() == 6);
- TEST_ExpectNotNone(IntBox(array.GetItem(0)));
- TEST_ExpectTrue(IntBox(array.GetItem(0)).Get() == 3);
- TEST_ExpectNone(array.GetItem(1));
- TEST_ExpectNone(array.GetItem(2));
- TEST_ExpectNone(array.GetItem(3));
- TEST_ExpectNotNone(ByteBox(array.GetItem(4)));
- TEST_ExpectTrue(ByteBox(array.GetItem(4)).Get() == 7);
- TEST_ExpectNone(array.GetItem(5));
-
- Issue("`Insert()`/`InsertItem()` incorrectly add new items to"
- @ "the `DynamicArray`.");
- array.Insert(2, 2).InsertItem(0, __().ref.bool(true));
- TEST_ExpectTrue(array.GetLength() == 9);
- TEST_ExpectNotNone(BoolRef(array.GetItem(0)));
- TEST_ExpectTrue(BoolRef(array.GetItem(0)).Get());
- TEST_ExpectNotNone(IntBox(array.GetItem(1)));
- TEST_ExpectTrue(IntBox(array.GetItem(1)).Get() == 3);
- TEST_ExpectNone(array.GetItem(2));
- TEST_ExpectNone(array.GetItem(6));
- TEST_ExpectNotNone(ByteBox(array.GetItem(7)));
- TEST_ExpectTrue(ByteBox(array.GetItem(7)).Get() == 7);
- TEST_ExpectNone(array.GetItem(8));
-}
-
-protected static function Test_Remove()
-{
- local DynamicArray array;
- array = DynamicArray(__().memory.Allocate(class'DynamicArray'));
- Context("Testing removing items from `DynamicArray`.");
- array.AddItem(__().box.int(1)).AddItem(__().box.int(3))
- .AddItem(__().box.int(1)).AddItem(__().box.int(3))
- .AddItem(__().box.int(5)).AddItem(__().box.int(2))
- .AddItem(__().box.int(4)).AddItem(__().box.int(7))
- .AddItem(__().box.int(5)).AddItem(__().box.int(1))
- .AddItem(__().box.int(5)).AddItem(__().box.int(0));
- Issue("`Remove()` incorrectly removes items from array.");
- array.Remove(3, 2).Remove(0, 2).Remove(7, 9);
- TEST_ExpectTrue(array.GetLength() == 7);
- TEST_ExpectTrue(IntBox(array.GetItem(0)).Get() == 1);
- TEST_ExpectTrue(IntBox(array.GetItem(1)).Get() == 2);
- TEST_ExpectTrue(IntBox(array.GetItem(2)).Get() == 4);
- TEST_ExpectTrue(IntBox(array.GetItem(3)).Get() == 7);
- TEST_ExpectTrue(IntBox(array.GetItem(4)).Get() == 5);
- TEST_ExpectTrue(IntBox(array.GetItem(5)).Get() == 1);
- TEST_ExpectTrue(IntBox(array.GetItem(6)).Get() == 5);
-
- Issue("`RemoveItem()` incorrectly removes items from array.");
- array.RemoveItem(__().box.int(1)).RemoveItem(__().box.int(5), true);
- TEST_ExpectTrue(array.GetLength() == 4);
- TEST_ExpectTrue(IntBox(array.GetItem(0)).Get() == 2);
- TEST_ExpectTrue(IntBox(array.GetItem(1)).Get() == 4);
- TEST_ExpectTrue(IntBox(array.GetItem(2)).Get() == 7);
- TEST_ExpectTrue(IntBox(array.GetItem(3)).Get() == 5);
-
- Issue("`RemoveIndex()` incorrectly removes items from array.");
- array.RemoveIndex(0).RemoveIndex(1).RemoveIndex(1);
- TEST_ExpectTrue(array.GetLength() == 1);
- TEST_ExpectTrue(IntBox(array.GetItem(0)).Get() == 4);
-}
-
-protected static function Test_Find()
-{
- local DynamicArray array;
- array = DynamicArray(__().memory.Allocate(class'DynamicArray'));
- Context("Testing searching for items in `DynamicArray`.");
- array.AddItem(__().box.int(1)).AddItem(__().box.int(3))
- .AddItem(__().box.int(1)).AddItem(__().box.int(3))
- .AddItem(__().box.int(5)).AddItem(__().box.bool(true))
- .AddItem(none).AddItem(__().box.float(72.54))
- .AddItem(__().box.int(5)).AddItem(__().box.int(1))
- .AddItem(__().box.int(5)).AddItem(__().box.int(0));
- Issue("`Find()` does not properly find indices of existing items.");
- TEST_ExpectTrue(array.Find(__().box.int(5)) == 4);
- TEST_ExpectTrue(array.Find(__().box.int(1)) == 0);
- TEST_ExpectTrue(array.Find(__().box.int(0)) == 11);
- TEST_ExpectTrue(array.Find(__().box.float(72.54)) == 7);
- TEST_ExpectTrue(array.Find(__().box.bool(true)) == 5);
- TEST_ExpectTrue(array.Find(none) == 6);
-
- Issue("`Find()` does not return `-1` on missing values.");
- TEST_ExpectTrue(array.Find(__().box.int(42)) == -1);
- TEST_ExpectTrue(array.Find(__().box.float(72.543)) == -1);
- TEST_ExpectTrue(array.Find(__().box.bool(false)) == -1);
- TEST_ExpectTrue(array.Find(__().box.byte(128)) == -1);
-}
-
-protected static function MockItem NewMockItem()
-{
- return MockItem(__().memory.Allocate(class'MockItem'));
-}
-
-// Creates array with mock objects, also zeroing their count.
-// Managed items' count: 6, but 12 items total.
-protected static function DynamicArray NewMockArray()
-{
- local DynamicArray array;
- class'MockItem'.default.objectCount = 0;
- array = DynamicArray(__().memory.Allocate(class'DynamicArray'));
- array.AddItem(NewMockItem(), true).AddItem(NewMockItem(), false)
- .InsertItem(2, NewMockItem(), true).AddItem(NewMockItem(), true)
- .AddItem(NewMockItem(), false).AddItem(NewMockItem(), true)
- .InsertItem(6, NewMockItem(), false).AddItem(NewMockItem(), true)
- .InsertItem(3, NewMockItem(), false).AddItem(NewMockItem(), false)
- .InsertItem(10, NewMockItem(), true).AddItem(NewMockItem(), false);
- return array;
-}
-
-protected static function Test_Managed()
-{
- local MockItem exampleItem;
- local DynamicArray array;
- exampleItem = NewMockItem();
- // Managed items' count: 6, but 12 items total.
- array = NewMockArray();
- Context("Testing how `DynamicArray` deallocates managed objects.");
- Issue("`Remove()` incorrectly deallocates managed items.");
- // -2 managed items
- array.Remove(3, 2).Remove(0, 2).Remove(7, 9);
- TEST_ExpectTrue(class'MockItem'.default.objectCount == 10);
-
- Issue("`RemoveIndex()` incorrectly deallocates managed items.");
- // -1 managed items
- array.RemoveIndex(3).RemoveIndex(0);
- TEST_ExpectTrue(class'MockItem'.default.objectCount == 9);
- // -1 managed items
- array.RemoveItem(exampleItem, true).RemoveItem(exampleItem, true);
- TEST_ExpectTrue(class'MockItem'.default.objectCount == 8);
- // -2 managed items
- array.RemoveItem(exampleItem);
- TEST_ExpectTrue(class'MockItem'.default.objectCount == 6);
-
- array = NewMockArray();
- Issue("Shrinking array with `SetLength()` incorrectly handles"
- @ "managed items");
- // -4 managed items
- array.SetLength(3);
- TEST_ExpectTrue(class'MockItem'.default.objectCount == 8);
-
- Issue("Rewriting values with `SetItem()` incorrectly handles"
- @ "managed items.");
- // -2 managed items
- array.SetItem(0, exampleItem, true);
- array.SetItem(2, exampleItem, true);
- TEST_ExpectTrue(class'MockItem'.default.objectCount == 6);
-}
-
-protected static function Test_DeallocationHandling()
-{
- local MockItem exampleItem;
- local DynamicArray array;
- exampleItem = NewMockItem();
- // Managed items' count: 6, but 12 items total.
- array = NewMockArray();
- Context("Testing how `DynamicArray` deals with external deallocation of"
- @ "managed objects.");
- Issue("`DynamicArray` does not return `none` even though stored object"
- @ "was already deallocated.");
- array.GetItem(0).FreeSelf();
- TEST_ExpectTrue(class'MockItem'.default.objectCount == 11);
- TEST_ExpectTrue(array.GetItem(0) == none);
-
- Issue("Managed items are not deallocated when they are duplicated inside"
- @ "`DynamicArray`, but they should.");
- array.SetItem(1, exampleItem, true).SetItem(2, exampleItem, true);
- TEST_ExpectTrue(class'MockItem'.default.objectCount == 10);
- array.SetLength(2);
- // At this point we got rid of all the managed objects that were generated
- // in `array` + deallocated `exampleObject`.
- TEST_ExpectTrue(class'MockItem'.default.objectCount == 5);
- TEST_ExpectTrue(array.GetItem(1) == none);
-}
-
-protected static function Test_Take()
-{
- local DynamicArray array;
- Context("Testing `TakeItem()` method of `DynamicArray`.");
- // Managed items' count: 6, but 12 items total.
- array = NewMockArray();
- Issue("`TakeItem()` returns incorrect value.");
- TEST_ExpectTrue(array.TakeItem(0).class == class'MockItem');
- TEST_ExpectTrue(array.TakeItem(3).class == class'MockItem');
- TEST_ExpectTrue(array.TakeItem(4).class == class'MockItem');
- TEST_ExpectTrue(array.TakeItem(6).class == class'MockItem');
-
- Issue("Objects returned by `TakeItem()` are still managed by"
- @ "`DynamicArray`.");
- array.Empty();
- TEST_ExpectTrue(class'MockItem'.default.objectCount == 9);
-}
-
-defaultproperties
-{
- caseGroup = "Collections"
- caseName = "DynamicArray"
-}
\ No newline at end of file
diff --git a/sources/Data/Collections/Tests/TEST_IteratorOld.uc b/sources/Data/Collections/Tests/TEST_IteratorOld.uc
deleted file mode 100644
index cb7bc4c..0000000
--- a/sources/Data/Collections/Tests/TEST_IteratorOld.uc
+++ /dev/null
@@ -1,143 +0,0 @@
-/**
- * Set of tests for `Iterator` classes.
- * Copyright 2020 Anton Tarasenko
- *------------------------------------------------------------------------------
- * This file is part of Acedia.
- *
- * Acedia is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, version 3 of the License, or
- * (at your option) any later version.
- *
- * Acedia is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Acedia. If not, see .
- */
-class TEST_IteratorOld extends TestCase
- abstract;
-
-var const int TESTED_ITEMS_AMOUNT;
-var array items;
-var array seenFlags;
-
-protected static function CreateItems()
-{
- local int i;
- ResetFlags();
- for (i = 0; i < default.TESTED_ITEMS_AMOUNT; i += 1) {
- default.items[default.items.length] = __().ref.float(i*2 + 1/i);
- }
-}
-
-protected static function ResetFlags()
-{
- default.seenFlags.length = 0;
- default.seenFlags.length = default.TESTED_ITEMS_AMOUNT;
-}
-
-protected static function DoTestIterator(Iter iter)
-{
- local int i;
- local int seenCount;
- local AcediaObject nextObject;
- ResetFlags();
- while (!iter.HasFinished())
- {
- nextObject = iter.Get();
- for (i = 0; i < default.items.length; i += 1)
- {
- if (default.items[i] == nextObject)
- {
- if (default.seenFlags[i] == 0) {
- seenCount += 1;
- }
- default.seenFlags[i] = 1;
- continue;
- }
- }
- iter.Next();
- }
- TEST_ExpectTrue(seenCount == default.TESTED_ITEMS_AMOUNT);
-}
-
-protected static function TESTS()
-{
- // Prepare
- CreateItems();
- // Test
- Test_DynamicArray();
- Test_AssociativeArray();
-}
-
-protected static function Test_DynamicArray()
-{
- local int i;
- local CollectionIterator iter;
- local DynamicArray array;
-
- array = DynamicArray(__().memory.Allocate(class'DynamicArray'));
- iter = array.Iterate();
- Context("Testing iterator for `DynamicArray`");
- Issue("`DynamicArray` returns `none` iterator.");
- TEST_ExpectNotNone(iter);
-
- Issue("Iterator for empty `DynamicArray` is not finished by default.");
- TEST_ExpectTrue(iter.HasFinished());
-
- Issue("Iterator for empty `DynamicArray` does not return `none` as"
- @ "a current item.");
- TEST_ExpectNone(iter.Get());
- TEST_ExpectNone(iter.Next().Get());
-
- for (i = 0; i < default.items.length; i += 1) {
- array.AddItem(default.items[i]);
- }
- iter = array.Iterate();
- Issue("`DynamicArray` returns `none` iterator.");
- TEST_ExpectNotNone(iter);
-
- Issue("`DynamicArray`'s iterator iterates over incorrect set of items.");
- DoTestIterator(iter);
-}
-
-protected static function Test_AssociativeArray()
-{
- local int i;
- local CollectionIterator iter;
- local AssociativeArray array;
- array = AssociativeArray(__().memory.Allocate(class'AssociativeArray'));
- iter = array.Iterate();
- Context("Testing iterator for `AssociativeArray`");
- Issue("`AssociativeArray` returns `none` iterator.");
- TEST_ExpectNotNone(iter);
-
- Issue("Iterator for empty `AssociativeArray` is not finished by default.");
- TEST_ExpectTrue(iter.HasFinished());
-
- Issue("Iterator for empty `AssociativeArray` does not return `none` as"
- @ "a current item.");
- TEST_ExpectNone(iter.Get());
- TEST_ExpectNone(iter.Next().Get());
-
- for (i = 0; i < default.items.length; i += 1) {
- array.SetItem(__().box.int(i), default.items[i]);
- }
- iter = array.Iterate();
- Issue("`AssociativeArray` returns `none` iterator.");
- TEST_ExpectNotNone(iter);
-
- Issue("`AssociativeArray`'s iterator iterates over incorrect set of"
- @ "items.");
- DoTestIterator(iter);
-}
-
-defaultproperties
-{
- caseGroup = "Collections"
- caseName = "IteratorOld"
- TESTED_ITEMS_AMOUNT = 100
-}
\ No newline at end of file
diff --git a/sources/Data/Database/DBAPI.uc b/sources/Data/Database/DBAPI.uc
index a9ef625..df5f038 100644
--- a/sources/Data/Database/DBAPI.uc
+++ b/sources/Data/Database/DBAPI.uc
@@ -25,7 +25,7 @@ var private const class localDBClass;
// Store all already loaded databases to make sure we do not create two
// different `LocalDatabaseInstance` that are trying to make changes
// separately.
-var private AssociativeArray loadedLocalDatabases;
+var private HashTable loadedLocalDatabases;
var private LoggerAPI.Definition infoLocalDatabaseCreated;
var private LoggerAPI.Definition infoLocalDatabaseDeleted;
@@ -34,7 +34,7 @@ var private LoggerAPI.Definition infoLocalDatabaseLoaded;
private final function CreateLocalDBMapIfMissing()
{
if (loadedLocalDatabases == none) {
- loadedLocalDatabases = __().collections.EmptyAssociativeArray();
+ loadedLocalDatabases = __().collections.EmptyHashTable();
}
}
@@ -126,6 +126,7 @@ public final function LocalDatabaseInstance NewLocal(BaseText databaseName)
{
local DBRecord rootRecord;
local Text rootRecordName;
+ local Text databaseNameCopy;
local LocalDatabase newConfig;
local LocalDatabaseInstance newLocalDBInstance;
@@ -138,13 +139,14 @@ public final function LocalDatabaseInstance NewLocal(BaseText databaseName)
if (loadedLocalDatabases.HasKey(databaseName)) return none;
newLocalDBInstance = LocalDatabaseInstance(_.memory.Allocate(localDBClass));
- loadedLocalDatabases.SetItem(databaseName.Copy(), newLocalDBInstance);
+ databaseNameCopy = databaseName.Copy();
+ loadedLocalDatabases.SetItem(databaseNameCopy, newLocalDBInstance);
rootRecord = class'DBRecord'.static.NewRecord(databaseName);
rootRecordName = _.text.FromString(string(rootRecord.name));
newConfig.SetRootName(rootRecordName);
newConfig.Save();
newLocalDBInstance.Initialize(newConfig, rootRecord);
- _.logger.Auto(infoLocalDatabaseCreated).Arg(databaseName.Copy());
+ _.logger.Auto(infoLocalDatabaseCreated).Arg(databaseNameCopy);
_.memory.Free(rootRecordName);
return newLocalDBInstance;
}
@@ -201,6 +203,7 @@ public final function LocalDatabaseInstance LoadLocal(BaseText databaseName)
newLocalDBInstance.Initialize(newConfig, rootRecord);
_.logger.Auto(infoLocalDatabaseLoaded).Arg(databaseName.Copy());
_.memory.Free(rootRecordName);
+ _.memory.Free(newLocalDBInstance);
return newLocalDBInstance;
}
@@ -212,9 +215,16 @@ public final function LocalDatabaseInstance LoadLocal(BaseText databaseName)
*/
public final function bool ExistsLocal(BaseText databaseName)
{
- return LoadLocal(databaseName) != none;
+ local bool result;
+ local LocalDatabaseInstance instance;
+
+ instance = LoadLocal(databaseName);
+ result = (instance != none);
+ _.memory.Free(instance);
+ return result;
}
+// TODO: deleted database must be marked as disposed + change tests too
/**
* Deletes local database with name `databaseName`.
*
@@ -224,17 +234,19 @@ public final function bool ExistsLocal(BaseText databaseName)
*/
public final function bool DeleteLocal(BaseText databaseName)
{
- local LocalDatabase localDatabaseConfig;
- local LocalDatabaseInstance localDatabase;
- local AssociativeArray.Entry dbEntry;
+ local LocalDatabase localDatabaseConfig;
+ local LocalDatabaseInstance localDatabase;
+ local HashTable.Entry dbEntry;
if (databaseName == none) {
return false;
}
CreateLocalDBMapIfMissing();
// To delete database we first need to load it
localDatabase = LoadLocal(databaseName);
- if (localDatabase != none) {
+ if (localDatabase != none)
+ {
localDatabaseConfig = localDatabase.GetConfig();
+ _.memory.Free(localDatabase);
}
dbEntry = loadedLocalDatabases.TakeEntry(databaseName);
// Delete `LocalDatabaseInstance` before erasing the package,
diff --git a/sources/Data/Database/Tests/TEST_LocalDatabase.uc b/sources/Data/Database/Tests/TEST_LocalDatabase.uc
index 47fbd6f..fd4200a 100644
--- a/sources/Data/Database/Tests/TEST_LocalDatabase.uc
+++ b/sources/Data/Database/Tests/TEST_LocalDatabase.uc
@@ -243,6 +243,8 @@ protected static function Test_LoadingPrepared()
SubTest_LoadingPreparedGetSizeNegative(db);
SubTest_LoadingPreparedGetKeysSuccess(db);
SubTest_LoadingPreparedGetKeysFail(db);
+ __().memory.Free(db);
+ __().memory.Free(db);
}
protected static function SubTest_LoadingPreparedSuccessRoot(
@@ -491,6 +493,8 @@ protected static function Test_Writing()
Issue("`DeleteLocal()` does not return `true` after deleting existing"
@ "local database.");
+ __().memory.Free(db); // For `NewLocal()` call
+ __().memory.Free(db); // For `LoadLocal()` call
TEST_ExpectTrue(__().db.DeleteLocal(P("TEST_DB")));
Issue("Newly created database is reported to still exist after deletion.");
@@ -516,6 +520,7 @@ protected static function Test_Recreate()
SubTest_WritingArrayIndicies(db);
__().db.DeleteLocal(P("TEST_DB"));
Issue("Newly created database is reported to still exist after deletion.");
+ __().memory.Free(db);
TEST_ExpectFalse(__().db.ExistsLocal(P("TEST_DB")));
TEST_ExpectFalse(db.IsAllocated());
}
@@ -540,14 +545,14 @@ protected static function HashTable GetJSONSubTemplateObject()
{
local Parser parser;
parser = __().text.ParseString("{\"A\":\"simpleValue\",\"B\":11.12}");
- return HashTable(__().json.ParseWith(parser,, true));
+ return HashTable(__().json.ParseWith(parser));
}
protected static function ArrayList GetJSONSubTemplateArray()
{
local Parser parser;
parser = __().text.ParseString("[true, null, \"huh\"]");
- return ArrayList(__().json.ParseWith(parser,, true));
+ return ArrayList(__().json.ParseWith(parser));
}
/*
diff --git a/sources/Gameplay/KF1Frontend/BaseImplementation/EKFInventory.uc b/sources/Gameplay/KF1Frontend/BaseImplementation/EKFInventory.uc
index 0ec096c..cff004b 100644
--- a/sources/Gameplay/KF1Frontend/BaseImplementation/EKFInventory.uc
+++ b/sources/Gameplay/KF1Frontend/BaseImplementation/EKFInventory.uc
@@ -579,7 +579,7 @@ public function bool Remove(
local NativeActorRef pawnRef;
local Inventory nativeInstance;
local KFWeapon kfWeapon;
- local DynamicArray removalList;
+ local ArrayList removalList;
if (EAmmo(itemToRemove) != none) return false;
nativeInstance = GetItemNativeInstance(itemToRemove);
if (nativeInstance == none) return false;
@@ -600,8 +600,8 @@ public function bool Remove(
// guaranteed.
// Only optimize this if this method will become
// a bottleneck somewhere.
- removalList = _.collections.EmptyDynamicArray();
- removalList.AddItem(_server.unreal.ActorRef(nativeInstance), true);
+ removalList = _.collections.EmptyArrayList();
+ removalList.AddItem(_server.unreal.ActorRef(nativeInstance));
pawnRef = _server.unreal.ActorRef(pawn);
result = RemoveInventoryArray( pawnRef, removalList,
keepItem, forceRemoval, true);
@@ -623,7 +623,7 @@ public function bool RemoveTemplate(
local bool result;
local Pawn pawn;
local NativeActorRef pawnRef;
- local DynamicArray removalList;
+ local ArrayList removalList;
local class inventoryClass;
local class weaponClass;
if (template == none) return false;
@@ -635,7 +635,7 @@ public function bool RemoveTemplate(
if (pawn == none) return false;
pawnRef = _server.unreal.ActorRef(pawn);
- removalList = _.collections.EmptyDynamicArray();
+ removalList = _.collections.EmptyArrayList();
// All removal works the same - form a "kill list", then remove
// all `Inventory` at once with `RemoveInventoryArray`
AddClassForRemoval(removalList, inventoryClass, forceRemoval, removeAll);
@@ -654,7 +654,7 @@ public function bool RemoveTemplate(
// Searches `EKFInventory`'s owner's inventory chain for items of class
// `inventoryClass` and adds them to the `removalArray` (for later removal).
private function AddClassForRemoval(
- DynamicArray removalArray,
+ ArrayList removalArray,
class inventoryClass,
optional bool forceRemoval,
optional bool removeAll)
@@ -686,7 +686,7 @@ private function AddClassForRemoval(
}
if (canRemoveInventory)
{
- removalArray.AddItem(_server.unreal.ActorRef(nextInventory), true);
+ removalArray.AddItem(_server.unreal.ActorRef(nextInventory));
if (!removeAll) {
break;
}
@@ -709,12 +709,12 @@ public function bool RemoveAll(
local NativeActorRef pawnRef;
local KFWeapon kfWeapon;
local Inventory nextInventory;
- local DynamicArray inventoryToRemove;
+ local ArrayList inventoryToRemove;
pawn = GetOwnerPawn();
if (pawn == none) {
return false;
}
- inventoryToRemove = _.collections.EmptyDynamicArray();
+ inventoryToRemove = _.collections.EmptyArrayList();
nextInventory = pawn.inventory;
while (nextInventory != none)
{
@@ -723,11 +723,8 @@ public function bool RemoveAll(
&& (forceRemoval || !kfWeapon.bKFNeverThrow);
canRemoveItem = canRemoveItem
|| (includeHidden && Ammunition(nextInventory) == none);
- if (canRemoveItem)
- {
- inventoryToRemove.AddItem(
- _server.unreal.ActorRef(nextInventory),
- true);
+ if (canRemoveItem) {
+ inventoryToRemove.AddItem(_server.unreal.ActorRef(nextInventory));
}
nextInventory = nextInventory.inventory;
}
@@ -745,7 +742,7 @@ public function bool RemoveAll(
// dropped/removed.
private function bool RemoveInventoryArray(
NativeActorRef ownerPawnRef,
- DynamicArray itemsToRemove,
+ ArrayList itemsToRemove,
bool keepItems,
bool forceRemoval,
bool completeRemoval)
diff --git a/sources/Gameplay/KF1Frontend/World/KF1_EntityIterator.uc b/sources/Gameplay/KF1Frontend/World/KF1_EntityIterator.uc
index 287c373..00962f2 100644
--- a/sources/Gameplay/KF1Frontend/World/KF1_EntityIterator.uc
+++ b/sources/Gameplay/KF1Frontend/World/KF1_EntityIterator.uc
@@ -101,7 +101,7 @@ private final function TryIterating()
iterated = true;
}
-public function Iter Next(optional bool skipNone)
+public function Iter Next()
{
if (!initialized) {
return self;
diff --git a/sources/Gameplay/KF1Frontend/World/KF1_TracingIterator.uc b/sources/Gameplay/KF1Frontend/World/KF1_TracingIterator.uc
index 549802c..7767e99 100644
--- a/sources/Gameplay/KF1Frontend/World/KF1_TracingIterator.uc
+++ b/sources/Gameplay/KF1Frontend/World/KF1_TracingIterator.uc
@@ -126,7 +126,7 @@ private final function TryTracing()
traced = true;
}
-public function Iter Next(optional bool skipNone)
+public function Iter Next()
{
if (!initialized) {
return self;
diff --git a/sources/Logger/Logger.uc b/sources/Logger/Logger.uc
index 7240897..b05c5c5 100644
--- a/sources/Logger/Logger.uc
+++ b/sources/Logger/Logger.uc
@@ -33,7 +33,7 @@ class Logger extends AcediaObject
abstract;
// Named loggers are stored here to avoid recreating them
-var protected AssociativeArray loadedLoggers;
+var protected HashTable loadedLoggers;
// Should `Logger` display prefix indicating it's a log message from Acedia?
var protected config bool acediaStamp;
@@ -68,7 +68,7 @@ public final static function Logger GetLogger(BaseText loggerName)
return none;
}
if (default.loadedLoggers == none) {
- default.loadedLoggers = __().collections.EmptyAssociativeArray();
+ default.loadedLoggers = __().collections.EmptyHashTable();
}
loggerKey = loggerName.LowerCopy();
loggerInstance = Logger(default.loadedLoggers.GetItem(loggerKey));
diff --git a/sources/Text/JSON/JSONAPI.uc b/sources/Text/JSON/JSONAPI.uc
index 7895440..44db0a2 100644
--- a/sources/Text/JSON/JSONAPI.uc
+++ b/sources/Text/JSON/JSONAPI.uc
@@ -91,11 +91,11 @@ public final function JSONPointer Pointer(optional BaseText pointerAsText)
*
* Compatible objects are `none` and any object that has one of the following
* classes: `BoolBox`, `BoolRef`, `ByteBox`, `ByteRef`, `IntBox`, `IntRef`,
- * `FloatBox`, `FloatRef`, `Text`, `MutableText`, `DynamicArray`,
- * `AssociativeArray`.
+ * `FloatBox`, `FloatRef`, `Text`, `MutableText`, `ArrayList`,
+ * `HashTable`.
*
- * This method does not check whether objects stored inside `DynamicArray`,
- * `AssociativeArray` are compatible. If they are not, they will normally be
+ * This method does not check whether objects stored inside `ArrayList`,
+ * `HashTable` are compatible. If they are not, they will normally be
* defaulted to JSON null upon any conversion.
*/
public function bool IsCompatible(AcediaObject data)
@@ -110,9 +110,7 @@ public function bool IsCompatible(AcediaObject data)
|| dataClass == class'IntBox' || dataClass == class'IntRef'
|| dataClass == class'FloatBox' || dataClass == class'FloatRef'
|| dataClass == class'Text' || dataClass == class'MutableText'
- || dataClass == class'ArrayList' || dataClass == class'HashTable'
- || dataClass == class'DynamicArray'
- || dataClass == class'AssociativeArray';
+ || dataClass == class'ArrayList' || dataClass == class'HashTable';
}
/**
@@ -598,75 +596,6 @@ public final function BaseText ParseString(
return immutableTextValue;
}
-/**
- * Uses given parser to parse a JSON array.
- *
- * This method will parse JSON values that are contained in parsed JSON array
- * according to description given for `ParseWith()` method.
- *
- * It does not matter what content follows parsed value in the `parser`,
- * method will be successful as long as it manages to parse correct
- * JSON array (from the current `parser`'s position).
- *
- * To check whether parsing have failed, simply check if `parser` is in
- * a failed state after the method call.
- *
- * @param parser Parser that method would use to parse JSON array
- * from it's current position. It's confirmed state will not be changed.
- * If parsing was successful it will point at the next available character.
- * Parser will be in a failed state after this method iff
- * parsing has failed.
- * @param parseAsMutable `true` if you want this method to parse array's
- * items as mutable values and `false` otherwise (as immutable ones).
- * @return Parsed JSON array as `DynamicArray` if parsing was successful and
- * `none` otherwise. To check for parsing success check the state of
- * the `parser`.
- */
-public final function DynamicArray ParseArrayWith(
- Parser parser,
- optional bool parseAsMutable)
-{
- local bool parsingSucceeded;
- local Parser.ParserState confirmedState;
- local AcediaObject nextValue;
- local array parsedValues;
- if (parser == none) return none;
-
- confirmedState =
- parser.Skip().Match(T(default.TOPEN_BRACKET)).GetCurrentState();
- while (parser.Ok() && !parser.HasFinished())
- {
- confirmedState = parser.Skip().GetCurrentState();
- // Check for JSON array ending and ONLY THEN declare parsing
- // is successful, not encountering '}' implies bad JSON format.
- if (parser.Match(T(default.TCLOSE_BRACKET)).Ok()) {
- parsingSucceeded = true;
- break;
- }
- parser.RestoreState(confirmedState);
- // Look for comma after each element
- if (parsedValues.length > 0)
- {
- if (!parser.Match(T(default.TCOMMA)).Skip().Ok()) {
- break;
- }
- confirmedState = parser.GetCurrentState();
- }
- // Parse next value
- nextValue = ParseWith(parser, parseAsMutable);
- parsedValues[parsedValues.length] = nextValue;
- if (!parser.Ok()) {
- break;
- }
- }
- if (parsingSucceeded) {
- return _.collections.NewDynamicArray(parsedValues, true);
- }
- _.memory.FreeMany(parsedValues);
- parser.Fail();
- return none;
-}
-
/**
* Uses given parser to parse a JSON array.
*
@@ -725,7 +654,7 @@ public final function ArrayList ParseArrayListWith(
confirmedState = parser.GetCurrentState();
}
// Parse next value
- nextValue = ParseWith(parser, parseAsMutable, true);
+ nextValue = ParseWith(parser, parseAsMutable);
parsedValues[parsedValues.length] = nextValue;
if (!parser.Ok()) {
break;
@@ -741,79 +670,6 @@ public final function ArrayList ParseArrayListWith(
return result;
}
-/**
- * Uses given parser to parse a JSON object.
- *
- * This method will parse JSON values that are contained in parsed JSON object
- * according to description given for `ParseWith()` method.
- *
- * It does not matter what content follows parsed value in the `parser`,
- * method will be successful as long as it manages to parse correct
- * JSON object (from the current `parser`'s position).
- *
- * To check whether parsing have failed, simply check if `parser` is in
- * a failed state after the method call.
- *
- * @param parser Parser that method would use to parse JSON object
- * from it's current position. It's confirmed state will not be changed.
- * If parsing was successful it will point at the next available character.
- * Parser will be in a failed state after this method iff
- * parsing has failed.
- * @param parseAsMutable `true` if you want this method to parse object's
- * items as mutable values and `false` otherwise (as immutable ones).
- * @return Parsed JSON object as `AssociativeArray` if parsing was successful
- * and `none` otherwise. To check for parsing success check the state of
- * the `parser`.
- */
-public function AssociativeArray ParseObjectWith(
- Parser parser,
- optional bool parseAsMutable)
-{
- local bool parsingSucceeded;
- local Parser.ParserState confirmedState;
- local array parsedEntries;
- if (parser == none) return none;
-
- // Ensure that parser starts pointing at what looks like a JSON object
- confirmedState =
- parser.Skip().Match(T(default.TOPEN_BRACE)).GetCurrentState();
- if (!parser.Ok()) {
- return none;
- }
- while (parser.Ok() && !parser.HasFinished())
- {
- confirmedState = parser.Skip().GetCurrentState();
- // Check for JSON object ending and ONLY THEN declare parsing
- // is successful, not encountering '}' implies bad JSON format.
- if (parser.Match(T(default.TCLOSE_BRACE)).Ok())
- {
- parsingSucceeded = true;
- break;
- }
- parser.RestoreState(confirmedState);
- // Look for comma after each key-value pair
- if (parsedEntries.length > 0)
- {
- if (!parser.Match(T(default.TCOMMA)).Skip().Ok()) {
- break;
- }
- confirmedState = parser.GetCurrentState();
- }
- // Parse property
- parsedEntries[parsedEntries.length] =
- ParseProperty(parser, parseAsMutable);
- if (!parser.Ok()) {
- break;
- }
- }
- if (parsingSucceeded) {
- return _.collections.NewAssociativeArray(parsedEntries, true);
- }
- FreeEntries(parsedEntries);
- parser.Fail();
- return none;
-}
-
/**
* Uses given parser to parse a JSON object.
*
@@ -892,20 +748,7 @@ public function HashTable ParseHashTableWith(
return result;
}
-// Parses a JSON key-value pair (there must not be any leading spaces).
-private function AssociativeArray.Entry ParseProperty(
- Parser parser,
- bool parseAsMutable)
-{
- local MutableText nextKey;
- local AssociativeArray.Entry entry;
- parser.MStringLiteral(nextKey).Skip().Match(T(default.TCOLON)).Skip();
- entry.key = nextKey.Copy();
- nextKey.FreeSelf();
- entry.value = ParseWith(parser, parseAsMutable);
- return entry;
-}
-
+// TODO: ParseProperty
// Parses a JSON key-value pair (there must not be any leading spaces).
private function HashTable.Entry ParseHashTableProperty(
Parser parser,
@@ -915,21 +758,11 @@ private function HashTable.Entry ParseHashTableProperty(
local HashTable.Entry entry;
parser.MStringLiteral(nextKey).Skip().Match(T(default.TCOLON)).Skip();
entry.key = nextKey.IntoText();
- entry.value = ParseWith(parser, parseAsMutable, true);
+ entry.value = ParseWith(parser, parseAsMutable);
return entry;
}
-// Auxiliary method for deallocating unneeded objects in entry pairs.
-private function FreeEntries(array entries)
-{
- local int i;
- for (i = 0; i < entries.length; i += 1)
- {
- _.memory.Free(entries[i].key);
- _.memory.Free(entries[i].value);
- }
-}
-
+// TODO: FreeEntries
// Auxiliary method for deallocating unneeded objects in entry pairs.
private function FreeHashTableEntries(array entries)
{
@@ -955,9 +788,9 @@ private function FreeHashTableEntries(array entries)
* `parseAsMutable` parameter (boxes are immutable, refs are mutable);
* 3. String values will be parsed as `Text`/`MutableText`, based on
* `parseAsMutable` parameter;
- * 4. Array values will be parsed as a `DynamicArray`, it's items parsed
+ * 4. Array values will be parsed as a `ArrayList`s, their items parsed
* according to these rules (`parseAsMutable` parameter is propagated).
- * 5. Object values will be parsed as a `AssociativeArray`, it's items
+ * 5. Object values will be parsed as a `HashTable`s, their items
* parsed according to these rules (`parseAsMutable` parameter is
* propagated) and recorded under the keys parsed into `Text`.
*
@@ -983,8 +816,7 @@ private function FreeHashTableEntries(array entries)
*/
public final function AcediaObject ParseWith(
Parser parser,
- optional bool parseAsMutable,
- optional bool parseAsNew)
+ optional bool parseAsMutable)
{
local AcediaObject result;
local Parser.ParserState initState;
@@ -1008,35 +840,17 @@ public final function AcediaObject ParseWith(
if (parser.Ok()) {
return result;
}
- if (parseAsNew)
- {
- result = ParseArrayListWith(
- parser.RestoreState(initState),
- parseAsMutable);
- if (parser.Ok()) {
- return result;
- }
- result = ParseHashTableWith(
- parser.RestoreState(initState),
- parseAsMutable);
- if (parser.Ok()) {
- return result;
- }
+ result = ParseArrayListWith(
+ parser.RestoreState(initState),
+ parseAsMutable);
+ if (parser.Ok()) {
+ return result;
}
- else
- {
- result = ParseArrayWith(
- parser.RestoreState(initState),
- parseAsMutable);
- if (parser.Ok()) {
- return result;
- }
- result = ParseObjectWith(
- parser.RestoreState(initState),
- parseAsMutable);
- if (parser.Ok()) {
- return result;
- }
+ result = ParseHashTableWith(
+ parser.RestoreState(initState),
+ parseAsMutable);
+ if (parser.Ok()) {
+ return result;
}
return none;
}
@@ -1054,10 +868,10 @@ public final function AcediaObject ParseWith(
* 3. Integer (`IntBox`/`IntRef`) and float (`FloatBox`/`FloatRef`) types
* are printed into JSON number value;
* 4. `Text` and `MutableText` are printed into JSON string value;
- * 5. `DynamicArray` is printed into JSON array with `Print()` method
+ * 5. `ArrayList` is printed into JSON array with `Print()` method
* applied to each of it's items. If some of them have not printable
* types - "none" will be used as a fallback.
- * 6. `AssociativeArray` is printed into JSON object with `Print()` method
+ * 6. `HashTable` is printed into JSON object with `Print()` method
* applied to each of it's items. Only items with `Text` keys are
* printed, the rest is omitted. If some of them have not printable
* types - "none" will be used as a fallback.
@@ -1094,66 +908,15 @@ public final function MutableText Print(AcediaObject toPrint)
|| toPrint.class == class'MutableText') {
return DisplayText(BaseText(toPrint));
}
- if (toPrint.class == class'DynamicArray') {
- return PrintArray(DynamicArray(toPrint));
- }
if (toPrint.class == class'ArrayList') {
return PrintArrayList(ArrayList(toPrint));
}
- if (toPrint.class == class'AssociativeArray') {
- return PrintObject(AssociativeArray(toPrint));
- }
if (toPrint.class == class'HashTable') {
return PrintHashTable(HashTable(toPrint));
}
return none;
}
-/**
- * "Prints" given `DynamicArray` value, saving it as a JSON array in
- * `MutableText`.
- *
- * "Prints" given `DynamicArray` in a minimal way, for a human-readable output
- * use `PrettyPrintArray()` method.
- *
- * It's items must either be equal to `none` or have one of the following
- * classes: `BoolBox`, `BoolRef`, `IntBox`, `IntRef`, `FloatBox`, `FloatRef`,
- * `Text`, `MutableText`, `DynamicArray`, `AssociativeArray`.
- * Otherwise items will be printed as "null" values.
- * Also see `Print()` method.
- *
- * @param toPrint Array to "print" into `MutableText`.
- * @return Text version of given `toPrint`, if it has one of the printable
- * classes. Otherwise returns `none`.
- * Note that `none` is considered printable and will produce "null".
- */
-public final function MutableText PrintArray(DynamicArray toPrint)
-{
- local int i, length;
- local MutableText result, printedItem;
- if (toPrint == none) return none;
-
- length = toPrint.GetLength();
- result = T(default.TOPEN_BRACKET).MutableCopy();
- for (i = 0; i < length; i += 1)
- {
- if (i > 0) {
- result.Append(T(default.TCOMMA));
- }
- printedItem = Print(toPrint.GetItem(i));
- if (printedItem != none)
- {
- result.Append(printedItem);
- printedItem.FreeSelf();
- }
- else {
- result.Append(T(default.TNULL));
- }
- }
- result.Append(T(default.TCLOSE_BRACKET));
- return result;
-}
-
/**
* "Prints" given `ArrayList` value, saving it as a JSON array in
* `MutableText`.
@@ -1163,7 +926,7 @@ public final function MutableText PrintArray(DynamicArray toPrint)
*
* It's items must either be equal to `none` or have one of the following
* classes: `BoolBox`, `BoolRef`, `IntBox`, `IntRef`, `FloatBox`, `FloatRef`,
- * `Text`, `MutableText`, `DynamicArray`, `AssociativeArray`.
+ * `Text`, `MutableText`, `ArrayList`, `HashTable`.
* Otherwise items will be printed as "null" values.
* Also see `Print()` method.
*
@@ -1204,65 +967,6 @@ public final function MutableText PrintArrayList(ArrayList toPrint)
return result;
}
-/**
- * "Prints" given `AssociativeArray` value, saving it as a JSON object in
- * `MutableText`.
- *
- * "Prints" given `AssociativeArray` in a minimal way, for
- * a human-readable output use `PrettyPrintObject()` method.
- *
- * Only prints items recorded with `Text` key, the rest is omitted.
- *
- * It's items must either be equal to `none` or have one of the following
- * classes: `BoolBox`, `BoolRef`, `IntBox`, `IntRef`, `FloatBox`, `FloatRef`,
- * `Text`, `MutableText`, `DynamicArray`, `AssociativeArray`.
- * Otherwise items will be printed as "null" values.
- * Also see `Print()` method.
- *
- * @param toPrint Array to "print" into `MutableText`.
- * @return Text version of given `toPrint`, if it has one of the printable
- * classes. Otherwise returns `none`.
- * Note that `none` is considered printable and will produce "null".
- */
-public final function MutableText PrintObject(AssociativeArray toPrint)
-{
- local bool printedKeyValuePair;
- local CollectionIterator iter;
- local Text nextKey;
- local AcediaObject nextValue;
- local MutableText result, printedKey, printedValue;
- if (toPrint == none) return none;
-
- result = T(default.TOPEN_BRACE).MutableCopy();
- iter = toPrint.Iterate();
- for (iter = toPrint.Iterate(); !iter.HasFinished(); iter.Next())
- {
- if (printedKeyValuePair) {
- result.Append(T(default.TCOMMA));
- }
- nextKey = Text(iter.GetKey());
- nextValue = iter.Get();
- if (nextKey == none) continue;
- if (nextKey.class != class'Text') continue;
- printedKey = DisplayText(nextKey);
- printedValue = Print(nextValue);
- result.Append(printedKey).Append(T(default.TCOLON));
- printedKey.FreeSelf();
- if (printedValue != none)
- {
- result.Append(printedValue);
- printedValue.FreeSelf();
- }
- else {
- result.Append(T(default.TNULL));
- }
- printedKeyValuePair = true;
- }
- iter.FreeSelf();
- result.Append(T(default.TCLOSE_BRACE));
- return result;
-}
-
/**
* "Prints" given `HashTable` value, saving it as a JSON object in
* `MutableText`.
@@ -1274,7 +978,7 @@ public final function MutableText PrintObject(AssociativeArray toPrint)
*
* It's items must either be equal to `none` or have one of the following
* classes: `BoolBox`, `BoolRef`, `IntBox`, `IntRef`, `FloatBox`, `FloatRef`,
- * `Text`, `MutableText`, `DynamicArray`, `AssociativeArray`.
+ * `Text`, `MutableText`, `ArrayList`, `HashTable`.
* Otherwise items will be printed as "null" values.
* Also see `Print()` method.
*
@@ -1343,10 +1047,10 @@ public final function MutableText PrintHashTable(HashTable toPrint)
* 3. Integer (`IntBox`/`IntRef`) and float (`FloatBox`/`FloatRef`) types
* are printed into JSON number value;
* 4. `Text` and `MutableText` are printed into JSON string value;
- * 5. `DynamicArray` is printed into JSON array with `Print()` method
+ * 5. `ArrayList` is printed into JSON array with `Print()` method
* applied to each of it's items. If some of them have not printable
* types - "none" will be used as a fallback.
- * 6. `AssociativeArray` is printed into JSON object with `Print()` method
+ * 6. `HashTable` is printed into JSON object with `Print()` method
* applied to each of it's items. Only items with `Text` keys are
* printed, the rest is omitted. If some of them have not printable
* types - "none" will be used as a fallback.
@@ -1367,35 +1071,6 @@ public final function MutableText PrettyPrint(AcediaObject toPrint)
return result;
}
-/**
- * "Prints" given `DynamicArray` value, saving it as a JSON array in
- * `MutableText`.
- *
- * "Prints" given `DynamicArray` in human-readable way, for minimal output
- * use `PrintArray()` method.
- *
- * It's items must either be equal to `none` or have one of the following
- * classes: `BoolBox`, `BoolRef`, `IntBox`, `IntRef`, `FloatBox`, `FloatRef`,
- * `Text`, `MutableText`, `DynamicArray`, `AssociativeArray`.
- * Otherwise items will be printed as "null" values.
- * Also see `Print()` method.
- *
- * @param toPrint Array to "print" into `MutableText`.
- * @return Text version of given `toPrint`, if it has one of the printable
- * classes. Otherwise returns `none`.
- * Note that `none` is considered printable and will produce "null".
- */
-public final function MutableText PrettyPrintArray(DynamicArray toPrint)
-{
- local MutableText result;
- local MutableText accumulatedIndent;
- InitFormatting();
- accumulatedIndent = _.text.Empty();
- result = PrettyPrintArrayWithIndent(toPrint, accumulatedIndent);
- accumulatedIndent.FreeSelf();
- return result;
-}
-
/**
* "Prints" given `ArrayList` value, saving it as a JSON array in
* `MutableText`.
@@ -1405,7 +1080,7 @@ public final function MutableText PrettyPrintArray(DynamicArray toPrint)
*
* It's items must either be equal to `none` or have one of the following
* classes: `BoolBox`, `BoolRef`, `IntBox`, `IntRef`, `FloatBox`, `FloatRef`,
- * `Text`, `MutableText`, `DynamicArray`, `AssociativeArray`.
+ * `Text`, `MutableText`, `ArrayList`, `HashTable`.
* Otherwise items will be printed as "null" values.
* Also see `Print()` method.
*
@@ -1426,37 +1101,6 @@ public final function MutableText PrettyPrintArrayList(ArrayList toPrint)
return result;
}
-/**
- * "Prints" given `AssociativeArray` value, saving it as a JSON object in
- * `MutableText`.
- *
- * "Prints" given `AssociativeArray` in a human readable way, for
- * a minimal output use `PrintObject()` method.
- *
- * Only prints items recorded with `Text` key, the rest is omitted.
- *
- * It's items must either be equal to `none` or have one of the following
- * classes: `BoolBox`, `BoolRef`, `IntBox`, `IntRef`, `FloatBox`, `FloatRef`,
- * `Text`, `MutableText`, `DynamicArray`, `AssociativeArray`.
- * Otherwise items will be printed as "null" values.
- * Also see `Print()` method.
- *
- * @param toPrint Array to "print" into `MutableText`.
- * @return Text version of given `toPrint`, if it has one of the printable
- * classes. Otherwise returns `none`.
- * Note that `none` is considered printable and will produce "null".
- */
-public final function MutableText PrettyPrintObject(AssociativeArray toPrint)
-{
- local MutableText result;
- local MutableText accumulatedIndent;
- InitFormatting();
- accumulatedIndent = _.text.Empty();
- result = PrettyPrintObjectWithIndent(toPrint, accumulatedIndent);
- accumulatedIndent.FreeSelf();
- return result;
-}
-
/**
* "Prints" given `HashTable` value, saving it as a JSON object in
* `MutableText`.
@@ -1468,7 +1112,7 @@ public final function MutableText PrettyPrintObject(AssociativeArray toPrint)
*
* It's items must either be equal to `none` or have one of the following
* classes: `BoolBox`, `BoolRef`, `IntBox`, `IntRef`, `FloatBox`, `FloatRef`,
- * `Text`, `MutableText`, `DynamicArray`, `AssociativeArray`.
+ * `Text`, `MutableText`, `ArrayList`, `HashTable`.
* Otherwise items will be printed as "null" values.
* Also see `Print()` method.
*
@@ -1532,20 +1176,11 @@ private final function MutableText PrettyPrintWithIndent(
{
return DisplayText(BaseText(toPrint)).ChangeFormatting(jString);
}
- if (toPrint.class == class'DynamicArray')
- {
- return PrettyPrintArrayWithIndent( DynamicArray(toPrint),
- accumulatedIndent);
- }
if (toPrint.class == class'ArrayList')
{
return PrettyPrintArrayListWithIndent( ArrayList(toPrint),
accumulatedIndent);
}
- if (toPrint.class == class'AssociativeArray') {
- return PrettyPrintObjectWithIndent( AssociativeArray(toPrint),
- accumulatedIndent);
- }
if (toPrint.class == class'HashTable') {
return PrettyPrintHashTableWithIndent( HashTable(toPrint),
accumulatedIndent);
@@ -1553,48 +1188,6 @@ private final function MutableText PrettyPrintWithIndent(
return none;
}
-// Does the actual job for `PrettyPrintArray()` method.
-// Separated to hide `accumulatedIndent` parameter that is necessary for
-// pretty printing.
-// Assumes `InitFormatting()` was made and json formatting variables are
-// initialized.
-private final function MutableText PrettyPrintArrayWithIndent(
- DynamicArray toPrint,
- MutableText accumulatedIndent)
-{
- local int i, length;
- local MutableText extendedIndent;
- local MutableText result, printedItem;
- if (toPrint == none) {
- return none;
- }
- length = toPrint.GetLength();
- extendedIndent = accumulatedIndent.MutableCopy().Append(T(TJSON_INDENT));
- result = T(default.TOPEN_BRACKET).MutableCopy()
- .ChangeFormatting(jArrayBraces);
- for (i = 0; i < length; i += 1)
- {
- if (i > 0) {
- result.Append(T(default.TCOMMA), jComma);
- }
- printedItem = PrettyPrintWithIndent(toPrint.GetItem(i), extendedIndent);
- if (printedItem != none)
- {
- result.AppendLineBreak().Append(extendedIndent).Append(printedItem);
- printedItem.FreeSelf();
- }
- else {
- result.Append(T(default.TNULL), jNull);
- }
- }
- if (i > 0) {
- result.AppendLineBreak().Append(accumulatedIndent);
- }
- result.Append(T(default.TCLOSE_BRACKET), jArrayBraces);
- extendedIndent.FreeSelf();
- return result;
-}
-
// Does the actual job for `PrettyPrintArray()` method.
// Separated to hide `accumulatedIndent` parameter that is necessary for
// pretty printing.
@@ -1641,49 +1234,6 @@ private final function MutableText PrettyPrintArrayListWithIndent(
return result;
}
-// Does the actual job for `PrettyPrintObject()` method.
-// Separated to hide `accumulatedIndent` parameter that is necessary for
-// pretty printing.
-// Assumes `InitFormatting()` was made and json formatting variables are
-// initialized.
-private final function MutableText PrettyPrintObjectWithIndent(
- AssociativeArray toPrint,
- MutableText accumulatedIndent)
-{
- local bool printedKeyValuePair;
- local CollectionIterator iter;
- local Text nextKey;
- local AcediaObject nextValue;
- local MutableText extendedIndent;
- local MutableText result;
- if (toPrint == none) {
- return none;
- }
- extendedIndent = accumulatedIndent.MutableCopy().Append(T(TJSON_INDENT));
- result = T(default.TOPEN_BRACE).MutableCopy()
- .ChangeFormatting(jObjectBraces);
- iter = toPrint.Iterate();
- for (iter = toPrint.Iterate(); !iter.HasFinished(); iter.Next())
- {
- if (printedKeyValuePair) {
- result.Append(T(default.TCOMMA), jComma);
- }
- nextKey = Text(iter.GetKey());
- nextValue = iter.Get();
- if (nextKey == none) continue;
- if (nextKey.class != class'Text') continue;
- PrettyPrintKeyValue(result, nextKey, nextValue, extendedIndent);
- printedKeyValuePair = true;
- }
- if (printedKeyValuePair) {
- result.AppendLineBreak().Append(accumulatedIndent);
- }
- iter.FreeSelf();
- result.Append(T(default.TCLOSE_BRACE), jObjectBraces);
- extendedIndent.FreeSelf();
- return result;
-}
-
// Does the actual job for `PrettyPrintHashTable()` method.
// Separated to hide `accumulatedIndent` parameter that is necessary for
// pretty printing.
diff --git a/sources/Text/Tests/TEST_JSON.uc b/sources/Text/Tests/TEST_JSON.uc
index 605d28b..ac5de65 100644
--- a/sources/Text/Tests/TEST_JSON.uc
+++ b/sources/Text/Tests/TEST_JSON.uc
@@ -525,17 +525,17 @@ protected static function SubTest_ParseSimpleValueSuccess()
api = __().json;
Issue("`ParseWith()` fails to parse correct JSON values.");
parser = __().text.ParseString("false, 98.2, 42, \"hmmm\", null");
- TEST_ExpectFalse(BoolBox(api.ParseWith(parser,, true)).Get());
+ TEST_ExpectFalse(BoolBox(api.ParseWith(parser)).Get());
parser.MatchS(",").Skip();
- TEST_ExpectTrue(FloatBox(api.ParseWith(parser,, true)).Get() == 98.2);
+ TEST_ExpectTrue(FloatBox(api.ParseWith(parser)).Get() == 98.2);
parser.MatchS(",").Skip();
- TEST_ExpectTrue(IntRef(api.ParseWith(parser, true, true)).Get() == 42);
+ TEST_ExpectTrue(IntRef(api.ParseWith(parser, true)).Get() == 42);
parser.MatchS(",").Skip();
TEST_ExpectTrue(
- MutableText(api.ParseWith(parser, true, true)).ToString()
+ MutableText(api.ParseWith(parser, true)).ToString()
== "hmmm");
parser.MatchS(",").Skip();
- TEST_ExpectNone(api.ParseWith(parser,, true));
+ TEST_ExpectNone(api.ParseWith(parser));
TEST_ExpectTrue(parser.Ok());
}
protected static function SubTest_ParseSimpleValueFailure()
@@ -546,13 +546,13 @@ protected static function SubTest_ParseSimpleValueFailure()
Issue("`ParseWith()` does not correctly handle parsing invalid"
@ "JSON values.");
parser = __().text.ParseString("tru");
- TEST_ExpectNone(api.ParseWith(parser,, true));
+ TEST_ExpectNone(api.ParseWith(parser));
TEST_ExpectFalse(parser.Ok());
parser = __().text.ParseString("");
- TEST_ExpectNone(api.ParseWith(parser,, true));
+ TEST_ExpectNone(api.ParseWith(parser));
TEST_ExpectFalse(parser.Ok());
parser = __().text.ParseString("NUL");
- TEST_ExpectNone(api.ParseWith(parser,, true));
+ TEST_ExpectNone(api.ParseWith(parser));
TEST_ExpectFalse(parser.Ok());
}
@@ -624,7 +624,7 @@ protected static function SubTest_ParseComplex()
local HashTable root, mainObj, subObj, inner;
Issue("`ParseHashTableWith()` cannot handle complex values.");
parser = __().text.ParseString(default.complexJSONObject);
- root = HashTable(__().json.ParseWith(parser,, true));
+ root = HashTable(__().json.ParseWith(parser));
TEST_ExpectTrue(root.GetLength() == 3);
TEST_ExpectTrue(FloatBox(root.GetItem(P("some_var"))).Get() == -7.32);
TEST_ExpectTrue( Text(root.GetItem(P("another_var"))).ToString()