Browse Source

Squashed commit of the following:

commit dd6f236b360640b4c5ca2bfefdddf11482ab1bcf
Author: Anton Tarasenko <dkanus@gmail.com>
Date:   Mon Jul 4 03:55:45 2022 +0700

    Change `AcediaConfig` to use new collections
pull/8/head
Anton Tarasenko 2 years ago
parent
commit
8cfc42eda4
  1. 43
      sources/Avarice/Avarice.uc
  2. 14
      sources/Commands/Commands.uc
  3. 63
      sources/Config/AcediaConfig.uc
  4. 10
      sources/Config/Tests/MockConfig.uc
  5. 10
      sources/Config/Tests/TEST_AcediaConfig.uc
  6. 24
      sources/Data/Collections/ArrayList.uc
  7. 1
      sources/Data/Collections/HashTable.uc

43
sources/Avarice/Avarice.uc

@ -43,58 +43,67 @@ var public config array<AvariceLinkRecord> link;
// connection too long. // connection too long.
var public config float reconnectTime; var public config float reconnectTime;
protected function AssociativeArray ToData() protected function HashTable ToData()
{ {
local int i; local int i;
local AssociativeArray data; local Text nextValue;
local AssociativeArray linkData; local HashTable data;
local DynamicArray linksArray; local HashTable linkData;
data = __().collections.EmptyAssociativeArray(); local ArrayList linksArray;
data = __().collections.EmptyHashTable();
data.SetFloat(P("reconnectTime"), reconnectTime, true); data.SetFloat(P("reconnectTime"), reconnectTime, true);
linksArray = __().collections.EmptyDynamicArray(); linksArray = __().collections.EmptyArrayList();
data.SetItem(P("link"), linksArray); data.SetItem(P("link"), linksArray);
for (i = 0; i < link.length; i += 1) for (i = 0; i < link.length; i += 1)
{ {
linkData = __().collections.EmptyAssociativeArray(); linkData = __().collections.EmptyHashTable();
linkData.SetItem(P("name"), __().text.FromString(link[i].name)); nextValue = __().text.FromString(link[i].name);
linkData.SetItem(P("address"), __().text.FromString(link[i].address)); linkData.SetItem(P("name"), nextValue);
nextValue.FreeSelf();
nextValue = __().text.FromString(link[i].address);
linkData.SetItem(P("address"), nextValue);
nextValue.FreeSelf();
linksArray.AddItem(linkData); linksArray.AddItem(linkData);
linkData.FreeSelf();
} }
linksArray.FreeSelf();
return data; return data;
} }
protected function FromData(AssociativeArray source) protected function FromData(HashTable source)
{ {
local int i; local int i;
local Text nextText; local Text nextText;
local DynamicArray linksArray; local ArrayList linksArray;
local AssociativeArray nextLink; local HashTable nextLink;
local AvariceLinkRecord nextRecord; local AvariceLinkRecord nextRecord;
if (source == none) { if (source == none) {
return; return;
} }
reconnectTime = source.GetFloat(P("reconnectTime")); reconnectTime = source.GetFloat(P("reconnectTime"));
link.length = 0; link.length = 0;
linksArray = source.GetDynamicArray(P("link")); linksArray = source.GetArrayList(P("link"));
if (linksArray == none) { if (linksArray == none) {
return; return;
} }
for (i = 0; i < linksArray.GetLength(); i += 1) for (i = 0; i < linksArray.GetLength(); i += 1)
{ {
nextLink = linksArray.GetAssociativeArray(i); nextLink = linksArray.GetHashTable(i);
if (nextLink == none) { if (nextLink == none) {
continue; continue;
} }
nextText = nextLink.GetText(P("name")); nextText = nextLink.GetText(P("name"));
if (nextText != none) { if (nextText != none) {
nextRecord.name = nextText.ToString(); nextRecord.name = __().text.ToString(nextText);
} }
nextText = nextLink.GetText(P("address")); nextText = nextLink.GetText(P("address"));
if (nextText != none) { if (nextText != none) {
nextRecord.address = nextText.ToString(); nextRecord.address = __().text.ToString(nextText);
} }
link[i] = nextRecord; link[i] = nextRecord;
_.memory.Free(nextLink);
} }
_.memory.Free(linksArray);
} }
protected function DefaultIt() protected function DefaultIt()

