Skip to content

Commit 787cfe6

Browse files
committed
[Core] Fix issues with sorting/grouping in MultiValueSortedList
1 parent cf5af19 commit 787cfe6

File tree

2 files changed

+39
-19
lines changed

2 files changed

+39
-19
lines changed

sources/core/Stride.Core.Tests/Collections/MultiValueSortedListTests.cs

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -24,21 +24,23 @@ public void Add_SingleValue_AddsToList()
2424
Assert.Single(list);
2525
}
2626

27-
[Fact(Skip = "Implementation has issues with retrieving all values for a key")]
27+
[Fact]
2828
public void Add_MultipleValuesWithSameKey_AllAdded()
2929
{
3030
var list = new MultiValueSortedList<int, string>();
3131
list.Add(new KeyValuePair<int, string>(1, "first"));
3232
list.Add(new KeyValuePair<int, string>(1, "second"));
3333
list.Add(new KeyValuePair<int, string>(1, "third"));
3434

35-
// All 3 values are properly added
3635
Assert.Equal(3, list.Count);
3736
var values = list[1].ToList();
38-
Assert.Single(values);
37+
Assert.Equal(3, values.Count);
38+
Assert.Contains("first", values);
39+
Assert.Contains("second", values);
40+
Assert.Contains("third", values);
3941
}
4042

41-
[Fact(Skip = "Implementation has sorting issues")]
43+
[Fact]
4244
public void Add_MaintainsSortedOrder()
4345
{
4446
var list = new MultiValueSortedList<int, string>();
@@ -62,8 +64,9 @@ public void Indexer_ReturnsValuesForKey()
6264
var valuesFor1 = list[1].ToList();
6365
var valuesFor2 = list[2].ToList();
6466

65-
// Note: Implementation has an issue with multiple values per key
66-
Assert.Single(valuesFor1);
67+
Assert.Equal(2, valuesFor1.Count);
68+
Assert.Contains("a", valuesFor1);
69+
Assert.Contains("b", valuesFor1);
6770
Assert.Single(valuesFor2);
6871
Assert.Contains("c", valuesFor2);
6972
}
@@ -142,7 +145,7 @@ public void Remove_NonExistentKey_ReturnsFalse()
142145
Assert.Single(list);
143146
}
144147

145-
[Fact(Skip = "Implementation has sorting issues")]
148+
[Fact]
146149
public void Keys_ReturnsDistinctKeysInOrder()
147150
{
148151
var list = new MultiValueSortedList<int, string>();
@@ -172,7 +175,7 @@ public void Values_ReturnsAllValues()
172175
Assert.Contains("c", values);
173176
}
174177

175-
[Fact(Skip = "Implementation has grouping issues")]
178+
[Fact]
176179
public void GetEnumerator_GroupsByKey()
177180
{
178181
var list = new MultiValueSortedList<int, string>();
@@ -227,7 +230,7 @@ public void CopyTo_CopiesAllElements()
227230
Assert.NotEqual(default, array[2]);
228231
}
229232

230-
[Fact(Skip = "Implementation has sorting issues")]
233+
[Fact]
231234
public void MixedKeys_MaintainsSortOrder()
232235
{
233236
var list = new MultiValueSortedList<int, string>();

sources/core/Stride.Core/Collections/MultiValueSortedList.cs

Lines changed: 27 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -83,23 +83,25 @@ IEnumerator IEnumerable.GetEnumerator()
8383

8484
public void Add(KeyValuePair<TKey, TValue> item)
8585
{
86+
// Binary search to find insertion point
8687
var lower = 0;
87-
var greater = list.Count;
88-
var current = (lower + greater) >> 1;
89-
while (greater - lower > 1)
88+
var upper = list.Count;
89+
90+
while (lower < upper)
9091
{
91-
if (keys[current].CompareTo(item.Key) < 0)
92+
var mid = lower + (upper - lower) / 2;
93+
if (keys[mid].CompareTo(item.Key) < 0)
9294
{
93-
lower = current;
95+
lower = mid + 1;
9496
}
9597
else
9698
{
97-
greater = current;
99+
upper = mid;
98100
}
99-
current = (lower + greater) >> 1;
100101
}
101-
list.Insert(greater, item);
102-
keys.Insert(greater, item.Key);
102+
103+
list.Insert(lower, item);
104+
keys.Insert(lower, item.Key);
103105
}
104106

105107
public bool Contains(object key)
@@ -152,7 +154,22 @@ public bool Contains(TKey key)
152154

153155
public int Count => list.Count;
154156

155-
public IEnumerable<TValue> this[TKey key] { get { return list.Skip(KeyToIndex(key)).TakeWhile(x => x.Key.Equals(key)).Select(x => x.Value); } }
157+
public IEnumerable<TValue> this[TKey key]
158+
{
159+
get
160+
{
161+
var index = KeyToIndex(key);
162+
if (index < 0) return Enumerable.Empty<TValue>();
163+
164+
// Binary search may return any matching index, so we need to find the first one
165+
while (index > 0 && keys[index - 1].Equals(key))
166+
{
167+
index--;
168+
}
169+
170+
return list.Skip(index).TakeWhile(x => x.Key.Equals(key)).Select(x => x.Value);
171+
}
172+
}
156173

157174
int ICollection.Count => list.Count;
158175

0 commit comments

Comments
 (0)