Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/mono/corefx.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Wrighton <davidwr@microsoft.com>2017-02-07 20:23:15 +0300
committerIan Hays <ianha@microsoft.com>2017-02-07 20:23:15 +0300
commit29d7b6dee194e71bc5c98eec962bcac39bee8bb7 (patch)
tree49e5b45dc3f46701e91575c292295ac2f64060d7
parentc932468fc4021d0ce3ae20564bbc2f12499a2158 (diff)
Factor ImmutableArray<T> into many files (#15526)
* Factor ImmutableArray<T> into many files - Break immutable array (an enumerable, immutable, array) into a core component - And a bunch of algorithm components which represents algorithms on the array - And a bunch of components which represent creation of new related immutable arrays - The purpose of this work is to make it possible to source include the core of immutable array into a component which cannot depend on high level apis such as LINQ, SortedDictionary, etc. (All api use must be satisfied by System.Private.CoreLib). The work to add this other component (System.Private.Reflection.Metadata.Ecma335 will be delivered via a separate PR) * Finish merge with ImmutableArray changes * Reduce number of partial files to two
-rw-r--r--src/System.Collections.Immutable/src/System.Collections.Immutable.csproj2
-rw-r--r--src/System.Collections.Immutable/src/System/Collections/Immutable/ImmutableArray_1.Minimal.cs426
-rw-r--r--src/System.Collections.Immutable/src/System/Collections/Immutable/ImmutableArray_1.cs411
-rw-r--r--src/System.Collections.Immutable/src/System/Collections/Immutable/ImmutableExtensions.Minimal.cs181
-rw-r--r--src/System.Collections.Immutable/src/System/Collections/Immutable/ImmutableExtensions.cs166
5 files changed, 611 insertions, 575 deletions
diff --git a/src/System.Collections.Immutable/src/System.Collections.Immutable.csproj b/src/System.Collections.Immutable/src/System.Collections.Immutable.csproj
index 553fef628d..f13f641d9d 100644
--- a/src/System.Collections.Immutable/src/System.Collections.Immutable.csproj
+++ b/src/System.Collections.Immutable/src/System.Collections.Immutable.csproj
@@ -45,6 +45,7 @@
<Compile Include="System\Collections\Immutable\ImmutableArray_1.Builder.DebuggerProxy.cs" />
<Compile Include="System\Collections\Immutable\ImmutableArray_1.Enumerator.cs" />
<Compile Include="System\Collections\Immutable\ImmutableArray_1.cs" />
+ <Compile Include="System\Collections\Immutable\ImmutableArray_1.Minimal.cs" />
<Compile Include="System\Collections\Immutable\ImmutableDictionary.cs" />
<Compile Include="System\Collections\Immutable\ImmutableDictionary_2.Builder.cs" />
<Compile Include="System\Collections\Immutable\ImmutableDictionary_2.Comparers.cs" />
@@ -55,6 +56,7 @@
<Compile Include="System\Collections\Immutable\ImmutableDictionary_2.MutationResult.cs" />
<Compile Include="System\Collections\Immutable\ImmutableDictionary_2.cs" />
<Compile Include="System\Collections\Immutable\ImmutableExtensions.cs" />
+ <Compile Include="System\Collections\Immutable\ImmutableExtensions.Minimal.cs" />
<Compile Include="System\Collections\Immutable\ImmutableHashSet.cs" />
<Compile Include="System\Collections\Immutable\ImmutableHashSet_1.Builder.cs" />
<Compile Include="System\Collections\Immutable\ImmutableHashSet_1.DebuggerProxy.cs" />
diff --git a/src/System.Collections.Immutable/src/System/Collections/Immutable/ImmutableArray_1.Minimal.cs b/src/System.Collections.Immutable/src/System/Collections/Immutable/ImmutableArray_1.Minimal.cs
new file mode 100644
index 0000000000..b5a30ae825
--- /dev/null
+++ b/src/System.Collections.Immutable/src/System/Collections/Immutable/ImmutableArray_1.Minimal.cs
@@ -0,0 +1,426 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.Diagnostics.CodeAnalysis;
+using System.Diagnostics.Contracts;
+using System.Globalization;
+using System.Linq;
+using System.Runtime.Versioning;
+
+namespace System.Collections.Immutable
+{
+ /// <summary>
+ /// A readonly array with O(1) indexable lookup time.
+ /// </summary>
+ /// <typeparam name="T">The type of element stored by the array.</typeparam>
+ /// <devremarks>
+ /// This type has a documented contract of being exactly one reference-type field in size.
+ /// Our own <see cref="ImmutableInterlocked"/> class depends on it, as well as others externally.
+ /// IMPORTANT NOTICE FOR MAINTAINERS AND REVIEWERS:
+ /// This type should be thread-safe. As a struct, it cannot protect its own fields
+ /// from being changed from one thread while its members are executing on other threads
+ /// because structs can change *in place* simply by reassigning the field containing
+ /// this struct. Therefore it is extremely important that
+ /// ** Every member should only dereference <c>this</c> ONCE. **
+ /// If a member needs to reference the array field, that counts as a dereference of <c>this</c>.
+ /// Calling other instance members (properties or methods) also counts as dereferencing <c>this</c>.
+ /// Any member that needs to use <c>this</c> more than once must instead
+ /// assign <c>this</c> to a local variable and use that for the rest of the code instead.
+ /// This effectively copies the one field in the struct to a local variable so that
+ /// it is insulated from other threads.
+ /// </devremarks>
+ [DebuggerDisplay("{DebuggerDisplay,nq}")]
+ [NonVersionable] // Applies to field layout
+ public partial struct ImmutableArray<T> : IEnumerable<T>, IEquatable<ImmutableArray<T>>, IImmutableArray
+ {
+ /// <summary>
+ /// An empty (initialized) instance of <see cref="ImmutableArray{T}"/>.
+ /// </summary>
+ public static readonly ImmutableArray<T> Empty = new ImmutableArray<T>(new T[0]);
+
+ /// <summary>
+ /// The backing field for this instance. References to this value should never be shared with outside code.
+ /// </summary>
+ /// <remarks>
+ /// This would be private, but we make it internal so that our own extension methods can access it.
+ /// </remarks>
+ [DebuggerBrowsable(DebuggerBrowsableState.RootHidden)]
+ internal T[] array;
+
+ /// <summary>
+ /// Initializes a new instance of the <see cref="ImmutableArray{T}"/> struct
+ /// *without making a defensive copy*.
+ /// </summary>
+ /// <param name="items">The array to use. May be null for "default" arrays.</param>
+ internal ImmutableArray(T[] items)
+ {
+ this.array = items;
+ }
+
+ #region Operators
+
+ /// <summary>
+ /// Checks equality between two instances.
+ /// </summary>
+ /// <param name="left">The instance to the left of the operator.</param>
+ /// <param name="right">The instance to the right of the operator.</param>
+ /// <returns><c>true</c> if the values' underlying arrays are reference equal; <c>false</c> otherwise.</returns>
+ [NonVersionable]
+ public static bool operator ==(ImmutableArray<T> left, ImmutableArray<T> right)
+ {
+ return left.Equals(right);
+ }
+
+ /// <summary>
+ /// Checks inequality between two instances.
+ /// </summary>
+ /// <param name="left">The instance to the left of the operator.</param>
+ /// <param name="right">The instance to the right of the operator.</param>
+ /// <returns><c>true</c> if the values' underlying arrays are reference not equal; <c>false</c> otherwise.</returns>
+ [NonVersionable]
+ public static bool operator !=(ImmutableArray<T> left, ImmutableArray<T> right)
+ {
+ return !left.Equals(right);
+ }
+
+ /// <summary>
+ /// Checks equality between two instances.
+ /// </summary>
+ /// <param name="left">The instance to the left of the operator.</param>
+ /// <param name="right">The instance to the right of the operator.</param>
+ /// <returns><c>true</c> if the values' underlying arrays are reference equal; <c>false</c> otherwise.</returns>
+ public static bool operator ==(ImmutableArray<T>? left, ImmutableArray<T>? right)
+ {
+ return left.GetValueOrDefault().Equals(right.GetValueOrDefault());
+ }
+
+ /// <summary>
+ /// Checks inequality between two instances.
+ /// </summary>
+ /// <param name="left">The instance to the left of the operator.</param>
+ /// <param name="right">The instance to the right of the operator.</param>
+ /// <returns><c>true</c> if the values' underlying arrays are reference not equal; <c>false</c> otherwise.</returns>
+ public static bool operator !=(ImmutableArray<T>? left, ImmutableArray<T>? right)
+ {
+ return !left.GetValueOrDefault().Equals(right.GetValueOrDefault());
+ }
+
+ #endregion
+
+ /// <summary>
+ /// Gets the element at the specified index in the read-only list.
+ /// </summary>
+ /// <param name="index">The zero-based index of the element to get.</param>
+ /// <returns>The element at the specified index in the read-only list.</returns>
+ public T this[int index]
+ {
+ [NonVersionable]
+ get
+ {
+ // We intentionally do not check this.array != null, and throw NullReferenceException
+ // if this is called while uninitialized.
+ // The reason for this is perf.
+ // Length and the indexer must be absolutely trivially implemented for the JIT optimization
+ // of removing array bounds checking to work.
+ return this.array[index];
+ }
+ }
+
+ /// <summary>
+ /// Gets a value indicating whether this collection is empty.
+ /// </summary>
+ [DebuggerBrowsable(DebuggerBrowsableState.Never)]
+ public bool IsEmpty
+ {
+ [NonVersionable]
+ get { return this.Length == 0; }
+ }
+
+ /// <summary>
+ /// Gets the number of elements in the array.
+ /// </summary>
+ [DebuggerBrowsable(DebuggerBrowsableState.Never)]
+ public int Length
+ {
+ [NonVersionable]
+ get
+ {
+ // We intentionally do not check this.array != null, and throw NullReferenceException
+ // if this is called while uninitialized.
+ // The reason for this is perf.
+ // Length and the indexer must be absolutely trivially implemented for the JIT optimization
+ // of removing array bounds checking to work.
+ return this.array.Length;
+ }
+ }
+
+ /// <summary>
+ /// Gets a value indicating whether this struct was initialized without an actual array instance.
+ /// </summary>
+ [DebuggerBrowsable(DebuggerBrowsableState.Never)]
+ public bool IsDefault
+ {
+ get { return this.array == null; }
+ }
+
+ /// <summary>
+ /// Gets a value indicating whether this struct is empty or uninitialized.
+ /// </summary>
+ [DebuggerBrowsable(DebuggerBrowsableState.Never)]
+ public bool IsDefaultOrEmpty
+ {
+ get
+ {
+ var self = this;
+ return self.array == null || self.array.Length == 0;
+ }
+ }
+
+ /// <summary>
+ /// Gets an untyped reference to the array.
+ /// </summary>
+ [DebuggerBrowsable(DebuggerBrowsableState.Never)]
+ Array IImmutableArray.Array
+ {
+ get { return this.array; }
+ }
+
+ /// <summary>
+ /// Gets the string to display in the debugger watches window for this instance.
+ /// </summary>
+ [DebuggerBrowsable(DebuggerBrowsableState.Never)]
+ private string DebuggerDisplay
+ {
+ get
+ {
+ var self = this;
+ return self.IsDefault ? "Uninitialized" : String.Format(CultureInfo.CurrentCulture, "Length = {0}", self.Length);
+ }
+ }
+
+ /// <summary>
+ /// Copies the contents of this array to the specified array.
+ /// </summary>
+ /// <param name="destination">The array to copy to.</param>
+ [Pure]
+ public void CopyTo(T[] destination)
+ {
+ var self = this;
+ self.ThrowNullRefIfNotInitialized();
+ Array.Copy(self.array, 0, destination, 0, self.Length);
+ }
+
+ /// <summary>
+ /// Copies the contents of this array to the specified array.
+ /// </summary>
+ /// <param name="destination">The array to copy to.</param>
+ /// <param name="destinationIndex">The index into the destination array to which the first copied element is written.</param>
+ [Pure]
+ public void CopyTo(T[] destination, int destinationIndex)
+ {
+ var self = this;
+ self.ThrowNullRefIfNotInitialized();
+ Array.Copy(self.array, 0, destination, destinationIndex, self.Length);
+ }
+
+ /// <summary>
+ /// Copies the contents of this array to the specified array.
+ /// </summary>
+ /// <param name="sourceIndex">The index into this collection of the first element to copy.</param>
+ /// <param name="destination">The array to copy to.</param>
+ /// <param name="destinationIndex">The index into the destination array to which the first copied element is written.</param>
+ /// <param name="length">The number of elements to copy.</param>
+ [Pure]
+ public void CopyTo(int sourceIndex, T[] destination, int destinationIndex, int length)
+ {
+ var self = this;
+ self.ThrowNullRefIfNotInitialized();
+ Array.Copy(self.array, sourceIndex, destination, destinationIndex, length);
+ }
+
+ /// <summary>
+ /// Returns a builder that is populated with the same contents as this array.
+ /// </summary>
+ /// <returns>The new builder.</returns>
+ [Pure]
+ public ImmutableArray<T>.Builder ToBuilder()
+ {
+ var self = this;
+ if (self.Length == 0)
+ {
+ return new Builder(); // allow the builder to create itself with a reasonable default capacity
+ }
+
+ var builder = new Builder(self.Length);
+ builder.AddRange(self);
+ return builder;
+ }
+
+ /// <summary>
+ /// Returns an enumerator for the contents of the array.
+ /// </summary>
+ /// <returns>An enumerator.</returns>
+ [Pure]
+ public Enumerator GetEnumerator()
+ {
+ var self = this;
+ self.ThrowNullRefIfNotInitialized();
+ return new Enumerator(self.array);
+ }
+
+ /// <summary>
+ /// Returns a hash code for this instance.
+ /// </summary>
+ /// <returns>
+ /// A hash code for this instance, suitable for use in hashing algorithms and data structures like a hash table.
+ /// </returns>
+ [Pure]
+ public override int GetHashCode()
+ {
+ var self = this;
+ return self.array == null ? 0 : self.array.GetHashCode();
+ }
+
+ /// <summary>
+ /// Determines whether the specified <see cref="Object"/> is equal to this instance.
+ /// </summary>
+ /// <param name="obj">The <see cref="Object"/> to compare with this instance.</param>
+ /// <returns>
+ /// <c>true</c> if the specified <see cref="Object"/> is equal to this instance; otherwise, <c>false</c>.
+ /// </returns>
+ [Pure]
+ public override bool Equals(object obj)
+ {
+ IImmutableArray other = obj as IImmutableArray;
+ if (other != null)
+ {
+ return this.array == other.Array;
+ }
+
+ return false;
+ }
+
+ /// <summary>
+ /// Indicates whether the current object is equal to another object of the same type.
+ /// </summary>
+ /// <param name="other">An object to compare with this object.</param>
+ /// <returns>
+ /// true if the current object is equal to the <paramref name="other"/> parameter; otherwise, false.
+ /// </returns>
+ [Pure]
+ [NonVersionable]
+ public bool Equals(ImmutableArray<T> other)
+ {
+ return this.array == other.array;
+ }
+
+ /// <summary>
+ /// Initializes a new instance of the <see cref="ImmutableArray{T}"/> struct based on the contents
+ /// of an existing instance, allowing a covariant static cast to efficiently reuse the existing array.
+ /// </summary>
+ /// <param name="items">The array to initialize the array with. No copy is made.</param>
+ /// <remarks>
+ /// Covariant upcasts from this method may be reversed by calling the
+ /// <see cref="ImmutableArray{T}.As{TOther}"/> or <see cref="ImmutableArray{T}.CastArray{TOther}"/>method.
+ /// </remarks>
+ [Pure]
+ public static ImmutableArray<T> CastUp<TDerived>(ImmutableArray<TDerived> items)
+ where TDerived : class, T
+ {
+ return new ImmutableArray<T>(items.array);
+ }
+
+ /// <summary>
+ /// Initializes a new instance of the <see cref="ImmutableArray{T}"/> struct by casting the underlying
+ /// array to an array of type <typeparam name="TOther"/>.
+ /// </summary>
+ /// <exception cref="InvalidCastException">Thrown if the cast is illegal.</exception>
+ [Pure]
+ public ImmutableArray<TOther> CastArray<TOther>() where TOther : class
+ {
+ return new ImmutableArray<TOther>((TOther[])(object)array);
+ }
+
+ /// <summary>
+ /// Creates an immutable array for this array, cast to a different element type.
+ /// </summary>
+ /// <typeparam name="TOther">The type of array element to return.</typeparam>
+ /// <returns>
+ /// A struct typed for the base element type. If the cast fails, an instance
+ /// is returned whose <see cref="IsDefault"/> property returns <c>true</c>.
+ /// </returns>
+ /// <remarks>
+ /// Arrays of derived elements types can be cast to arrays of base element types
+ /// without reallocating the array.
+ /// These upcasts can be reversed via this same method, casting an array of base
+ /// element types to their derived types. However, downcasting is only successful
+ /// when it reverses a prior upcasting operation.
+ /// </remarks>
+ [Pure]
+ public ImmutableArray<TOther> As<TOther>() where TOther : class
+ {
+ return new ImmutableArray<TOther>(this.array as TOther[]);
+ }
+
+ /// <summary>
+ /// Returns an enumerator for the contents of the array.
+ /// </summary>
+ /// <returns>An enumerator.</returns>
+ /// <exception cref="InvalidOperationException">Thrown if the <see cref="IsDefault"/> property returns true.</exception>
+ [Pure]
+ IEnumerator<T> IEnumerable<T>.GetEnumerator()
+ {
+ var self = this;
+ self.ThrowInvalidOperationIfNotInitialized();
+ return EnumeratorObject.Create(self.array);
+ }
+
+ /// <summary>
+ /// Returns an enumerator for the contents of the array.
+ /// </summary>
+ /// <returns>An enumerator.</returns>
+ /// <exception cref="InvalidOperationException">Thrown if the <see cref="IsDefault"/> property returns true.</exception>
+ [Pure]
+ IEnumerator IEnumerable.GetEnumerator()
+ {
+ var self = this;
+ self.ThrowInvalidOperationIfNotInitialized();
+ return EnumeratorObject.Create(self.array);
+ }
+
+ /// <summary>
+ /// Throws a null reference exception if the array field is null.
+ /// </summary>
+ internal void ThrowNullRefIfNotInitialized()
+ {
+ // Force NullReferenceException if array is null by touching its Length.
+ // This way of checking has a nice property of requiring very little code
+ // and not having any conditions/branches.
+ // In a faulting scenario we are relying on hardware to generate the fault.
+ // And in the non-faulting scenario (most common) the check is virtually free since
+ // if we are going to do anything with the array, we will need Length anyways
+ // so touching it, and potentially causing a cache miss, is not going to be an
+ // extra expense.
+ var unused = this.array.Length;
+ }
+
+ /// <summary>
+ /// Throws an <see cref="InvalidOperationException"/> if the <see cref="array"/> field is null, i.e. the
+ /// <see cref="IsDefault"/> property returns true. The
+ /// <see cref="InvalidOperationException"/> message specifies that the operation cannot be performed
+ /// on a default instance of <see cref="ImmutableArray{T}"/>.
+ ///
+ /// This is intended for explicitly implemented interface method and property implementations.
+ /// </summary>
+ private void ThrowInvalidOperationIfNotInitialized()
+ {
+ if (this.IsDefault)
+ {
+ throw new InvalidOperationException(SR.InvalidOperationOnDefaultArray);
+ }
+ }
+ }
+}
diff --git a/src/System.Collections.Immutable/src/System/Collections/Immutable/ImmutableArray_1.cs b/src/System.Collections.Immutable/src/System/Collections/Immutable/ImmutableArray_1.cs
index c6585b17da..48981cfc7f 100644
--- a/src/System.Collections.Immutable/src/System/Collections/Immutable/ImmutableArray_1.cs
+++ b/src/System.Collections.Immutable/src/System/Collections/Immutable/ImmutableArray_1.cs
@@ -12,124 +12,9 @@ using System.Runtime.Versioning;
namespace System.Collections.Immutable
{
- /// <summary>
- /// A readonly array with O(1) indexable lookup time.
- /// </summary>
- /// <typeparam name="T">The type of element stored by the array.</typeparam>
- /// <devremarks>
- /// This type has a documented contract of being exactly one reference-type field in size.
- /// Our own <see cref="ImmutableInterlocked"/> class depends on it, as well as others externally.
- /// IMPORTANT NOTICE FOR MAINTAINERS AND REVIEWERS:
- /// This type should be thread-safe. As a struct, it cannot protect its own fields
- /// from being changed from one thread while its members are executing on other threads
- /// because structs can change *in place* simply by reassigning the field containing
- /// this struct. Therefore it is extremely important that
- /// ** Every member should only dereference <c>this</c> ONCE. **
- /// If a member needs to reference the array field, that counts as a dereference of <c>this</c>.
- /// Calling other instance members (properties or methods) also counts as dereferencing <c>this</c>.
- /// Any member that needs to use <c>this</c> more than once must instead
- /// assign <c>this</c> to a local variable and use that for the rest of the code instead.
- /// This effectively copies the one field in the struct to a local variable so that
- /// it is insulated from other threads.
- /// </devremarks>
- [DebuggerDisplay("{DebuggerDisplay,nq}")]
- [NonVersionable] // Applies to field layout
- public partial struct ImmutableArray<T> : IReadOnlyList<T>, IList<T>, IEquatable<ImmutableArray<T>>, IImmutableList<T>, IList, IImmutableArray, IStructuralComparable, IStructuralEquatable
+ public partial struct ImmutableArray<T> : IReadOnlyList<T>, IList<T>, IEquatable<ImmutableArray<T>>, IList, IImmutableArray, IStructuralComparable, IStructuralEquatable, IImmutableList<T>
{
/// <summary>
- /// An empty (initialized) instance of <see cref="ImmutableArray{T}"/>.
- /// </summary>
- public static readonly ImmutableArray<T> Empty = new ImmutableArray<T>(new T[0]);
-
- /// <summary>
- /// The backing field for this instance. References to this value should never be shared with outside code.
- /// </summary>
- /// <remarks>
- /// This would be private, but we make it internal so that our own extension methods can access it.
- /// </remarks>
- [DebuggerBrowsable(DebuggerBrowsableState.RootHidden)]
- internal T[] array;
-
- /// <summary>
- /// Initializes a new instance of the <see cref="ImmutableArray{T}"/> struct
- /// *without making a defensive copy*.
- /// </summary>
- /// <param name="items">The array to use. May be null for "default" arrays.</param>
- internal ImmutableArray(T[] items)
- {
- this.array = items;
- }
-
- #region Operators
-
- /// <summary>
- /// Checks equality between two instances.
- /// </summary>
- /// <param name="left">The instance to the left of the operator.</param>
- /// <param name="right">The instance to the right of the operator.</param>
- /// <returns><c>true</c> if the values' underlying arrays are reference equal; <c>false</c> otherwise.</returns>
- [NonVersionable]
- public static bool operator ==(ImmutableArray<T> left, ImmutableArray<T> right)
- {
- return left.Equals(right);
- }
-
- /// <summary>
- /// Checks inequality between two instances.
- /// </summary>
- /// <param name="left">The instance to the left of the operator.</param>
- /// <param name="right">The instance to the right of the operator.</param>
- /// <returns><c>true</c> if the values' underlying arrays are reference not equal; <c>false</c> otherwise.</returns>
- [NonVersionable]
- public static bool operator !=(ImmutableArray<T> left, ImmutableArray<T> right)
- {
- return !left.Equals(right);
- }
-
- /// <summary>
- /// Checks equality between two instances.
- /// </summary>
- /// <param name="left">The instance to the left of the operator.</param>
- /// <param name="right">The instance to the right of the operator.</param>
- /// <returns><c>true</c> if the values' underlying arrays are reference equal; <c>false</c> otherwise.</returns>
- public static bool operator ==(ImmutableArray<T>? left, ImmutableArray<T>? right)
- {
- return left.GetValueOrDefault().Equals(right.GetValueOrDefault());
- }
-
- /// <summary>
- /// Checks inequality between two instances.
- /// </summary>
- /// <param name="left">The instance to the left of the operator.</param>
- /// <param name="right">The instance to the right of the operator.</param>
- /// <returns><c>true</c> if the values' underlying arrays are reference not equal; <c>false</c> otherwise.</returns>
- public static bool operator !=(ImmutableArray<T>? left, ImmutableArray<T>? right)
- {
- return !left.GetValueOrDefault().Equals(right.GetValueOrDefault());
- }
-
- #endregion
-
- /// <summary>
- /// Gets the element at the specified index in the read-only list.
- /// </summary>
- /// <param name="index">The zero-based index of the element to get.</param>
- /// <returns>The element at the specified index in the read-only list.</returns>
- public T this[int index]
- {
- [NonVersionable]
- get
- {
- // We intentionally do not check this.array != null, and throw NullReferenceException
- // if this is called while uninitialized.
- // The reason for this is perf.
- // Length and the indexer must be absolutely trivially implemented for the JIT optimization
- // of removing array bounds checking to work.
- return this.array[index];
- }
- }
-
- /// <summary>
/// Gets or sets the element at the specified index in the read-only list.
/// </summary>
/// <param name="index">The zero-based index of the element to get.</param>
@@ -160,34 +45,6 @@ namespace System.Collections.Immutable
}
/// <summary>
- /// Gets a value indicating whether this collection is empty.
- /// </summary>
- [DebuggerBrowsable(DebuggerBrowsableState.Never)]
- public bool IsEmpty
- {
- [NonVersionable]
- get { return this.Length == 0; }
- }
-
- /// <summary>
- /// Gets the number of elements in the array.
- /// </summary>
- [DebuggerBrowsable(DebuggerBrowsableState.Never)]
- public int Length
- {
- [NonVersionable]
- get
- {
- // We intentionally do not check this.array != null, and throw NullReferenceException
- // if this is called while uninitialized.
- // The reason for this is perf.
- // Length and the indexer must be absolutely trivially implemented for the JIT optimization
- // of removing array bounds checking to work.
- return this.array.Length;
- }
- }
-
- /// <summary>
/// Gets the number of array in the collection.
/// </summary>
/// <exception cref="InvalidOperationException">Thrown if the <see cref="IsDefault"/> property returns true.</exception>
@@ -236,50 +93,6 @@ namespace System.Collections.Immutable
}
/// <summary>
- /// Gets a value indicating whether this struct was initialized without an actual array instance.
- /// </summary>
- [DebuggerBrowsable(DebuggerBrowsableState.Never)]
- public bool IsDefault
- {
- get { return this.array == null; }
- }
-
- /// <summary>
- /// Gets a value indicating whether this struct is empty or uninitialized.
- /// </summary>
- [DebuggerBrowsable(DebuggerBrowsableState.Never)]
- public bool IsDefaultOrEmpty
- {
- get
- {
- var self = this;
- return self.array == null || self.array.Length == 0;
- }
- }
-
- /// <summary>
- /// Gets an untyped reference to the array.
- /// </summary>
- [DebuggerBrowsable(DebuggerBrowsableState.Never)]
- Array IImmutableArray.Array
- {
- get { return this.array; }
- }
-
- /// <summary>
- /// Gets the string to display in the debugger watches window for this instance.
- /// </summary>
- [DebuggerBrowsable(DebuggerBrowsableState.Never)]
- private string DebuggerDisplay
- {
- get
- {
- var self = this;
- return self.IsDefault ? "Uninitialized" : String.Format(CultureInfo.CurrentCulture, "Length = {0}", self.Length);
- }
- }
-
- /// <summary>
/// Searches the array for the specified item.
/// </summary>
/// <param name="item">The item to search for.</param>
@@ -476,46 +289,6 @@ namespace System.Collections.Immutable
}
/// <summary>
- /// Copies the contents of this array to the specified array.
- /// </summary>
- /// <param name="destination">The array to copy to.</param>
- [Pure]
- public void CopyTo(T[] destination)
- {
- var self = this;
- self.ThrowNullRefIfNotInitialized();
- Array.Copy(self.array, 0, destination, 0, self.Length);
- }
-
- /// <summary>
- /// Copies the contents of this array to the specified array.
- /// </summary>
- /// <param name="destination">The array to copy to.</param>
- /// <param name="destinationIndex">The index into the destination array to which the first copied element is written.</param>
- [Pure]
- public void CopyTo(T[] destination, int destinationIndex)
- {
- var self = this;
- self.ThrowNullRefIfNotInitialized();
- Array.Copy(self.array, 0, destination, destinationIndex, self.Length);
- }
-
- /// <summary>
- /// Copies the contents of this array to the specified array.
- /// </summary>
- /// <param name="sourceIndex">The index into this collection of the first element to copy.</param>
- /// <param name="destination">The array to copy to.</param>
- /// <param name="destinationIndex">The index into the destination array to which the first copied element is written.</param>
- /// <param name="length">The number of elements to copy.</param>
- [Pure]
- public void CopyTo(int sourceIndex, T[] destination, int destinationIndex, int length)
- {
- var self = this;
- self.ThrowNullRefIfNotInitialized();
- Array.Copy(self.array, sourceIndex, destination, destinationIndex, length);
- }
-
- /// <summary>
/// Returns a new array with the specified value inserted at the specified position.
/// </summary>
/// <param name="index">The 0-based index into the array at which the new item should be added.</param>
@@ -1030,131 +803,6 @@ namespace System.Collections.Immutable
return self;
}
-
- /// <summary>
- /// Returns a builder that is populated with the same contents as this array.
- /// </summary>
- /// <returns>The new builder.</returns>
- [Pure]
- public ImmutableArray<T>.Builder ToBuilder()
- {
- var self = this;
- if (self.Length == 0)
- {
- return new Builder(); // allow the builder to create itself with a reasonable default capacity
- }
-
- var builder = new Builder(self.Length);
- builder.AddRange(self);
- return builder;
- }
-
- /// <summary>
- /// Returns an enumerator for the contents of the array.
- /// </summary>
- /// <returns>An enumerator.</returns>
- [Pure]
- public Enumerator GetEnumerator()
- {
- var self = this;
- self.ThrowNullRefIfNotInitialized();
- return new Enumerator(self.array);
- }
-
- /// <summary>
- /// Returns a hash code for this instance.
- /// </summary>
- /// <returns>
- /// A hash code for this instance, suitable for use in hashing algorithms and data structures like a hash table.
- /// </returns>
- [Pure]
- public override int GetHashCode()
- {
- var self = this;
- return self.array == null ? 0 : self.array.GetHashCode();
- }
-
- /// <summary>
- /// Determines whether the specified <see cref="Object"/> is equal to this instance.
- /// </summary>
- /// <param name="obj">The <see cref="Object"/> to compare with this instance.</param>
- /// <returns>
- /// <c>true</c> if the specified <see cref="Object"/> is equal to this instance; otherwise, <c>false</c>.
- /// </returns>
- [Pure]
- public override bool Equals(object obj)
- {
- IImmutableArray other = obj as IImmutableArray;
- if (other != null)
- {
- return this.array == other.Array;
- }
-
- return false;
- }
-
- /// <summary>
- /// Indicates whether the current object is equal to another object of the same type.
- /// </summary>
- /// <param name="other">An object to compare with this object.</param>
- /// <returns>
- /// true if the current object is equal to the <paramref name="other"/> parameter; otherwise, false.
- /// </returns>
- [Pure]
- [NonVersionable]
- public bool Equals(ImmutableArray<T> other)
- {
- return this.array == other.array;
- }
-
- /// <summary>
- /// Initializes a new instance of the <see cref="ImmutableArray{T}"/> struct based on the contents
- /// of an existing instance, allowing a covariant static cast to efficiently reuse the existing array.
- /// </summary>
- /// <param name="items">The array to initialize the array with. No copy is made.</param>
- /// <remarks>
- /// Covariant upcasts from this method may be reversed by calling the
- /// <see cref="ImmutableArray{T}.As{TOther}"/> or <see cref="ImmutableArray{T}.CastArray{TOther}"/>method.
- /// </remarks>
- [Pure]
- public static ImmutableArray<T> CastUp<TDerived>(ImmutableArray<TDerived> items)
- where TDerived : class, T
- {
- return new ImmutableArray<T>(items.array);
- }
-
- /// <summary>
- /// Initializes a new instance of the <see cref="ImmutableArray{T}"/> struct by casting the underlying
- /// array to an array of type <typeparam name="TOther"/>.
- /// </summary>
- /// <exception cref="InvalidCastException">Thrown if the cast is illegal.</exception>
- [Pure]
- public ImmutableArray<TOther> CastArray<TOther>() where TOther : class
- {
- return new ImmutableArray<TOther>((TOther[])(object)array);
- }
-
- /// <summary>
- /// Creates an immutable array for this array, cast to a different element type.
- /// </summary>
- /// <typeparam name="TOther">The type of array element to return.</typeparam>
- /// <returns>
- /// A struct typed for the base element type. If the cast fails, an instance
- /// is returned whose <see cref="IsDefault"/> property returns <c>true</c>.
- /// </returns>
- /// <remarks>
- /// Arrays of derived elements types can be cast to arrays of base element types
- /// without reallocating the array.
- /// These upcasts can be reversed via this same method, casting an array of base
- /// element types to their derived types. However, downcasting is only successful
- /// when it reverses a prior upcasting operation.
- /// </remarks>
- [Pure]
- public ImmutableArray<TOther> As<TOther>() where TOther : class
- {
- return new ImmutableArray<TOther>(this.array as TOther[]);
- }
-
/// <summary>
/// Filters the elements of this array to those assignable to the specified type.
/// </summary>
@@ -1208,32 +856,6 @@ namespace System.Collections.Immutable
}
/// <summary>
- /// Returns an enumerator for the contents of the array.
- /// </summary>
- /// <returns>An enumerator.</returns>
- /// <exception cref="InvalidOperationException">Thrown if the <see cref="IsDefault"/> property returns true.</exception>
- [Pure]
- IEnumerator<T> IEnumerable<T>.GetEnumerator()
- {
- var self = this;
- self.ThrowInvalidOperationIfNotInitialized();
- return EnumeratorObject.Create(self.array);
- }
-
- /// <summary>
- /// Returns an enumerator for the contents of the array.
- /// </summary>
- /// <returns>An enumerator.</returns>
- /// <exception cref="InvalidOperationException">Thrown if the <see cref="IsDefault"/> property returns true.</exception>
- [Pure]
- IEnumerator IEnumerable.GetEnumerator()
- {
- var self = this;
- self.ThrowInvalidOperationIfNotInitialized();
- return EnumeratorObject.Create(self.array);
- }
-
- /// <summary>
/// See <see cref="IImmutableList{T}"/>
/// </summary>
[ExcludeFromCodeCoverage]
@@ -1643,37 +1265,6 @@ namespace System.Collections.Immutable
#endregion
- /// <summary>
- /// Throws a null reference exception if the array field is null.
- /// </summary>
- internal void ThrowNullRefIfNotInitialized()
- {
- // Force NullReferenceException if array is null by touching its Length.
- // This way of checking has a nice property of requiring very little code
- // and not having any conditions/branches.
- // In a faulting scenario we are relying on hardware to generate the fault.
- // And in the non-faulting scenario (most common) the check is virtually free since
- // if we are going to do anything with the array, we will need Length anyways
- // so touching it, and potentially causing a cache miss, is not going to be an
- // extra expense.
- var unused = this.array.Length;
- }
-
- /// <summary>
- /// Throws an <see cref="InvalidOperationException"/> if the <see cref="array"/> field is null, i.e. the
- /// <see cref="IsDefault"/> property returns true. The
- /// <see cref="InvalidOperationException"/> message specifies that the operation cannot be performed
- /// on a default instance of <see cref="ImmutableArray{T}"/>.
- ///
- /// This is intended for explicitly implemented interface method and property implementations.
- /// </summary>
- private void ThrowInvalidOperationIfNotInitialized()
- {
- if (this.IsDefault)
- {
- throw new InvalidOperationException(SR.InvalidOperationOnDefaultArray);
- }
- }
/// <summary>
/// Returns an array with items at the specified indices removed.
diff --git a/src/System.Collections.Immutable/src/System/Collections/Immutable/ImmutableExtensions.Minimal.cs b/src/System.Collections.Immutable/src/System/Collections/Immutable/ImmutableExtensions.Minimal.cs
new file mode 100644
index 0000000000..2887d99fd3
--- /dev/null
+++ b/src/System.Collections.Immutable/src/System/Collections/Immutable/ImmutableExtensions.Minimal.cs
@@ -0,0 +1,181 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.Diagnostics.CodeAnalysis;
+using System.Diagnostics.Contracts;
+using System.Linq;
+using System.Reflection;
+
+namespace System.Collections.Immutable
+{
+ internal static partial class ImmutableExtensions
+ {
+ /// <summary>
+ /// Tries to divine the number of elements in a sequence without actually enumerating each element.
+ /// </summary>
+ /// <typeparam name="T">The type of elements in the sequence.</typeparam>
+ /// <param name="sequence">The enumerable source.</param>
+ /// <param name="count">Receives the number of elements in the enumeration, if it could be determined.</param>
+ /// <returns><c>true</c> if the count could be determined; <c>false</c> otherwise.</returns>
+ internal static bool TryGetCount<T>(this IEnumerable<T> sequence, out int count)
+ {
+ return TryGetCount<T>((IEnumerable)sequence, out count);
+ }
+
+ /// <summary>
+ /// Tries to divine the number of elements in a sequence without actually enumerating each element.
+ /// </summary>
+ /// <typeparam name="T">The type of elements in the sequence.</typeparam>
+ /// <param name="sequence">The enumerable source.</param>
+ /// <param name="count">Receives the number of elements in the enumeration, if it could be determined.</param>
+ /// <returns><c>true</c> if the count could be determined; <c>false</c> otherwise.</returns>
+ internal static bool TryGetCount<T>(this IEnumerable sequence, out int count)
+ {
+ var collection = sequence as ICollection;
+ if (collection != null)
+ {
+ count = collection.Count;
+ return true;
+ }
+
+ var collectionOfT = sequence as ICollection<T>;
+ if (collectionOfT != null)
+ {
+ count = collectionOfT.Count;
+ return true;
+ }
+
+ var readOnlyCollection = sequence as IReadOnlyCollection<T>;
+ if (readOnlyCollection != null)
+ {
+ count = readOnlyCollection.Count;
+ return true;
+ }
+
+ count = 0;
+ return false;
+ }
+
+ /// <summary>
+ /// Gets the number of elements in the specified sequence,
+ /// while guaranteeing that the sequence is only enumerated once
+ /// in total by this method and the caller.
+ /// </summary>
+ /// <typeparam name="T">The type of element in the collection.</typeparam>
+ /// <param name="sequence">The sequence.</param>
+ /// <returns>The number of elements in the sequence.</returns>
+ internal static int GetCount<T>(ref IEnumerable<T> sequence)
+ {
+ int count;
+ if (!sequence.TryGetCount(out count))
+ {
+ // We cannot predict the length of the sequence. We must walk the entire sequence
+ // to find the count. But avoid our caller also having to enumerate by capturing
+ // the enumeration in a snapshot and passing that back to the caller.
+ var list = sequence.ToList();
+ count = list.Count;
+ sequence = list;
+ }
+
+ return count;
+ }
+
+ /// <summary>
+ /// Tries to copy the elements in the sequence to the specified array,
+ /// if the sequence is a well-known collection type. Otherwise, does
+ /// nothing and returns <c>false</c>.
+ /// </summary>
+ /// <typeparam name="T">The type of element in the sequence.</typeparam>
+ /// <param name="sequence">The sequence to copy.</param>
+ /// <param name="array">The array to copy the elements to.</param>
+ /// <param name="arrayIndex">The index in the array to start copying.</param>
+ /// <returns><c>true</c> if the elements were successfully copied; <c>false</c> otherwise.</returns>
+ /// <remarks>
+ /// <para>
+ /// The reason we don't copy anything other than for well-known types is that a malicious interface
+ /// implementation of <see cref="ICollection{T}"/> could hold on to the array when its <see cref="ICollection{T}.CopyTo"/>
+ /// method is called. If the array it holds onto underlies an <see cref="ImmutableArray{T}"/>, it could violate
+ /// immutability by modifying the array.
+ /// </para>
+ /// </remarks>
+ internal static bool TryCopyTo<T>(this IEnumerable<T> sequence, T[] array, int arrayIndex)
+ {
+ Debug.Assert(sequence != null);
+ Debug.Assert(array != null);
+ Debug.Assert(arrayIndex >= 0 && arrayIndex <= array.Length);
+
+ // IList is the GCD of what the following types implement.
+ var listInterface = sequence as IList<T>;
+ if (listInterface != null)
+ {
+ var list = sequence as List<T>;
+ if (list != null)
+ {
+ list.CopyTo(array, arrayIndex);
+ return true;
+ }
+
+ // Array.Copy can throw an ArrayTypeMismatchException if the underlying type of
+ // the destination array is not typeof(T[]), but is assignment-compatible with T[].
+ // See https://github.com/dotnet/corefx/issues/2241 for more info.
+ if (sequence.GetType() == typeof(T[]))
+ {
+ var sourceArray = (T[])sequence;
+ Array.Copy(sourceArray, 0, array, arrayIndex, sourceArray.Length);
+ return true;
+ }
+
+ if (sequence is ImmutableArray<T>)
+ {
+ var immutable = (ImmutableArray<T>)sequence;
+ Array.Copy(immutable.array, 0, array, arrayIndex, immutable.Length);
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ /// <summary>
+ /// Gets a copy of a sequence as an array.
+ /// </summary>
+ /// <typeparam name="T">The type of element.</typeparam>
+ /// <param name="sequence">The sequence to be copied.</param>
+ /// <param name="count">The number of elements in the sequence.</param>
+ /// <returns>The array.</returns>
+ /// <remarks>
+ /// This is more efficient than the <see cref="Enumerable.ToArray{TSource}"/> extension method
+ /// because that only tries to cast the sequence to <see cref="ICollection{T}"/> to determine
+ /// the count before it falls back to reallocating arrays as it enumerates.
+ /// </remarks>
+ internal static T[] ToArray<T>(this IEnumerable<T> sequence, int count)
+ {
+ Requires.NotNull(sequence, nameof(sequence));
+ Requires.Range(count >= 0, nameof(count));
+
+ if (count == 0)
+ {
+ return ImmutableArray<T>.Empty.array;
+ }
+
+ T[] array = new T[count];
+
+ if (!sequence.TryCopyTo(array, 0))
+ {
+ int i = 0;
+ foreach (var item in sequence)
+ {
+ Requires.Argument(i < count);
+ array[i++] = item;
+ }
+
+ Requires.Argument(i == count);
+ }
+
+ return array;
+ }
+ }
+}
diff --git a/src/System.Collections.Immutable/src/System/Collections/Immutable/ImmutableExtensions.cs b/src/System.Collections.Immutable/src/System/Collections/Immutable/ImmutableExtensions.cs
index 783192bbd5..4f0a711ca7 100644
--- a/src/System.Collections.Immutable/src/System/Collections/Immutable/ImmutableExtensions.cs
+++ b/src/System.Collections.Immutable/src/System/Collections/Immutable/ImmutableExtensions.cs
@@ -14,172 +14,8 @@ namespace System.Collections.Immutable
/// <summary>
/// Extension methods for immutable types.
/// </summary>
- internal static class ImmutableExtensions
+ internal static partial class ImmutableExtensions
{
- /// <summary>
- /// Tries to divine the number of elements in a sequence without actually enumerating each element.
- /// </summary>
- /// <typeparam name="T">The type of elements in the sequence.</typeparam>
- /// <param name="sequence">The enumerable source.</param>
- /// <param name="count">Receives the number of elements in the enumeration, if it could be determined.</param>
- /// <returns><c>true</c> if the count could be determined; <c>false</c> otherwise.</returns>
- internal static bool TryGetCount<T>(this IEnumerable<T> sequence, out int count)
- {
- return TryGetCount<T>((IEnumerable)sequence, out count);
- }
-
- /// <summary>
- /// Tries to divine the number of elements in a sequence without actually enumerating each element.
- /// </summary>
- /// <typeparam name="T">The type of elements in the sequence.</typeparam>
- /// <param name="sequence">The enumerable source.</param>
- /// <param name="count">Receives the number of elements in the enumeration, if it could be determined.</param>
- /// <returns><c>true</c> if the count could be determined; <c>false</c> otherwise.</returns>
- internal static bool TryGetCount<T>(this IEnumerable sequence, out int count)
- {
- var collection = sequence as ICollection;
- if (collection != null)
- {
- count = collection.Count;
- return true;
- }
-
- var collectionOfT = sequence as ICollection<T>;
- if (collectionOfT != null)
- {
- count = collectionOfT.Count;
- return true;
- }
-
- var readOnlyCollection = sequence as IReadOnlyCollection<T>;
- if (readOnlyCollection != null)
- {
- count = readOnlyCollection.Count;
- return true;
- }
-
- count = 0;
- return false;
- }
-
- /// <summary>
- /// Gets the number of elements in the specified sequence,
- /// while guaranteeing that the sequence is only enumerated once
- /// in total by this method and the caller.
- /// </summary>
- /// <typeparam name="T">The type of element in the collection.</typeparam>
- /// <param name="sequence">The sequence.</param>
- /// <returns>The number of elements in the sequence.</returns>
- internal static int GetCount<T>(ref IEnumerable<T> sequence)
- {
- int count;
- if (!sequence.TryGetCount(out count))
- {
- // We cannot predict the length of the sequence. We must walk the entire sequence
- // to find the count. But avoid our caller also having to enumerate by capturing
- // the enumeration in a snapshot and passing that back to the caller.
- var list = sequence.ToList();
- count = list.Count;
- sequence = list;
- }
-
- return count;
- }
-
- /// <summary>
- /// Tries to copy the elements in the sequence to the specified array,
- /// if the sequence is a well-known collection type. Otherwise, does
- /// nothing and returns <c>false</c>.
- /// </summary>
- /// <typeparam name="T">The type of element in the sequence.</typeparam>
- /// <param name="sequence">The sequence to copy.</param>
- /// <param name="array">The array to copy the elements to.</param>
- /// <param name="arrayIndex">The index in the array to start copying.</param>
- /// <returns><c>true</c> if the elements were successfully copied; <c>false</c> otherwise.</returns>
- /// <remarks>
- /// <para>
- /// The reason we don't copy anything other than for well-known types is that a malicious interface
- /// implementation of <see cref="ICollection{T}"/> could hold on to the array when its <see cref="ICollection{T}.CopyTo"/>
- /// method is called. If the array it holds onto underlies an <see cref="ImmutableArray{T}"/>, it could violate
- /// immutability by modifying the array.
- /// </para>
- /// </remarks>
- internal static bool TryCopyTo<T>(this IEnumerable<T> sequence, T[] array, int arrayIndex)
- {
- Debug.Assert(sequence != null);
- Debug.Assert(array != null);
- Debug.Assert(arrayIndex >= 0 && arrayIndex <= array.Length);
-
- // IList is the GCD of what the following types implement.
- var listInterface = sequence as IList<T>;
- if (listInterface != null)
- {
- var list = sequence as List<T>;
- if (list != null)
- {
- list.CopyTo(array, arrayIndex);
- return true;
- }
-
- // Array.Copy can throw an ArrayTypeMismatchException if the underlying type of
- // the destination array is not typeof(T[]), but is assignment-compatible with T[].
- // See https://github.com/dotnet/corefx/issues/2241 for more info.
- if (sequence.GetType() == typeof(T[]))
- {
- var sourceArray = (T[])sequence;
- Array.Copy(sourceArray, 0, array, arrayIndex, sourceArray.Length);
- return true;
- }
-
- if (sequence is ImmutableArray<T>)
- {
- var immutable = (ImmutableArray<T>)sequence;
- Array.Copy(immutable.array, 0, array, arrayIndex, immutable.Length);
- return true;
- }
- }
-
- return false;
- }
-
- /// <summary>
- /// Gets a copy of a sequence as an array.
- /// </summary>
- /// <typeparam name="T">The type of element.</typeparam>
- /// <param name="sequence">The sequence to be copied.</param>
- /// <param name="count">The number of elements in the sequence.</param>
- /// <returns>The array.</returns>
- /// <remarks>
- /// This is more efficient than the <see cref="Enumerable.ToArray{TSource}"/> extension method
- /// because that only tries to cast the sequence to <see cref="ICollection{T}"/> to determine
- /// the count before it falls back to reallocating arrays as it enumerates.
- /// </remarks>
- internal static T[] ToArray<T>(this IEnumerable<T> sequence, int count)
- {
- Requires.NotNull(sequence, nameof(sequence));
- Requires.Range(count >= 0, nameof(count));
-
- if (count == 0)
- {
- return ImmutableArray<T>.Empty.array;
- }
-
- T[] array = new T[count];
-
- if (!sequence.TryCopyTo(array, 0))
- {
- int i = 0;
- foreach (var item in sequence)
- {
- Requires.Argument(i < count);
- array[i++] = item;
- }
-
- Requires.Argument(i == count);
- }
-
- return array;
- }
#if EqualsStructurally