Skip to content
This repository was archived by the owner on Jan 23, 2023. It is now read-only.

Commit c9a1a97

Browse files
committed
Optimize ImmutableSortedSet<T>.LeafToRootRefill
Some basic microbenchmarks show that this can double throughput and halve garbage production, depending on the inputs.
1 parent 9aa6349 commit c9a1a97

File tree

1 file changed

+34
-5
lines changed

1 file changed

+34
-5
lines changed

src/System.Collections.Immutable/src/System/Collections/Immutable/ImmutableSortedSet`1.cs

Lines changed: 34 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1102,10 +1102,39 @@ private ImmutableSortedSet<T> LeafToRootRefill(IEnumerable<T> addedItems)
11021102
// and can index into that sequence like a list, so the limited
11031103
// garbage produced is a temporary mutable data structure we use
11041104
// as a reference when creating the immutable one.
1105-
// The (mutable) SortedSet<T> is much faster at constructing its collection
1106-
// when passed a sequence into its constructor than into its Union method.
1107-
var sortedSet = new SortedSet<T>(this.Concat(addedItems), this.KeyComparer);
1108-
Node root = Node.NodeTreeFromSortedSet(sortedSet);
1105+
1106+
// Produce the initial list containing all elements, including any duplicates.
1107+
List<T> list;
1108+
if (this.IsEmpty)
1109+
{
1110+
list = new List<T>(addedItems);
1111+
if (list.Count == 0)
1112+
{
1113+
return this;
1114+
}
1115+
}
1116+
else
1117+
{
1118+
list = new List<T>(this);
1119+
list.AddRange(addedItems);
1120+
}
1121+
Debug.Assert(list.Count > 0);
1122+
1123+
// Sort the list and remove duplicate entries.
1124+
IComparer<T> comparer = this.KeyComparer;
1125+
list.Sort(comparer);
1126+
int index = 1;
1127+
for (int i = 1; i < list.Count; i++)
1128+
{
1129+
if (comparer.Compare(list[i], list[i - 1]) != 0)
1130+
{
1131+
list[index++] = list[i];
1132+
}
1133+
}
1134+
list.RemoveRange(index, list.Count - index);
1135+
1136+
// Use the now sorted list of unique items to construct a new sorted set.
1137+
Node root = Node.NodeTreeFromList(list.AsOrderedCollection(), 0, list.Count);
11091138
return this.Wrap(root);
11101139
}
11111140

@@ -2128,7 +2157,7 @@ private static Node MakeBalanced(Node tree)
21282157
/// <param name="length">The number of elements from <paramref name="items"/> that should be captured by the node tree.</param>
21292158
/// <returns>The root of the created node tree.</returns>
21302159
[Pure]
2131-
private static Node NodeTreeFromList(IOrderedCollection<T> items, int start, int length)
2160+
internal static Node NodeTreeFromList(IOrderedCollection<T> items, int start, int length)
21322161
{
21332162
Requires.NotNull(items, "items");
21342163
Debug.Assert(start >= 0);

0 commit comments

Comments
 (0)