Skip to content
Merged
Show file tree
Hide file tree
Changes from 8 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions Content.Tests/DMProject/Tests/List/alist/AListAdd.dm
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
/proc/RunTest()
var/alist/AL = alist("a" = 1, "b" = 2, "c" = -4)
AL.Add("c", "d")
ASSERT(AL["c"] == -4)
ASSERT(AL["d"] == null)

AL.Add(list("c", "d"))
ASSERT(AL["c"] == -4)
ASSERT(AL["d"] == null)
6 changes: 6 additions & 0 deletions Content.Tests/DMProject/Tests/List/alist/AListBadCopy.dm
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
// RUNTIME ERROR

/proc/RunTest()
var/alist/AL = alist("a" = 1, "b" = 2, "c" = -4)
var/alist/AL2
AL2 = AL.Copy(1, 2)
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
/proc/RunTest()
var/alist/AL = alist("left"=alist("one"=1,"two"=2),"right"=1)
ASSERT(istype(AL["left"], /alist))
ASSERT(AL["left"]["one"] == 1)
ASSERT(AL["left"]["two"] == 2)
ASSERT(AL["right"] == 1)
ASSERT(!("two" in AL))
8 changes: 8 additions & 0 deletions Content.Tests/DMProject/Tests/List/alist/AListCopy.dm
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
/proc/RunTest()
var/alist/AL = alist("a" = 1, "b" = 2, "c" = -4)
var/alist/AL2
AL2 = AL.Copy()
ASSERT(AL["a"] == 1)
ASSERT(AL2["a"] == 1)
ASSERT(AL2["b"] == 2)
ASSERT("c" in AL2)
5 changes: 5 additions & 0 deletions Content.Tests/DMProject/Tests/List/alist/AListCut.dm
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
/proc/RunTest()
var/alist/AL = alist("a" = 1, "b" = 2, "c" = -4)
AL.Cut()
ASSERT(length(AL) == 0)
ASSERT(!("a" in AL))
5 changes: 5 additions & 0 deletions Content.Tests/DMProject/Tests/List/alist/AListFind.dm
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
/proc/RunTest()
var/alist/AL = alist("a" = 1, "b" = 2, "c" = -4)
ASSERT(AL.Find("a"))
ASSERT(AL.Find("a", 2, 3))
ASSERT(!AL.Find("d"))
5 changes: 5 additions & 0 deletions Content.Tests/DMProject/Tests/List/alist/AListInsert.dm
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
// RUNTIME ERROR

/proc/RunTest()
var/alist/AL = alist("a" = 1, "b" = -2, "c" = 5.05)
AL.Insert(2, "d", "e")
6 changes: 6 additions & 0 deletions Content.Tests/DMProject/Tests/List/alist/AListJoin.dm
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
/proc/RunTest()
var/alist/AL = alist("a" = 1, "b" = 2, "c" = -4)
var/string_output = AL.Join(",")
ASSERT(string_output == "a,b,c")
string_output = AL.Join("", 2)
ASSERT(string_output == "bc")
20 changes: 20 additions & 0 deletions Content.Tests/DMProject/Tests/List/alist/AListProcInteractions.dm
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
/proc/RunTest()
var/alist/AL = alist("a" = 1, "b" = 2, "c" = -4)
values_cut_over(AL, 0)
ASSERT(AL["a"] == null)
ASSERT(AL["c"] == -4)
ASSERT(length(AL) == 1)

AL = alist("a" = 1, "b" = 2, "c" = -4)
values_cut_under(AL, 0)
ASSERT(AL["a"] == 1)
ASSERT(AL["c"] == null)
ASSERT(length(AL) == 2)

AL = alist("a" = 1, "b" = 2, "c" = -4)
var/alist/AL2 = alist("c" = 5, "d" = 6, "e" = 2)
ASSERT(values_dot(AL, AL2) == -20)

