Skip to content
Closed
13 changes: 13 additions & 0 deletions Content.Tests/DMProject/Tests/List/ListIndexToKey.dm
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
/proc/RunTest()
var/list/A = list("thing")
ASSERT(A[1] == "thing")

A["thing"] = 6
ASSERT(A["thing"] == 6)

var/list/L = list()
for(var/i in 1 to 5)
L.Add("[i]")
L["[i]"] = "item [i]"
ASSERT(length(L) == 5)
ASSERT(L["3"] == "item 3")
79 changes: 68 additions & 11 deletions OpenDreamRuntime/Objects/Types/DreamList.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,10 @@ public class DreamList : DreamObject, IDreamList {

public virtual bool IsAssociative => _associativeValues is { Count: > 0 };

/// <summary>
/// Looks up the key to find the index
/// </summary>
private readonly Dictionary<DreamValue, int> _reverseLookup = [];
private readonly List<DreamValue> _values;
private Dictionary<DreamValue, DreamValue>? _associativeValues;

Expand All @@ -30,6 +34,12 @@ public DreamList(DreamObjectDefinition listDef, int size) : base(listDef) {
if (size >= DreamManager.ListPoolThreshold && ListPool.TryPop(out var poppedValues)) {
_values = poppedValues;
_values.EnsureCapacity(size);
foreach (var value in poppedValues) {
if (!_reverseLookup.TryAdd(value, 1)) {
_reverseLookup[value] += 1;
}
}

} else {
_values = new List<DreamValue>(size);
}
Expand All @@ -40,6 +50,11 @@ public DreamList(DreamObjectDefinition listDef, int size) : base(listDef) {
/// </summary>
public DreamList(DreamObjectDefinition listDef, List<DreamValue> values, Dictionary<DreamValue, DreamValue>? associativeValues) : base(listDef) {
_values = values;
foreach (var value in values) {
if (!_reverseLookup.TryAdd(value, 1)) {
_reverseLookup[value] += 1;
}
}
_associativeValues = associativeValues;

#if TOOLS
Expand Down Expand Up @@ -173,13 +188,33 @@ public virtual DreamValue GetValue(DreamValue key) {

public virtual void SetValue(DreamValue key, DreamValue value, bool allowGrowth = false) {
if (key.TryGetValueAsInteger(out int keyInteger)) {
if (allowGrowth && keyInteger == _values.Count + 1) {
var index = _values.Count + 1;
if (allowGrowth && keyInteger == index) {
_values.Add(value);

if (!_reverseLookup.TryAdd(value, 1)) {
_reverseLookup[value] += 1;
}
} else {
var oldValue = _values[keyInteger - 1];
var rLCount = _reverseLookup[oldValue] -= 1;
if(rLCount <= 0) {
_reverseLookup.Remove(oldValue);
}

_values[keyInteger - 1] = value;

if (!_reverseLookup.TryAdd(value, 1)) {
_reverseLookup[value] += 1;
}

}
} else {
if (!ContainsValue(key)) _values.Add(key);
if (!_reverseLookup.TryAdd(key, 1)) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should be:

if (_reverseLookup.TryAdd(key, 1)) {
    _values.Add(key);
}

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is covered by the containsvalue function. also this is closed

_reverseLookup[key] += 1;
} else {
_values.Add(key);
}

_associativeValues ??= new Dictionary<DreamValue, DreamValue>(1);
_associativeValues[key] = value;
Expand All @@ -192,6 +227,13 @@ public virtual void RemoveValue(DreamValue value) {
int valueIndex = _values.LastIndexOf(value);

if (valueIndex != -1) {
if (_reverseLookup.ContainsKey(value)) {
var rLCount = _reverseLookup[value] -= 1;
if (rLCount <= 0) {
_reverseLookup.Remove(value);
}
}

_associativeValues?.Remove(value);
_values.RemoveAt(valueIndex);
}
Expand All @@ -200,18 +242,17 @@ public virtual void RemoveValue(DreamValue value) {
}

public virtual void AddValue(DreamValue value) {
_values.Add(value);
_values.Add(value);
if (!_reverseLookup.TryAdd(value, 1)) {
_reverseLookup[value] += 1;
}

UpdateTracyContentsMemory();
}

//Does not include associations
public virtual bool ContainsValue(DreamValue value) {
for (int i = 0; i < _values.Count; i++) {
if (_values[i].Equals(value))
return true;
}

return false;
return _reverseLookup.ContainsKey(value);
}

public virtual bool ContainsKey(DreamValue value) {
Expand All @@ -236,14 +277,30 @@ public virtual void Cut(int start = 1, int end = 0) {
_associativeValues.Remove(_values[i - 1]);
}

if (end > start)
_values.RemoveRange(start - 1, end - start);
if (end > start) {
var index = start - 1;
var len = end - start;
var elements = _values.GetRange(index, len);

foreach (var element in elements) {
var rlCache = _reverseLookup[element] -= 1;

if (rlCache <= 0) {
_reverseLookup.Remove(element);
}
}

_values.RemoveRange(index, len);
}

UpdateTracyContentsMemory();
}

public void Insert(int index, DreamValue value) {
_values.Insert(index - 1, value);
if (!_reverseLookup.TryAdd(value, 1)) {
_reverseLookup[value] += 1;
}
UpdateTracyContentsMemory();
}

Expand Down
Loading