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

A["thing"] = 6
ASSERT(A["thing"] == 6)
68 changes: 63 additions & 5 deletions OpenDreamRuntime/Objects/Types/DreamList.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,10 @@

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 @@
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 @@
/// </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,27 @@

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 {
_values[keyInteger - 1] = value;

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

}
} else {
if (!ContainsValue(key)) _values.Add(key);
if (!reverseLookup.TryAdd(key, 1)) {
reverseLookup[key] += 1;
} else {
_values.Add(key);
}

_associativeValues ??= new Dictionary<DreamValue, DreamValue>(1);
_associativeValues[key] = value;
Expand All @@ -192,6 +221,12 @@
int valueIndex = _values.LastIndexOf(value);

if (valueIndex != -1) {
if(reverseLookup.TryGetValue(value, out int element)) {
if (element - 1 <= 0) {
reverseLookup.Remove(value);
}
}

_associativeValues?.Remove(value);
_values.RemoveAt(valueIndex);
}
Expand All @@ -200,12 +235,19 @@
}

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) {
if(reverseLookup.ContainsKey(value)) {
return true;
}
for (int i = 0; i < _values.Count; i++) {
if (_values[i].Equals(value))
return true;
Expand Down Expand Up @@ -236,14 +278,30 @@
_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