AL = alist("a" = 1, "b" = 2, "c" = -5)
ASSERT(values_product(AL) == -10)
ASSERT(values_sum(AL) == -2)
12 changes: 12 additions & 0 deletions Content.Tests/DMProject/Tests/List/alist/AListRemove.dm
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
/proc/RunTest()
var/alist/AL = alist("a" = 1, "b" = 2, "c" = -4)
ASSERT(AL.Remove("a", "b"))
ASSERT(!("a" in AL))
ASSERT(!("b" in AL))
ASSERT("c" in AL)

AL = alist("a" = 1, "b" = 2, "c" = -4)
ASSERT(AL.Remove(list("a", "b")))
ASSERT(!("a" in AL))
ASSERT(!("b" in AL))
ASSERT("c" in AL)
12 changes: 12 additions & 0 deletions Content.Tests/DMProject/Tests/List/alist/AListRemoveAll.dm
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
/proc/RunTest()
var/alist/AL = alist("a" = 1, "b" = 2, "c" = -4)
ASSERT(AL.Remove("a", "b"))
ASSERT(!("a" in AL))
ASSERT(!("b" in AL))
ASSERT("c" in AL)

AL = alist("a" = 1, "b" = 2, "c" = -4)
ASSERT(AL.Remove(list("a", "b")))
ASSERT(!("a" in AL))
ASSERT(!("b" in AL))
ASSERT("c" in AL)
7 changes: 7 additions & 0 deletions Content.Tests/DMProject/Tests/List/alist/AListSetGet.dm
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
/proc/RunTest()
var/alist/A1 = alist("1" = 1)
ASSERT(A1["1"] == 1)
A1["1"] = 1.5
A1["2"] = 2
ASSERT(A1["1"] == 1.5)
ASSERT(A1["2"] == 2)
5 changes: 5 additions & 0 deletions Content.Tests/DMProject/Tests/List/alist/AListSplice.dm
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
// RUNTIME ERROR

/proc/RunTest()
var/alist/AL = alist("a" = 1, "b" = -2, "c" = 5.05)
AL.Splice(1, 1, "d")
5 changes: 5 additions & 0 deletions Content.Tests/DMProject/Tests/List/alist/AListSwap.dm
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
// RUNTIME ERROR

