From 68e1f0f818b3b94a5e5d7c264d6950ba86276928 Mon Sep 17 00:00:00 2001 From: Stephen Toub Date: Thu, 22 Jun 2023 17:43:12 -0400 Subject: [PATCH] Add span-based static Create overloads for immutable collections --- .../ref/System.Collections.Immutable.cs | 7 ++ .../Collections/Immutable/ImmutableHashSet.cs | 27 +++++ .../Immutable/ImmutableHashSet_1.cs | 32 +++++- .../Collections/Immutable/ImmutableList.cs | 19 +++- .../Immutable/ImmutableList_1.Builder.cs | 2 +- .../Immutable/ImmutableList_1.Node.cs | 36 +++++++ .../Collections/Immutable/ImmutableList_1.cs | 25 +++++ .../Collections/Immutable/ImmutableQueue.cs | 13 ++- .../Immutable/ImmutableSortedSet.cs | 26 +++++ .../Immutable/ImmutableSortedSet_1.Builder.cs | 2 +- .../Immutable/ImmutableSortedSet_1.cs | 102 +++++++++++++++++- .../Collections/Immutable/ImmutableStack.cs | 11 ++ .../tests/ImmutableHashSetTest.cs | 8 ++ .../tests/ImmutableListBuilderTest.cs | 2 +- .../tests/ImmutableListTest.cs | 15 +-- .../tests/ImmutableListTestBase.cs | 6 +- .../tests/ImmutableQueueTest.cs | 4 + .../tests/ImmutableSortedSetTest.cs | 10 +- .../tests/ImmutableStackTest.cs | 4 + 19 files changed, 331 insertions(+), 20 deletions(-) diff --git a/src/libraries/System.Collections.Immutable/ref/System.Collections.Immutable.cs b/src/libraries/System.Collections.Immutable/ref/System.Collections.Immutable.cs index a9d74045f154..e643b6a16e0e 100644 --- a/src/libraries/System.Collections.Immutable/ref/System.Collections.Immutable.cs +++ b/src/libraries/System.Collections.Immutable/ref/System.Collections.Immutable.cs @@ -561,8 +561,10 @@ public static partial class ImmutableHashSet public static System.Collections.Immutable.ImmutableHashSet Create(System.Collections.Generic.IEqualityComparer? equalityComparer) { throw null; } public static System.Collections.Immutable.ImmutableHashSet Create(System.Collections.Generic.IEqualityComparer? equalityComparer, T item) { throw null; } public static System.Collections.Immutable.ImmutableHashSet Create(System.Collections.Generic.IEqualityComparer? equalityComparer, params T[] items) { throw null; } + public static System.Collections.Immutable.ImmutableHashSet Create(System.Collections.Generic.IEqualityComparer? equalityComparer, System.ReadOnlySpan items) { throw null; } public static System.Collections.Immutable.ImmutableHashSet Create(T item) { throw null; } public static System.Collections.Immutable.ImmutableHashSet Create(params T[] items) { throw null; } + public static System.Collections.Immutable.ImmutableHashSet Create(System.ReadOnlySpan items) { throw null; } public static System.Collections.Immutable.ImmutableHashSet ToImmutableHashSet(this System.Collections.Generic.IEnumerable source) { throw null; } public static System.Collections.Immutable.ImmutableHashSet ToImmutableHashSet(this System.Collections.Generic.IEnumerable source, System.Collections.Generic.IEqualityComparer? equalityComparer) { throw null; } public static System.Collections.Immutable.ImmutableHashSet ToImmutableHashSet(this System.Collections.Immutable.ImmutableHashSet.Builder builder) { throw null; } @@ -687,6 +689,7 @@ public static partial class ImmutableList public static System.Collections.Immutable.ImmutableList Create() { throw null; } public static System.Collections.Immutable.ImmutableList Create(T item) { throw null; } public static System.Collections.Immutable.ImmutableList Create(params T[] items) { throw null; } + public static System.Collections.Immutable.ImmutableList Create(System.ReadOnlySpan items) { throw null; } public static int IndexOf(this System.Collections.Immutable.IImmutableList list, T item) { throw null; } public static int IndexOf(this System.Collections.Immutable.IImmutableList list, T item, System.Collections.Generic.IEqualityComparer? equalityComparer) { throw null; } public static int IndexOf(this System.Collections.Immutable.IImmutableList list, T item, int startIndex) { throw null; } @@ -881,6 +884,7 @@ public static partial class ImmutableQueue public static System.Collections.Immutable.ImmutableQueue Create() { throw null; } public static System.Collections.Immutable.ImmutableQueue Create(T item) { throw null; } public static System.Collections.Immutable.ImmutableQueue Create(params T[] items) { throw null; } + public static System.Collections.Immutable.ImmutableQueue Create(System.ReadOnlySpan items) { throw null; } public static System.Collections.Immutable.IImmutableQueue Dequeue(this System.Collections.Immutable.IImmutableQueue queue, out T value) { throw null; } } public sealed partial class ImmutableQueue : System.Collections.Generic.IEnumerable, System.Collections.IEnumerable, System.Collections.Immutable.IImmutableQueue @@ -1055,8 +1059,10 @@ public static partial class ImmutableSortedSet public static System.Collections.Immutable.ImmutableSortedSet Create(System.Collections.Generic.IComparer? comparer) { throw null; } public static System.Collections.Immutable.ImmutableSortedSet Create(System.Collections.Generic.IComparer? comparer, T item) { throw null; } public static System.Collections.Immutable.ImmutableSortedSet Create(System.Collections.Generic.IComparer? comparer, params T[] items) { throw null; } + public static System.Collections.Immutable.ImmutableSortedSet Create(System.Collections.Generic.IComparer? comparer, System.ReadOnlySpan items) { throw null; } public static System.Collections.Immutable.ImmutableSortedSet Create(T item) { throw null; } public static System.Collections.Immutable.ImmutableSortedSet Create(params T[] items) { throw null; } + public static System.Collections.Immutable.ImmutableSortedSet Create(System.ReadOnlySpan items) { throw null; } public static System.Collections.Immutable.ImmutableSortedSet ToImmutableSortedSet(this System.Collections.Generic.IEnumerable source) { throw null; } public static System.Collections.Immutable.ImmutableSortedSet ToImmutableSortedSet(this System.Collections.Generic.IEnumerable source, System.Collections.Generic.IComparer? comparer) { throw null; } public static System.Collections.Immutable.ImmutableSortedSet ToImmutableSortedSet(this System.Collections.Immutable.ImmutableSortedSet.Builder builder) { throw null; } @@ -1187,6 +1193,7 @@ public static partial class ImmutableStack public static System.Collections.Immutable.ImmutableStack Create() { throw null; } public static System.Collections.Immutable.ImmutableStack Create(T item) { throw null; } public static System.Collections.Immutable.ImmutableStack Create(params T[] items) { throw null; } + public static System.Collections.Immutable.ImmutableStack Create(System.ReadOnlySpan items) { throw null; } public static System.Collections.Immutable.IImmutableStack Pop(this System.Collections.Immutable.IImmutableStack stack, out T value) { throw null; } } public sealed partial class ImmutableStack : System.Collections.Generic.IEnumerable, System.Collections.IEnumerable, System.Collections.Immutable.IImmutableStack diff --git a/src/libraries/System.Collections.Immutable/src/System/Collections/Immutable/ImmutableHashSet.cs b/src/libraries/System.Collections.Immutable/src/System/Collections/Immutable/ImmutableHashSet.cs index 6c6550168d45..9630bb33b5c0 100644 --- a/src/libraries/System.Collections.Immutable/src/System/Collections/Immutable/ImmutableHashSet.cs +++ b/src/libraries/System.Collections.Immutable/src/System/Collections/Immutable/ImmutableHashSet.cs @@ -86,6 +86,19 @@ public static ImmutableHashSet CreateRange(IEqualityComparer? equalityC /// The items to prepopulate. /// The new immutable collection. public static ImmutableHashSet Create(params T[] items) + { + Requires.NotNull(items, nameof(items)); + + return Create((ReadOnlySpan)items); + } + + /// + /// Creates a new immutable collection prefilled with the specified items. + /// + /// The type of items stored by the collection. + /// The items to prepopulate. + /// The new immutable collection. + public static ImmutableHashSet Create(ReadOnlySpan items) { return ImmutableHashSet.Empty.Union(items); } @@ -98,6 +111,20 @@ public static ImmutableHashSet Create(params T[] items) /// The items to prepopulate. /// The new immutable collection. public static ImmutableHashSet Create(IEqualityComparer? equalityComparer, params T[] items) + { + Requires.NotNull(items, nameof(items)); + + return Create(equalityComparer, (ReadOnlySpan)items); + } + + /// + /// Creates a new immutable collection prefilled with the specified items. + /// + /// The type of items stored by the collection. + /// The equality comparer. + /// The items to prepopulate. + /// The new immutable collection. + public static ImmutableHashSet Create(IEqualityComparer? equalityComparer, ReadOnlySpan items) { return ImmutableHashSet.Empty.WithComparer(equalityComparer).Union(items); } diff --git a/src/libraries/System.Collections.Immutable/src/System/Collections/Immutable/ImmutableHashSet_1.cs b/src/libraries/System.Collections.Immutable/src/System/Collections/Immutable/ImmutableHashSet_1.cs index 0a0dce740ee8..b0117e842121 100644 --- a/src/libraries/System.Collections.Immutable/src/System/Collections/Immutable/ImmutableHashSet_1.cs +++ b/src/libraries/System.Collections.Immutable/src/System/Collections/Immutable/ImmutableHashSet_1.cs @@ -3,7 +3,6 @@ using System.Collections.Generic; using System.Diagnostics; -using System.Diagnostics.CodeAnalysis; using System.Linq; namespace System.Collections.Immutable @@ -239,6 +238,14 @@ public ImmutableHashSet Union(IEnumerable other) return this.Union(other, avoidWithComparer: false); } + /// + /// See the interface. + /// + internal ImmutableHashSet Union(ReadOnlySpan other) + { + return Union(other, this.Origin).Finalize(this); + } + /// /// See the interface. /// @@ -693,6 +700,29 @@ private static MutationResult Union(IEnumerable other, MutationInput origin) return new MutationResult(newRoot, count); } + /// + /// Performs the set operation on a given data structure. + /// + private static MutationResult Union(ReadOnlySpan other, MutationInput origin) + { + int count = 0; + SortedInt32KeyNode.HashBucket> newRoot = origin.Root; + foreach (T item in other) + { + int hashCode = item != null ? origin.EqualityComparer.GetHashCode(item) : 0; + HashBucket bucket = newRoot.GetValueOrDefault(hashCode); + OperationResult result; + ImmutableHashSet.HashBucket newBucket = bucket.Add(item, origin.EqualityComparer, out result); + if (result == OperationResult.SizeChanged) + { + newRoot = UpdateRoot(newRoot, hashCode, origin.HashBucketEqualityComparer, newBucket); + count++; + } + } + + return new MutationResult(newRoot, count); + } + /// /// Performs the set operation on a given data structure. /// diff --git a/src/libraries/System.Collections.Immutable/src/System/Collections/Immutable/ImmutableList.cs b/src/libraries/System.Collections.Immutable/src/System/Collections/Immutable/ImmutableList.cs index 9ed4ab5b27f2..f3004e3fd019 100644 --- a/src/libraries/System.Collections.Immutable/src/System/Collections/Immutable/ImmutableList.cs +++ b/src/libraries/System.Collections.Immutable/src/System/Collections/Immutable/ImmutableList.cs @@ -36,10 +36,23 @@ public static class ImmutableList /// /// Creates a new immutable collection prefilled with the specified items. /// - /// The type of items stored by the collection. - /// The items to prepopulate. + /// The type of items in the immutable list. + /// A span that contains the items to prepopulate the list with. /// The new immutable collection. - public static ImmutableList Create(params T[] items) => ImmutableList.Empty.AddRange(items); + public static ImmutableList Create(params T[] items) + { + Requires.NotNull(items, nameof(items)); + + return Create((ReadOnlySpan)items); + } + + /// + /// Creates a new immutable list that contains the items from the specified span of items. + /// + /// The type of items stored by the collection. + /// A span that contains the items to prepopulate the list with. + /// A new immutable list that contains the specified items. + public static ImmutableList Create(ReadOnlySpan items) => ImmutableList.Empty.AddRange(items); /// /// Creates a new immutable list builder. diff --git a/src/libraries/System.Collections.Immutable/src/System/Collections/Immutable/ImmutableList_1.Builder.cs b/src/libraries/System.Collections.Immutable/src/System/Collections/Immutable/ImmutableList_1.Builder.cs index 620a9568469b..803e13162c53 100644 --- a/src/libraries/System.Collections.Immutable/src/System/Collections/Immutable/ImmutableList_1.Builder.cs +++ b/src/libraries/System.Collections.Immutable/src/System/Collections/Immutable/ImmutableList_1.Builder.cs @@ -18,7 +18,7 @@ public sealed partial class ImmutableList /// /// /// - /// While and other bulk change methods + /// While and other bulk change methods /// already provide fast bulk change operations on the collection, this class allows /// multiple combinations of changes to be made to a set with equal efficiency. /// diff --git a/src/libraries/System.Collections.Immutable/src/System/Collections/Immutable/ImmutableList_1.Node.cs b/src/libraries/System.Collections.Immutable/src/System/Collections/Immutable/ImmutableList_1.Node.cs index 1eeec15ab32d..36e3441531a9 100644 --- a/src/libraries/System.Collections.Immutable/src/System/Collections/Immutable/ImmutableList_1.Node.cs +++ b/src/libraries/System.Collections.Immutable/src/System/Collections/Immutable/ImmutableList_1.Node.cs @@ -278,6 +278,25 @@ internal static Node NodeTreeFromList(IOrderedCollection items, int start, in return new Node(items[start + leftCount], left, right, true); } + /// + /// Creates a node tree that contains the contents of a span. + /// + /// A span with the contents that the new node tree should contain. + /// The root of the created node tree. + internal static Node NodeTreeFromList(ReadOnlySpan items) + { + if (items.IsEmpty) + { + return EmptyNode; + } + + int rightCount = (items.Length - 1) / 2; + int leftCount = (items.Length - 1) - rightCount; + Node left = NodeTreeFromList(items.Slice(0, leftCount)); + Node right = NodeTreeFromList(items.Slice(leftCount + 1)); + return new Node(items[leftCount], left, right, frozen: true); + } + /// /// Adds the specified key to the tree. /// @@ -343,6 +362,23 @@ internal Node AddRange(IEnumerable keys) return result.BalanceMany(); } + /// + /// Adds the specified keys to this tree. + /// + /// The keys. + /// The new tree. + internal Node AddRange(ReadOnlySpan keys) + { + if (this.IsEmpty) + { + return NodeTreeFromList(keys); + } + + Node newRight = _right!.AddRange(keys); + Node result = this.MutateRight(newRight); + return result.BalanceMany(); + } + /// /// Adds the specified keys at a given index to this tree. /// diff --git a/src/libraries/System.Collections.Immutable/src/System/Collections/Immutable/ImmutableList_1.cs b/src/libraries/System.Collections.Immutable/src/System/Collections/Immutable/ImmutableList_1.cs index 9d0d342f3d23..966244fa4ead 100644 --- a/src/libraries/System.Collections.Immutable/src/System/Collections/Immutable/ImmutableList_1.cs +++ b/src/libraries/System.Collections.Immutable/src/System/Collections/Immutable/ImmutableList_1.cs @@ -233,6 +233,31 @@ public ImmutableList AddRange(IEnumerable items) return this.Wrap(result); } + /// + /// See the interface. + /// + internal ImmutableList AddRange(ReadOnlySpan items) + { + if (this.IsEmpty) + { + if (items.IsEmpty) + { + return Empty; + } + + return new ImmutableList(Node.NodeTreeFromList(items)); + } + else + { + if (items.IsEmpty) + { + return this; + } + + return this.Wrap(_root.AddRange(items)); + } + } + /// /// See the interface. /// diff --git a/src/libraries/System.Collections.Immutable/src/System/Collections/Immutable/ImmutableQueue.cs b/src/libraries/System.Collections.Immutable/src/System/Collections/Immutable/ImmutableQueue.cs index f4079238c9c6..122bae100534 100644 --- a/src/libraries/System.Collections.Immutable/src/System/Collections/Immutable/ImmutableQueue.cs +++ b/src/libraries/System.Collections.Immutable/src/System/Collections/Immutable/ImmutableQueue.cs @@ -74,7 +74,18 @@ public static ImmutableQueue Create(params T[] items) { Requires.NotNull(items, nameof(items)); - if (items.Length == 0) + return Create((ReadOnlySpan)items); + } + + /// + /// Creates a new immutable queue that contains the specified array of items. + /// + /// The type of items in the immutable queue. + /// A span that contains the items to prepopulate the queue with. + /// A new immutable queue that contains the specified items. + public static ImmutableQueue Create(ReadOnlySpan items) + { + if (items.IsEmpty) { return ImmutableQueue.Empty; } diff --git a/src/libraries/System.Collections.Immutable/src/System/Collections/Immutable/ImmutableSortedSet.cs b/src/libraries/System.Collections.Immutable/src/System/Collections/Immutable/ImmutableSortedSet.cs index 54548ffc1406..567997ed0472 100644 --- a/src/libraries/System.Collections.Immutable/src/System/Collections/Immutable/ImmutableSortedSet.cs +++ b/src/libraries/System.Collections.Immutable/src/System/Collections/Immutable/ImmutableSortedSet.cs @@ -86,6 +86,18 @@ public static ImmutableSortedSet CreateRange(IComparer? comparer, IEnum /// The items to prepopulate. /// The new immutable collection. public static ImmutableSortedSet Create(params T[] items) + { + Requires.NotNull(items, nameof(items)); + return Create((ReadOnlySpan)items); + } + + /// + /// Creates a new immutable sorted set that contains the specified array of items. + /// + /// The type of items in the immutable set. + /// A span that contains the items to prepopulate the set with. + /// A new immutable set that contains the specified items. + public static ImmutableSortedSet Create(ReadOnlySpan items) { return ImmutableSortedSet.Empty.Union(items); } @@ -98,6 +110,20 @@ public static ImmutableSortedSet Create(params T[] items) /// The items to prepopulate. /// The new immutable collection. public static ImmutableSortedSet Create(IComparer? comparer, params T[] items) + { + Requires.NotNull(items, nameof(items)); + + return Create(comparer, (ReadOnlySpan)items); + } + + /// + /// Creates a new immutable collection prefilled with the specified items. + /// + /// The type of items stored by the collection. + /// The comparer. + /// The items to prepopulate. + /// The new immutable collection. + public static ImmutableSortedSet Create(IComparer? comparer, ReadOnlySpan items) { return ImmutableSortedSet.Empty.WithComparer(comparer).Union(items); } diff --git a/src/libraries/System.Collections.Immutable/src/System/Collections/Immutable/ImmutableSortedSet_1.Builder.cs b/src/libraries/System.Collections.Immutable/src/System/Collections/Immutable/ImmutableSortedSet_1.Builder.cs index e202ccd199f2..1aa94496f43a 100644 --- a/src/libraries/System.Collections.Immutable/src/System/Collections/Immutable/ImmutableSortedSet_1.Builder.cs +++ b/src/libraries/System.Collections.Immutable/src/System/Collections/Immutable/ImmutableSortedSet_1.Builder.cs @@ -18,7 +18,7 @@ public sealed partial class ImmutableSortedSet /// /// /// - /// While and other bulk change methods + /// While and other bulk change methods /// already provide fast bulk change operations on the collection, this class allows /// multiple combinations of changes to be made to a set with equal efficiency. /// diff --git a/src/libraries/System.Collections.Immutable/src/System/Collections/Immutable/ImmutableSortedSet_1.cs b/src/libraries/System.Collections.Immutable/src/System/Collections/Immutable/ImmutableSortedSet_1.cs index ba8328777147..493172c31ecb 100644 --- a/src/libraries/System.Collections.Immutable/src/System/Collections/Immutable/ImmutableSortedSet_1.cs +++ b/src/libraries/System.Collections.Immutable/src/System/Collections/Immutable/ImmutableSortedSet_1.cs @@ -334,6 +334,23 @@ public ImmutableSortedSet Union(IEnumerable other) return this.UnionIncremental(other); } + /// + /// See the interface. + /// + internal ImmutableSortedSet Union(ReadOnlySpan other) + { + if (this.IsEmpty || (this.Count + other.Length) * RefillOverIncrementalThreshold > this.Count) + { + // The payload being added is so large compared to this collection's current size + // that we likely won't see much memory reuse in the node tree by performing an + // incremental update. So just recreate the entire node tree since that will + // likely be faster. + return this.LeafToRootRefill(other); + } + + return this.UnionIncremental(other); + } + /// /// See the interface. /// @@ -1042,8 +1059,31 @@ private ImmutableSortedSet UnionIncremental(IEnumerable items) ImmutableSortedSet.Node result = _root; foreach (T item in items.GetEnumerableDisposable()) { - bool mutated; - result = result.Add(item, _comparer, out mutated); + result = result.Add(item, _comparer, out _); + } + + return this.Wrap(result); + } + + /// + /// Adds items to this collection using the standard spine rewrite and tree rebalance technique. + /// + /// The items to add. + /// The new collection. + /// + /// This method is least demanding on memory, providing the great chance of memory reuse + /// and does not require allocating memory large enough to store all items contiguously. + /// It's performance is optimal for additions that do not significantly dwarf the existing + /// size of this collection. + /// + private ImmutableSortedSet UnionIncremental(ReadOnlySpan items) + { + // Let's not implement in terms of ImmutableSortedSet.Add so that we're + // not unnecessarily generating a new wrapping set object for each item. + ImmutableSortedSet.Node result = _root; + foreach (T item in items) + { + result = result.Add(item, _comparer, out _); } return this.Wrap(result); @@ -1131,6 +1171,64 @@ private ImmutableSortedSet LeafToRootRefill(IEnumerable addedItems) return this.Wrap(root); } + /// + /// Creates an immutable sorted set with the contents from this collection and a sequence of elements. + /// + /// The sequence of elements to add to this set. + /// The immutable sorted set. + private ImmutableSortedSet LeafToRootRefill(ReadOnlySpan addedItems) + { + // See comments in LeafToRootRefill(IEnumerable addedItems) + + // Produce the initial list containing all elements, including any duplicates. + List list; + if (this.IsEmpty && addedItems.IsEmpty) + { + // If the additional items enumerable list is known to be empty, too, + // then just return this empty instance. + if (addedItems.IsEmpty) + { + return this; + } + + list = new List(addedItems.Length); + } + else + { + // Build the list from this set and then add the additional items. + // Even if the additional items is empty, this set isn't, so we know + // the resulting list will not be empty. + list = new List(this.Count + addedItems.Length); + list.AddRange(this); + } +#if NET8_0_OR_GREATER + list.AddRange(addedItems); +#else + foreach (var item in addedItems) + { + list.Add(item); + } +#endif + Debug.Assert(list.Count > 0); + + // Sort the list and remove duplicate entries. + IComparer comparer = this.KeyComparer; + list.Sort(comparer); + int index = 1; + for (int i = 1; i < list.Count; i++) + { + if (comparer.Compare(list[i], list[i - 1]) != 0) + { + list[index++] = list[i]; + } + } + list.RemoveRange(index, list.Count - index); + + // Use the now sorted list of unique items to construct a new sorted set. + Node root = Node.NodeTreeFromList(list.AsOrderedCollection(), 0, list.Count); + return this.Wrap(root); + } + /// /// An reverse enumerable of a sorted set. /// diff --git a/src/libraries/System.Collections.Immutable/src/System/Collections/Immutable/ImmutableStack.cs b/src/libraries/System.Collections.Immutable/src/System/Collections/Immutable/ImmutableStack.cs index 9acbdf2ab8e2..4e11bb768880 100644 --- a/src/libraries/System.Collections.Immutable/src/System/Collections/Immutable/ImmutableStack.cs +++ b/src/libraries/System.Collections.Immutable/src/System/Collections/Immutable/ImmutableStack.cs @@ -61,6 +61,17 @@ public static ImmutableStack Create(params T[] items) { Requires.NotNull(items, nameof(items)); + return Create((ReadOnlySpan)items); + } + + /// + /// Creates a new immutable stack that contains the specified array of items. + /// + /// The type of items in the immutable stack. + /// A span that contains the items to prepopulate the stack with. + /// A new immutable stack that contains the specified items. + public static ImmutableStack Create(ReadOnlySpan items) + { ImmutableStack stack = ImmutableStack.Empty; foreach (T item in items) { diff --git a/src/libraries/System.Collections.Immutable/tests/ImmutableHashSetTest.cs b/src/libraries/System.Collections.Immutable/tests/ImmutableHashSetTest.cs index 5c316919438e..0aab9405d559 100644 --- a/src/libraries/System.Collections.Immutable/tests/ImmutableHashSetTest.cs +++ b/src/libraries/System.Collections.Immutable/tests/ImmutableHashSetTest.cs @@ -122,10 +122,18 @@ public void Create() Assert.Equal(2, set.Count); Assert.Same(EqualityComparer.Default, set.KeyComparer); + set = ImmutableHashSet.Create((ReadOnlySpan)new[] { "a", "b" }); + Assert.Equal(2, set.Count); + Assert.Same(EqualityComparer.Default, set.KeyComparer); + set = ImmutableHashSet.Create(comparer, "a", "b"); Assert.Equal(2, set.Count); Assert.Same(comparer, set.KeyComparer); + set = ImmutableHashSet.Create(comparer, (ReadOnlySpan)new[] { "a", "b" }); + Assert.Equal(2, set.Count); + Assert.Same(comparer, set.KeyComparer); + set = ImmutableHashSet.CreateRange((IEnumerable)new[] { "a", "b" }); Assert.Equal(2, set.Count); Assert.Same(EqualityComparer.Default, set.KeyComparer); diff --git a/src/libraries/System.Collections.Immutable/tests/ImmutableListBuilderTest.cs b/src/libraries/System.Collections.Immutable/tests/ImmutableListBuilderTest.cs index f6e60f0f23f9..897a00b40a7d 100644 --- a/src/libraries/System.Collections.Immutable/tests/ImmutableListBuilderTest.cs +++ b/src/libraries/System.Collections.Immutable/tests/ImmutableListBuilderTest.cs @@ -476,7 +476,7 @@ public void ToImmutableList() protected override IEnumerable GetEnumerableOf(params T[] contents) { - return ImmutableList.Empty.AddRange(contents).ToBuilder(); + return ImmutableList.Empty.AddRange((ReadOnlySpan)contents).ToBuilder(); } protected override void RemoveAllTestHelper(ImmutableList list, Predicate test) diff --git a/src/libraries/System.Collections.Immutable/tests/ImmutableListTest.cs b/src/libraries/System.Collections.Immutable/tests/ImmutableListTest.cs index 275603414355..707a66ff23c8 100644 --- a/src/libraries/System.Collections.Immutable/tests/ImmutableListTest.cs +++ b/src/libraries/System.Collections.Immutable/tests/ImmutableListTest.cs @@ -51,7 +51,7 @@ public void RandomOperationsTest() int[] values = Enumerable.Range(0, inputLength).Select(i => random.Next()).ToArray(); Debug.WriteLine("Adding {0} elements to the list.", inputLength); expected.AddRange(values); - actual = actual.AddRange(values); + actual = actual.AddRange((IEnumerable)values); VerifyBalanced(actual); break; case Operation.Insert: @@ -139,10 +139,10 @@ public void AddAndIndexerTest() public void AddRangeTest() { ImmutableList list = ImmutableList.Empty; - list = list.AddRange(new[] { 1, 2, 3 }); + list = list.AddRange((IEnumerable)new[] { 1, 2, 3 }); list = list.AddRange(Enumerable.Range(4, 2)); - list = list.AddRange(ImmutableList.Empty.AddRange(new[] { 6, 7, 8 })); - list = list.AddRange(new int[0]); + list = list.AddRange(ImmutableList.Empty.AddRange((IEnumerable)new[] { 6, 7, 8 })); + list = list.AddRange((IEnumerable)new int[0]); list = list.AddRange(ImmutableList.Empty.AddRange(Enumerable.Range(9, 1000))); Assert.Equal(Enumerable.Range(1, 1008), list); } @@ -165,7 +165,7 @@ public void AddRangeOptimizationsTest() ImmutableList emptyList = ImmutableList.Create(); // Adding an empty list to an empty list should yield the original list. - Assert.Same(emptyList, emptyList.AddRange(new string[0])); + Assert.Same(emptyList, emptyList.AddRange(Enumerable.Empty())); // Adding a non-empty immutable list to an empty one should return the added list. ImmutableList nonEmptyListDefaultComparer = ImmutableList.Create("5"); @@ -587,6 +587,9 @@ public void Create() list = ImmutableList.Create("a", "b"); Assert.Equal(2, list.Count); + list = ImmutableList.Create((ReadOnlySpan)new[] { "a", "b" }); + Assert.Equal(2, list.Count); + list = ImmutableList.CreateRange((IEnumerable)new[] { "a", "b" }); Assert.Equal(2, list.Count); } @@ -836,7 +839,7 @@ public void ItemRef_OutOfBounds() protected override IEnumerable GetEnumerableOf(params T[] contents) { - return ImmutableList.Empty.AddRange(contents); + return ImmutableList.Empty.AddRange((IEnumerable)contents); } protected override void RemoveAllTestHelper(ImmutableList list, Predicate test) diff --git a/src/libraries/System.Collections.Immutable/tests/ImmutableListTestBase.cs b/src/libraries/System.Collections.Immutable/tests/ImmutableListTestBase.cs index 1144529e7907..09eeac7214e5 100644 --- a/src/libraries/System.Collections.Immutable/tests/ImmutableListTestBase.cs +++ b/src/libraries/System.Collections.Immutable/tests/ImmutableListTestBase.cs @@ -91,7 +91,7 @@ public void ExistsTest() public void FindAllTest() { Assert.True(this.GetListQuery(ImmutableList.Empty).FindAll(n => true).IsEmpty); - ImmutableList list = ImmutableList.Empty.AddRange(new[] { 2, 3, 4, 5, 6 }); + ImmutableList list = ImmutableList.Empty.AddRange((IEnumerable)new[] { 2, 3, 4, 5, 6 }); ImmutableList actual = this.GetListQuery(list).FindAll(n => n % 2 == 1); List expected = list.ToList().FindAll(n => n % 2 == 1); Assert.Equal(expected, actual.ToList()); @@ -101,7 +101,7 @@ public void FindAllTest() public void FindTest() { Assert.Equal(0, this.GetListQuery(ImmutableList.Empty).Find(n => true)); - ImmutableList list = ImmutableList.Empty.AddRange(new[] { 2, 3, 4, 5, 6 }); + ImmutableList list = ImmutableList.Empty.AddRange((IEnumerable)new[] { 2, 3, 4, 5, 6 }); Assert.Equal(3, this.GetListQuery(list).Find(n => (n % 2) == 1)); } @@ -109,7 +109,7 @@ public void FindTest() public void FindLastTest() { Assert.Equal(0, this.GetListQuery(ImmutableList.Empty).FindLast(n => { throw new ShouldNotBeInvokedException(); })); - ImmutableList list = ImmutableList.Empty.AddRange(new[] { 2, 3, 4, 5, 6 }); + ImmutableList list = ImmutableList.Empty.AddRange((IEnumerable)new[] { 2, 3, 4, 5, 6 }); Assert.Equal(5, this.GetListQuery(list).FindLast(n => (n % 2) == 1)); } diff --git a/src/libraries/System.Collections.Immutable/tests/ImmutableQueueTest.cs b/src/libraries/System.Collections.Immutable/tests/ImmutableQueueTest.cs index dc0de12b7bf3..365240105e34 100644 --- a/src/libraries/System.Collections.Immutable/tests/ImmutableQueueTest.cs +++ b/src/libraries/System.Collections.Immutable/tests/ImmutableQueueTest.cs @@ -217,6 +217,10 @@ public void Create() Assert.False(queue.IsEmpty); Assert.Equal(new[] { 1, 2 }, queue); + queue = ImmutableQueue.Create((ReadOnlySpan)new[] { 1, 2 }); + Assert.False(queue.IsEmpty); + Assert.Equal(new[] { 1, 2 }, queue); + queue = ImmutableQueue.CreateRange((IEnumerable)new[] { 1, 2 }); Assert.False(queue.IsEmpty); Assert.Equal(new[] { 1, 2 }, queue); diff --git a/src/libraries/System.Collections.Immutable/tests/ImmutableSortedSetTest.cs b/src/libraries/System.Collections.Immutable/tests/ImmutableSortedSetTest.cs index 6b90b2a354b8..1f6808c4f696 100644 --- a/src/libraries/System.Collections.Immutable/tests/ImmutableSortedSetTest.cs +++ b/src/libraries/System.Collections.Immutable/tests/ImmutableSortedSetTest.cs @@ -49,7 +49,7 @@ public void RandomOperationsTest() break; case Operation.Union: int inputLength = random.Next(100); - int[] values = Enumerable.Range(0, inputLength).Select(i => random.Next()).ToArray(); + IEnumerable values = Enumerable.Range(0, inputLength).Select(i => random.Next()).ToArray(); Debug.WriteLine("Adding {0} elements to the set.", inputLength); expected.UnionWith(values); actual = actual.Union(values); @@ -293,10 +293,18 @@ public void Create() Assert.Equal(2, set.Count); Assert.Same(Comparer.Default, set.KeyComparer); + set = ImmutableSortedSet.Create((ReadOnlySpan)new[] { "a", "b" }); + Assert.Equal(2, set.Count); + Assert.Same(Comparer.Default, set.KeyComparer); + set = ImmutableSortedSet.Create(comparer, "a", "b"); Assert.Equal(2, set.Count); Assert.Same(comparer, set.KeyComparer); + set = ImmutableSortedSet.Create(comparer, (ReadOnlySpan)new[] { "a", "b" }); + Assert.Equal(2, set.Count); + Assert.Same(comparer, set.KeyComparer); + set = ImmutableSortedSet.CreateRange((IEnumerable)new[] { "a", "b" }); Assert.Equal(2, set.Count); Assert.Same(Comparer.Default, set.KeyComparer); diff --git a/src/libraries/System.Collections.Immutable/tests/ImmutableStackTest.cs b/src/libraries/System.Collections.Immutable/tests/ImmutableStackTest.cs index 60c392224a9b..1813326705ef 100644 --- a/src/libraries/System.Collections.Immutable/tests/ImmutableStackTest.cs +++ b/src/libraries/System.Collections.Immutable/tests/ImmutableStackTest.cs @@ -245,6 +245,10 @@ public void Create() Assert.False(stack.IsEmpty); Assert.Equal(new[] { 2, 1 }, stack); + stack = ImmutableStack.Create((ReadOnlySpan)new[] { 1, 2 }); + Assert.False(stack.IsEmpty); + Assert.Equal(new[] { 2, 1 }, stack); + stack = ImmutableStack.CreateRange((IEnumerable)new[] { 1, 2 }); Assert.False(stack.IsEmpty); Assert.Equal(new[] { 2, 1 }, stack);