14
sources/Commands/Commands.uc

@ -25,18 +25,20 @@ var public config bool useChatInput;
var public config bool useMutateInput; var public config bool useMutateInput;
var public config string chatCommandPrefix; var public config string chatCommandPrefix;
protected function AssociativeArray ToData() protected function HashTable ToData()
{ {
local AssociativeArray data; local Text chatPrefix;
data = __().collections.EmptyAssociativeArray(); local HashTable data;
data = __().collections.EmptyHashTable();
data.SetBool(P("useChatInput"), useChatInput, true); data.SetBool(P("useChatInput"), useChatInput, true);
data.SetBool(P("useMutateInput"), useMutateInput, true); data.SetBool(P("useMutateInput"), useMutateInput, true);
data.SetItem( P("chatCommandPrefix"), chatPrefix = _.text.FromString(chatCommandPrefix);
_.text.FromString(chatCommandPrefix), true); data.SetItem(P("chatCommandPrefix"), chatPrefix);
_.memory.Free(chatPrefix);
return data; return data;
} }
protected function FromData(AssociativeArray source) protected function FromData(HashTable source)
{ {
local Text newChatPrefix; local Text newChatPrefix;
if (source == none) { if (source == none) {

63
sources/Config/AcediaConfig.uc

@ -8,7 +8,7 @@
* is that "<config_object_name>" must be considered *valid* by * is that "<config_object_name>" must be considered *valid* by
* `BaseText.IsValidName()` standards, otherwise method will return `none`. * `BaseText.IsValidName()` standards, otherwise method will return `none`.
* *
* Copyright 2021 Anton Tarasenko * Copyright 2021-2022 Anton Tarasenko
*------------------------------------------------------------------------------ *------------------------------------------------------------------------------
* This file is part of Acedia. * This file is part of Acedia.
* *
@ -26,7 +26,7 @@
* along with Acedia. If not, see <https://www.gnu.org/licenses/>. * along with Acedia. If not, see <https://www.gnu.org/licenses/>.
*/ */
class AcediaConfig extends AcediaObject class AcediaConfig extends AcediaObject
dependson(AssociativeArray) dependson(HashTable)
abstract; abstract;
/** /**
@ -65,7 +65,7 @@ class AcediaConfig extends AcediaObject
// In case it has a `none` value stored under some key - it means that value // In case it has a `none` value stored under some key - it means that value
// was detected in config, but not yet loaded. // was detected in config, but not yet loaded.
// Only its default value is ever used. // Only its default value is ever used.
var private AssociativeArray existingConfigs; var private HashTable existingConfigs;
// Stores name of the config where settings are to be stored. // Stores name of the config where settings are to be stored.
// Must correspond to value in `config(...)` modifier in class definition. // Must correspond to value in `config(...)` modifier in class definition.
@ -79,10 +79,10 @@ var public const bool supportsDataConversion;
/** /**
* These methods must be overloaded to store and load all the config * These methods must be overloaded to store and load all the config
* variables inside an `AssociativeArray` collection. How exactly to store * variables inside an `HashTable` collection. How exactly to store
* them is up to each config class to decide, as long as it allows conversion * them is up to each config class to decide, as long as it allows conversion
* into JSON (see `JSONAPI.IsCompatible()` for details). * into JSON (see `JSONAPI.IsCompatible()` for details).
* Note that `AssociativeArray` reference `FromData()` receives is * Note that `HashTable` reference `FromData()` receives is
* not necessarily the same one your `ToData()` method returns - any particular * not necessarily the same one your `ToData()` method returns - any particular
* value boxes can be replaced with value references and vice versa. * value boxes can be replaced with value references and vice versa.
* NOTE: DO NOT use `P()`, `C()`, `F()` or `T()` methods for keys or * NOTE: DO NOT use `P()`, `C()`, `F()` or `T()` methods for keys or
@ -90,8 +90,8 @@ var public const bool supportsDataConversion;
* deallocated when necessary, so these methods for creating `Text` values are * deallocated when necessary, so these methods for creating `Text` values are
* not suitable. * not suitable.
*/ */
protected function AssociativeArray ToData() { return none; } protected function HashTable ToData() { return none; }
protected function FromData(AssociativeArray source) {} protected function FromData(HashTable source) {}
/** /**
* This method must be overloaded to setup default values for all config * This method must be overloaded to setup default values for all config
@ -99,12 +99,6 @@ protected function FromData(AssociativeArray source) {}
*/ */
protected function DefaultIt() {} protected function DefaultIt() {}
protected static function StaticFinalizer()
{
__().memory.Free(default.existingConfigs);
default.existingConfigs = none;
}
/** /**
* This reads all of the `AcediaConfig`'s settings objects into internal * This reads all of the `AcediaConfig`'s settings objects into internal
* storage. Must be called before any other methods. Actual loading might be * storage. Must be called before any other methods. Actual loading might be
@ -113,12 +107,12 @@ protected static function StaticFinalizer()
public static function Initialize() public static function Initialize()
{ {
local int i; local int i;
local Text nextName; local Text nextName, lowerName;
local array<string> names; local array<string> names;
if (default.existingConfigs != none) { if (default.existingConfigs != none) {
return; return;
} }
default.existingConfigs = __().collections.EmptyAssociativeArray(); default.existingConfigs = __().collections.EmptyHashTable();
names = GetPerObjectNames( default.configName, string(default.class.name), names = GetPerObjectNames( default.configName, string(default.class.name),
MaxInt); MaxInt);
for (i = 0; i < names.length; i += 1) for (i = 0; i < names.length; i += 1)
@ -127,8 +121,11 @@ public static function Initialize()
continue; continue;
} }
nextName = __().text.FromString(NameToActualVersion(names[i])); nextName = __().text.FromString(NameToActualVersion(names[i]));
if (nextName.IsValidName()) { if (nextName.IsValidName())
default.existingConfigs.SetItem(nextName.LowerCopy(), none); {
lowerName = nextName.LowerCopy();
default.existingConfigs.SetItem(lowerName, none);
lowerName.FreeSelf();
} }
nextName.FreeSelf(); nextName.FreeSelf();
} }
@ -178,6 +175,7 @@ public final static function bool NewConfig(BaseText name)
newConfig.DefaultIt(); newConfig.DefaultIt();
newConfig.SaveConfig(); newConfig.SaveConfig();
default.existingConfigs.SetItem(name, newConfig); default.existingConfigs.SetItem(name, newConfig);
name.FreeSelf();
return true; return true;
} }
@ -214,15 +212,16 @@ public final static function bool Exists(BaseText name)
*/ */
public final static function DeleteConfig(BaseText name) public final static function DeleteConfig(BaseText name)
{ {
local AssociativeArray.Entry entry; local AcediaObject value;
if (default.existingConfigs == none) { if (name == none) return;
return; if (default.existingConfigs == none) return;
}
entry = default.existingConfigs.TakeEntry(name); name = name.LowerCopy();
if (entry.value != none) { value = default.existingConfigs.TakeItem(name);
entry.value.ClearConfig(); if (value != none) {
value.ClearConfig();
} }
__().memory.Free(entry.key); __().memory.Free(name);
} }
/** /**
@ -235,7 +234,7 @@ public static function array<Text> AvailableConfigs()
{ {
local array<Text> emptyResult; local array<Text> emptyResult;
if (default.existingConfigs != none) { if (default.existingConfigs != none) {
return default.existingConfigs.CopyTextKeys(); return default.existingConfigs.GetTextKeys();
} }
return emptyResult; return emptyResult;
} }
@ -250,7 +249,7 @@ public static function array<Text> AvailableConfigs()
*/ */
public final static function AcediaConfig GetConfigInstance(BaseText name) public final static function AcediaConfig GetConfigInstance(BaseText name)
{ {
local AssociativeArray.Entry configEntry; local HashTable.Entry configEntry;
if (name == none) return none; if (name == none) return none;
if (!name.IsValidName()) return none; if (!name.IsValidName()) return none;
if (default.existingConfigs == none) return none; if (default.existingConfigs == none) return none;
@ -265,6 +264,8 @@ public final static function AcediaConfig GetConfigInstance(BaseText name)
default.existingConfigs.SetItem(configEntry.key, configEntry.value); default.existingConfigs.SetItem(configEntry.key, configEntry.value);
} }
__().memory.Free(name); __().memory.Free(name);
// We return value, so do not deallocate it
__().memory.Free(configEntry.key);
return AcediaConfig(configEntry.value); return AcediaConfig(configEntry.value);
} }
@ -284,10 +285,10 @@ public final static function AcediaConfig GetConfigInstance(BaseText name)
* For correctly implemented config objects should only return `none` if * For correctly implemented config objects should only return `none` if
* their class was not yet initialized (see `self.Initialize()` method). * their class was not yet initialized (see `self.Initialize()` method).
*/ */
public final static function AssociativeArray LoadData(BaseText name) public final static function HashTable LoadData(BaseText name)
{ {
local AssociativeArray result; local HashTable result;
local AcediaConfig requiredConfig; local AcediaConfig requiredConfig;
requiredConfig = GetConfigInstance(name); requiredConfig = GetConfigInstance(name);
if (requiredConfig != none) { if (requiredConfig != none) {
result = requiredConfig.ToData(); result = requiredConfig.ToData();
@ -309,7 +310,7 @@ public final static function AssociativeArray LoadData(BaseText name)
* allows for JSON deserialization (see `JSONAPI.IsCompatible()` for * allows for JSON deserialization (see `JSONAPI.IsCompatible()` for
* details). * details).
*/ */
public final static function SaveData(BaseText name, AssociativeArray data) public final static function SaveData(BaseText name, HashTable data)
{ {
local AcediaConfig requiredConfig; local AcediaConfig requiredConfig;
requiredConfig = GetConfigInstance(name); requiredConfig = GetConfigInstance(name);

10
sources/Config/Tests/MockConfig.uc

@ -1,6 +1,6 @@
/** /**
* Mock object for testing config functionality of Acedia's `Feature`s. * Mock object for testing config functionality of Acedia's `Feature`s.
* Copyright 2021 Anton Tarasenko * Copyright 2021-2022 Anton Tarasenko
*------------------------------------------------------------------------------ *------------------------------------------------------------------------------
* This file is part of Acedia. * This file is part of Acedia.
* *
@ -23,15 +23,15 @@ class MockConfig extends AcediaConfig
var public config int value; var public config int value;
protected function AssociativeArray ToData() protected function HashTable ToData()
{ {
local AssociativeArray data; local HashTable data;
data = __().collections.EmptyAssociativeArray(); data = __().collections.EmptyHashTable();
data.SetInt(P("value").Copy(), value, true); data.SetInt(P("value").Copy(), value, true);
return data; return data;
} }
protected function FromData(AssociativeArray source) protected function FromData(HashTable source)
{ {
if (source != none) { if (source != none) {
value = source.GetIntBy(P("/value")); value = source.GetIntBy(P("/value"));

10
sources/Config/Tests/TEST_AcediaConfig.uc

@ -1,6 +1,6 @@
/** /**
* Set of tests for `AcediaConfig` class. * Set of tests for `AcediaConfig` class.
* Copyright 2021 Anton Tarasenko * Copyright 2021-2022 Anton Tarasenko
*------------------------------------------------------------------------------ *------------------------------------------------------------------------------
* This file is part of Acedia. * This file is part of Acedia.
* *
@ -68,19 +68,19 @@ protected static function TEST_AvailableConfigs()
protected static function TEST_DataGetSet() protected static function TEST_DataGetSet()
{ {
local AssociativeArray data, newData; local HashTable data, newData;
data = class'MockConfig'.static.LoadData(P("other")); data = class'MockConfig'.static.LoadData(P("other"));
Issue("Wrong value is loaded from config."); Issue("Wrong value is loaded from config.");
TEST_ExpectTrue(data.GetIntBy(P("/value")) == 11); TEST_ExpectTrue(data.GetIntBy(P("/value")) == 11);
newData = __().collections.EmptyAssociativeArray(); newData = __().collections.EmptyHashTable();
newData.SetItem(P("value"), __().box.int(903)); newData.SetItem(P("value"), __().box.int(903));
class'MockConfig'.static.SaveData(P("other"), newData); class'MockConfig'.static.SaveData(P("other"), newData);
data = class'MockConfig'.static.LoadData(P("other")); data = class'MockConfig'.static.LoadData(P("other"));
Issue("Wrong value is loaded from config after saving another value."); Issue("Wrong value is loaded from config after saving another value.");
TEST_ExpectTrue(data.GetIntBy(P("/value")) == 903); TEST_ExpectTrue(data.GetIntBy(P("/value")) == 903);
Issue("`AcediaConfig` returns `AssociativeArray` reference that was" Issue("`AcediaConfig` returns `HashTable` reference that was"
@ "passed in `SaveData()` call instead of a new collection."); @ "passed in `SaveData()` call instead of a new collection.");
TEST_ExpectTrue(data != newData); TEST_ExpectTrue(data != newData);
@ -91,7 +91,7 @@ protected static function TEST_DataGetSet()
protected static function TEST_DataNew() protected static function TEST_DataNew()
{ {
local AssociativeArray data; local HashTable data;
Issue("Creating new config with existing name succeeds."); Issue("Creating new config with existing name succeeds.");
TEST_ExpectFalse(class'MockConfig'.static.NewConfig(P("another.config"))); TEST_ExpectFalse(class'MockConfig'.static.NewConfig(P("another.config")));
data = class'MockConfig'.static.LoadData(P("another.config")); data = class'MockConfig'.static.LoadData(P("another.config"));

24
sources/Data/Collections/ArrayList.uc

@ -870,6 +870,30 @@ public final function ArrayList GetArrayList(int index)
return result; return result;
} }
/**
* Returns `HashTable` item at `index`. If index is invalid or
* stores a non-`HashTable` 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 `HashTable` item that caller `ArrayList`
* has to return.
* @return `HashTable` value at `index` in the caller `ArrayList`.
* `none` if passed `index` is invalid or non-`HashTable` value
* is stored there.
*/
public final function HashTable GetHashTable(int index)
{
local HashTable result;
result = HashTable(BorrowItem(index));
if (result != none) {
result.NewRef();
}
return result;
}
defaultproperties defaultproperties
{ {
iteratorClass = class'ArrayListIterator' iteratorClass = class'ArrayListIterator'

1
sources/Data/Collections/HashTable.uc

@ -388,6 +388,7 @@ public final function HashTable SetItem(
storedElementCount += 1; storedElementCount += 1;
} }
key.NewRef(); key.NewRef();
_.memory.Free(oldEntry.key);
newEntry.key = key; newEntry.key = key;
newEntry.value = value; newEntry.value = value;
if (value != none) { if (value != none) {

Loading…
Cancel
Save