/proc/RunTest()
var/alist/AL = alist("a" = 1, "b" = -2, "c" = 5.05)
AL.Swap(1, 1)
14 changes: 14 additions & 0 deletions Content.Tests/DMProject/Tests/List/alist/AListValidKeys.dm
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
/proc/RunTest()
var/alist/AL = alist()
var/datum/D = new()
var/list/L = new()
AL[D] = 1
AL["A"] = 2
AL[5] = 3
AL[L] = 4
AL[null] = 5
ASSERT(AL[D] == 1)
ASSERT(AL["A"] == 2)
ASSERT(AL[5] == 3)
ASSERT(AL[L] == 4)
ASSERT(AL[null] == 5)
14 changes: 14 additions & 0 deletions Content.Tests/DMProject/Tests/List/alist/AListValidValues.dm
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
/proc/RunTest()
var/alist/AL = alist()
var/datum/D = new()
var/list/L = new()
AL[1] = D
AL[2] = L
AL[3] = 3
AL[4] = "4"
AL[5] = null
ASSERT(AL[1] == D)
ASSERT(AL[2] == L)
ASSERT(AL[3] == 3)
ASSERT(AL[4] == "4")
ASSERT(AL[5] == null)
2 changes: 2 additions & 0 deletions OpenDreamRuntime/Objects/DreamObjectTree.cs
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,8 @@ public IEnumerable<TreeEntry> GetAllDescendants(TreeEntry treeEntry) {
public DreamObject CreateObject(TreeEntry type) {
if (type == List)
return CreateList();
if (type == AssocList)
return CreateAssocList();
if (type == Savefile)
return new DreamObjectSavefile(Savefile.ObjectDefinition);
if (type.ObjectDefinition.IsSubtypeOf(DatabaseQuery))
Expand Down
90 changes: 89 additions & 1 deletion OpenDreamRuntime/Objects/Types/DreamAssocList.cs
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
using System.Linq;
using OpenDreamRuntime.Procs;

namespace OpenDreamRuntime.Objects.Types;

// TODO: An arglist given to New() can be used to initialize an alist with values
Expand All @@ -6,13 +9,19 @@

private readonly Dictionary<DreamValue, DreamValue> _values = new(size);

public DreamAssocList(DreamObjectDefinition listDef, Dictionary<DreamValue, DreamValue>? values) : this(listDef, values?.Count ?? 0) {
if (values != null) {
_values = values;
}
}

public void SetValue(DreamValue key, DreamValue value, bool allowGrowth = false) {
_values[key] = value;
}

public DreamValue GetValue(DreamValue key) {
if (!_values.TryGetValue(key, out var value))
throw new Exception($"No value with the key {key}");
return DreamValue.Null;

return value;
}
Expand All @@ -21,10 +30,40 @@
return _values.ContainsKey(key);
}

public override DreamValue OperatorIndex(DreamValue index, DMProcState state) {
return GetValue(index);
}

public IEnumerable<DreamValue> EnumerateValues() {
return _values.Keys; // The keys, counter-intuitively
}

public int GetLength() {
return _values.Count;
}

public void Cut(int start = 1, int end = 0) {
if (start != 1) {
throw new Exception($"Cut() was called with non-default start value of {start}.");
}
if (end != 0) {
throw new Exception($"Cut() was called with non-default end value of {end}.");
}
_values.Clear();
}

public List<DreamValue> GetValues() {
return _values.Keys.ToList();
}

public Dictionary<DreamValue, DreamValue> GetAssociativeValues() {
return _values;
}

public void RemoveValue(DreamValue value) {
_values.Remove(value);
}

public IEnumerable<KeyValuePair<DreamValue, DreamValue>> EnumerateAssocValues() {
return _values;
}
Expand All @@ -39,4 +78,53 @@
public Dictionary<DreamValue, DreamValue> CopyAssocValues() {
return new(_values);
}

public void AddValue(DreamValue value) {
//if (GetValue(value) != DreamValue.Null) {
if(ContainsValue(value)) {
return; // calling Add("c") on alist("c" = 5) does not change anything
}
_values[value] = DreamValue.Null;
}

public IDreamList CreateCopy(int start = 1, int end = 0) {
if (start == 0) ++start; //start being 0 and start being 1 are equivalent

var values = GetValues();
if (end > values.Count + 1 || start > values.Count + 1) throw new Exception("list index out of bounds");
if (end == 0) end = values.Count + 1;
if (end <= start)
return new DreamAssocList(ObjectDefinition, 0);

Dictionary<DreamValue, DreamValue> copyValues = new Dictionary<DreamValue, DreamValue>(_values);

return new DreamAssocList(ObjectDefinition, copyValues);
}

public int FindValue(DreamValue value, int start = 1, int end = 0) {
// Unlike list.Find(), alist.Find() doesn't pay attention to start and end, and returns a boolean 0/1 instead of the position of the found object
if(ContainsValue(value)) {
return 1;
}
return 0;
}

public void Insert(int index, DreamValue value) {
throw new Exception("insert not allowed for this list");
}

public void Swap(int index1, int index2) {
throw new Exception("swap not allowed for this list");
}

public bool ContainsValue(DreamValue value) {
var keys = GetValues();
for (int i = 0; i < keys.Count; i++) {
if (keys[i].Equals(value))
return true;
}

return false;
}

}
16 changes: 10 additions & 6 deletions OpenDreamRuntime/Objects/Types/DreamList.cs
Original file line number Diff line number Diff line change
Expand Up @@ -104,14 +104,14 @@
base.HandleDeletion(possiblyThreaded);
}

public DreamList CreateCopy(int start = 1, int end = 0) {
public IDreamList CreateCopy(int start = 1, int end = 0) {
if (start == 0) ++start; //start being 0 and start being 1 are equivalent

var values = GetValues();
if (end > values.Count + 1 || start > values.Count + 1) throw new Exception("list index out of bounds");
if (end == 0) end = values.Count + 1;
if (end <= start)
return new(ObjectDefinition, 0);
return new DreamList(ObjectDefinition, 0);

List<DreamValue> copyValues = values.GetRange(start - 1, end - start);

Expand All @@ -124,7 +124,7 @@
}
}

return new(ObjectDefinition, copyValues, associativeValues);
return new DreamList(ObjectDefinition, copyValues, associativeValues);
}

/// <summary>
Expand Down Expand Up @@ -242,6 +242,10 @@
UpdateTracyContentsMemory();
}

public void DoCut(int start = 1, int end = 0) {
Cut(start, end);
}

public void Insert(int index, DreamValue value) {
_values.Insert(index - 1, value);
UpdateTracyContentsMemory();
Expand Down Expand Up @@ -333,7 +337,7 @@
}

public override DreamValue OperatorAdd(DreamValue b, DMProcState state) {
DreamList listCopy = CreateCopy();
DreamList listCopy = (DreamList)CreateCopy()!;

Check warning

Code scanning / InspectCode

Redundant nullable warning suppression expression Warning

The nullable warning suppression expression is redundant

if (b.TryGetValueAsDreamList(out var bList)) {
foreach (DreamValue value in bList.EnumerateValues()) {
Expand All @@ -351,7 +355,7 @@
}

public override DreamValue OperatorSubtract(DreamValue b, DMProcState state) {
DreamList listCopy = CreateCopy();
DreamList listCopy = (DreamList)CreateCopy()!;

Check warning

Code scanning / InspectCode

Redundant nullable warning suppression expression Warning

The nullable warning suppression expression is redundant

if (b.TryGetValueAsDreamList(out var bList)) {
foreach (DreamValue value in bList.EnumerateValues()) {
Expand All @@ -370,7 +374,7 @@
if (b.TryGetValueAsDreamList(out var bList)) { // List | List
list = Union(bList);
} else { // List | x
list = CreateCopy();
list = (DreamList)CreateCopy()!;

Check warning

Code scanning / InspectCode

Redundant nullable warning suppression expression Warning

The nullable warning suppression expression is redundant
list.AddValue(b);
}

Expand Down
4 changes: 2 additions & 2 deletions OpenDreamRuntime/Objects/Types/DreamObjectImage.cs
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,7 @@ protected override void SetVar(string varName, DreamValue value) {
// Otherwise it attempts to create an appearance and creates a new (normal) list with that appearance
if (ObjectDefinition.IsSubtypeOf(ObjectTree.MutableAppearance)) {
if (valueList != null) {
_overlays = valueList.CreateCopy();
_overlays = (DreamList)valueList.CreateCopy();
} else {
var overlay = DreamOverlaysList.CreateOverlayAppearance(AtomManager, value, AtomManager.MustGetAppearance(this).Icon);
if (overlay == null)
Expand Down Expand Up @@ -165,7 +165,7 @@ protected override void SetVar(string varName, DreamValue value) {
// See the comment in the overlays setter for info on this
if (ObjectDefinition.IsSubtypeOf(ObjectTree.MutableAppearance)) {
if (valueList != null) {
_underlays = valueList.CreateCopy();
_underlays = (DreamList)valueList.CreateCopy();
} else {
var underlay = DreamOverlaysList.CreateOverlayAppearance(AtomManager, value, AtomManager.MustGetAppearance(this).Icon);
if (underlay == null)
Expand Down
Loading
Loading